rice 4.3.3 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }