rice 4.5.0 → 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 (166) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  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/Rakefile +5 -4
  8. data/include/rice/rice.hpp +5436 -3201
  9. data/include/rice/stl.hpp +2355 -1269
  10. data/lib/make_rice_headers.rb +79 -0
  11. data/lib/mkmf-rice.rb +4 -0
  12. data/lib/rice/version.rb +3 -0
  13. data/lib/rice.rb +1 -0
  14. data/lib/rubygems/builder.rb +11 -0
  15. data/lib/rubygems/cmake_builder.rb +113 -0
  16. data/lib/rubygems_plugin.rb +9 -0
  17. data/rice/Arg.hpp +7 -1
  18. data/rice/Arg.ipp +11 -2
  19. data/rice/Buffer.hpp +123 -0
  20. data/rice/Buffer.ipp +599 -0
  21. data/rice/Constructor.ipp +3 -3
  22. data/rice/Data_Object.hpp +2 -3
  23. data/rice/Data_Object.ipp +188 -188
  24. data/rice/Data_Type.hpp +4 -5
  25. data/rice/Data_Type.ipp +42 -26
  26. data/rice/Enum.hpp +0 -1
  27. data/rice/Enum.ipp +26 -23
  28. data/rice/Init.hpp +8 -0
  29. data/rice/Init.ipp +8 -0
  30. data/rice/MemoryView.ipp +1 -41
  31. data/rice/Return.hpp +1 -1
  32. data/rice/Return.ipp +6 -0
  33. data/rice/cpp_api/Array.hpp +209 -0
  34. data/rice/cpp_api/Array.ipp +304 -0
  35. data/rice/cpp_api/Builtin_Object.hpp +31 -0
  36. data/rice/cpp_api/Builtin_Object.ipp +37 -0
  37. data/rice/cpp_api/Class.hpp +70 -0
  38. data/rice/cpp_api/Class.ipp +97 -0
  39. data/rice/cpp_api/Encoding.hpp +32 -0
  40. data/rice/cpp_api/Encoding.ipp +59 -0
  41. data/rice/cpp_api/Hash.hpp +194 -0
  42. data/rice/cpp_api/Hash.ipp +257 -0
  43. data/rice/cpp_api/Identifier.hpp +46 -0
  44. data/rice/cpp_api/Identifier.ipp +31 -0
  45. data/rice/cpp_api/Module.hpp +72 -0
  46. data/rice/cpp_api/Module.ipp +101 -0
  47. data/rice/cpp_api/Object.hpp +272 -0
  48. data/rice/cpp_api/Object.ipp +235 -0
  49. data/rice/cpp_api/String.hpp +74 -0
  50. data/rice/cpp_api/String.ipp +120 -0
  51. data/rice/cpp_api/Struct.hpp +113 -0
  52. data/rice/cpp_api/Struct.ipp +92 -0
  53. data/rice/cpp_api/Symbol.hpp +46 -0
  54. data/rice/cpp_api/Symbol.ipp +93 -0
  55. data/rice/cpp_api/shared_methods.hpp +134 -0
  56. data/rice/detail/MethodInfo.hpp +1 -9
  57. data/rice/detail/MethodInfo.ipp +5 -72
  58. data/rice/detail/Native.hpp +3 -2
  59. data/rice/detail/Native.ipp +32 -4
  60. data/rice/detail/NativeAttributeGet.hpp +3 -2
  61. data/rice/detail/NativeAttributeGet.ipp +8 -2
  62. data/rice/detail/NativeAttributeSet.hpp +3 -2
  63. data/rice/detail/NativeAttributeSet.ipp +8 -2
  64. data/rice/detail/NativeCallbackFFI.ipp +1 -1
  65. data/rice/detail/NativeFunction.hpp +17 -6
  66. data/rice/detail/NativeFunction.ipp +168 -64
  67. data/rice/detail/NativeIterator.hpp +3 -2
  68. data/rice/detail/NativeIterator.ipp +8 -2
  69. data/rice/detail/RubyType.hpp +2 -5
  70. data/rice/detail/RubyType.ipp +50 -5
  71. data/rice/detail/Type.hpp +3 -1
  72. data/rice/detail/Type.ipp +61 -31
  73. data/rice/detail/Wrapper.hpp +68 -33
  74. data/rice/detail/Wrapper.ipp +103 -113
  75. data/rice/detail/from_ruby.hpp +5 -4
  76. data/rice/detail/from_ruby.ipp +737 -365
  77. data/rice/detail/to_ruby.ipp +1092 -186
  78. data/rice/global_function.ipp +1 -1
  79. data/rice/libc/file.hpp +11 -0
  80. data/rice/libc/file.ipp +32 -0
  81. data/rice/rice.hpp +23 -16
  82. data/rice/stl/complex.hpp +6 -0
  83. data/rice/stl/complex.ipp +93 -0
  84. data/rice/stl/exception.hpp +11 -0
  85. data/rice/stl/exception.ipp +29 -0
  86. data/rice/stl/exception_ptr.hpp +6 -0
  87. data/rice/stl/exception_ptr.ipp +27 -0
  88. data/rice/stl/map.hpp +12 -0
  89. data/rice/stl/map.ipp +469 -0
  90. data/rice/stl/monostate.hpp +6 -0
  91. data/rice/stl/monostate.ipp +80 -0
  92. data/rice/stl/multimap.hpp +14 -0
  93. data/rice/stl/multimap.ipp +448 -0
  94. data/rice/stl/optional.hpp +6 -0
  95. data/rice/stl/optional.ipp +118 -0
  96. data/rice/stl/pair.hpp +13 -0
  97. data/rice/stl/pair.ipp +155 -0
  98. data/rice/stl/reference_wrapper.hpp +6 -0
  99. data/rice/stl/reference_wrapper.ipp +41 -0
  100. data/rice/stl/set.hpp +12 -0
  101. data/rice/stl/set.ipp +495 -0
  102. data/rice/stl/shared_ptr.hpp +28 -0
  103. data/rice/stl/shared_ptr.ipp +224 -0
  104. data/rice/stl/string.hpp +6 -0
  105. data/rice/stl/string.ipp +158 -0
  106. data/rice/stl/string_view.hpp +6 -0
  107. data/rice/stl/string_view.ipp +65 -0
  108. data/rice/stl/tuple.hpp +6 -0
  109. data/rice/stl/tuple.ipp +128 -0
  110. data/rice/stl/type_index.hpp +6 -0
  111. data/rice/stl/type_index.ipp +30 -0
  112. data/rice/stl/type_info.hpp +6 -0
  113. data/rice/stl/type_info.ipp +29 -0
  114. data/rice/stl/unique_ptr.hpp +22 -0
  115. data/rice/stl/unique_ptr.ipp +139 -0
  116. data/rice/stl/unordered_map.hpp +12 -0
  117. data/rice/stl/unordered_map.ipp +469 -0
  118. data/rice/stl/variant.hpp +6 -0
  119. data/rice/stl/variant.ipp +242 -0
  120. data/rice/stl/vector.hpp +12 -0
  121. data/rice/stl/vector.ipp +590 -0
  122. data/rice/stl.hpp +7 -3
  123. data/rice/traits/attribute_traits.hpp +26 -0
  124. data/rice/traits/function_traits.hpp +95 -0
  125. data/rice/traits/method_traits.hpp +47 -0
  126. data/rice/traits/rice_traits.hpp +160 -0
  127. data/rice.gemspec +85 -0
  128. data/test/embed_ruby.cpp +3 -0
  129. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  130. data/test/test_Array.cpp +6 -3
  131. data/test/test_Attribute.cpp +34 -1
  132. data/test/test_Buffer.cpp +285 -0
  133. data/test/test_Callback.cpp +2 -3
  134. data/test/test_Data_Object.cpp +88 -34
  135. data/test/test_Data_Type.cpp +106 -65
  136. data/test/test_Director.cpp +7 -3
  137. data/test/test_Enum.cpp +5 -2
  138. data/test/test_File.cpp +1 -1
  139. data/test/test_From_Ruby.cpp +181 -114
  140. data/test/test_Iterator.cpp +1 -1
  141. data/test/{test_JumpException.cpp → test_Jump_Exception.cpp} +1 -0
  142. data/test/test_Keep_Alive.cpp +7 -18
  143. data/test/test_Keep_Alive_No_Wrapper.cpp +0 -1
  144. data/test/test_Module.cpp +13 -6
  145. data/test/test_Native_Registry.cpp +0 -1
  146. data/test/test_Overloads.cpp +180 -5
  147. data/test/test_Ownership.cpp +100 -57
  148. data/test/test_Proc.cpp +0 -1
  149. data/test/test_Self.cpp +4 -4
  150. data/test/test_Stl_Map.cpp +37 -39
  151. data/test/test_Stl_Multimap.cpp +693 -0
  152. data/test/test_Stl_Pair.cpp +8 -8
  153. data/test/test_Stl_Reference_Wrapper.cpp +4 -2
  154. data/test/test_Stl_Set.cpp +790 -0
  155. data/test/{test_Stl_SmartPointer.cpp → test_Stl_SharedPtr.cpp} +97 -127
  156. data/test/test_Stl_Tuple.cpp +116 -0
  157. data/test/test_Stl_Type.cpp +1 -1
  158. data/test/test_Stl_UniquePtr.cpp +202 -0
  159. data/test/test_Stl_Unordered_Map.cpp +28 -34
  160. data/test/test_Stl_Variant.cpp +217 -89
  161. data/test/test_Stl_Vector.cpp +209 -83
  162. data/test/test_To_Ruby.cpp +373 -1
  163. data/test/test_Type.cpp +85 -14
  164. data/test/test_global_functions.cpp +17 -4
  165. metadata +94 -10
  166. data/rice/detail/TupleIterator.hpp +0 -14
data/rice/detail/Type.hpp CHANGED
@@ -14,8 +14,10 @@ namespace Rice::detail
14
14
  // Return the name of a type
15
15
  std::string typeName(const std::type_info& typeInfo);
16
16
  std::string typeName(const std::type_index& typeIndex);
17
- std::string makeClassName(const std::string& typeInfoName);
17
+ std::string cppClassName(const std::string& typeInfoName);
18
+ std::string rubyClassName(const std::string& typeInfoName);
18
19
  std::string findGroup(std::string& string, size_t start = 0);
20
+ void replaceGroup(std::string& string, std::regex regex, std::string replacement);
19
21
  void replaceAll(std::string& string, std::regex regex, std::string replacement);
20
22
 
21
23
  template<typename T>
data/rice/detail/Type.ipp CHANGED
@@ -13,21 +13,16 @@ namespace Rice::detail
13
13
  {
14
14
  return true;
15
15
  }
16
+ else if constexpr (std::is_array_v<T> && std::is_fundamental_v<std::remove_extent_t<T>>)
17
+ {
18
+ return true;
19
+ }
16
20
  else
17
21
  {
18
22
  return Registries::instance.types.verify<T>();
19
23
  }
20
24
  }
21
25
 
22
- template<>
23
- struct Type<void>
24
- {
25
- static bool verify()
26
- {
27
- return true;
28
- }
29
- };
30
-
31
26
  template<typename T>
32
27
  void verifyType()
33
28
  {
@@ -35,7 +30,7 @@ namespace Rice::detail
35
30
  }
36
31
 
37
32
  template<typename Tuple_T, size_t...Is>
38
- void verifyTypesImpl()
33
+ void verifyTypesImpl(std::index_sequence<Is...> indexes)
39
34
  {
40
35
  (verifyType<typename std::tuple_element<Is, Tuple_T>::type>(), ...);
41
36
  }
@@ -43,10 +38,8 @@ namespace Rice::detail
43
38
  template<typename Tuple_T>
44
39
  void verifyTypes()
45
40
  {
46
- if constexpr (std::tuple_size<Tuple_T>::value > 0)
47
- {
48
- verifyTypesImpl<Tuple_T, std::tuple_size<Tuple_T>::value - 1>();
49
- }
41
+ std::make_index_sequence<std::tuple_size_v<Tuple_T>> indexes;
42
+ verifyTypesImpl<Tuple_T>(indexes);
50
43
  }
51
44
 
52
45
  inline std::string demangle(char const* mangled_name)
@@ -156,7 +149,18 @@ namespace Rice::detail
156
149
  }
157
150
  }
158
151
 
159
- inline std::string makeClassName(const std::string& typeInfoName)
152
+ inline void replaceGroup(std::string& string, std::regex regex, std::string replacement)
153
+ {
154
+ std::smatch match;
155
+ while (std::regex_search(string, match, regex))
156
+ {
157
+ std::string group = findGroup(string, match.position());
158
+ group = match.str() + group;
159
+ string.replace(match.position(), group.length(), replacement);
160
+ }
161
+ }
162
+
163
+ inline std::string cppClassName(const std::string& typeInfoName)
160
164
  {
161
165
  std::string base = typeInfoName;
162
166
 
@@ -170,34 +174,26 @@ namespace Rice::detail
170
174
 
171
175
  // Remove std::__[^:]*::
172
176
  auto stdClangRegex = std::regex("std::__[^:]+::");
173
- base = std::regex_replace(base, stdClangRegex, "");
174
-
175
- // Remove std::
176
- auto stdRegex = std::regex("std::");
177
- base = std::regex_replace(base, stdRegex, "");
177
+ base = std::regex_replace(base, stdClangRegex, "std::");
178
178
 
179
- // Replace basic_string with string
180
- auto basicStringRegex = std::regex(R"(basic_string)");
181
- replaceAll(base, basicStringRegex, "string");
182
-
183
179
  // Remove allocators
184
- std::regex allocatorRegex(R"(,\s*allocator)");
180
+ std::regex allocatorRegex(R"(,\s*std::allocator)");
185
181
  removeGroup(base, allocatorRegex);
186
182
 
187
183
  // Remove char_traits
188
- std::regex charTraitsRegex(R"(,\s*char_traits)");
184
+ std::regex charTraitsRegex(R"(,\s*std::char_traits)");
189
185
  removeGroup(base, charTraitsRegex);
190
186
 
191
187
  // Remove less (std::map)
192
- std::regex lessRegex(R"(,\s*less)");
188
+ std::regex lessRegex(R"(,\s*std::less)");
193
189
  removeGroup(base, lessRegex);
194
190
 
195
191
  // Remove hash (std::unordered_map)
196
- std::regex hashRegex(R"(,\s*hash)");
192
+ std::regex hashRegex(R"(,\s*std::hash)");
197
193
  removeGroup(base, hashRegex);
198
194
 
199
195
  // Remove equal_to (std::unordered_map)
200
- std::regex equalRegex(R"(,\s*equal_to)");
196
+ std::regex equalRegex(R"(,\s*std::equal_to)");
201
197
  removeGroup(base, equalRegex);
202
198
 
203
199
  // Remove spaces before pointers
@@ -216,6 +212,36 @@ namespace Rice::detail
216
212
  auto commaSpaceRegex = std::regex(R"(,(\S))");
217
213
  replaceAll(base, commaSpaceRegex, ", $1");
218
214
 
215
+ // Fix strings
216
+ auto stringRegex = std::regex(R"(basic_string<char>)");
217
+ replaceAll(base, stringRegex, "string");
218
+
219
+ auto wstringRegex = std::regex(R"(basic_string<wchar_t>)");
220
+ replaceAll(base, wstringRegex, "wstring");
221
+
222
+ // Normalize Anonymous namespace
223
+ auto anonymousNamespaceGcc = std::regex(R"(\(anonymous namespace\))");
224
+ replaceAll(base, anonymousNamespaceGcc, "AnonymousNamespace");
225
+ auto anonymousNamespaceMsvc = std::regex(R"(`anonymous namespace')");
226
+ replaceAll(base, anonymousNamespaceMsvc, "AnonymousNamespace");
227
+
228
+ return base;
229
+ }
230
+
231
+
232
+ inline std::string rubyClassName(const std::string& typeInfoName)
233
+ {
234
+ std::string base = cppClassName(typeInfoName);
235
+
236
+ // Remove std:: these could be embedded in template types
237
+ auto stdRegex = std::regex("std::");
238
+ base = std::regex_replace(base, stdRegex, "");
239
+
240
+ // Remove leading namespaces. This will not remove namespaces
241
+ // embedded in template types like std::vector<mynamespace::foo>
242
+ auto leadingNamespacesRegex = std::regex("^[^<]*::");
243
+ base = std::regex_replace(base, leadingNamespacesRegex, "");
244
+
219
245
  // Capitalize first letter
220
246
  base[0] = std::toupper(base[0]);
221
247
 
@@ -239,18 +265,22 @@ namespace Rice::detail
239
265
 
240
266
  // Replace < with unicode U+227A (Precedes)
241
267
  auto lessThanRegex = std::regex("<");
242
- //replaceAll(base, lessThanRegex, u8"≺");
268
+ //replaceAll(base, lessThanRegex, "≺");
243
269
  replaceAll(base, lessThanRegex, "\u227A");
244
270
 
245
271
  // Replace > with unicode U+227B (Succeeds)
246
272
  auto greaterThanRegex = std::regex(">");
247
- //replaceAll(base, greaterThanRegex, u8"≻");
273
+ //replaceAll(base, greaterThanRegex, "≻");
248
274
  replaceAll(base, greaterThanRegex, "\u227B");
249
275
 
250
276
  // Replace , with Unicode Character (U+066C) - Arabic Thousands Separator
251
277
  auto commaRegex = std::regex(R"(,\s*)");
252
278
  replaceAll(base, commaRegex, "\u201A");
253
279
 
280
+ // Replace * with Unicode Character (U+2217) - Asterisk Operator
281
+ auto asteriskRegex = std::regex(R"(\*)");
282
+ replaceAll(base, asteriskRegex, "\u2217");
283
+
254
284
  return base;
255
285
  }
256
286
  }
@@ -1,50 +1,85 @@
1
1
  #ifndef Rice__detail__Wrapper__hpp_
2
2
  #define Rice__detail__Wrapper__hpp_
3
3
 
4
- namespace Rice
5
- {
6
- namespace detail
4
+ namespace Rice::detail
7
5
  {
6
+ class WrapperBase
7
+ {
8
+ public:
9
+ WrapperBase() = default;
10
+ virtual ~WrapperBase() = default;
11
+ virtual void* get() = 0;
12
+ bool isConst();
8
13
 
9
- class Wrapper
10
- {
11
- public:
12
- Wrapper(bool isOwner = false);
13
- virtual ~Wrapper() = default;
14
- virtual void* get() = 0;
14
+ void ruby_mark();
15
+ void addKeepAlive(VALUE value);
16
+ void setOwner(bool value);
15
17
 
16
- void ruby_mark();
17
- void addKeepAlive(VALUE value);
18
- void setOwner(bool value);
18
+ protected:
19
+ bool isOwner_ = false;
20
+ bool isConst_ = false;
19
21
 
20
- protected:
21
- bool isOwner_ = false;
22
+ private:
23
+ // We use a vector for speed and memory locality versus a set which does
24
+ // not scale well when getting to tens of thousands of objects (not expecting
25
+ // that to happen...but just in case)
26
+ std::vector<VALUE> keepAlive_;
27
+ };
22
28
 
23
- private:
24
- // We use a vector for speed and memory locality versus a set which does
25
- // not scale well when getting to tens of thousands of objects (not expecting
26
- // that to happen...but just in case)
27
- std::vector<VALUE> keepAlive_;
28
- };
29
+ template <typename T>
30
+ class Wrapper : public WrapperBase
31
+ {
32
+ public:
33
+ Wrapper(T& data);
34
+ Wrapper(T&& data);
35
+ ~Wrapper();
36
+ void* get() override;
29
37
 
30
- template <typename T, typename Wrapper_T = void>
31
- VALUE wrap(VALUE klass, rb_data_type_t* rb_type, T& data, bool isOwner);
38
+ private:
39
+ T data_;
40
+ };
32
41
 
33
- template <typename T, typename Wrapper_T = void>
34
- VALUE wrap(VALUE klass, rb_data_type_t* rb_type, T* data, bool isOwner);
42
+ template<typename T>
43
+ class Wrapper<T&> : public WrapperBase
44
+ {
45
+ public:
46
+ Wrapper(T& data);
47
+ ~Wrapper();
48
+ void* get() override;
35
49
 
36
- template <typename T>
37
- T* unwrap(VALUE value, rb_data_type_t* rb_type, bool takeOwnership);
50
+ private:
51
+ T& data_;
52
+ };
38
53
 
39
- Wrapper* getWrapper(VALUE value, rb_data_type_t* rb_type);
54
+ template <typename T>
55
+ class Wrapper<T*> : public WrapperBase
56
+ {
57
+ public:
58
+ Wrapper(T* data, bool isOwner);
59
+ ~Wrapper();
60
+ void* get() override;
40
61
 
41
- template <typename T>
42
- void replace(VALUE value, rb_data_type_t* rb_type, T* data, bool isOwner);
62
+ private:
63
+ T* data_ = nullptr;
64
+ };
43
65
 
44
- Wrapper* getWrapper(VALUE value);
66
+ // ---- Helper Functions ---------
67
+ template <typename T>
68
+ void wrapConstructed(VALUE value, rb_data_type_t* rb_data_type, T* data, bool isOwner);
45
69
 
46
- } // namespace detail
47
- } // namespace Rice
70
+ template <typename T>
71
+ VALUE wrap(VALUE klass, rb_data_type_t* rb_data_type, T& data, bool isOwner);
48
72
 
49
- #endif // Rice__detail__Wrapper__hpp_
73
+ template <typename T>
74
+ VALUE wrap(VALUE klass, rb_data_type_t* rb_data_type, T* data, bool isOwner);
50
75
 
76
+ template <typename T>
77
+ T* unwrap(VALUE value, rb_data_type_t* rb_data_type, bool takeOwnership);
78
+
79
+ template <typename Wrapper_T = WrapperBase>
80
+ Wrapper_T* getWrapper(VALUE value, rb_data_type_t* rb_data_type);
81
+
82
+ WrapperBase* getWrapper(VALUE value);
83
+ }
84
+ #endif // Rice__detail__Wrapper__hpp_
85
+
@@ -2,11 +2,12 @@
2
2
 
3
3
  namespace Rice::detail
4
4
  {
5
- inline Wrapper::Wrapper(bool isOwner): isOwner_(isOwner)
5
+ inline bool WrapperBase::isConst()
6
6
  {
7
+ return this->isConst_;
7
8
  }
8
9
 
9
- inline void Wrapper::ruby_mark()
10
+ inline void WrapperBase::ruby_mark()
10
11
  {
11
12
  for (VALUE value : this->keepAlive_)
12
13
  {
@@ -14,133 +15,122 @@ namespace Rice::detail
14
15
  }
15
16
  }
16
17
 
17
- inline void Wrapper::addKeepAlive(VALUE value)
18
+ inline void WrapperBase::addKeepAlive(VALUE value)
18
19
  {
19
20
  this->keepAlive_.push_back(value);
20
21
  }
21
22
 
22
- inline void Wrapper::setOwner(bool value)
23
+ inline void WrapperBase::setOwner(bool value)
23
24
  {
24
25
  this->isOwner_ = value;
25
26
  }
26
27
 
28
+ // ---- Wrapper -----
27
29
  template <typename T>
28
- class WrapperValue : public Wrapper
30
+ inline Wrapper<T>::Wrapper(T& data): data_(data)
29
31
  {
30
- public:
31
- WrapperValue(T& data): data_(std::move(data))
32
- {
33
- }
34
-
35
- ~WrapperValue()
36
- {
37
- Registries::instance.instances.remove(this->get());
38
- }
32
+ }
39
33
 
40
- void* get() override
41
- {
42
- return (void*)&this->data_;
43
- }
34
+ template <typename T>
35
+ inline Wrapper<T>::Wrapper(T&& data) : data_(std::move(data))
36
+ {
37
+ }
44
38
 
45
- private:
46
- T data_;
47
- };
39
+ template <typename T>
40
+ inline Wrapper<T>::~Wrapper()
41
+ {
42
+ Registries::instance.instances.remove(this->get());
43
+ }
48
44
 
49
45
  template <typename T>
50
- class WrapperReference : public Wrapper
46
+ inline void* Wrapper<T>::Wrapper::get()
51
47
  {
52
- public:
53
- WrapperReference(T& data): data_(data)
54
- {
55
- }
48
+ return (void*)&this->data_;
49
+ }
56
50
 
57
- ~WrapperReference()
58
- {
59
- Registries::instance.instances.remove(this->get());
60
- }
51
+ // ---- Wrapper& -----
52
+ template <typename T>
53
+ inline Wrapper<T&>::Wrapper(T& data): data_(data)
54
+ {
55
+ this->isConst_ = std::is_const_v<std::remove_reference_t<T>>;
56
+ }
61
57
 
62
- void* get() override
63
- {
64
- return (void*)&this->data_;
65
- }
58
+ template <typename T>
59
+ inline Wrapper<T&>::~Wrapper()
60
+ {
61
+ Registries::instance.instances.remove(this->get());
62
+ }
66
63
 
67
- private:
68
- T& data_;
69
- };
64
+ template <typename T>
65
+ inline void* Wrapper<T&>::get()
66
+ {
67
+ return (void*)&this->data_;
68
+ }
70
69
 
70
+ // ---- Wrapper* -----
71
71
  template <typename T>
72
- class WrapperPointer : public Wrapper
72
+ inline Wrapper<T*>::Wrapper(T* data, bool isOwner) : data_(data)
73
73
  {
74
- public:
75
- WrapperPointer(T* data, bool isOwner) : Wrapper(isOwner), data_(data)
76
- {
77
- }
74
+ this->isOwner_ = isOwner;
75
+ this->isConst_ = std::is_const_v<std::remove_pointer_t<T>>;
76
+ }
78
77
 
79
- ~WrapperPointer()
78
+ template <typename T>
79
+ inline Wrapper<T*>::~Wrapper()
80
+ {
81
+ Registries::instance.instances.remove(this->get());
82
+ if constexpr (std::is_destructible_v<T>)
80
83
  {
81
- Registries::instance.instances.remove(this->get());
82
-
83
- if constexpr (std::is_destructible_v<T>)
84
+ if (this->isOwner_)
84
85
  {
85
- if (this->isOwner_)
86
- {
87
- delete this->data_;
88
- }
86
+ delete this->data_;
89
87
  }
90
88
  }
89
+ }
91
90
 
92
- void* get() override
93
- {
94
- return (void*)this->data_;
95
- }
96
-
97
- private:
98
- T* data_ = nullptr;
99
- };
91
+ template <typename T>
92
+ inline void* Wrapper<T*>::get()
93
+ {
94
+ return (void*)this->data_;
95
+ }
100
96
 
101
97
  // ---- Helper Functions -------
102
- template <typename T, typename Wrapper_T>
103
- inline VALUE wrap(VALUE klass, rb_data_type_t* rb_type, T& data, bool isOwner)
98
+ template <typename T>
99
+ inline VALUE wrap(VALUE klass, rb_data_type_t* rb_data_type, T& data, bool isOwner)
104
100
  {
105
101
  VALUE result = Registries::instance.instances.lookup(&data);
106
102
 
107
103
  if (result != Qnil)
108
104
  return result;
109
105
 
110
- Wrapper* wrapper = nullptr;
106
+ WrapperBase* wrapper = nullptr;
111
107
 
112
- // Is this a pointer but cannot be copied? For example a std::unique_ptr
113
- if constexpr (!std::is_void_v<Wrapper_T> && !std::is_copy_constructible_v<Wrapper_T>)
108
+ // If Ruby is not the owner then wrap the reference
109
+ if (!isOwner)
114
110
  {
115
- wrapper = new Wrapper_T(std::move(data));
116
- result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
111
+ wrapper = new Wrapper<T&>(data);
112
+ result = TypedData_Wrap_Struct(klass, rb_data_type, wrapper);
117
113
  }
118
- // Is this a pointer or smart pointer like std::shared_ptr
119
- else if constexpr (!std::is_void_v<Wrapper_T>)
114
+
115
+ // Ruby is the owner so copy data
116
+ else if constexpr (std::is_copy_constructible_v<T>)
120
117
  {
121
- wrapper = new Wrapper_T(data);
122
- result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
118
+ wrapper = new Wrapper<T>(data);
119
+ result = TypedData_Wrap_Struct(klass, rb_data_type, wrapper);
123
120
  }
124
- // If ruby is the owner than copy the object if possible
125
- else if (isOwner)
121
+
122
+ // Ruby is the owner so move data
123
+ else if constexpr (std::is_move_constructible_v<T>)
126
124
  {
127
- if constexpr (std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>)
128
- {
129
- wrapper = new WrapperValue<T>(data);
130
- result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
131
- }
132
- else
133
- {
134
- std::string message = "Ruby was directed to take ownership of a C++ object but it does not have an accessible copy or move constructor. Type: " +
135
- typeName(typeid(T));
136
- throw std::runtime_error(message);
137
- }
125
+ wrapper = new Wrapper<T>(std::forward<T>(data));
126
+ result = TypedData_Wrap_Struct(klass, rb_data_type, wrapper);
138
127
  }
139
- // Ruby is not the owner so just wrap the reference
128
+
140
129
  else
141
130
  {
142
- wrapper = new WrapperReference<T>(data);
143
- result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
131
+ std::string message = "Rice was directed to take ownership of a C++ object but it does not have an accessible copy or move constructor. Type: " +
132
+ typeName(typeid(T));
133
+ throw std::runtime_error(message);
144
134
  }
145
135
 
146
136
  Registries::instance.instances.add(wrapper->get(), result);
@@ -148,37 +138,31 @@ namespace Rice::detail
148
138
  return result;
149
139
  };
150
140
 
151
- template <typename T, typename Wrapper_T>
152
- inline VALUE wrap(VALUE klass, rb_data_type_t* rb_type, T* data, bool isOwner)
141
+ template <typename T>
142
+ inline VALUE wrap(VALUE klass, rb_data_type_t* rb_data_type, T* data, bool isOwner)
153
143
  {
154
144
  VALUE result = Registries::instance.instances.lookup(data);
155
145
 
156
146
  if (result != Qnil)
157
147
  return result;
158
148
 
159
- Wrapper* wrapper = nullptr;
160
-
161
- if constexpr (!std::is_void_v<Wrapper_T>)
162
- {
163
- wrapper = new Wrapper_T(data);
164
- result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
165
- }
166
- else
167
- {
168
- wrapper = new WrapperPointer<T>(data, isOwner);
169
- result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
170
- }
149
+ WrapperBase* wrapper = new Wrapper<T*>(data, isOwner);
150
+ result = TypedData_Wrap_Struct(klass, rb_data_type, wrapper);
171
151
 
172
152
  Registries::instance.instances.add(wrapper->get(), result);
173
153
  return result;
174
154
  };
175
155
 
176
156
  template <typename T>
177
- inline T* unwrap(VALUE value, rb_data_type_t* rb_type, bool takeOwnership)
157
+ inline T* unwrap(VALUE value, rb_data_type_t* rb_data_type, bool takeOwnership)
178
158
  {
179
- Wrapper* wrapper = getWrapper(value, rb_type);
180
- if (takeOwnership)
181
- wrapper->setOwner(false);
159
+ if (rb_type(value) != RUBY_T_DATA)
160
+ {
161
+ std::string message = "The provided Ruby object does not wrap a C++ object";
162
+ throw std::runtime_error(message);
163
+ }
164
+
165
+ WrapperBase* wrapper = getWrapper(value, rb_data_type);
182
166
 
183
167
  if (wrapper == nullptr)
184
168
  {
@@ -189,17 +173,21 @@ namespace Rice::detail
189
173
  throw std::runtime_error(message);
190
174
  }
191
175
 
176
+ if (takeOwnership)
177
+ wrapper->setOwner(false);
178
+
192
179
  return static_cast<T*>(wrapper->get());
193
180
  }
194
181
 
195
- inline Wrapper* getWrapper(VALUE value, rb_data_type_t* rb_type)
182
+ template <typename Wrapper_T>
183
+ inline Wrapper_T* getWrapper(VALUE value, rb_data_type_t* rb_data_type)
196
184
  {
197
- Wrapper* wrapper = nullptr;
198
- TypedData_Get_Struct(value, Wrapper, rb_type, wrapper);
199
- return wrapper;
185
+ WrapperBase* wrapper = nullptr;
186
+ TypedData_Get_Struct(value, WrapperBase, rb_data_type, wrapper);
187
+ return dynamic_cast<Wrapper_T*>(wrapper);
200
188
  }
201
189
 
202
- inline Wrapper* getWrapper(VALUE value)
190
+ inline WrapperBase* getWrapper(VALUE value)
203
191
  {
204
192
  // Turn off spurious warning on g++ 12
205
193
  #if defined(__GNUC__) || defined(__clang__)
@@ -207,7 +195,7 @@ namespace Rice::detail
207
195
  #pragma GCC diagnostic ignored "-Warray-bounds"
208
196
  #endif
209
197
 
210
- return RTYPEDDATA_P(value) ? static_cast<Wrapper*>(RTYPEDDATA_DATA(value)) : nullptr;
198
+ return RTYPEDDATA_P(value) ? static_cast<WrapperBase*>(RTYPEDDATA_DATA(value)) : nullptr;
211
199
 
212
200
  #if defined(__GNUC__) || defined(__clang__)
213
201
  #pragma GCC diagnostic pop
@@ -215,17 +203,19 @@ namespace Rice::detail
215
203
  }
216
204
 
217
205
  template <typename T>
218
- inline void replace(VALUE value, rb_data_type_t* rb_type, T* data, bool isOwner)
206
+ inline void wrapConstructed(VALUE value, rb_data_type_t* rb_data_type, T* data, bool isOwner)
219
207
  {
220
- WrapperPointer<T>* wrapper = nullptr;
221
- TypedData_Get_Struct(value, WrapperPointer<T>, rb_type, wrapper);
208
+ using Wrapper_T = Wrapper<T*>;
209
+
210
+ Wrapper_T* wrapper = nullptr;
211
+ TypedData_Get_Struct(value, Wrapper_T, rb_data_type, wrapper);
222
212
  if (wrapper)
223
213
  {
224
214
  Registries::instance.instances.remove(wrapper->get());
225
215
  delete wrapper;
226
216
  }
227
217
 
228
- wrapper = new WrapperPointer<T>(data, isOwner);
218
+ wrapper = new Wrapper_T(data, true);
229
219
  RTYPEDDATA_DATA(value) = wrapper;
230
220
 
231
221
  Registries::instance.instances.add(data, value);
@@ -32,10 +32,11 @@ namespace Rice::detail
32
32
 
33
33
  enum class Convertible: uint8_t
34
34
  {
35
- None = 0b000,
36
- Narrowable = 0b001,
37
- Cast = 0b011,
38
- Exact = 0b111,
35
+ None = 0b0000,
36
+ Narrow = 0b0001,
37
+ Cast = 0b0011,
38
+ Const = 0b0111,
39
+ Exact = 0b1111
39
40
  };
40
41
  }
41
42