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/Data_Object.ipp CHANGED
@@ -18,6 +18,13 @@ namespace Rice
18
18
  this->set_value(value);
19
19
  }
20
20
 
21
+ template<typename T>
22
+ inline Data_Object<T>::Data_Object(T&& data, Class klass)
23
+ {
24
+ VALUE value = detail::wrap(klass, Data_Type<T>::ruby_data_type(), data, true);
25
+ this->set_value(value);
26
+ }
27
+
21
28
  template<typename T>
22
29
  inline Data_Object<T>::Data_Object(const T& data, bool isOwner, Class klass)
23
30
  {
@@ -38,6 +45,12 @@ namespace Rice
38
45
  check_ruby_type(value);
39
46
  }
40
47
 
48
+ template<typename T>
49
+ inline Data_Object<T>::Data_Object(VALUE value) : Object(value)
50
+ {
51
+ check_ruby_type(value);
52
+ }
53
+
41
54
  template<typename T>
42
55
  inline void Data_Object<T>::check_ruby_type(VALUE value)
43
56
  {
@@ -71,19 +84,6 @@ namespace Rice
71
84
  return detail::unwrap<T>(this->value(), Data_Type<T>::ruby_data_type(), false);
72
85
  }
73
86
  }
74
-
75
- template<typename T>
76
- inline T* Data_Object<T>::from_ruby(VALUE value, bool takeOwnership)
77
- {
78
- if (Data_Type<T>::is_descendant(value))
79
- {
80
- return detail::unwrap<T>(value, Data_Type<T>::ruby_data_type(), takeOwnership);
81
- }
82
- else
83
- {
84
- throw create_type_exception<T>(value);
85
- }
86
- }
87
87
  }
88
88
 
89
89
  namespace Rice::detail
@@ -91,8 +91,19 @@ namespace Rice::detail
91
91
  template<typename T>
92
92
  class To_Ruby
93
93
  {
94
+ static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
95
+ "Data_Object cannot be used with fundamental types");
96
+
97
+ static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
98
+ !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
99
+ !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
100
+ !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
101
+ !std::is_same_v<T, std::vector<T>>,
102
+ "Please include rice/stl.hpp header for STL support");
103
+
94
104
  public:
95
- VALUE convert(T& data)
105
+ template<typename U>
106
+ VALUE convert(U& data)
96
107
  {
97
108
  // Get the ruby typeinfo
98
109
  std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(data);
@@ -102,7 +113,8 @@ namespace Rice::detail
102
113
  return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
103
114
  }
104
115
 
105
- VALUE convert(const T& data)
116
+ template<typename U>
117
+ VALUE convert(U&& data)
106
118
  {
107
119
  // Get the ruby typeinfo
108
120
  std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(data);
@@ -116,6 +128,16 @@ namespace Rice::detail
116
128
  template <typename T>
117
129
  class To_Ruby<T&>
118
130
  {
131
+ static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
132
+ "Data_Object cannot be used with fundamental types");
133
+
134
+ static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
135
+ !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
136
+ !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
137
+ !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
138
+ !std::is_same_v<T, std::vector<T>>,
139
+ "Please include rice/stl.hpp header for STL support");
140
+
119
141
  public:
120
142
  To_Ruby() = default;
121
143
 
@@ -123,26 +145,16 @@ namespace Rice::detail
123
145
  {
124
146
  }
125
147
 
126
- VALUE convert(T& data)
127
- {
128
- // Note that T could be a pointer or reference to a base class while data is in fact a
129
- // child class. Lookup the correct type so we return an instance of the correct Ruby class
130
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(data);
131
-
132
- bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
133
- return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner);
134
- }
135
-
136
- VALUE convert(const T& data)
148
+ template<typename U>
149
+ VALUE convert(U& data)
137
150
  {
138
151
  // Note that T could be a pointer or reference to a base class while data is in fact a
139
152
  // child class. Lookup the correct type so we return an instance of the correct Ruby class
140
153
  std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(data);
141
154
 
142
- bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
155
+ bool isOwner = (this->returnInfo_ && this->returnInfo_->isOwner());
143
156
  return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner);
144
157
  }
145
-
146
158
  private:
147
159
  Return* returnInfo_ = nullptr;
148
160
  };
@@ -150,6 +162,16 @@ namespace Rice::detail
150
162
  template <typename T>
151
163
  class To_Ruby<T*>
152
164
  {
165
+ static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
166
+ "Data_Object cannot be used with fundamental types");
167
+
168
+ static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
169
+ !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
170
+ !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
171
+ !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
172
+ !std::is_same_v<T, std::vector<T>>,
173
+ "Please include rice/stl.hpp header for STL support");
174
+
153
175
  public:
154
176
  To_Ruby() = default;
155
177
 
@@ -157,38 +179,31 @@ namespace Rice::detail
157
179
  {
158
180
  }
159
181
 
160
- VALUE convert(T* data)
182
+ template<typename U>
183
+ VALUE convert(U* data)
161
184
  {
162
- if (data)
185
+ bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
186
+
187
+ if (data == nullptr)
163
188
  {
164
- // Note that T could be a pointer or reference to a base class while data is in fact a
165
- // child class. Lookup the correct type so we return an instance of the correct Ruby class
166
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType(*data);
167
- bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
168
- return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner);
189
+ return Qnil;
169
190
  }
170
- else
191
+ else if (this->returnInfo_ && this->returnInfo_->isArray())
171
192
  {
172
- return Qnil;
193
+ using Buffer_T = Buffer<T>;
194
+ Buffer_T buffer((T*)data);
195
+ buffer.setOwner(isOwner);
196
+ return detail::wrap(Data_Type<Buffer_T>::klass(), Data_Type<Buffer_T>::ruby_data_type(), buffer, true);
173
197
  }
174
- }
175
-
176
- VALUE convert(const T* data)
177
- {
178
- if (data)
198
+ else
179
199
  {
180
200
  // Note that T could be a pointer or reference to a base class while data is in fact a
181
201
  // child class. Lookup the correct type so we return an instance of the correct Ruby class
182
202
  std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType(*data);
183
- bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
184
203
  return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner);
185
204
  }
186
- else
187
- {
188
- return Qnil;
189
- }
190
205
  }
191
-
206
+
192
207
  private:
193
208
  Return* returnInfo_ = nullptr;
194
209
  };
@@ -196,6 +211,16 @@ namespace Rice::detail
196
211
  template <typename T>
197
212
  class To_Ruby<T*&>
198
213
  {
214
+ static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
215
+ "Data_Object cannot be used with fundamental types");
216
+
217
+ static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
218
+ !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
219
+ !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
220
+ !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
221
+ !std::is_same_v<T, std::vector<T>>,
222
+ "Please include rice/stl.hpp header for STL support");
223
+
199
224
  public:
200
225
  To_Ruby() = default;
201
226
 
@@ -203,36 +228,29 @@ namespace Rice::detail
203
228
  {
204
229
  }
205
230
 
206
- VALUE convert(T* data)
231
+ template<typename U>
232
+ VALUE convert(U* data)
207
233
  {
208
- if (data)
234
+ bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
235
+
236
+ if (data == nullptr)
209
237
  {
210
- // Note that T could be a pointer or reference to a base class while data is in fact a
211
- // child class. Lookup the correct type so we return an instance of the correct Ruby class
212
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType(*data);
213
- bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
214
- return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner);
238
+ return Qnil;
215
239
  }
216
- else
240
+ else if (this->returnInfo_ && this->returnInfo_->isArray())
217
241
  {
218
- return Qnil;
242
+ using Buffer_T = Buffer<intrinsic_type<T>>;
243
+ Buffer_T buffer((T*)data);
244
+ buffer.setOwner(isOwner);
245
+ return detail::wrap(Data_Type<Buffer_T>::klass(), Data_Type<Buffer_T>::ruby_data_type(), buffer, true);
219
246
  }
220
- }
221
-
222
- VALUE convert(const T* data)
223
- {
224
- if (data)
247
+ else
225
248
  {
226
249
  // Note that T could be a pointer or reference to a base class while data is in fact a
227
250
  // child class. Lookup the correct type so we return an instance of the correct Ruby class
228
251
  std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType(*data);
229
- bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
230
252
  return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner);
231
253
  }
232
- else
233
- {
234
- return Qnil;
235
- }
236
254
  }
237
255
 
238
256
  private:
@@ -242,6 +260,16 @@ namespace Rice::detail
242
260
  template <typename T>
243
261
  class To_Ruby<T**>
244
262
  {
263
+ static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
264
+ "Data_Object cannot be used with fundamental types");
265
+
266
+ static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
267
+ !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
268
+ !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
269
+ !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
270
+ !std::is_same_v<T, std::vector<T>>,
271
+ "Please include rice/stl.hpp header for STL support");
272
+
245
273
  public:
246
274
  To_Ruby() = default;
247
275
 
@@ -249,31 +277,16 @@ namespace Rice::detail
249
277
  {
250
278
  }
251
279
 
252
- VALUE convert(T** data)
280
+ template<typename U>
281
+ VALUE convert(U** data)
253
282
  {
254
283
  if (data)
255
284
  {
256
- // Note that T could be a pointer or reference to a base class while data is in fact a
257
- // child class. Lookup the correct type so we return an instance of the correct Ruby class
258
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType(**data);
259
285
  bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
260
- return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner);
261
- }
262
- else
263
- {
264
- return Qnil;
265
- }
266
- }
267
-
268
- VALUE convert(const T** data)
269
- {
270
- if (data)
271
- {
272
- // Note that T could be a pointer or reference to a base class while data is in fact a
273
- // child class. Lookup the correct type so we return an instance of the correct Ruby class
274
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType(*data);
275
- bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
276
- return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner);
286
+ Buffer<T*> buffer((T**)data);
287
+ buffer.setOwner(isOwner);
288
+ using Buffer_T = Buffer<intrinsic_type<T>*>;
289
+ return detail::wrap(Data_Type<Buffer_T>::klass(), Data_Type<Buffer_T>::ruby_data_type(), buffer, true);
277
290
  }
278
291
  else
279
292
  {
@@ -300,6 +313,14 @@ namespace Rice::detail
300
313
  {
301
314
  static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
302
315
  "Data_Object cannot be used with fundamental types");
316
+
317
+ static_assert(!std::is_same_v<T, std::map<T, T>> || !std::is_same_v<T, std::unordered_map<T, T>> ||
318
+ !std::is_same_v<T, std::monostate> || !std::is_same_v<T, std::multimap<T, T>> ||
319
+ !std::is_same_v<T, std::optional<T>> || !std::is_same_v<T, std::pair<T, T>> ||
320
+ !std::is_same_v<T, std::set<T>> || !std::is_same_v<T, std::string> ||
321
+ !std::is_same_v<T, std::vector<T>>,
322
+ "Please include rice/stl.hpp header for STL support");
323
+
303
324
  public:
304
325
  From_Ruby() = default;
305
326
 
@@ -321,34 +342,16 @@ namespace Rice::detail
321
342
 
322
343
  T convert(VALUE value)
323
344
  {
324
- // This expression checks to see if T has an explicit copy constructor
325
- // If it does then we have to call it directly. Not sure if this end ups
326
- // with an extra copy or not?
327
- //
328
- // std::is_constructible_v<T, T> && !std::is_convertible_v<T, T>
329
- if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
345
+ using Intrinsic_T = intrinsic_type<T>;
346
+ Intrinsic_T* instance = detail::unwrap<Intrinsic_T>(value, Data_Type<Intrinsic_T>::ruby_data_type(), this->arg_ && this->arg_->isOwner());
347
+
348
+ if constexpr (std::is_constructible_v<T, T> && !std::is_convertible_v<T, T>)
330
349
  {
331
- if constexpr (std::is_constructible_v<T, T> && !std::is_convertible_v<T, T>)
332
- {
333
- return T(this->arg_->template defaultValue<T>());
334
- }
335
- else
336
- {
337
- return this->arg_->template defaultValue<T>();
338
- }
350
+ return T(*instance);
339
351
  }
340
352
  else
341
353
  {
342
- if constexpr (std::is_constructible_v<T, T> && !std::is_convertible_v<T, T>)
343
- {
344
- using Intrinsic_T = intrinsic_type<T>;
345
- return T(*Data_Object<Intrinsic_T>::from_ruby(value, this->arg_ && this->arg_->isOwner()));
346
- }
347
- else
348
- {
349
- using Intrinsic_T = intrinsic_type<T>;
350
- return *Data_Object<Intrinsic_T>::from_ruby(value, this->arg_ && this->arg_->isOwner());
351
- }
354
+ return *instance;
352
355
  }
353
356
  }
354
357
 
@@ -361,6 +364,14 @@ namespace Rice::detail
361
364
  {
362
365
  static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
363
366
  "Data_Object cannot be used with fundamental types");
367
+
368
+ static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
369
+ !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
370
+ !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
371
+ !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
372
+ !std::is_same_v<T, std::vector<T>>,
373
+ "Please include rice/stl.hpp header for STL support");
374
+
364
375
  public:
365
376
  From_Ruby() = default;
366
377
 
@@ -384,14 +395,7 @@ namespace Rice::detail
384
395
  {
385
396
  using Intrinsic_T = intrinsic_type<T>;
386
397
 
387
- if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
388
- {
389
- return this->arg_->template defaultValue<Intrinsic_T>();
390
- }
391
- else
392
- {
393
- return *Data_Object<Intrinsic_T>::from_ruby(value, this->arg_ && this->arg_->isOwner());
394
- }
398
+ return *detail::unwrap<Intrinsic_T>(value, Data_Type<Intrinsic_T>::ruby_data_type(), this->arg_ && this->arg_->isOwner());
395
399
  }
396
400
 
397
401
  private:
@@ -403,6 +407,14 @@ namespace Rice::detail
403
407
  {
404
408
  static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
405
409
  "Data_Object cannot be used with fundamental types");
410
+
411
+ static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
412
+ !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
413
+ !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
414
+ !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
415
+ !std::is_same_v<T, std::vector<T>>,
416
+ "Please include rice/stl.hpp header for STL support");
417
+
406
418
  public:
407
419
  From_Ruby() = default;
408
420
 
@@ -426,55 +438,30 @@ namespace Rice::detail
426
438
  {
427
439
  using Intrinsic_T = intrinsic_type<T>;
428
440
 
429
- if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
430
- {
431
- return std::move(this->arg_->template defaultValue<Intrinsic_T>());
432
- }
433
- else
434
- {
435
- return std::move(*Data_Object<Intrinsic_T>::from_ruby(value, this->arg_ && this->arg_->isOwner()));
436
- }
441
+ Intrinsic_T* object = detail::unwrap<Intrinsic_T>(value, Data_Type<Intrinsic_T>::ruby_data_type(), this->arg_ && this->arg_->isOwner());
442
+ return std::move(*object);
437
443
  }
438
444
 
439
445
  private:
440
446
  Arg* arg_ = nullptr;
441
447
  };
442
448
 
443
- // Helper class to convert a Ruby array of T to a C++ array of T (this happens when an API take T* as parameter
444
- // along with a second size parameter)
445
- template<typename T>
446
- class ArrayHelper
447
- {
448
- public:
449
- using Intrinsic_T = intrinsic_type<T>;
450
-
451
- T* convert(VALUE value)
452
- {
453
- this->vector_ = Array(value).to_vector<T>();
454
- return this->vector_.data();
455
- }
456
-
457
- private:
458
- std::vector<Intrinsic_T> vector_;
459
- };
460
-
461
449
  // 99% of the time a T* represents a wrapped C++ object that we want to call methods on. However, T*
462
450
  // could also be a pointer to an array of T objects, so T[]. OpenCV for example has API calls like this.
463
- //
464
- // Therefore this From_Ruby implementation supports both uses cases which complicates the code. The problem
465
- // is for T[] to compile, a class needs to be constructible, destructible and not abstract. A further wrinkle
466
- // is if T has an explicit copy-constructor then that requires additional special handling in the code
467
- // (see From_Ruby<T>). Whether this extra complication is worth it is debatable, but it does mean that
468
- // a Ruby array can be passed to any C++ API that takes a * including fundamental types (unsigned char)
469
- // and class types (T).
470
- //
471
- // Note that the From_Ruby<T[]> specialization never matches a parameter defined in function as T[] - the C++
472
- // compiler always picks T* instead. Not sure why...
451
+ // In that case, the Ruby VALUE will be a Buffer<T> instance
473
452
  template<typename T>
474
453
  class From_Ruby<T*>
475
454
  {
476
455
  static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
477
456
  "Data_Object cannot be used with fundamental types");
457
+
458
+ static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
459
+ !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
460
+ !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
461
+ !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
462
+ !std::is_same_v<T, std::vector<T>>,
463
+ "Please include rice/stl.hpp header for STL support");
464
+
478
465
  using Intrinsic_T = intrinsic_type<T>;
479
466
 
480
467
  public:
@@ -484,20 +471,19 @@ namespace Rice::detail
484
471
  {
485
472
  }
486
473
 
487
- ~From_Ruby()
488
- {
489
- if constexpr (std::is_destructible_v<Intrinsic_T>)
490
- {
491
- delete this->arrayHelper_;
492
- }
493
- }
494
-
495
474
  Convertible is_convertible(VALUE value)
496
475
  {
497
476
  switch (rb_type(value))
498
477
  {
499
478
  case RUBY_T_DATA:
500
- return Data_Type<T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
479
+ if (this->arg_ && this->arg_->isArray())
480
+ {
481
+ return Data_Type<Buffer<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
482
+ }
483
+ else
484
+ {
485
+ return Data_Type<T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
486
+ }
501
487
  break;
502
488
  case RUBY_T_NIL:
503
489
  return Convertible::Exact;
@@ -514,28 +500,23 @@ namespace Rice::detail
514
500
  {
515
501
  switch (rb_type(value))
516
502
  {
517
- case RUBY_T_DATA:
518
- {
519
- return Data_Object<Intrinsic_T>::from_ruby(value, this->arg_ && this->arg_->isOwner());
520
- break;
521
- }
522
503
  case RUBY_T_NIL:
523
504
  {
524
505
  return nullptr;
525
506
  break;
526
507
  }
527
- case RUBY_T_ARRAY:
508
+ case RUBY_T_DATA:
528
509
  {
529
- if constexpr (std::is_copy_constructible_v<Intrinsic_T> && std::is_destructible_v<Intrinsic_T> && !std::is_abstract_v<Intrinsic_T>)
510
+ if (this->arg_ && this->arg_->isArray())
511
+ {
512
+ using Buffer_T = Buffer<Intrinsic_T>;
513
+ Buffer_T* buffer = detail::unwrap<Buffer_T>(value, Data_Type<Buffer_T>::ruby_data_type(), this->arg_ && this->arg_->isOwner());
514
+ return buffer->ptr();
515
+ }
516
+ else
530
517
  {
531
- if (this->arrayHelper_ == nullptr)
532
- {
533
- this->arrayHelper_ = new ArrayHelper<T>();
534
- }
535
- return this->arrayHelper_->convert(value);
536
- break;
518
+ return detail::unwrap<Intrinsic_T>(value, Data_Type<Intrinsic_T>::ruby_data_type(), this->arg_ && this->arg_->isOwner());
537
519
  }
538
- // Will fall through to the type exception if we get here
539
520
  }
540
521
  default:
541
522
  {
@@ -546,7 +527,6 @@ namespace Rice::detail
546
527
 
547
528
  private:
548
529
  Arg* arg_ = nullptr;
549
- ArrayHelper<T>* arrayHelper_ = nullptr;
550
530
  };
551
531
 
552
532
  template<typename T>
@@ -554,6 +534,14 @@ namespace Rice::detail
554
534
  {
555
535
  static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
556
536
  "Data_Object cannot be used with fundamental types");
537
+
538
+ static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
539
+ !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
540
+ !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
541
+ !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
542
+ !std::is_same_v<T, std::vector<T>>,
543
+ "Please include rice/stl.hpp header for STL support");
544
+
557
545
  public:
558
546
  From_Ruby() = default;
559
547
 
@@ -583,7 +571,7 @@ namespace Rice::detail
583
571
  }
584
572
  else
585
573
  {
586
- return Data_Object<Intrinsic_T>::from_ruby(value, this->arg_ && this->arg_->isOwner());
574
+ return detail::unwrap<Intrinsic_T>(value, Data_Type<Intrinsic_T>::ruby_data_type(), this->arg_ && this->arg_->isOwner());
587
575
  }
588
576
  }
589
577
 
@@ -596,6 +584,14 @@ namespace Rice::detail
596
584
  {
597
585
  static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
598
586
  "Data_Object cannot be used with fundamental types");
587
+
588
+ static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
589
+ !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
590
+ !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
591
+ !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
592
+ !std::is_same_v<T, std::vector<T>>,
593
+ "Please include rice/stl.hpp header for STL support");
594
+
599
595
  using Intrinsic_T = intrinsic_type<T>;
600
596
  public:
601
597
  From_Ruby() = default;
@@ -609,7 +605,7 @@ namespace Rice::detail
609
605
  switch (rb_type(value))
610
606
  {
611
607
  case RUBY_T_DATA:
612
- return Data_Type<T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
608
+ return Data_Type<Buffer<T*>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
613
609
  break;
614
610
  case RUBY_T_NIL:
615
611
  return Convertible::Exact;
@@ -628,7 +624,8 @@ namespace Rice::detail
628
624
  {
629
625
  case RUBY_T_DATA:
630
626
  {
631
- return detail::unwrap<Intrinsic_T*>(value, Data_Type<T>::ruby_data_type(), false);
627
+ Buffer<Intrinsic_T*>* buffer = detail::unwrap<Buffer<Intrinsic_T*>>(value, Data_Type<Buffer<Intrinsic_T*>>::ruby_data_type(), false);
628
+ return buffer->ptr();
632
629
  break;
633
630
  }
634
631
  case RUBY_T_NIL:
@@ -636,11 +633,6 @@ namespace Rice::detail
636
633
  return nullptr;
637
634
  break;
638
635
  }
639
- case RUBY_T_ARRAY:
640
- {
641
- this->vector_ = Array(value).to_vector<Intrinsic_T*>();
642
- return this->vector_.data();
643
- }
644
636
  default:
645
637
  {
646
638
  throw create_type_exception<Intrinsic_T>(value);
@@ -658,6 +650,14 @@ namespace Rice::detail
658
650
  {
659
651
  static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
660
652
  "Data_Object cannot be used with fundamental types");
653
+
654
+ static_assert(!std::is_same_v<T, std::map<T, T>> && !std::is_same_v<T, std::unordered_map<T, T>> &&
655
+ !std::is_same_v<T, std::monostate> && !std::is_same_v<T, std::multimap<T, T>> &&
656
+ !std::is_same_v<T, std::optional<T>> && !std::is_same_v<T, std::pair<T, T>> &&
657
+ !std::is_same_v<T, std::set<T>> && !std::is_same_v<T, std::string> &&
658
+ !std::is_same_v<T, std::vector<T>>,
659
+ "Please include rice/stl.hpp header for STL support");
660
+
661
661
  public:
662
662
  Convertible is_convertible(VALUE value)
663
663
  {
data/rice/Data_Type.hpp CHANGED
@@ -43,7 +43,7 @@ namespace Rice
43
43
  * bound.
44
44
  * \return *this
45
45
  */
46
- virtual Data_Type & operator=(Module const & klass);
46
+ Data_Type& operator=(Module const & klass);
47
47
 
48
48
  /*! Creates a singleton method allocate and an instance method called
49
49
  * initialize which together create a new instance of the class. The
@@ -114,7 +114,8 @@ namespace Rice
114
114
  */
115
115
  static bool is_bound();
116
116
  static void check_is_bound();
117
- static bool is_defined(Object parent, const std::string& name);
117
+ static bool is_defined();
118
+ static bool check_defined(const std::string& name, Object parent = rb_cObject);
118
119
 
119
120
  // This is only for testing - DO NOT USE!!!
120
121
  static void unbind();
@@ -174,9 +175,7 @@ namespace Rice
174
175
  // Typed Data support
175
176
  static inline rb_data_type_t* rb_data_type_ = nullptr;
176
177
 
177
- // Track unbound instances (ie, declared variables of type Data_Type<T>
178
- // before define_class is called)
179
- static inline std::set<Data_Type<T>*>unbound_instances_;
178
+ static inline std::set<Data_Type<T>*>& unbound_instances();
180
179
  };
181
180
 
182
181
  //! Define a new data class in the namespace given by module.