rice 4.5.0 → 4.6.1

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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -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 +5619 -3129
  9. data/include/rice/stl.hpp +2319 -1234
  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 +168 -0
  20. data/rice/Buffer.ipp +788 -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 +7 -5
  25. data/rice/Data_Type.ipp +79 -52
  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 +20 -3
  62. data/rice/detail/NativeAttributeSet.hpp +3 -2
  63. data/rice/detail/NativeAttributeSet.ipp +11 -23
  64. data/rice/detail/NativeCallbackFFI.ipp +2 -1
  65. data/rice/detail/NativeFunction.hpp +17 -6
  66. data/rice/detail/NativeFunction.ipp +169 -64
  67. data/rice/detail/NativeIterator.hpp +3 -2
  68. data/rice/detail/NativeIterator.ipp +8 -2
  69. data/rice/detail/RubyFunction.ipp +1 -0
  70. data/rice/detail/RubyType.hpp +2 -5
  71. data/rice/detail/RubyType.ipp +50 -5
  72. data/rice/detail/Type.hpp +3 -1
  73. data/rice/detail/Type.ipp +60 -31
  74. data/rice/detail/Wrapper.hpp +68 -33
  75. data/rice/detail/Wrapper.ipp +103 -113
  76. data/rice/detail/from_ruby.hpp +5 -4
  77. data/rice/detail/from_ruby.ipp +737 -365
  78. data/rice/detail/to_ruby.ipp +1092 -186
  79. data/rice/global_function.ipp +1 -1
  80. data/rice/libc/file.hpp +11 -0
  81. data/rice/libc/file.ipp +32 -0
  82. data/rice/rice.hpp +23 -16
  83. data/rice/stl/complex.hpp +6 -0
  84. data/rice/stl/complex.ipp +93 -0
  85. data/rice/stl/exception.hpp +11 -0
  86. data/rice/stl/exception.ipp +29 -0
  87. data/rice/stl/exception_ptr.hpp +6 -0
  88. data/rice/stl/exception_ptr.ipp +27 -0
  89. data/rice/stl/map.hpp +12 -0
  90. data/rice/stl/map.ipp +469 -0
  91. data/rice/stl/monostate.hpp +6 -0
  92. data/rice/stl/monostate.ipp +80 -0
  93. data/rice/stl/multimap.hpp +14 -0
  94. data/rice/stl/multimap.ipp +448 -0
  95. data/rice/stl/optional.hpp +6 -0
  96. data/rice/stl/optional.ipp +118 -0
  97. data/rice/stl/pair.hpp +13 -0
  98. data/rice/stl/pair.ipp +155 -0
  99. data/rice/stl/reference_wrapper.hpp +6 -0
  100. data/rice/stl/reference_wrapper.ipp +41 -0
  101. data/rice/stl/set.hpp +12 -0
  102. data/rice/stl/set.ipp +495 -0
  103. data/rice/stl/shared_ptr.hpp +28 -0
  104. data/rice/stl/shared_ptr.ipp +224 -0
  105. data/rice/stl/string.hpp +6 -0
  106. data/rice/stl/string.ipp +158 -0
  107. data/rice/stl/string_view.hpp +6 -0
  108. data/rice/stl/string_view.ipp +65 -0
  109. data/rice/stl/tuple.hpp +6 -0
  110. data/rice/stl/tuple.ipp +128 -0
  111. data/rice/stl/type_index.hpp +6 -0
  112. data/rice/stl/type_index.ipp +30 -0
  113. data/rice/stl/type_info.hpp +6 -0
  114. data/rice/stl/type_info.ipp +29 -0
  115. data/rice/stl/unique_ptr.hpp +22 -0
  116. data/rice/stl/unique_ptr.ipp +139 -0
  117. data/rice/stl/unordered_map.hpp +12 -0
  118. data/rice/stl/unordered_map.ipp +469 -0
  119. data/rice/stl/variant.hpp +6 -0
  120. data/rice/stl/variant.ipp +242 -0
  121. data/rice/stl/vector.hpp +12 -0
  122. data/rice/stl/vector.ipp +589 -0
  123. data/rice/stl.hpp +7 -3
  124. data/rice/traits/attribute_traits.hpp +26 -0
  125. data/rice/traits/function_traits.hpp +95 -0
  126. data/rice/traits/method_traits.hpp +47 -0
  127. data/rice/traits/rice_traits.hpp +172 -0
  128. data/rice.gemspec +85 -0
  129. data/test/embed_ruby.cpp +3 -0
  130. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  131. data/test/test_Array.cpp +6 -3
  132. data/test/test_Attribute.cpp +91 -9
  133. data/test/test_Buffer.cpp +340 -0
  134. data/test/test_Callback.cpp +2 -3
  135. data/test/test_Data_Object.cpp +88 -34
  136. data/test/test_Data_Type.cpp +106 -65
  137. data/test/test_Director.cpp +7 -3
  138. data/test/test_Enum.cpp +5 -2
  139. data/test/test_File.cpp +1 -1
  140. data/test/test_From_Ruby.cpp +180 -113
  141. data/test/test_Iterator.cpp +1 -1
  142. data/test/{test_JumpException.cpp → test_Jump_Exception.cpp} +1 -0
  143. data/test/test_Keep_Alive.cpp +7 -18
  144. data/test/test_Keep_Alive_No_Wrapper.cpp +0 -1
  145. data/test/test_Module.cpp +13 -6
  146. data/test/test_Native_Registry.cpp +0 -1
  147. data/test/test_Overloads.cpp +180 -5
  148. data/test/test_Ownership.cpp +100 -57
  149. data/test/test_Proc.cpp +0 -1
  150. data/test/test_Self.cpp +4 -4
  151. data/test/test_Stl_Map.cpp +37 -39
  152. data/test/test_Stl_Multimap.cpp +693 -0
  153. data/test/test_Stl_Pair.cpp +8 -8
  154. data/test/test_Stl_Reference_Wrapper.cpp +4 -2
  155. data/test/test_Stl_Set.cpp +790 -0
  156. data/test/{test_Stl_SmartPointer.cpp → test_Stl_SharedPtr.cpp} +97 -127
  157. data/test/test_Stl_Tuple.cpp +116 -0
  158. data/test/test_Stl_Type.cpp +1 -1
  159. data/test/test_Stl_UniquePtr.cpp +202 -0
  160. data/test/test_Stl_Unordered_Map.cpp +28 -34
  161. data/test/test_Stl_Variant.cpp +217 -89
  162. data/test/test_Stl_Vector.cpp +209 -83
  163. data/test/test_To_Ruby.cpp +373 -1
  164. data/test/test_Type.cpp +85 -14
  165. data/test/test_global_functions.cpp +17 -4
  166. metadata +94 -10
  167. 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,156 +1836,172 @@ 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?");
1614
- }
1615
-
1616
- // Methods that require Value_T to support operator==
1617
- void define_comparable_methods()
1618
- {
1619
- if constexpr (detail::is_comparable_v<Mapped_T>)
1620
- {
1621
- klass_.define_method("value?", [](T& map, Mapped_T& value) -> bool
1622
- {
1623
- auto it = std::find_if(map.begin(), map.end(),
1624
- [&value](auto& pair)
1625
- {
1626
- return pair.second == value;
1627
- });
1628
-
1629
- return it != map.end();
1630
- });
1631
- }
1632
- else
1633
- {
1634
- klass_.define_method("value?", [](T& map, Mapped_T& value) -> bool
1929
+ return result;
1930
+ })
1931
+ .define_method("<", [](const T& self, const T& other) -> bool
1635
1932
  {
1636
- return false;
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());
1637
1940
  });
1638
- }
1639
-
1640
- rb_define_alias(klass_, "has_value", "value?");
1641
- }
1642
-
1643
- void define_modify_methods()
1644
- {
1645
- klass_.define_method("clear", &T::clear)
1646
- .define_method("delete", [](T& map, Key_T& key) -> std::optional<Mapped_T>
1647
- {
1648
- auto iter = map.find(key);
1649
-
1650
- if (iter != map.end())
1651
- {
1652
- Mapped_T result = iter->second;
1653
- map.erase(iter);
1654
- return result;
1655
- }
1656
- else
1657
- {
1658
- return std::nullopt;
1659
- }
1660
- })
1661
- .define_method("[]=", [](T& map, Key_T key, Mapped_T& value) -> Mapped_T
1662
- {
1663
- map[key] = value;
1664
- return value;
1665
- });
1666
-
1667
- rb_define_alias(klass_, "store", "[]=");
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?", ">");
1668
1950
  }
1669
1951
 
1670
1952
  void define_enumerable()
1671
1953
  {
1672
1954
  // Add enumerable support
1673
- klass_.template define_iterator<typename T::iterator (T::*)()>(&T::begin, &T::end);
1955
+ klass_.template define_iterator<typename T::iterator(T::*)() const>(&T::begin, &T::end);
1674
1956
  }
1675
1957
 
1676
- void define_to_hash()
1958
+ void define_to_array()
1677
1959
  {
1678
1960
  // Add enumerable support
1679
- klass_.define_method("to_h", [](T& map)
1961
+ klass_.define_method("to_a", [](T& self) -> VALUE
1680
1962
  {
1681
- VALUE result = rb_hash_new();
1682
- std::for_each(map.begin(), map.end(), [&result](const Reference_T pair)
1963
+ Array array;
1964
+ for (const Value_T& element: self)
1683
1965
  {
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
- });
1966
+ array.push(element);
1967
+ }
1688
1968
 
1689
- return result;
1969
+ return array.value();
1690
1970
  }, Return().setValue());
1691
1971
  }
1692
1972
 
1693
1973
  void define_to_s()
1694
1974
  {
1695
- if constexpr (detail::is_ostreamable_v<Key_T> && detail::is_ostreamable_v<Mapped_T>)
1975
+ if constexpr (detail::is_ostreamable_v<Value_T>)
1696
1976
  {
1697
- klass_.define_method("to_s", [](const T& map)
1698
- {
1699
- auto iter = map.begin();
1977
+ klass_.define_method("to_s", [](const T& self)
1978
+ {
1979
+ auto iter = self.begin();
1980
+ auto finish = self.end();
1700
1981
 
1701
- std::stringstream stream;
1702
- stream << "{";
1982
+ std::stringstream stream;
1983
+ stream << "<" << detail::rubyClassName(detail::typeName(typeid(T))) << ":";
1984
+ stream << "{";
1703
1985
 
1704
- for (; iter != map.end(); iter++)
1986
+ for (; iter != finish; iter++)
1987
+ {
1988
+ if (iter == self.begin())
1705
1989
  {
1706
- if (iter != map.begin())
1707
- {
1708
- stream << ", ";
1709
- }
1710
- stream << iter->first << " => " << iter->second;
1990
+ stream << *iter;
1991
+ }
1992
+ else
1993
+ {
1994
+ stream << ", " << *iter;
1711
1995
  }
1996
+ }
1712
1997
 
1713
- stream << "}";
1714
- return stream.str();
1715
- });
1998
+ stream << "}>";
1999
+ return stream.str();
2000
+ });
1716
2001
  }
1717
2002
  else
1718
2003
  {
1719
- klass_.define_method("to_s", [](const T& map)
2004
+ klass_.define_method("to_s", [](const T& self)
1720
2005
  {
1721
2006
  return "[Not printable]";
1722
2007
  });
@@ -1729,98 +2014,76 @@ namespace Rice
1729
2014
  } // namespace
1730
2015
 
1731
2016
  template<typename T>
1732
- Data_Type<T> define_map_under(Object parent, std::string name)
2017
+ Data_Type<std::set<T>> define_set(std::string klassName)
1733
2018
  {
1734
- if (detail::Registries::instance.types.isDefined<T>())
2019
+ using Set_T = std::set<T>;
2020
+ using Data_Type_T = Data_Type<Set_T>;
2021
+
2022
+ if (klassName.empty())
1735
2023
  {
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>();
2024
+ std::string typeName = detail::typeName(typeid(Set_T));
2025
+ klassName = detail::rubyClassName(typeName);
1740
2026
  }
1741
2027
 
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
- }
1746
-
1747
- template<typename T>
1748
- Data_Type<T> define_map(std::string name)
1749
- {
1750
- if (detail::Registries::instance.types.isDefined<T>())
2028
+ Module rb_mStd = define_module("Std");
2029
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
1751
2030
  {
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>();
2031
+ return Data_Type_T();
1756
2032
  }
1757
2033
 
1758
- Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
1759
- stl::MapHelper<T> helper(result);
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);
1760
2037
  return result;
1761
2038
  }
1762
2039
 
1763
- 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
2040
  namespace detail
1774
2041
  {
1775
- template<typename T, typename U>
1776
- struct Type<std::map<T, U>>
2042
+ // Helper method - maybe someday create a C++ Ruby set wrapper
2043
+ template<typename T>
2044
+ std::set<T> toSet(VALUE rubySet)
1777
2045
  {
1778
- static bool verify()
1779
- {
1780
- Type<T>::verify();
1781
- Type<U>::verify();
2046
+ using Function_T = VALUE(*)(VALUE, ID, int, const VALUE*, rb_block_call_func_t, VALUE);
2047
+ static Identifier identifier("each");
1782
2048
 
1783
- if (!detail::Registries::instance.types.isDefined<std::map<T, U>>())
1784
- {
1785
- define_map_auto<std::map<T, U>>();
1786
- }
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>;
1787
2057
 
1788
- return true;
1789
- }
1790
- };
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
+ }
1791
2064
 
1792
- template<typename T, typename U>
1793
- struct MapFromHash
2065
+ template<typename T>
2066
+ struct Type<std::set<T>>
1794
2067
  {
1795
- static int convertPair(VALUE key, VALUE value, VALUE user_data)
2068
+ static bool verify()
1796
2069
  {
1797
- std::map<T, U>* result = (std::map<T, U>*)(user_data);
2070
+ Type<intrinsic_type<T>>::verify();
1798
2071
 
1799
- // This method is being called from Ruby so we cannot let any C++
1800
- // exceptions propogate back to Ruby
1801
- return cpp_protect([&]
2072
+ if (!Data_Type<std::set<T>>::is_defined())
1802
2073
  {
1803
- result->operator[](From_Ruby<T>().convert(key)) = From_Ruby<U>().convert(value);
1804
- return ST_CONTINUE;
1805
- });
1806
- }
1807
-
1808
- static std::map<T, U> convert(VALUE value)
1809
- {
1810
- std::map<T, U> result;
1811
- VALUE user_data = (VALUE)(&result);
1812
-
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);
2074
+ define_set<T>();
2075
+ }
1816
2076
 
1817
- return result;
2077
+ return true;
1818
2078
  }
1819
2079
  };
1820
2080
 
1821
- template<typename T, typename U>
1822
- class From_Ruby<std::map<T, U>>
2081
+ template<typename T>
2082
+ class From_Ruby<std::set<T>>
1823
2083
  {
2084
+ private:
2085
+ static inline std::string setName = "Set";
2086
+
1824
2087
  public:
1825
2088
  From_Ruby() = default;
1826
2089
 
@@ -1833,44 +2096,44 @@ namespace Rice
1833
2096
  switch (rb_type(value))
1834
2097
  {
1835
2098
  case RUBY_T_DATA:
1836
- return Convertible::Exact;
1837
- break;
1838
- case RUBY_T_HASH:
1839
- return Convertible::Cast;
2099
+ return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1840
2100
  break;
2101
+ case RUBY_T_OBJECT:
2102
+ {
2103
+ Object object(value);
2104
+ if (object.class_name().str() == setName)
2105
+ {
2106
+ return Convertible::Cast;
2107
+ }
2108
+ }
1841
2109
  default:
1842
2110
  return Convertible::None;
1843
2111
  }
1844
2112
  }
1845
2113
 
1846
- std::map<T, U> convert(VALUE value)
2114
+ std::set<T> convert(VALUE value)
1847
2115
  {
1848
2116
  switch (rb_type(value))
1849
2117
  {
1850
2118
  case RUBY_T_DATA:
1851
2119
  {
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
- }
2120
+ // This is a wrapped self (hopefully!)
2121
+ return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
1862
2122
  }
1863
- case RUBY_T_NIL:
2123
+ case RUBY_T_OBJECT:
1864
2124
  {
1865
- if (this->arg_ && this->arg_->hasDefaultValue())
2125
+ Object object(value);
2126
+ if (object.class_name().str() == setName)
1866
2127
  {
1867
- return this->arg_->template defaultValue<std::map<T, U>>();
2128
+ return toSet<T>(value);
1868
2129
  }
2130
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2131
+ detail::protect(rb_obj_classname, value), "std::set");
1869
2132
  }
1870
2133
  default:
1871
2134
  {
1872
2135
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1873
- detail::protect(rb_obj_classname, value), "std::map");
2136
+ detail::protect(rb_obj_classname, value), "std::set");
1874
2137
  }
1875
2138
  }
1876
2139
  }
@@ -1879,9 +2142,12 @@ namespace Rice
1879
2142
  Arg* arg_ = nullptr;
1880
2143
  };
1881
2144
 
1882
- template<typename T, typename U>
1883
- class From_Ruby<std::map<T, U>&>
2145
+ template<typename T>
2146
+ class From_Ruby<std::set<T>&>
1884
2147
  {
2148
+ private:
2149
+ static inline std::string setName = "Set";
2150
+
1885
2151
  public:
1886
2152
  From_Ruby() = default;
1887
2153
 
@@ -1894,128 +2160,1003 @@ namespace Rice
1894
2160
  switch (rb_type(value))
1895
2161
  {
1896
2162
  case RUBY_T_DATA:
1897
- return Convertible::Exact;
1898
- break;
1899
- case RUBY_T_HASH:
1900
- return Convertible::Cast;
2163
+ return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1901
2164
  break;
2165
+ case RUBY_T_OBJECT:
2166
+ {
2167
+ Object object(value);
2168
+ if (object.class_name().str() == setName)
2169
+ {
2170
+ return Convertible::Cast;
2171
+ }
2172
+ }
1902
2173
  default:
1903
2174
  return Convertible::None;
1904
2175
  }
1905
2176
  }
1906
2177
 
1907
- std::map<T, U>& convert(VALUE value)
2178
+ std::set<T>& convert(VALUE value)
1908
2179
  {
1909
2180
  switch (rb_type(value))
1910
2181
  {
1911
2182
  case RUBY_T_DATA:
1912
2183
  {
1913
- // This is a wrapped map (hopefully!)
1914
- return *Data_Object<std::map<T, U>>::from_ruby(value);
2184
+ // This is a wrapped self (hopefully!)
2185
+ return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
1915
2186
  }
1916
- case RUBY_T_HASH:
2187
+ case RUBY_T_OBJECT:
1917
2188
  {
1918
- // If this an Ruby array and the map type is copyable
1919
- if constexpr (std::is_default_constructible_v<std::map<T, U>>)
2189
+ Object object(value);
2190
+ if (object.class_name().str() == setName)
1920
2191
  {
1921
- this->converted_ = MapFromHash<T, U>::convert(value);
1922
- return this->converted_;
2192
+ // If this an Ruby array and the vector type is copyable
2193
+ if constexpr (std::is_default_constructible_v<T>)
2194
+ {
2195
+ this->converted_ = toSet<T>(value);
2196
+ return this->converted_;
2197
+ }
1923
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");
1924
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;
1925
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:
1926
2254
  {
1927
- if (this->arg_ && this->arg_->hasDefaultValue())
2255
+ Object object(value);
2256
+ if (object.class_name().str() == setName)
1928
2257
  {
1929
- return this->arg_->template defaultValue<std::map<T, U>>();
2258
+ // If this an Ruby array and the vector type is copyable
2259
+ if constexpr (std::is_default_constructible_v<T>)
2260
+ {
2261
+ this->converted_ = toSet<T>(value);
2262
+ return &this->converted_;
2263
+ }
1930
2264
  }
2265
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2266
+ detail::protect(rb_obj_classname, value), "std::set");
1931
2267
  }
1932
2268
  default:
1933
2269
  {
1934
2270
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1935
- detail::protect(rb_obj_classname, value), "std::map");
2271
+ detail::protect(rb_obj_classname, value), "std::set");
1936
2272
  }
1937
2273
  }
1938
2274
  }
1939
2275
 
1940
- private:
1941
- Arg* arg_ = nullptr;
1942
- std::map<T, U> converted_;
1943
- };
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
+ });
2898
+
2899
+ return result;
2900
+ }
2901
+
2902
+ // This method search through a variant's types to figure out which one the
2903
+ // currently Ruby value best matches. It then returns the index of the type.
2904
+ int figureIndex(VALUE value)
2905
+ {
2906
+ int i = 0;
2907
+ int index = -1;
2908
+ Convertible foundConversion = Convertible::None;
2909
+
2910
+ for_each_tuple(this->fromRubys_,
2911
+ [&](auto& fromRuby)
2912
+ {
2913
+ Convertible isConvertible = fromRuby.is_convertible(value);
2914
+
2915
+ if (isConvertible > foundConversion)
2916
+ {
2917
+ index = i;
2918
+ foundConversion = isConvertible;
2919
+ }
2920
+ i++;
2921
+ });
2922
+
2923
+ if (index == -1)
2924
+ {
2925
+ rb_raise(rb_eArgError, "Could not find converter for variant");
2926
+ }
2927
+
2928
+ return index;
2929
+ }
2930
+
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.
2936
+
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);
2950
+ }
2951
+ else
2952
+ {
2953
+ return convertInternal<I + 1>(value, index);
2954
+ }
2955
+ }
2956
+ rb_raise(rb_eArgError, "Could not find converter for variant");
2957
+ }
2958
+
2959
+ std::variant<Types...> convert(VALUE value)
2960
+ {
2961
+ int index = this->figureIndex(value);
2962
+ return this->convertInternal(value, index);
2963
+ }
2964
+
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
+ };
2970
+
2971
+ template<typename...Types>
2972
+ class From_Ruby<std::variant<Types...>&> : public From_Ruby<std::variant<Types...>>
2973
+ {
2974
+ public:
2975
+ std::variant<Types...>& convert(VALUE value)
2976
+ {
2977
+ int index = this->figureIndex(value);
2978
+ this->converted_ = this->convertInternal(value, index);
2979
+ return this->converted_;
2980
+ }
2981
+
2982
+ private:
2983
+ std::variant<Types...> converted_;
2984
+ };
2985
+ }
2986
+
2987
+
2988
+ // ========= unique_ptr.hpp =========
2989
+
2990
+ namespace Rice::detail
2991
+ {
2992
+ template<typename T>
2993
+ class Wrapper<std::unique_ptr<T>> : public WrapperBase
2994
+ {
2995
+ public:
2996
+ Wrapper(std::unique_ptr<T>&& data);
2997
+ ~Wrapper();
2998
+ void* get() override;
2999
+ std::unique_ptr<T>& data();
3000
+
3001
+ private:
3002
+ std::unique_ptr<T> data_;
3003
+ };
3004
+ }
3005
+
3006
+
3007
+ // --------- unique_ptr.ipp ---------
3008
+ #include <memory>
3009
+
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
+ }
3017
+
3018
+ template<typename T>
3019
+ inline Wrapper<std::unique_ptr<T>>::~Wrapper()
3020
+ {
3021
+ Registries::instance.instances.remove(this->get());
3022
+ }
3023
+
3024
+ template<typename T>
3025
+ inline void* Wrapper<std::unique_ptr<T>>::get()
3026
+ {
3027
+ return (void*)this->data_.get();
3028
+ }
3029
+
3030
+ template<typename T>
3031
+ inline std::unique_ptr<T>& Wrapper<std::unique_ptr<T>>::data()
3032
+ {
3033
+ return data_;
3034
+ }
3035
+
3036
+ template <typename T>
3037
+ class To_Ruby<std::unique_ptr<T>>
3038
+ {
3039
+ public:
3040
+ VALUE convert(std::unique_ptr<T>& data)
3041
+ {
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
+ }
3045
+
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
+ };
3052
+
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
+ };
3063
+
3064
+ template <typename T>
3065
+ class From_Ruby<std::unique_ptr<T>>
3066
+ {
3067
+ public:
3068
+ Wrapper<std::unique_ptr<T>>* is_same_smart_ptr(VALUE value)
3069
+ {
3070
+ WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
3071
+ return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
3072
+ }
3073
+
3074
+ Convertible is_convertible(VALUE value)
3075
+ {
3076
+ if (!is_same_smart_ptr(value))
3077
+ return Convertible::None;
3078
+
3079
+ switch (rb_type(value))
3080
+ {
3081
+ case RUBY_T_DATA:
3082
+ return Convertible::Exact;
3083
+ break;
3084
+ default:
3085
+ return Convertible::None;
3086
+ }
3087
+ }
3088
+
3089
+ std::unique_ptr<T> convert(VALUE value)
3090
+ {
3091
+ Wrapper<std::unique_ptr<T>>* wrapper = is_same_smart_ptr(value);
3092
+ if (!wrapper)
3093
+ {
3094
+ std::string message = "Invalid smart pointer wrapper";
3095
+ throw std::runtime_error(message.c_str());
3096
+ }
3097
+ return std::move(wrapper->data());
3098
+ }
3099
+ };
1944
3100
 
1945
- template<typename T, typename U>
1946
- class From_Ruby<std::map<T, U>*>
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)
1947
3106
  {
1948
- public:
1949
- Convertible is_convertible(VALUE value)
3107
+ WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
3108
+ return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
3109
+ }
3110
+
3111
+ Convertible is_convertible(VALUE value)
3112
+ {
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()
@@ -2665,66 +3771,73 @@ namespace Rice
2665
3771
  }
2666
3772
  })
2667
3773
  .define_method("last", [](const T& vector) -> std::optional<Value_T>
3774
+ {
3775
+ if (vector.size() > 0)
2668
3776
  {
2669
- if (vector.size() > 0)
2670
- {
2671
- return vector.back();
2672
- }
2673
- else
2674
- {
2675
- return std::nullopt;
2676
- }
2677
- })
3777
+ return vector.back();
3778
+ }
3779
+ else
3780
+ {
3781
+ return std::nullopt;
3782
+ }
3783
+ })
2678
3784
  .define_method("[]", [this](const T& vector, Difference_T index) -> std::optional<Value_T>
3785
+ {
3786
+ index = normalizeIndex(vector.size(), index);
3787
+ if (index < 0 || index >= (Difference_T)vector.size())
2679
3788
  {
2680
- index = normalizeIndex(vector.size(), index);
2681
- if (index < 0 || index >= (Difference_T)vector.size())
2682
- {
2683
- return std::nullopt;
2684
- }
2685
- else
2686
- {
2687
- return vector[index];
2688
- }
2689
- })
3789
+ return std::nullopt;
3790
+ }
3791
+ else
3792
+ {
3793
+ return vector[index];
3794
+ }
3795
+ })
2690
3796
  .define_method("[]", [this](const T& vector, Difference_T start, Difference_T length) -> VALUE
3797
+ {
3798
+ start = normalizeIndex(vector.size(), start);
3799
+ if (start < 0 || start >= (Difference_T)vector.size())
3800
+ {
3801
+ return rb_ary_new();
3802
+ }
3803
+ else
2691
3804
  {
2692
- start = normalizeIndex(vector.size(), start);
2693
- if (start < 0 || start >= (Difference_T)vector.size())
3805
+ auto begin = vector.begin() + start;
3806
+
3807
+ // Ruby does not throw an exception when the length is too long
3808
+ Difference_T size = (Difference_T)vector.size();
3809
+ if (start + length > size)
2694
3810
  {
2695
- return rb_ary_new();
3811
+ length = size - start;
2696
3812
  }
2697
- else
2698
- {
2699
- auto begin = vector.begin() + start;
2700
3813
 
2701
- // Ruby does not throw an exception when the length is too long
2702
- if (start + length > vector.size())
2703
- {
2704
- length = vector.size() - start;
2705
- }
3814
+ auto finish = vector.begin() + start + length;
3815
+ T slice(begin, finish);
2706
3816
 
2707
- auto finish = vector.begin() + start + length;
2708
- T slice(begin, finish);
3817
+ VALUE result = rb_ary_new();
3818
+ std::for_each(slice.begin(), slice.end(), [&result](const Reference_T element)
3819
+ {
3820
+ VALUE value = detail::To_Ruby<Parameter_T>().convert(element);
3821
+ rb_ary_push(result, value);
3822
+ });
2709
3823
 
2710
- VALUE result = rb_ary_new();
2711
- std::for_each(slice.begin(), slice.end(), [&result](const Reference_T element)
2712
- {
2713
- VALUE value = detail::To_Ruby<Parameter_T>().convert(element);
2714
- rb_ary_push(result, value);
2715
- });
3824
+ return result;
3825
+ }
3826
+ }, Return().setValue());
2716
3827
 
2717
- return result;
2718
- }
2719
- }, Return().setValue());
3828
+ if constexpr (!std::is_same_v<Value_T, bool>)
3829
+ {
3830
+ define_buffer<Value_T>();
3831
+ klass_.template define_method<Value_T*(T::*)()>("data", &T::data);
3832
+ }
2720
3833
 
2721
- rb_define_alias(klass_, "at", "[]");
3834
+ rb_define_alias(klass_, "at", "[]");
2722
3835
  }
2723
3836
 
2724
3837
  // Methods that require Value_T to support operator==
2725
3838
  void define_comparable_methods()
2726
3839
  {
2727
- if constexpr (detail::is_comparable_v<Value_T>)
3840
+ if constexpr (detail::is_comparable_v<T>)
2728
3841
  {
2729
3842
  klass_.define_method("delete", [](T& vector, Parameter_T element) -> std::optional<Value_T>
2730
3843
  {
@@ -2817,8 +3930,9 @@ namespace Rice
2817
3930
  return element;
2818
3931
  });
2819
3932
 
2820
- rb_define_alias(klass_, "<<", "push");
2821
- rb_define_alias(klass_, "append", "push");
3933
+ rb_define_alias(klass_, "push_back", "push");
3934
+ rb_define_alias(klass_, "<<", "push");
3935
+ rb_define_alias(klass_, "append", "push");
2822
3936
  }
2823
3937
 
2824
3938
  void define_enumerable()
@@ -2886,50 +4000,30 @@ namespace Rice
2886
4000
  } // namespace
2887
4001
 
2888
4002
  template<typename T>
2889
- Data_Type<T> define_vector_under(Object parent, std::string name)
4003
+ Data_Type<std::vector<T>> define_vector(std::string klassName)
2890
4004
  {
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());
4005
+ using Vector_T = std::vector<T>;
4006
+ using Data_Type_T = Data_Type<Vector_T>;
2896
4007
 
2897
- return Data_Type<T>();
4008
+ if (klassName.empty())
4009
+ {
4010
+ std::string typeName = detail::typeName(typeid(Vector_T));
4011
+ klassName = detail::rubyClassName(typeName);
2898
4012
  }
2899
4013
 
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>())
4014
+ Module rb_mStd = define_module("Std");
4015
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
2910
4016
  {
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>();
4017
+ return Data_Type_T();
2916
4018
  }
2917
4019
 
2918
- Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
2919
- stl::VectorHelper<T> helper(result);
4020
+ Identifier id(klassName);
4021
+ Data_Type_T result = define_class_under<detail::intrinsic_type<Vector_T>>(rb_mStd, id);
4022
+ stl::VectorHelper helper(result);
2920
4023
  return result;
2921
4024
  }
2922
4025
 
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
-
4026
+
2933
4027
  namespace detail
2934
4028
  {
2935
4029
  template<typename T>
@@ -2939,16 +4033,15 @@ namespace Rice
2939
4033
  {
2940
4034
  Type<intrinsic_type<T>>::verify();
2941
4035
 
2942
- if (!detail::Registries::instance.types.isDefined<std::vector<T>>())
4036
+ if (!Data_Type<std::vector<T>>::is_defined())
2943
4037
  {
2944
- define_vector_auto<std::vector<T>>();
4038
+ define_vector<T>();
2945
4039
  }
2946
4040
 
2947
4041
  return true;
2948
4042
  }
2949
4043
  };
2950
4044
 
2951
-
2952
4045
  template<typename T>
2953
4046
  class From_Ruby<std::vector<T>>
2954
4047
  {
@@ -2964,11 +4057,13 @@ namespace Rice
2964
4057
  switch (rb_type(value))
2965
4058
  {
2966
4059
  case RUBY_T_DATA:
2967
- return Convertible::Exact;
4060
+ return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2968
4061
  break;
2969
4062
  case RUBY_T_ARRAY:
2970
- return Convertible::Cast;
2971
- break;
4063
+ if constexpr (std::is_default_constructible_v<T>)
4064
+ {
4065
+ return Convertible::Cast;
4066
+ }
2972
4067
  default:
2973
4068
  return Convertible::None;
2974
4069
  }
@@ -2981,7 +4076,7 @@ namespace Rice
2981
4076
  case RUBY_T_DATA:
2982
4077
  {
2983
4078
  // This is a wrapped vector (hopefully!)
2984
- return *Data_Object<std::vector<T>>::from_ruby(value);
4079
+ return *detail::unwrap<std::vector<T>>(value, Data_Type<std::vector<T>>::ruby_data_type(), false);
2985
4080
  }
2986
4081
  case RUBY_T_ARRAY:
2987
4082
  {
@@ -2991,13 +4086,6 @@ namespace Rice
2991
4086
  return Array(value).to_vector<T>();
2992
4087
  }
2993
4088
  }
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
4089
  default:
3002
4090
  {
3003
4091
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
@@ -3025,11 +4113,13 @@ namespace Rice
3025
4113
  switch (rb_type(value))
3026
4114
  {
3027
4115
  case RUBY_T_DATA:
3028
- return Convertible::Exact;
4116
+ return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
3029
4117
  break;
3030
4118
  case RUBY_T_ARRAY:
3031
- return Convertible::Cast;
3032
- break;
4119
+ if constexpr (std::is_default_constructible_v<T>)
4120
+ {
4121
+ return Convertible::Cast;
4122
+ }
3033
4123
  default:
3034
4124
  return Convertible::None;
3035
4125
  }
@@ -3042,7 +4132,7 @@ namespace Rice
3042
4132
  case RUBY_T_DATA:
3043
4133
  {
3044
4134
  // This is a wrapped vector (hopefully!)
3045
- return *Data_Object<std::vector<T>>::from_ruby(value);
4135
+ return *detail::unwrap<std::vector<T>>(value, Data_Type<std::vector<T>>::ruby_data_type(), false);
3046
4136
  }
3047
4137
  case RUBY_T_ARRAY:
3048
4138
  {
@@ -3053,13 +4143,6 @@ namespace Rice
3053
4143
  return this->converted_;
3054
4144
  }
3055
4145
  }
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
4146
  default:
3064
4147
  {
3065
4148
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
@@ -3082,14 +4165,16 @@ namespace Rice
3082
4165
  switch (rb_type(value))
3083
4166
  {
3084
4167
  case RUBY_T_DATA:
3085
- return Convertible::Exact;
4168
+ return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
3086
4169
  break;
3087
4170
  case RUBY_T_NIL:
3088
4171
  return Convertible::Exact;
3089
4172
  break;
3090
4173
  case RUBY_T_ARRAY:
3091
- return Convertible::Cast;
3092
- break;
4174
+ if constexpr (std::is_default_constructible_v<T>)
4175
+ {
4176
+ return Convertible::Cast;
4177
+ }
3093
4178
  default:
3094
4179
  return Convertible::None;
3095
4180
  }
@@ -3102,7 +4187,7 @@ namespace Rice
3102
4187
  case RUBY_T_DATA:
3103
4188
  {
3104
4189
  // This is a wrapped vector (hopefully!)
3105
- return Data_Object<std::vector<T>>::from_ruby(value);
4190
+ return detail::unwrap<std::vector<T>>(value, Data_Type<std::vector<T>>::ruby_data_type(), false);
3106
4191
  }
3107
4192
  case RUBY_T_ARRAY:
3108
4193
  {