rice 4.3.3 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -26
  3. data/CMakeLists.txt +31 -0
  4. data/CMakePresets.json +75 -0
  5. data/COPYING +3 -2
  6. data/FindRuby.cmake +437 -0
  7. data/README.md +7 -2
  8. data/Rakefile +12 -5
  9. data/include/rice/rice.hpp +9522 -4426
  10. data/include/rice/stl.hpp +2831 -1198
  11. data/lib/make_rice_headers.rb +79 -0
  12. data/lib/mkmf-rice.rb +40 -94
  13. data/lib/rice/version.rb +3 -0
  14. data/lib/rice.rb +1 -0
  15. data/lib/rubygems/builder.rb +11 -0
  16. data/lib/rubygems/cmake_builder.rb +113 -0
  17. data/lib/rubygems_plugin.rb +9 -0
  18. data/rice/Address_Registration_Guard.hpp +72 -3
  19. data/rice/Arg.hpp +26 -6
  20. data/rice/Arg.ipp +35 -2
  21. data/rice/Buffer.hpp +123 -0
  22. data/rice/Buffer.ipp +599 -0
  23. data/rice/Callback.hpp +21 -0
  24. data/rice/Callback.ipp +13 -0
  25. data/rice/Constructor.hpp +4 -27
  26. data/rice/Constructor.ipp +79 -0
  27. data/rice/Data_Object.hpp +73 -3
  28. data/rice/Data_Object.ipp +388 -96
  29. data/rice/Data_Type.hpp +214 -3
  30. data/rice/Data_Type.ipp +144 -67
  31. data/rice/Director.hpp +0 -2
  32. data/rice/Enum.hpp +4 -7
  33. data/rice/Enum.ipp +102 -55
  34. data/rice/Exception.hpp +62 -2
  35. data/rice/Exception.ipp +7 -12
  36. data/rice/Init.hpp +8 -0
  37. data/rice/Init.ipp +8 -0
  38. data/rice/JumpException.hpp +44 -0
  39. data/rice/JumpException.ipp +48 -0
  40. data/rice/MemoryView.hpp +11 -0
  41. data/rice/MemoryView.ipp +3 -0
  42. data/rice/Return.hpp +7 -27
  43. data/rice/Return.ipp +13 -13
  44. data/rice/cpp_api/Array.hpp +209 -0
  45. data/rice/cpp_api/Array.ipp +304 -0
  46. data/rice/cpp_api/Builtin_Object.hpp +31 -0
  47. data/rice/cpp_api/Builtin_Object.ipp +37 -0
  48. data/rice/cpp_api/Class.hpp +70 -0
  49. data/rice/cpp_api/Class.ipp +97 -0
  50. data/rice/cpp_api/Encoding.hpp +32 -0
  51. data/rice/cpp_api/Encoding.ipp +59 -0
  52. data/rice/cpp_api/Hash.hpp +194 -0
  53. data/rice/cpp_api/Hash.ipp +257 -0
  54. data/rice/{Identifier.hpp → cpp_api/Identifier.hpp} +2 -6
  55. data/rice/{Identifier.ipp → cpp_api/Identifier.ipp} +4 -2
  56. data/rice/cpp_api/Module.hpp +72 -0
  57. data/rice/cpp_api/Module.ipp +101 -0
  58. data/rice/cpp_api/Object.hpp +272 -0
  59. data/rice/cpp_api/Object.ipp +235 -0
  60. data/rice/cpp_api/String.hpp +74 -0
  61. data/rice/cpp_api/String.ipp +120 -0
  62. data/rice/cpp_api/Struct.hpp +113 -0
  63. data/rice/cpp_api/Struct.ipp +92 -0
  64. data/rice/cpp_api/Symbol.hpp +46 -0
  65. data/rice/cpp_api/Symbol.ipp +93 -0
  66. data/rice/cpp_api/shared_methods.hpp +134 -0
  67. data/rice/detail/DefaultHandler.hpp +12 -0
  68. data/rice/detail/DefaultHandler.ipp +8 -0
  69. data/rice/detail/HandlerRegistry.hpp +5 -35
  70. data/rice/detail/HandlerRegistry.ipp +7 -11
  71. data/rice/detail/InstanceRegistry.hpp +1 -4
  72. data/rice/detail/MethodInfo.hpp +12 -10
  73. data/rice/detail/MethodInfo.ipp +26 -21
  74. data/rice/detail/Native.hpp +33 -0
  75. data/rice/detail/Native.ipp +157 -0
  76. data/rice/detail/NativeAttributeGet.hpp +52 -0
  77. data/rice/detail/NativeAttributeGet.ipp +57 -0
  78. data/rice/detail/NativeAttributeSet.hpp +44 -0
  79. data/rice/detail/NativeAttributeSet.ipp +88 -0
  80. data/rice/detail/NativeCallbackFFI.hpp +55 -0
  81. data/rice/detail/NativeCallbackFFI.ipp +151 -0
  82. data/rice/detail/NativeCallbackSimple.hpp +30 -0
  83. data/rice/detail/NativeCallbackSimple.ipp +29 -0
  84. data/rice/detail/NativeFunction.hpp +33 -23
  85. data/rice/detail/NativeFunction.ipp +309 -70
  86. data/rice/detail/NativeIterator.hpp +9 -11
  87. data/rice/detail/NativeIterator.ipp +33 -31
  88. data/rice/detail/NativeRegistry.hpp +24 -15
  89. data/rice/detail/NativeRegistry.ipp +23 -48
  90. data/rice/detail/Proc.hpp +4 -0
  91. data/rice/detail/Proc.ipp +85 -0
  92. data/rice/detail/Registries.hpp +0 -7
  93. data/rice/detail/Registries.ipp +0 -18
  94. data/rice/detail/RubyFunction.hpp +0 -3
  95. data/rice/detail/RubyFunction.ipp +4 -8
  96. data/rice/detail/RubyType.hpp +16 -0
  97. data/rice/detail/RubyType.ipp +232 -0
  98. data/rice/detail/Type.hpp +7 -6
  99. data/rice/detail/Type.ipp +192 -45
  100. data/rice/detail/TypeRegistry.hpp +15 -7
  101. data/rice/detail/TypeRegistry.ipp +105 -12
  102. data/rice/detail/Wrapper.hpp +68 -32
  103. data/rice/detail/Wrapper.ipp +121 -109
  104. data/rice/detail/cpp_protect.hpp +5 -6
  105. data/rice/detail/default_allocation_func.ipp +0 -2
  106. data/rice/detail/from_ruby.hpp +38 -3
  107. data/rice/detail/from_ruby.ipp +1321 -492
  108. data/rice/detail/ruby.hpp +18 -0
  109. data/rice/detail/to_ruby.hpp +41 -3
  110. data/rice/detail/to_ruby.ipp +1424 -194
  111. data/rice/global_function.hpp +0 -4
  112. data/rice/global_function.ipp +0 -1
  113. data/rice/libc/file.hpp +11 -0
  114. data/rice/libc/file.ipp +32 -0
  115. data/rice/rice.hpp +116 -26
  116. data/rice/ruby_mark.hpp +4 -3
  117. data/rice/stl/complex.hpp +6 -0
  118. data/rice/stl/complex.ipp +93 -0
  119. data/rice/stl/exception.hpp +11 -0
  120. data/rice/stl/exception.ipp +29 -0
  121. data/rice/stl/exception_ptr.hpp +6 -0
  122. data/rice/stl/exception_ptr.ipp +27 -0
  123. data/rice/stl/map.hpp +12 -0
  124. data/rice/stl/map.ipp +469 -0
  125. data/rice/stl/monostate.hpp +6 -0
  126. data/rice/stl/monostate.ipp +80 -0
  127. data/rice/stl/multimap.hpp +14 -0
  128. data/rice/stl/multimap.ipp +448 -0
  129. data/rice/stl/optional.hpp +6 -0
  130. data/rice/stl/optional.ipp +118 -0
  131. data/rice/stl/pair.hpp +13 -0
  132. data/rice/stl/pair.ipp +155 -0
  133. data/rice/stl/reference_wrapper.hpp +6 -0
  134. data/rice/stl/reference_wrapper.ipp +41 -0
  135. data/rice/stl/set.hpp +12 -0
  136. data/rice/stl/set.ipp +495 -0
  137. data/rice/stl/shared_ptr.hpp +28 -0
  138. data/rice/stl/shared_ptr.ipp +224 -0
  139. data/rice/stl/string.hpp +6 -0
  140. data/rice/stl/string.ipp +158 -0
  141. data/rice/stl/string_view.hpp +6 -0
  142. data/rice/stl/string_view.ipp +65 -0
  143. data/rice/stl/tuple.hpp +6 -0
  144. data/rice/stl/tuple.ipp +128 -0
  145. data/rice/stl/type_index.hpp +6 -0
  146. data/rice/stl/type_index.ipp +30 -0
  147. data/rice/stl/type_info.hpp +6 -0
  148. data/rice/stl/type_info.ipp +29 -0
  149. data/rice/stl/unique_ptr.hpp +22 -0
  150. data/rice/stl/unique_ptr.ipp +139 -0
  151. data/rice/stl/unordered_map.hpp +12 -0
  152. data/rice/stl/unordered_map.ipp +469 -0
  153. data/rice/stl/variant.hpp +6 -0
  154. data/rice/stl/variant.ipp +242 -0
  155. data/rice/stl/vector.hpp +12 -0
  156. data/rice/stl/vector.ipp +590 -0
  157. data/rice/stl.hpp +11 -3
  158. data/rice/traits/attribute_traits.hpp +26 -0
  159. data/rice/traits/function_traits.hpp +95 -0
  160. data/rice/traits/method_traits.hpp +47 -0
  161. data/rice/traits/rice_traits.hpp +160 -0
  162. data/rice.gemspec +85 -0
  163. data/test/embed_ruby.cpp +7 -1
  164. data/test/extconf.rb +2 -0
  165. data/test/test_Address_Registration_Guard.cpp +5 -0
  166. data/test/test_Array.cpp +18 -4
  167. data/test/test_Attribute.cpp +136 -21
  168. data/test/test_Buffer.cpp +285 -0
  169. data/test/test_Builtin_Object.cpp +5 -0
  170. data/test/test_Callback.cpp +230 -0
  171. data/test/test_Class.cpp +5 -31
  172. data/test/test_Constructor.cpp +69 -6
  173. data/test/test_Data_Object.cpp +97 -38
  174. data/test/test_Data_Type.cpp +470 -65
  175. data/test/test_Director.cpp +17 -8
  176. data/test/test_Enum.cpp +155 -40
  177. data/test/test_Exception.cpp +235 -0
  178. data/test/test_File.cpp +70 -0
  179. data/test/test_From_Ruby.cpp +609 -0
  180. data/test/test_Hash.cpp +5 -0
  181. data/test/test_Identifier.cpp +5 -0
  182. data/test/test_Inheritance.cpp +6 -1
  183. data/test/test_Iterator.cpp +6 -1
  184. data/test/test_Jump_Exception.cpp +23 -0
  185. data/test/test_Keep_Alive.cpp +13 -19
  186. data/test/test_Keep_Alive_No_Wrapper.cpp +5 -1
  187. data/test/test_Memory_Management.cpp +5 -0
  188. data/test/test_Module.cpp +128 -67
  189. data/test/test_Native_Registry.cpp +2 -34
  190. data/test/test_Object.cpp +5 -0
  191. data/test/test_Overloads.cpp +806 -0
  192. data/test/test_Ownership.cpp +160 -54
  193. data/test/test_Proc.cpp +44 -0
  194. data/test/test_Self.cpp +9 -4
  195. data/test/test_Stl_Exception.cpp +109 -0
  196. data/test/test_Stl_Map.cpp +54 -42
  197. data/test/test_Stl_Multimap.cpp +693 -0
  198. data/test/test_Stl_Optional.cpp +5 -0
  199. data/test/test_Stl_Pair.cpp +14 -9
  200. data/test/test_Stl_Reference_Wrapper.cpp +9 -2
  201. data/test/test_Stl_Set.cpp +790 -0
  202. data/test/test_Stl_SharedPtr.cpp +458 -0
  203. data/test/test_Stl_String.cpp +5 -0
  204. data/test/test_Stl_String_View.cpp +5 -0
  205. data/test/test_Stl_Tuple.cpp +116 -0
  206. data/test/test_Stl_Type.cpp +147 -0
  207. data/test/test_Stl_UniquePtr.cpp +202 -0
  208. data/test/test_Stl_Unordered_Map.cpp +43 -38
  209. data/test/test_Stl_Variant.cpp +217 -84
  210. data/test/test_Stl_Vector.cpp +306 -58
  211. data/test/test_String.cpp +5 -0
  212. data/test/test_Struct.cpp +5 -0
  213. data/test/test_Symbol.cpp +5 -0
  214. data/test/test_Template.cpp +192 -0
  215. data/test/test_To_Ruby.cpp +524 -0
  216. data/test/test_Tracking.cpp +1 -0
  217. data/test/test_Type.cpp +171 -0
  218. data/test/test_global_functions.cpp +67 -7
  219. data/test/unittest.cpp +8 -0
  220. metadata +127 -26
  221. data/lib/version.rb +0 -3
  222. data/rice/Address_Registration_Guard_defn.hpp +0 -79
  223. data/rice/Data_Object_defn.hpp +0 -84
  224. data/rice/Data_Type_defn.hpp +0 -190
  225. data/rice/Exception_defn.hpp +0 -68
  226. data/rice/HandlerRegistration.hpp +0 -15
  227. data/rice/detail/ExceptionHandler.hpp +0 -8
  228. data/rice/detail/ExceptionHandler.ipp +0 -28
  229. data/rice/detail/ExceptionHandler_defn.hpp +0 -77
  230. data/rice/detail/Jump_Tag.hpp +0 -21
  231. data/rice/detail/NativeAttribute.hpp +0 -64
  232. data/rice/detail/NativeAttribute.ipp +0 -112
  233. data/rice/detail/from_ruby_defn.hpp +0 -38
  234. data/rice/detail/to_ruby_defn.hpp +0 -48
  235. data/test/test_Jump_Tag.cpp +0 -17
  236. data/test/test_Stl_SmartPointer.cpp +0 -283
  237. data/test/test_To_From_Ruby.cpp +0 -399
data/include/rice/stl.hpp CHANGED
@@ -2,6 +2,79 @@
2
2
  #define Rice__stl__hpp_
3
3
 
4
4
 
5
+ // ========= exception.hpp =========
6
+
7
+ namespace Rice::stl
8
+ {
9
+ extern Class rb_cStlException;
10
+ }
11
+
12
+
13
+ // --------- exception.ipp ---------
14
+ #include <exception>
15
+
16
+ // Libraries sometime inherit custom exception objects from std::exception,
17
+ // so define it for Ruby if necessary
18
+ namespace Rice::stl
19
+ {
20
+ inline Class rb_cStlException;
21
+
22
+ inline void define_stl_exception()
23
+ {
24
+ Module rb_mStd = define_module("Std");
25
+ rb_cStlException = define_class_under<std::exception>(rb_mStd, "Exception", rb_eStandardError).
26
+ define_constructor(Constructor<std::exception>()).
27
+ define_method("message", &std::exception::what);
28
+ }
29
+ }
30
+
31
+ namespace Rice::detail
32
+ {
33
+ template<>
34
+ struct Type<std::exception>
35
+ {
36
+ static bool verify()
37
+ {
38
+ Rice::stl::define_stl_exception();
39
+ return true;
40
+ }
41
+ };
42
+ }
43
+
44
+
45
+ // ========= exception_ptr.hpp =========
46
+
47
+
48
+ // --------- exception_ptr.ipp ---------
49
+ #include <exception>
50
+
51
+ namespace Rice::stl
52
+ {
53
+ inline Data_Type<std::exception_ptr> define_exception_ptr()
54
+ {
55
+ Module rb_mStd = define_module("Std");
56
+ return define_class_under<std::exception_ptr>(rb_mStd, "ExceptionPtr");
57
+ }
58
+ }
59
+
60
+ namespace Rice::detail
61
+ {
62
+ template<>
63
+ struct Type<std::exception_ptr>
64
+ {
65
+ static bool verify()
66
+ {
67
+ if (!Data_Type<std::exception_ptr>::is_defined())
68
+ {
69
+ stl::define_exception_ptr();
70
+ }
71
+
72
+ return true;
73
+ }
74
+ };
75
+ }
76
+
77
+
5
78
  // ========= string.hpp =========
6
79
 
7
80
 
@@ -23,7 +96,7 @@ namespace Rice::detail
23
96
  class To_Ruby<std::string>
24
97
  {
25
98
  public:
26
- VALUE convert(std::string const& x)
99
+ VALUE convert(const std::string& x)
27
100
  {
28
101
  return detail::protect(rb_external_str_new, x.data(), (long)x.size());
29
102
  }
@@ -33,46 +106,46 @@ namespace Rice::detail
33
106
  class To_Ruby<std::string&>
34
107
  {
35
108
  public:
36
- VALUE convert(std::string const& x)
109
+ VALUE convert(const std::string& x)
37
110
  {
38
111
  return detail::protect(rb_external_str_new, x.data(), (long)x.size());
39
112
  }
40
113
  };
41
114
 
42
115
  template<>
43
- class From_Ruby<std::string>
116
+ class To_Ruby<std::string*>
44
117
  {
45
118
  public:
46
- From_Ruby() = default;
47
-
48
- explicit From_Ruby(Arg* arg) : arg_(arg)
119
+ VALUE convert(const std::string* x)
49
120
  {
121
+ return detail::protect(rb_external_str_new, x->data(), (long)x->size());
50
122
  }
123
+ };
51
124
 
52
- bool is_convertible(VALUE value)
125
+ template<>
126
+ class To_Ruby<std::string*&>
127
+ {
128
+ public:
129
+ VALUE convert(const std::string* x)
53
130
  {
54
- return rb_type(value) == RUBY_T_STRING;
131
+ return detail::protect(rb_external_str_new, x->data(), (long)x->size());
55
132
  }
133
+ };
56
134
 
57
- std::string convert(VALUE value)
135
+ template<>
136
+ class To_Ruby<std::string**>
137
+ {
138
+ public:
139
+ VALUE convert(std::string** data)
58
140
  {
59
- if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
60
- {
61
- return this->arg_->defaultValue<std::string>();
62
- }
63
- else
64
- {
65
- detail::protect(rb_check_type, value, (int)T_STRING);
66
- return std::string(RSTRING_PTR(value), RSTRING_LEN(value));
67
- }
141
+ Buffer<std::string*> buffer(data);
142
+ Data_Object<Buffer<std::string*>> dataObject(std::move(buffer));
143
+ return dataObject.value();
68
144
  }
69
-
70
- private:
71
- Arg* arg_ = nullptr;
72
145
  };
73
146
 
74
147
  template<>
75
- class From_Ruby<std::string&>
148
+ class From_Ruby<std::string>
76
149
  {
77
150
  public:
78
151
  From_Ruby() = default;
@@ -81,57 +154,76 @@ namespace Rice::detail
81
154
  {
82
155
  }
83
156
 
84
- bool is_convertible(VALUE value)
157
+ Convertible is_convertible(VALUE value)
85
158
  {
86
- return rb_type(value) == RUBY_T_STRING;
159
+ switch (rb_type(value))
160
+ {
161
+ case RUBY_T_STRING:
162
+ return Convertible::Exact;
163
+ break;
164
+ default:
165
+ return Convertible::None;
166
+ }
87
167
  }
88
168
 
89
- std::string& convert(VALUE value)
169
+ std::string convert(VALUE value)
90
170
  {
91
- if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
92
- {
93
- return this->arg_->defaultValue<std::string>();
94
- }
95
- else
96
- {
97
- detail::protect(rb_check_type, value, (int)T_STRING);
98
- this->converted_ = std::string(RSTRING_PTR(value), RSTRING_LEN(value));
99
- return this->converted_;
100
- }
171
+ detail::protect(rb_check_type, value, (int)T_STRING);
172
+ return std::string(RSTRING_PTR(value), RSTRING_LEN(value));
101
173
  }
102
174
 
103
175
  private:
104
176
  Arg* arg_ = nullptr;
105
- std::string converted_;
106
177
  };
107
178
 
108
179
  template<>
109
- class From_Ruby<std::string*>
180
+ class From_Ruby<std::string&>
110
181
  {
111
182
  public:
112
- bool is_convertible(VALUE value)
183
+ From_Ruby() = default;
184
+
185
+ explicit From_Ruby(Arg* arg) : arg_(arg)
113
186
  {
114
- return rb_type(value) == RUBY_T_STRING;
115
187
  }
116
188
 
117
- std::string* convert(VALUE value)
189
+ Convertible is_convertible(VALUE value)
190
+ {
191
+ switch (rb_type(value))
192
+ {
193
+ case RUBY_T_STRING:
194
+ return Convertible::Exact;
195
+ break;
196
+ default:
197
+ return Convertible::None;
198
+ }
199
+ }
200
+
201
+ std::string& convert(VALUE value)
118
202
  {
119
203
  detail::protect(rb_check_type, value, (int)T_STRING);
120
204
  this->converted_ = std::string(RSTRING_PTR(value), RSTRING_LEN(value));
121
- return &this->converted_;
205
+ return this->converted_;
122
206
  }
123
207
 
124
208
  private:
125
- std::string converted_;
209
+ Arg* arg_ = nullptr;
210
+ std::string converted_ = "";
126
211
  };
127
212
 
128
213
  template<>
129
- class From_Ruby<std::string*&>
214
+ class From_Ruby<std::string*>
130
215
  {
131
216
  public:
132
- bool is_convertible(VALUE value)
217
+ Convertible is_convertible(VALUE value)
133
218
  {
134
- return rb_type(value) == RUBY_T_STRING;
219
+ switch (rb_type(value))
220
+ {
221
+ case RUBY_T_STRING:
222
+ return Convertible::Exact;
223
+ break;
224
+ default:
225
+ return Convertible::None;
226
+ }
135
227
  }
136
228
 
137
229
  std::string* convert(VALUE value)
@@ -193,22 +285,22 @@ namespace Rice::detail
193
285
  {
194
286
  }
195
287
 
196
- bool is_convertible(VALUE value)
288
+ Convertible is_convertible(VALUE value)
197
289
  {
198
- return rb_type(value) == RUBY_T_STRING;
290
+ switch (rb_type(value))
291
+ {
292
+ case RUBY_T_STRING:
293
+ return Convertible::Exact;
294
+ break;
295
+ default:
296
+ return Convertible::None;
297
+ }
199
298
  }
200
299
 
201
300
  std::string_view convert(VALUE value)
202
301
  {
203
- if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
204
- {
205
- return this->arg_->defaultValue<std::string_view>();
206
- }
207
- else
208
- {
209
- detail::protect(rb_check_type, value, (int)T_STRING);
210
- return std::string_view(RSTRING_PTR(value), RSTRING_LEN(value));
211
- }
302
+ detail::protect(rb_check_type, value, (int)T_STRING);
303
+ return std::string_view(RSTRING_PTR(value), RSTRING_LEN(value));
212
304
  }
213
305
 
214
306
  private:
@@ -222,7 +314,6 @@ namespace Rice::detail
222
314
  // --------- complex.ipp ---------
223
315
  #include <complex>
224
316
 
225
-
226
317
  namespace Rice::detail
227
318
  {
228
319
  template<typename T>
@@ -247,10 +338,35 @@ namespace Rice::detail
247
338
  }
248
339
  };
249
340
 
341
+ template<typename T>
342
+ class To_Ruby<std::complex<T>&>
343
+ {
344
+ public:
345
+ VALUE convert(const std::complex<T>& data)
346
+ {
347
+ std::vector<VALUE> args(2);
348
+ args[0] = To_Ruby<T>().convert(data.real());
349
+ args[1] = To_Ruby<T>().convert(data.imag());
350
+ return protect(rb_funcallv, rb_mKernel, rb_intern("Complex"), (int)args.size(), (const VALUE*)args.data());
351
+ }
352
+ };
353
+
250
354
  template<typename T>
251
355
  class From_Ruby<std::complex<T>>
252
356
  {
253
357
  public:
358
+ Convertible is_convertible(VALUE value)
359
+ {
360
+ switch (rb_type(value))
361
+ {
362
+ case RUBY_T_COMPLEX:
363
+ return Convertible::Exact;
364
+ break;
365
+ default:
366
+ return Convertible::None;
367
+ }
368
+ }
369
+
254
370
  std::complex<T> convert(VALUE value)
255
371
  {
256
372
  VALUE real = protect(rb_funcallv, value, rb_intern("real"), 0, (const VALUE*)nullptr);
@@ -258,17 +374,24 @@ namespace Rice::detail
258
374
 
259
375
  return std::complex<T>(From_Ruby<T>().convert(real), From_Ruby<T>().convert(imaginary));
260
376
  }
261
-
262
- bool is_convertible(VALUE value)
263
- {
264
- return rb_type(value) == RUBY_T_COMPLEX;
265
- }
266
377
  };
267
378
 
268
379
  template<typename T>
269
380
  class From_Ruby<std::complex<T>&>
270
381
  {
271
382
  public:
383
+ Convertible is_convertible(VALUE value)
384
+ {
385
+ switch (rb_type(value))
386
+ {
387
+ case RUBY_T_COMPLEX:
388
+ return Convertible::Exact;
389
+ break;
390
+ default:
391
+ return Convertible::None;
392
+ }
393
+ }
394
+
272
395
  std::complex<T>& convert(VALUE value)
273
396
  {
274
397
  VALUE real = protect(rb_funcallv, value, rb_intern("real"), 0, (const VALUE*)nullptr);
@@ -278,11 +401,6 @@ namespace Rice::detail
278
401
  return this->converted_;
279
402
  }
280
403
 
281
- bool is_convertible(VALUE value)
282
- {
283
- return rb_type(value) == RUBY_T_COMPLEX;
284
- }
285
-
286
404
  private:
287
405
  std::complex<T> converted_;
288
406
  };
@@ -310,7 +428,7 @@ namespace Rice::detail
310
428
  class To_Ruby<std::nullopt_t>
311
429
  {
312
430
  public:
313
- VALUE convert(std::nullopt_t& _)
431
+ VALUE convert(const std::nullopt_t& _)
314
432
  {
315
433
  return Qnil;
316
434
  }
@@ -354,6 +472,18 @@ namespace Rice::detail
354
472
  class From_Ruby<std::optional<T>>
355
473
  {
356
474
  public:
475
+ Convertible is_convertible(VALUE value)
476
+ {
477
+ switch (rb_type(value))
478
+ {
479
+ case RUBY_T_NIL:
480
+ return Convertible::Exact;
481
+ break;
482
+ default:
483
+ return From_Ruby<T>().is_convertible(value);
484
+ }
485
+ }
486
+
357
487
  std::optional<T> convert(VALUE value)
358
488
  {
359
489
  if (value == Qnil)
@@ -371,6 +501,18 @@ namespace Rice::detail
371
501
  class From_Ruby<std::optional<T>&>
372
502
  {
373
503
  public:
504
+ Convertible is_convertible(VALUE value)
505
+ {
506
+ switch (rb_type(value))
507
+ {
508
+ case RUBY_T_NIL:
509
+ return Convertible::Exact;
510
+ break;
511
+ default:
512
+ return From_Ruby<T>().is_convertible(value);
513
+ }
514
+ }
515
+
374
516
  std::optional<T>& convert(VALUE value)
375
517
  {
376
518
  if (value == Qnil)
@@ -383,7 +525,6 @@ namespace Rice::detail
383
525
  }
384
526
  return this->converted_;
385
527
  }
386
-
387
528
  private:
388
529
  std::optional<T> converted_;
389
530
  };
@@ -421,9 +562,9 @@ namespace Rice::detail
421
562
  class From_Ruby<std::reference_wrapper<T>>
422
563
  {
423
564
  public:
424
- bool is_convertible(VALUE value)
565
+ Convertible is_convertible(VALUE value)
425
566
  {
426
- return true;
567
+ return this->converter_.is_convertible(value);
427
568
  }
428
569
 
429
570
  std::reference_wrapper<T> convert(VALUE value)
@@ -437,1166 +578,2585 @@ namespace Rice::detail
437
578
  }
438
579
 
439
580
 
440
- // ========= smart_ptr.hpp =========
441
-
581
+ // ========= pair.hpp =========
442
582
 
443
- namespace Rice::detail
583
+ namespace Rice
444
584
  {
445
- template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
446
- class WrapperSmartPointer : public Wrapper
447
- {
448
- public:
449
- WrapperSmartPointer(SmartPointer_T<Arg_Ts...> data);
450
- ~WrapperSmartPointer();
451
- void* get() override;
452
- SmartPointer_T<Arg_Ts...>& data();
453
-
454
- private:
455
- SmartPointer_T<Arg_Ts...> data_;
456
- };
585
+ template<typename T1, typename T2>
586
+ Data_Type<std::pair<T1, T2>> define_pair(std::string klassName = "");
457
587
  }
458
588
 
459
589
 
460
- // --------- smart_ptr.ipp ---------
461
-
462
- #include <assert.h>
463
- #include <memory>
590
+ // --------- pair.ipp ---------
591
+ #include <utility>
464
592
 
465
- namespace Rice::detail
593
+ namespace Rice
466
594
  {
467
- // ---- WrapperSmartPointer ------
468
- template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
469
- inline WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::WrapperSmartPointer(SmartPointer_T<Arg_Ts...> data)
470
- : data_(std::move(data))
471
- {
472
- }
473
-
474
- template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
475
- inline WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::~WrapperSmartPointer()
476
- {
477
- Registries::instance.instances.remove(this->get());
478
- }
479
-
480
- template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
481
- inline void* WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::get()
482
- {
483
- return (void*)this->data_.get();
484
- }
485
-
486
- template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
487
- inline SmartPointer_T<Arg_Ts...>& WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::data()
488
- {
489
- return data_;
490
- }
491
-
492
- // ---- unique_ptr ------
493
- template <typename T>
494
- class To_Ruby<std::unique_ptr<T>>
495
- {
496
- public:
497
- VALUE convert(std::unique_ptr<T>& data)
498
- {
499
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
500
-
501
- // Use custom wrapper type
502
- using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
503
- return detail::wrap<std::unique_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
504
- }
505
- };
506
-
507
- template <typename T>
508
- class To_Ruby<std::unique_ptr<T>&>
595
+ namespace stl
509
596
  {
510
- public:
511
- VALUE convert(std::unique_ptr<T>& data)
597
+ template<typename T>
598
+ class PairHelper
512
599
  {
513
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
600
+ public:
601
+ PairHelper(Data_Type<T> klass) : klass_(klass)
602
+ {
603
+ this->define_constructor();
604
+ this->define_copyable_methods();
605
+ this->define_access_methods();
606
+ this->define_modify_methods();
607
+ this->define_to_s();
608
+ }
514
609
 
515
- // Use custom wrapper type
516
- using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
517
- return detail::wrap<std::unique_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
518
- }
519
- };
610
+ private:
611
+ void define_constructor()
612
+ {
613
+ klass_.define_constructor(Constructor<T, typename T::first_type&, typename T::second_type&>());
614
+ }
520
615
 
521
- template <typename T>
522
- class From_Ruby<std::unique_ptr<T>&>
523
- {
524
- public:
525
- std::unique_ptr<T>& convert(VALUE value)
526
- {
527
- Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
616
+ void define_copyable_methods()
617
+ {
618
+ if constexpr (std::is_copy_constructible_v<typename T::first_type> && std::is_copy_constructible_v<typename T::second_type>)
619
+ {
620
+ klass_.define_method("copy", [](T& pair) -> T
621
+ {
622
+ return pair;
623
+ });
624
+ }
625
+ else
626
+ {
627
+ klass_.define_method("copy", [](T& pair) -> T
628
+ {
629
+ throw std::runtime_error("Cannot copy pair with non-copy constructible types");
630
+ return pair;
631
+ });
632
+ }
633
+ }
528
634
 
529
- using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
530
- Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
531
- if (!smartWrapper)
635
+ void define_access_methods()
532
636
  {
533
- std::string message = "Invalid smart pointer wrapper";
534
- throw std::runtime_error(message.c_str());
637
+ // Access methods
638
+ klass_.define_method("first", [](T& pair) -> typename T::first_type&
639
+ {
640
+ return pair.first;
641
+ })
642
+ .define_method("second", [](T& pair) -> typename T::second_type&
643
+ {
644
+ return pair.second;
645
+ });
535
646
  }
536
- return smartWrapper->data();
537
- }
538
- };
539
647
 
540
- template<typename T>
541
- struct Type<std::unique_ptr<T>>
648
+ void define_modify_methods()
649
+ {
650
+ // Access methods
651
+ klass_.define_method("first=", [](T& pair, typename T::first_type& value) -> typename T::first_type&
652
+ {
653
+ if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::first_type>>>)
654
+ {
655
+ throw std::runtime_error("Cannot set pair.first since it is a constant");
656
+ }
657
+ else
658
+ {
659
+ pair.first = value;
660
+ return pair.first;
661
+ }
662
+ })
663
+ .define_method("second=", [](T& pair, typename T::second_type& value) -> typename T::second_type&
664
+ {
665
+ if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::second_type>>>)
666
+ {
667
+ throw std::runtime_error("Cannot set pair.second since it is a constant");
668
+ }
669
+ else
670
+ {
671
+ pair.second = value;
672
+ return pair.second;
673
+ }
674
+ });
675
+ }
676
+
677
+ void define_to_s()
678
+ {
679
+ if constexpr (detail::is_ostreamable_v<typename T::first_type> && detail::is_ostreamable_v<typename T::second_type>)
680
+ {
681
+ klass_.define_method("to_s", [](const T& pair)
682
+ {
683
+ std::stringstream stream;
684
+ stream << "[" << pair.first << ", " << pair.second << "]";
685
+ return stream.str();
686
+ });
687
+ }
688
+ else
689
+ {
690
+ klass_.define_method("to_s", [](const T& pair)
691
+ {
692
+ return "[Not printable]";
693
+ });
694
+ }
695
+ }
696
+
697
+ private:
698
+ Data_Type<T> klass_;
699
+ };
700
+ } // namespace
701
+
702
+ template<typename T1, typename T2>
703
+ Data_Type<std::pair<T1, T2>> define_pair(std::string klassName)
704
+ {
705
+ using Pair_T = std::pair<T1, T2>;
706
+ using Data_Type_T = Data_Type<Pair_T>;
707
+
708
+ if (klassName.empty())
709
+ {
710
+ std::string typeName = detail::typeName(typeid(Pair_T));
711
+ klassName = detail::rubyClassName(typeName);
712
+ }
713
+
714
+ Module rb_mStd = define_module("Std");
715
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
716
+ {
717
+ return Data_Type_T();
718
+ }
719
+
720
+ Identifier id(klassName);
721
+ Data_Type_T result = define_class_under<detail::intrinsic_type<Pair_T>>(rb_mStd, id);
722
+ stl::PairHelper helper(result);
723
+ return result;
724
+ }
725
+
726
+ namespace detail
727
+ {
728
+ template<typename T1, typename T2>
729
+ struct Type<std::pair<T1, T2>>
730
+ {
731
+ static bool verify()
732
+ {
733
+ detail::verifyType<T1>();
734
+ detail::verifyType<T2>();
735
+
736
+ if (!Data_Type<std::pair<T1, T2>>::is_defined())
737
+ {
738
+ define_pair<T1, T2>();
739
+ }
740
+
741
+ return true;
742
+ }
743
+ };
744
+ }
745
+ }
746
+
747
+
748
+
749
+ // ========= map.hpp =========
750
+
751
+ namespace Rice
752
+ {
753
+ template<typename K, typename T>
754
+ Data_Type<std::map<K, T>> define_map(std::string name = "");
755
+ }
756
+
757
+
758
+ // --------- map.ipp ---------
759
+ #include <map>
760
+
761
+ namespace Rice
762
+ {
763
+ namespace stl
764
+ {
765
+ template<typename T>
766
+ class MapHelper
767
+ {
768
+ using Key_T = typename T::key_type;
769
+ using Mapped_T = typename T::mapped_type;
770
+ using Value_T = typename T::value_type;
771
+ using Reference_T = typename T::reference;
772
+ using Size_T = typename T::size_type;
773
+ using Difference_T = typename T::difference_type;
774
+ using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
775
+
776
+ public:
777
+ MapHelper(Data_Type<T> klass) : klass_(klass)
778
+ {
779
+ this->register_pair();
780
+ this->define_constructor();
781
+ this->define_copyable_methods();
782
+ this->define_capacity_methods();
783
+ this->define_access_methods();
784
+ this->define_comparable_methods();
785
+ this->define_modify_methods();
786
+ this->define_enumerable();
787
+ this->define_to_s();
788
+ this->define_to_hash();
789
+ }
790
+
791
+ private:
792
+
793
+ void register_pair()
794
+ {
795
+ define_pair<const Key_T, Mapped_T>();
796
+ }
797
+
798
+ void define_constructor()
799
+ {
800
+ klass_.define_constructor(Constructor<T>());
801
+ }
802
+
803
+ void define_copyable_methods()
804
+ {
805
+ if constexpr (std::is_copy_constructible_v<Value_T>)
806
+ {
807
+ klass_.define_method("copy", [](T& map) -> T
808
+ {
809
+ return map;
810
+ });
811
+ }
812
+ else
813
+ {
814
+ klass_.define_method("copy", [](T& map) -> T
815
+ {
816
+ throw std::runtime_error("Cannot copy maps with non-copy constructible types");
817
+ return map;
818
+ });
819
+ }
820
+ }
821
+
822
+ void define_capacity_methods()
823
+ {
824
+ klass_.define_method("empty?", &T::empty)
825
+ .define_method("max_size", &T::max_size)
826
+ .define_method("size", &T::size);
827
+
828
+ rb_define_alias(klass_, "count", "size");
829
+ rb_define_alias(klass_, "length", "size");
830
+ }
831
+
832
+ void define_access_methods()
833
+ {
834
+ // Access methods
835
+ klass_.define_method("[]", [](const T& map, const Key_T& key) -> std::optional<Mapped_T>
836
+ {
837
+ auto iter = map.find(key);
838
+
839
+ if (iter != map.end())
840
+ {
841
+ return iter->second;
842
+ }
843
+ else
844
+ {
845
+ return std::nullopt;
846
+ }
847
+ })
848
+ .define_method("include?", [](T& map, Key_T& key) -> bool
849
+ {
850
+ return map.find(key) != map.end();
851
+ })
852
+ .define_method("keys", [](T& map) -> std::vector<Key_T>
853
+ {
854
+ std::vector<Key_T> result;
855
+ std::transform(map.begin(), map.end(), std::back_inserter(result),
856
+ [](const auto& pair)
857
+ {
858
+ return pair.first;
859
+ });
860
+
861
+ return result;
862
+ })
863
+ .define_method("values", [](T& map) -> std::vector<Mapped_T>
864
+ {
865
+ std::vector<Mapped_T> result;
866
+ std::transform(map.begin(), map.end(), std::back_inserter(result),
867
+ [](const auto& pair)
868
+ {
869
+ return pair.second;
870
+ });
871
+
872
+ return result;
873
+ });
874
+
875
+ rb_define_alias(klass_, "has_key", "include?");
876
+ }
877
+
878
+ // Methods that require Value_T to support operator==
879
+ void define_comparable_methods()
880
+ {
881
+ if constexpr (detail::is_comparable_v<Mapped_T>)
882
+ {
883
+ klass_.define_method("value?", [](T& map, Mapped_T& value) -> bool
884
+ {
885
+ auto it = std::find_if(map.begin(), map.end(),
886
+ [&value](auto& pair)
887
+ {
888
+ return pair.second == value;
889
+ });
890
+
891
+ return it != map.end();
892
+ });
893
+ }
894
+ else
895
+ {
896
+ klass_.define_method("value?", [](T& map, Mapped_T& value) -> bool
897
+ {
898
+ return false;
899
+ });
900
+ }
901
+
902
+ rb_define_alias(klass_, "has_value", "value?");
903
+ }
904
+
905
+ void define_modify_methods()
906
+ {
907
+ klass_.define_method("clear", &T::clear)
908
+ .define_method("delete", [](T& map, Key_T& key) -> std::optional<Mapped_T>
909
+ {
910
+ auto iter = map.find(key);
911
+
912
+ if (iter != map.end())
913
+ {
914
+ Mapped_T result = iter->second;
915
+ map.erase(iter);
916
+ return result;
917
+ }
918
+ else
919
+ {
920
+ return std::nullopt;
921
+ }
922
+ })
923
+ .define_method("[]=", [](T& map, Key_T key, Mapped_T& value) -> Mapped_T
924
+ {
925
+ map[key] = value;
926
+ return value;
927
+ });
928
+
929
+ rb_define_alias(klass_, "store", "[]=");
930
+ }
931
+
932
+ void define_enumerable()
933
+ {
934
+ // Add enumerable support
935
+ klass_.template define_iterator<typename T::iterator (T::*)()>(&T::begin, &T::end);
936
+ }
937
+
938
+ void define_to_hash()
939
+ {
940
+ // Add enumerable support
941
+ klass_.define_method("to_h", [](T& map)
942
+ {
943
+ VALUE result = rb_hash_new();
944
+ std::for_each(map.begin(), map.end(), [&result](const Reference_T pair)
945
+ {
946
+ VALUE key = detail::To_Ruby<Key_T&>().convert(pair.first);
947
+ VALUE value = detail::To_Ruby<To_Ruby_T&>().convert(pair.second);
948
+ rb_hash_aset(result, key, value);
949
+ });
950
+
951
+ return result;
952
+ }, Return().setValue());
953
+ }
954
+
955
+ void define_to_s()
956
+ {
957
+ if constexpr (detail::is_ostreamable_v<Key_T> && detail::is_ostreamable_v<Mapped_T>)
958
+ {
959
+ klass_.define_method("to_s", [](const T& map)
960
+ {
961
+ auto iter = map.begin();
962
+
963
+ std::stringstream stream;
964
+ stream << "{";
965
+
966
+ for (; iter != map.end(); iter++)
967
+ {
968
+ if (iter != map.begin())
969
+ {
970
+ stream << ", ";
971
+ }
972
+ stream << iter->first << " => " << iter->second;
973
+ }
974
+
975
+ stream << "}";
976
+ return stream.str();
977
+ });
978
+ }
979
+ else
980
+ {
981
+ klass_.define_method("to_s", [](const T& map)
982
+ {
983
+ return "[Not printable]";
984
+ });
985
+ }
986
+ }
987
+
988
+ private:
989
+ Data_Type<T> klass_;
990
+ };
991
+ } // namespace
992
+
993
+ template<typename Key, typename T>
994
+ Data_Type<std::map<Key, T>> define_map(std::string klassName)
995
+ {
996
+ using Map_T = std::map<Key, T>;
997
+ using Data_Type_T = Data_Type<Map_T>;
998
+
999
+ if (klassName.empty())
1000
+ {
1001
+ std::string typeName = detail::typeName(typeid(Map_T));
1002
+ klassName = detail::rubyClassName(typeName);
1003
+ }
1004
+
1005
+ Module rb_mStd = define_module("Std");
1006
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
1007
+ {
1008
+ return Data_Type_T();
1009
+ }
1010
+
1011
+ Identifier id(klassName);
1012
+ Data_Type_T result = define_class_under<detail::intrinsic_type<Map_T>>(rb_mStd, id);
1013
+ stl::MapHelper helper(result);
1014
+ return result;
1015
+ }
1016
+
1017
+ namespace detail
1018
+ {
1019
+ template<typename Key_T, typename T>
1020
+ struct Type<std::map<Key_T, T>>
1021
+ {
1022
+ static bool verify()
1023
+ {
1024
+ Type<Key_T>::verify();
1025
+ Type<T>::verify();
1026
+
1027
+ if (!Data_Type<std::map<Key_T, T>>::is_defined())
1028
+ {
1029
+ define_map<Key_T, T>();
1030
+ }
1031
+
1032
+ return true;
1033
+ }
1034
+ };
1035
+
1036
+ template<typename T, typename U>
1037
+ struct MapFromHash
1038
+ {
1039
+ static int convertPair(VALUE key, VALUE value, VALUE user_data)
1040
+ {
1041
+ std::map<T, U>* result = (std::map<T, U>*)(user_data);
1042
+
1043
+ // This method is being called from Ruby so we cannot let any C++
1044
+ // exceptions propogate back to Ruby
1045
+ return cpp_protect([&]
1046
+ {
1047
+ result->operator[](From_Ruby<T>().convert(key)) = From_Ruby<U>().convert(value);
1048
+ return ST_CONTINUE;
1049
+ });
1050
+ }
1051
+
1052
+ static std::map<T, U> convert(VALUE value)
1053
+ {
1054
+ std::map<T, U> result;
1055
+ VALUE user_data = (VALUE)(&result);
1056
+
1057
+ // MSVC needs help here, but g++ does not
1058
+ using Rb_Hash_ForEach_T = void(*)(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE);
1059
+ detail::protect<Rb_Hash_ForEach_T>(rb_hash_foreach, value, convertPair, user_data);
1060
+
1061
+ return result;
1062
+ }
1063
+ };
1064
+
1065
+ template<typename T, typename U>
1066
+ class From_Ruby<std::map<T, U>>
1067
+ {
1068
+ public:
1069
+ From_Ruby() = default;
1070
+
1071
+ explicit From_Ruby(Arg * arg) : arg_(arg)
1072
+ {
1073
+ }
1074
+
1075
+ Convertible is_convertible(VALUE value)
1076
+ {
1077
+ switch (rb_type(value))
1078
+ {
1079
+ case RUBY_T_DATA:
1080
+ return Data_Type<std::map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1081
+ break;
1082
+ case RUBY_T_HASH:
1083
+ return Convertible::Cast;
1084
+ break;
1085
+ default:
1086
+ return Convertible::None;
1087
+ }
1088
+ }
1089
+
1090
+ std::map<T, U> convert(VALUE value)
1091
+ {
1092
+ switch (rb_type(value))
1093
+ {
1094
+ case RUBY_T_DATA:
1095
+ {
1096
+ // This is a wrapped map (hopefully!)
1097
+ return *detail::unwrap<std::map<T, U>>(value, Data_Type<std::map<T, U>>::ruby_data_type(), false);
1098
+ }
1099
+ case RUBY_T_HASH:
1100
+ {
1101
+ // If this an Ruby hash and the mapped type is copyable
1102
+ if constexpr (std::is_default_constructible_v<U>)
1103
+ {
1104
+ return MapFromHash<T, U>::convert(value);
1105
+ }
1106
+ }
1107
+ default:
1108
+ {
1109
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1110
+ detail::protect(rb_obj_classname, value), "std::map");
1111
+ }
1112
+ }
1113
+ }
1114
+
1115
+ private:
1116
+ Arg* arg_ = nullptr;
1117
+ };
1118
+
1119
+ template<typename T, typename U>
1120
+ class From_Ruby<std::map<T, U>&>
1121
+ {
1122
+ public:
1123
+ From_Ruby() = default;
1124
+
1125
+ explicit From_Ruby(Arg * arg) : arg_(arg)
1126
+ {
1127
+ }
1128
+
1129
+ Convertible is_convertible(VALUE value)
1130
+ {
1131
+ switch (rb_type(value))
1132
+ {
1133
+ case RUBY_T_DATA:
1134
+ return Data_Type<std::map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1135
+ break;
1136
+ case RUBY_T_HASH:
1137
+ return Convertible::Cast;
1138
+ break;
1139
+ default:
1140
+ return Convertible::None;
1141
+ }
1142
+ }
1143
+
1144
+ std::map<T, U>& convert(VALUE value)
1145
+ {
1146
+ switch (rb_type(value))
1147
+ {
1148
+ case RUBY_T_DATA:
1149
+ {
1150
+ // This is a wrapped map (hopefully!)
1151
+ return *detail::unwrap<std::map<T, U>>(value, Data_Type<std::map<T, U>>::ruby_data_type(), false);
1152
+ }
1153
+ case RUBY_T_HASH:
1154
+ {
1155
+ // If this an Ruby array and the map type is copyable
1156
+ if constexpr (std::is_default_constructible_v<std::map<T, U>>)
1157
+ {
1158
+ this->converted_ = MapFromHash<T, U>::convert(value);
1159
+ return this->converted_;
1160
+ }
1161
+ }
1162
+ default:
1163
+ {
1164
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1165
+ detail::protect(rb_obj_classname, value), "std::map");
1166
+ }
1167
+ }
1168
+ }
1169
+
1170
+ private:
1171
+ Arg* arg_ = nullptr;
1172
+ std::map<T, U> converted_;
1173
+ };
1174
+
1175
+ template<typename T, typename U>
1176
+ class From_Ruby<std::map<T, U>*>
1177
+ {
1178
+ public:
1179
+ Convertible is_convertible(VALUE value)
1180
+ {
1181
+ switch (rb_type(value))
1182
+ {
1183
+ case RUBY_T_DATA:
1184
+ return Data_Type<std::map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1185
+ break;
1186
+ case RUBY_T_NIL:
1187
+ return Convertible::Exact;
1188
+ break;
1189
+ case RUBY_T_HASH:
1190
+ return Convertible::Cast;
1191
+ break;
1192
+ default:
1193
+ return Convertible::None;
1194
+ }
1195
+ }
1196
+
1197
+ std::map<T, U>* convert(VALUE value)
1198
+ {
1199
+ switch (rb_type(value))
1200
+ {
1201
+ case RUBY_T_DATA:
1202
+ {
1203
+ // This is a wrapped map (hopefully!)
1204
+ return detail::unwrap<std::map<T, U>>(value, Data_Type<std::map<T, U>>::ruby_data_type(), false);
1205
+ }
1206
+ case RUBY_T_HASH:
1207
+ {
1208
+ // If this an Ruby array and the map type is copyable
1209
+ if constexpr (std::is_default_constructible_v<U>)
1210
+ {
1211
+ this->converted_ = MapFromHash<T, U>::convert(value);
1212
+ return &this->converted_;
1213
+ }
1214
+ }
1215
+ default:
1216
+ {
1217
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1218
+ detail::protect(rb_obj_classname, value), "std::map");
1219
+ }
1220
+ }
1221
+ }
1222
+
1223
+ private:
1224
+ std::map<T, U> converted_;
1225
+ };
1226
+ }
1227
+ }
1228
+
1229
+ // ========= monostate.hpp =========
1230
+
1231
+
1232
+ // --------- monostate.ipp ---------
1233
+ #include <variant>
1234
+
1235
+ namespace Rice::detail
1236
+ {
1237
+ template<>
1238
+ struct Type<std::monostate>
1239
+ {
1240
+ constexpr static bool verify()
1241
+ {
1242
+ return true;
1243
+ }
1244
+ };
1245
+
1246
+ template<>
1247
+ class To_Ruby<std::monostate>
1248
+ {
1249
+ public:
1250
+ VALUE convert(const std::monostate& _)
1251
+ {
1252
+ return Qnil;
1253
+ }
1254
+ };
1255
+
1256
+ template<>
1257
+ class To_Ruby<std::monostate&>
1258
+ {
1259
+ public:
1260
+ static VALUE convert(const std::monostate& data, bool takeOwnership = false)
1261
+ {
1262
+ return Qnil;
1263
+ }
1264
+ };
1265
+
1266
+ template<>
1267
+ class From_Ruby<std::monostate>
1268
+ {
1269
+ public:
1270
+ Convertible is_convertible(VALUE value)
1271
+ {
1272
+ return value == Qnil ? Convertible::Exact : Convertible::None;
1273
+ }
1274
+
1275
+ std::monostate convert(VALUE value)
1276
+ {
1277
+ if (value == Qnil)
1278
+ {
1279
+ return std::monostate();
1280
+ }
1281
+ else
1282
+ {
1283
+ throw std::runtime_error("Can only convert nil values to std::monostate");
1284
+ }
1285
+ }
1286
+ };
1287
+
1288
+ template<>
1289
+ class From_Ruby<std::monostate&>
1290
+ {
1291
+ public:
1292
+ Convertible is_convertible(VALUE value)
1293
+ {
1294
+ return value == Qnil ? Convertible::Exact : Convertible::None;
1295
+ }
1296
+
1297
+ std::monostate& convert(VALUE value)
1298
+ {
1299
+ if (value == Qnil)
1300
+ {
1301
+ return this->converted_;
1302
+ }
1303
+ else
1304
+ {
1305
+ throw std::runtime_error("Can only convert nil values to std::monostate");
1306
+ }
1307
+ }
1308
+
1309
+ private:
1310
+ std::monostate converted_ = std::monostate();
1311
+ };
1312
+ }
1313
+
1314
+
1315
+ // ========= multimap.hpp =========
1316
+
1317
+ #include <map>
1318
+
1319
+ namespace Rice
1320
+ {
1321
+ template<typename K, typename T>
1322
+ Data_Type<std::multimap<K, T>> define_multimap(std::string name = "");
1323
+ }
1324
+
1325
+
1326
+ // --------- multimap.ipp ---------
1327
+ #include <map>
1328
+
1329
+ namespace Rice
1330
+ {
1331
+ namespace stl
1332
+ {
1333
+ template<typename T>
1334
+ class MultimapHelper
1335
+ {
1336
+ using Key_T = typename T::key_type;
1337
+ using Mapped_T = typename T::mapped_type;
1338
+ using Value_T = typename T::value_type;
1339
+ using Reference_T = typename T::reference;
1340
+ using Size_T = typename T::size_type;
1341
+ using Difference_T = typename T::difference_type;
1342
+ using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
1343
+
1344
+ public:
1345
+ MultimapHelper(Data_Type<T> klass) : klass_(klass)
1346
+ {
1347
+ this->register_pair();
1348
+ this->define_constructor();
1349
+ this->define_copyable_methods();
1350
+ this->define_capacity_methods();
1351
+ this->define_access_methods();
1352
+ this->define_comparable_methods();
1353
+ this->define_modify_methods();
1354
+ this->define_enumerable();
1355
+ this->define_to_s();
1356
+ }
1357
+
1358
+ private:
1359
+
1360
+ void register_pair()
1361
+ {
1362
+ define_pair<const Key_T, Mapped_T>();
1363
+ }
1364
+
1365
+ void define_constructor()
1366
+ {
1367
+ klass_.define_constructor(Constructor<T>());
1368
+ }
1369
+
1370
+ void define_copyable_methods()
1371
+ {
1372
+ if constexpr (std::is_copy_constructible_v<Value_T>)
1373
+ {
1374
+ klass_.define_method("copy", [](T& multimap) -> T
1375
+ {
1376
+ return multimap;
1377
+ });
1378
+ }
1379
+ else
1380
+ {
1381
+ klass_.define_method("copy", [](T& multimap) -> T
1382
+ {
1383
+ throw std::runtime_error("Cannot copy multimaps with non-copy constructible types");
1384
+ return multimap;
1385
+ });
1386
+ }
1387
+ }
1388
+
1389
+ void define_capacity_methods()
1390
+ {
1391
+ klass_.define_method("empty?", &T::empty)
1392
+ .define_method("max_size", &T::max_size)
1393
+ .define_method("size", &T::size);
1394
+
1395
+ rb_define_alias(klass_, "count", "size");
1396
+ rb_define_alias(klass_, "length", "size");
1397
+ }
1398
+
1399
+ void define_access_methods()
1400
+ {
1401
+ // Access methods
1402
+ klass_.
1403
+ define_method("[]", [](const T& multimap, const Key_T& key) -> Array
1404
+ {
1405
+ Array result;
1406
+ auto range = multimap.equal_range(key);
1407
+
1408
+ for (auto iter = range.first; iter != range.second; iter++)
1409
+ {
1410
+ result.push<Mapped_T>(iter->second);
1411
+ }
1412
+
1413
+ return result;
1414
+ })
1415
+ .define_method("include?", [](T& multimap, Key_T& key) -> bool
1416
+ {
1417
+ return multimap.find(key) != multimap.end();
1418
+ })
1419
+ .define_method("keys", [](T& multimap) -> std::vector<Key_T>
1420
+ {
1421
+ std::vector<Key_T> result;
1422
+ std::transform(multimap.begin(), multimap.end(), std::back_inserter(result),
1423
+ [](const auto& pair)
1424
+ {
1425
+ return pair.first;
1426
+ });
1427
+
1428
+ return result;
1429
+ })
1430
+ .define_method("values", [](T& multimap) -> std::vector<Mapped_T>
1431
+ {
1432
+ std::vector<Mapped_T> result;
1433
+ std::transform(multimap.begin(), multimap.end(), std::back_inserter(result),
1434
+ [](const auto& pair)
1435
+ {
1436
+ return pair.second;
1437
+ });
1438
+
1439
+ return result;
1440
+ });
1441
+
1442
+ rb_define_alias(klass_, "has_key", "include?");
1443
+ }
1444
+
1445
+ // Methods that require Value_T to support operator==
1446
+ void define_comparable_methods()
1447
+ {
1448
+ if constexpr (detail::is_comparable_v<Mapped_T>)
1449
+ {
1450
+ klass_.define_method("value?", [](T& multimap, Mapped_T& value) -> bool
1451
+ {
1452
+ auto it = std::find_if(multimap.begin(), multimap.end(),
1453
+ [&value](auto& pair)
1454
+ {
1455
+ return pair.second == value;
1456
+ });
1457
+
1458
+ return it != multimap.end();
1459
+ });
1460
+ }
1461
+ else
1462
+ {
1463
+ klass_.define_method("value?", [](T& multimap, Mapped_T& value) -> bool
1464
+ {
1465
+ return false;
1466
+ });
1467
+ }
1468
+
1469
+ rb_define_alias(klass_, "has_value", "value?");
1470
+ }
1471
+
1472
+ void define_modify_methods()
1473
+ {
1474
+ klass_.define_method("clear", &T::clear)
1475
+ .define_method("delete", [](T& multimap, Key_T& key) -> std::optional<Mapped_T>
1476
+ {
1477
+ auto iter = multimap.find(key);
1478
+
1479
+ if (iter != multimap.end())
1480
+ {
1481
+ Mapped_T result = iter->second;
1482
+ multimap.erase(iter);
1483
+ return result;
1484
+ }
1485
+ else
1486
+ {
1487
+ return std::nullopt;
1488
+ }
1489
+ })
1490
+ .define_method("insert", [](T& map, Key_T key, Mapped_T& value) -> Mapped_T
1491
+ {
1492
+ Value_T element{ key, value };
1493
+ map.insert(element);
1494
+ return value;
1495
+ });
1496
+ }
1497
+
1498
+ void define_enumerable()
1499
+ {
1500
+ // Add enumerable support
1501
+ klass_.template define_iterator<typename T::iterator (T::*)()>(&T::begin, &T::end);
1502
+ }
1503
+
1504
+ void define_to_s()
1505
+ {
1506
+ if constexpr (detail::is_ostreamable_v<Key_T> && detail::is_ostreamable_v<Mapped_T>)
1507
+ {
1508
+ klass_.define_method("to_s", [](const T& multimap)
1509
+ {
1510
+ auto iter = multimap.begin();
1511
+
1512
+ std::stringstream stream;
1513
+ stream << "<" << detail::rubyClassName(detail::typeName(typeid(T))) << ":";
1514
+ stream << "{";
1515
+
1516
+ for (; iter != multimap.end(); iter++)
1517
+ {
1518
+ if (iter != multimap.begin())
1519
+ {
1520
+ stream << ", ";
1521
+ }
1522
+ stream << iter->first << " => " << iter->second;
1523
+ }
1524
+
1525
+ stream << "}>";
1526
+ return stream.str();
1527
+ });
1528
+ }
1529
+ else
1530
+ {
1531
+ klass_.define_method("to_s", [](const T& multimap)
1532
+ {
1533
+ return "[Not printable]";
1534
+ });
1535
+ }
1536
+ }
1537
+
1538
+ private:
1539
+ Data_Type<T> klass_;
1540
+ };
1541
+ } // namespace
1542
+
1543
+ template<typename Key, typename T>
1544
+ Data_Type<std::multimap<Key, T>> define_multimap(std::string klassName)
1545
+ {
1546
+ using MultiMap_T = std::multimap<Key, T>;
1547
+ using Data_Type_T = Data_Type<MultiMap_T>;
1548
+
1549
+ if (klassName.empty())
1550
+ {
1551
+ std::string typeName = detail::typeName(typeid(MultiMap_T));
1552
+ klassName = detail::rubyClassName(typeName);
1553
+ }
1554
+
1555
+ Module rb_mStd = define_module("Std");
1556
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
1557
+ {
1558
+ return Data_Type_T();
1559
+ }
1560
+
1561
+ Identifier id(klassName);
1562
+ Data_Type_T result = define_class_under<detail::intrinsic_type<MultiMap_T>>(rb_mStd, id);
1563
+ stl::MultimapHelper helper(result);
1564
+ return result;
1565
+ }
1566
+
1567
+ namespace detail
1568
+ {
1569
+ // Helper method - maybe someday create a C++ Ruby set wrapper
1570
+ template<typename T, typename U>
1571
+ std::multimap<T, U> toMultimap(VALUE rubyHash)
1572
+ {
1573
+ using Function_T = void(*)(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE);
1574
+
1575
+ auto block = [](VALUE key, VALUE value, VALUE user_data) -> int
1576
+ {
1577
+ using Key_T = typename std::multimap<T, U>::key_type;
1578
+ using Mapped_T = typename std::multimap<T, U>::mapped_type;
1579
+ using Value_T = typename std::multimap<T, U>::value_type;
1580
+
1581
+ return cpp_protect([&]
1582
+ {
1583
+ Value_T pair = { From_Ruby<Key_T>().convert(key), From_Ruby<Mapped_T>().convert(value) };
1584
+ std::multimap<T, U>* result = (std::multimap<T, U>*)user_data;
1585
+ result->insert(pair);
1586
+ return ST_CONTINUE;
1587
+ });
1588
+ };
1589
+
1590
+ std::multimap<T, U> result;
1591
+ detail::protect<Function_T>(rb_hash_foreach, rubyHash, block, (VALUE)&result);
1592
+ return result;
1593
+ }
1594
+
1595
+ template<typename Key_T, typename T>
1596
+ struct Type<std::multimap<Key_T, T>>
1597
+ {
1598
+ static bool verify()
1599
+ {
1600
+ Type<Key_T>::verify();
1601
+ Type<Key_T>::verify();
1602
+
1603
+ if (!Data_Type<std::multimap<Key_T, T>>::is_defined())
1604
+ {
1605
+ define_multimap<Key_T, T>();
1606
+ }
1607
+
1608
+ return true;
1609
+ }
1610
+ };
1611
+
1612
+ template<typename T, typename U>
1613
+ class From_Ruby<std::multimap<T, U>>
1614
+ {
1615
+ public:
1616
+ From_Ruby() = default;
1617
+
1618
+ explicit From_Ruby(Arg * arg) : arg_(arg)
1619
+ {
1620
+ }
1621
+
1622
+ Convertible is_convertible(VALUE value)
1623
+ {
1624
+ switch (rb_type(value))
1625
+ {
1626
+ case RUBY_T_DATA:
1627
+ return Data_Type<std::multimap<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1628
+ break;
1629
+ case RUBY_T_HASH:
1630
+ return Convertible::Cast;
1631
+ break;
1632
+ default:
1633
+ return Convertible::None;
1634
+ }
1635
+ }
1636
+
1637
+ std::multimap<T, U> convert(VALUE value)
1638
+ {
1639
+ switch (rb_type(value))
1640
+ {
1641
+ case RUBY_T_DATA:
1642
+ {
1643
+ // This is a wrapped multimap (hopefully!)
1644
+ return *detail::unwrap<std::multimap<T, U>>(value, Data_Type<std::multimap<T, U>>::ruby_data_type(), false);
1645
+ }
1646
+ case RUBY_T_HASH:
1647
+ {
1648
+ // If this an Ruby hash and the multimapped type is copyable
1649
+ if constexpr (std::is_default_constructible_v<U>)
1650
+ {
1651
+ return toMultimap<T, U>(value);
1652
+ }
1653
+ }
1654
+ default:
1655
+ {
1656
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1657
+ detail::protect(rb_obj_classname, value), "std::multimap");
1658
+ }
1659
+ }
1660
+ }
1661
+
1662
+ private:
1663
+ Arg* arg_ = nullptr;
1664
+ };
1665
+
1666
+ template<typename T, typename U>
1667
+ class From_Ruby<std::multimap<T, U>&>
1668
+ {
1669
+ public:
1670
+ From_Ruby() = default;
1671
+
1672
+ explicit From_Ruby(Arg * arg) : arg_(arg)
1673
+ {
1674
+ }
1675
+
1676
+ Convertible is_convertible(VALUE value)
1677
+ {
1678
+ switch (rb_type(value))
1679
+ {
1680
+ case RUBY_T_DATA:
1681
+ return Data_Type<std::multimap<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1682
+ break;
1683
+ case RUBY_T_HASH:
1684
+ return Convertible::Cast;
1685
+ break;
1686
+ default:
1687
+ return Convertible::None;
1688
+ }
1689
+ }
1690
+
1691
+ std::multimap<T, U>& convert(VALUE value)
1692
+ {
1693
+ switch (rb_type(value))
1694
+ {
1695
+ case RUBY_T_DATA:
1696
+ {
1697
+ // This is a wrapped multimap (hopefully!)
1698
+ return *detail::unwrap<std::multimap<T, U>>(value, Data_Type<std::multimap<T, U>>::ruby_data_type(), false);
1699
+ }
1700
+ case RUBY_T_HASH:
1701
+ {
1702
+ // If this an Ruby array and the multimap type is copyable
1703
+ if constexpr (std::is_default_constructible_v<std::multimap<T, U>>)
1704
+ {
1705
+ this->converted_ = toMultimap<T, U>(value);
1706
+ return this->converted_;
1707
+ }
1708
+ }
1709
+ default:
1710
+ {
1711
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1712
+ detail::protect(rb_obj_classname, value), "std::multimap");
1713
+ }
1714
+ }
1715
+ }
1716
+
1717
+ private:
1718
+ Arg* arg_ = nullptr;
1719
+ std::multimap<T, U> converted_;
1720
+ };
1721
+
1722
+ template<typename T, typename U>
1723
+ class From_Ruby<std::multimap<T, U>*>
1724
+ {
1725
+ public:
1726
+ Convertible is_convertible(VALUE value)
1727
+ {
1728
+ switch (rb_type(value))
1729
+ {
1730
+ case RUBY_T_DATA:
1731
+ return Data_Type<std::multimap<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1732
+ break;
1733
+ case RUBY_T_NIL:
1734
+ return Convertible::Exact;
1735
+ break;
1736
+ case RUBY_T_HASH:
1737
+ return Convertible::Cast;
1738
+ break;
1739
+ default:
1740
+ return Convertible::None;
1741
+ }
1742
+ }
1743
+
1744
+ std::multimap<T, U>* convert(VALUE value)
1745
+ {
1746
+ switch (rb_type(value))
1747
+ {
1748
+ case RUBY_T_DATA:
1749
+ {
1750
+ // This is a wrapped multimap (hopefully!)
1751
+ return detail::unwrap<std::multimap<T, U>>(value, Data_Type<std::multimap<T, U>>::ruby_data_type(), false);
1752
+ }
1753
+ case RUBY_T_HASH:
1754
+ {
1755
+ // If this an Ruby array and the multimap type is copyable
1756
+ if constexpr (std::is_default_constructible_v<U>)
1757
+ {
1758
+ this->converted_ = toMultimap<T, U>(value);
1759
+ return &this->converted_;
1760
+ }
1761
+ }
1762
+ default:
1763
+ {
1764
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1765
+ detail::protect(rb_obj_classname, value), "std::multimap");
1766
+ }
1767
+ }
1768
+ }
1769
+
1770
+ private:
1771
+ std::multimap<T, U> converted_;
1772
+ };
1773
+ }
1774
+ }
1775
+
1776
+ // ========= set.hpp =========
1777
+
1778
+ namespace Rice
1779
+ {
1780
+ template<typename T>
1781
+ Data_Type<std::set<T>> define_set(std::string klassName = "");
1782
+ }
1783
+
1784
+
1785
+ // --------- set.ipp ---------
1786
+ #include <set>
1787
+
1788
+ namespace Rice
1789
+ {
1790
+ namespace stl
542
1791
  {
543
- static bool verify()
1792
+ template<typename T>
1793
+ class SetHelper
544
1794
  {
545
- return Type<T>::verify();
546
- }
547
- };
1795
+ // We do NOT use Reference_T and instead use Parameter_T to avoid the weirdness
1796
+ // of std::set<bool>. Reference_T is actually a proxy class that we do not
1797
+ // want to have to register with Rice nor do we want to pass it around.
1798
+ using Key_T = typename T::key_type;
1799
+ using Value_T = typename T::value_type;
1800
+ using Size_T = typename T::size_type;
1801
+ using Difference_T = typename T::difference_type;
1802
+ // For To_Ruby_T however we do need to use reference type because this is what
1803
+ // will be passed by an interator to To_Ruby#convert
1804
+ using Reference_T = typename T::reference;
1805
+ using Parameter_T = std::conditional_t<std::is_pointer_v<Value_T>, Value_T, Value_T&>;
1806
+ using To_Ruby_T = detail::remove_cv_recursive_t<typename T::reference>;
548
1807
 
549
- // ----- shared_ptr -------------
550
- template <typename T>
551
- class To_Ruby<std::shared_ptr<T>>
1808
+ public:
1809
+ SetHelper(Data_Type<T> klass) : klass_(klass)
1810
+ {
1811
+ this->define_constructors();
1812
+ this->define_capacity_methods();
1813
+ this->define_comparable_methods();
1814
+ this->define_modify_methods();
1815
+ this->define_operators();
1816
+ this->define_enumerable();
1817
+ this->define_to_array();
1818
+ this->define_to_s();
1819
+ }
1820
+
1821
+ private:
1822
+
1823
+ void define_constructors()
1824
+ {
1825
+ klass_.define_constructor(Constructor<T>())
1826
+ .define_constructor(Constructor<T, const T&>());
1827
+ }
1828
+
1829
+ void define_capacity_methods()
1830
+ {
1831
+ klass_.define_method("empty?", &T::empty)
1832
+ .define_method("max_size", &T::max_size)
1833
+ .define_method("size", &T::size);
1834
+
1835
+ rb_define_alias(klass_, "count", "size");
1836
+ rb_define_alias(klass_, "length", "size");
1837
+ }
1838
+
1839
+ void define_comparable_methods()
1840
+ {
1841
+ klass_
1842
+ .define_method("include?", [](T& self, const Key_T element) -> bool
1843
+ {
1844
+ auto iter = self.find(element);
1845
+ return iter != self.end();
1846
+ })
1847
+ .define_method("count", [](T& self, const Key_T element) -> Size_T
1848
+ {
1849
+ return self.count(element);
1850
+ });
1851
+ }
1852
+
1853
+ void define_modify_methods()
1854
+ {
1855
+ klass_
1856
+ .define_method("clear", &T::clear)
1857
+ .define_method("delete", [](T& self, const Key_T key) -> T&
1858
+ {
1859
+ self.erase(key);
1860
+ return self;
1861
+ })
1862
+ .define_method("insert", [](T& self, const Value_T value) -> T&
1863
+ {
1864
+ self.insert(value);
1865
+ return self;
1866
+ })
1867
+ .define_method("merge", [](T& self, T& other) -> T&
1868
+ {
1869
+ self.merge(other);
1870
+ return self;
1871
+ });
1872
+
1873
+ rb_define_alias(klass_, "erase", "delete");
1874
+ }
1875
+
1876
+ void define_operators()
1877
+ {
1878
+ klass_
1879
+ .define_method("<<", [](T& self, const Value_T value) -> T&
1880
+ {
1881
+ self.insert(value);
1882
+ return self;
1883
+ })
1884
+ .define_method("==", [](const T& self, const T& other) -> bool
1885
+ {
1886
+ if constexpr (detail::is_comparable_v<Value_T>)
1887
+ {
1888
+ return self == other;
1889
+ }
1890
+ else
1891
+ {
1892
+ return false;
1893
+ }
1894
+ })
1895
+ .define_method("&", [](const T& self, const T& other) -> T
1896
+ {
1897
+ T result;
1898
+ std::set_intersection(self.begin(), self.end(),
1899
+ other.begin(), other.end(),
1900
+ std::inserter(result, result.begin()));
1901
+
1902
+ return result;
1903
+ })
1904
+ .define_method("|", [](const T& self, const T& other) -> T
1905
+ {
1906
+ T result;
1907
+ std::set_union(self.begin(), self.end(),
1908
+ other.begin(), other.end(),
1909
+ std::inserter(result, result.begin()));
1910
+
1911
+ return result;
1912
+ })
1913
+ .define_method("-", [](const T& self, const T& other) -> T
1914
+ {
1915
+ T result;
1916
+ std::set_difference(self.begin(), self.end(),
1917
+ other.begin(), other.end(),
1918
+ std::inserter(result, result.begin()));
1919
+
1920
+ return result;
1921
+ })
1922
+ .define_method("^", [](const T& self, const T& other) -> T
1923
+ {
1924
+ T result;
1925
+ std::set_symmetric_difference(self.begin(), self.end(),
1926
+ other.begin(), other.end(),
1927
+ std::inserter(result, result.begin()));
1928
+
1929
+ return result;
1930
+ })
1931
+ .define_method("<", [](const T& self, const T& other) -> bool
1932
+ {
1933
+ return std::includes(other.begin(), other.end(),
1934
+ self.begin(), self.end());
1935
+ })
1936
+ .define_method(">", [](const T& self, const T& other) -> bool
1937
+ {
1938
+ return std::includes(self.begin(), self.end(),
1939
+ other.begin(), other.end());
1940
+ });
1941
+
1942
+ rb_define_alias(klass_, "eql?", "==");
1943
+ rb_define_alias(klass_, "intersection", "&");
1944
+ rb_define_alias(klass_, "union", "|");
1945
+ rb_define_alias(klass_, "difference", "-");
1946
+ rb_define_alias(klass_, "proper_subset?", "<");
1947
+ rb_define_alias(klass_, "subset?", "<");
1948
+ rb_define_alias(klass_, "proper_superset?", ">");
1949
+ rb_define_alias(klass_, "superset?", ">");
1950
+ }
1951
+
1952
+ void define_enumerable()
1953
+ {
1954
+ // Add enumerable support
1955
+ klass_.template define_iterator<typename T::iterator(T::*)() const>(&T::begin, &T::end);
1956
+ }
1957
+
1958
+ void define_to_array()
1959
+ {
1960
+ // Add enumerable support
1961
+ klass_.define_method("to_a", [](T& self) -> VALUE
1962
+ {
1963
+ Array array;
1964
+ for (const Value_T& element: self)
1965
+ {
1966
+ array.push(element);
1967
+ }
1968
+
1969
+ return array.value();
1970
+ }, Return().setValue());
1971
+ }
1972
+
1973
+ void define_to_s()
1974
+ {
1975
+ if constexpr (detail::is_ostreamable_v<Value_T>)
1976
+ {
1977
+ klass_.define_method("to_s", [](const T& self)
1978
+ {
1979
+ auto iter = self.begin();
1980
+ auto finish = self.end();
1981
+
1982
+ std::stringstream stream;
1983
+ stream << "<" << detail::rubyClassName(detail::typeName(typeid(T))) << ":";
1984
+ stream << "{";
1985
+
1986
+ for (; iter != finish; iter++)
1987
+ {
1988
+ if (iter == self.begin())
1989
+ {
1990
+ stream << *iter;
1991
+ }
1992
+ else
1993
+ {
1994
+ stream << ", " << *iter;
1995
+ }
1996
+ }
1997
+
1998
+ stream << "}>";
1999
+ return stream.str();
2000
+ });
2001
+ }
2002
+ else
2003
+ {
2004
+ klass_.define_method("to_s", [](const T& self)
2005
+ {
2006
+ return "[Not printable]";
2007
+ });
2008
+ }
2009
+ }
2010
+
2011
+ private:
2012
+ Data_Type<T> klass_;
2013
+ };
2014
+ } // namespace
2015
+
2016
+ template<typename T>
2017
+ Data_Type<std::set<T>> define_set(std::string klassName)
552
2018
  {
553
- public:
554
- VALUE convert(std::shared_ptr<T>& data)
2019
+ using Set_T = std::set<T>;
2020
+ using Data_Type_T = Data_Type<Set_T>;
2021
+
2022
+ if (klassName.empty())
555
2023
  {
556
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
2024
+ std::string typeName = detail::typeName(typeid(Set_T));
2025
+ klassName = detail::rubyClassName(typeName);
2026
+ }
557
2027
 
558
- // Use custom wrapper type
559
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
560
- return detail::wrap<std::shared_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
2028
+ Module rb_mStd = define_module("Std");
2029
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
2030
+ {
2031
+ return Data_Type_T();
561
2032
  }
562
- };
563
2033
 
564
- template <typename T>
565
- class From_Ruby<std::shared_ptr<T>>
2034
+ Identifier id(klassName);
2035
+ Data_Type_T result = define_class_under<detail::intrinsic_type<Set_T>>(rb_mStd, id);
2036
+ stl::SetHelper helper(result);
2037
+ return result;
2038
+ }
2039
+
2040
+ namespace detail
566
2041
  {
567
- public:
568
- From_Ruby() = default;
2042
+ // Helper method - maybe someday create a C++ Ruby set wrapper
2043
+ template<typename T>
2044
+ std::set<T> toSet(VALUE rubySet)
2045
+ {
2046
+ using Function_T = VALUE(*)(VALUE, ID, int, const VALUE*, rb_block_call_func_t, VALUE);
2047
+ static Identifier identifier("each");
2048
+
2049
+ std::set<T> result;
2050
+ auto block = [&result](const typename std::set<T>::value_type element) -> VALUE
2051
+ {
2052
+ result.insert(element);
2053
+ return Qnil;
2054
+ };
2055
+
2056
+ using NativeFunction_T = NativeFunction<void, decltype(block), false>;
2057
+
2058
+ // It is ok to use the address of native because it will remain valid while we iterate the set
2059
+ NativeFunction_T native(block);
2060
+ detail::protect<Function_T>(rb_block_call, rubySet, identifier.id(), 0, nullptr, NativeFunction_T::procEntry, (VALUE)&native);
2061
+
2062
+ return result;
2063
+ }
2064
+
2065
+ template<typename T>
2066
+ struct Type<std::set<T>>
2067
+ {
2068
+ static bool verify()
2069
+ {
2070
+ Type<intrinsic_type<T>>::verify();
2071
+
2072
+ if (!Data_Type<std::set<T>>::is_defined())
2073
+ {
2074
+ define_set<T>();
2075
+ }
2076
+
2077
+ return true;
2078
+ }
2079
+ };
2080
+
2081
+ template<typename T>
2082
+ class From_Ruby<std::set<T>>
2083
+ {
2084
+ private:
2085
+ static inline std::string setName = "Set";
2086
+
2087
+ public:
2088
+ From_Ruby() = default;
2089
+
2090
+ explicit From_Ruby(Arg * arg) : arg_(arg)
2091
+ {
2092
+ }
2093
+
2094
+ Convertible is_convertible(VALUE value)
2095
+ {
2096
+ switch (rb_type(value))
2097
+ {
2098
+ case RUBY_T_DATA:
2099
+ return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2100
+ break;
2101
+ case RUBY_T_OBJECT:
2102
+ {
2103
+ Object object(value);
2104
+ if (object.class_name().str() == setName)
2105
+ {
2106
+ return Convertible::Cast;
2107
+ }
2108
+ }
2109
+ default:
2110
+ return Convertible::None;
2111
+ }
2112
+ }
2113
+
2114
+ std::set<T> convert(VALUE value)
2115
+ {
2116
+ switch (rb_type(value))
2117
+ {
2118
+ case RUBY_T_DATA:
2119
+ {
2120
+ // This is a wrapped self (hopefully!)
2121
+ return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
2122
+ }
2123
+ case RUBY_T_OBJECT:
2124
+ {
2125
+ Object object(value);
2126
+ if (object.class_name().str() == setName)
2127
+ {
2128
+ return toSet<T>(value);
2129
+ }
2130
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2131
+ detail::protect(rb_obj_classname, value), "std::set");
2132
+ }
2133
+ default:
2134
+ {
2135
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2136
+ detail::protect(rb_obj_classname, value), "std::set");
2137
+ }
2138
+ }
2139
+ }
2140
+
2141
+ private:
2142
+ Arg* arg_ = nullptr;
2143
+ };
2144
+
2145
+ template<typename T>
2146
+ class From_Ruby<std::set<T>&>
2147
+ {
2148
+ private:
2149
+ static inline std::string setName = "Set";
2150
+
2151
+ public:
2152
+ From_Ruby() = default;
2153
+
2154
+ explicit From_Ruby(Arg * arg) : arg_(arg)
2155
+ {
2156
+ }
2157
+
2158
+ Convertible is_convertible(VALUE value)
2159
+ {
2160
+ switch (rb_type(value))
2161
+ {
2162
+ case RUBY_T_DATA:
2163
+ return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2164
+ break;
2165
+ case RUBY_T_OBJECT:
2166
+ {
2167
+ Object object(value);
2168
+ if (object.class_name().str() == setName)
2169
+ {
2170
+ return Convertible::Cast;
2171
+ }
2172
+ }
2173
+ default:
2174
+ return Convertible::None;
2175
+ }
2176
+ }
2177
+
2178
+ std::set<T>& convert(VALUE value)
2179
+ {
2180
+ switch (rb_type(value))
2181
+ {
2182
+ case RUBY_T_DATA:
2183
+ {
2184
+ // This is a wrapped self (hopefully!)
2185
+ return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
2186
+ }
2187
+ case RUBY_T_OBJECT:
2188
+ {
2189
+ Object object(value);
2190
+ if (object.class_name().str() == setName)
2191
+ {
2192
+ // If this an Ruby array and the vector type is copyable
2193
+ if constexpr (std::is_default_constructible_v<T>)
2194
+ {
2195
+ this->converted_ = toSet<T>(value);
2196
+ return this->converted_;
2197
+ }
2198
+ }
2199
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2200
+ detail::protect(rb_obj_classname, value), "std::set");
2201
+ }
2202
+ default:
2203
+ {
2204
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2205
+ detail::protect(rb_obj_classname, value), "std::set");
2206
+ }
2207
+ }
2208
+ }
569
2209
 
570
- explicit From_Ruby(Arg * arg) : arg_(arg)
571
- {
572
- }
2210
+ private:
2211
+ Arg* arg_ = nullptr;
2212
+ std::set<T> converted_;
2213
+ };
573
2214
 
574
- std::shared_ptr<T> convert(VALUE value)
2215
+ template<typename T>
2216
+ class From_Ruby<std::set<T>*>
575
2217
  {
576
- if(value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
577
- return this->arg_->template defaultValue<std::shared_ptr<T>>();
2218
+ private:
2219
+ static inline std::string setName = "Set";
2220
+ public:
2221
+ Convertible is_convertible(VALUE value)
2222
+ {
2223
+ switch (rb_type(value))
2224
+ {
2225
+ case RUBY_T_DATA:
2226
+ return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2227
+ break;
2228
+ case RUBY_T_NIL:
2229
+ return Convertible::Exact;
2230
+ break;
2231
+ case RUBY_T_OBJECT:
2232
+ {
2233
+ Object object(value);
2234
+ if (object.class_name().str() == setName)
2235
+ {
2236
+ return Convertible::Cast;
2237
+ }
2238
+ }
2239
+ default:
2240
+ return Convertible::None;
2241
+ }
578
2242
  }
579
2243
 
580
- Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
581
-
582
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
583
- Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
584
- if (!smartWrapper)
2244
+ std::set<T>* convert(VALUE value)
585
2245
  {
586
- std::string message = "Invalid smart pointer wrapper";
587
- throw std::runtime_error(message.c_str());
2246
+ switch (rb_type(value))
2247
+ {
2248
+ case RUBY_T_DATA:
2249
+ {
2250
+ // This is a wrapped self (hopefully!)
2251
+ return detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
2252
+ }
2253
+ case RUBY_T_OBJECT:
2254
+ {
2255
+ Object object(value);
2256
+ if (object.class_name().str() == setName)
2257
+ {
2258
+ // If this an Ruby array and the vector type is copyable
2259
+ if constexpr (std::is_default_constructible_v<T>)
2260
+ {
2261
+ this->converted_ = toSet<T>(value);
2262
+ return &this->converted_;
2263
+ }
2264
+ }
2265
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2266
+ detail::protect(rb_obj_classname, value), "std::set");
2267
+ }
2268
+ default:
2269
+ {
2270
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2271
+ detail::protect(rb_obj_classname, value), "std::set");
2272
+ }
2273
+ }
588
2274
  }
589
- return smartWrapper->data();
590
- }
591
2275
 
592
- private:
593
- Arg* arg_ = nullptr;
594
- };
2276
+ private:
2277
+ std::set<T> converted_;
2278
+ };
2279
+ }
2280
+ }
595
2281
 
596
- template <typename T>
597
- class To_Ruby<std::shared_ptr<T>&>
598
- {
599
- public:
600
- VALUE convert(std::shared_ptr<T>& data)
601
- {
602
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
603
2282
 
604
- // Use custom wrapper type
605
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
606
- return detail::wrap<std::shared_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
607
- }
608
- };
2283
+ // ========= shared_ptr.hpp =========
609
2284
 
610
- template <typename T>
611
- class From_Ruby<std::shared_ptr<T>&>
2285
+ namespace Rice::detail
2286
+ {
2287
+ template<typename T>
2288
+ class Wrapper<std::shared_ptr<T>> : public WrapperBase
612
2289
  {
613
2290
  public:
614
- From_Ruby() = default;
615
-
616
- explicit From_Ruby(Arg * arg) : arg_(arg)
617
- {
618
- }
2291
+ Wrapper(const std::shared_ptr<T>& data);
2292
+ ~Wrapper();
2293
+ void* get() override;
2294
+ std::shared_ptr<T>& data();
619
2295
 
620
- std::shared_ptr<T>& convert(VALUE value)
621
- {
622
- if(value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
623
- return this->arg_->template defaultValue<std::shared_ptr<T>>();
624
- }
2296
+ private:
2297
+ std::shared_ptr<T> data_;
2298
+ };
2299
+ }
625
2300
 
626
- Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
2301
+ namespace Rice
2302
+ {
2303
+ template<typename T>
2304
+ Data_Type<std::shared_ptr<T>> define_shared_ptr(std::string klassName = "");
2305
+ }
627
2306
 
628
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
629
- Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
630
- if (!smartWrapper)
631
- {
632
- std::string message = "Invalid smart pointer wrapper";
633
- throw std::runtime_error(message.c_str());
634
- }
635
- return smartWrapper->data();
636
- }
637
2307
 
638
- private:
639
- Arg* arg_ = nullptr;
640
- };
2308
+ // --------- shared_ptr.ipp ---------
2309
+ #include <memory>
641
2310
 
2311
+ // --------- Enable creation of std::shared_ptr from Ruby ---------
2312
+ namespace Rice
2313
+ {
642
2314
  template<typename T>
643
- struct Type<std::shared_ptr<T>>
2315
+ Data_Type<std::shared_ptr<T>> define_shared_ptr(std::string klassName)
644
2316
  {
645
- static bool verify()
2317
+ using SharedPtr_T = std::shared_ptr<T>;
2318
+ using Data_Type_T = Data_Type<SharedPtr_T>;
2319
+
2320
+ if (klassName.empty())
646
2321
  {
647
- return Type<T>::verify();
2322
+ std::string typeName = detail::typeName(typeid(SharedPtr_T));
2323
+ klassName = detail::rubyClassName(typeName);
648
2324
  }
649
- };
650
- }
651
2325
 
2326
+ Module rb_mStd = define_module("Std");
2327
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
2328
+ {
2329
+ return Data_Type_T();
2330
+ }
652
2331
 
653
- // ========= monostate.hpp =========
654
-
2332
+ Identifier id(klassName);
2333
+ Data_Type_T result = define_class_under<detail::intrinsic_type<SharedPtr_T>>(rb_mStd, id).
2334
+ define_constructor(Constructor<SharedPtr_T, typename SharedPtr_T::element_type*>(), Arg("value").takeOwnership());
655
2335
 
656
- // --------- monostate.ipp ---------
657
- #include <variant>
2336
+ return result;
2337
+ }
2338
+ }
658
2339
 
2340
+ // --------- Wrapper ---------
659
2341
  namespace Rice::detail
660
2342
  {
661
- template<>
662
- struct Type<std::monostate>
2343
+ template<typename T>
2344
+ inline Wrapper<std::shared_ptr<T>>::Wrapper(const std::shared_ptr<T>& data)
2345
+ : data_(data)
663
2346
  {
664
- constexpr static bool verify()
665
- {
666
- return true;
667
- }
668
- };
2347
+ }
669
2348
 
670
- template<>
671
- class To_Ruby<std::monostate>
2349
+ template<typename T>
2350
+ inline Wrapper<std::shared_ptr<T>>::~Wrapper()
672
2351
  {
673
- public:
674
- VALUE convert(const std::monostate& _)
675
- {
676
- return Qnil;
677
- }
678
- };
2352
+ Registries::instance.instances.remove(this->get());
2353
+ }
679
2354
 
680
- template<>
681
- class To_Ruby<std::monostate&>
2355
+ template<typename T>
2356
+ inline void* Wrapper<std::shared_ptr<T>>::get()
682
2357
  {
683
- public:
684
- static VALUE convert(const std::monostate& data, bool takeOwnership = false)
2358
+ return (void*)this->data_.get();
2359
+ }
2360
+
2361
+ template<typename T>
2362
+ inline std::shared_ptr<T>& Wrapper<std::shared_ptr<T>>::data()
2363
+ {
2364
+ return data_;
2365
+ }
2366
+ }
2367
+
2368
+ // --------- Type/To_Ruby/From_Ruby ---------
2369
+ namespace Rice::detail
2370
+ {
2371
+ template<typename T>
2372
+ struct Type<std::shared_ptr<T>>
2373
+ {
2374
+ static bool verify()
685
2375
  {
686
- return Qnil;
2376
+ return Type<T>::verify();
687
2377
  }
688
2378
  };
689
2379
 
690
- template<>
691
- class From_Ruby<std::monostate>
2380
+ template <typename T>
2381
+ class To_Ruby<std::shared_ptr<T>>
692
2382
  {
693
2383
  public:
694
- bool is_convertible(VALUE value)
2384
+ VALUE convert(std::shared_ptr<T>& data)
695
2385
  {
696
- return false;
2386
+ if constexpr (std::is_fundamental_v<T>)
2387
+ {
2388
+ return detail::wrap(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
2389
+ }
2390
+ else
2391
+ {
2392
+ return detail::wrap<std::shared_ptr<T>>(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
2393
+ }
697
2394
  }
698
2395
 
699
- std::monostate convert(VALUE value)
2396
+ VALUE convert(std::shared_ptr<T>&& data)
700
2397
  {
701
- return std::monostate();
2398
+ if constexpr (std::is_fundamental_v<T>)
2399
+ {
2400
+ return detail::wrap(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
2401
+ }
2402
+ else
2403
+ {
2404
+ return detail::wrap<std::shared_ptr<T>>(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
2405
+ }
702
2406
  }
703
2407
  };
704
2408
 
705
- template<>
706
- class From_Ruby<std::monostate&>
2409
+ template <typename T>
2410
+ class From_Ruby<std::shared_ptr<T>>
707
2411
  {
708
2412
  public:
709
- bool is_convertible(VALUE value)
710
- {
711
- return false;
712
- }
2413
+ From_Ruby() = default;
713
2414
 
714
- std::monostate& convert(VALUE value)
2415
+ explicit From_Ruby(Arg * arg) : arg_(arg)
715
2416
  {
716
- return this->converted_;
717
2417
  }
718
-
719
- private:
720
- std::monostate converted_ = std::monostate();
721
- };
722
- }
723
-
724
-
725
- // ========= variant.hpp =========
726
-
727
-
728
- // --------- variant.ipp ---------
729
- #include <variant>
730
-
731
- namespace Rice::detail
732
- {
733
- template<typename...Types>
734
- struct Type<std::variant<Types...>>
735
- {
736
- using Tuple_T = std::tuple<Types...>;
737
2418
 
738
- template<std::size_t... I>
739
- constexpr static bool verifyTypes(std::index_sequence<I...>& indices)
2419
+ Convertible is_convertible(VALUE value)
740
2420
  {
741
- return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
2421
+ switch (rb_type(value))
2422
+ {
2423
+ case RUBY_T_DATA:
2424
+ return Convertible::Exact;
2425
+ break;
2426
+ default:
2427
+ return Convertible::None;
2428
+ }
742
2429
  }
743
2430
 
744
- template<std::size_t... I>
745
- constexpr static bool verify()
2431
+ std::shared_ptr<T> convert(VALUE value)
746
2432
  {
747
- auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
748
- return verifyTypes(indices);
2433
+ // Get the wrapper
2434
+ WrapperBase* wrapperBase = detail::getWrapper(value);
2435
+
2436
+ // Was this shared_ptr created by the user from Ruby? If so it will
2437
+ // be wrapped as a pointer, std::shared_ptr<T>*. In the case just
2438
+ // return the shared pointer
2439
+ if (dynamic_cast<Wrapper<std::shared_ptr<T>*>*>(wrapperBase))
2440
+ {
2441
+ // Use unwrap to validate the underlying wrapper is the correct type
2442
+ std::shared_ptr<T>* ptr = unwrap<std::shared_ptr<T>>(value, Data_Type<std::shared_ptr<T>>::ruby_data_type(), false);
2443
+ return *ptr;
2444
+ }
2445
+ else if constexpr (std::is_fundamental_v<T>)
2446
+ {
2447
+ // Get the wrapper again to validate T's type
2448
+ Wrapper<std::shared_ptr<T>>* wrapper = getWrapper<Wrapper<std::shared_ptr<T>>>(value, Data_Type<T>::ruby_data_type());
2449
+ return wrapper->data();
2450
+ }
2451
+ else
2452
+ {
2453
+ // Get the wrapper again to validate T's type
2454
+ Wrapper<std::shared_ptr<T>>* wrapper = getWrapper<Wrapper<std::shared_ptr<T>>>(value, Data_Type<T>::ruby_data_type());
2455
+ return wrapper->data();
2456
+ }
749
2457
  }
2458
+ private:
2459
+ Arg* arg_ = nullptr;
750
2460
  };
751
2461
 
752
- template<typename...Types>
753
- class To_Ruby<std::variant<Types...>>
2462
+ template <typename T>
2463
+ class To_Ruby<std::shared_ptr<T>&>
754
2464
  {
755
2465
  public:
756
-
757
- template<typename T>
758
- static VALUE convertElement(const std::variant<Types...>& data, bool takeOwnership)
2466
+ VALUE convert(std::shared_ptr<T>& data)
759
2467
  {
760
- return To_Ruby<T>().convert(std::get<T>(data));
2468
+ if constexpr (std::is_fundamental_v<T>)
2469
+ {
2470
+ return detail::wrap(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
2471
+ }
2472
+ else
2473
+ {
2474
+ return detail::wrap<std::shared_ptr<T>>(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
2475
+ }
761
2476
  }
2477
+ };
762
2478
 
763
- template<std::size_t... I>
764
- static VALUE convertIterator(const std::variant<Types...>& data, bool takeOwnership, std::index_sequence<I...>& indices)
765
- {
766
- // Create a tuple of the variant types so we can look over the tuple's types
767
- using Tuple_T = std::tuple<Types...>;
768
-
769
- /* This is a fold expression. In pseudo code:
770
-
771
- for (type in variant.types)
772
- {
773
- if (variant.has_value<type>())
774
- return ToRuby<type>().convert(variant.getValue<type>)
775
- }
776
-
777
- The list of variant types is stored in Tuple_T. The number of types is stored in I.
778
- Starting with index 0, get the variant type using td::tuple_element_t<I, Tuple_T>>.
779
- Next check if the variant has a value for that type using std::holds_alternative<T>.
780
- If yes, then call convertElement and save the return value to result. Then use the
781
- comma operator to return true to the fold expression. If the variant does not have
782
- a value for the type then return false.
783
-
784
- The fold operator is or (||). If an index returns false, then the next index is evaulated
785
- up until I.
786
-
787
- Code inspired by https://www.foonathan.net/2020/05/fold-tricks/ */
2479
+ template <typename T>
2480
+ class From_Ruby<std::shared_ptr<T>&>
2481
+ {
2482
+ public:
2483
+ From_Ruby() = default;
788
2484
 
789
- VALUE result = Qnil;
790
- ((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
791
- (result = convertElement<std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
2485
+ explicit From_Ruby(Arg * arg) : arg_(arg)
2486
+ {
2487
+ }
792
2488
 
793
- return result;
2489
+ Convertible is_convertible(VALUE value)
2490
+ {
2491
+ switch (rb_type(value))
2492
+ {
2493
+ case RUBY_T_DATA:
2494
+ return Convertible::Exact;
2495
+ break;
2496
+ default:
2497
+ return Convertible::None;
2498
+ }
794
2499
  }
795
2500
 
796
- static VALUE convert(const std::variant<Types...>& data, bool takeOwnership = false)
2501
+ std::shared_ptr<T>& convert(VALUE value)
797
2502
  {
798
- auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
799
- return convertIterator(data, takeOwnership, indices);
2503
+ // Get the wrapper
2504
+ WrapperBase* wrapperBase = detail::getWrapper(value);
2505
+
2506
+ // Was this shared_ptr created by the user from Ruby? If so it will
2507
+ // be wrapped as a pointer, std::shared_ptr<T>*. In the case just
2508
+ // return the shared pointer
2509
+ if (dynamic_cast<Wrapper<std::shared_ptr<T>*>*>(wrapperBase))
2510
+ {
2511
+ // Use unwrap to validate the underlying wrapper is the correct type
2512
+ std::shared_ptr<T>* ptr = unwrap<std::shared_ptr<T>>(value, Data_Type<std::shared_ptr<T>>::ruby_data_type(), false);
2513
+ return *ptr;
2514
+ }
2515
+ else if constexpr (std::is_fundamental_v<T>)
2516
+ {
2517
+ // Get the wrapper again to validate T's type
2518
+ Wrapper<std::shared_ptr<T>>* wrapper = getWrapper<Wrapper<std::shared_ptr<T>>>(value, Data_Type<T>::ruby_data_type());
2519
+ return wrapper->data();
2520
+ }
2521
+ else
2522
+ {
2523
+ // Get the wrapper again to validate T's type
2524
+ Wrapper<std::shared_ptr<T>>* wrapper = getWrapper<Wrapper<std::shared_ptr<T>>>(value, Data_Type<T>::ruby_data_type());
2525
+ return wrapper->data();
2526
+ }
800
2527
  }
2528
+
2529
+ private:
2530
+ Arg* arg_ = nullptr;
801
2531
  };
2532
+ }
2533
+
802
2534
 
2535
+ // ========= tuple.hpp =========
2536
+
2537
+
2538
+ // --------- tuple.ipp ---------
2539
+ #include <tuple>
2540
+
2541
+ namespace Rice::detail
2542
+ {
803
2543
  template<typename...Types>
804
- class To_Ruby<std::variant<Types...>&>
2544
+ struct Type<std::tuple<Types...>>
805
2545
  {
806
- public:
807
- template<typename T>
808
- static VALUE convertElement(const std::variant<Types...>& data, bool takeOwnership)
809
- {
810
- return To_Ruby<T>().convert(std::get<T>(data));
811
- }
2546
+ using Tuple_T = std::tuple<Types...>;
812
2547
 
813
2548
  template<std::size_t... I>
814
- static VALUE convertIterator(const std::variant<Types...>& data, bool takeOwnership, std::index_sequence<I...>& indices)
2549
+ constexpr static bool verifyTypes(std::index_sequence<I...>& indices)
815
2550
  {
816
- // Create a tuple of the variant types so we can look over the tuple's types
817
- using Tuple_T = std::tuple<Types...>;
818
-
819
- // See comments above for explanation of this code
820
- VALUE result = Qnil;
821
- ((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
822
- (result = convertElement<std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
823
-
824
- return result;
2551
+ return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
825
2552
  }
826
2553
 
827
- static VALUE convert(const std::variant<Types...>& data, bool takeOwnership = false)
2554
+ template<std::size_t... I>
2555
+ constexpr static bool verify()
828
2556
  {
829
- auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
830
- return convertIterator(data, takeOwnership, indices);
2557
+ auto indices = std::make_index_sequence<std::tuple_size_v<std::tuple<Types...>>>{};
2558
+ return verifyTypes(indices);
831
2559
  }
832
2560
  };
833
2561
 
834
2562
  template<typename...Types>
835
- class From_Ruby<std::variant<Types...>>
2563
+ class To_Ruby<std::tuple<Types...>>
836
2564
  {
837
- private:
838
- // Possible converters we could use for this variant
839
- using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
840
-
841
2565
  public:
842
- /* This method loops over each type in the variant, creates a From_Ruby converter,
843
- and then check if the converter can work with the provided Rby value (it checks
844
- the type of the Ruby object to see if it matches the variant type).
845
- If yes, then the converter runs. If no, then the method recursively calls itself
846
- increasing the index.
847
-
848
- We use recursion, with a constexpr, to avoid having to instantiate an instance
849
- of the variant to store results from a fold expression like the To_Ruby code
850
- does above. That allows us to process variants with non default constructible
851
- arguments like std::reference_wrapper. */
852
- template <std::size_t I = 0>
853
- std::variant<Types...> convertInternal(VALUE value)
2566
+ static VALUE convert(const std::tuple<Types...>& data, bool takeOwnership = false)
854
2567
  {
855
- // Loop over each possible type in the variant.
856
- if constexpr (I < std::variant_size_v<std::variant<Types...>>)
857
- {
858
- // Get the converter for the current index
859
- typename std::tuple_element_t<I, From_Ruby_Ts> converter;
2568
+ Array result;
860
2569
 
861
- // See if it will work
862
- if (converter.is_convertible(value))
863
- {
864
- return converter.convert(value);
865
- }
866
- else
867
- {
868
- return convertInternal<I + 1>(value);
869
- }
870
- }
871
- throw std::runtime_error("Could not find converter for variant");
872
- }
2570
+ for_each_tuple(data, [&](auto element)
2571
+ {
2572
+ using Element_T = decltype(element);
2573
+ result.push<Element_T>((Element_T)element);
2574
+ });
873
2575
 
874
- std::variant<Types...> convert(VALUE value)
875
- {
876
- return convertInternal(value);
2576
+ return result.value();
877
2577
  }
878
2578
  };
879
2579
 
880
2580
  template<typename...Types>
881
- class From_Ruby<std::variant<Types...>&>
2581
+ class To_Ruby<std::tuple<Types...>&>
882
2582
  {
883
- private:
884
- // Possible converters we could use for this variant
885
- using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
886
-
887
2583
  public:
888
- template <std::size_t I = 0>
889
- std::variant<Types...> convertInternal(VALUE value)
2584
+ static VALUE convert(const std::tuple<Types...>& data, bool takeOwnership = false)
890
2585
  {
891
- // Loop over each possible type in the variant
892
- if constexpr (I < std::variant_size_v<std::variant<Types...>>)
893
- {
894
- // Get the converter for the current index
895
- typename std::tuple_element_t<I, From_Ruby_Ts> converter;
2586
+ Array result;
896
2587
 
897
- // See if it will work
898
- if (converter.is_convertible(value))
899
- {
900
- return converter.convert(value);
901
- }
902
- else
2588
+ for_each_tuple(data, [&](auto& value)
903
2589
  {
904
- return convertInternal<I + 1>(value);
905
- }
906
- }
907
- throw std::runtime_error("Could not find converter for variant");
908
- }
2590
+ VALUE element = detail::To_Ruby<decltype(value)>().convert(value);
2591
+ result.push(element);
2592
+ });
909
2593
 
910
- std::variant<Types...> convert(VALUE value)
911
- {
912
- return convertInternal(value);
2594
+ return result.value();
913
2595
  }
914
2596
  };
915
- }
916
-
917
-
918
- // ========= pair.hpp =========
919
-
920
-
921
- namespace Rice
922
- {
923
- template<typename T>
924
- Data_Type<T> define_pair(std::string name);
925
-
926
- template<typename T>
927
- Data_Type<T> define_pair_under(Object module, std::string name);
928
- }
929
-
930
-
931
- // --------- pair.ipp ---------
932
-
933
- #include <sstream>
934
- #include <stdexcept>
935
- #include <utility>
936
2597
 
937
- namespace Rice
938
- {
939
- namespace stl
2598
+ template<typename...Types>
2599
+ class From_Ruby<std::tuple<Types...>>
940
2600
  {
941
- template<typename T>
942
- class PairHelper
943
- {
944
- public:
945
- PairHelper(Data_Type<T> klass) : klass_(klass)
946
- {
947
- this->define_constructor();
948
- this->define_copyable_methods();
949
- this->define_access_methods();
950
- this->define_modify_methods();
951
- this->define_to_s();
952
- }
2601
+ public:
2602
+ using Tuple_T = std::tuple<Types...>;
953
2603
 
954
- private:
955
- void define_constructor()
956
- {
957
- klass_.define_constructor(Constructor<T, typename T::first_type&, typename T::second_type&>());
958
- }
2604
+ template<std::size_t... I>
2605
+ constexpr static bool verifyTypes(Array& array, std::index_sequence<I...>& indices)
2606
+ {
2607
+ return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
2608
+ }
959
2609
 
960
- void define_copyable_methods()
961
- {
962
- if constexpr (std::is_copy_constructible_v<typename T::first_type> && std::is_copy_constructible_v<typename T::second_type>)
963
- {
964
- klass_.define_method("copy", [](T& pair) -> T
965
- {
966
- return pair;
967
- });
968
- }
969
- else
970
- {
971
- klass_.define_method("copy", [](T& pair) -> T
972
- {
973
- throw std::runtime_error("Cannot copy pair with non-copy constructible types");
974
- return pair;
975
- });
976
- }
977
- }
2610
+ Convertible is_convertible(VALUE value)
2611
+ {
2612
+ Convertible result = Convertible::None;
978
2613
 
979
- void define_access_methods()
2614
+ // The ruby value must be an array of the correct size
2615
+ if (rb_type(value) != RUBY_T_ARRAY || Array(value).size() != std::tuple_size_v<Tuple_T>)
980
2616
  {
981
- // Access methods
982
- klass_.define_method("first", [](T& pair) -> typename T::first_type&
983
- {
984
- return pair.first;
985
- })
986
- .define_method("second", [](T& pair) -> typename T::second_type&
987
- {
988
- return pair.second;
989
- });
2617
+ return result;
990
2618
  }
991
-
992
- void define_modify_methods()
993
- {
994
- // Access methods
995
- klass_.define_method("first=", [](T& pair, typename T::first_type& value) -> typename T::first_type&
996
- {
997
- if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::first_type>>>)
998
- {
999
- throw std::runtime_error("Cannot set pair.first since it is a constant");
1000
- }
1001
- else
1002
- {
1003
- pair.first = value;
1004
- return pair.first;
1005
- }
1006
- })
1007
- .define_method("second=", [](T& pair, typename T::second_type& value) -> typename T::second_type&
2619
+
2620
+ // Now check that each tuple type is convertible
2621
+ Array array(value);
2622
+ int i = 0;
2623
+ for_each_tuple(this->fromRubys_,
2624
+ [&](auto& fromRuby)
1008
2625
  {
1009
- if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::second_type>>>)
1010
- {
1011
- throw std::runtime_error("Cannot set pair.second since it is a constant");
1012
- }
1013
- else
1014
- {
1015
- pair.second = value;
1016
- return pair.second;
1017
- }
2626
+ result = result | fromRuby.is_convertible(array[i].value());
2627
+ i++;
1018
2628
  });
1019
- }
1020
2629
 
1021
- void define_to_s()
1022
- {
1023
- if constexpr (detail::is_ostreamable_v<typename T::first_type> && detail::is_ostreamable_v<typename T::second_type>)
1024
- {
1025
- klass_.define_method("to_s", [](const T& pair)
1026
- {
1027
- std::stringstream stream;
1028
- stream << "[" << pair.first << ", " << pair.second << "]";
1029
- return stream.str();
1030
- });
1031
- }
1032
- else
1033
- {
1034
- klass_.define_method("to_s", [](const T& pair)
1035
- {
1036
- return "[Not printable]";
1037
- });
1038
- }
1039
- }
2630
+ return result;
2631
+ }
1040
2632
 
1041
- private:
1042
- Data_Type<T> klass_;
1043
- };
1044
- } // namespace
2633
+ template <std::size_t... I>
2634
+ std::tuple<Types...> convertInternal(Array array, std::index_sequence<I...>& indices)
2635
+ {
2636
+ return std::forward_as_tuple(std::get<I>(this->fromRubys_).convert(array[I].value())...);
2637
+ }
1045
2638
 
1046
- template<typename T>
1047
- Data_Type<T> define_pair_under(Object module, std::string name)
1048
- {
1049
- if (detail::Registries::instance.types.isDefined<T>())
2639
+ std::tuple<Types...> convert(VALUE value)
1050
2640
  {
1051
- // If the pair has been previously seen it will be registered but may
1052
- // not be associated with the constant Module::<name>
1053
- module.const_set_maybe(name, Data_Type<T>().klass());
1054
- return Data_Type<T>();
2641
+ Array array(value);
2642
+ auto indices = std::make_index_sequence<std::tuple_size_v<Tuple_T>>{};
2643
+ return convertInternal(array, indices);
1055
2644
  }
1056
2645
 
1057
- Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(module, name.c_str());
1058
- stl::PairHelper helper(result);
1059
- return result;
1060
- }
2646
+ private:
2647
+ // Possible converters we could use for this variant
2648
+ using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
2649
+ From_Ruby_Ts fromRubys_;
2650
+ };
1061
2651
 
1062
- template<typename T>
1063
- Data_Type<T> define_pair(std::string name)
2652
+ /* template<typename...Types>
2653
+ class From_Ruby<std::tuple<Types...>&> : public From_Ruby<std::tuple<Types...>>
1064
2654
  {
1065
- if (detail::Registries::instance.types.isDefined<T>())
2655
+ public:
2656
+ std::tuple<Types...>& convert(VALUE value)
1066
2657
  {
1067
- // If the pair has been previously seen it will be registered but may
1068
- // not be associated with the constant Object::<name>
1069
- Object(rb_cObject).const_set_maybe(name, Data_Type<T>().klass());
1070
- return Data_Type<T>();
2658
+ int index = this->figureIndex(value);
2659
+ this->converted_ = this->convertInternal(value, index);
2660
+ return this->converted_;
1071
2661
  }
1072
2662
 
1073
- Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
1074
- stl::PairHelper<T> helper(result);
1075
- return result;
1076
- }
2663
+ private:
2664
+ std::tuple<Types...> converted_;
2665
+ };*/
2666
+ }
1077
2667
 
1078
- template<typename T>
1079
- Data_Type<T> define_pair_auto()
2668
+
2669
+ // ========= type_index.hpp =========
2670
+
2671
+
2672
+ // --------- type_index.ipp ---------
2673
+ #include <typeindex>
2674
+
2675
+ namespace Rice::stl
2676
+ {
2677
+ inline Data_Type<std::type_index> define_type_index()
1080
2678
  {
1081
- std::string klassName = detail::makeClassName(typeid(T));
1082
- Module rb_mRice = define_module("Rice");
1083
- Module rb_mpair = define_module_under(rb_mRice, "Std");
1084
- return define_pair_under<T>(rb_mpair, klassName);
2679
+ Module rb_mStd = define_module("Std");
2680
+ return define_class_under<std::type_index>(rb_mStd, "TypeIndex").
2681
+ define_constructor(Constructor<std::type_index, const std::type_info&>()).
2682
+ define_method("hash_code", &std::type_index::hash_code).
2683
+ define_method("name", &std::type_index::name);
1085
2684
  }
1086
-
1087
- namespace detail
2685
+ }
2686
+
2687
+ namespace Rice::detail
2688
+ {
2689
+ template<>
2690
+ struct Type<std::type_index>
1088
2691
  {
1089
- template<typename T1, typename T2>
1090
- struct Type<std::pair<T1, T2>>
2692
+ static bool verify()
1091
2693
  {
1092
- static bool verify()
2694
+ if (!detail::Registries::instance.types.isDefined<std::type_index>())
1093
2695
  {
1094
- detail::verifyType<T1>();
1095
- detail::verifyType<T2>();
1096
-
1097
- if (!detail::Registries::instance.types.isDefined<std::pair<T1, T2>>())
1098
- {
1099
- define_pair_auto<std::pair<T1, T2>>();
1100
- }
1101
-
1102
- return true;
2696
+ stl::define_type_index();
1103
2697
  }
1104
- };
1105
- }
2698
+
2699
+ return true;
2700
+ }
2701
+ };
1106
2702
  }
1107
2703
 
1108
2704
 
2705
+ // ========= type_info.hpp =========
1109
2706
 
1110
- // ========= map.hpp =========
1111
2707
 
2708
+ // --------- type_info.ipp ---------
2709
+ #include <typeinfo>
1112
2710
 
1113
- namespace Rice
2711
+ namespace Rice::stl
1114
2712
  {
1115
- template<typename U>
1116
- Data_Type<U> define_map(std::string name);
2713
+ inline Data_Type<std::type_info> define_type_info()
2714
+ {
2715
+ Module rb_mStd = define_module("Std");
2716
+ return define_class_under<std::type_info>(rb_mStd, "TypeInfo").
2717
+ define_method("hash_code", &std::type_info::hash_code).
2718
+ define_method("name", &std::type_info::name);
2719
+ }
2720
+ }
2721
+
2722
+ namespace Rice::detail
2723
+ {
2724
+ template<>
2725
+ struct Type<std::type_info>
2726
+ {
2727
+ static inline bool verify()
2728
+ {
2729
+ if (!detail::Registries::instance.types.isDefined<std::type_info>())
2730
+ {
2731
+ stl::define_type_info();
2732
+ }
1117
2733
 
1118
- template<typename U>
1119
- Data_Type<U> define_map_under(Object module, std::string name);
2734
+ return true;
2735
+ }
2736
+ };
1120
2737
  }
1121
2738
 
1122
2739
 
1123
- // --------- map.ipp ---------
2740
+ // ========= variant.hpp =========
1124
2741
 
1125
- #include <sstream>
1126
- #include <stdexcept>
1127
- #include <map>
1128
- #include <type_traits>
2742
+
2743
+ // --------- variant.ipp ---------
1129
2744
  #include <variant>
1130
2745
 
1131
- namespace Rice
2746
+ namespace Rice::detail
1132
2747
  {
1133
- namespace stl
2748
+ template<typename...Types>
2749
+ struct Type<std::variant<Types...>>
1134
2750
  {
1135
- template<typename T>
1136
- class MapHelper
1137
- {
1138
- using Key_T = typename T::key_type;
1139
- using Mapped_T = typename T::mapped_type;
1140
- using Value_T = typename T::value_type;
1141
- using Size_T = typename T::size_type;
1142
- using Difference_T = typename T::difference_type;
2751
+ using Tuple_T = std::tuple<Types...>;
1143
2752
 
1144
- public:
1145
- MapHelper(Data_Type<T> klass) : klass_(klass)
1146
- {
1147
- this->register_pair();
1148
- this->define_constructor();
1149
- this->define_copyable_methods();
1150
- this->define_capacity_methods();
1151
- this->define_access_methods();
1152
- this->define_comparable_methods();
1153
- this->define_modify_methods();
1154
- this->define_enumerable();
1155
- this->define_to_s();
1156
- this->define_to_hash();
1157
- }
2753
+ template<std::size_t... I>
2754
+ constexpr static bool verifyTypes(std::index_sequence<I...>& indices)
2755
+ {
2756
+ return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
2757
+ }
1158
2758
 
1159
- private:
2759
+ template<std::size_t... I>
2760
+ constexpr static bool verify()
2761
+ {
2762
+ auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
2763
+ return verifyTypes(indices);
2764
+ }
2765
+ };
1160
2766
 
1161
- void register_pair()
1162
- {
1163
- define_pair_auto<Value_T>();
1164
- }
2767
+ template<typename...Types>
2768
+ class To_Ruby<std::variant<Types...>>
2769
+ {
2770
+ public:
1165
2771
 
1166
- void define_constructor()
1167
- {
1168
- klass_.define_constructor(Constructor<T>());
1169
- }
2772
+ template<typename U, typename V>
2773
+ static VALUE convertElement(U& data, bool takeOwnership)
2774
+ {
2775
+ return To_Ruby<V>().convert(std::forward<V>(std::get<V>(data)));
2776
+ }
1170
2777
 
1171
- void define_copyable_methods()
1172
- {
1173
- if constexpr (std::is_copy_constructible_v<Value_T>)
1174
- {
1175
- klass_.define_method("copy", [](T& map) -> T
1176
- {
1177
- return map;
1178
- });
1179
- }
1180
- else
2778
+ template<typename U, std::size_t... I>
2779
+ static VALUE convertIterator(U& data, bool takeOwnership, std::index_sequence<I...>& indices)
2780
+ {
2781
+ // Create a tuple of the variant types so we can look over the tuple's types
2782
+ using Tuple_T = std::tuple<Types...>;
2783
+
2784
+ /* This is a fold expression. In pseudo code:
2785
+
2786
+ for (type in variant.types)
1181
2787
  {
1182
- klass_.define_method("copy", [](T& map) -> T
1183
- {
1184
- throw std::runtime_error("Cannot copy maps with non-copy constructible types");
1185
- return map;
1186
- });
2788
+ if (variant.has_value<type>())
2789
+ return ToRuby<type>().convert(variant.getValue<type>)
1187
2790
  }
1188
- }
1189
2791
 
1190
- void define_capacity_methods()
1191
- {
1192
- klass_.define_method("empty?", &T::empty)
1193
- .define_method("max_size", &T::max_size)
1194
- .define_method("size", &T::size);
2792
+ The list of variant types is stored in Tuple_T. The number of types is stored in I.
2793
+ Starting with index 0, get the variant type using td::tuple_element_t<I, Tuple_T>>.
2794
+ Next check if the variant has a value for that type using std::holds_alternative<T>.
2795
+ If yes, then call convertElement and save the return value to result. Then use the
2796
+ comma operator to return true to the fold expression. If the variant does not have
2797
+ a value for the type then return false.
1195
2798
 
1196
- rb_define_alias(klass_, "count", "size");
1197
- rb_define_alias(klass_, "length", "size");
1198
- }
2799
+ The fold operator is or (||). If an index returns false, then the next index is evaluated
2800
+ up until I.
2801
+
2802
+ Code inspired by https://www.foonathan.net/2020/05/fold-tricks/ */
1199
2803
 
1200
- void define_access_methods()
1201
- {
1202
- // Access methods
1203
- klass_.define_method("[]", [](const T& map, const Key_T& key) -> std::optional<Mapped_T>
1204
- {
1205
- auto iter = map.find(key);
2804
+ VALUE result = Qnil;
1206
2805
 
1207
- if (iter != map.end())
1208
- {
1209
- return iter->second;
1210
- }
1211
- else
1212
- {
1213
- return std::nullopt;
1214
- }
1215
- })
1216
- .define_method("include?", [](T& map, Key_T& key) -> bool
1217
- {
1218
- return map.find(key) != map.end();
1219
- })
1220
- .define_method("keys", [](T& map) -> std::vector<Key_T>
1221
- {
1222
- std::vector<Key_T> result;
1223
- std::transform(map.begin(), map.end(), std::back_inserter(result),
1224
- [](const auto& pair)
1225
- {
1226
- return pair.first;
1227
- });
2806
+ #if defined(__GNUC__) || defined(__clang__)
2807
+ #pragma GCC diagnostic push
2808
+ #pragma GCC diagnostic ignored "-Wunused-value"
2809
+ #endif
1228
2810
 
1229
- return result;
1230
- })
1231
- .define_method("values", [](T& map) -> std::vector<Mapped_T>
1232
- {
1233
- std::vector<Mapped_T> result;
1234
- std::transform(map.begin(), map.end(), std::back_inserter(result),
1235
- [](const auto& pair)
1236
- {
1237
- return pair.second;
1238
- });
2811
+ ((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
2812
+ (result = convertElement<U, std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
2813
+
2814
+ #if defined(__GNUC__) || defined(__clang__)
2815
+ #pragma GCC diagnostic pop
2816
+ #endif
1239
2817
 
1240
- return result;
1241
- });
2818
+ return result;
2819
+ }
1242
2820
 
1243
- rb_define_alias(klass_, "has_key", "include?");
1244
- }
2821
+ template<typename U>
2822
+ static VALUE convert(U& data, bool takeOwnership = false)
2823
+ {
2824
+ auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
2825
+ return convertIterator(data, takeOwnership, indices);
2826
+ }
1245
2827
 
1246
- // Methods that require Value_T to support operator==
1247
- void define_comparable_methods()
2828
+ template<typename U>
2829
+ static VALUE convert(U&& data, bool takeOwnership = false)
2830
+ {
2831
+ auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
2832
+ return convertIterator(data, takeOwnership, indices);
2833
+ }
2834
+ };
2835
+
2836
+ template<typename...Types>
2837
+ class To_Ruby<std::variant<Types...>&>
2838
+ {
2839
+ public:
2840
+ template<typename U, typename V>
2841
+ static VALUE convertElement(U& data, bool takeOwnership)
2842
+ {
2843
+ if constexpr (std::is_const_v<U>)
1248
2844
  {
1249
- if constexpr (detail::is_comparable_v<Mapped_T>)
1250
- {
1251
- klass_.define_method("value?", [](T& map, Mapped_T& value) -> bool
1252
- {
1253
- auto it = std::find_if(map.begin(), map.end(),
1254
- [&value](auto& pair)
1255
- {
1256
- return pair.second == value;
1257
- });
2845
+ return To_Ruby<V>().convert(std::get<V>(data));
2846
+ }
2847
+ else
2848
+ {
2849
+ return To_Ruby<V>().convert(std::forward<V>(std::get<V>(data)));
2850
+ }
2851
+ }
1258
2852
 
1259
- return it != map.end();
1260
- });
1261
- }
1262
- else
1263
- {
1264
- klass_.define_method("value?", [](T& map, Mapped_T& value) -> bool
1265
- {
1266
- return false;
1267
- });
1268
- }
2853
+ template<typename U, std::size_t... I>
2854
+ static VALUE convertIterator(U& data, bool takeOwnership, std::index_sequence<I...>& indices)
2855
+ {
2856
+ // Create a tuple of the variant types so we can look over the tuple's types
2857
+ using Tuple_T = std::tuple<Types...>;
1269
2858
 
1270
- rb_define_alias(klass_, "has_value", "value?");
1271
- }
2859
+ // See comments above for explanation of this code
2860
+ VALUE result = Qnil;
1272
2861
 
1273
- void define_modify_methods()
1274
- {
1275
- klass_.define_method("clear", &T::clear)
1276
- .define_method("delete", [](T& map, Key_T& key) -> std::optional<Mapped_T>
1277
- {
1278
- auto iter = map.find(key);
2862
+ #if defined(__GNUC__) || defined(__clang__)
2863
+ #pragma GCC diagnostic push
2864
+ #pragma GCC diagnostic ignored "-Wunused-value"
2865
+ #endif
1279
2866
 
1280
- if (iter != map.end())
1281
- {
1282
- Mapped_T result = iter->second;
1283
- map.erase(iter);
1284
- return result;
1285
- }
1286
- else
1287
- {
1288
- return std::nullopt;
1289
- }
1290
- })
1291
- .define_method("[]=", [](T& map, Key_T key, Mapped_T value) -> Mapped_T
1292
- {
1293
- map[key] = value;
1294
- return value;
1295
- });
2867
+ ((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
2868
+ (result = convertElement<U, std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
2869
+
2870
+ #if defined(__GNUC__) || defined(__clang__)
2871
+ #pragma GCC diagnostic pop
2872
+ #endif
2873
+
2874
+ return result;
2875
+ }
2876
+
2877
+ template<typename U>
2878
+ static VALUE convert(U& data, bool takeOwnership = false)
2879
+ {
2880
+ auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
2881
+ return convertIterator(data, takeOwnership, indices);
2882
+ }
2883
+ };
1296
2884
 
1297
- rb_define_alias(klass_, "store", "[]=");
1298
- }
2885
+ template<typename...Types>
2886
+ class From_Ruby<std::variant<Types...>>
2887
+ {
2888
+ public:
2889
+ Convertible is_convertible(VALUE value)
2890
+ {
2891
+ Convertible result = Convertible::None;
1299
2892
 
1300
- void define_enumerable()
1301
- {
1302
- // Add enumerable support
1303
- klass_.template define_iterator<typename T::iterator (T::*)()>(&T::begin, &T::end);
1304
- }
2893
+ for_each_tuple(this->fromRubys_,
2894
+ [&](auto& fromRuby)
2895
+ {
2896
+ result = result | fromRuby.is_convertible(value);
2897
+ });
1305
2898
 
1306
- void define_to_hash()
1307
- {
1308
- // Add enumerable support
1309
- klass_.define_method("to_h", [](T& map)
2899
+ return result;
2900
+ }
2901
+
2902
+ // This method search through a variant's types to figure out which one the
2903
+ // currently Ruby value best matches. It then returns the index of the type.
2904
+ int figureIndex(VALUE value)
2905
+ {
2906
+ int i = 0;
2907
+ int index = -1;
2908
+ Convertible foundConversion = Convertible::None;
2909
+
2910
+ for_each_tuple(this->fromRubys_,
2911
+ [&](auto& fromRuby)
1310
2912
  {
1311
- VALUE result = rb_hash_new();
1312
- std::for_each(map.begin(), map.end(), [&result](const typename T::reference pair)
1313
- {
1314
- VALUE key = detail::To_Ruby<Key_T&>().convert(pair.first);
1315
- VALUE value = detail::To_Ruby<Mapped_T&>().convert(pair.second);
1316
- rb_hash_aset(result, key, value);
1317
- });
2913
+ Convertible isConvertible = fromRuby.is_convertible(value);
1318
2914
 
1319
- return result;
1320
- }, Return().setValue());
1321
- }
2915
+ if (isConvertible > foundConversion)
2916
+ {
2917
+ index = i;
2918
+ foundConversion = isConvertible;
2919
+ }
2920
+ i++;
2921
+ });
1322
2922
 
1323
- void define_to_s()
2923
+ if (index == -1)
1324
2924
  {
1325
- if constexpr (detail::is_ostreamable_v<Key_T> && detail::is_ostreamable_v<Mapped_T>)
1326
- {
1327
- klass_.define_method("to_s", [](const T& map)
1328
- {
1329
- auto iter = map.begin();
2925
+ rb_raise(rb_eArgError, "Could not find converter for variant");
2926
+ }
1330
2927
 
1331
- std::stringstream stream;
1332
- stream << "{";
2928
+ return index;
2929
+ }
1333
2930
 
1334
- for (; iter != map.end(); iter++)
1335
- {
1336
- if (iter != map.begin())
1337
- {
1338
- stream << ", ";
1339
- }
1340
- stream << iter->first << " => " << iter->second;
1341
- }
2931
+ /* This method loops over each type in the variant, creates a From_Ruby converter,
2932
+ and then check if the converter can work with the provided Rby value (it checks
2933
+ the type of the Ruby object to see if it matches the variant type).
2934
+ If yes, then the converter runs. If no, then the method recursively calls itself
2935
+ increasing the index.
1342
2936
 
1343
- stream << "}";
1344
- return stream.str();
1345
- });
2937
+ We use recursion, with a constexpr, to avoid having to instantiate an instance
2938
+ of the variant to store results from a fold expression like the To_Ruby code
2939
+ does above. That allows us to process variants with non default constructible
2940
+ arguments like std::reference_wrapper. */
2941
+ template <std::size_t I = 0>
2942
+ std::variant<Types...> convertInternal(VALUE value, int index)
2943
+ {
2944
+ if constexpr (I < std::variant_size_v<std::variant<Types...>>)
2945
+ {
2946
+ if (I == index)
2947
+ {
2948
+ auto fromRuby = std::get<I>(this->fromRubys_);
2949
+ return fromRuby.convert(value);
1346
2950
  }
1347
2951
  else
1348
2952
  {
1349
- klass_.define_method("to_s", [](const T& map)
1350
- {
1351
- return "[Not printable]";
1352
- });
2953
+ return convertInternal<I + 1>(value, index);
1353
2954
  }
1354
2955
  }
2956
+ rb_raise(rb_eArgError, "Could not find converter for variant");
2957
+ }
1355
2958
 
1356
- private:
1357
- Data_Type<T> klass_;
1358
- };
1359
- } // namespace
1360
-
1361
- template<typename T>
1362
- Data_Type<T> define_map_under(Object module, std::string name)
1363
- {
1364
- if (detail::Registries::instance.types.isDefined<T>())
2959
+ std::variant<Types...> convert(VALUE value)
1365
2960
  {
1366
- // If the map has been previously seen it will be registered but may
1367
- // not be associated with the constant Module::<name>
1368
- module.const_set_maybe(name, Data_Type<T>().klass());
1369
- return Data_Type<T>();
2961
+ int index = this->figureIndex(value);
2962
+ return this->convertInternal(value, index);
1370
2963
  }
1371
2964
 
1372
- Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(module, name.c_str());
1373
- stl::MapHelper helper(result);
1374
- return result;
1375
- }
2965
+ private:
2966
+ // Possible converters we could use for this variant
2967
+ using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
2968
+ From_Ruby_Ts fromRubys_;
2969
+ };
1376
2970
 
1377
- template<typename T>
1378
- Data_Type<T> define_map(std::string name)
2971
+ template<typename...Types>
2972
+ class From_Ruby<std::variant<Types...>&> : public From_Ruby<std::variant<Types...>>
1379
2973
  {
1380
- if (detail::Registries::instance.types.isDefined<T>())
2974
+ public:
2975
+ std::variant<Types...>& convert(VALUE value)
1381
2976
  {
1382
- // If the map has been previously seen it will be registered but may
1383
- // not be associated with the constant Object::<name>
1384
- Object(rb_cObject).const_set_maybe(name, Data_Type<T>().klass());
1385
- return Data_Type<T>();
2977
+ int index = this->figureIndex(value);
2978
+ this->converted_ = this->convertInternal(value, index);
2979
+ return this->converted_;
1386
2980
  }
1387
2981
 
1388
- Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
1389
- stl::MapHelper<T> helper(result);
1390
- return result;
1391
- }
2982
+ private:
2983
+ std::variant<Types...> converted_;
2984
+ };
2985
+ }
2986
+
1392
2987
 
2988
+ // ========= unique_ptr.hpp =========
2989
+
2990
+ namespace Rice::detail
2991
+ {
1393
2992
  template<typename T>
1394
- Data_Type<T> define_map_auto()
1395
- {
1396
- std::string klassName = detail::makeClassName(typeid(T));
1397
- Module rb_mRice = define_module("Rice");
1398
- Module rb_mmap = define_module_under(rb_mRice, "Std");
1399
- return define_map_under<T>(rb_mmap, klassName);
1400
- }
1401
-
1402
- namespace detail
2993
+ class Wrapper<std::unique_ptr<T>> : public WrapperBase
1403
2994
  {
1404
- template<typename T, typename U>
1405
- struct Type<std::map<T, U>>
1406
- {
1407
- static bool verify()
1408
- {
1409
- Type<T>::verify();
1410
- Type<U>::verify();
2995
+ public:
2996
+ Wrapper(std::unique_ptr<T>&& data);
2997
+ ~Wrapper();
2998
+ void* get() override;
2999
+ std::unique_ptr<T>& data();
1411
3000
 
1412
- if (!detail::Registries::instance.types.isDefined<std::map<T, U>>())
1413
- {
1414
- define_map_auto<std::map<T, U>>();
1415
- }
3001
+ private:
3002
+ std::unique_ptr<T> data_;
3003
+ };
3004
+ }
1416
3005
 
1417
- return true;
1418
- }
1419
- };
1420
3006
 
1421
- template<typename T, typename U>
1422
- struct MapFromHash
1423
- {
1424
- static int convertPair(VALUE key, VALUE value, VALUE user_data)
1425
- {
1426
- std::map<T, U>* result = (std::map<T, U>*)(user_data);
3007
+ // --------- unique_ptr.ipp ---------
3008
+ #include <memory>
1427
3009
 
1428
- // This method is being called from Ruby so we cannot let any C++
1429
- // exceptions propogate back to Ruby
1430
- return cpp_protect([&]
1431
- {
1432
- result->operator[](From_Ruby<T>().convert(key)) = From_Ruby<U>().convert(value);
1433
- return ST_CONTINUE;
1434
- });
1435
- }
3010
+ namespace Rice::detail
3011
+ {
3012
+ template<typename T>
3013
+ inline Wrapper<std::unique_ptr<T>>::Wrapper(std::unique_ptr<T>&& data)
3014
+ : data_(std::move(data))
3015
+ {
3016
+ }
1436
3017
 
1437
- static std::map<T, U> convert(VALUE value)
1438
- {
1439
- std::map<T, U> result;
1440
- VALUE user_data = (VALUE)(&result);
3018
+ template<typename T>
3019
+ inline Wrapper<std::unique_ptr<T>>::~Wrapper()
3020
+ {
3021
+ Registries::instance.instances.remove(this->get());
3022
+ }
1441
3023
 
1442
- // MSVC needs help here, but g++ does not
1443
- using Rb_Hash_ForEach_T = void(*)(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE);
1444
- detail::protect<Rb_Hash_ForEach_T>(rb_hash_foreach, value, convertPair, user_data);
3024
+ template<typename T>
3025
+ inline void* Wrapper<std::unique_ptr<T>>::get()
3026
+ {
3027
+ return (void*)this->data_.get();
3028
+ }
1445
3029
 
1446
- return result;
1447
- }
1448
- };
3030
+ template<typename T>
3031
+ inline std::unique_ptr<T>& Wrapper<std::unique_ptr<T>>::data()
3032
+ {
3033
+ return data_;
3034
+ }
1449
3035
 
1450
- template<typename T, typename U>
1451
- class From_Ruby<std::map<T, U>>
3036
+ template <typename T>
3037
+ class To_Ruby<std::unique_ptr<T>>
3038
+ {
3039
+ public:
3040
+ VALUE convert(std::unique_ptr<T>& data)
1452
3041
  {
1453
- public:
1454
- From_Ruby() = default;
3042
+ std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
3043
+ return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
3044
+ }
1455
3045
 
1456
- explicit From_Ruby(Arg * arg) : arg_(arg)
1457
- {
1458
- }
3046
+ VALUE convert(std::unique_ptr<T>&& data)
3047
+ {
3048
+ std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
3049
+ return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
3050
+ }
3051
+ };
1459
3052
 
1460
- std::map<T, U> convert(VALUE value)
1461
- {
1462
- switch (rb_type(value))
1463
- {
1464
- case T_DATA:
1465
- {
1466
- // This is a wrapped map (hopefully!)
1467
- return *Data_Object<std::map<T, U>>::from_ruby(value);
1468
- }
1469
- case T_HASH:
1470
- {
1471
- // If this an Ruby hash and the mapped type is copyable
1472
- if constexpr (std::is_default_constructible_v<U>)
1473
- {
1474
- return MapFromHash<T, U>::convert(value);
1475
- }
1476
- }
1477
- case T_NIL:
1478
- {
1479
- if (this->arg_ && this->arg_->hasDefaultValue())
1480
- {
1481
- return this->arg_->template defaultValue<std::map<T, U>>();
1482
- }
1483
- }
1484
- default:
1485
- {
1486
- throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1487
- detail::protect(rb_obj_classname, value), "std::map");
1488
- }
1489
- }
1490
- }
3053
+ template <typename T>
3054
+ class To_Ruby<std::unique_ptr<T>&>
3055
+ {
3056
+ public:
3057
+ VALUE convert(std::unique_ptr<T>& data)
3058
+ {
3059
+ std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
3060
+ return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, std::move(data), true);
3061
+ }
3062
+ };
1491
3063
 
1492
- private:
1493
- Arg* arg_ = nullptr;
1494
- };
3064
+ template <typename T>
3065
+ class From_Ruby<std::unique_ptr<T>>
3066
+ {
3067
+ public:
3068
+ Wrapper<std::unique_ptr<T>>* is_same_smart_ptr(VALUE value)
3069
+ {
3070
+ WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
3071
+ return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
3072
+ }
1495
3073
 
1496
- template<typename T, typename U>
1497
- class From_Ruby<std::map<T, U>&>
3074
+ Convertible is_convertible(VALUE value)
1498
3075
  {
1499
- public:
1500
- From_Ruby() = default;
3076
+ if (!is_same_smart_ptr(value))
3077
+ return Convertible::None;
1501
3078
 
1502
- explicit From_Ruby(Arg * arg) : arg_(arg)
3079
+ switch (rb_type(value))
1503
3080
  {
3081
+ case RUBY_T_DATA:
3082
+ return Convertible::Exact;
3083
+ break;
3084
+ default:
3085
+ return Convertible::None;
1504
3086
  }
3087
+ }
1505
3088
 
1506
- std::map<T, U>& convert(VALUE value)
3089
+ std::unique_ptr<T> convert(VALUE value)
3090
+ {
3091
+ Wrapper<std::unique_ptr<T>>* wrapper = is_same_smart_ptr(value);
3092
+ if (!wrapper)
1507
3093
  {
1508
- switch (rb_type(value))
1509
- {
1510
- case T_DATA:
1511
- {
1512
- // This is a wrapped map (hopefully!)
1513
- return *Data_Object<std::map<T, U>>::from_ruby(value);
1514
- }
1515
- case T_HASH:
1516
- {
1517
- // If this an Ruby array and the map type is copyable
1518
- if constexpr (std::is_default_constructible_v<std::map<T, U>>)
1519
- {
1520
- this->converted_ = MapFromHash<T, U>::convert(value);
1521
- return this->converted_;
1522
- }
1523
- }
1524
- case T_NIL:
1525
- {
1526
- if (this->arg_ && this->arg_->hasDefaultValue())
1527
- {
1528
- return this->arg_->template defaultValue<std::map<T, U>>();
1529
- }
1530
- }
1531
- default:
1532
- {
1533
- throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1534
- detail::protect(rb_obj_classname, value), "std::map");
1535
- }
1536
- }
3094
+ std::string message = "Invalid smart pointer wrapper";
3095
+ throw std::runtime_error(message.c_str());
1537
3096
  }
3097
+ return std::move(wrapper->data());
3098
+ }
3099
+ };
1538
3100
 
1539
- private:
1540
- Arg* arg_ = nullptr;
1541
- std::map<T, U> converted_;
1542
- };
3101
+ template <typename T>
3102
+ class From_Ruby<std::unique_ptr<T>&>
3103
+ {
3104
+ public:
3105
+ Wrapper<std::unique_ptr<T>>* is_same_smart_ptr(VALUE value)
3106
+ {
3107
+ WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
3108
+ return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
3109
+ }
1543
3110
 
1544
- template<typename T, typename U>
1545
- class From_Ruby<std::map<T, U>*>
3111
+ Convertible is_convertible(VALUE value)
1546
3112
  {
1547
- public:
1548
- std::map<T, U>* convert(VALUE value)
3113
+ if (!is_same_smart_ptr(value))
3114
+ return Convertible::None;
3115
+
3116
+ switch (rb_type(value))
1549
3117
  {
1550
- switch (rb_type(value))
1551
- {
1552
- case T_DATA:
1553
- {
1554
- // This is a wrapped map (hopefully!)
1555
- return Data_Object<std::map<T, U>>::from_ruby(value);
1556
- }
1557
- case T_HASH:
1558
- {
1559
- // If this an Ruby array and the map type is copyable
1560
- if constexpr (std::is_default_constructible_v<U>)
1561
- {
1562
- this->converted_ = MapFromHash<T, U>::convert(value);
1563
- return &this->converted_;
1564
- }
1565
- }
1566
- default:
1567
- {
1568
- throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1569
- detail::protect(rb_obj_classname, value), "std::map");
1570
- }
1571
- }
3118
+ case RUBY_T_DATA:
3119
+ return Convertible::Exact;
3120
+ break;
3121
+ default:
3122
+ return Convertible::None;
1572
3123
  }
3124
+ }
1573
3125
 
1574
- private:
1575
- std::map<T, U> converted_;
1576
- };
1577
- }
3126
+ std::unique_ptr<T>& convert(VALUE value)
3127
+ {
3128
+ Wrapper<std::unique_ptr<T>>* wrapper = is_same_smart_ptr(value);
3129
+ if (!wrapper)
3130
+ {
3131
+ std::string message = "Invalid smart pointer wrapper";
3132
+ throw std::runtime_error(message.c_str());
3133
+ }
3134
+ return wrapper->data();
3135
+ }
3136
+ };
3137
+
3138
+ template<typename T>
3139
+ struct Type<std::unique_ptr<T>>
3140
+ {
3141
+ static bool verify()
3142
+ {
3143
+ return Type<T>::verify();
3144
+ }
3145
+ };
1578
3146
  }
1579
3147
 
1580
- // ========= unordered_map.hpp =========
1581
3148
 
3149
+ // ========= unordered_map.hpp =========
1582
3150
 
1583
3151
  namespace Rice
1584
3152
  {
1585
- template<typename U>
1586
- Data_Type<U> define_unordered_map(std::string name);
1587
-
1588
- template<typename U>
1589
- Data_Type<U> define_unordered_map_under(Object module, std::string name);
3153
+ template<typename Key, typename T>
3154
+ Data_Type<std::unordered_map<Key, T>> define_unordered_map(std::string name = "");
1590
3155
  }
1591
3156
 
1592
3157
 
1593
3158
  // --------- unordered_map.ipp ---------
1594
-
1595
- #include <sstream>
1596
- #include <stdexcept>
1597
- #include <type_traits>
1598
3159
  #include <unordered_map>
1599
- #include <variant>
1600
3160
 
1601
3161
  namespace Rice
1602
3162
  {
@@ -1608,8 +3168,10 @@ namespace Rice
1608
3168
  using Key_T = typename T::key_type;
1609
3169
  using Mapped_T = typename T::mapped_type;
1610
3170
  using Value_T = typename T::value_type;
3171
+ using Reference_T = typename T::reference;
1611
3172
  using Size_T = typename T::size_type;
1612
3173
  using Difference_T = typename T::difference_type;
3174
+ using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
1613
3175
 
1614
3176
  public:
1615
3177
  UnorderedMapHelper(Data_Type<T> klass) : klass_(klass)
@@ -1630,7 +3192,7 @@ namespace Rice
1630
3192
 
1631
3193
  void register_pair()
1632
3194
  {
1633
- define_pair_auto<Value_T>();
3195
+ define_pair<const Key_T, T>();
1634
3196
  }
1635
3197
 
1636
3198
  void define_constructor()
@@ -1758,7 +3320,7 @@ namespace Rice
1758
3320
  return std::nullopt;
1759
3321
  }
1760
3322
  })
1761
- .define_method("[]=", [](T& unordered_map, Key_T key, Mapped_T value) -> Mapped_T
3323
+ .define_method("[]=", [](T& unordered_map, Key_T key, Mapped_T& value) -> Mapped_T
1762
3324
  {
1763
3325
  unordered_map[key] = value;
1764
3326
  return value;
@@ -1779,10 +3341,10 @@ namespace Rice
1779
3341
  klass_.define_method("to_h", [](T& unordered_map)
1780
3342
  {
1781
3343
  VALUE result = rb_hash_new();
1782
- std::for_each(unordered_map.begin(), unordered_map.end(), [&result](const auto& pair)
3344
+ std::for_each(unordered_map.begin(), unordered_map.end(), [&result](const Reference_T& pair)
1783
3345
  {
1784
- VALUE key = detail::To_Ruby<Key_T>().convert(pair.first);
1785
- VALUE value = detail::To_Ruby<Mapped_T>().convert(pair.second);
3346
+ VALUE key = detail::To_Ruby<Key_T&>().convert(pair.first);
3347
+ VALUE value = detail::To_Ruby<To_Ruby_T&>().convert(pair.second);
1786
3348
  rb_hash_aset(result, key, value);
1787
3349
  });
1788
3350
 
@@ -1828,60 +3390,43 @@ namespace Rice
1828
3390
  };
1829
3391
  } // namespace
1830
3392
 
1831
- template<typename T>
1832
- Data_Type<T> define_unordered_map_under(Object module, std::string name)
3393
+ template<typename Key, typename T>
3394
+ Data_Type<std::unordered_map<Key, T>> define_unordered_map(std::string klassName)
1833
3395
  {
1834
- if (detail::Registries::instance.types.isDefined<T>())
3396
+ using UnorderedMap_T = std::unordered_map<Key, T>;
3397
+ using Data_Type_T = Data_Type<UnorderedMap_T>;
3398
+
3399
+ if (klassName.empty())
1835
3400
  {
1836
- // If the unordered_map has been previously seen it will be registered but may
1837
- // not be associated with the constant Module::<name>
1838
- module.const_set_maybe(name, Data_Type<T>().klass());
1839
- return Data_Type<T>();
3401
+ std::string typeName = detail::typeName(typeid(UnorderedMap_T));
3402
+ klassName = detail::rubyClassName(typeName);
1840
3403
  }
1841
3404
 
1842
- Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(module, name.c_str());
1843
- stl::UnorderedMapHelper helper(result);
1844
- return result;
1845
- }
1846
-
1847
- template<typename T>
1848
- Data_Type<T> define_unordered_map(std::string name)
1849
- {
1850
- if (detail::Registries::instance.types.isDefined<T>())
3405
+ Module rb_mStd = define_module("Std");
3406
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
1851
3407
  {
1852
- // If the unordered_map has been previously seen it will be registered but may
1853
- // not be associated with the constant Object::<name>
1854
- Object(rb_cObject).const_set_maybe(name, Data_Type<T>().klass());
1855
- return Data_Type<T>();
3408
+ return Data_Type_T();
1856
3409
  }
1857
3410
 
1858
- Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
1859
- stl::UnorderedMapHelper<T> helper(result);
3411
+ Identifier id(klassName);
3412
+ Data_Type_T result = define_class_under<detail::intrinsic_type<UnorderedMap_T>>(rb_mStd, id);
3413
+ stl::UnorderedMapHelper helper(result);
1860
3414
  return result;
1861
3415
  }
1862
3416
 
1863
- template<typename T>
1864
- Data_Type<T> define_unordered_map_auto()
1865
- {
1866
- std::string klassName = detail::makeClassName(typeid(T));
1867
- Module rb_mRice = define_module("Rice");
1868
- Module rb_munordered_map = define_module_under(rb_mRice, "Std");
1869
- return define_unordered_map_under<T>(rb_munordered_map, klassName);
1870
- }
1871
-
1872
3417
  namespace detail
1873
3418
  {
1874
- template<typename T, typename U>
1875
- struct Type<std::unordered_map<T, U>>
3419
+ template<typename Key_T, typename T>
3420
+ struct Type<std::unordered_map<Key_T, T>>
1876
3421
  {
1877
3422
  static bool verify()
1878
3423
  {
3424
+ Type<Key_T>::verify();
1879
3425
  Type<T>::verify();
1880
- Type<U>::verify();
1881
3426
 
1882
- if (!detail::Registries::instance.types.isDefined<std::unordered_map<T, U>>())
3427
+ if (!Data_Type<std::unordered_map<Key_T, T>>::is_defined())
1883
3428
  {
1884
- define_unordered_map_auto<std::unordered_map<T, U>>();
3429
+ define_unordered_map<Key_T, T>();
1885
3430
  }
1886
3431
 
1887
3432
  return true;
@@ -1927,16 +3472,31 @@ namespace Rice
1927
3472
  {
1928
3473
  }
1929
3474
 
3475
+ Convertible is_convertible(VALUE value)
3476
+ {
3477
+ switch (rb_type(value))
3478
+ {
3479
+ case RUBY_T_DATA:
3480
+ return Data_Type<std::unordered_map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
3481
+ break;
3482
+ case RUBY_T_HASH:
3483
+ return Convertible::Cast;
3484
+ break;
3485
+ default:
3486
+ return Convertible::None;
3487
+ }
3488
+ }
3489
+
1930
3490
  std::unordered_map<T, U> convert(VALUE value)
1931
3491
  {
1932
3492
  switch (rb_type(value))
1933
3493
  {
1934
- case T_DATA:
3494
+ case RUBY_T_DATA:
1935
3495
  {
1936
3496
  // This is a wrapped unordered_map (hopefully!)
1937
- return *Data_Object<std::unordered_map<T, U>>::from_ruby(value);
3497
+ return *detail::unwrap<std::unordered_map<T, U>>(value, Data_Type<std::unordered_map<T, U>>::ruby_data_type(), false);
1938
3498
  }
1939
- case T_HASH:
3499
+ case RUBY_T_HASH:
1940
3500
  {
1941
3501
  // If this an Ruby hash and the unordered_mapped type is copyable
1942
3502
  if constexpr (std::is_default_constructible_v<U>)
@@ -1944,13 +3504,6 @@ namespace Rice
1944
3504
  return UnorderedMapFromHash<T, U>::convert(value);
1945
3505
  }
1946
3506
  }
1947
- case T_NIL:
1948
- {
1949
- if (this->arg_ && this->arg_->hasDefaultValue())
1950
- {
1951
- return this->arg_->template defaultValue<std::unordered_map<T, U>>();
1952
- }
1953
- }
1954
3507
  default:
1955
3508
  {
1956
3509
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
@@ -1973,16 +3526,31 @@ namespace Rice
1973
3526
  {
1974
3527
  }
1975
3528
 
3529
+ Convertible is_convertible(VALUE value)
3530
+ {
3531
+ switch (rb_type(value))
3532
+ {
3533
+ case RUBY_T_DATA:
3534
+ return Data_Type<std::unordered_map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
3535
+ break;
3536
+ case RUBY_T_HASH:
3537
+ return Convertible::Cast;
3538
+ break;
3539
+ default:
3540
+ return Convertible::None;
3541
+ }
3542
+ }
3543
+
1976
3544
  std::unordered_map<T, U>& convert(VALUE value)
1977
3545
  {
1978
3546
  switch (rb_type(value))
1979
3547
  {
1980
- case T_DATA:
3548
+ case RUBY_T_DATA:
1981
3549
  {
1982
3550
  // This is a wrapped unordered_map (hopefully!)
1983
- return *Data_Object<std::unordered_map<T, U>>::from_ruby(value);
3551
+ return *detail::unwrap<std::unordered_map<T, U>>(value, Data_Type<std::unordered_map<T, U>>::ruby_data_type(), false);
1984
3552
  }
1985
- case T_HASH:
3553
+ case RUBY_T_HASH:
1986
3554
  {
1987
3555
  // If this an Ruby array and the unordered_map type is copyable
1988
3556
  if constexpr (std::is_default_constructible_v<std::unordered_map<T, U>>)
@@ -1991,13 +3559,6 @@ namespace Rice
1991
3559
  return this->converted_;
1992
3560
  }
1993
3561
  }
1994
- case T_NIL:
1995
- {
1996
- if (this->arg_ && this->arg_->hasDefaultValue())
1997
- {
1998
- return this->arg_->template defaultValue<std::unordered_map<T, U>>();
1999
- }
2000
- }
2001
3562
  default:
2002
3563
  {
2003
3564
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
@@ -2015,16 +3576,34 @@ namespace Rice
2015
3576
  class From_Ruby<std::unordered_map<T, U>*>
2016
3577
  {
2017
3578
  public:
3579
+ Convertible is_convertible(VALUE value)
3580
+ {
3581
+ switch (rb_type(value))
3582
+ {
3583
+ case RUBY_T_DATA:
3584
+ return Data_Type<std::unordered_map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
3585
+ break;
3586
+ case RUBY_T_NIL:
3587
+ return Convertible::Exact;
3588
+ break;
3589
+ case RUBY_T_HASH:
3590
+ return Convertible::Cast;
3591
+ break;
3592
+ default:
3593
+ return Convertible::None;
3594
+ }
3595
+ }
3596
+
2018
3597
  std::unordered_map<T, U>* convert(VALUE value)
2019
3598
  {
2020
3599
  switch (rb_type(value))
2021
3600
  {
2022
- case T_DATA:
3601
+ case RUBY_T_DATA:
2023
3602
  {
2024
3603
  // This is a wrapped unordered_map (hopefully!)
2025
- return Data_Object<std::unordered_map<T, U>>::from_ruby(value);
3604
+ return detail::unwrap<std::unordered_map<T, U>>(value, Data_Type<std::unordered_map<T, U>>::ruby_data_type(), false);
2026
3605
  }
2027
- case T_HASH:
3606
+ case RUBY_T_HASH:
2028
3607
  {
2029
3608
  // If this an Ruby array and the unordered_map type is copyable
2030
3609
  if constexpr (std::is_default_constructible_v<U>)
@@ -2049,24 +3628,15 @@ namespace Rice
2049
3628
 
2050
3629
  // ========= vector.hpp =========
2051
3630
 
2052
-
2053
3631
  namespace Rice
2054
3632
  {
2055
3633
  template<typename T>
2056
- Data_Type<T> define_vector(std::string name);
2057
-
2058
- template<typename T>
2059
- Data_Type<T> define_vector_under(Object module, std::string name);
3634
+ Data_Type<std::vector<T>> define_vector(std::string name = "" );
2060
3635
  }
2061
3636
 
2062
3637
 
2063
3638
  // --------- vector.ipp ---------
2064
-
2065
- #include <sstream>
2066
- #include <stdexcept>
2067
- #include <type_traits>
2068
3639
  #include <vector>
2069
- #include <variant>
2070
3640
 
2071
3641
  namespace Rice
2072
3642
  {
@@ -2075,15 +3645,22 @@ namespace Rice
2075
3645
  template<typename T>
2076
3646
  class VectorHelper
2077
3647
  {
3648
+ // We do NOT use Reference_T and instead use Parameter_T to avoid the weirdness
3649
+ // of std::vector<bool>. Reference_T is actually a proxy class that we do not
3650
+ // want to have to register with Rice nor do we want to pass it around.
2078
3651
  using Value_T = typename T::value_type;
2079
3652
  using Size_T = typename T::size_type;
2080
3653
  using Difference_T = typename T::difference_type;
3654
+ // For To_Ruby_T however we do need to use reference type because this is what
3655
+ // will be passed by an interator to To_Ruby#convert
3656
+ using Reference_T = typename T::reference;
3657
+ using Parameter_T = std::conditional_t<std::is_pointer_v<Value_T>, Value_T, Value_T&>;
3658
+ using To_Ruby_T = detail::remove_cv_recursive_t<typename T::reference>;
2081
3659
 
2082
3660
  public:
2083
3661
  VectorHelper(Data_Type<T> klass) : klass_(klass)
2084
3662
  {
2085
- this->define_constructor();
2086
- this->define_copyable_methods();
3663
+ this->define_constructors();
2087
3664
  this->define_constructable_methods();
2088
3665
  this->define_capacity_methods();
2089
3666
  this->define_access_methods();
@@ -2115,33 +3692,44 @@ namespace Rice
2115
3692
  return index;
2116
3693
  };
2117
3694
 
2118
- void define_constructor()
3695
+ void define_constructors()
2119
3696
  {
2120
- klass_.define_constructor(Constructor<T>());
2121
- }
3697
+ klass_.define_constructor(Constructor<T>())
3698
+ .define_constructor(Constructor<T, Size_T, const Parameter_T>())
3699
+ .define_constructor(Constructor<T, const T&>());
2122
3700
 
2123
- void define_copyable_methods()
2124
- {
2125
- if constexpr (std::is_copy_constructible_v<Value_T>)
3701
+ if constexpr (std::is_default_constructible_v<Value_T>)
2126
3702
  {
2127
- klass_.define_method("copy", [](T& vector) -> T
2128
- {
2129
- return vector;
2130
- });
3703
+ klass_.define_constructor(Constructor<T, Size_T>());
2131
3704
  }
2132
- else
3705
+
3706
+ // Allow creation of a vector from a Ruby Array
3707
+ klass_.define_method("initialize", [](VALUE self, Array array) -> void
2133
3708
  {
2134
- klass_.define_method("copy", [](T& vector) -> T
2135
- {
2136
- throw std::runtime_error("Cannot copy vectors with non-copy constructible types");
2137
- return vector;
2138
- });
2139
- }
3709
+ // Create a new vector from the array
3710
+ T* data = new T();
3711
+ data->reserve(array.size());
3712
+
3713
+ detail::From_Ruby<Value_T> fromRuby;
3714
+
3715
+ for (long i = 0; i < array.size(); i++)
3716
+ {
3717
+ VALUE element = detail::protect(rb_ary_entry, array, i);
3718
+ data->push_back(fromRuby.convert(element));
3719
+ }
3720
+
3721
+ // Wrap the vector
3722
+ detail::wrapConstructed<T>(self, Data_Type<T>::ruby_data_type(), data, true);
3723
+ });
2140
3724
  }
2141
3725
 
2142
3726
  void define_constructable_methods()
2143
3727
  {
2144
- if constexpr (std::is_default_constructible_v<Value_T>)
3728
+ if constexpr (std::is_default_constructible_v<Value_T> && std::is_same_v<Value_T, bool>)
3729
+ {
3730
+ klass_.define_method("resize", static_cast<void (T::*)(const size_t, bool)>(&T::resize));
3731
+ }
3732
+ else if constexpr (std::is_default_constructible_v<Value_T>)
2145
3733
  {
2146
3734
  klass_.define_method("resize", static_cast<void (T::*)(const size_t)>(&T::resize));
2147
3735
  }
@@ -2172,49 +3760,87 @@ namespace Rice
2172
3760
  {
2173
3761
  // Access methods
2174
3762
  klass_.define_method("first", [](const T& vector) -> std::optional<Value_T>
3763
+ {
3764
+ if (vector.size() > 0)
3765
+ {
3766
+ return vector.front();
3767
+ }
3768
+ else
3769
+ {
3770
+ return std::nullopt;
3771
+ }
3772
+ })
3773
+ .define_method("last", [](const T& vector) -> std::optional<Value_T>
2175
3774
  {
2176
3775
  if (vector.size() > 0)
2177
3776
  {
2178
- return vector.front();
3777
+ return vector.back();
2179
3778
  }
2180
3779
  else
2181
3780
  {
2182
3781
  return std::nullopt;
2183
3782
  }
2184
3783
  })
2185
- .define_method("last", [](const T& vector) -> std::optional<Value_T>
3784
+ .define_method("[]", [this](const T& vector, Difference_T index) -> std::optional<Value_T>
3785
+ {
3786
+ index = normalizeIndex(vector.size(), index);
3787
+ if (index < 0 || index >= (Difference_T)vector.size())
2186
3788
  {
2187
- if (vector.size() > 0)
2188
- {
2189
- return vector.back();
2190
- }
2191
- else
3789
+ return std::nullopt;
3790
+ }
3791
+ else
3792
+ {
3793
+ return vector[index];
3794
+ }
3795
+ })
3796
+ .define_method("[]", [this](const T& vector, Difference_T start, Difference_T length) -> VALUE
3797
+ {
3798
+ start = normalizeIndex(vector.size(), start);
3799
+ if (start < 0 || start >= (Difference_T)vector.size())
3800
+ {
3801
+ return rb_ary_new();
3802
+ }
3803
+ else
3804
+ {
3805
+ auto begin = vector.begin() + start;
3806
+
3807
+ // Ruby does not throw an exception when the length is too long
3808
+ Difference_T size = (Difference_T)vector.size();
3809
+ if (start + length > size)
2192
3810
  {
2193
- return std::nullopt;
3811
+ length = size - start;
2194
3812
  }
2195
- })
2196
- .define_method("[]", [this](const T& vector, Difference_T index) -> std::optional<Value_T>
3813
+
3814
+ auto finish = vector.begin() + start + length;
3815
+ T slice(begin, finish);
3816
+
3817
+ VALUE result = rb_ary_new();
3818
+ std::for_each(slice.begin(), slice.end(), [&result](const Reference_T element)
2197
3819
  {
2198
- index = normalizeIndex(vector.size(), index);
2199
- if (index < 0 || index >= (Difference_T)vector.size())
2200
- {
2201
- return std::nullopt;
2202
- }
2203
- else
2204
- {
2205
- return vector[index];
2206
- }
3820
+ VALUE value = detail::To_Ruby<Parameter_T>().convert(element);
3821
+ rb_ary_push(result, value);
2207
3822
  });
2208
3823
 
2209
- rb_define_alias(klass_, "at", "[]");
3824
+ return result;
3825
+ }
3826
+ }, Return().setValue());
3827
+
3828
+ if constexpr (!std::is_same_v<Value_T, bool>)
3829
+ {
3830
+ define_buffer<Value_T>();
3831
+ define_buffer<Value_T*>();
3832
+ klass_.template define_method<Value_T*(T::*)()>("data", &T::data);
3833
+ }
3834
+
3835
+ rb_define_alias(klass_, "at", "[]");
2210
3836
  }
2211
3837
 
2212
3838
  // Methods that require Value_T to support operator==
2213
3839
  void define_comparable_methods()
2214
3840
  {
2215
- if constexpr (detail::is_comparable_v<Value_T>)
3841
+ if constexpr (detail::is_comparable_v<T>)
2216
3842
  {
2217
- klass_.define_method("delete", [](T& vector, Value_T& element) -> std::optional<Value_T>
3843
+ klass_.define_method("delete", [](T& vector, Parameter_T element) -> std::optional<Value_T>
2218
3844
  {
2219
3845
  auto iter = std::find(vector.begin(), vector.end(), element);
2220
3846
  if (iter == vector.end())
@@ -2228,11 +3854,11 @@ namespace Rice
2228
3854
  return result;
2229
3855
  }
2230
3856
  })
2231
- .define_method("include?", [](T& vector, Value_T& element)
3857
+ .define_method("include?", [](T& vector, Parameter_T element)
2232
3858
  {
2233
3859
  return std::find(vector.begin(), vector.end(), element) != vector.end();
2234
3860
  })
2235
- .define_method("index", [](T& vector, Value_T& element) -> std::optional<Difference_T>
3861
+ .define_method("index", [](T& vector, Parameter_T element) -> std::optional<Difference_T>
2236
3862
  {
2237
3863
  auto iter = std::find(vector.begin(), vector.end(), element);
2238
3864
  if (iter == vector.end())
@@ -2247,15 +3873,15 @@ namespace Rice
2247
3873
  }
2248
3874
  else
2249
3875
  {
2250
- klass_.define_method("delete", [](T& vector, Value_T& element) -> std::optional<Value_T>
3876
+ klass_.define_method("delete", [](T& vector, Parameter_T element) -> std::optional<Value_T>
2251
3877
  {
2252
3878
  return std::nullopt;
2253
3879
  })
2254
- .define_method("include?", [](const T& vector, Value_T& element)
3880
+ .define_method("include?", [](const T& vector, Parameter_T element)
2255
3881
  {
2256
3882
  return false;
2257
3883
  })
2258
- .define_method("index", [](const T& vector, Value_T& element) -> std::optional<Difference_T>
3884
+ .define_method("index", [](const T& vector, Parameter_T element) -> std::optional<Difference_T>
2259
3885
  {
2260
3886
  return std::nullopt;
2261
3887
  });
@@ -2272,7 +3898,7 @@ namespace Rice
2272
3898
  vector.erase(iter);
2273
3899
  return result;
2274
3900
  })
2275
- .define_method("insert", [this](T& vector, Difference_T index, Value_T& element) -> T&
3901
+ .define_method("insert", [this](T& vector, Difference_T index, Parameter_T element) -> T&
2276
3902
  {
2277
3903
  index = normalizeIndex(vector.size(), index, true);
2278
3904
  auto iter = vector.begin() + index;
@@ -2292,21 +3918,22 @@ namespace Rice
2292
3918
  return std::nullopt;
2293
3919
  }
2294
3920
  })
2295
- .define_method("push", [](T& vector, Value_T& element) -> T&
3921
+ .define_method("push", [](T& vector, Parameter_T element) -> T&
2296
3922
  {
2297
3923
  vector.push_back(element);
2298
3924
  return vector;
2299
3925
  })
2300
3926
  .define_method("shrink_to_fit", &T::shrink_to_fit)
2301
- .define_method("[]=", [this](T& vector, Difference_T index, Value_T& element) -> Value_T&
3927
+ .define_method("[]=", [this](T& vector, Difference_T index, Parameter_T element) -> Parameter_T
2302
3928
  {
2303
3929
  index = normalizeIndex(vector.size(), index, true);
2304
3930
  vector[index] = element;
2305
3931
  return element;
2306
3932
  });
2307
3933
 
2308
- rb_define_alias(klass_, "<<", "push");
2309
- rb_define_alias(klass_, "append", "push");
3934
+ rb_define_alias(klass_, "push_back", "push");
3935
+ rb_define_alias(klass_, "<<", "push");
3936
+ rb_define_alias(klass_, "append", "push");
2310
3937
  }
2311
3938
 
2312
3939
  void define_enumerable()
@@ -2321,9 +3948,9 @@ namespace Rice
2321
3948
  klass_.define_method("to_a", [](T& vector)
2322
3949
  {
2323
3950
  VALUE result = rb_ary_new();
2324
- std::for_each(vector.begin(), vector.end(), [&result](const Value_T& element)
3951
+ std::for_each(vector.begin(), vector.end(), [&result](const Reference_T element)
2325
3952
  {
2326
- VALUE value = detail::To_Ruby<Value_T&>().convert(element);
3953
+ VALUE value = detail::To_Ruby<Parameter_T>().convert(element);
2327
3954
  rb_ary_push(result, value);
2328
3955
  });
2329
3956
 
@@ -2374,48 +4001,30 @@ namespace Rice
2374
4001
  } // namespace
2375
4002
 
2376
4003
  template<typename T>
2377
- Data_Type<T> define_vector_under(Object module, std::string name)
4004
+ Data_Type<std::vector<T>> define_vector(std::string klassName)
2378
4005
  {
2379
- if (detail::Registries::instance.types.isDefined<T>())
2380
- {
2381
- // If the vector has been previously seen it will be registered but may
2382
- // not be associated with the constant Module::<name>
2383
- module.const_set_maybe(name, Data_Type<T>().klass());
4006
+ using Vector_T = std::vector<T>;
4007
+ using Data_Type_T = Data_Type<Vector_T>;
2384
4008
 
2385
- return Data_Type<T>();
4009
+ if (klassName.empty())
4010
+ {
4011
+ std::string typeName = detail::typeName(typeid(Vector_T));
4012
+ klassName = detail::rubyClassName(typeName);
2386
4013
  }
2387
4014
 
2388
- Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(module, name.c_str());
2389
- stl::VectorHelper helper(result);
2390
- return result;
2391
- }
2392
-
2393
- template<typename T>
2394
- Data_Type<T> define_vector(std::string name)
2395
- {
2396
- if (detail::Registries::instance.types.isDefined<T>())
4015
+ Module rb_mStd = define_module("Std");
4016
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
2397
4017
  {
2398
- // If the vector has been previously seen it will be registered but may
2399
- // not be associated with the constant Module::<name>
2400
- Object(rb_cObject).const_set_maybe(name, Data_Type<T>().klass());
2401
-
2402
- return Data_Type<T>();
4018
+ return Data_Type_T();
2403
4019
  }
2404
4020
 
2405
- Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
2406
- stl::VectorHelper<T> helper(result);
4021
+ Identifier id(klassName);
4022
+ Data_Type_T result = define_class_under<detail::intrinsic_type<Vector_T>>(rb_mStd, id);
4023
+ stl::VectorHelper helper(result);
2407
4024
  return result;
2408
4025
  }
2409
4026
 
2410
- template<typename T>
2411
- Data_Type<T> define_vector_auto()
2412
- {
2413
- std::string klassName = detail::makeClassName(typeid(T));
2414
- Module rb_mRice = define_module("Rice");
2415
- Module rb_mVector = define_module_under(rb_mRice, "Std");
2416
- return define_vector_under<T>(rb_mVector, klassName);
2417
- }
2418
-
4027
+
2419
4028
  namespace detail
2420
4029
  {
2421
4030
  template<typename T>
@@ -2425,30 +4034,15 @@ namespace Rice
2425
4034
  {
2426
4035
  Type<intrinsic_type<T>>::verify();
2427
4036
 
2428
- if (!detail::Registries::instance.types.isDefined<std::vector<T>>())
4037
+ if (!Data_Type<std::vector<T>>::is_defined())
2429
4038
  {
2430
- define_vector_auto<std::vector<T>>();
4039
+ define_vector<T>();
2431
4040
  }
2432
4041
 
2433
4042
  return true;
2434
4043
  }
2435
4044
  };
2436
4045
 
2437
- template<typename T>
2438
- std::vector<T> vectorFromArray(VALUE value)
2439
- {
2440
- long length = protect(rb_array_len, value);
2441
- std::vector<T> result(length);
2442
-
2443
- for (long i = 0; i < length; i++)
2444
- {
2445
- VALUE element = protect(rb_ary_entry, value, i);
2446
- result[i] = From_Ruby<T>().convert(element);
2447
- }
2448
-
2449
- return result;
2450
- }
2451
-
2452
4046
  template<typename T>
2453
4047
  class From_Ruby<std::vector<T>>
2454
4048
  {
@@ -2459,28 +4053,38 @@ namespace Rice
2459
4053
  {
2460
4054
  }
2461
4055
 
4056
+ Convertible is_convertible(VALUE value)
4057
+ {
4058
+ switch (rb_type(value))
4059
+ {
4060
+ case RUBY_T_DATA:
4061
+ return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
4062
+ break;
4063
+ case RUBY_T_ARRAY:
4064
+ if constexpr (std::is_default_constructible_v<T>)
4065
+ {
4066
+ return Convertible::Cast;
4067
+ }
4068
+ default:
4069
+ return Convertible::None;
4070
+ }
4071
+ }
4072
+
2462
4073
  std::vector<T> convert(VALUE value)
2463
4074
  {
2464
4075
  switch (rb_type(value))
2465
4076
  {
2466
- case T_DATA:
4077
+ case RUBY_T_DATA:
2467
4078
  {
2468
4079
  // This is a wrapped vector (hopefully!)
2469
- return *Data_Object<std::vector<T>>::from_ruby(value);
4080
+ return *detail::unwrap<std::vector<T>>(value, Data_Type<std::vector<T>>::ruby_data_type(), false);
2470
4081
  }
2471
- case T_ARRAY:
4082
+ case RUBY_T_ARRAY:
2472
4083
  {
2473
4084
  // If this an Ruby array and the vector type is copyable
2474
4085
  if constexpr (std::is_default_constructible_v<T>)
2475
4086
  {
2476
- return vectorFromArray<T>(value);
2477
- }
2478
- }
2479
- case T_NIL:
2480
- {
2481
- if (this->arg_ && this->arg_->hasDefaultValue())
2482
- {
2483
- return this->arg_->template defaultValue<std::vector<T>>();
4087
+ return Array(value).to_vector<T>();
2484
4088
  }
2485
4089
  }
2486
4090
  default:
@@ -2491,11 +4095,6 @@ namespace Rice
2491
4095
  }
2492
4096
  }
2493
4097
 
2494
- bool is_convertible(VALUE value)
2495
- {
2496
- return rb_type(value) == RUBY_T_ARRAY;
2497
- }
2498
-
2499
4098
  private:
2500
4099
  Arg* arg_ = nullptr;
2501
4100
  };
@@ -2510,31 +4109,41 @@ namespace Rice
2510
4109
  {
2511
4110
  }
2512
4111
 
4112
+ Convertible is_convertible(VALUE value)
4113
+ {
4114
+ switch (rb_type(value))
4115
+ {
4116
+ case RUBY_T_DATA:
4117
+ return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
4118
+ break;
4119
+ case RUBY_T_ARRAY:
4120
+ if constexpr (std::is_default_constructible_v<T>)
4121
+ {
4122
+ return Convertible::Cast;
4123
+ }
4124
+ default:
4125
+ return Convertible::None;
4126
+ }
4127
+ }
4128
+
2513
4129
  std::vector<T>& convert(VALUE value)
2514
4130
  {
2515
4131
  switch (rb_type(value))
2516
4132
  {
2517
- case T_DATA:
4133
+ case RUBY_T_DATA:
2518
4134
  {
2519
4135
  // This is a wrapped vector (hopefully!)
2520
- return *Data_Object<std::vector<T>>::from_ruby(value);
4136
+ return *detail::unwrap<std::vector<T>>(value, Data_Type<std::vector<T>>::ruby_data_type(), false);
2521
4137
  }
2522
- case T_ARRAY:
4138
+ case RUBY_T_ARRAY:
2523
4139
  {
2524
4140
  // If this an Ruby array and the vector type is copyable
2525
4141
  if constexpr (std::is_default_constructible_v<T>)
2526
4142
  {
2527
- this->converted_ = vectorFromArray<T>(value);
4143
+ this->converted_ = Array(value).to_vector<T>();
2528
4144
  return this->converted_;
2529
4145
  }
2530
4146
  }
2531
- case T_NIL:
2532
- {
2533
- if (this->arg_ && this->arg_->hasDefaultValue())
2534
- {
2535
- return this->arg_->template defaultValue<std::vector<T>>();
2536
- }
2537
- }
2538
4147
  default:
2539
4148
  {
2540
4149
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
@@ -2543,11 +4152,6 @@ namespace Rice
2543
4152
  }
2544
4153
  }
2545
4154
 
2546
- bool is_convertible(VALUE value)
2547
- {
2548
- return rb_type(value) == RUBY_T_ARRAY;
2549
- }
2550
-
2551
4155
  private:
2552
4156
  Arg* arg_ = nullptr;
2553
4157
  std::vector<T> converted_;
@@ -2557,21 +4161,41 @@ namespace Rice
2557
4161
  class From_Ruby<std::vector<T>*>
2558
4162
  {
2559
4163
  public:
4164
+ Convertible is_convertible(VALUE value)
4165
+ {
4166
+ switch (rb_type(value))
4167
+ {
4168
+ case RUBY_T_DATA:
4169
+ return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
4170
+ break;
4171
+ case RUBY_T_NIL:
4172
+ return Convertible::Exact;
4173
+ break;
4174
+ case RUBY_T_ARRAY:
4175
+ if constexpr (std::is_default_constructible_v<T>)
4176
+ {
4177
+ return Convertible::Cast;
4178
+ }
4179
+ default:
4180
+ return Convertible::None;
4181
+ }
4182
+ }
4183
+
2560
4184
  std::vector<T>* convert(VALUE value)
2561
4185
  {
2562
4186
  switch (rb_type(value))
2563
4187
  {
2564
- case T_DATA:
4188
+ case RUBY_T_DATA:
2565
4189
  {
2566
4190
  // This is a wrapped vector (hopefully!)
2567
- return Data_Object<std::vector<T>>::from_ruby(value);
4191
+ return detail::unwrap<std::vector<T>>(value, Data_Type<std::vector<T>>::ruby_data_type(), false);
2568
4192
  }
2569
- case T_ARRAY:
4193
+ case RUBY_T_ARRAY:
2570
4194
  {
2571
- // If this an Ruby array and the vector type is copyable
4195
+ // If this a Ruby array and the vector type is copyable
2572
4196
  if constexpr (std::is_default_constructible_v<T>)
2573
4197
  {
2574
- this->converted_ = vectorFromArray<T>(value);
4198
+ this->converted_ = Array(value).to_vector<T>();
2575
4199
  return &this->converted_;
2576
4200
  }
2577
4201
  }
@@ -2583,15 +4207,24 @@ namespace Rice
2583
4207
  }
2584
4208
  }
2585
4209
 
2586
- bool is_convertible(VALUE value)
2587
- {
2588
- return rb_type(value) == RUBY_T_ARRAY;
2589
- }
2590
-
2591
4210
  private:
2592
4211
  std::vector<T> converted_;
2593
4212
  };
2594
4213
  }
4214
+
4215
+ // Special handling for std::vector<bool>
4216
+ namespace detail
4217
+ {
4218
+ template<>
4219
+ class To_Ruby<std::vector<bool>::reference>
4220
+ {
4221
+ public:
4222
+ VALUE convert(const std::vector<bool>::reference& value)
4223
+ {
4224
+ return value ? Qtrue : Qfalse;
4225
+ }
4226
+ };
4227
+ }
2595
4228
  }
2596
4229
 
2597
4230