rice 4.3.3 → 4.6.0

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 (237) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -26
  3. data/CMakeLists.txt +31 -0
  4. data/CMakePresets.json +75 -0
  5. data/COPYING +3 -2
  6. data/FindRuby.cmake +437 -0
  7. data/README.md +7 -2
  8. data/Rakefile +12 -5
  9. data/include/rice/rice.hpp +9522 -4426
  10. data/include/rice/stl.hpp +2831 -1198
  11. data/lib/make_rice_headers.rb +79 -0
  12. data/lib/mkmf-rice.rb +40 -94
  13. data/lib/rice/version.rb +3 -0
  14. data/lib/rice.rb +1 -0
  15. data/lib/rubygems/builder.rb +11 -0
  16. data/lib/rubygems/cmake_builder.rb +113 -0
  17. data/lib/rubygems_plugin.rb +9 -0
  18. data/rice/Address_Registration_Guard.hpp +72 -3
  19. data/rice/Arg.hpp +26 -6
  20. data/rice/Arg.ipp +35 -2
  21. data/rice/Buffer.hpp +123 -0
  22. data/rice/Buffer.ipp +599 -0
  23. data/rice/Callback.hpp +21 -0
  24. data/rice/Callback.ipp +13 -0
  25. data/rice/Constructor.hpp +4 -27
  26. data/rice/Constructor.ipp +79 -0
  27. data/rice/Data_Object.hpp +73 -3
  28. data/rice/Data_Object.ipp +388 -96
  29. data/rice/Data_Type.hpp +214 -3
  30. data/rice/Data_Type.ipp +144 -67
  31. data/rice/Director.hpp +0 -2
  32. data/rice/Enum.hpp +4 -7
  33. data/rice/Enum.ipp +102 -55
  34. data/rice/Exception.hpp +62 -2
  35. data/rice/Exception.ipp +7 -12
  36. data/rice/Init.hpp +8 -0
  37. data/rice/Init.ipp +8 -0
  38. data/rice/JumpException.hpp +44 -0
  39. data/rice/JumpException.ipp +48 -0
  40. data/rice/MemoryView.hpp +11 -0
  41. data/rice/MemoryView.ipp +3 -0
  42. data/rice/Return.hpp +7 -27
  43. data/rice/Return.ipp +13 -13
  44. data/rice/cpp_api/Array.hpp +209 -0
  45. data/rice/cpp_api/Array.ipp +304 -0
  46. data/rice/cpp_api/Builtin_Object.hpp +31 -0
  47. data/rice/cpp_api/Builtin_Object.ipp +37 -0
  48. data/rice/cpp_api/Class.hpp +70 -0
  49. data/rice/cpp_api/Class.ipp +97 -0
  50. data/rice/cpp_api/Encoding.hpp +32 -0
  51. data/rice/cpp_api/Encoding.ipp +59 -0
  52. data/rice/cpp_api/Hash.hpp +194 -0
  53. data/rice/cpp_api/Hash.ipp +257 -0
  54. data/rice/{Identifier.hpp → cpp_api/Identifier.hpp} +2 -6
  55. data/rice/{Identifier.ipp → cpp_api/Identifier.ipp} +4 -2
  56. data/rice/cpp_api/Module.hpp +72 -0
  57. data/rice/cpp_api/Module.ipp +101 -0
  58. data/rice/cpp_api/Object.hpp +272 -0
  59. data/rice/cpp_api/Object.ipp +235 -0
  60. data/rice/cpp_api/String.hpp +74 -0
  61. data/rice/cpp_api/String.ipp +120 -0
  62. data/rice/cpp_api/Struct.hpp +113 -0
  63. data/rice/cpp_api/Struct.ipp +92 -0
  64. data/rice/cpp_api/Symbol.hpp +46 -0
  65. data/rice/cpp_api/Symbol.ipp +93 -0
  66. data/rice/cpp_api/shared_methods.hpp +134 -0
  67. data/rice/detail/DefaultHandler.hpp +12 -0
  68. data/rice/detail/DefaultHandler.ipp +8 -0
  69. data/rice/detail/HandlerRegistry.hpp +5 -35
  70. data/rice/detail/HandlerRegistry.ipp +7 -11
  71. data/rice/detail/InstanceRegistry.hpp +1 -4
  72. data/rice/detail/MethodInfo.hpp +12 -10
  73. data/rice/detail/MethodInfo.ipp +26 -21
  74. data/rice/detail/Native.hpp +33 -0
  75. data/rice/detail/Native.ipp +157 -0
  76. data/rice/detail/NativeAttributeGet.hpp +52 -0
  77. data/rice/detail/NativeAttributeGet.ipp +57 -0
  78. data/rice/detail/NativeAttributeSet.hpp +44 -0
  79. data/rice/detail/NativeAttributeSet.ipp +88 -0
  80. data/rice/detail/NativeCallbackFFI.hpp +55 -0
  81. data/rice/detail/NativeCallbackFFI.ipp +151 -0
  82. data/rice/detail/NativeCallbackSimple.hpp +30 -0
  83. data/rice/detail/NativeCallbackSimple.ipp +29 -0
  84. data/rice/detail/NativeFunction.hpp +33 -23
  85. data/rice/detail/NativeFunction.ipp +309 -70
  86. data/rice/detail/NativeIterator.hpp +9 -11
  87. data/rice/detail/NativeIterator.ipp +33 -31
  88. data/rice/detail/NativeRegistry.hpp +24 -15
  89. data/rice/detail/NativeRegistry.ipp +23 -48
  90. data/rice/detail/Proc.hpp +4 -0
  91. data/rice/detail/Proc.ipp +85 -0
  92. data/rice/detail/Registries.hpp +0 -7
  93. data/rice/detail/Registries.ipp +0 -18
  94. data/rice/detail/RubyFunction.hpp +0 -3
  95. data/rice/detail/RubyFunction.ipp +4 -8
  96. data/rice/detail/RubyType.hpp +16 -0
  97. data/rice/detail/RubyType.ipp +232 -0
  98. data/rice/detail/Type.hpp +7 -6
  99. data/rice/detail/Type.ipp +192 -45
  100. data/rice/detail/TypeRegistry.hpp +15 -7
  101. data/rice/detail/TypeRegistry.ipp +105 -12
  102. data/rice/detail/Wrapper.hpp +68 -32
  103. data/rice/detail/Wrapper.ipp +121 -109
  104. data/rice/detail/cpp_protect.hpp +5 -6
  105. data/rice/detail/default_allocation_func.ipp +0 -2
  106. data/rice/detail/from_ruby.hpp +38 -3
  107. data/rice/detail/from_ruby.ipp +1321 -492
  108. data/rice/detail/ruby.hpp +18 -0
  109. data/rice/detail/to_ruby.hpp +41 -3
  110. data/rice/detail/to_ruby.ipp +1424 -194
  111. data/rice/global_function.hpp +0 -4
  112. data/rice/global_function.ipp +0 -1
  113. data/rice/libc/file.hpp +11 -0
  114. data/rice/libc/file.ipp +32 -0
  115. data/rice/rice.hpp +116 -26
  116. data/rice/ruby_mark.hpp +4 -3
  117. data/rice/stl/complex.hpp +6 -0
  118. data/rice/stl/complex.ipp +93 -0
  119. data/rice/stl/exception.hpp +11 -0
  120. data/rice/stl/exception.ipp +29 -0
  121. data/rice/stl/exception_ptr.hpp +6 -0
  122. data/rice/stl/exception_ptr.ipp +27 -0
  123. data/rice/stl/map.hpp +12 -0
  124. data/rice/stl/map.ipp +469 -0
  125. data/rice/stl/monostate.hpp +6 -0
  126. data/rice/stl/monostate.ipp +80 -0
  127. data/rice/stl/multimap.hpp +14 -0
  128. data/rice/stl/multimap.ipp +448 -0
  129. data/rice/stl/optional.hpp +6 -0
  130. data/rice/stl/optional.ipp +118 -0
  131. data/rice/stl/pair.hpp +13 -0
  132. data/rice/stl/pair.ipp +155 -0
  133. data/rice/stl/reference_wrapper.hpp +6 -0
  134. data/rice/stl/reference_wrapper.ipp +41 -0
  135. data/rice/stl/set.hpp +12 -0
  136. data/rice/stl/set.ipp +495 -0
  137. data/rice/stl/shared_ptr.hpp +28 -0
  138. data/rice/stl/shared_ptr.ipp +224 -0
  139. data/rice/stl/string.hpp +6 -0
  140. data/rice/stl/string.ipp +158 -0
  141. data/rice/stl/string_view.hpp +6 -0
  142. data/rice/stl/string_view.ipp +65 -0
  143. data/rice/stl/tuple.hpp +6 -0
  144. data/rice/stl/tuple.ipp +128 -0
  145. data/rice/stl/type_index.hpp +6 -0
  146. data/rice/stl/type_index.ipp +30 -0
  147. data/rice/stl/type_info.hpp +6 -0
  148. data/rice/stl/type_info.ipp +29 -0
  149. data/rice/stl/unique_ptr.hpp +22 -0
  150. data/rice/stl/unique_ptr.ipp +139 -0
  151. data/rice/stl/unordered_map.hpp +12 -0
  152. data/rice/stl/unordered_map.ipp +469 -0
  153. data/rice/stl/variant.hpp +6 -0
  154. data/rice/stl/variant.ipp +242 -0
  155. data/rice/stl/vector.hpp +12 -0
  156. data/rice/stl/vector.ipp +590 -0
  157. data/rice/stl.hpp +11 -3
  158. data/rice/traits/attribute_traits.hpp +26 -0
  159. data/rice/traits/function_traits.hpp +95 -0
  160. data/rice/traits/method_traits.hpp +47 -0
  161. data/rice/traits/rice_traits.hpp +160 -0
  162. data/rice.gemspec +85 -0
  163. data/test/embed_ruby.cpp +7 -1
  164. data/test/extconf.rb +2 -0
  165. data/test/test_Address_Registration_Guard.cpp +5 -0
  166. data/test/test_Array.cpp +18 -4
  167. data/test/test_Attribute.cpp +136 -21
  168. data/test/test_Buffer.cpp +285 -0
  169. data/test/test_Builtin_Object.cpp +5 -0
  170. data/test/test_Callback.cpp +230 -0
  171. data/test/test_Class.cpp +5 -31
  172. data/test/test_Constructor.cpp +69 -6
  173. data/test/test_Data_Object.cpp +97 -38
  174. data/test/test_Data_Type.cpp +470 -65
  175. data/test/test_Director.cpp +17 -8
  176. data/test/test_Enum.cpp +155 -40
  177. data/test/test_Exception.cpp +235 -0
  178. data/test/test_File.cpp +70 -0
  179. data/test/test_From_Ruby.cpp +609 -0
  180. data/test/test_Hash.cpp +5 -0
  181. data/test/test_Identifier.cpp +5 -0
  182. data/test/test_Inheritance.cpp +6 -1
  183. data/test/test_Iterator.cpp +6 -1
  184. data/test/test_Jump_Exception.cpp +23 -0
  185. data/test/test_Keep_Alive.cpp +13 -19
  186. data/test/test_Keep_Alive_No_Wrapper.cpp +5 -1
  187. data/test/test_Memory_Management.cpp +5 -0
  188. data/test/test_Module.cpp +128 -67
  189. data/test/test_Native_Registry.cpp +2 -34
  190. data/test/test_Object.cpp +5 -0
  191. data/test/test_Overloads.cpp +806 -0
  192. data/test/test_Ownership.cpp +160 -54
  193. data/test/test_Proc.cpp +44 -0
  194. data/test/test_Self.cpp +9 -4
  195. data/test/test_Stl_Exception.cpp +109 -0
  196. data/test/test_Stl_Map.cpp +54 -42
  197. data/test/test_Stl_Multimap.cpp +693 -0
  198. data/test/test_Stl_Optional.cpp +5 -0
  199. data/test/test_Stl_Pair.cpp +14 -9
  200. data/test/test_Stl_Reference_Wrapper.cpp +9 -2
  201. data/test/test_Stl_Set.cpp +790 -0
  202. data/test/test_Stl_SharedPtr.cpp +458 -0
  203. data/test/test_Stl_String.cpp +5 -0
  204. data/test/test_Stl_String_View.cpp +5 -0
  205. data/test/test_Stl_Tuple.cpp +116 -0
  206. data/test/test_Stl_Type.cpp +147 -0
  207. data/test/test_Stl_UniquePtr.cpp +202 -0
  208. data/test/test_Stl_Unordered_Map.cpp +43 -38
  209. data/test/test_Stl_Variant.cpp +217 -84
  210. data/test/test_Stl_Vector.cpp +306 -58
  211. data/test/test_String.cpp +5 -0
  212. data/test/test_Struct.cpp +5 -0
  213. data/test/test_Symbol.cpp +5 -0
  214. data/test/test_Template.cpp +192 -0
  215. data/test/test_To_Ruby.cpp +524 -0
  216. data/test/test_Tracking.cpp +1 -0
  217. data/test/test_Type.cpp +171 -0
  218. data/test/test_global_functions.cpp +67 -7
  219. data/test/unittest.cpp +8 -0
  220. metadata +127 -26
  221. data/lib/version.rb +0 -3
  222. data/rice/Address_Registration_Guard_defn.hpp +0 -79
  223. data/rice/Data_Object_defn.hpp +0 -84
  224. data/rice/Data_Type_defn.hpp +0 -190
  225. data/rice/Exception_defn.hpp +0 -68
  226. data/rice/HandlerRegistration.hpp +0 -15
  227. data/rice/detail/ExceptionHandler.hpp +0 -8
  228. data/rice/detail/ExceptionHandler.ipp +0 -28
  229. data/rice/detail/ExceptionHandler_defn.hpp +0 -77
  230. data/rice/detail/Jump_Tag.hpp +0 -21
  231. data/rice/detail/NativeAttribute.hpp +0 -64
  232. data/rice/detail/NativeAttribute.ipp +0 -112
  233. data/rice/detail/from_ruby_defn.hpp +0 -38
  234. data/rice/detail/to_ruby_defn.hpp +0 -48
  235. data/test/test_Jump_Tag.cpp +0 -17
  236. data/test/test_Stl_SmartPointer.cpp +0 -283
  237. data/test/test_To_From_Ruby.cpp +0 -399
@@ -1,51 +1,21 @@
1
1
  #ifndef Rice__detail__HandlerRegistry__hpp_
2
2
  #define Rice__detail__HandlerRegistry__hpp_
3
3
 
4
- #include "ExceptionHandler.hpp"
4
+ #include <functional>
5
5
 
6
6
  namespace Rice::detail
7
7
  {
8
8
  class HandlerRegistry
9
9
  {
10
10
  public:
11
- //! Define an exception handler.
12
- /*! Whenever an exception of type Exception_T is thrown from a
13
- * function defined on this class, the supplied functor will be called to
14
- * translate the exception into a ruby exception.
15
- * \param Exception_T a template parameter indicating the type of
16
- * exception to be translated.
17
- * \param functor a functor to be called to translate the exception
18
- * into a ruby exception. This functor should re-throw the exception
19
- * as an Exception.
20
- * Example:
21
- * \code
22
- * Class rb_cFoo;
23
- *
24
- * void translate_my_exception(MyException const& ex)
25
- * {
26
- * throw Rice::Exception(rb_eRuntimeError, ex.what_without_backtrace());
27
- * }
28
- *
29
- * extern "C"
30
- * void Init_MyExtension()
31
- * {
32
- * rb_cFoo = define_class("Foo");
33
- * register_handler<MyException>(translate_my_exception);
34
- * }
35
- * \endcode
36
- */
37
- template<typename Exception_T, typename Functor_T>
38
- HandlerRegistry& add(Functor_T functor);
39
-
40
- std::shared_ptr<detail::ExceptionHandler> handler() const;
11
+ HandlerRegistry();
12
+ void set(std::function<void()> handler);
13
+ std::function<void()> handler() const;
41
14
 
42
15
  private:
43
- mutable std::shared_ptr<detail::ExceptionHandler> handler_ = std::make_shared<Rice::detail::DefaultExceptionHandler>();
44
-
16
+ std::function<void()> handler_;
45
17
  };
46
18
  } // namespace Rice::detail
47
19
 
48
- #include "HandlerRegistry.ipp"
49
-
50
20
  #endif // Rice__detail__HandlerRegistry__hpp_
51
21
 
@@ -1,20 +1,16 @@
1
- #include <memory>
2
-
3
1
  namespace Rice::detail
4
2
  {
5
- template<typename Exception_T, typename Functor_T>
6
- inline HandlerRegistry& HandlerRegistry::add(Functor_T functor)
3
+ inline HandlerRegistry::HandlerRegistry() : handler_(DefaultHandler())
7
4
  {
8
- // Create a new exception handler and pass ownership of the current handler to it (they
9
- // get chained together). Then take ownership of the new handler.
10
- this->handler_ = std::make_shared<detail::CustomExceptionHandler<Exception_T, Functor_T>>(
11
- functor, std::move(this->handler_));
5
+ }
12
6
 
13
- return *this;
7
+ inline void HandlerRegistry::set(std::function<void()> handler)
8
+ {
9
+ this->handler_ = handler;
14
10
  }
15
11
 
16
- inline std::shared_ptr<detail::ExceptionHandler> HandlerRegistry::handler() const
12
+ inline std::function<void()> HandlerRegistry::handler() const
17
13
  {
18
14
  return this->handler_;
19
15
  }
20
- } // namespace
16
+ }
@@ -2,7 +2,6 @@
2
2
  #define Rice__detail__InstanceRegistry__hpp_
3
3
 
4
4
  #include <map>
5
- #include "ruby.hpp"
6
5
 
7
6
  namespace Rice::detail
8
7
  {
@@ -14,6 +13,7 @@ namespace Rice::detail
14
13
 
15
14
  template <typename T>
16
15
  VALUE lookup(T* cppInstance);
16
+ VALUE lookup(void* cppInstance);
17
17
 
18
18
  void add(void* cppInstance, VALUE rubyInstance);
19
19
  void remove(void* cppInstance);
@@ -23,12 +23,9 @@ namespace Rice::detail
23
23
  bool isEnabled = false;
24
24
 
25
25
  private:
26
- VALUE lookup(void* cppInstance);
27
26
  std::map<void*, VALUE> objectMap_;
28
27
  };
29
28
  } // namespace Rice::detail
30
29
 
31
- #include "InstanceRegistry.ipp"
32
-
33
30
  #endif // Rice__detail__InstanceRegistry__hpp_
34
31
 
@@ -2,29 +2,33 @@
2
2
  #define Rice__MethodInfo__hpp_
3
3
 
4
4
  #include <vector>
5
- #include "../Arg.hpp"
6
- #include "../Return.hpp"
7
5
 
8
6
  namespace Rice
9
7
  {
10
8
  class MethodInfo
11
9
  {
12
10
  public:
11
+ MethodInfo() = default;
12
+
13
13
  template <typename...Arg_Ts>
14
14
  MethodInfo(size_t argCount, const Arg_Ts&...args);
15
15
 
16
16
  /**
17
- * Get the rb_scan_args format string for this
18
- * list of arguments.
17
+ * Add a defined Arg to this list of Arguments
19
18
  */
20
- std::string formatString();
19
+ void addArg(const Arg& arg);
21
20
 
22
21
  /**
23
- * Add a defined Arg to this list of Arguments
22
+ * Get argument by position
24
23
  */
25
- void addArg(const Arg& arg);
24
+ Arg* arg(size_t pos);
26
25
 
27
- Arg& arg(size_t pos);
26
+ /**
27
+ * Get argument by name
28
+ */
29
+ Arg* arg(std::string name);
30
+
31
+ int argCount();
28
32
 
29
33
  // Iterator support
30
34
  std::vector<Arg>::iterator begin();
@@ -39,6 +43,4 @@ namespace Rice
39
43
  std::vector<Arg> args_;
40
44
  };
41
45
  }
42
- #include "MethodInfo.ipp"
43
-
44
46
  #endif // Rice__MethodInfo__hpp_
@@ -1,5 +1,4 @@
1
1
  #include <sstream>
2
- #include "from_ruby_defn.hpp"
3
2
 
4
3
  namespace Rice
5
4
  {
@@ -26,13 +25,15 @@ namespace Rice
26
25
  template <typename Arg_T>
27
26
  inline void MethodInfo::processArg(const Arg_T& arg)
28
27
  {
29
- if constexpr (std::is_same_v<Arg_T, Arg>)
28
+ static_assert(std::is_same_v<Arg_T, Return> || std::is_same_v<Arg_T, Arg>, "Unknown argument type");
29
+
30
+ if constexpr (std::is_same_v<Arg_T, Return>)
30
31
  {
31
- this->addArg(arg);
32
+ this->returnInfo = arg;
32
33
  }
33
- else
34
+ else if constexpr (std::is_same_v<Arg_T, Arg>)
34
35
  {
35
- this->returnInfo = arg;
36
+ this->addArg(arg);
36
37
  }
37
38
  }
38
39
 
@@ -41,29 +42,33 @@ namespace Rice
41
42
  this->args_.push_back(arg);
42
43
  }
43
44
 
44
- inline std::string MethodInfo::formatString()
45
+ inline int MethodInfo::argCount()
45
46
  {
46
- size_t required = 0;
47
- size_t optional = 0;
47
+ return this->args_.size();
48
+ }
48
49
 
49
- for (const Arg& arg : this->args_)
50
+ inline Arg* MethodInfo::arg(size_t pos)
51
+ {
52
+ if (pos < this->args_.size())
50
53
  {
51
- if (arg.hasDefaultValue())
52
- {
53
- optional++;
54
- }
55
- else
56
- {
57
- required++;
58
- }
54
+ return &this->args_[pos];
55
+ }
56
+ else
57
+ {
58
+ return nullptr;
59
59
  }
60
-
61
- return std::to_string(required) + std::to_string(optional);
62
60
  }
63
61
 
64
- inline Arg& MethodInfo::arg(size_t pos)
62
+ inline Arg* MethodInfo::arg(std::string name)
65
63
  {
66
- return args_[pos];
64
+ for (Arg& arg : this->args_)
65
+ {
66
+ if (arg.name == name)
67
+ {
68
+ return &arg;
69
+ }
70
+ }
71
+ return nullptr;
67
72
  }
68
73
 
69
74
  inline std::vector<Arg>::iterator MethodInfo::begin()
@@ -0,0 +1,33 @@
1
+ #ifndef Rice__detail__Native__hpp_
2
+ #define Rice__detail__Native__hpp_
3
+
4
+ namespace Rice::detail
5
+ {
6
+ class Native;
7
+
8
+ class Resolved
9
+ {
10
+ public:
11
+ inline bool operator<(Resolved other);
12
+ inline bool operator>(Resolved other);
13
+
14
+ Convertible convertible;
15
+ double parameterMatch;
16
+ Native* native;
17
+ };
18
+
19
+ class Native
20
+ {
21
+ public:
22
+ static VALUE resolve(int argc, VALUE* argv, VALUE self);
23
+ public:
24
+ virtual ~Native() = default;
25
+ VALUE call(int argc, VALUE* argv, VALUE self);
26
+
27
+ virtual Resolved matches(size_t argc, const VALUE* argv, VALUE self) = 0;
28
+ virtual VALUE operator()(size_t argc, const VALUE* argv, VALUE self) = 0;
29
+ virtual std::string toString() = 0;
30
+ };
31
+ }
32
+
33
+ #endif // Rice__detail__Native__hpp_
@@ -0,0 +1,157 @@
1
+
2
+ namespace Rice::detail
3
+ {
4
+ inline bool Resolved::operator<(Resolved other)
5
+ {
6
+ if (this->convertible != other.convertible)
7
+ {
8
+ return this->convertible < other.convertible;
9
+ }
10
+ else
11
+ {
12
+ return this->parameterMatch < other.parameterMatch;
13
+ }
14
+ }
15
+
16
+ inline bool Resolved::operator>(Resolved other)
17
+ {
18
+ if (this->convertible != other.convertible)
19
+ {
20
+ return this->convertible > other.convertible;
21
+ }
22
+ else
23
+ {
24
+ return this->parameterMatch > other.parameterMatch;
25
+ }
26
+ }
27
+
28
+ inline VALUE Native::resolve(int argc, VALUE* argv, VALUE self)
29
+ {
30
+ /* This method is called from Ruby and is responsible for determining the correct
31
+ Native object (ie, NativeFunction, NativeIterator, NativeAttributeGet and
32
+ NativeAttributeSet) that shoudl be used to invoke the underlying C++ code.
33
+ Most of the time there will be a single Native object registered for a C++ function,
34
+ method, constructor, iterator or attribute. However, there can be multiple Natives
35
+ when a C++ function/method/construtor is overloaded.
36
+
37
+ In that case, the code iterates over each Native and calls its matches method. The matches
38
+ method returns a Resolved object which includes a Convertible field and parameterMatch field.
39
+ The Convertible field is an enum that specifies if the types of the values supplied by Ruby
40
+ match the types of the C++ function parameters. Allowed values include can be Exact (example Ruby into to C++ int),
41
+ TypeCast (example Ruby into to C++ float) or None (cannot be converted).
42
+
43
+ The parameterMatch field is simply the number or arguments provided by Ruby divided by the
44
+ number of arguments required by C++. These numbers can be different because C++ method
45
+ parameters can have default values.
46
+
47
+ Taking these two values into account, the method sorts the Natives and picks the one with the
48
+ highest score (Convertible::Exact and 1.0 for parameterMatch). Thus given these two C++ functions:
49
+
50
+ void some_method(int a);
51
+ void some_mtehod(int a, float b = 2.0).
52
+
53
+ A call from ruby of some_method(1) will exactly match both signatures, but the first one
54
+ will be chosen because the parameterMatch will be 1.0 for the first overload but 0.5
55
+ for the second. */
56
+
57
+ Native* native = nullptr;
58
+
59
+ ID methodId;
60
+ VALUE klass;
61
+ if (!rb_frame_method_id_and_class(&methodId, &klass))
62
+ {
63
+ rb_raise(rb_eRuntimeError, "Cannot get method id and class for function");
64
+ }
65
+
66
+ // Execute the function but make sure to catch any C++ exceptions!
67
+ return cpp_protect([&]
68
+ {
69
+ Identifier id(methodId);
70
+ std::string methodName = id.str();
71
+ std::string className = rb_class2name(klass);
72
+
73
+ const std::vector<std::unique_ptr<Native>>& natives = Registries::instance.natives.lookup(klass, methodId);
74
+
75
+ if (natives.size() == 1)
76
+ {
77
+ native = natives.front().get();
78
+ }
79
+ else if (natives.size() == 0)
80
+ {
81
+ Identifier identifier(methodId);
82
+ rb_raise(rb_eArgError, "Could not find method call for %s#%s", rb_class2name(klass), identifier.c_str());
83
+ }
84
+ else
85
+ {
86
+ Identifier identifier(methodId);
87
+
88
+ // Loop over every native to see how well they match the Ruby parameters
89
+ std::vector<Resolved> resolves;
90
+ std::transform(natives.begin(), natives.end(),
91
+ std::back_inserter(resolves),
92
+ [&](const std::unique_ptr<Native>& native)
93
+ {
94
+ return native->matches(argc, argv, self);
95
+ });
96
+
97
+ // Now sort from best to worst
98
+ std::sort(resolves.begin(), resolves.end(), std::greater{});
99
+
100
+ // Get the first one
101
+ Resolved resolved = resolves.front();
102
+
103
+ // Was there more than one match?
104
+ /*size_t count = std::count_if(resolves.begin(), resolves.end(),
105
+ [&resolved](Resolved& element)
106
+ {
107
+ return resolved.convertible == element.convertible;
108
+ });
109
+
110
+ if (count > 1)
111
+ {
112
+ std::ostringstream message;
113
+ message << "Could not resolve method call for %s#%s" << "\n"
114
+ << " %d overloaded functions matched based on the types of Ruby parameters provided:";
115
+
116
+ for (int i = 0; i < count; i++)
117
+ {
118
+ message << "\n " << resolves[i].native->toString();
119
+ }
120
+
121
+ rb_raise(rb_eArgError, message.str().c_str(), rb_class2name(klass), identifier.c_str(), count);
122
+ }*/
123
+
124
+ // Did it match?
125
+ if (resolved.convertible != Convertible::None)
126
+ {
127
+ native = resolved.native;
128
+ }
129
+ else
130
+ {
131
+ // Special case == to make the RubyMine debugger work. It calls == with a Module as
132
+ // the other argument, thus breaking if C++ operator== is implemented.
133
+ if (identifier.str() == "==")
134
+ {
135
+ return detail::protect(rb_call_super, argc, argv);
136
+ }
137
+ else
138
+ {
139
+ std::ostringstream message;
140
+ message << "Could not resolve method call for %s#%s" << "\n"
141
+ << " %d overload(s) were evaluated based on the types of Ruby parameters provided:";
142
+
143
+ for (Resolved& resolve: resolves)
144
+ {
145
+ message << "\n " << resolve.native->toString();
146
+ }
147
+
148
+ rb_raise(rb_eArgError, message.str().c_str(), rb_class2name(klass), identifier.c_str(), natives.size());
149
+ }
150
+ }
151
+ }
152
+
153
+ // Call the C++ function
154
+ return (*native)(argc, argv, self);
155
+ });
156
+ }
157
+ }
@@ -0,0 +1,52 @@
1
+ #ifndef Rice__detail__Native_Attribute_Get__hpp_
2
+ #define Rice__detail__Native_Attribute_Get__hpp_
3
+
4
+ namespace Rice
5
+ {
6
+ enum class AttrAccess
7
+ {
8
+ ReadWrite,
9
+ Read,
10
+ Write
11
+ };
12
+
13
+ namespace detail
14
+ {
15
+ template<typename Attribute_T>
16
+ class NativeAttributeGet: Native
17
+ {
18
+ public:
19
+ using NativeAttribute_T = NativeAttributeGet<Attribute_T>;
20
+
21
+ using T = typename attribute_traits<Attribute_T>::attr_type;
22
+ using Receiver_T = typename attribute_traits<Attribute_T>::class_type;
23
+ using To_Ruby_T = remove_cv_recursive_t<T>;
24
+
25
+ public:
26
+ // Register attribute getter with Ruby
27
+ static void define(VALUE klass, std::string name, Attribute_T attribute);
28
+
29
+ public:
30
+ // Disallow creating/copying/moving
31
+ NativeAttributeGet() = delete;
32
+ NativeAttributeGet(const NativeAttribute_T&) = delete;
33
+ NativeAttributeGet(NativeAttribute_T&&) = delete;
34
+ void operator=(const NativeAttribute_T&) = delete;
35
+ void operator=(NativeAttribute_T&&) = delete;
36
+
37
+ Resolved matches(size_t argc, const VALUE* argv, VALUE self) override;
38
+ VALUE operator()(size_t argc, const VALUE* argv, VALUE self) override;
39
+ std::string toString() override;
40
+
41
+ protected:
42
+ NativeAttributeGet(VALUE klass, std::string name, Attribute_T attr);
43
+
44
+ private:
45
+ VALUE klass_;
46
+ std::string name_;
47
+ Attribute_T attribute_;
48
+ };
49
+ } // detail
50
+ } // Rice
51
+
52
+ #endif // Rice__detail__Native_Attribute_Get__hpp_
@@ -0,0 +1,57 @@
1
+ #include <array>
2
+ #include <algorithm>
3
+
4
+
5
+ namespace Rice::detail
6
+ {
7
+ template<typename Attribute_T>
8
+ void NativeAttributeGet<Attribute_T>::define(VALUE klass, std::string name, Attribute_T attribute)
9
+ {
10
+ // Create a NativeAttributeGet that Ruby will call to read/write C++ variables
11
+ NativeAttribute_T* nativeAttribute = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute));
12
+ std::unique_ptr<Native> native(nativeAttribute);
13
+
14
+ detail::protect(rb_define_method, klass, name.c_str(), (RUBY_METHOD_FUNC)&Native::resolve, -1);
15
+
16
+ // Add to native registry. Since attributes cannot be overridden, there is no need to set the
17
+ // matches or calls function pointer. Instead Ruby can call the static call method defined on
18
+ // this class (&NativeAttribute_T::get).
19
+ Identifier identifier(name);
20
+ detail::Registries::instance.natives.add(klass, identifier.id(), native);
21
+ }
22
+
23
+ template<typename Attribute_T>
24
+ inline Resolved NativeAttributeGet<Attribute_T>::matches(size_t argc, const VALUE* argv, VALUE self)
25
+ {
26
+ if (argc == 0)
27
+ return Resolved { Convertible::Exact, 1, this };
28
+ else
29
+ return Resolved{ Convertible::None, 0, this };
30
+ }
31
+
32
+ template<typename Attribute_T>
33
+ NativeAttributeGet<Attribute_T>::NativeAttributeGet(VALUE klass, std::string name, Attribute_T attribute)
34
+ : klass_(klass), name_(name), attribute_(attribute)
35
+ {
36
+ }
37
+
38
+ template<typename Attribute_T>
39
+ inline VALUE NativeAttributeGet<Attribute_T>::operator()(size_t argc, const VALUE* argv, VALUE self)
40
+ {
41
+ if constexpr (std::is_member_object_pointer_v<Attribute_T>)
42
+ {
43
+ Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
44
+ return To_Ruby<To_Ruby_T>().convert(nativeSelf->*attribute_);
45
+ }
46
+ else
47
+ {
48
+ return To_Ruby<To_Ruby_T>().convert(*attribute_);
49
+ }
50
+ }
51
+
52
+ template<typename Attribute_T>
53
+ inline std::string NativeAttributeGet<Attribute_T>::toString()
54
+ {
55
+ return "";
56
+ }
57
+ } // Rice
@@ -0,0 +1,44 @@
1
+ #ifndef Rice__detail__Native_Attribute_Set__hpp_
2
+ #define Rice__detail__Native_Attribute_Set__hpp_
3
+
4
+ namespace Rice
5
+ {
6
+ namespace detail
7
+ {
8
+ template<typename Attribute_T>
9
+ class NativeAttributeSet: Native
10
+ {
11
+ public:
12
+ using NativeAttribute_T = NativeAttributeSet<Attribute_T>;
13
+ using Attr_T = typename attribute_traits<Attribute_T>::attr_type;
14
+ using T_Unqualified = remove_cv_recursive_t<Attr_T>;
15
+ using Receiver_T = typename attribute_traits<Attribute_T>::class_type;
16
+
17
+ public:
18
+ // Register attribute getter/setter with Ruby
19
+ static void define(VALUE klass, std::string name, Attribute_T attribute);
20
+
21
+ public:
22
+ // Disallow creating/copying/moving
23
+ NativeAttributeSet() = delete;
24
+ NativeAttributeSet(const NativeAttribute_T&) = delete;
25
+ NativeAttributeSet(NativeAttribute_T&&) = delete;
26
+ void operator=(const NativeAttribute_T&) = delete;
27
+ void operator=(NativeAttribute_T&&) = delete;
28
+
29
+ Resolved matches(size_t argc, const VALUE* argv, VALUE self) override;
30
+ VALUE operator()(size_t argc, const VALUE* argv, VALUE self) override;
31
+ std::string toString() override;
32
+
33
+ protected:
34
+ NativeAttributeSet(VALUE klass, std::string name, Attribute_T attr);
35
+
36
+ private:
37
+ VALUE klass_;
38
+ std::string name_;
39
+ Attribute_T attribute_;
40
+ };
41
+ } // detail
42
+ } // Rice
43
+
44
+ #endif // Rice__detail__Native_Attribute_Set__hpp_
@@ -0,0 +1,88 @@
1
+ #include <array>
2
+ #include <algorithm>
3
+
4
+
5
+ namespace Rice::detail
6
+ {
7
+ template<typename Attribute_T>
8
+ void NativeAttributeSet<Attribute_T>::define(VALUE klass, std::string name, Attribute_T attribute)
9
+ {
10
+ // Create a NativeAttributeSet that Ruby will call to read/write C++ variables
11
+ NativeAttribute_T* nativeAttribute = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute));
12
+ std::unique_ptr<Native> native(nativeAttribute);
13
+
14
+ // Define the write method name
15
+ std::string setter = name + "=";
16
+
17
+ // Tell Ruby to invoke the static method write to get the attribute value
18
+ detail::protect(rb_define_method, klass, setter.c_str(), (RUBY_METHOD_FUNC)&Native::resolve, -1);
19
+
20
+ // Add to native registry. Since attributes cannot be overridden, there is no need to set the
21
+ // matches or calls function pointer. Instead Ruby can call the static call method defined on
22
+ // this class (&NativeAttribute_T::set).
23
+ Identifier identifier(setter);
24
+ detail::Registries::instance.natives.add(klass, identifier.id(), native);
25
+ }
26
+
27
+ template<typename Attribute_T>
28
+ NativeAttributeSet<Attribute_T>::NativeAttributeSet(VALUE klass, std::string name, Attribute_T attribute)
29
+ : klass_(klass), name_(name), attribute_(attribute)
30
+ {
31
+ }
32
+
33
+ template<typename Attribute_T>
34
+ inline Resolved NativeAttributeSet<Attribute_T>::matches(size_t argc, const VALUE* argv, VALUE self)
35
+ {
36
+ if (argc == 1)
37
+ return Resolved{ Convertible::Exact, 1, this };
38
+ else
39
+ return Resolved{ Convertible::None, 0, this };
40
+ }
41
+
42
+ template<typename Attribute_T>
43
+ inline VALUE NativeAttributeSet<Attribute_T>::operator()(size_t argc, const VALUE* argv, VALUE self)
44
+ {
45
+ if constexpr (std::is_fundamental_v<intrinsic_type<Attr_T>> && std::is_pointer_v<Attr_T>)
46
+ {
47
+ static_assert(true, "An fundamental value, such as an integer, cannot be assigned to an attribute that is a pointer.");
48
+ }
49
+ else if constexpr (std::is_same_v<intrinsic_type<Attr_T>, std::string> && std::is_pointer_v<Attr_T>)
50
+ {
51
+ static_assert(true, "An string cannot be assigned to an attribute that is a pointer.");
52
+ }
53
+
54
+ if (argc != 1)
55
+ {
56
+ throw std::runtime_error("Incorrect number of parameters for setting attribute. Attribute: " + this->name_);
57
+ }
58
+
59
+ VALUE value = argv[0];
60
+
61
+ if constexpr (!std::is_null_pointer_v<Receiver_T> &&
62
+ !std::is_const_v<Attr_T> &&
63
+ (std::is_fundamental_v<Attr_T> || std::is_assignable_v<Attr_T, Attr_T>))
64
+ {
65
+ Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
66
+ nativeSelf->*attribute_ = From_Ruby<T_Unqualified>().convert(value);
67
+ }
68
+ else if constexpr (std::is_null_pointer_v<Receiver_T> &&
69
+ !std::is_const_v<Attr_T> &&
70
+ (std::is_fundamental_v<Attr_T> || std::is_assignable_v<Attr_T, Attr_T>))
71
+ {
72
+ *attribute_ = From_Ruby<T_Unqualified>().convert(value);
73
+ }
74
+ else
75
+ {
76
+ // Should never get here because define_attr won't compile this code, but just in case!
77
+ throw std::invalid_argument("Could not set attribute. Attribute: " + this->name_);
78
+ }
79
+
80
+ return value;
81
+ }
82
+
83
+ template<typename Attribute_T>
84
+ inline std::string NativeAttributeSet<Attribute_T>::toString()
85
+ {
86
+ return "";
87
+ }
88
+ } // Rice