rice 3.0.0 → 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }