rice 4.3.3 → 4.5.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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +63 -26
  3. data/README.md +7 -2
  4. data/Rakefile +7 -1
  5. data/include/rice/rice.hpp +7291 -4430
  6. data/include/rice/stl.hpp +769 -222
  7. data/lib/mkmf-rice.rb +37 -95
  8. data/rice/Address_Registration_Guard.hpp +72 -3
  9. data/rice/Arg.hpp +19 -5
  10. data/rice/Arg.ipp +24 -0
  11. data/rice/Callback.hpp +21 -0
  12. data/rice/Callback.ipp +13 -0
  13. data/rice/Constructor.hpp +4 -27
  14. data/rice/Constructor.ipp +79 -0
  15. data/rice/Data_Object.hpp +74 -3
  16. data/rice/Data_Object.ipp +324 -32
  17. data/rice/Data_Type.hpp +215 -3
  18. data/rice/Data_Type.ipp +125 -64
  19. data/rice/Director.hpp +0 -2
  20. data/rice/Enum.hpp +4 -6
  21. data/rice/Enum.ipp +101 -57
  22. data/rice/Exception.hpp +62 -2
  23. data/rice/Exception.ipp +7 -12
  24. data/rice/JumpException.hpp +44 -0
  25. data/rice/JumpException.ipp +48 -0
  26. data/rice/MemoryView.hpp +11 -0
  27. data/rice/MemoryView.ipp +43 -0
  28. data/rice/Return.hpp +6 -26
  29. data/rice/Return.ipp +10 -16
  30. data/rice/detail/DefaultHandler.hpp +12 -0
  31. data/rice/detail/DefaultHandler.ipp +8 -0
  32. data/rice/detail/HandlerRegistry.hpp +5 -35
  33. data/rice/detail/HandlerRegistry.ipp +7 -11
  34. data/rice/detail/InstanceRegistry.hpp +1 -4
  35. data/rice/detail/MethodInfo.hpp +15 -5
  36. data/rice/detail/MethodInfo.ipp +78 -6
  37. data/rice/detail/Native.hpp +32 -0
  38. data/rice/detail/Native.ipp +129 -0
  39. data/rice/detail/NativeAttributeGet.hpp +51 -0
  40. data/rice/detail/NativeAttributeGet.ipp +51 -0
  41. data/rice/detail/NativeAttributeSet.hpp +43 -0
  42. data/rice/detail/NativeAttributeSet.ipp +82 -0
  43. data/rice/detail/NativeCallbackFFI.hpp +55 -0
  44. data/rice/detail/NativeCallbackFFI.ipp +151 -0
  45. data/rice/detail/NativeCallbackSimple.hpp +30 -0
  46. data/rice/detail/NativeCallbackSimple.ipp +29 -0
  47. data/rice/detail/NativeFunction.hpp +20 -21
  48. data/rice/detail/NativeFunction.ipp +199 -64
  49. data/rice/detail/NativeIterator.hpp +8 -11
  50. data/rice/detail/NativeIterator.ipp +27 -31
  51. data/rice/detail/NativeRegistry.hpp +24 -15
  52. data/rice/detail/NativeRegistry.ipp +23 -48
  53. data/rice/detail/Proc.hpp +4 -0
  54. data/rice/detail/Proc.ipp +85 -0
  55. data/rice/detail/Registries.hpp +0 -7
  56. data/rice/detail/Registries.ipp +0 -18
  57. data/rice/detail/RubyFunction.hpp +0 -3
  58. data/rice/detail/RubyFunction.ipp +4 -8
  59. data/rice/detail/RubyType.hpp +19 -0
  60. data/rice/detail/RubyType.ipp +187 -0
  61. data/rice/detail/TupleIterator.hpp +14 -0
  62. data/rice/detail/Type.hpp +5 -6
  63. data/rice/detail/Type.ipp +150 -33
  64. data/rice/detail/TypeRegistry.hpp +15 -7
  65. data/rice/detail/TypeRegistry.ipp +105 -12
  66. data/rice/detail/Wrapper.hpp +6 -5
  67. data/rice/detail/Wrapper.ipp +45 -23
  68. data/rice/detail/cpp_protect.hpp +5 -6
  69. data/rice/detail/default_allocation_func.ipp +0 -2
  70. data/rice/detail/from_ruby.hpp +37 -3
  71. data/rice/detail/from_ruby.ipp +911 -454
  72. data/rice/detail/ruby.hpp +18 -0
  73. data/rice/detail/to_ruby.hpp +41 -3
  74. data/rice/detail/to_ruby.ipp +437 -113
  75. data/rice/global_function.hpp +0 -4
  76. data/rice/global_function.ipp +1 -2
  77. data/rice/rice.hpp +105 -22
  78. data/rice/ruby_mark.hpp +4 -3
  79. data/rice/stl.hpp +4 -0
  80. data/test/embed_ruby.cpp +4 -1
  81. data/test/extconf.rb +2 -0
  82. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  83. data/test/test_Address_Registration_Guard.cpp +5 -0
  84. data/test/test_Array.cpp +12 -1
  85. data/test/test_Attribute.cpp +103 -21
  86. data/test/test_Builtin_Object.cpp +5 -0
  87. data/test/test_Callback.cpp +231 -0
  88. data/test/test_Class.cpp +5 -31
  89. data/test/test_Constructor.cpp +69 -6
  90. data/test/test_Data_Object.cpp +9 -4
  91. data/test/test_Data_Type.cpp +428 -64
  92. data/test/test_Director.cpp +10 -5
  93. data/test/test_Enum.cpp +152 -40
  94. data/test/test_Exception.cpp +235 -0
  95. data/test/test_File.cpp +70 -0
  96. data/test/test_From_Ruby.cpp +542 -0
  97. data/test/test_Hash.cpp +5 -0
  98. data/test/test_Identifier.cpp +5 -0
  99. data/test/test_Inheritance.cpp +6 -1
  100. data/test/test_Iterator.cpp +5 -0
  101. data/test/test_JumpException.cpp +22 -0
  102. data/test/test_Keep_Alive.cpp +6 -1
  103. data/test/test_Keep_Alive_No_Wrapper.cpp +5 -0
  104. data/test/test_Memory_Management.cpp +5 -0
  105. data/test/test_Module.cpp +118 -64
  106. data/test/test_Native_Registry.cpp +2 -33
  107. data/test/test_Object.cpp +5 -0
  108. data/test/test_Overloads.cpp +631 -0
  109. data/test/test_Ownership.cpp +67 -4
  110. data/test/test_Proc.cpp +45 -0
  111. data/test/test_Self.cpp +5 -0
  112. data/test/test_Stl_Exception.cpp +109 -0
  113. data/test/test_Stl_Map.cpp +22 -8
  114. data/test/test_Stl_Optional.cpp +5 -0
  115. data/test/test_Stl_Pair.cpp +7 -2
  116. data/test/test_Stl_Reference_Wrapper.cpp +5 -0
  117. data/test/test_Stl_SmartPointer.cpp +210 -5
  118. data/test/test_Stl_String.cpp +5 -0
  119. data/test/test_Stl_String_View.cpp +5 -0
  120. data/test/test_Stl_Type.cpp +147 -0
  121. data/test/test_Stl_Unordered_Map.cpp +18 -7
  122. data/test/test_Stl_Variant.cpp +5 -0
  123. data/test/test_Stl_Vector.cpp +130 -8
  124. data/test/test_String.cpp +5 -0
  125. data/test/test_Struct.cpp +5 -0
  126. data/test/test_Symbol.cpp +5 -0
  127. data/test/test_Template.cpp +192 -0
  128. data/test/test_To_Ruby.cpp +152 -0
  129. data/test/test_Tracking.cpp +1 -0
  130. data/test/test_Type.cpp +100 -0
  131. data/test/test_global_functions.cpp +53 -6
  132. data/test/unittest.cpp +8 -0
  133. metadata +37 -20
  134. data/lib/version.rb +0 -3
  135. data/rice/Address_Registration_Guard_defn.hpp +0 -79
  136. data/rice/Data_Object_defn.hpp +0 -84
  137. data/rice/Data_Type_defn.hpp +0 -190
  138. data/rice/Exception_defn.hpp +0 -68
  139. data/rice/HandlerRegistration.hpp +0 -15
  140. data/rice/Identifier.hpp +0 -50
  141. data/rice/Identifier.ipp +0 -29
  142. data/rice/detail/ExceptionHandler.hpp +0 -8
  143. data/rice/detail/ExceptionHandler.ipp +0 -28
  144. data/rice/detail/ExceptionHandler_defn.hpp +0 -77
  145. data/rice/detail/Jump_Tag.hpp +0 -21
  146. data/rice/detail/NativeAttribute.hpp +0 -64
  147. data/rice/detail/NativeAttribute.ipp +0 -112
  148. data/rice/detail/from_ruby_defn.hpp +0 -38
  149. data/rice/detail/to_ruby_defn.hpp +0 -48
  150. data/test/test_Jump_Tag.cpp +0 -17
  151. data/test/test_To_From_Ruby.cpp +0 -399
@@ -0,0 +1,48 @@
1
+ namespace Rice
2
+ {
3
+ inline JumpException::JumpException(ruby_tag_type tag) : tag(tag)
4
+ {
5
+ this->createMessage();
6
+ }
7
+
8
+ inline const char* JumpException::what() const noexcept
9
+ {
10
+ return this->message_.c_str();
11
+ }
12
+
13
+ inline void JumpException::createMessage()
14
+ {
15
+ switch (this->tag)
16
+ {
17
+ case RUBY_TAG_NONE:
18
+ this->message_ = "No error";
19
+ break;
20
+ case RUBY_TAG_RETURN:
21
+ this->message_ = "Unexpected return";
22
+ break;
23
+ case RUBY_TAG_NEXT:
24
+ this->message_ = "Unexpected next";
25
+ break;
26
+ case RUBY_TAG_BREAK:
27
+ this->message_ = "Unexpected break";
28
+ break;
29
+ case RUBY_TAG_REDO:
30
+ this->message_ = "Unexpected redo";
31
+ break;
32
+ case RUBY_TAG_RETRY:
33
+ this->message_ = "Retry outside of rescue clause";
34
+ break;
35
+ case RUBY_TAG_THROW:
36
+ this->message_ = "Unexpected throw";
37
+ case RUBY_TAG_RAISE:
38
+ this->message_ = "Ruby exception was thrown";
39
+ break;
40
+ case RUBY_TAG_FATAL:
41
+ this->message_ = "Fatal error";
42
+ break;
43
+ case RUBY_TAG_MASK:
44
+ this->message_ = "Mask error";
45
+ break;
46
+ }
47
+ }
48
+ } // namespace Rice
@@ -0,0 +1,11 @@
1
+ #ifndef Rice__MemoryView__hpp_
2
+ #define Rice__MemoryView__hpp_
3
+
4
+ namespace Rice
5
+ {
6
+ class MemoryView
7
+ {
8
+ };
9
+ }
10
+
11
+ #endif // Rice__MemoryView__hpp_
@@ -0,0 +1,43 @@
1
+ namespace Rice
2
+ {
3
+ }
4
+
5
+ namespace Rice::detail
6
+ {
7
+ template<>
8
+ class To_Ruby<unsigned char**>
9
+ {
10
+ public:
11
+ VALUE convert(unsigned char** x)
12
+ {
13
+ std::runtime_error("To_Ruby unsigned char** is not implemented yet");
14
+ return Qnil;
15
+ }
16
+ };
17
+
18
+ template<>
19
+ class From_Ruby<unsigned char**>
20
+ {
21
+ public:
22
+ From_Ruby() = default;
23
+
24
+ explicit From_Ruby(Arg* arg) : arg_(arg)
25
+ {
26
+ }
27
+
28
+ Convertible is_convertible(VALUE value)
29
+ {
30
+ std::runtime_error("From_Ruby unsigned char** is not implemented yet");
31
+ return Convertible::None;
32
+ }
33
+
34
+ unsigned char** convert(VALUE value)
35
+ {
36
+ std::runtime_error("From_Ruby unsigned char** is not implemented yet");
37
+ return nullptr;
38
+ }
39
+
40
+ private:
41
+ Arg* arg_ = nullptr;
42
+ };
43
+ }
data/rice/Return.hpp CHANGED
@@ -1,40 +1,20 @@
1
1
  #ifndef Rice__Return__hpp_
2
2
  #define Rice__Return__hpp_
3
3
 
4
- #include <any>
5
-
6
4
  namespace Rice
7
5
  {
8
6
  //! Helper for defining Return argument of a method
9
7
 
10
- class Return
8
+ class Return: public Arg
11
9
  {
12
10
  public:
13
- //! Specifies Ruby should take ownership of the returned value
14
- Return& takeOwnership();
15
-
16
- //! Does Ruby own the returned value?
17
- bool isOwner();
18
-
19
- //! Specifies the returned value is a Ruby value
20
- Return& setValue();
21
-
22
- //! Is the returned value a Ruby value?
23
- bool isValue() const;
11
+ Return();
12
+ Return& keepAlive() override;
13
+ Return& setValue() override;
14
+ Return& setOpaque() override;
15
+ Return& takeOwnership() override;
24
16
 
25
- //! Tell the returned object to keep alive the receving object
26
- Return& keepAlive();
27
-
28
- //! Is the returned value being kept alive?
29
- bool isKeepAlive() const;
30
-
31
- private:
32
- bool isKeepAlive_ = false;
33
- bool isOwner_ = false;
34
- bool isValue_ = false;
35
17
  };
36
18
  } // Rice
37
19
 
38
- #include "Return.ipp"
39
-
40
20
  #endif // Rice__Return__hpp_
data/rice/Return.ipp CHANGED
@@ -1,38 +1,32 @@
1
1
  #include <any>
2
- #include <string>
3
2
 
4
3
  namespace Rice
5
4
  {
6
- inline Return& Return::takeOwnership()
5
+ inline Return::Return(): Arg("Return")
7
6
  {
8
- this->isOwner_ = true;
9
- return *this;
10
7
  }
11
8
 
12
- inline bool Return::isOwner()
9
+ inline Return& Return::keepAlive()
13
10
  {
14
- return this->isOwner_;
11
+ Arg::keepAlive();
12
+ return *this;
15
13
  }
16
14
 
17
15
  inline Return& Return::setValue()
18
16
  {
19
- this->isValue_ = true;
17
+ Arg::setValue();
20
18
  return *this;
21
19
  }
22
20
 
23
- inline bool Return::isValue() const
24
- {
25
- return this->isValue_;
26
- }
27
-
28
- inline Return& Return::keepAlive()
21
+ inline Return& Return::setOpaque()
29
22
  {
30
- this->isKeepAlive_ = true;
23
+ Arg::setOpaque();
31
24
  return *this;
32
25
  }
33
26
 
34
- inline bool Return::isKeepAlive() const
27
+ inline Return& Return::takeOwnership()
35
28
  {
36
- return this->isKeepAlive_;
29
+ Arg::takeOwnership();
30
+ return *this;
37
31
  }
38
32
  } // Rice
@@ -0,0 +1,12 @@
1
+ #ifndef Rice__detail__DefaultHandler__hpp_
2
+ #define Rice__detail__DefaultHandler__hpp_
3
+
4
+ namespace Rice::detail
5
+ {
6
+ class DefaultHandler
7
+ {
8
+ public:
9
+ void operator()() const;
10
+ };
11
+ }
12
+ #endif // Rice__detail__DefaultHandler__hpp_
@@ -0,0 +1,8 @@
1
+ namespace Rice::detail
2
+ {
3
+ inline void Rice::detail::DefaultHandler::operator()() const
4
+ {
5
+ // This handler does nothing, it just rethrows the exception so it can be handled
6
+ throw;
7
+ }
8
+ }
@@ -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,14 +2,14 @@
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
 
@@ -24,7 +24,19 @@ namespace Rice
24
24
  */
25
25
  void addArg(const Arg& arg);
26
26
 
27
- Arg& arg(size_t pos);
27
+ /**
28
+ * Get argument by position
29
+ */
30
+ Arg* arg(size_t pos);
31
+
32
+ /**
33
+ * Get argument by name
34
+ */
35
+ Arg* arg(std::string name);
36
+
37
+ int requiredArgCount();
38
+ int optionalArgCount();
39
+ void verifyArgCount(int argc);
28
40
 
29
41
  // Iterator support
30
42
  std::vector<Arg>::iterator begin();
@@ -39,6 +51,4 @@ namespace Rice
39
51
  std::vector<Arg> args_;
40
52
  };
41
53
  }
42
- #include "MethodInfo.ipp"
43
-
44
54
  #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,13 @@ 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
+ if constexpr (std::is_same_v<Arg_T, Return>)
30
29
  {
31
- this->addArg(arg);
30
+ this->returnInfo = arg;
32
31
  }
33
32
  else
34
33
  {
35
- this->returnInfo = arg;
34
+ this->addArg(arg);
36
35
  }
37
36
  }
38
37
 
@@ -41,6 +40,60 @@ namespace Rice
41
40
  this->args_.push_back(arg);
42
41
  }
43
42
 
43
+ inline int MethodInfo::requiredArgCount()
44
+ {
45
+ int result = 0;
46
+
47
+ for (const Arg& arg : this->args_)
48
+ {
49
+ if (!arg.hasDefaultValue())
50
+ {
51
+ result++;
52
+ }
53
+ }
54
+
55
+ return result;
56
+ }
57
+
58
+ inline int MethodInfo::optionalArgCount()
59
+ {
60
+ int result = 0;
61
+
62
+ for (const Arg& arg : this->args_)
63
+ {
64
+ if (arg.hasDefaultValue())
65
+ {
66
+ result++;
67
+ }
68
+ }
69
+
70
+ return result;
71
+ }
72
+
73
+ inline void MethodInfo::verifyArgCount(int argc)
74
+ {
75
+ int requiredArgCount = this->requiredArgCount();
76
+ int optionalArgCount = this->optionalArgCount();
77
+
78
+ if (argc < requiredArgCount || argc > requiredArgCount + optionalArgCount)
79
+ {
80
+ std::string message;
81
+
82
+ if (optionalArgCount > 0)
83
+ {
84
+ message = "wrong number of arguments (given " +
85
+ std::to_string(argc) + ", expected " +
86
+ std::to_string(requiredArgCount) + ".." + std::to_string(requiredArgCount + optionalArgCount) + ")";
87
+ }
88
+ else
89
+ {
90
+ message = "wrong number of arguments (given " +
91
+ std::to_string(argc) + ", expected " + std::to_string(requiredArgCount) + ")";
92
+ }
93
+ throw std::invalid_argument(message);
94
+ }
95
+ }
96
+
44
97
  inline std::string MethodInfo::formatString()
45
98
  {
46
99
  size_t required = 0;
@@ -61,9 +114,28 @@ namespace Rice
61
114
  return std::to_string(required) + std::to_string(optional);
62
115
  }
63
116
 
64
- inline Arg& MethodInfo::arg(size_t pos)
117
+ inline Arg* MethodInfo::arg(size_t pos)
65
118
  {
66
- return args_[pos];
119
+ if (pos < this->args_.size())
120
+ {
121
+ return &this->args_[pos];
122
+ }
123
+ else
124
+ {
125
+ return nullptr;
126
+ }
127
+ }
128
+
129
+ inline Arg* MethodInfo::arg(std::string name)
130
+ {
131
+ for (Arg& arg : this->args_)
132
+ {
133
+ if (arg.name == name)
134
+ {
135
+ return &arg;
136
+ }
137
+ }
138
+ return nullptr;
67
139
  }
68
140
 
69
141
  inline std::vector<Arg>::iterator MethodInfo::begin()
@@ -0,0 +1,32 @@
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(int argc, const VALUE* argv, VALUE self) = 0;
28
+ virtual VALUE operator()(int argc, const VALUE* argv, VALUE self) = 0;
29
+ };
30
+ }
31
+
32
+ #endif // Rice__detail__Native__hpp_
@@ -0,0 +1,129 @@
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
+ // Loop over every native to see how well they match the Ruby parameters
87
+ std::vector<Resolved> resolves;
88
+ std::transform(natives.begin(), natives.end(),
89
+ std::back_inserter(resolves),
90
+ [&](const std::unique_ptr<Native>& native)
91
+ {
92
+ return native->matches(argc, argv, self);
93
+ });
94
+
95
+ // Now sort from best to worst
96
+ std::sort(resolves.begin(), resolves.end(), std::greater{});
97
+
98
+ // Get the best one
99
+ Resolved resolved = resolves.front();
100
+
101
+ // Did it match?
102
+ if (resolved.convertible != Convertible::None)
103
+ {
104
+ native = resolved.native;
105
+ }
106
+ else
107
+ {
108
+ // Special case == to make the RubyMine debugger work. It calls == with a Module as
109
+ // the other argument, thus breaking if C++ operator== is implemented.
110
+ Identifier identifier(methodId);
111
+ if (identifier.str() == "==")
112
+ {
113
+ return detail::protect(rb_call_super, argc, argv);
114
+ }
115
+ else
116
+ {
117
+ std::ostringstream message;
118
+ message << "Could not resolve method call for %s#%s" << "\n"
119
+ << " %d overload(s) were evaluated based on the types of Ruby parameters provided.";
120
+ rb_raise(rb_eArgError, message.str().c_str(), rb_class2name(klass), identifier.c_str(), natives.size());
121
+ }
122
+ }
123
+ }
124
+
125
+ // Call the C++ function
126
+ return (*native)(argc, argv, self);
127
+ });
128
+ }
129
+ }