rice 4.5.0 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/CMakeLists.txt +31 -0
  4. data/CMakePresets.json +75 -0
  5. data/COPYING +3 -2
  6. data/FindRuby.cmake +437 -0
  7. data/Rakefile +5 -4
  8. data/include/rice/rice.hpp +5436 -3201
  9. data/include/rice/stl.hpp +2355 -1269
  10. data/lib/make_rice_headers.rb +79 -0
  11. data/lib/mkmf-rice.rb +4 -0
  12. data/lib/rice/version.rb +3 -0
  13. data/lib/rice.rb +1 -0
  14. data/lib/rubygems/builder.rb +11 -0
  15. data/lib/rubygems/cmake_builder.rb +113 -0
  16. data/lib/rubygems_plugin.rb +9 -0
  17. data/rice/Arg.hpp +7 -1
  18. data/rice/Arg.ipp +11 -2
  19. data/rice/Buffer.hpp +123 -0
  20. data/rice/Buffer.ipp +599 -0
  21. data/rice/Constructor.ipp +3 -3
  22. data/rice/Data_Object.hpp +2 -3
  23. data/rice/Data_Object.ipp +188 -188
  24. data/rice/Data_Type.hpp +4 -5
  25. data/rice/Data_Type.ipp +42 -26
  26. data/rice/Enum.hpp +0 -1
  27. data/rice/Enum.ipp +26 -23
  28. data/rice/Init.hpp +8 -0
  29. data/rice/Init.ipp +8 -0
  30. data/rice/MemoryView.ipp +1 -41
  31. data/rice/Return.hpp +1 -1
  32. data/rice/Return.ipp +6 -0
  33. data/rice/cpp_api/Array.hpp +209 -0
  34. data/rice/cpp_api/Array.ipp +304 -0
  35. data/rice/cpp_api/Builtin_Object.hpp +31 -0
  36. data/rice/cpp_api/Builtin_Object.ipp +37 -0
  37. data/rice/cpp_api/Class.hpp +70 -0
  38. data/rice/cpp_api/Class.ipp +97 -0
  39. data/rice/cpp_api/Encoding.hpp +32 -0
  40. data/rice/cpp_api/Encoding.ipp +59 -0
  41. data/rice/cpp_api/Hash.hpp +194 -0
  42. data/rice/cpp_api/Hash.ipp +257 -0
  43. data/rice/cpp_api/Identifier.hpp +46 -0
  44. data/rice/cpp_api/Identifier.ipp +31 -0
  45. data/rice/cpp_api/Module.hpp +72 -0
  46. data/rice/cpp_api/Module.ipp +101 -0
  47. data/rice/cpp_api/Object.hpp +272 -0
  48. data/rice/cpp_api/Object.ipp +235 -0
  49. data/rice/cpp_api/String.hpp +74 -0
  50. data/rice/cpp_api/String.ipp +120 -0
  51. data/rice/cpp_api/Struct.hpp +113 -0
  52. data/rice/cpp_api/Struct.ipp +92 -0
  53. data/rice/cpp_api/Symbol.hpp +46 -0
  54. data/rice/cpp_api/Symbol.ipp +93 -0
  55. data/rice/cpp_api/shared_methods.hpp +134 -0
  56. data/rice/detail/MethodInfo.hpp +1 -9
  57. data/rice/detail/MethodInfo.ipp +5 -72
  58. data/rice/detail/Native.hpp +3 -2
  59. data/rice/detail/Native.ipp +32 -4
  60. data/rice/detail/NativeAttributeGet.hpp +3 -2
  61. data/rice/detail/NativeAttributeGet.ipp +8 -2
  62. data/rice/detail/NativeAttributeSet.hpp +3 -2
  63. data/rice/detail/NativeAttributeSet.ipp +8 -2
  64. data/rice/detail/NativeCallbackFFI.ipp +1 -1
  65. data/rice/detail/NativeFunction.hpp +17 -6
  66. data/rice/detail/NativeFunction.ipp +168 -64
  67. data/rice/detail/NativeIterator.hpp +3 -2
  68. data/rice/detail/NativeIterator.ipp +8 -2
  69. data/rice/detail/RubyType.hpp +2 -5
  70. data/rice/detail/RubyType.ipp +50 -5
  71. data/rice/detail/Type.hpp +3 -1
  72. data/rice/detail/Type.ipp +61 -31
  73. data/rice/detail/Wrapper.hpp +68 -33
  74. data/rice/detail/Wrapper.ipp +103 -113
  75. data/rice/detail/from_ruby.hpp +5 -4
  76. data/rice/detail/from_ruby.ipp +737 -365
  77. data/rice/detail/to_ruby.ipp +1092 -186
  78. data/rice/global_function.ipp +1 -1
  79. data/rice/libc/file.hpp +11 -0
  80. data/rice/libc/file.ipp +32 -0
  81. data/rice/rice.hpp +23 -16
  82. data/rice/stl/complex.hpp +6 -0
  83. data/rice/stl/complex.ipp +93 -0
  84. data/rice/stl/exception.hpp +11 -0
  85. data/rice/stl/exception.ipp +29 -0
  86. data/rice/stl/exception_ptr.hpp +6 -0
  87. data/rice/stl/exception_ptr.ipp +27 -0
  88. data/rice/stl/map.hpp +12 -0
  89. data/rice/stl/map.ipp +469 -0
  90. data/rice/stl/monostate.hpp +6 -0
  91. data/rice/stl/monostate.ipp +80 -0
  92. data/rice/stl/multimap.hpp +14 -0
  93. data/rice/stl/multimap.ipp +448 -0
  94. data/rice/stl/optional.hpp +6 -0
  95. data/rice/stl/optional.ipp +118 -0
  96. data/rice/stl/pair.hpp +13 -0
  97. data/rice/stl/pair.ipp +155 -0
  98. data/rice/stl/reference_wrapper.hpp +6 -0
  99. data/rice/stl/reference_wrapper.ipp +41 -0
  100. data/rice/stl/set.hpp +12 -0
  101. data/rice/stl/set.ipp +495 -0
  102. data/rice/stl/shared_ptr.hpp +28 -0
  103. data/rice/stl/shared_ptr.ipp +224 -0
  104. data/rice/stl/string.hpp +6 -0
  105. data/rice/stl/string.ipp +158 -0
  106. data/rice/stl/string_view.hpp +6 -0
  107. data/rice/stl/string_view.ipp +65 -0
  108. data/rice/stl/tuple.hpp +6 -0
  109. data/rice/stl/tuple.ipp +128 -0
  110. data/rice/stl/type_index.hpp +6 -0
  111. data/rice/stl/type_index.ipp +30 -0
  112. data/rice/stl/type_info.hpp +6 -0
  113. data/rice/stl/type_info.ipp +29 -0
  114. data/rice/stl/unique_ptr.hpp +22 -0
  115. data/rice/stl/unique_ptr.ipp +139 -0
  116. data/rice/stl/unordered_map.hpp +12 -0
  117. data/rice/stl/unordered_map.ipp +469 -0
  118. data/rice/stl/variant.hpp +6 -0
  119. data/rice/stl/variant.ipp +242 -0
  120. data/rice/stl/vector.hpp +12 -0
  121. data/rice/stl/vector.ipp +590 -0
  122. data/rice/stl.hpp +7 -3
  123. data/rice/traits/attribute_traits.hpp +26 -0
  124. data/rice/traits/function_traits.hpp +95 -0
  125. data/rice/traits/method_traits.hpp +47 -0
  126. data/rice/traits/rice_traits.hpp +160 -0
  127. data/rice.gemspec +85 -0
  128. data/test/embed_ruby.cpp +3 -0
  129. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  130. data/test/test_Array.cpp +6 -3
  131. data/test/test_Attribute.cpp +34 -1
  132. data/test/test_Buffer.cpp +285 -0
  133. data/test/test_Callback.cpp +2 -3
  134. data/test/test_Data_Object.cpp +88 -34
  135. data/test/test_Data_Type.cpp +106 -65
  136. data/test/test_Director.cpp +7 -3
  137. data/test/test_Enum.cpp +5 -2
  138. data/test/test_File.cpp +1 -1
  139. data/test/test_From_Ruby.cpp +181 -114
  140. data/test/test_Iterator.cpp +1 -1
  141. data/test/{test_JumpException.cpp → test_Jump_Exception.cpp} +1 -0
  142. data/test/test_Keep_Alive.cpp +7 -18
  143. data/test/test_Keep_Alive_No_Wrapper.cpp +0 -1
  144. data/test/test_Module.cpp +13 -6
  145. data/test/test_Native_Registry.cpp +0 -1
  146. data/test/test_Overloads.cpp +180 -5
  147. data/test/test_Ownership.cpp +100 -57
  148. data/test/test_Proc.cpp +0 -1
  149. data/test/test_Self.cpp +4 -4
  150. data/test/test_Stl_Map.cpp +37 -39
  151. data/test/test_Stl_Multimap.cpp +693 -0
  152. data/test/test_Stl_Pair.cpp +8 -8
  153. data/test/test_Stl_Reference_Wrapper.cpp +4 -2
  154. data/test/test_Stl_Set.cpp +790 -0
  155. data/test/{test_Stl_SmartPointer.cpp → test_Stl_SharedPtr.cpp} +97 -127
  156. data/test/test_Stl_Tuple.cpp +116 -0
  157. data/test/test_Stl_Type.cpp +1 -1
  158. data/test/test_Stl_UniquePtr.cpp +202 -0
  159. data/test/test_Stl_Unordered_Map.cpp +28 -34
  160. data/test/test_Stl_Variant.cpp +217 -89
  161. data/test/test_Stl_Vector.cpp +209 -83
  162. data/test/test_To_Ruby.cpp +373 -1
  163. data/test/test_Type.cpp +85 -14
  164. data/test/test_global_functions.cpp +17 -4
  165. metadata +94 -10
  166. data/rice/detail/TupleIterator.hpp +0 -14
data/include/rice/stl.hpp CHANGED
@@ -21,8 +21,7 @@ namespace Rice::stl
21
21
 
22
22
  inline void define_stl_exception()
23
23
  {
24
- Module rb_mRice = define_module("Rice");
25
- Module rb_mStd = define_module_under(rb_mRice, "Std");
24
+ Module rb_mStd = define_module("Std");
26
25
  rb_cStlException = define_class_under<std::exception>(rb_mStd, "Exception", rb_eStandardError).
27
26
  define_constructor(Constructor<std::exception>()).
28
27
  define_method("message", &std::exception::what);
@@ -47,15 +46,13 @@ namespace Rice::detail
47
46
 
48
47
 
49
48
  // --------- exception_ptr.ipp ---------
50
- #include <functional>
49
+ #include <exception>
51
50
 
52
51
  namespace Rice::stl
53
52
  {
54
53
  inline Data_Type<std::exception_ptr> define_exception_ptr()
55
54
  {
56
- Module rb_mRice = define_module("Rice");
57
- Module rb_mStd = define_module_under(rb_mRice, "Std");
58
-
55
+ Module rb_mStd = define_module("Std");
59
56
  return define_class_under<std::exception_ptr>(rb_mStd, "ExceptionPtr");
60
57
  }
61
58
  }
@@ -67,7 +64,7 @@ namespace Rice::detail
67
64
  {
68
65
  static bool verify()
69
66
  {
70
- if (!detail::Registries::instance.types.isDefined<std::exception_ptr>())
67
+ if (!Data_Type<std::exception_ptr>::is_defined())
71
68
  {
72
69
  stl::define_exception_ptr();
73
70
  }
@@ -82,6 +79,8 @@ namespace Rice::detail
82
79
 
83
80
 
84
81
  // --------- string.ipp ---------
82
+ #include <string>
83
+
85
84
  namespace Rice::detail
86
85
  {
87
86
  template<>
@@ -97,7 +96,7 @@ namespace Rice::detail
97
96
  class To_Ruby<std::string>
98
97
  {
99
98
  public:
100
- VALUE convert(std::string const& x)
99
+ VALUE convert(const std::string& x)
101
100
  {
102
101
  return detail::protect(rb_external_str_new, x.data(), (long)x.size());
103
102
  }
@@ -107,53 +106,46 @@ namespace Rice::detail
107
106
  class To_Ruby<std::string&>
108
107
  {
109
108
  public:
110
- VALUE convert(std::string const& x)
109
+ VALUE convert(const std::string& x)
111
110
  {
112
111
  return detail::protect(rb_external_str_new, x.data(), (long)x.size());
113
112
  }
114
113
  };
115
114
 
116
115
  template<>
117
- class From_Ruby<std::string>
116
+ class To_Ruby<std::string*>
118
117
  {
119
118
  public:
120
- From_Ruby() = default;
121
-
122
- explicit From_Ruby(Arg* arg) : arg_(arg)
119
+ VALUE convert(const std::string* x)
123
120
  {
121
+ return detail::protect(rb_external_str_new, x->data(), (long)x->size());
124
122
  }
123
+ };
125
124
 
126
- Convertible is_convertible(VALUE value)
125
+ template<>
126
+ class To_Ruby<std::string*&>
127
+ {
128
+ public:
129
+ VALUE convert(const std::string* x)
127
130
  {
128
- switch (rb_type(value))
129
- {
130
- case RUBY_T_STRING:
131
- return Convertible::Exact;
132
- break;
133
- default:
134
- return Convertible::None;
135
- }
131
+ return detail::protect(rb_external_str_new, x->data(), (long)x->size());
136
132
  }
133
+ };
137
134
 
138
- std::string convert(VALUE value)
135
+ template<>
136
+ class To_Ruby<std::string**>
137
+ {
138
+ public:
139
+ VALUE convert(std::string** data)
139
140
  {
140
- if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
141
- {
142
- return this->arg_->defaultValue<std::string>();
143
- }
144
- else
145
- {
146
- detail::protect(rb_check_type, value, (int)T_STRING);
147
- return std::string(RSTRING_PTR(value), RSTRING_LEN(value));
148
- }
141
+ Buffer<std::string*> buffer(data);
142
+ Data_Object<Buffer<std::string*>> dataObject(std::move(buffer));
143
+ return dataObject.value();
149
144
  }
150
-
151
- private:
152
- Arg* arg_ = nullptr;
153
145
  };
154
146
 
155
147
  template<>
156
- class From_Ruby<std::string&>
148
+ class From_Ruby<std::string>
157
149
  {
158
150
  public:
159
151
  From_Ruby() = default;
@@ -174,29 +166,26 @@ namespace Rice::detail
174
166
  }
175
167
  }
176
168
 
177
- std::string& convert(VALUE value)
169
+ std::string convert(VALUE value)
178
170
  {
179
- if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
180
- {
181
- return this->arg_->defaultValue<std::string>();
182
- }
183
- else
184
- {
185
- detail::protect(rb_check_type, value, (int)T_STRING);
186
- this->converted_ = std::string(RSTRING_PTR(value), RSTRING_LEN(value));
187
- return this->converted_;
188
- }
171
+ detail::protect(rb_check_type, value, (int)T_STRING);
172
+ return std::string(RSTRING_PTR(value), RSTRING_LEN(value));
189
173
  }
190
174
 
191
175
  private:
192
176
  Arg* arg_ = nullptr;
193
- std::string converted_;
194
177
  };
195
178
 
196
179
  template<>
197
- class From_Ruby<std::string*>
180
+ class From_Ruby<std::string&>
198
181
  {
199
182
  public:
183
+ From_Ruby() = default;
184
+
185
+ explicit From_Ruby(Arg* arg) : arg_(arg)
186
+ {
187
+ }
188
+
200
189
  Convertible is_convertible(VALUE value)
201
190
  {
202
191
  switch (rb_type(value))
@@ -209,19 +198,20 @@ namespace Rice::detail
209
198
  }
210
199
  }
211
200
 
212
- std::string* convert(VALUE value)
201
+ std::string& convert(VALUE value)
213
202
  {
214
203
  detail::protect(rb_check_type, value, (int)T_STRING);
215
204
  this->converted_ = std::string(RSTRING_PTR(value), RSTRING_LEN(value));
216
- return &this->converted_;
205
+ return this->converted_;
217
206
  }
218
207
 
219
208
  private:
220
- std::string converted_;
209
+ Arg* arg_ = nullptr;
210
+ std::string converted_ = "";
221
211
  };
222
212
 
223
213
  template<>
224
- class From_Ruby<std::string*&>
214
+ class From_Ruby<std::string*>
225
215
  {
226
216
  public:
227
217
  Convertible is_convertible(VALUE value)
@@ -309,15 +299,8 @@ namespace Rice::detail
309
299
 
310
300
  std::string_view convert(VALUE value)
311
301
  {
312
- if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
313
- {
314
- return this->arg_->defaultValue<std::string_view>();
315
- }
316
- else
317
- {
318
- detail::protect(rb_check_type, value, (int)T_STRING);
319
- return std::string_view(RSTRING_PTR(value), RSTRING_LEN(value));
320
- }
302
+ detail::protect(rb_check_type, value, (int)T_STRING);
303
+ return std::string_view(RSTRING_PTR(value), RSTRING_LEN(value));
321
304
  }
322
305
 
323
306
  private:
@@ -331,7 +314,6 @@ namespace Rice::detail
331
314
  // --------- complex.ipp ---------
332
315
  #include <complex>
333
316
 
334
-
335
317
  namespace Rice::detail
336
318
  {
337
319
  template<typename T>
@@ -356,6 +338,19 @@ namespace Rice::detail
356
338
  }
357
339
  };
358
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
+
359
354
  template<typename T>
360
355
  class From_Ruby<std::complex<T>>
361
356
  {
@@ -433,7 +428,7 @@ namespace Rice::detail
433
428
  class To_Ruby<std::nullopt_t>
434
429
  {
435
430
  public:
436
- VALUE convert(std::nullopt_t& _)
431
+ VALUE convert(const std::nullopt_t& _)
437
432
  {
438
433
  return Qnil;
439
434
  }
@@ -583,822 +578,957 @@ namespace Rice::detail
583
578
  }
584
579
 
585
580
 
586
- // ========= smart_ptr.hpp =========
587
-
581
+ // ========= pair.hpp =========
588
582
 
589
- namespace Rice::detail
583
+ namespace Rice
590
584
  {
591
- template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
592
- class WrapperSmartPointer : public Wrapper
593
- {
594
- public:
595
- WrapperSmartPointer(SmartPointer_T<Arg_Ts...> data);
596
- ~WrapperSmartPointer();
597
- void* get() override;
598
- SmartPointer_T<Arg_Ts...>& data();
599
-
600
- private:
601
- SmartPointer_T<Arg_Ts...> data_;
602
- };
585
+ template<typename T1, typename T2>
586
+ Data_Type<std::pair<T1, T2>> define_pair(std::string klassName = "");
603
587
  }
604
588
 
605
589
 
606
- // --------- smart_ptr.ipp ---------
607
-
608
- #include <assert.h>
609
- #include <memory>
590
+ // --------- pair.ipp ---------
591
+ #include <utility>
610
592
 
611
- namespace Rice::detail
593
+ namespace Rice
612
594
  {
613
- // ---- WrapperSmartPointer ------
614
- template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
615
- inline WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::WrapperSmartPointer(SmartPointer_T<Arg_Ts...> data)
616
- : data_(std::move(data))
617
- {
618
- }
619
-
620
- template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
621
- inline WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::~WrapperSmartPointer()
622
- {
623
- Registries::instance.instances.remove(this->get());
624
- }
625
-
626
- template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
627
- inline void* WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::get()
628
- {
629
- return (void*)this->data_.get();
630
- }
631
-
632
- template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
633
- inline SmartPointer_T<Arg_Ts...>& WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::data()
634
- {
635
- return data_;
636
- }
637
-
638
- // ---- unique_ptr ------
639
- template <typename T>
640
- class To_Ruby<std::unique_ptr<T>>
641
- {
642
- public:
643
- using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
644
-
645
- VALUE convert(std::unique_ptr<T>& data)
646
- {
647
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
648
- return detail::wrap<std::unique_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
649
- }
650
- };
651
-
652
- template <typename T>
653
- class To_Ruby<std::unique_ptr<T>&>
595
+ namespace stl
654
596
  {
655
- public:
656
- using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
657
-
658
- VALUE convert(std::unique_ptr<T>& data)
597
+ template<typename T>
598
+ class PairHelper
659
599
  {
660
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
661
- return detail::wrap<std::unique_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
662
- }
663
- };
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
+ }
664
609
 
665
- template <typename T>
666
- class From_Ruby<std::unique_ptr<T>>
667
- {
668
- public:
669
- using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
610
+ private:
611
+ void define_constructor()
612
+ {
613
+ klass_.define_constructor(Constructor<T, typename T::first_type&, typename T::second_type&>());
614
+ }
670
615
 
671
- Wrapper_T* is_same_smart_ptr(VALUE value)
672
- {
673
- Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
674
- return dynamic_cast<Wrapper_T*>(wrapper);
675
- }
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
+ }
676
634
 
677
- Convertible is_convertible(VALUE value)
678
- {
679
- if (!is_same_smart_ptr(value))
680
- return Convertible::None;
635
+ void define_access_methods()
636
+ {
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
+ });
646
+ }
681
647
 
682
- switch (rb_type(value))
648
+ void define_modify_methods()
683
649
  {
684
- case RUBY_T_DATA:
685
- return Convertible::Exact;
686
- break;
687
- default:
688
- return Convertible::None;
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
+ });
689
675
  }
690
- }
691
676
 
692
- std::unique_ptr<T> convert(VALUE value)
693
- {
694
- Wrapper_T* smartWrapper = is_same_smart_ptr(value);
695
- if (!smartWrapper)
677
+ void define_to_s()
696
678
  {
697
- std::string message = "Invalid smart pointer wrapper";
698
- throw std::runtime_error(message.c_str());
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
+ }
699
695
  }
700
- return std::move(smartWrapper->data());
701
- }
702
- };
703
696
 
704
- template <typename T>
705
- class From_Ruby<std::unique_ptr<T>&>
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)
706
704
  {
707
- public:
708
- using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
705
+ using Pair_T = std::pair<T1, T2>;
706
+ using Data_Type_T = Data_Type<Pair_T>;
709
707
 
710
- Wrapper_T* is_same_smart_ptr(VALUE value)
708
+ if (klassName.empty())
711
709
  {
712
- Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
713
- return dynamic_cast<Wrapper_T*>(wrapper);
710
+ std::string typeName = detail::typeName(typeid(Pair_T));
711
+ klassName = detail::rubyClassName(typeName);
714
712
  }
715
713
 
716
- Convertible is_convertible(VALUE value)
714
+ Module rb_mStd = define_module("Std");
715
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
717
716
  {
718
- if (!is_same_smart_ptr(value))
719
- return Convertible::None;
717
+ return Data_Type_T();
718
+ }
720
719
 
721
- switch (rb_type(value))
722
- {
723
- case RUBY_T_DATA:
724
- return Convertible::Exact;
725
- break;
726
- default:
727
- return Convertible::None;
728
- }
729
- }
730
-
731
- std::unique_ptr<T>& convert(VALUE value)
732
- {
733
- Wrapper_T* smartWrapper = is_same_smart_ptr(value);
734
- if (!smartWrapper)
735
- {
736
- std::string message = "Invalid smart pointer wrapper";
737
- throw std::runtime_error(message.c_str());
738
- }
739
- return smartWrapper->data();
740
- }
741
- };
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
+ }
742
725
 
743
- template<typename T>
744
- struct Type<std::unique_ptr<T>>
726
+ namespace detail
745
727
  {
746
- static bool verify()
728
+ template<typename T1, typename T2>
729
+ struct Type<std::pair<T1, T2>>
747
730
  {
748
- return Type<T>::verify();
749
- }
750
- };
731
+ static bool verify()
732
+ {
733
+ detail::verifyType<T1>();
734
+ detail::verifyType<T2>();
751
735
 
752
- // ----- shared_ptr -------------
753
- template <typename T>
754
- class To_Ruby<std::shared_ptr<T>>
755
- {
756
- public:
757
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
736
+ if (!Data_Type<std::pair<T1, T2>>::is_defined())
737
+ {
738
+ define_pair<T1, T2>();
739
+ }
758
740
 
759
- VALUE convert(std::shared_ptr<T>& data)
760
- {
761
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
762
- return detail::wrap<std::shared_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
763
- }
764
- };
741
+ return true;
742
+ }
743
+ };
744
+ }
745
+ }
765
746
 
766
- template <>
767
- class To_Ruby<std::shared_ptr<void>>
768
- {
769
- public:
770
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, void>;
771
747
 
772
- VALUE convert(std::shared_ptr<void>& data)
773
- {
774
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType(data.get());
775
- return detail::wrap<std::shared_ptr<void>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
776
- }
777
- };
778
748
 
779
- template <typename T>
780
- class From_Ruby<std::shared_ptr<T>>
781
- {
782
- public:
783
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
749
+ // ========= map.hpp =========
784
750
 
785
- From_Ruby() = default;
751
+ namespace Rice
752
+ {
753
+ template<typename K, typename T>
754
+ Data_Type<std::map<K, T>> define_map(std::string name = "");
755
+ }
786
756
 
787
- explicit From_Ruby(Arg * arg) : arg_(arg)
788
- {
789
- }
790
757
 
791
- Wrapper_T* is_same_smart_ptr(VALUE value)
792
- {
793
- Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
794
- return dynamic_cast<Wrapper_T*>(wrapper);
795
- }
758
+ // --------- map.ipp ---------
759
+ #include <map>
796
760
 
797
- Convertible is_convertible(VALUE value)
761
+ namespace Rice
762
+ {
763
+ namespace stl
764
+ {
765
+ template<typename T>
766
+ class MapHelper
798
767
  {
799
- if (!is_same_smart_ptr(value))
800
- return Convertible::None;
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>;
801
775
 
802
- switch (rb_type(value))
776
+ public:
777
+ MapHelper(Data_Type<T> klass) : klass_(klass)
803
778
  {
804
- case RUBY_T_DATA:
805
- return Convertible::Exact;
806
- break;
807
- default:
808
- return Convertible::None;
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();
809
789
  }
810
- }
811
790
 
812
- std::shared_ptr<T> convert(VALUE value)
813
- {
814
- if(value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
815
- return this->arg_->template defaultValue<std::shared_ptr<T>>();
816
- }
791
+ private:
817
792
 
818
- Wrapper_T* smartWrapper = is_same_smart_ptr(value);
819
- if (!smartWrapper)
793
+ void register_pair()
820
794
  {
821
- std::string message = "Invalid smart pointer wrapper";
822
- throw std::runtime_error(message.c_str());
795
+ define_pair<const Key_T, Mapped_T>();
823
796
  }
824
- return smartWrapper->data();
825
- }
826
- private:
827
- Arg* arg_ = nullptr;
828
- };
829
-
830
- template <typename T>
831
- class To_Ruby<std::shared_ptr<T>&>
832
- {
833
- public:
834
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
835
-
836
- VALUE convert(std::shared_ptr<T>& data)
837
- {
838
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
839
- return detail::wrap<std::shared_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
840
- }
841
- };
842
-
843
- template <typename T>
844
- class From_Ruby<std::shared_ptr<T>&>
845
- {
846
- public:
847
- using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
848
-
849
- From_Ruby() = default;
850
-
851
- explicit From_Ruby(Arg * arg) : arg_(arg)
852
- {
853
- }
854
-
855
- Wrapper_T* is_same_smart_ptr(VALUE value)
856
- {
857
- Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
858
- return dynamic_cast<Wrapper_T*>(wrapper);
859
- }
860
-
861
- Convertible is_convertible(VALUE value)
862
- {
863
- if (!is_same_smart_ptr(value))
864
- return Convertible::None;
865
797
 
866
- switch (rb_type(value))
798
+ void define_constructor()
867
799
  {
868
- case RUBY_T_DATA:
869
- return Convertible::Exact;
870
- break;
871
- default:
872
- return Convertible::None;
800
+ klass_.define_constructor(Constructor<T>());
873
801
  }
874
- }
875
802
 
876
- std::shared_ptr<T>& convert(VALUE value)
877
- {
878
- if(value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
879
- return this->arg_->template defaultValue<std::shared_ptr<T>>();
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
+ }
880
820
  }
881
821
 
882
- Wrapper_T* smartWrapper = is_same_smart_ptr(value);
883
- if (!smartWrapper)
822
+ void define_capacity_methods()
884
823
  {
885
- std::string message = "Invalid smart pointer wrapper";
886
- throw std::runtime_error(message.c_str());
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");
887
830
  }
888
- return smartWrapper->data();
889
- }
890
831
 
891
- private:
892
- Arg* arg_ = nullptr;
893
- };
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);
894
838
 
895
- template<typename T>
896
- struct Type<std::shared_ptr<T>>
897
- {
898
- static bool verify()
899
- {
900
- return Type<T>::verify();
901
- }
902
- };
903
- }
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
+ });
904
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
+ });
905
871
 
906
- // ========= monostate.hpp =========
872
+ return result;
873
+ });
907
874
 
875
+ rb_define_alias(klass_, "has_key", "include?");
876
+ }
908
877
 
909
- // --------- monostate.ipp ---------
910
- #include <variant>
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
+ });
911
890
 
912
- namespace Rice::detail
913
- {
914
- template<>
915
- struct Type<std::monostate>
916
- {
917
- constexpr static bool verify()
918
- {
919
- return true;
920
- }
921
- };
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
+ }
922
901
 
923
- template<>
924
- class To_Ruby<std::monostate>
925
- {
926
- public:
927
- VALUE convert(const std::monostate& _)
928
- {
929
- return Qnil;
930
- }
931
- };
902
+ rb_define_alias(klass_, "has_value", "value?");
903
+ }
932
904
 
933
- template<>
934
- class To_Ruby<std::monostate&>
935
- {
936
- public:
937
- static VALUE convert(const std::monostate& data, bool takeOwnership = false)
938
- {
939
- return Qnil;
940
- }
941
- };
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);
942
911
 
943
- template<>
944
- class From_Ruby<std::monostate>
945
- {
946
- public:
947
- Convertible is_convertible(VALUE value)
948
- {
949
- return Convertible::None;
950
- }
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
+ });
951
928
 
952
- std::monostate convert(VALUE value)
953
- {
954
- return std::monostate();
955
- }
956
- };
929
+ rb_define_alias(klass_, "store", "[]=");
930
+ }
957
931
 
958
- template<>
959
- class From_Ruby<std::monostate&>
960
- {
961
- public:
962
- Convertible is_convertible(VALUE value)
963
- {
964
- return Convertible::None;
965
- }
932
+ void define_enumerable()
933
+ {
934
+ // Add enumerable support
935
+ klass_.template define_iterator<typename T::iterator (T::*)()>(&T::begin, &T::end);
936
+ }
966
937
 
967
- std::monostate& convert(VALUE value)
968
- {
969
- return this->converted_;
970
- }
971
-
972
- private:
973
- std::monostate converted_ = std::monostate();
974
- };
975
- }
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
+ });
976
950
 
951
+ return result;
952
+ }, Return().setValue());
953
+ }
977
954
 
978
- // ========= type_index.hpp =========
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();
979
962
 
963
+ std::stringstream stream;
964
+ stream << "{";
980
965
 
981
- // --------- type_index.ipp ---------
982
- #include <typeindex>
966
+ for (; iter != map.end(); iter++)
967
+ {
968
+ if (iter != map.begin())
969
+ {
970
+ stream << ", ";
971
+ }
972
+ stream << iter->first << " => " << iter->second;
973
+ }
983
974
 
984
- namespace Rice::stl
985
- {
986
- inline Data_Type<std::type_index> define_type_index()
987
- {
988
- Module rb_mRice = define_module("Rice");
989
- Module rb_mStd = define_module_under(rb_mRice, "Std");
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
+ }
990
987
 
991
- return define_class_under<std::type_index>(rb_mStd, "TypeIndex").
992
- define_constructor(Constructor<std::type_index, const std::type_info&>()).
993
- define_method("hash_code", &std::type_index::hash_code).
994
- define_method("name", &std::type_index::name);
995
- }
996
- }
988
+ private:
989
+ Data_Type<T> klass_;
990
+ };
991
+ } // namespace
997
992
 
998
- namespace Rice::detail
999
- {
1000
- template<>
1001
- struct Type<std::type_index>
993
+ template<typename Key, typename T>
994
+ Data_Type<std::map<Key, T>> define_map(std::string klassName)
1002
995
  {
1003
- static bool verify()
1004
- {
1005
- if (!detail::Registries::instance.types.isDefined<std::type_index>())
1006
- {
1007
- stl::define_type_index();
1008
- }
996
+ using Map_T = std::map<Key, T>;
997
+ using Data_Type_T = Data_Type<Map_T>;
1009
998
 
1010
- return true;
999
+ if (klassName.empty())
1000
+ {
1001
+ std::string typeName = detail::typeName(typeid(Map_T));
1002
+ klassName = detail::rubyClassName(typeName);
1011
1003
  }
1012
- };
1013
- }
1014
-
1015
-
1016
- // ========= type_info.hpp =========
1017
-
1018
-
1019
- // --------- type_info.ipp ---------
1020
- #include <typeinfo>
1021
1004
 
1022
- namespace Rice::stl
1023
- {
1024
- inline Data_Type<std::type_info> define_type_info()
1025
- {
1026
- Module rb_mRice = define_module("Rice");
1027
- Module rb_mStd = define_module_under(rb_mRice, "Std");
1005
+ Module rb_mStd = define_module("Std");
1006
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
1007
+ {
1008
+ return Data_Type_T();
1009
+ }
1028
1010
 
1029
- return define_class_under<std::type_info>(rb_mStd, "TypeInfo").
1030
- define_method("hash_code", &std::type_info::hash_code).
1031
- define_method("name", &std::type_info::name);
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;
1032
1015
  }
1033
- }
1034
1016
 
1035
- namespace Rice::detail
1036
- {
1037
- template<>
1038
- struct Type<std::type_info>
1017
+ namespace detail
1039
1018
  {
1040
- static inline bool verify()
1019
+ template<typename Key_T, typename T>
1020
+ struct Type<std::map<Key_T, T>>
1041
1021
  {
1042
- if (!detail::Registries::instance.types.isDefined<std::type_info>())
1022
+ static bool verify()
1043
1023
  {
1044
- stl::define_type_info();
1045
- }
1024
+ Type<Key_T>::verify();
1025
+ Type<T>::verify();
1046
1026
 
1047
- return true;
1048
- }
1049
- };
1050
- }
1027
+ if (!Data_Type<std::map<Key_T, T>>::is_defined())
1028
+ {
1029
+ define_map<Key_T, T>();
1030
+ }
1051
1031
 
1032
+ return true;
1033
+ }
1034
+ };
1052
1035
 
1053
- // ========= variant.hpp =========
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);
1054
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
+ }
1055
1051
 
1056
- // --------- variant.ipp ---------
1057
- #include <variant>
1052
+ static std::map<T, U> convert(VALUE value)
1053
+ {
1054
+ std::map<T, U> result;
1055
+ VALUE user_data = (VALUE)(&result);
1058
1056
 
1059
- namespace Rice::detail
1060
- {
1061
- template<typename...Types>
1062
- struct Type<std::variant<Types...>>
1063
- {
1064
- using Tuple_T = std::tuple<Types...>;
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);
1065
1060
 
1066
- template<std::size_t... I>
1067
- constexpr static bool verifyTypes(std::index_sequence<I...>& indices)
1068
- {
1069
- return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
1070
- }
1061
+ return result;
1062
+ }
1063
+ };
1071
1064
 
1072
- template<std::size_t... I>
1073
- constexpr static bool verify()
1065
+ template<typename T, typename U>
1066
+ class From_Ruby<std::map<T, U>>
1074
1067
  {
1075
- auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
1076
- return verifyTypes(indices);
1077
- }
1078
- };
1068
+ public:
1069
+ From_Ruby() = default;
1079
1070
 
1080
- template<typename...Types>
1081
- class To_Ruby<std::variant<Types...>>
1082
- {
1083
- public:
1071
+ explicit From_Ruby(Arg * arg) : arg_(arg)
1072
+ {
1073
+ }
1084
1074
 
1085
- template<typename T>
1086
- static VALUE convertElement(const std::variant<Types...>& data, bool takeOwnership)
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>&>
1087
1121
  {
1088
- return To_Ruby<T>().convert(std::get<T>(data));
1089
- }
1122
+ public:
1123
+ From_Ruby() = default;
1090
1124
 
1091
- template<std::size_t... I>
1092
- static VALUE convertIterator(const std::variant<Types...>& data, bool takeOwnership, std::index_sequence<I...>& indices)
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>*>
1093
1177
  {
1094
- // Create a tuple of the variant types so we can look over the tuple's types
1095
- using Tuple_T = std::tuple<Types...>;
1096
-
1097
- /* This is a fold expression. In pseudo code:
1098
-
1099
- for (type in variant.types)
1178
+ public:
1179
+ Convertible is_convertible(VALUE value)
1180
+ {
1181
+ switch (rb_type(value))
1100
1182
  {
1101
- if (variant.has_value<type>())
1102
- return ToRuby<type>().convert(variant.getValue<type>)
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;
1103
1194
  }
1195
+ }
1104
1196
 
1105
- The list of variant types is stored in Tuple_T. The number of types is stored in I.
1106
- Starting with index 0, get the variant type using td::tuple_element_t<I, Tuple_T>>.
1107
- Next check if the variant has a value for that type using std::holds_alternative<T>.
1108
- If yes, then call convertElement and save the return value to result. Then use the
1109
- comma operator to return true to the fold expression. If the variant does not have
1110
- a value for the type then return false.
1111
-
1112
- The fold operator is or (||). If an index returns false, then the next index is evaluated
1113
- up until I.
1114
-
1115
- Code inspired by https://www.foonathan.net/2020/05/fold-tricks/ */
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
+ }
1116
1222
 
1117
- VALUE result = Qnil;
1223
+ private:
1224
+ std::map<T, U> converted_;
1225
+ };
1226
+ }
1227
+ }
1118
1228
 
1119
- #if defined(__GNUC__) || defined(__clang__)
1120
- #pragma GCC diagnostic push
1121
- #pragma GCC diagnostic ignored "-Wunused-value"
1122
- #endif
1229
+ // ========= monostate.hpp =========
1123
1230
 
1124
- ((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
1125
- (result = convertElement<std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
1126
-
1127
- #if defined(__GNUC__) || defined(__clang__)
1128
- #pragma GCC diagnostic pop
1129
- #endif
1130
1231
 
1131
- return result;
1132
- }
1232
+ // --------- monostate.ipp ---------
1233
+ #include <variant>
1133
1234
 
1134
- static VALUE convert(const std::variant<Types...>& data, bool takeOwnership = false)
1235
+ namespace Rice::detail
1236
+ {
1237
+ template<>
1238
+ struct Type<std::monostate>
1239
+ {
1240
+ constexpr static bool verify()
1135
1241
  {
1136
- auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
1137
- return convertIterator(data, takeOwnership, indices);
1242
+ return true;
1138
1243
  }
1139
1244
  };
1140
1245
 
1141
- template<typename...Types>
1142
- class To_Ruby<std::variant<Types...>&>
1246
+ template<>
1247
+ class To_Ruby<std::monostate>
1143
1248
  {
1144
1249
  public:
1145
- template<typename T>
1146
- static VALUE convertElement(const std::variant<Types...>& data, bool takeOwnership)
1250
+ VALUE convert(const std::monostate& _)
1147
1251
  {
1148
- return To_Ruby<T>().convert(std::get<T>(data));
1252
+ return Qnil;
1149
1253
  }
1254
+ };
1150
1255
 
1151
- template<std::size_t... I>
1152
- static VALUE convertIterator(const std::variant<Types...>& data, bool takeOwnership, std::index_sequence<I...>& indices)
1256
+ template<>
1257
+ class To_Ruby<std::monostate&>
1258
+ {
1259
+ public:
1260
+ static VALUE convert(const std::monostate& data, bool takeOwnership = false)
1153
1261
  {
1154
- // Create a tuple of the variant types so we can look over the tuple's types
1155
- using Tuple_T = std::tuple<Types...>;
1156
-
1157
- // See comments above for explanation of this code
1158
- VALUE result = Qnil;
1159
-
1160
- #if defined(__GNUC__) || defined(__clang__)
1161
- #pragma GCC diagnostic push
1162
- #pragma GCC diagnostic ignored "-Wunused-value"
1163
- #endif
1164
-
1165
- ((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
1166
- (result = convertElement<std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
1167
-
1168
- #if defined(__GNUC__) || defined(__clang__)
1169
- #pragma GCC diagnostic pop
1170
- #endif
1262
+ return Qnil;
1263
+ }
1264
+ };
1171
1265
 
1172
- return result;
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;
1173
1273
  }
1174
1274
 
1175
- static VALUE convert(const std::variant<Types...>& data, bool takeOwnership = false)
1275
+ std::monostate convert(VALUE value)
1176
1276
  {
1177
- auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
1178
- return convertIterator(data, takeOwnership, indices);
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
+ }
1179
1285
  }
1180
1286
  };
1181
1287
 
1182
- template<typename...Types>
1183
- class From_Ruby<std::variant<Types...>>
1288
+ template<>
1289
+ class From_Ruby<std::monostate&>
1184
1290
  {
1185
1291
  public:
1186
1292
  Convertible is_convertible(VALUE value)
1187
1293
  {
1188
- Convertible result = Convertible::None;
1189
-
1190
- for_each_tuple(this->fromRubys_,
1191
- [&](auto& fromRuby)
1192
- {
1193
- result = result | fromRuby.is_convertible(value);
1194
- });
1195
-
1196
- return result;
1294
+ return value == Qnil ? Convertible::Exact : Convertible::None;
1197
1295
  }
1198
1296
 
1199
- // This method search through a variant's types to figure out which one the
1200
- // currently Ruby value best matches. It then returns the index of the type.
1201
- int figureIndex(VALUE value)
1297
+ std::monostate& convert(VALUE value)
1202
1298
  {
1203
- int i = 0;
1204
- int index = -1;
1205
- Convertible foundConversion = Convertible::None;
1206
-
1207
- for_each_tuple(this->fromRubys_,
1208
- [&](auto& fromRuby)
1209
- {
1210
- Convertible isConvertible = fromRuby.is_convertible(value);
1211
-
1212
- if (isConvertible > foundConversion)
1213
- {
1214
- index = i;
1215
- foundConversion = isConvertible;
1216
- }
1217
- i++;
1218
- });
1219
-
1220
- if (index == -1)
1299
+ if (value == Qnil)
1221
1300
  {
1222
- rb_raise(rb_eArgError, "Could not find converter for variant");
1301
+ return this->converted_;
1223
1302
  }
1224
-
1225
- return index;
1226
- }
1227
-
1228
- /* This method loops over each type in the variant, creates a From_Ruby converter,
1229
- and then check if the converter can work with the provided Rby value (it checks
1230
- the type of the Ruby object to see if it matches the variant type).
1231
- If yes, then the converter runs. If no, then the method recursively calls itself
1232
- increasing the index.
1233
-
1234
- We use recursion, with a constexpr, to avoid having to instantiate an instance
1235
- of the variant to store results from a fold expression like the To_Ruby code
1236
- does above. That allows us to process variants with non default constructible
1237
- arguments like std::reference_wrapper. */
1238
- template <std::size_t I = 0>
1239
- std::variant<Types...> convertInternal(VALUE value, int index)
1240
- {
1241
- if constexpr (I < std::variant_size_v<std::variant<Types...>>)
1303
+ else
1242
1304
  {
1243
- if (I == index)
1244
- {
1245
- auto fromRuby = std::get<I>(this->fromRubys_);
1246
- return fromRuby.convert(value);
1247
- }
1248
- else
1249
- {
1250
- return convertInternal<I + 1>(value, index);
1251
- }
1305
+ throw std::runtime_error("Can only convert nil values to std::monostate");
1252
1306
  }
1253
- rb_raise(rb_eArgError, "Could not find converter for variant");
1254
- }
1255
-
1256
- std::variant<Types...> convert(VALUE value)
1257
- {
1258
- int index = this->figureIndex(value);
1259
- return this->convertInternal(value, index);
1260
- }
1261
-
1262
- private:
1263
- // Possible converters we could use for this variant
1264
- using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
1265
- From_Ruby_Ts fromRubys_;
1266
- };
1267
-
1268
- template<typename...Types>
1269
- class From_Ruby<std::variant<Types...>&> : public From_Ruby<std::variant<Types...>>
1270
- {
1271
- public:
1272
- std::variant<Types...>& convert(VALUE value)
1273
- {
1274
- int index = this->figureIndex(value);
1275
- this->converted_ = this->convertInternal(value, index);
1276
- return this->converted_;
1277
1307
  }
1278
-
1308
+
1279
1309
  private:
1280
- std::variant<Types...> converted_;
1310
+ std::monostate converted_ = std::monostate();
1281
1311
  };
1282
1312
  }
1283
1313
 
1284
1314
 
1285
- // ========= pair.hpp =========
1315
+ // ========= multimap.hpp =========
1286
1316
 
1317
+ #include <map>
1287
1318
 
1288
1319
  namespace Rice
1289
1320
  {
1290
- template<typename T>
1291
- Data_Type<T> define_pair(std::string name);
1292
-
1293
- template<typename T>
1294
- Data_Type<T> define_pair_under(Object parent, std::string name);
1321
+ template<typename K, typename T>
1322
+ Data_Type<std::multimap<K, T>> define_multimap(std::string name = "");
1295
1323
  }
1296
1324
 
1297
1325
 
1298
- // --------- pair.ipp ---------
1299
-
1300
- #include <sstream>
1301
- #include <stdexcept>
1302
- #include <utility>
1326
+ // --------- multimap.ipp ---------
1327
+ #include <map>
1303
1328
 
1304
1329
  namespace Rice
1305
1330
  {
1306
1331
  namespace stl
1307
1332
  {
1308
1333
  template<typename T>
1309
- class PairHelper
1334
+ class MultimapHelper
1310
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
+
1311
1344
  public:
1312
- PairHelper(Data_Type<T> klass) : klass_(klass)
1345
+ MultimapHelper(Data_Type<T> klass) : klass_(klass)
1313
1346
  {
1347
+ this->register_pair();
1314
1348
  this->define_constructor();
1315
1349
  this->define_copyable_methods();
1350
+ this->define_capacity_methods();
1316
1351
  this->define_access_methods();
1352
+ this->define_comparable_methods();
1317
1353
  this->define_modify_methods();
1354
+ this->define_enumerable();
1318
1355
  this->define_to_s();
1319
1356
  }
1320
1357
 
1321
1358
  private:
1359
+
1360
+ void register_pair()
1361
+ {
1362
+ define_pair<const Key_T, Mapped_T>();
1363
+ }
1364
+
1322
1365
  void define_constructor()
1323
1366
  {
1324
- klass_.define_constructor(Constructor<T, typename T::first_type&, typename T::second_type&>());
1367
+ klass_.define_constructor(Constructor<T>());
1325
1368
  }
1326
1369
 
1327
1370
  void define_copyable_methods()
1328
1371
  {
1329
- if constexpr (std::is_copy_constructible_v<typename T::first_type> && std::is_copy_constructible_v<typename T::second_type>)
1372
+ if constexpr (std::is_copy_constructible_v<Value_T>)
1330
1373
  {
1331
- klass_.define_method("copy", [](T& pair) -> T
1374
+ klass_.define_method("copy", [](T& multimap) -> T
1332
1375
  {
1333
- return pair;
1376
+ return multimap;
1334
1377
  });
1335
1378
  }
1336
1379
  else
1337
1380
  {
1338
- klass_.define_method("copy", [](T& pair) -> T
1381
+ klass_.define_method("copy", [](T& multimap) -> T
1339
1382
  {
1340
- throw std::runtime_error("Cannot copy pair with non-copy constructible types");
1341
- return pair;
1383
+ throw std::runtime_error("Cannot copy multimaps with non-copy constructible types");
1384
+ return multimap;
1342
1385
  });
1343
1386
  }
1344
1387
  }
1345
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
+
1346
1399
  void define_access_methods()
1347
1400
  {
1348
1401
  // Access methods
1349
- klass_.define_method("first", [](T& pair) -> typename T::first_type&
1402
+ klass_.
1403
+ define_method("[]", [](const T& multimap, const Key_T& key) -> Array
1350
1404
  {
1351
- return pair.first;
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;
1352
1414
  })
1353
- .define_method("second", [](T& pair) -> typename T::second_type&
1415
+ .define_method("include?", [](T& multimap, Key_T& key) -> bool
1354
1416
  {
1355
- return pair.second;
1356
- });
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?");
1357
1443
  }
1358
1444
 
1359
- void define_modify_methods()
1445
+ // Methods that require Value_T to support operator==
1446
+ void define_comparable_methods()
1360
1447
  {
1361
- // Access methods
1362
- klass_.define_method("first=", [](T& pair, typename T::first_type& value) -> typename T::first_type&
1448
+ if constexpr (detail::is_comparable_v<Mapped_T>)
1363
1449
  {
1364
- if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::first_type>>>)
1365
- {
1366
- throw std::runtime_error("Cannot set pair.first since it is a constant");
1367
- }
1368
- else
1369
- {
1370
- pair.first = value;
1371
- return pair.first;
1372
- }
1373
- })
1374
- .define_method("second=", [](T& pair, typename T::second_type& value) -> typename T::second_type&
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
1375
1462
  {
1376
- if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::second_type>>>)
1463
+ klass_.define_method("value?", [](T& multimap, Mapped_T& value) -> bool
1377
1464
  {
1378
- throw std::runtime_error("Cannot set pair.second since it is a constant");
1379
- }
1380
- else
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>
1381
1476
  {
1382
- pair.second = value;
1383
- return pair.second;
1384
- }
1385
- });
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);
1386
1502
  }
1387
1503
 
1388
1504
  void define_to_s()
1389
1505
  {
1390
- if constexpr (detail::is_ostreamable_v<typename T::first_type> && detail::is_ostreamable_v<typename T::second_type>)
1506
+ if constexpr (detail::is_ostreamable_v<Key_T> && detail::is_ostreamable_v<Mapped_T>)
1391
1507
  {
1392
- klass_.define_method("to_s", [](const T& pair)
1508
+ klass_.define_method("to_s", [](const T& multimap)
1393
1509
  {
1510
+ auto iter = multimap.begin();
1511
+
1394
1512
  std::stringstream stream;
1395
- stream << "[" << pair.first << ", " << pair.second << "]";
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 << "}>";
1396
1526
  return stream.str();
1397
1527
  });
1398
1528
  }
1399
1529
  else
1400
1530
  {
1401
- klass_.define_method("to_s", [](const T& pair)
1531
+ klass_.define_method("to_s", [](const T& multimap)
1402
1532
  {
1403
1533
  return "[Not printable]";
1404
1534
  });
@@ -1410,151 +1540,290 @@ namespace Rice
1410
1540
  };
1411
1541
  } // namespace
1412
1542
 
1413
- template<typename T>
1414
- Data_Type<T> define_pair_under(Object parent, std::string name)
1543
+ template<typename Key, typename T>
1544
+ Data_Type<std::multimap<Key, T>> define_multimap(std::string klassName)
1415
1545
  {
1416
- if (detail::Registries::instance.types.isDefined<T>())
1546
+ using MultiMap_T = std::multimap<Key, T>;
1547
+ using Data_Type_T = Data_Type<MultiMap_T>;
1548
+
1549
+ if (klassName.empty())
1417
1550
  {
1418
- // If the pair has been previously seen it will be registered but may
1419
- // not be associated with the constant Module::<name>
1420
- parent.const_set_maybe(name, Data_Type<T>().klass());
1421
- return Data_Type<T>();
1551
+ std::string typeName = detail::typeName(typeid(MultiMap_T));
1552
+ klassName = detail::rubyClassName(typeName);
1422
1553
  }
1423
1554
 
1424
- Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(parent, name.c_str());
1425
- stl::PairHelper helper(result);
1426
- return result;
1427
- }
1428
-
1429
- template<typename T>
1430
- Data_Type<T> define_pair(std::string name)
1431
- {
1432
- if (detail::Registries::instance.types.isDefined<T>())
1555
+ Module rb_mStd = define_module("Std");
1556
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
1433
1557
  {
1434
- // If the pair has been previously seen it will be registered but may
1435
- // not be associated with the constant Object::<name>
1436
- Object(rb_cObject).const_set_maybe(name, Data_Type<T>().klass());
1437
- return Data_Type<T>();
1558
+ return Data_Type_T();
1438
1559
  }
1439
1560
 
1440
- Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
1441
- stl::PairHelper<T> helper(result);
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);
1442
1564
  return result;
1443
1565
  }
1444
1566
 
1445
- template<typename T>
1446
- Data_Type<T> define_pair_auto()
1447
- {
1448
- std::string name = detail::typeName(typeid(T));
1449
- std::string klassName = detail::makeClassName(name);
1450
- Module rb_mRice = define_module("Rice");
1451
- Module rb_mStd = define_module_under(rb_mRice, "Std");
1452
- return define_pair_under<T>(rb_mStd, klassName);
1453
- }
1454
-
1455
1567
  namespace detail
1456
1568
  {
1457
- template<typename T1, typename T2>
1458
- struct Type<std::pair<T1, T2>>
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)
1459
1572
  {
1460
- static bool verify()
1573
+ using Function_T = void(*)(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE);
1574
+
1575
+ auto block = [](VALUE key, VALUE value, VALUE user_data) -> int
1461
1576
  {
1462
- detail::verifyType<T1>();
1463
- detail::verifyType<T2>();
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;
1464
1580
 
1465
- if (!detail::Registries::instance.types.isDefined<std::pair<T1, T2>>())
1581
+ return cpp_protect([&]
1466
1582
  {
1467
- define_pair_auto<std::pair<T1, T2>>();
1468
- }
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
+ };
1469
1589
 
1470
- return true;
1471
- }
1472
- };
1473
- }
1474
- }
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();
1475
1602
 
1603
+ if (!Data_Type<std::multimap<Key_T, T>>::is_defined())
1604
+ {
1605
+ define_multimap<Key_T, T>();
1606
+ }
1476
1607
 
1608
+ return true;
1609
+ }
1610
+ };
1477
1611
 
1478
- // ========= map.hpp =========
1612
+ template<typename T, typename U>
1613
+ class From_Ruby<std::multimap<T, U>>
1614
+ {
1615
+ public:
1616
+ From_Ruby() = default;
1479
1617
 
1618
+ explicit From_Ruby(Arg * arg) : arg_(arg)
1619
+ {
1620
+ }
1480
1621
 
1481
- namespace Rice
1482
- {
1483
- template<typename U>
1484
- Data_Type<U> define_map(std::string name);
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
+ }
1485
1769
 
1486
- template<typename U>
1487
- Data_Type<U> define_map_under(Object module, std::string name);
1770
+ private:
1771
+ std::multimap<T, U> converted_;
1772
+ };
1773
+ }
1488
1774
  }
1489
1775
 
1776
+ // ========= set.hpp =========
1490
1777
 
1491
- // --------- map.ipp ---------
1778
+ namespace Rice
1779
+ {
1780
+ template<typename T>
1781
+ Data_Type<std::set<T>> define_set(std::string klassName = "");
1782
+ }
1492
1783
 
1493
- #include <sstream>
1494
- #include <stdexcept>
1495
- #include <map>
1496
- #include <type_traits>
1497
- #include <variant>
1784
+
1785
+ // --------- set.ipp ---------
1786
+ #include <set>
1498
1787
 
1499
1788
  namespace Rice
1500
1789
  {
1501
1790
  namespace stl
1502
1791
  {
1503
1792
  template<typename T>
1504
- class MapHelper
1793
+ class SetHelper
1505
1794
  {
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.
1506
1798
  using Key_T = typename T::key_type;
1507
- using Mapped_T = typename T::mapped_type;
1508
1799
  using Value_T = typename T::value_type;
1509
- using Reference_T = typename T::reference;
1510
1800
  using Size_T = typename T::size_type;
1511
1801
  using Difference_T = typename T::difference_type;
1512
- using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
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>;
1513
1807
 
1514
1808
  public:
1515
- MapHelper(Data_Type<T> klass) : klass_(klass)
1809
+ SetHelper(Data_Type<T> klass) : klass_(klass)
1516
1810
  {
1517
- this->register_pair();
1518
- this->define_constructor();
1519
- this->define_copyable_methods();
1811
+ this->define_constructors();
1520
1812
  this->define_capacity_methods();
1521
- this->define_access_methods();
1522
1813
  this->define_comparable_methods();
1523
1814
  this->define_modify_methods();
1815
+ this->define_operators();
1524
1816
  this->define_enumerable();
1817
+ this->define_to_array();
1525
1818
  this->define_to_s();
1526
- this->define_to_hash();
1527
1819
  }
1528
1820
 
1529
1821
  private:
1530
1822
 
1531
- void register_pair()
1532
- {
1533
- define_pair_auto<Value_T>();
1534
- }
1535
-
1536
- void define_constructor()
1537
- {
1538
- klass_.define_constructor(Constructor<T>());
1539
- }
1540
-
1541
- void define_copyable_methods()
1823
+ void define_constructors()
1542
1824
  {
1543
- if constexpr (std::is_copy_constructible_v<Value_T>)
1544
- {
1545
- klass_.define_method("copy", [](T& map) -> T
1546
- {
1547
- return map;
1548
- });
1549
- }
1550
- else
1551
- {
1552
- klass_.define_method("copy", [](T& map) -> T
1553
- {
1554
- throw std::runtime_error("Cannot copy maps with non-copy constructible types");
1555
- return map;
1556
- });
1557
- }
1825
+ klass_.define_constructor(Constructor<T>())
1826
+ .define_constructor(Constructor<T, const T&>());
1558
1827
  }
1559
1828
 
1560
1829
  void define_capacity_methods()
@@ -1567,455 +1836,1327 @@ namespace Rice
1567
1836
  rb_define_alias(klass_, "length", "size");
1568
1837
  }
1569
1838
 
1570
- void define_access_methods()
1839
+ void define_comparable_methods()
1571
1840
  {
1572
- // Access methods
1573
- klass_.define_method("[]", [](const T& map, const Key_T& key) -> std::optional<Mapped_T>
1841
+ klass_
1842
+ .define_method("include?", [](T& self, const Key_T element) -> bool
1574
1843
  {
1575
- auto iter = map.find(key);
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
+ }
1576
1852
 
1577
- if (iter != map.end())
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>)
1578
1887
  {
1579
- return iter->second;
1888
+ return self == other;
1580
1889
  }
1581
1890
  else
1582
1891
  {
1583
- return std::nullopt;
1892
+ return false;
1584
1893
  }
1585
1894
  })
1586
- .define_method("include?", [](T& map, Key_T& key) -> bool
1895
+ .define_method("&", [](const T& self, const T& other) -> T
1587
1896
  {
1588
- return map.find(key) != map.end();
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;
1589
1903
  })
1590
- .define_method("keys", [](T& map) -> std::vector<Key_T>
1591
- {
1592
- std::vector<Key_T> result;
1593
- std::transform(map.begin(), map.end(), std::back_inserter(result),
1594
- [](const auto& pair)
1595
- {
1596
- return pair.first;
1597
- });
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()));
1598
1910
 
1599
- return result;
1600
- })
1601
- .define_method("values", [](T& map) -> std::vector<Mapped_T>
1602
- {
1603
- std::vector<Mapped_T> result;
1604
- std::transform(map.begin(), map.end(), std::back_inserter(result),
1605
- [](const auto& pair)
1606
- {
1607
- return pair.second;
1608
- });
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()));
1609
1919
 
1610
- return result;
1611
- });
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()));
1612
1928
 
1613
- rb_define_alias(klass_, "has_key", "include?");
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?", ">");
1614
1950
  }
1615
1951
 
1616
- // Methods that require Value_T to support operator==
1617
- void define_comparable_methods()
1952
+ void define_enumerable()
1618
1953
  {
1619
- if constexpr (detail::is_comparable_v<Mapped_T>)
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
1620
1962
  {
1621
- klass_.define_method("value?", [](T& map, Mapped_T& value) -> bool
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++)
1622
1987
  {
1623
- auto it = std::find_if(map.begin(), map.end(),
1624
- [&value](auto& pair)
1625
- {
1626
- return pair.second == value;
1627
- });
1988
+ if (iter == self.begin())
1989
+ {
1990
+ stream << *iter;
1991
+ }
1992
+ else
1993
+ {
1994
+ stream << ", " << *iter;
1995
+ }
1996
+ }
1628
1997
 
1629
- return it != map.end();
1998
+ stream << "}>";
1999
+ return stream.str();
1630
2000
  });
1631
2001
  }
1632
2002
  else
1633
2003
  {
1634
- klass_.define_method("value?", [](T& map, Mapped_T& value) -> bool
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)
2018
+ {
2019
+ using Set_T = std::set<T>;
2020
+ using Data_Type_T = Data_Type<Set_T>;
2021
+
2022
+ if (klassName.empty())
2023
+ {
2024
+ std::string typeName = detail::typeName(typeid(Set_T));
2025
+ klassName = detail::rubyClassName(typeName);
2026
+ }
2027
+
2028
+ Module rb_mStd = define_module("Std");
2029
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
2030
+ {
2031
+ return Data_Type_T();
2032
+ }
2033
+
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
2041
+ {
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:
1635
2102
  {
1636
- return false;
1637
- });
2103
+ Object object(value);
2104
+ if (object.class_name().str() == setName)
2105
+ {
2106
+ return Convertible::Cast;
2107
+ }
2108
+ }
2109
+ default:
2110
+ return Convertible::None;
1638
2111
  }
2112
+ }
1639
2113
 
1640
- rb_define_alias(klass_, "has_value", "value?");
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
+ }
1641
2139
  }
1642
2140
 
1643
- void define_modify_methods()
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)
1644
2155
  {
1645
- klass_.define_method("clear", &T::clear)
1646
- .define_method("delete", [](T& map, Key_T& key) -> std::optional<Mapped_T>
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)
1647
2169
  {
1648
- auto iter = map.find(key);
2170
+ return Convertible::Cast;
2171
+ }
2172
+ }
2173
+ default:
2174
+ return Convertible::None;
2175
+ }
2176
+ }
1649
2177
 
1650
- if (iter != map.end())
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>)
1651
2194
  {
1652
- Mapped_T result = iter->second;
1653
- map.erase(iter);
1654
- return result;
2195
+ this->converted_ = toSet<T>(value);
2196
+ return this->converted_;
1655
2197
  }
1656
- else
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
+ }
2209
+
2210
+ private:
2211
+ Arg* arg_ = nullptr;
2212
+ std::set<T> converted_;
2213
+ };
2214
+
2215
+ template<typename T>
2216
+ class From_Ruby<std::set<T>*>
2217
+ {
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
+ }
2242
+ }
2243
+
2244
+ std::set<T>* convert(VALUE value)
2245
+ {
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>)
1657
2260
  {
1658
- return std::nullopt;
2261
+ this->converted_ = toSet<T>(value);
2262
+ return &this->converted_;
1659
2263
  }
1660
- })
1661
- .define_method("[]=", [](T& map, Key_T key, Mapped_T& value) -> Mapped_T
1662
- {
1663
- map[key] = value;
1664
- return value;
1665
- });
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
+ }
2274
+ }
2275
+
2276
+ private:
2277
+ std::set<T> converted_;
2278
+ };
2279
+ }
2280
+ }
2281
+
2282
+
2283
+ // ========= shared_ptr.hpp =========
2284
+
2285
+ namespace Rice::detail
2286
+ {
2287
+ template<typename T>
2288
+ class Wrapper<std::shared_ptr<T>> : public WrapperBase
2289
+ {
2290
+ public:
2291
+ Wrapper(const std::shared_ptr<T>& data);
2292
+ ~Wrapper();
2293
+ void* get() override;
2294
+ std::shared_ptr<T>& data();
2295
+
2296
+ private:
2297
+ std::shared_ptr<T> data_;
2298
+ };
2299
+ }
2300
+
2301
+ namespace Rice
2302
+ {
2303
+ template<typename T>
2304
+ Data_Type<std::shared_ptr<T>> define_shared_ptr(std::string klassName = "");
2305
+ }
2306
+
2307
+
2308
+ // --------- shared_ptr.ipp ---------
2309
+ #include <memory>
2310
+
2311
+ // --------- Enable creation of std::shared_ptr from Ruby ---------
2312
+ namespace Rice
2313
+ {
2314
+ template<typename T>
2315
+ Data_Type<std::shared_ptr<T>> define_shared_ptr(std::string klassName)
2316
+ {
2317
+ using SharedPtr_T = std::shared_ptr<T>;
2318
+ using Data_Type_T = Data_Type<SharedPtr_T>;
2319
+
2320
+ if (klassName.empty())
2321
+ {
2322
+ std::string typeName = detail::typeName(typeid(SharedPtr_T));
2323
+ klassName = detail::rubyClassName(typeName);
2324
+ }
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
+ }
2331
+
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());
2335
+
2336
+ return result;
2337
+ }
2338
+ }
2339
+
2340
+ // --------- Wrapper ---------
2341
+ namespace Rice::detail
2342
+ {
2343
+ template<typename T>
2344
+ inline Wrapper<std::shared_ptr<T>>::Wrapper(const std::shared_ptr<T>& data)
2345
+ : data_(data)
2346
+ {
2347
+ }
2348
+
2349
+ template<typename T>
2350
+ inline Wrapper<std::shared_ptr<T>>::~Wrapper()
2351
+ {
2352
+ Registries::instance.instances.remove(this->get());
2353
+ }
2354
+
2355
+ template<typename T>
2356
+ inline void* Wrapper<std::shared_ptr<T>>::get()
2357
+ {
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()
2375
+ {
2376
+ return Type<T>::verify();
2377
+ }
2378
+ };
2379
+
2380
+ template <typename T>
2381
+ class To_Ruby<std::shared_ptr<T>>
2382
+ {
2383
+ public:
2384
+ VALUE convert(std::shared_ptr<T>& data)
2385
+ {
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
+ }
2394
+ }
2395
+
2396
+ VALUE convert(std::shared_ptr<T>&& data)
2397
+ {
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
+ }
2406
+ }
2407
+ };
2408
+
2409
+ template <typename T>
2410
+ class From_Ruby<std::shared_ptr<T>>
2411
+ {
2412
+ public:
2413
+ From_Ruby() = default;
2414
+
2415
+ explicit From_Ruby(Arg * arg) : arg_(arg)
2416
+ {
2417
+ }
2418
+
2419
+ Convertible is_convertible(VALUE value)
2420
+ {
2421
+ switch (rb_type(value))
2422
+ {
2423
+ case RUBY_T_DATA:
2424
+ return Convertible::Exact;
2425
+ break;
2426
+ default:
2427
+ return Convertible::None;
2428
+ }
2429
+ }
2430
+
2431
+ std::shared_ptr<T> convert(VALUE value)
2432
+ {
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
+ }
2457
+ }
2458
+ private:
2459
+ Arg* arg_ = nullptr;
2460
+ };
2461
+
2462
+ template <typename T>
2463
+ class To_Ruby<std::shared_ptr<T>&>
2464
+ {
2465
+ public:
2466
+ VALUE convert(std::shared_ptr<T>& data)
2467
+ {
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
+ }
2476
+ }
2477
+ };
2478
+
2479
+ template <typename T>
2480
+ class From_Ruby<std::shared_ptr<T>&>
2481
+ {
2482
+ public:
2483
+ From_Ruby() = default;
2484
+
2485
+ explicit From_Ruby(Arg * arg) : arg_(arg)
2486
+ {
2487
+ }
2488
+
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
+ }
2499
+ }
2500
+
2501
+ std::shared_ptr<T>& convert(VALUE value)
2502
+ {
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
+ }
2527
+ }
2528
+
2529
+ private:
2530
+ Arg* arg_ = nullptr;
2531
+ };
2532
+ }
2533
+
2534
+
2535
+ // ========= tuple.hpp =========
2536
+
2537
+
2538
+ // --------- tuple.ipp ---------
2539
+ #include <tuple>
2540
+
2541
+ namespace Rice::detail
2542
+ {
2543
+ template<typename...Types>
2544
+ struct Type<std::tuple<Types...>>
2545
+ {
2546
+ using Tuple_T = std::tuple<Types...>;
2547
+
2548
+ template<std::size_t... I>
2549
+ constexpr static bool verifyTypes(std::index_sequence<I...>& indices)
2550
+ {
2551
+ return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
2552
+ }
2553
+
2554
+ template<std::size_t... I>
2555
+ constexpr static bool verify()
2556
+ {
2557
+ auto indices = std::make_index_sequence<std::tuple_size_v<std::tuple<Types...>>>{};
2558
+ return verifyTypes(indices);
2559
+ }
2560
+ };
2561
+
2562
+ template<typename...Types>
2563
+ class To_Ruby<std::tuple<Types...>>
2564
+ {
2565
+ public:
2566
+ static VALUE convert(const std::tuple<Types...>& data, bool takeOwnership = false)
2567
+ {
2568
+ Array result;
2569
+
2570
+ for_each_tuple(data, [&](auto element)
2571
+ {
2572
+ using Element_T = decltype(element);
2573
+ result.push<Element_T>((Element_T)element);
2574
+ });
2575
+
2576
+ return result.value();
2577
+ }
2578
+ };
2579
+
2580
+ template<typename...Types>
2581
+ class To_Ruby<std::tuple<Types...>&>
2582
+ {
2583
+ public:
2584
+ static VALUE convert(const std::tuple<Types...>& data, bool takeOwnership = false)
2585
+ {
2586
+ Array result;
2587
+
2588
+ for_each_tuple(data, [&](auto& value)
2589
+ {
2590
+ VALUE element = detail::To_Ruby<decltype(value)>().convert(value);
2591
+ result.push(element);
2592
+ });
2593
+
2594
+ return result.value();
2595
+ }
2596
+ };
2597
+
2598
+ template<typename...Types>
2599
+ class From_Ruby<std::tuple<Types...>>
2600
+ {
2601
+ public:
2602
+ using Tuple_T = std::tuple<Types...>;
2603
+
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
+ }
2609
+
2610
+ Convertible is_convertible(VALUE value)
2611
+ {
2612
+ Convertible result = Convertible::None;
2613
+
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>)
2616
+ {
2617
+ return result;
2618
+ }
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)
2625
+ {
2626
+ result = result | fromRuby.is_convertible(array[i].value());
2627
+ i++;
2628
+ });
2629
+
2630
+ return result;
2631
+ }
2632
+
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
+ }
2638
+
2639
+ std::tuple<Types...> convert(VALUE value)
2640
+ {
2641
+ Array array(value);
2642
+ auto indices = std::make_index_sequence<std::tuple_size_v<Tuple_T>>{};
2643
+ return convertInternal(array, indices);
2644
+ }
2645
+
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
+ };
2651
+
2652
+ /* template<typename...Types>
2653
+ class From_Ruby<std::tuple<Types...>&> : public From_Ruby<std::tuple<Types...>>
2654
+ {
2655
+ public:
2656
+ std::tuple<Types...>& convert(VALUE value)
2657
+ {
2658
+ int index = this->figureIndex(value);
2659
+ this->converted_ = this->convertInternal(value, index);
2660
+ return this->converted_;
2661
+ }
2662
+
2663
+ private:
2664
+ std::tuple<Types...> converted_;
2665
+ };*/
2666
+ }
2667
+
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()
2678
+ {
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);
2684
+ }
2685
+ }
2686
+
2687
+ namespace Rice::detail
2688
+ {
2689
+ template<>
2690
+ struct Type<std::type_index>
2691
+ {
2692
+ static bool verify()
2693
+ {
2694
+ if (!detail::Registries::instance.types.isDefined<std::type_index>())
2695
+ {
2696
+ stl::define_type_index();
2697
+ }
2698
+
2699
+ return true;
2700
+ }
2701
+ };
2702
+ }
2703
+
2704
+
2705
+ // ========= type_info.hpp =========
2706
+
2707
+
2708
+ // --------- type_info.ipp ---------
2709
+ #include <typeinfo>
2710
+
2711
+ namespace Rice::stl
2712
+ {
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
+ }
2733
+
2734
+ return true;
2735
+ }
2736
+ };
2737
+ }
2738
+
2739
+
2740
+ // ========= variant.hpp =========
2741
+
2742
+
2743
+ // --------- variant.ipp ---------
2744
+ #include <variant>
2745
+
2746
+ namespace Rice::detail
2747
+ {
2748
+ template<typename...Types>
2749
+ struct Type<std::variant<Types...>>
2750
+ {
2751
+ using Tuple_T = std::tuple<Types...>;
2752
+
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
+ }
2758
+
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
+ };
2766
+
2767
+ template<typename...Types>
2768
+ class To_Ruby<std::variant<Types...>>
2769
+ {
2770
+ public:
2771
+
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
+ }
2777
+
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)
2787
+ {
2788
+ if (variant.has_value<type>())
2789
+ return ToRuby<type>().convert(variant.getValue<type>)
2790
+ }
2791
+
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.
2798
+
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/ */
2803
+
2804
+ VALUE result = Qnil;
2805
+
2806
+ #if defined(__GNUC__) || defined(__clang__)
2807
+ #pragma GCC diagnostic push
2808
+ #pragma GCC diagnostic ignored "-Wunused-value"
2809
+ #endif
2810
+
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
2817
+
2818
+ return result;
2819
+ }
2820
+
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
+ }
2827
+
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>)
2844
+ {
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
+ }
2852
+
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...>;
2858
+
2859
+ // See comments above for explanation of this code
2860
+ VALUE result = Qnil;
2861
+
2862
+ #if defined(__GNUC__) || defined(__clang__)
2863
+ #pragma GCC diagnostic push
2864
+ #pragma GCC diagnostic ignored "-Wunused-value"
2865
+ #endif
2866
+
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
+ };
2884
+
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;
2892
+
2893
+ for_each_tuple(this->fromRubys_,
2894
+ [&](auto& fromRuby)
2895
+ {
2896
+ result = result | fromRuby.is_convertible(value);
2897
+ });
1666
2898
 
1667
- rb_define_alias(klass_, "store", "[]=");
1668
- }
2899
+ return result;
2900
+ }
1669
2901
 
1670
- void define_enumerable()
1671
- {
1672
- // Add enumerable support
1673
- klass_.template define_iterator<typename T::iterator (T::*)()>(&T::begin, &T::end);
1674
- }
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;
1675
2909
 
1676
- void define_to_hash()
1677
- {
1678
- // Add enumerable support
1679
- klass_.define_method("to_h", [](T& map)
2910
+ for_each_tuple(this->fromRubys_,
2911
+ [&](auto& fromRuby)
1680
2912
  {
1681
- VALUE result = rb_hash_new();
1682
- std::for_each(map.begin(), map.end(), [&result](const Reference_T pair)
1683
- {
1684
- VALUE key = detail::To_Ruby<Key_T&>().convert(pair.first);
1685
- VALUE value = detail::To_Ruby<To_Ruby_T&>().convert(pair.second);
1686
- rb_hash_aset(result, key, value);
1687
- });
2913
+ Convertible isConvertible = fromRuby.is_convertible(value);
1688
2914
 
1689
- return result;
1690
- }, Return().setValue());
1691
- }
2915
+ if (isConvertible > foundConversion)
2916
+ {
2917
+ index = i;
2918
+ foundConversion = isConvertible;
2919
+ }
2920
+ i++;
2921
+ });
1692
2922
 
1693
- void define_to_s()
2923
+ if (index == -1)
1694
2924
  {
1695
- if constexpr (detail::is_ostreamable_v<Key_T> && detail::is_ostreamable_v<Mapped_T>)
1696
- {
1697
- klass_.define_method("to_s", [](const T& map)
1698
- {
1699
- auto iter = map.begin();
2925
+ rb_raise(rb_eArgError, "Could not find converter for variant");
2926
+ }
1700
2927
 
1701
- std::stringstream stream;
1702
- stream << "{";
2928
+ return index;
2929
+ }
1703
2930
 
1704
- for (; iter != map.end(); iter++)
1705
- {
1706
- if (iter != map.begin())
1707
- {
1708
- stream << ", ";
1709
- }
1710
- stream << iter->first << " => " << iter->second;
1711
- }
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.
1712
2936
 
1713
- stream << "}";
1714
- return stream.str();
1715
- });
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);
1716
2950
  }
1717
2951
  else
1718
2952
  {
1719
- klass_.define_method("to_s", [](const T& map)
1720
- {
1721
- return "[Not printable]";
1722
- });
2953
+ return convertInternal<I + 1>(value, index);
1723
2954
  }
1724
2955
  }
2956
+ rb_raise(rb_eArgError, "Could not find converter for variant");
2957
+ }
1725
2958
 
1726
- private:
1727
- Data_Type<T> klass_;
1728
- };
1729
- } // namespace
1730
-
1731
- template<typename T>
1732
- Data_Type<T> define_map_under(Object parent, std::string name)
1733
- {
1734
- if (detail::Registries::instance.types.isDefined<T>())
2959
+ std::variant<Types...> convert(VALUE value)
1735
2960
  {
1736
- // If the map has been previously seen it will be registered but may
1737
- // not be associated with the constant Module::<name>
1738
- parent.const_set_maybe(name, Data_Type<T>().klass());
1739
- return Data_Type<T>();
2961
+ int index = this->figureIndex(value);
2962
+ return this->convertInternal(value, index);
1740
2963
  }
1741
2964
 
1742
- Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(parent, name.c_str());
1743
- stl::MapHelper helper(result);
1744
- return result;
1745
- }
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
+ };
1746
2970
 
1747
- template<typename T>
1748
- 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...>>
1749
2973
  {
1750
- if (detail::Registries::instance.types.isDefined<T>())
2974
+ public:
2975
+ std::variant<Types...>& convert(VALUE value)
1751
2976
  {
1752
- // If the map has been previously seen it will be registered but may
1753
- // not be associated with the constant Object::<name>
1754
- Object(rb_cObject).const_set_maybe(name, Data_Type<T>().klass());
1755
- return Data_Type<T>();
2977
+ int index = this->figureIndex(value);
2978
+ this->converted_ = this->convertInternal(value, index);
2979
+ return this->converted_;
1756
2980
  }
1757
2981
 
1758
- Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
1759
- stl::MapHelper<T> helper(result);
1760
- return result;
1761
- }
2982
+ private:
2983
+ std::variant<Types...> converted_;
2984
+ };
2985
+ }
2986
+
1762
2987
 
2988
+ // ========= unique_ptr.hpp =========
2989
+
2990
+ namespace Rice::detail
2991
+ {
1763
2992
  template<typename T>
1764
- Data_Type<T> define_map_auto()
1765
- {
1766
- std::string name = detail::typeName(typeid(T));
1767
- std::string klassName = detail::makeClassName(name);
1768
- Module rb_mRice = define_module("Rice");
1769
- Module rb_mStd = define_module_under(rb_mRice, "Std");
1770
- return define_map_under<T>(rb_mStd, klassName);
1771
- }
1772
-
1773
- namespace detail
2993
+ class Wrapper<std::unique_ptr<T>> : public WrapperBase
1774
2994
  {
1775
- template<typename T, typename U>
1776
- struct Type<std::map<T, U>>
1777
- {
1778
- static bool verify()
1779
- {
1780
- Type<T>::verify();
1781
- Type<U>::verify();
2995
+ public:
2996
+ Wrapper(std::unique_ptr<T>&& data);
2997
+ ~Wrapper();
2998
+ void* get() override;
2999
+ std::unique_ptr<T>& data();
1782
3000
 
1783
- if (!detail::Registries::instance.types.isDefined<std::map<T, U>>())
1784
- {
1785
- define_map_auto<std::map<T, U>>();
1786
- }
3001
+ private:
3002
+ std::unique_ptr<T> data_;
3003
+ };
3004
+ }
1787
3005
 
1788
- return true;
1789
- }
1790
- };
1791
3006
 
1792
- template<typename T, typename U>
1793
- struct MapFromHash
1794
- {
1795
- static int convertPair(VALUE key, VALUE value, VALUE user_data)
1796
- {
1797
- std::map<T, U>* result = (std::map<T, U>*)(user_data);
3007
+ // --------- unique_ptr.ipp ---------
3008
+ #include <memory>
1798
3009
 
1799
- // This method is being called from Ruby so we cannot let any C++
1800
- // exceptions propogate back to Ruby
1801
- return cpp_protect([&]
1802
- {
1803
- result->operator[](From_Ruby<T>().convert(key)) = From_Ruby<U>().convert(value);
1804
- return ST_CONTINUE;
1805
- });
1806
- }
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
+ }
1807
3017
 
1808
- static std::map<T, U> convert(VALUE value)
1809
- {
1810
- std::map<T, U> result;
1811
- 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
+ }
1812
3023
 
1813
- // MSVC needs help here, but g++ does not
1814
- using Rb_Hash_ForEach_T = void(*)(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE);
1815
- 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
+ }
1816
3029
 
1817
- return result;
1818
- }
1819
- };
3030
+ template<typename T>
3031
+ inline std::unique_ptr<T>& Wrapper<std::unique_ptr<T>>::data()
3032
+ {
3033
+ return data_;
3034
+ }
1820
3035
 
1821
- template<typename T, typename U>
1822
- 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)
1823
3041
  {
1824
- public:
1825
- From_Ruby() = default;
1826
-
1827
- explicit From_Ruby(Arg * arg) : arg_(arg)
1828
- {
1829
- }
1830
-
1831
- Convertible is_convertible(VALUE value)
1832
- {
1833
- switch (rb_type(value))
1834
- {
1835
- case RUBY_T_DATA:
1836
- return Convertible::Exact;
1837
- break;
1838
- case RUBY_T_HASH:
1839
- return Convertible::Cast;
1840
- break;
1841
- default:
1842
- return Convertible::None;
1843
- }
1844
- }
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
+ }
1845
3045
 
1846
- std::map<T, U> convert(VALUE value)
1847
- {
1848
- switch (rb_type(value))
1849
- {
1850
- case RUBY_T_DATA:
1851
- {
1852
- // This is a wrapped map (hopefully!)
1853
- return *Data_Object<std::map<T, U>>::from_ruby(value);
1854
- }
1855
- case RUBY_T_HASH:
1856
- {
1857
- // If this an Ruby hash and the mapped type is copyable
1858
- if constexpr (std::is_default_constructible_v<U>)
1859
- {
1860
- return MapFromHash<T, U>::convert(value);
1861
- }
1862
- }
1863
- case RUBY_T_NIL:
1864
- {
1865
- if (this->arg_ && this->arg_->hasDefaultValue())
1866
- {
1867
- return this->arg_->template defaultValue<std::map<T, U>>();
1868
- }
1869
- }
1870
- default:
1871
- {
1872
- throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1873
- detail::protect(rb_obj_classname, value), "std::map");
1874
- }
1875
- }
1876
- }
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
+ };
1877
3052
 
1878
- private:
1879
- Arg* arg_ = nullptr;
1880
- };
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
+ };
1881
3063
 
1882
- template<typename T, typename U>
1883
- class From_Ruby<std::map<T, U>&>
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)
1884
3069
  {
1885
- public:
1886
- From_Ruby() = default;
3070
+ WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
3071
+ return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
3072
+ }
1887
3073
 
1888
- explicit From_Ruby(Arg * arg) : arg_(arg)
1889
- {
1890
- }
3074
+ Convertible is_convertible(VALUE value)
3075
+ {
3076
+ if (!is_same_smart_ptr(value))
3077
+ return Convertible::None;
1891
3078
 
1892
- Convertible is_convertible(VALUE value)
3079
+ switch (rb_type(value))
1893
3080
  {
1894
- switch (rb_type(value))
1895
- {
1896
- case RUBY_T_DATA:
1897
- return Convertible::Exact;
1898
- break;
1899
- case RUBY_T_HASH:
1900
- return Convertible::Cast;
1901
- break;
1902
- default:
1903
- return Convertible::None;
1904
- }
3081
+ case RUBY_T_DATA:
3082
+ return Convertible::Exact;
3083
+ break;
3084
+ default:
3085
+ return Convertible::None;
1905
3086
  }
3087
+ }
1906
3088
 
1907
- 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)
1908
3093
  {
1909
- switch (rb_type(value))
1910
- {
1911
- case RUBY_T_DATA:
1912
- {
1913
- // This is a wrapped map (hopefully!)
1914
- return *Data_Object<std::map<T, U>>::from_ruby(value);
1915
- }
1916
- case RUBY_T_HASH:
1917
- {
1918
- // If this an Ruby array and the map type is copyable
1919
- if constexpr (std::is_default_constructible_v<std::map<T, U>>)
1920
- {
1921
- this->converted_ = MapFromHash<T, U>::convert(value);
1922
- return this->converted_;
1923
- }
1924
- }
1925
- case RUBY_T_NIL:
1926
- {
1927
- if (this->arg_ && this->arg_->hasDefaultValue())
1928
- {
1929
- return this->arg_->template defaultValue<std::map<T, U>>();
1930
- }
1931
- }
1932
- default:
1933
- {
1934
- throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1935
- detail::protect(rb_obj_classname, value), "std::map");
1936
- }
1937
- }
3094
+ std::string message = "Invalid smart pointer wrapper";
3095
+ throw std::runtime_error(message.c_str());
1938
3096
  }
3097
+ return std::move(wrapper->data());
3098
+ }
3099
+ };
1939
3100
 
1940
- private:
1941
- Arg* arg_ = nullptr;
1942
- std::map<T, U> converted_;
1943
- };
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
+ }
1944
3110
 
1945
- template<typename T, typename U>
1946
- class From_Ruby<std::map<T, U>*>
3111
+ Convertible is_convertible(VALUE value)
1947
3112
  {
1948
- public:
1949
- Convertible is_convertible(VALUE value)
3113
+ if (!is_same_smart_ptr(value))
3114
+ return Convertible::None;
3115
+
3116
+ switch (rb_type(value))
1950
3117
  {
1951
- switch (rb_type(value))
1952
- {
1953
- case RUBY_T_DATA:
1954
- return Convertible::Exact;
1955
- break;
1956
- case RUBY_T_NIL:
1957
- return Convertible::Exact;
1958
- break;
1959
- case RUBY_T_HASH:
1960
- return Convertible::Cast;
1961
- break;
1962
- default:
1963
- return Convertible::None;
1964
- }
3118
+ case RUBY_T_DATA:
3119
+ return Convertible::Exact;
3120
+ break;
3121
+ default:
3122
+ return Convertible::None;
1965
3123
  }
3124
+ }
1966
3125
 
1967
- std::map<T, U>* convert(VALUE value)
3126
+ std::unique_ptr<T>& convert(VALUE value)
3127
+ {
3128
+ Wrapper<std::unique_ptr<T>>* wrapper = is_same_smart_ptr(value);
3129
+ if (!wrapper)
1968
3130
  {
1969
- switch (rb_type(value))
1970
- {
1971
- case RUBY_T_DATA:
1972
- {
1973
- // This is a wrapped map (hopefully!)
1974
- return Data_Object<std::map<T, U>>::from_ruby(value);
1975
- }
1976
- case RUBY_T_HASH:
1977
- {
1978
- // If this an Ruby array and the map type is copyable
1979
- if constexpr (std::is_default_constructible_v<U>)
1980
- {
1981
- this->converted_ = MapFromHash<T, U>::convert(value);
1982
- return &this->converted_;
1983
- }
1984
- }
1985
- default:
1986
- {
1987
- throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1988
- detail::protect(rb_obj_classname, value), "std::map");
1989
- }
1990
- }
3131
+ std::string message = "Invalid smart pointer wrapper";
3132
+ throw std::runtime_error(message.c_str());
1991
3133
  }
3134
+ return wrapper->data();
3135
+ }
3136
+ };
1992
3137
 
1993
- private:
1994
- std::map<T, U> converted_;
1995
- };
1996
- }
3138
+ template<typename T>
3139
+ struct Type<std::unique_ptr<T>>
3140
+ {
3141
+ static bool verify()
3142
+ {
3143
+ return Type<T>::verify();
3144
+ }
3145
+ };
1997
3146
  }
1998
3147
 
1999
- // ========= unordered_map.hpp =========
2000
3148
 
3149
+ // ========= unordered_map.hpp =========
2001
3150
 
2002
3151
  namespace Rice
2003
3152
  {
2004
- template<typename U>
2005
- Data_Type<U> define_unordered_map(std::string name);
2006
-
2007
- template<typename U>
2008
- Data_Type<U> define_unordered_map_under(Object parent, std::string name);
3153
+ template<typename Key, typename T>
3154
+ Data_Type<std::unordered_map<Key, T>> define_unordered_map(std::string name = "");
2009
3155
  }
2010
3156
 
2011
3157
 
2012
3158
  // --------- unordered_map.ipp ---------
2013
-
2014
- #include <sstream>
2015
- #include <stdexcept>
2016
- #include <type_traits>
2017
3159
  #include <unordered_map>
2018
- #include <variant>
2019
3160
 
2020
3161
  namespace Rice
2021
3162
  {
@@ -2051,7 +3192,7 @@ namespace Rice
2051
3192
 
2052
3193
  void register_pair()
2053
3194
  {
2054
- define_pair_auto<Value_T>();
3195
+ define_pair<const Key_T, T>();
2055
3196
  }
2056
3197
 
2057
3198
  void define_constructor()
@@ -2249,61 +3390,43 @@ namespace Rice
2249
3390
  };
2250
3391
  } // namespace
2251
3392
 
2252
- template<typename T>
2253
- Data_Type<T> define_unordered_map_under(Object parent, std::string name)
3393
+ template<typename Key, typename T>
3394
+ Data_Type<std::unordered_map<Key, T>> define_unordered_map(std::string klassName)
2254
3395
  {
2255
- 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())
2256
3400
  {
2257
- // If the unordered_map has been previously seen it will be registered but may
2258
- // not be associated with the constant Module::<name>
2259
- parent.const_set_maybe(name, Data_Type<T>().klass());
2260
- return Data_Type<T>();
3401
+ std::string typeName = detail::typeName(typeid(UnorderedMap_T));
3402
+ klassName = detail::rubyClassName(typeName);
2261
3403
  }
2262
3404
 
2263
- Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(parent, name.c_str());
2264
- stl::UnorderedMapHelper helper(result);
2265
- return result;
2266
- }
2267
-
2268
- template<typename T>
2269
- Data_Type<T> define_unordered_map(std::string name)
2270
- {
2271
- if (detail::Registries::instance.types.isDefined<T>())
3405
+ Module rb_mStd = define_module("Std");
3406
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
2272
3407
  {
2273
- // If the unordered_map has been previously seen it will be registered but may
2274
- // not be associated with the constant Object::<name>
2275
- Object(rb_cObject).const_set_maybe(name, Data_Type<T>().klass());
2276
- return Data_Type<T>();
3408
+ return Data_Type_T();
2277
3409
  }
2278
3410
 
2279
- Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
2280
- 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);
2281
3414
  return result;
2282
3415
  }
2283
3416
 
2284
- template<typename T>
2285
- Data_Type<T> define_unordered_map_auto()
2286
- {
2287
- std::string name = detail::typeName(typeid(T));
2288
- std::string klassName = detail::makeClassName(name);
2289
- Module rb_mRice = define_module("Rice");
2290
- Module rb_mStd = define_module_under(rb_mRice, "Std");
2291
- return define_unordered_map_under<T>(rb_mStd, klassName);
2292
- }
2293
-
2294
3417
  namespace detail
2295
3418
  {
2296
- template<typename T, typename U>
2297
- struct Type<std::unordered_map<T, U>>
3419
+ template<typename Key_T, typename T>
3420
+ struct Type<std::unordered_map<Key_T, T>>
2298
3421
  {
2299
3422
  static bool verify()
2300
3423
  {
3424
+ Type<Key_T>::verify();
2301
3425
  Type<T>::verify();
2302
- Type<U>::verify();
2303
3426
 
2304
- if (!detail::Registries::instance.types.isDefined<std::unordered_map<T, U>>())
3427
+ if (!Data_Type<std::unordered_map<Key_T, T>>::is_defined())
2305
3428
  {
2306
- define_unordered_map_auto<std::unordered_map<T, U>>();
3429
+ define_unordered_map<Key_T, T>();
2307
3430
  }
2308
3431
 
2309
3432
  return true;
@@ -2354,7 +3477,7 @@ namespace Rice
2354
3477
  switch (rb_type(value))
2355
3478
  {
2356
3479
  case RUBY_T_DATA:
2357
- return Convertible::Exact;
3480
+ return Data_Type<std::unordered_map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2358
3481
  break;
2359
3482
  case RUBY_T_HASH:
2360
3483
  return Convertible::Cast;
@@ -2371,7 +3494,7 @@ namespace Rice
2371
3494
  case RUBY_T_DATA:
2372
3495
  {
2373
3496
  // This is a wrapped unordered_map (hopefully!)
2374
- 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);
2375
3498
  }
2376
3499
  case RUBY_T_HASH:
2377
3500
  {
@@ -2381,13 +3504,6 @@ namespace Rice
2381
3504
  return UnorderedMapFromHash<T, U>::convert(value);
2382
3505
  }
2383
3506
  }
2384
- case RUBY_T_NIL:
2385
- {
2386
- if (this->arg_ && this->arg_->hasDefaultValue())
2387
- {
2388
- return this->arg_->template defaultValue<std::unordered_map<T, U>>();
2389
- }
2390
- }
2391
3507
  default:
2392
3508
  {
2393
3509
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
@@ -2415,7 +3531,7 @@ namespace Rice
2415
3531
  switch (rb_type(value))
2416
3532
  {
2417
3533
  case RUBY_T_DATA:
2418
- return Convertible::Exact;
3534
+ return Data_Type<std::unordered_map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2419
3535
  break;
2420
3536
  case RUBY_T_HASH:
2421
3537
  return Convertible::Cast;
@@ -2432,7 +3548,7 @@ namespace Rice
2432
3548
  case RUBY_T_DATA:
2433
3549
  {
2434
3550
  // This is a wrapped unordered_map (hopefully!)
2435
- 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);
2436
3552
  }
2437
3553
  case RUBY_T_HASH:
2438
3554
  {
@@ -2443,13 +3559,6 @@ namespace Rice
2443
3559
  return this->converted_;
2444
3560
  }
2445
3561
  }
2446
- case RUBY_T_NIL:
2447
- {
2448
- if (this->arg_ && this->arg_->hasDefaultValue())
2449
- {
2450
- return this->arg_->template defaultValue<std::unordered_map<T, U>>();
2451
- }
2452
- }
2453
3562
  default:
2454
3563
  {
2455
3564
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
@@ -2472,7 +3581,7 @@ namespace Rice
2472
3581
  switch (rb_type(value))
2473
3582
  {
2474
3583
  case RUBY_T_DATA:
2475
- return Convertible::Exact;
3584
+ return Data_Type<std::unordered_map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2476
3585
  break;
2477
3586
  case RUBY_T_NIL:
2478
3587
  return Convertible::Exact;
@@ -2492,7 +3601,7 @@ namespace Rice
2492
3601
  case RUBY_T_DATA:
2493
3602
  {
2494
3603
  // This is a wrapped unordered_map (hopefully!)
2495
- 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);
2496
3605
  }
2497
3606
  case RUBY_T_HASH:
2498
3607
  {
@@ -2519,24 +3628,15 @@ namespace Rice
2519
3628
 
2520
3629
  // ========= vector.hpp =========
2521
3630
 
2522
-
2523
3631
  namespace Rice
2524
3632
  {
2525
3633
  template<typename T>
2526
- Data_Type<T> define_vector(std::string name);
2527
-
2528
- template<typename T>
2529
- Data_Type<T> define_vector_under(Object parent, std::string name);
3634
+ Data_Type<std::vector<T>> define_vector(std::string name = "" );
2530
3635
  }
2531
3636
 
2532
3637
 
2533
3638
  // --------- vector.ipp ---------
2534
-
2535
- #include <sstream>
2536
- #include <stdexcept>
2537
- #include <type_traits>
2538
3639
  #include <vector>
2539
- #include <variant>
2540
3640
 
2541
3641
  namespace Rice
2542
3642
  {
@@ -2560,8 +3660,7 @@ namespace Rice
2560
3660
  public:
2561
3661
  VectorHelper(Data_Type<T> klass) : klass_(klass)
2562
3662
  {
2563
- this->define_constructor();
2564
- this->define_copyable_methods();
3663
+ this->define_constructors();
2565
3664
  this->define_constructable_methods();
2566
3665
  this->define_capacity_methods();
2567
3666
  this->define_access_methods();
@@ -2593,28 +3692,35 @@ namespace Rice
2593
3692
  return index;
2594
3693
  };
2595
3694
 
2596
- void define_constructor()
3695
+ void define_constructors()
2597
3696
  {
2598
- klass_.define_constructor(Constructor<T>());
2599
- }
3697
+ klass_.define_constructor(Constructor<T>())
3698
+ .define_constructor(Constructor<T, Size_T, const Parameter_T>())
3699
+ .define_constructor(Constructor<T, const T&>());
2600
3700
 
2601
- void define_copyable_methods()
2602
- {
2603
- if constexpr (std::is_copy_constructible_v<Value_T>)
3701
+ if constexpr (std::is_default_constructible_v<Value_T>)
2604
3702
  {
2605
- klass_.define_method("copy", [](T& vector) -> T
2606
- {
2607
- return vector;
2608
- });
3703
+ klass_.define_constructor(Constructor<T, Size_T>());
2609
3704
  }
2610
- else
3705
+
3706
+ // Allow creation of a vector from a Ruby Array
3707
+ klass_.define_method("initialize", [](VALUE self, Array array) -> void
2611
3708
  {
2612
- klass_.define_method("copy", [](T& vector) -> T
2613
- {
2614
- throw std::runtime_error("Cannot copy vectors with non-copy constructible types");
2615
- return vector;
2616
- });
2617
- }
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
+ });
2618
3724
  }
2619
3725
 
2620
3726
  void define_constructable_methods()
@@ -2699,9 +3805,10 @@ namespace Rice
2699
3805
  auto begin = vector.begin() + start;
2700
3806
 
2701
3807
  // Ruby does not throw an exception when the length is too long
2702
- if (start + length > vector.size())
3808
+ Difference_T size = (Difference_T)vector.size();
3809
+ if (start + length > size)
2703
3810
  {
2704
- length = vector.size() - start;
3811
+ length = size - start;
2705
3812
  }
2706
3813
 
2707
3814
  auto finish = vector.begin() + start + length;
@@ -2718,13 +3825,20 @@ namespace Rice
2718
3825
  }
2719
3826
  }, Return().setValue());
2720
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
+
2721
3835
  rb_define_alias(klass_, "at", "[]");
2722
3836
  }
2723
3837
 
2724
3838
  // Methods that require Value_T to support operator==
2725
3839
  void define_comparable_methods()
2726
3840
  {
2727
- if constexpr (detail::is_comparable_v<Value_T>)
3841
+ if constexpr (detail::is_comparable_v<T>)
2728
3842
  {
2729
3843
  klass_.define_method("delete", [](T& vector, Parameter_T element) -> std::optional<Value_T>
2730
3844
  {
@@ -2817,8 +3931,9 @@ namespace Rice
2817
3931
  return element;
2818
3932
  });
2819
3933
 
2820
- rb_define_alias(klass_, "<<", "push");
2821
- 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");
2822
3937
  }
2823
3938
 
2824
3939
  void define_enumerable()
@@ -2886,50 +4001,30 @@ namespace Rice
2886
4001
  } // namespace
2887
4002
 
2888
4003
  template<typename T>
2889
- Data_Type<T> define_vector_under(Object parent, std::string name)
4004
+ Data_Type<std::vector<T>> define_vector(std::string klassName)
2890
4005
  {
2891
- if (detail::Registries::instance.types.isDefined<T>())
2892
- {
2893
- // If the vector has been previously seen it will be registered but may
2894
- // not be associated with the constant Module::<name>
2895
- parent.const_set_maybe(name, Data_Type<T>().klass());
4006
+ using Vector_T = std::vector<T>;
4007
+ using Data_Type_T = Data_Type<Vector_T>;
2896
4008
 
2897
- return Data_Type<T>();
4009
+ if (klassName.empty())
4010
+ {
4011
+ std::string typeName = detail::typeName(typeid(Vector_T));
4012
+ klassName = detail::rubyClassName(typeName);
2898
4013
  }
2899
4014
 
2900
- Identifier id(name);
2901
- Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(parent, id, rb_cObject);
2902
- stl::VectorHelper helper(result);
2903
- return result;
2904
- }
2905
-
2906
- template<typename T>
2907
- Data_Type<T> define_vector(std::string name)
2908
- {
2909
- if (detail::Registries::instance.types.isDefined<T>())
4015
+ Module rb_mStd = define_module("Std");
4016
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
2910
4017
  {
2911
- // If the vector has been previously seen it will be registered but may
2912
- // not be associated with the constant Module::<name>
2913
- Object(rb_cObject).const_set_maybe(name, Data_Type<T>().klass());
2914
-
2915
- return Data_Type<T>();
4018
+ return Data_Type_T();
2916
4019
  }
2917
4020
 
2918
- Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
2919
- 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);
2920
4024
  return result;
2921
4025
  }
2922
4026
 
2923
- template<typename T>
2924
- Data_Type<T> define_vector_auto()
2925
- {
2926
- std::string name = detail::typeName(typeid(T));
2927
- std::string klassName = detail::makeClassName(name);
2928
- Module rb_mRice = define_module("Rice");
2929
- Module rb_mStd = define_module_under(rb_mRice, "Std");
2930
- return define_vector_under<T>(rb_mStd, klassName);
2931
- }
2932
-
4027
+
2933
4028
  namespace detail
2934
4029
  {
2935
4030
  template<typename T>
@@ -2939,16 +4034,15 @@ namespace Rice
2939
4034
  {
2940
4035
  Type<intrinsic_type<T>>::verify();
2941
4036
 
2942
- if (!detail::Registries::instance.types.isDefined<std::vector<T>>())
4037
+ if (!Data_Type<std::vector<T>>::is_defined())
2943
4038
  {
2944
- define_vector_auto<std::vector<T>>();
4039
+ define_vector<T>();
2945
4040
  }
2946
4041
 
2947
4042
  return true;
2948
4043
  }
2949
4044
  };
2950
4045
 
2951
-
2952
4046
  template<typename T>
2953
4047
  class From_Ruby<std::vector<T>>
2954
4048
  {
@@ -2964,11 +4058,13 @@ namespace Rice
2964
4058
  switch (rb_type(value))
2965
4059
  {
2966
4060
  case RUBY_T_DATA:
2967
- return Convertible::Exact;
4061
+ return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2968
4062
  break;
2969
4063
  case RUBY_T_ARRAY:
2970
- return Convertible::Cast;
2971
- break;
4064
+ if constexpr (std::is_default_constructible_v<T>)
4065
+ {
4066
+ return Convertible::Cast;
4067
+ }
2972
4068
  default:
2973
4069
  return Convertible::None;
2974
4070
  }
@@ -2981,7 +4077,7 @@ namespace Rice
2981
4077
  case RUBY_T_DATA:
2982
4078
  {
2983
4079
  // This is a wrapped vector (hopefully!)
2984
- 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);
2985
4081
  }
2986
4082
  case RUBY_T_ARRAY:
2987
4083
  {
@@ -2991,13 +4087,6 @@ namespace Rice
2991
4087
  return Array(value).to_vector<T>();
2992
4088
  }
2993
4089
  }
2994
- case RUBY_T_NIL:
2995
- {
2996
- if (this->arg_ && this->arg_->hasDefaultValue())
2997
- {
2998
- return this->arg_->template defaultValue<std::vector<T>>();
2999
- }
3000
- }
3001
4090
  default:
3002
4091
  {
3003
4092
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
@@ -3025,11 +4114,13 @@ namespace Rice
3025
4114
  switch (rb_type(value))
3026
4115
  {
3027
4116
  case RUBY_T_DATA:
3028
- return Convertible::Exact;
4117
+ return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
3029
4118
  break;
3030
4119
  case RUBY_T_ARRAY:
3031
- return Convertible::Cast;
3032
- break;
4120
+ if constexpr (std::is_default_constructible_v<T>)
4121
+ {
4122
+ return Convertible::Cast;
4123
+ }
3033
4124
  default:
3034
4125
  return Convertible::None;
3035
4126
  }
@@ -3042,7 +4133,7 @@ namespace Rice
3042
4133
  case RUBY_T_DATA:
3043
4134
  {
3044
4135
  // This is a wrapped vector (hopefully!)
3045
- 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);
3046
4137
  }
3047
4138
  case RUBY_T_ARRAY:
3048
4139
  {
@@ -3053,13 +4144,6 @@ namespace Rice
3053
4144
  return this->converted_;
3054
4145
  }
3055
4146
  }
3056
- case RUBY_T_NIL:
3057
- {
3058
- if (this->arg_ && this->arg_->hasDefaultValue())
3059
- {
3060
- return this->arg_->template defaultValue<std::vector<T>>();
3061
- }
3062
- }
3063
4147
  default:
3064
4148
  {
3065
4149
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
@@ -3082,14 +4166,16 @@ namespace Rice
3082
4166
  switch (rb_type(value))
3083
4167
  {
3084
4168
  case RUBY_T_DATA:
3085
- return Convertible::Exact;
4169
+ return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
3086
4170
  break;
3087
4171
  case RUBY_T_NIL:
3088
4172
  return Convertible::Exact;
3089
4173
  break;
3090
4174
  case RUBY_T_ARRAY:
3091
- return Convertible::Cast;
3092
- break;
4175
+ if constexpr (std::is_default_constructible_v<T>)
4176
+ {
4177
+ return Convertible::Cast;
4178
+ }
3093
4179
  default:
3094
4180
  return Convertible::None;
3095
4181
  }
@@ -3102,7 +4188,7 @@ namespace Rice
3102
4188
  case RUBY_T_DATA:
3103
4189
  {
3104
4190
  // This is a wrapped vector (hopefully!)
3105
- 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);
3106
4192
  }
3107
4193
  case RUBY_T_ARRAY:
3108
4194
  {