rice 3.0.0 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (238) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +121 -0
  3. data/CONTRIBUTORS.md +19 -0
  4. data/Gemfile +3 -0
  5. data/README.md +44 -1025
  6. data/Rakefile +95 -12
  7. data/include/rice/rice.hpp +7766 -0
  8. data/include/rice/stl.hpp +1113 -0
  9. data/lib/mkmf-rice.rb +127 -0
  10. data/lib/version.rb +3 -0
  11. data/rice/Address_Registration_Guard.ipp +75 -32
  12. data/rice/Address_Registration_Guard_defn.hpp +60 -56
  13. data/rice/Arg.hpp +80 -4
  14. data/rice/Arg.ipp +51 -0
  15. data/rice/Constructor.hpp +12 -14
  16. data/rice/Data_Object.ipp +234 -107
  17. data/rice/Data_Object_defn.hpp +77 -117
  18. data/rice/Data_Type.hpp +1 -2
  19. data/rice/Data_Type.ipp +251 -295
  20. data/rice/Data_Type_defn.hpp +175 -243
  21. data/rice/Director.hpp +11 -6
  22. data/rice/Enum.hpp +54 -104
  23. data/rice/Enum.ipp +104 -230
  24. data/rice/Exception.hpp +2 -8
  25. data/rice/Exception.ipp +65 -0
  26. data/rice/Exception_defn.hpp +46 -47
  27. data/rice/Identifier.hpp +28 -28
  28. data/rice/Identifier.ipp +23 -27
  29. data/rice/Return.hpp +39 -0
  30. data/rice/Return.ipp +33 -0
  31. data/rice/detail/Exception_Handler.ipp +22 -62
  32. data/rice/detail/Exception_Handler_defn.hpp +76 -91
  33. data/rice/detail/Iterator.hpp +18 -88
  34. data/rice/detail/Iterator.ipp +47 -0
  35. data/rice/detail/Jump_Tag.hpp +21 -0
  36. data/rice/detail/MethodInfo.hpp +44 -0
  37. data/rice/detail/MethodInfo.ipp +78 -0
  38. data/rice/detail/NativeAttribute.hpp +53 -0
  39. data/rice/detail/NativeAttribute.ipp +83 -0
  40. data/rice/detail/NativeFunction.hpp +69 -0
  41. data/rice/detail/NativeFunction.ipp +248 -0
  42. data/rice/detail/RubyFunction.hpp +39 -0
  43. data/rice/detail/RubyFunction.ipp +92 -0
  44. data/rice/detail/Type.hpp +29 -0
  45. data/rice/detail/Type.ipp +138 -0
  46. data/rice/detail/TypeRegistry.hpp +50 -0
  47. data/rice/detail/TypeRegistry.ipp +106 -0
  48. data/rice/detail/Wrapper.hpp +51 -0
  49. data/rice/detail/Wrapper.ipp +151 -0
  50. data/rice/detail/default_allocation_func.hpp +8 -19
  51. data/rice/detail/default_allocation_func.ipp +9 -8
  52. data/rice/detail/from_ruby.hpp +2 -37
  53. data/rice/detail/from_ruby.ipp +1020 -46
  54. data/rice/detail/from_ruby_defn.hpp +38 -0
  55. data/rice/detail/function_traits.hpp +124 -0
  56. data/rice/detail/method_data.hpp +23 -15
  57. data/rice/detail/method_data.ipp +53 -0
  58. data/rice/detail/rice_traits.hpp +116 -0
  59. data/rice/detail/ruby.hpp +9 -46
  60. data/rice/detail/to_ruby.hpp +3 -17
  61. data/rice/detail/to_ruby.ipp +409 -31
  62. data/rice/detail/to_ruby_defn.hpp +48 -0
  63. data/rice/forward_declares.ipp +82 -0
  64. data/rice/global_function.hpp +16 -20
  65. data/rice/global_function.ipp +8 -17
  66. data/rice/rice.hpp +59 -0
  67. data/rice/ruby_mark.hpp +5 -3
  68. data/rice/ruby_try_catch.hpp +4 -4
  69. data/rice/stl.hpp +11 -0
  70. data/sample/callbacks/extconf.rb +3 -0
  71. data/sample/callbacks/sample_callbacks.cpp +10 -13
  72. data/sample/enum/extconf.rb +3 -0
  73. data/sample/enum/sample_enum.cpp +3 -17
  74. data/sample/enum/test.rb +2 -2
  75. data/sample/inheritance/animals.cpp +8 -24
  76. data/sample/inheritance/extconf.rb +3 -0
  77. data/sample/inheritance/test.rb +1 -1
  78. data/sample/map/extconf.rb +3 -0
  79. data/sample/map/map.cpp +10 -18
  80. data/sample/map/test.rb +1 -1
  81. data/test/embed_ruby.cpp +18 -5
  82. data/test/ext/t1/extconf.rb +3 -0
  83. data/test/ext/t1/t1.cpp +1 -3
  84. data/test/ext/t2/extconf.rb +3 -0
  85. data/test/ext/t2/t2.cpp +1 -1
  86. data/test/extconf.rb +23 -0
  87. data/test/ruby/test_callbacks_sample.rb +28 -0
  88. data/test/ruby/test_multiple_extensions.rb +18 -0
  89. data/test/ruby/test_multiple_extensions_same_class.rb +14 -0
  90. data/test/ruby/test_multiple_extensions_with_inheritance.rb +20 -0
  91. data/test/test_Address_Registration_Guard.cpp +23 -10
  92. data/test/test_Array.cpp +129 -73
  93. data/test/test_Attribute.cpp +147 -0
  94. data/test/test_Builtin_Object.cpp +34 -14
  95. data/test/test_Class.cpp +149 -275
  96. data/test/test_Constructor.cpp +10 -9
  97. data/test/test_Data_Object.cpp +133 -192
  98. data/test/test_Data_Type.cpp +322 -252
  99. data/test/test_Director.cpp +54 -41
  100. data/test/test_Enum.cpp +228 -103
  101. data/test/test_Exception.cpp +5 -6
  102. data/test/test_Hash.cpp +31 -30
  103. data/test/test_Identifier.cpp +4 -5
  104. data/test/test_Inheritance.cpp +221 -0
  105. data/test/test_Iterator.cpp +161 -0
  106. data/test/test_Jump_Tag.cpp +1 -1
  107. data/test/test_Keep_Alive.cpp +161 -0
  108. data/test/test_Memory_Management.cpp +2 -4
  109. data/test/test_Module.cpp +167 -110
  110. data/test/test_Object.cpp +41 -21
  111. data/test/test_Ownership.cpp +275 -0
  112. data/test/test_Self.cpp +205 -0
  113. data/test/test_Stl_Optional.cpp +90 -0
  114. data/test/test_Stl_Pair.cpp +144 -0
  115. data/test/test_Stl_SmartPointer.cpp +200 -0
  116. data/test/test_Stl_String.cpp +74 -0
  117. data/test/test_Stl_Vector.cpp +652 -0
  118. data/test/test_String.cpp +1 -2
  119. data/test/test_Struct.cpp +29 -39
  120. data/test/test_Symbol.cpp +1 -2
  121. data/test/test_To_From_Ruby.cpp +249 -285
  122. data/test/test_global_functions.cpp +39 -19
  123. data/test/unittest.hpp +0 -4
  124. metadata +70 -141
  125. data/Doxyfile +0 -2268
  126. data/Makefile.am +0 -26
  127. data/Makefile.in +0 -931
  128. data/README.mingw +0 -8
  129. data/aclocal.m4 +0 -1085
  130. data/ax_cxx_compile_stdcxx.m4 +0 -951
  131. data/bootstrap +0 -8
  132. data/config.guess +0 -1421
  133. data/config.sub +0 -1807
  134. data/configure +0 -7792
  135. data/configure.ac +0 -55
  136. data/depcomp +0 -791
  137. data/doxygen.ac +0 -314
  138. data/doxygen.am +0 -186
  139. data/extconf.rb +0 -70
  140. data/install-sh +0 -501
  141. data/missing +0 -215
  142. data/post-autoconf.rb +0 -22
  143. data/post-automake.rb +0 -28
  144. data/rice/Address_Registration_Guard.cpp +0 -22
  145. data/rice/Arg_impl.hpp +0 -129
  146. data/rice/Arg_operators.cpp +0 -21
  147. data/rice/Arg_operators.hpp +0 -19
  148. data/rice/Array.hpp +0 -214
  149. data/rice/Array.ipp +0 -256
  150. data/rice/Builtin_Object.hpp +0 -8
  151. data/rice/Builtin_Object.ipp +0 -50
  152. data/rice/Builtin_Object_defn.hpp +0 -50
  153. data/rice/Class.cpp +0 -57
  154. data/rice/Class.hpp +0 -8
  155. data/rice/Class.ipp +0 -6
  156. data/rice/Class_defn.hpp +0 -84
  157. data/rice/Data_Type.cpp +0 -54
  158. data/rice/Data_Type_fwd.hpp +0 -12
  159. data/rice/Director.cpp +0 -13
  160. data/rice/Exception.cpp +0 -54
  161. data/rice/Exception_Base.hpp +0 -8
  162. data/rice/Exception_Base.ipp +0 -13
  163. data/rice/Exception_Base_defn.hpp +0 -27
  164. data/rice/Hash.hpp +0 -230
  165. data/rice/Hash.ipp +0 -329
  166. data/rice/Identifier.cpp +0 -8
  167. data/rice/Jump_Tag.hpp +0 -24
  168. data/rice/Makefile.am +0 -121
  169. data/rice/Makefile.in +0 -884
  170. data/rice/Module.cpp +0 -84
  171. data/rice/Module.hpp +0 -8
  172. data/rice/Module.ipp +0 -6
  173. data/rice/Module_defn.hpp +0 -88
  174. data/rice/Module_impl.hpp +0 -281
  175. data/rice/Module_impl.ipp +0 -345
  176. data/rice/Object.cpp +0 -169
  177. data/rice/Object.hpp +0 -8
  178. data/rice/Object.ipp +0 -33
  179. data/rice/Object_defn.hpp +0 -214
  180. data/rice/Require_Guard.hpp +0 -21
  181. data/rice/String.cpp +0 -89
  182. data/rice/String.hpp +0 -91
  183. data/rice/Struct.cpp +0 -117
  184. data/rice/Struct.hpp +0 -162
  185. data/rice/Struct.ipp +0 -26
  186. data/rice/Symbol.cpp +0 -25
  187. data/rice/Symbol.hpp +0 -66
  188. data/rice/Symbol.ipp +0 -44
  189. data/rice/config.hpp +0 -47
  190. data/rice/config.hpp.in +0 -46
  191. data/rice/detail/Arguments.hpp +0 -118
  192. data/rice/detail/Auto_Function_Wrapper.hpp +0 -898
  193. data/rice/detail/Auto_Function_Wrapper.ipp +0 -3181
  194. data/rice/detail/Auto_Member_Function_Wrapper.hpp +0 -897
  195. data/rice/detail/Auto_Member_Function_Wrapper.ipp +0 -2501
  196. data/rice/detail/Caster.hpp +0 -103
  197. data/rice/detail/Not_Copyable.hpp +0 -25
  198. data/rice/detail/Wrapped_Function.hpp +0 -33
  199. data/rice/detail/cfp.hpp +0 -24
  200. data/rice/detail/cfp.ipp +0 -51
  201. data/rice/detail/check_ruby_type.cpp +0 -27
  202. data/rice/detail/check_ruby_type.hpp +0 -23
  203. data/rice/detail/creation_funcs.hpp +0 -37
  204. data/rice/detail/creation_funcs.ipp +0 -36
  205. data/rice/detail/define_method_and_auto_wrap.hpp +0 -31
  206. data/rice/detail/define_method_and_auto_wrap.ipp +0 -30
  207. data/rice/detail/demangle.cpp +0 -56
  208. data/rice/detail/demangle.hpp +0 -19
  209. data/rice/detail/env.hpp +0 -11
  210. data/rice/detail/method_data.cpp +0 -92
  211. data/rice/detail/node.hpp +0 -13
  212. data/rice/detail/protect.cpp +0 -29
  213. data/rice/detail/protect.hpp +0 -34
  214. data/rice/detail/ruby_version_code.hpp +0 -6
  215. data/rice/detail/ruby_version_code.hpp.in +0 -6
  216. data/rice/detail/st.hpp +0 -22
  217. data/rice/detail/win32.hpp +0 -16
  218. data/rice/detail/wrap_function.hpp +0 -66
  219. data/rice/protect.hpp +0 -38
  220. data/rice/protect.ipp +0 -1134
  221. data/rice/rubypp.rb +0 -97
  222. data/rice/to_from_ruby.hpp +0 -8
  223. data/rice/to_from_ruby.ipp +0 -418
  224. data/rice/to_from_ruby_defn.hpp +0 -70
  225. data/ruby/Makefile.am +0 -1
  226. data/ruby/Makefile.in +0 -628
  227. data/ruby/lib/Makefile.am +0 -3
  228. data/ruby/lib/Makefile.in +0 -506
  229. data/ruby/lib/mkmf-rice.rb.in +0 -217
  230. data/ruby/lib/version.rb +0 -3
  231. data/ruby.ac +0 -135
  232. data/sample/Makefile.am +0 -53
  233. data/sample/Makefile.in +0 -495
  234. data/test/Makefile.am +0 -73
  235. data/test/Makefile.in +0 -1219
  236. data/test/ext/Makefile.am +0 -41
  237. data/test/ext/Makefile.in +0 -483
  238. data/test/test_rice.rb +0 -45
@@ -0,0 +1,83 @@
1
+ #include <array>
2
+ #include <algorithm>
3
+
4
+ #include "rice_traits.hpp"
5
+ #include "method_data.hpp"
6
+ #include "to_ruby_defn.hpp"
7
+ #include "../ruby_try_catch.hpp"
8
+
9
+ namespace Rice::detail
10
+ {
11
+ template<typename Return_T, typename Attr_T, typename Self_T>
12
+ inline VALUE NativeAttribute<Return_T, Attr_T, Self_T>::get(VALUE self)
13
+ {
14
+ RUBY_TRY
15
+ {
16
+ using Native_Attr_T = NativeAttribute<Return_T, Attr_T, Self_T>;
17
+ Native_Attr_T* attr = detail::MethodData::data<Native_Attr_T*>();
18
+ return attr->read(self);
19
+ }
20
+ RUBY_CATCH
21
+ }
22
+
23
+ template<typename Return_T, typename Attr_T, typename Self_T>
24
+ inline VALUE NativeAttribute<Return_T, Attr_T, Self_T>::set(VALUE self, VALUE value)
25
+ {
26
+ RUBY_TRY
27
+ {
28
+ using Native_Attr_T = NativeAttribute<Return_T, Attr_T, Self_T>;
29
+ Native_Attr_T* attr = detail::MethodData::data<Native_Attr_T*>();
30
+ return attr->write(self, value);
31
+ }
32
+ RUBY_CATCH
33
+ }
34
+
35
+ template<typename Return_T, typename Attr_T, typename Self_T>
36
+ NativeAttribute<Return_T, Attr_T, Self_T>::NativeAttribute(Attr_T attr, AttrAccess access)
37
+ : attr_(attr), access_(access)
38
+ {
39
+ }
40
+
41
+ template<typename Return_T, typename Attr_T, typename Self_T>
42
+ inline VALUE NativeAttribute<Return_T, Attr_T, Self_T>::read(VALUE self)
43
+ {
44
+ using Unqualified_T = remove_cv_recursive_t<Return_T>;
45
+ if constexpr (std::is_member_object_pointer_v<Attr_T>)
46
+ {
47
+ Self_T* nativeSelf = From_Ruby<Self_T*>().convert(self);
48
+ return To_Ruby<Unqualified_T>().convert(nativeSelf->*attr_);
49
+ }
50
+ else
51
+ {
52
+ return To_Ruby<Unqualified_T>().convert(*attr_);
53
+ }
54
+ }
55
+
56
+ template<typename Return_T, typename Attr_T, typename Self_T>
57
+ inline VALUE NativeAttribute<Return_T, Attr_T, Self_T>::write(VALUE self, VALUE value)
58
+ {
59
+ if constexpr (!std::is_const_v<std::remove_pointer_t<Attr_T>> && std::is_member_object_pointer_v<Attr_T>)
60
+ {
61
+ Self_T* nativeSelf = From_Ruby<Self_T*>().convert(self);
62
+ nativeSelf->*attr_ = From_Ruby<Return_T>().convert(value);
63
+ }
64
+ else if constexpr (!std::is_const_v<std::remove_pointer_t<Attr_T>>)
65
+ {
66
+ *attr_ = From_Ruby<Return_T>().convert(value);
67
+ }
68
+ return value;
69
+ }
70
+
71
+ template<typename T>
72
+ auto* Make_Native_Attribute(T* attr, AttrAccess access)
73
+ {
74
+ return new NativeAttribute<T, T*>(attr, access);
75
+ }
76
+
77
+ template<typename Class_T, typename T>
78
+ auto* Make_Native_Attribute(T Class_T::* attr, AttrAccess access)
79
+ {
80
+ using Attr_T = T Class_T::*;
81
+ return new NativeAttribute<T, Attr_T, Class_T>(attr, access);
82
+ }
83
+ } // Rice
@@ -0,0 +1,69 @@
1
+ #ifndef Rice__detail__Native_Function__hpp_
2
+ #define Rice__detail__Native_Function__hpp_
3
+
4
+ #include "ruby.hpp"
5
+ #include "Exception_Handler_defn.hpp"
6
+ #include "MethodInfo.hpp"
7
+ #include "function_traits.hpp"
8
+ #include "from_ruby.hpp"
9
+
10
+ namespace Rice::detail
11
+ {
12
+ template<typename Function_T, bool IsMethod>
13
+ class NativeFunction
14
+ {
15
+ public:
16
+ // We remove const to avoid an explosion of To_Ruby specializations and Ruby doesn't
17
+ // have the concept of constants anyways
18
+ using Return_T = remove_cv_recursive_t<typename function_traits<Function_T>::return_type>;
19
+ using Self_T = typename method_traits<Function_T, IsMethod>::Self_T;
20
+ using Arg_Ts = typename method_traits<Function_T, IsMethod>::Arg_Ts;
21
+ using From_Ruby_Ts = typename tuple_map<From_Ruby, Arg_Ts>::type;
22
+
23
+ // Static member function that Ruby calls
24
+ static VALUE call(int argc, VALUE* argv, VALUE self);
25
+
26
+ public:
27
+ NativeFunction(Function_T func, std::shared_ptr<Exception_Handler> handler, MethodInfo* methodInfo);
28
+
29
+ // Invokes the wrapped function
30
+ VALUE operator()(int argc, VALUE* argv, VALUE self);
31
+
32
+ private:
33
+ template<typename T, std::size_t I>
34
+ From_Ruby<T> createFromRuby();
35
+
36
+ // Create NativeArgs which are used to convert values from Ruby to C++
37
+ template<std::size_t...I>
38
+ From_Ruby_Ts createFromRuby(std::index_sequence<I...>& indices);
39
+
40
+ To_Ruby<Return_T> createToRuby();
41
+
42
+ // Convert Ruby argv pointer to Ruby values
43
+ std::vector<VALUE> getRubyValues(int argc, VALUE* argv);
44
+
45
+ // Convert Ruby values to C++ values
46
+ template<typename std::size_t...I>
47
+ Arg_Ts getNativeValues(std::vector<VALUE>& values, std::index_sequence<I...>& indices);
48
+
49
+ // Figure out what self is
50
+ Self_T getSelf(VALUE self);
51
+
52
+ // Do we need to keep alive any arguments?
53
+ void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues);
54
+
55
+ // Call the underlying C++ function
56
+ VALUE invokeNativeFunction(Arg_Ts& nativeArgs);
57
+ VALUE invokeNativeMethod(VALUE self, Arg_Ts& nativeArgs);
58
+
59
+ private:
60
+ Function_T func_;
61
+ From_Ruby_Ts fromRubys_;
62
+ To_Ruby<Return_T> toRuby_;
63
+ std::shared_ptr<Exception_Handler> handler_;
64
+ std::unique_ptr<MethodInfo> methodInfo_;
65
+ };
66
+ }
67
+ #include "NativeFunction.ipp"
68
+
69
+ #endif // Rice__detail__Native_Function__hpp_
@@ -0,0 +1,248 @@
1
+ #include <array>
2
+ #include <algorithm>
3
+ #include <stdexcept>
4
+
5
+ #include "method_data.hpp"
6
+ #include "to_ruby_defn.hpp"
7
+ #include "../ruby_try_catch.hpp"
8
+
9
+ namespace Rice::detail
10
+ {
11
+ template<typename Function_T, bool IsMethod>
12
+ VALUE NativeFunction<Function_T, IsMethod>::call(int argc, VALUE* argv, VALUE self)
13
+ {
14
+ using Wrapper_T = NativeFunction<Function_T, IsMethod>;
15
+ Wrapper_T* wrapper = detail::MethodData::data<Wrapper_T*>();
16
+ return wrapper->operator()(argc, argv, self);
17
+ }
18
+
19
+ template<typename Function_T, bool IsMethod>
20
+ NativeFunction<Function_T, IsMethod>::NativeFunction(Function_T func, std::shared_ptr<Exception_Handler> handler, MethodInfo* methodInfo)
21
+ : func_(func), handler_(handler), methodInfo_(methodInfo)
22
+ {
23
+ // Create a tuple of NativeArgs that will convert the Ruby values to native values. For
24
+ // builtin types NativeArgs will keep a copy of the native value so that it
25
+ // can be passed by reference or pointer to the native function. For non-builtin types
26
+ // it will just pass the value through.
27
+ auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
28
+ this->fromRubys_ = this->createFromRuby(indices);
29
+
30
+ this->toRuby_ = this->createToRuby();
31
+ }
32
+
33
+ template<typename Function_T, bool IsMethod>
34
+ template<typename T, std::size_t I>
35
+ From_Ruby<T> NativeFunction<Function_T, IsMethod>::createFromRuby()
36
+ {
37
+ // Does the From_Ruby instantiation work with Arg?
38
+ if constexpr (std::is_constructible_v<From_Ruby<T>, Arg*>)
39
+ {
40
+ return From_Ruby<T>(&this->methodInfo_->arg(I));
41
+ }
42
+ else
43
+ {
44
+ return From_Ruby<T>();
45
+ }
46
+ }
47
+
48
+ template<typename Function_T, bool IsMethod>
49
+ To_Ruby<typename NativeFunction<Function_T, IsMethod>::Return_T> NativeFunction<Function_T, IsMethod>::createToRuby()
50
+ {
51
+ // Does the From_Ruby instantiation work with ReturnInfo?
52
+ if constexpr (std::is_constructible_v<To_Ruby<Return_T>, Return*>)
53
+ {
54
+ return To_Ruby<Return_T>(&this->methodInfo_->returnInfo);
55
+ }
56
+ else
57
+ {
58
+ return To_Ruby<Return_T>();
59
+ }
60
+ }
61
+
62
+ template<typename Function_T, bool IsMethod>
63
+ template<std::size_t... I>
64
+ typename NativeFunction<Function_T, IsMethod>::From_Ruby_Ts NativeFunction<Function_T, IsMethod>::createFromRuby(std::index_sequence<I...>& indices)
65
+ {
66
+ return std::make_tuple(createFromRuby<remove_cv_recursive_t<typename std::tuple_element<I, Arg_Ts>::type>, I>()...);
67
+ }
68
+
69
+ template<typename Function_T, bool IsMethod>
70
+ std::vector<VALUE> NativeFunction<Function_T, IsMethod>::getRubyValues(int argc, VALUE* argv)
71
+ {
72
+ // Setup a tuple to contain required methodInfo to rb_scan_args
73
+ std::string scanFormat = this->methodInfo_->formatString();
74
+ std::tuple<int, VALUE*, const char*> rbScanMandatory = std::forward_as_tuple(argc, argv, scanFormat.c_str());
75
+
76
+ // Create a vector to store the variable number of Ruby Values
77
+ std::vector<VALUE> rbScanArgsOptional(std::tuple_size_v<Arg_Ts>, Qnil);
78
+
79
+ // Convert the vector to an array so it can then be concatenated to a tuple
80
+ std::array<VALUE*, std::tuple_size_v<Arg_Ts>> rbScanArgsOptionalPointers;
81
+ std::transform(rbScanArgsOptional.begin(), rbScanArgsOptional.end(), rbScanArgsOptionalPointers.begin(),
82
+ [](VALUE& value)
83
+ {
84
+ return &value;
85
+ });
86
+
87
+ // Combine the tuples and call rb_scan_args
88
+ auto rbScanArgs = std::tuple_cat(rbScanMandatory, rbScanArgsOptionalPointers);
89
+ std::apply(rb_scan_args, rbScanArgs);
90
+
91
+ return rbScanArgsOptional;
92
+ }
93
+
94
+ template<typename Function_T, bool IsMethod>
95
+ template<std::size_t... I>
96
+ typename NativeFunction<Function_T, IsMethod>::Arg_Ts NativeFunction<Function_T, IsMethod>::getNativeValues(std::vector<VALUE>& values,
97
+ std::index_sequence<I...>& indices)
98
+ {
99
+ // Convert each Ruby value to its native value by calling the appropriate fromRuby instance.
100
+ // Note that for fundamental types From_Ruby<Arg_Ts> will keep a copy of the native value
101
+ // so it can be passed by reference or pointer to a native function.
102
+ return std::forward_as_tuple(std::get<I>(this->fromRubys_).convert(values[I])...);
103
+ }
104
+
105
+ template<typename Function_T, bool IsMethod>
106
+ typename NativeFunction<Function_T, IsMethod>::Self_T NativeFunction<Function_T, IsMethod>::getSelf(VALUE self)
107
+ {
108
+ // There is no self parameter
109
+ if constexpr (std::is_same_v<Self_T, std::nullptr_t>)
110
+ {
111
+ return nullptr;
112
+ }
113
+ // Self parameter is a Ruby VALUE so no conversion is needed
114
+ else if constexpr (std::is_same_v<Self_T, VALUE>)
115
+ {
116
+ return self;
117
+ }
118
+ // Self parameter could be derived from Object or it is an C++ instdance and
119
+ // needs to be unwrapped from Ruby
120
+ else
121
+ {
122
+ return From_Ruby<Self_T>().convert(self);
123
+ }
124
+ }
125
+
126
+ template<typename Function_T, bool IsMethod>
127
+ VALUE NativeFunction<Function_T, IsMethod>::invokeNativeFunction(Arg_Ts& nativeArgs)
128
+ {
129
+ if constexpr (std::is_void_v<Return_T>)
130
+ {
131
+ std::apply(this->func_, nativeArgs);
132
+ return Qnil;
133
+ }
134
+ else
135
+ {
136
+ // Call the native method and get the result
137
+ Return_T nativeResult = std::apply(this->func_, nativeArgs);
138
+
139
+ // Return the result
140
+ return this->toRuby_.convert(nativeResult);
141
+ }
142
+ }
143
+
144
+ template<typename Function_T, bool IsMethod>
145
+ VALUE NativeFunction<Function_T, IsMethod>::invokeNativeMethod(VALUE self, Arg_Ts& nativeArgs)
146
+ {
147
+ Self_T receiver = this->getSelf(self);
148
+ auto selfAndNativeArgs = std::tuple_cat(std::forward_as_tuple(receiver), nativeArgs);
149
+
150
+ if constexpr (std::is_void_v<Return_T>)
151
+ {
152
+ std::apply(this->func_, selfAndNativeArgs);
153
+ return Qnil;
154
+ }
155
+ else
156
+ {
157
+ Return_T nativeResult = (Return_T)std::apply(this->func_, selfAndNativeArgs);
158
+
159
+ // Special handling if the method returns self. If so we do not want
160
+ // to create a new Ruby wrapper object and instead return self.
161
+ if constexpr (std::is_same_v<intrinsic_type<Return_T>, intrinsic_type<Self_T>>)
162
+ {
163
+ if constexpr (std::is_pointer_v<Return_T> && std::is_pointer_v<Self_T>)
164
+ {
165
+ if (nativeResult == receiver)
166
+ return self;
167
+ }
168
+ else if constexpr (std::is_pointer_v<Return_T> && std::is_reference_v<Self_T>)
169
+ {
170
+ if (nativeResult == &receiver)
171
+ return self;
172
+ }
173
+ else if constexpr (std::is_reference_v<Return_T> && std::is_pointer_v<Self_T>)
174
+ {
175
+ if (&nativeResult == receiver)
176
+ return self;
177
+ }
178
+ else if constexpr (std::is_reference_v<Return_T> && std::is_reference_v<Self_T>)
179
+ {
180
+ if (&nativeResult == &receiver)
181
+ return self;
182
+ }
183
+ }
184
+
185
+ return this->toRuby_.convert(nativeResult);
186
+ }
187
+ }
188
+
189
+ template<typename Function_T, bool IsMethod>
190
+ void NativeFunction<Function_T, IsMethod>::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues)
191
+ {
192
+ // Check function arguments
193
+ Wrapper* selfWrapper = getWrapper(self);
194
+ for (const Arg& arg : (*this->methodInfo_))
195
+ {
196
+ if (arg.isKeepAlive)
197
+ {
198
+ selfWrapper->addKeepAlive(rubyValues[arg.position]);
199
+ }
200
+ }
201
+
202
+ // Check return value
203
+ if (this->methodInfo_->returnInfo.isKeepAlive)
204
+ {
205
+ Wrapper* returnWrapper = getWrapper(returnValue);
206
+ returnWrapper->addKeepAlive(self);
207
+ }
208
+ }
209
+
210
+ template<typename Function_T, bool IsMethod>
211
+ VALUE NativeFunction<Function_T, IsMethod>::operator()(int argc, VALUE* argv, VALUE self)
212
+ {
213
+ try
214
+ {
215
+ // Get the ruby values
216
+ std::vector<VALUE> rubyValues = this->getRubyValues(argc, argv);
217
+
218
+ auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
219
+
220
+ // Convert the Ruby values to native values
221
+ Arg_Ts nativeValues = this->getNativeValues(rubyValues, indices);
222
+
223
+ // Now call the native method
224
+ VALUE result = Qnil;
225
+ if constexpr (std::is_same_v<Self_T, std::nullptr_t>)
226
+ {
227
+ result = this->invokeNativeFunction(nativeValues);
228
+ }
229
+ else
230
+ {
231
+ result = this->invokeNativeMethod(self, nativeValues);
232
+ }
233
+
234
+ // Check if any function arguments or return values need to have their lifetimes tied to the receiver
235
+ this->checkKeepAlive(self, result, rubyValues);
236
+
237
+ return result;
238
+ }
239
+ catch (...)
240
+ {
241
+ RUBY_TRY
242
+ {
243
+ return this->handler_->handle_exception();
244
+ }
245
+ RUBY_CATCH
246
+ }
247
+ }
248
+ }
@@ -0,0 +1,39 @@
1
+ #ifndef Rice__detail__ruby_function__hpp_
2
+ #define Rice__detail__ruby_function__hpp_
3
+
4
+ #include "ruby.hpp"
5
+
6
+ namespace Rice::detail
7
+ {
8
+ /* This is functor class that wraps calls to a Ruby C API method. It is needed because
9
+ rb_protect only supports calling methods that take one argument. Thus
10
+ we invoke rb_protect telling it to invoke Ruby_Function::call with an
11
+ instance of a Ruby_Function. That instance then in turn calls the original
12
+ Ruby method passing along its required arguments. */
13
+
14
+ template<typename Function_T, typename Return_T, typename...Arg_Ts>
15
+ class RubyFunction
16
+ {
17
+ public:
18
+ RubyFunction(Function_T func, const Arg_Ts&... args);
19
+ Return_T operator()();
20
+
21
+ private:
22
+ Function_T func_;
23
+ std::tuple<Arg_Ts...> args_;
24
+ };
25
+
26
+ template<typename Return_T, typename ...Arg_Ts>
27
+ Return_T protect(Return_T(*func)(Arg_Ts...), Arg_Ts...args);
28
+ }
29
+
30
+ namespace Rice
31
+ {
32
+ template<typename Return_T, typename ...Arg_Ts>
33
+ [[deprecated("Please use detail::protect")]]
34
+ Return_T protect(Return_T(*func)(Arg_Ts...), Arg_Ts...args);
35
+ }
36
+
37
+ #include "RubyFunction.ipp"
38
+
39
+ #endif // Rice__detail__ruby_function__hpp_
@@ -0,0 +1,92 @@
1
+ #include "Jump_Tag.hpp"
2
+ #include "../Exception_defn.hpp"
3
+
4
+ #include <any>
5
+
6
+ namespace Rice::detail
7
+ {
8
+ template<typename Function_T, typename Return_T, typename...Arg_Ts>
9
+ inline RubyFunction<Function_T, Return_T, Arg_Ts...>::RubyFunction(Function_T func, const Arg_Ts&... args)
10
+ : func_(func), args_(std::forward_as_tuple(args...))
11
+ {
12
+ }
13
+
14
+ template<typename Function_T, typename Return_T, typename...Arg_Ts>
15
+ inline Return_T RubyFunction<Function_T, Return_T, Arg_Ts...>::operator()()
16
+ {
17
+ const int TAG_RAISE = 0x6; // From Ruby header files
18
+ int state = 0;
19
+
20
+ // Setup a thread local variable to capture the result of the Ruby function call.
21
+ // We use thread_local because the lambda has to be captureless so it can
22
+ // be converted to a function pointer callable by C.
23
+ // The thread local variable avoids having to cast the result to VALUE and then
24
+ // back again to Return_T. The problem with that is the translation is not lossless
25
+ // in some cases - for example a double with value of -1.0 does not roundrip.
26
+ //
27
+ thread_local std::any result;
28
+
29
+ // Callback that will invoke the Ruby function
30
+ using Functor_T = RubyFunction<Function_T, Return_T, Arg_Ts...>;
31
+ auto callback = [](VALUE value)
32
+ {
33
+ Functor_T* functor = (Functor_T*)value;
34
+
35
+ if constexpr (std::is_same_v<Return_T, void>)
36
+ {
37
+ std::apply(functor->func_, functor->args_);
38
+ }
39
+ else
40
+ {
41
+ result = std::apply(functor->func_, functor->args_);
42
+ }
43
+
44
+ return Qnil;
45
+ };
46
+
47
+ // Now call rb_protect which will invoke the callback lambda above
48
+ rb_protect(callback, (VALUE)this, &state);
49
+
50
+ // Did anything go wrong?
51
+ if (state == 0)
52
+ {
53
+ if constexpr (!std::is_same_v<Return_T, void>)
54
+ {
55
+ return std::any_cast<Return_T>(result);
56
+ }
57
+ }
58
+ else
59
+ {
60
+ VALUE err = rb_errinfo();
61
+ if (state == TAG_RAISE && RTEST(err))
62
+ {
63
+ rb_set_errinfo(Qnil);
64
+ throw Rice::Exception(err);
65
+ }
66
+ else
67
+ {
68
+ throw Jump_Tag(state);
69
+ }
70
+ }
71
+ }
72
+
73
+ // Create a functor for calling a Ruby function and define some aliases for readability.
74
+ template<typename Return_T, typename ...Arg_Ts>
75
+ inline Return_T protect(Return_T(*func)(Arg_Ts...), Arg_Ts...args)
76
+ {
77
+ using Function_T = Return_T(*)(Arg_Ts...);
78
+ auto rubyFunction = RubyFunction<Function_T, Return_T, Arg_Ts...>(func, args...);
79
+ return rubyFunction();
80
+ }
81
+ }
82
+
83
+ namespace Rice
84
+ {
85
+ template<typename Return_T, typename ...Arg_Ts>
86
+ inline Return_T protect(Return_T(*func)(Arg_Ts...), Arg_Ts...args)
87
+ {
88
+ using Function_T = Return_T(*)(Arg_Ts...);
89
+ auto rubyFunction = detail::RubyFunction<Function_T, Return_T, Arg_Ts...>(func, args...);
90
+ return rubyFunction();
91
+ }
92
+ }
@@ -0,0 +1,29 @@
1
+ #ifndef Rice__Type__hpp_
2
+ #define Rice__Type__hpp_
3
+
4
+ #include <string>
5
+ #include <typeinfo>
6
+ #include "rice_traits.hpp"
7
+
8
+ namespace Rice::detail
9
+ {
10
+ template<typename T>
11
+ struct Type
12
+ {
13
+ static bool verify();
14
+ };
15
+
16
+ // Return the name of a type
17
+ std::string typeName(const std::type_info& typeInfo);
18
+ std::string makeClassName(const std::type_info& typeInfo);
19
+
20
+ template<typename T>
21
+ void verifyType();
22
+
23
+ template<typename Tuple_T>
24
+ void verifyTypes();
25
+ }
26
+
27
+ #include "Type.ipp"
28
+
29
+ #endif // Rice__Type__hpp_
@@ -0,0 +1,138 @@
1
+ #include "rice_traits.hpp"
2
+
3
+ #include <iosfwd>
4
+ #include <numeric>
5
+ #include <regex>
6
+ #include <sstream>
7
+ #include <tuple>
8
+
9
+ #ifdef __GNUC__
10
+ #include <cxxabi.h>
11
+ #include <cstdlib>
12
+ #include <cstring>
13
+ #endif
14
+
15
+ namespace Rice::detail
16
+ {
17
+ template<>
18
+ struct Type<void>
19
+ {
20
+ static bool verify()
21
+ {
22
+ return true;
23
+ }
24
+ };
25
+
26
+ template<typename T>
27
+ void verifyType()
28
+ {
29
+ Type<intrinsic_type<T>>::verify();
30
+ }
31
+
32
+ template<typename Tuple_T, size_t...Is>
33
+ void verifyTypesImpl()
34
+ {
35
+ (Type<intrinsic_type<typename std::tuple_element<Is, Tuple_T>::type>>::verify(), ...);
36
+ }
37
+
38
+ template<typename Tuple_T>
39
+ void verifyTypes()
40
+ {
41
+ if constexpr (std::tuple_size<Tuple_T>::value > 0)
42
+ {
43
+ verifyTypesImpl<Tuple_T, std::tuple_size<Tuple_T>::value - 1>();
44
+ }
45
+ }
46
+
47
+ inline std::string demangle(char const* mangled_name)
48
+ {
49
+ #ifdef __GNUC__
50
+ struct Helper
51
+ {
52
+ Helper(
53
+ char const* mangled_name)
54
+ : name_(0)
55
+ {
56
+ int status = 0;
57
+ name_ = abi::__cxa_demangle(mangled_name, 0, 0, &status);
58
+ }
59
+
60
+ ~Helper()
61
+ {
62
+ std::free(name_);
63
+ }
64
+
65
+ char* name_;
66
+
67
+ private:
68
+ Helper(Helper const&);
69
+ void operator=(Helper const&);
70
+ };
71
+
72
+ Helper helper(mangled_name);
73
+ if (helper.name_)
74
+ {
75
+ return helper.name_;
76
+ }
77
+ else
78
+ {
79
+ return mangled_name;
80
+ }
81
+ #else
82
+ return mangled_name;
83
+ #endif
84
+ }
85
+
86
+ inline std::string typeName(const std::type_info& typeInfo)
87
+ {
88
+ return demangle(typeInfo.name());
89
+ }
90
+
91
+ inline std::string makeClassName(const std::type_info& typeInfo)
92
+ {
93
+ std::string base = demangle(typeInfo.name());
94
+
95
+ // Remove class keyword
96
+ auto classRegex = std::regex("class +");
97
+ base = std::regex_replace(base, classRegex, "");
98
+
99
+ // Remove struct keyword
100
+ auto structRegex = std::regex("struct +");
101
+ base = std::regex_replace(base, structRegex, "");
102
+
103
+ // Remove std::__[^:]*::
104
+ auto stdClangRegex = std::regex("std::__[^:]+::");
105
+ base = std::regex_replace(base, stdClangRegex, "");
106
+
107
+ // Remove std::
108
+ auto stdRegex = std::regex("std::");
109
+ base = std::regex_replace(base, stdRegex, "");
110
+
111
+ // Replace > >
112
+ auto trailingAngleBracketSpaceRegex = std::regex(" >");
113
+ base = std::regex_replace(base, trailingAngleBracketSpaceRegex, ">");
114
+
115
+ // Replace < and >
116
+ auto angleBracketRegex = std::regex("<|>");
117
+ base = std::regex_replace(base, angleBracketRegex, "__");
118
+
119
+ // Replace ,
120
+ auto commaRegex = std::regex(", *");
121
+ base = std::regex_replace(base, commaRegex, "_");
122
+
123
+ // Now create a vector of strings split on whitespace
124
+ std::istringstream stream(base);
125
+ std::vector<std::string> words{ std::istream_iterator<std::string>{stream},
126
+ std::istream_iterator<std::string>{} };
127
+
128
+ std::string result = std::accumulate(words.begin(), words.end(), std::string(),
129
+ [](const std::string& memo, const std::string& word) -> std::string
130
+ {
131
+ std::string capitalized = word;
132
+ capitalized[0] = toupper(capitalized[0]);
133
+ return memo + capitalized;
134
+ });
135
+
136
+ return result;
137
+ }
138
+ }