rice 4.5.0 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/CMakeLists.txt +31 -0
  4. data/CMakePresets.json +75 -0
  5. data/COPYING +3 -2
  6. data/FindRuby.cmake +437 -0
  7. data/Rakefile +5 -4
  8. data/include/rice/rice.hpp +5436 -3201
  9. data/include/rice/stl.hpp +2355 -1269
  10. data/lib/make_rice_headers.rb +79 -0
  11. data/lib/mkmf-rice.rb +4 -0
  12. data/lib/rice/version.rb +3 -0
  13. data/lib/rice.rb +1 -0
  14. data/lib/rubygems/builder.rb +11 -0
  15. data/lib/rubygems/cmake_builder.rb +113 -0
  16. data/lib/rubygems_plugin.rb +9 -0
  17. data/rice/Arg.hpp +7 -1
  18. data/rice/Arg.ipp +11 -2
  19. data/rice/Buffer.hpp +123 -0
  20. data/rice/Buffer.ipp +599 -0
  21. data/rice/Constructor.ipp +3 -3
  22. data/rice/Data_Object.hpp +2 -3
  23. data/rice/Data_Object.ipp +188 -188
  24. data/rice/Data_Type.hpp +4 -5
  25. data/rice/Data_Type.ipp +42 -26
  26. data/rice/Enum.hpp +0 -1
  27. data/rice/Enum.ipp +26 -23
  28. data/rice/Init.hpp +8 -0
  29. data/rice/Init.ipp +8 -0
  30. data/rice/MemoryView.ipp +1 -41
  31. data/rice/Return.hpp +1 -1
  32. data/rice/Return.ipp +6 -0
  33. data/rice/cpp_api/Array.hpp +209 -0
  34. data/rice/cpp_api/Array.ipp +304 -0
  35. data/rice/cpp_api/Builtin_Object.hpp +31 -0
  36. data/rice/cpp_api/Builtin_Object.ipp +37 -0
  37. data/rice/cpp_api/Class.hpp +70 -0
  38. data/rice/cpp_api/Class.ipp +97 -0
  39. data/rice/cpp_api/Encoding.hpp +32 -0
  40. data/rice/cpp_api/Encoding.ipp +59 -0
  41. data/rice/cpp_api/Hash.hpp +194 -0
  42. data/rice/cpp_api/Hash.ipp +257 -0
  43. data/rice/cpp_api/Identifier.hpp +46 -0
  44. data/rice/cpp_api/Identifier.ipp +31 -0
  45. data/rice/cpp_api/Module.hpp +72 -0
  46. data/rice/cpp_api/Module.ipp +101 -0
  47. data/rice/cpp_api/Object.hpp +272 -0
  48. data/rice/cpp_api/Object.ipp +235 -0
  49. data/rice/cpp_api/String.hpp +74 -0
  50. data/rice/cpp_api/String.ipp +120 -0
  51. data/rice/cpp_api/Struct.hpp +113 -0
  52. data/rice/cpp_api/Struct.ipp +92 -0
  53. data/rice/cpp_api/Symbol.hpp +46 -0
  54. data/rice/cpp_api/Symbol.ipp +93 -0
  55. data/rice/cpp_api/shared_methods.hpp +134 -0
  56. data/rice/detail/MethodInfo.hpp +1 -9
  57. data/rice/detail/MethodInfo.ipp +5 -72
  58. data/rice/detail/Native.hpp +3 -2
  59. data/rice/detail/Native.ipp +32 -4
  60. data/rice/detail/NativeAttributeGet.hpp +3 -2
  61. data/rice/detail/NativeAttributeGet.ipp +8 -2
  62. data/rice/detail/NativeAttributeSet.hpp +3 -2
  63. data/rice/detail/NativeAttributeSet.ipp +8 -2
  64. data/rice/detail/NativeCallbackFFI.ipp +1 -1
  65. data/rice/detail/NativeFunction.hpp +17 -6
  66. data/rice/detail/NativeFunction.ipp +168 -64
  67. data/rice/detail/NativeIterator.hpp +3 -2
  68. data/rice/detail/NativeIterator.ipp +8 -2
  69. data/rice/detail/RubyType.hpp +2 -5
  70. data/rice/detail/RubyType.ipp +50 -5
  71. data/rice/detail/Type.hpp +3 -1
  72. data/rice/detail/Type.ipp +61 -31
  73. data/rice/detail/Wrapper.hpp +68 -33
  74. data/rice/detail/Wrapper.ipp +103 -113
  75. data/rice/detail/from_ruby.hpp +5 -4
  76. data/rice/detail/from_ruby.ipp +737 -365
  77. data/rice/detail/to_ruby.ipp +1092 -186
  78. data/rice/global_function.ipp +1 -1
  79. data/rice/libc/file.hpp +11 -0
  80. data/rice/libc/file.ipp +32 -0
  81. data/rice/rice.hpp +23 -16
  82. data/rice/stl/complex.hpp +6 -0
  83. data/rice/stl/complex.ipp +93 -0
  84. data/rice/stl/exception.hpp +11 -0
  85. data/rice/stl/exception.ipp +29 -0
  86. data/rice/stl/exception_ptr.hpp +6 -0
  87. data/rice/stl/exception_ptr.ipp +27 -0
  88. data/rice/stl/map.hpp +12 -0
  89. data/rice/stl/map.ipp +469 -0
  90. data/rice/stl/monostate.hpp +6 -0
  91. data/rice/stl/monostate.ipp +80 -0
  92. data/rice/stl/multimap.hpp +14 -0
  93. data/rice/stl/multimap.ipp +448 -0
  94. data/rice/stl/optional.hpp +6 -0
  95. data/rice/stl/optional.ipp +118 -0
  96. data/rice/stl/pair.hpp +13 -0
  97. data/rice/stl/pair.ipp +155 -0
  98. data/rice/stl/reference_wrapper.hpp +6 -0
  99. data/rice/stl/reference_wrapper.ipp +41 -0
  100. data/rice/stl/set.hpp +12 -0
  101. data/rice/stl/set.ipp +495 -0
  102. data/rice/stl/shared_ptr.hpp +28 -0
  103. data/rice/stl/shared_ptr.ipp +224 -0
  104. data/rice/stl/string.hpp +6 -0
  105. data/rice/stl/string.ipp +158 -0
  106. data/rice/stl/string_view.hpp +6 -0
  107. data/rice/stl/string_view.ipp +65 -0
  108. data/rice/stl/tuple.hpp +6 -0
  109. data/rice/stl/tuple.ipp +128 -0
  110. data/rice/stl/type_index.hpp +6 -0
  111. data/rice/stl/type_index.ipp +30 -0
  112. data/rice/stl/type_info.hpp +6 -0
  113. data/rice/stl/type_info.ipp +29 -0
  114. data/rice/stl/unique_ptr.hpp +22 -0
  115. data/rice/stl/unique_ptr.ipp +139 -0
  116. data/rice/stl/unordered_map.hpp +12 -0
  117. data/rice/stl/unordered_map.ipp +469 -0
  118. data/rice/stl/variant.hpp +6 -0
  119. data/rice/stl/variant.ipp +242 -0
  120. data/rice/stl/vector.hpp +12 -0
  121. data/rice/stl/vector.ipp +590 -0
  122. data/rice/stl.hpp +7 -3
  123. data/rice/traits/attribute_traits.hpp +26 -0
  124. data/rice/traits/function_traits.hpp +95 -0
  125. data/rice/traits/method_traits.hpp +47 -0
  126. data/rice/traits/rice_traits.hpp +160 -0
  127. data/rice.gemspec +85 -0
  128. data/test/embed_ruby.cpp +3 -0
  129. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  130. data/test/test_Array.cpp +6 -3
  131. data/test/test_Attribute.cpp +34 -1
  132. data/test/test_Buffer.cpp +285 -0
  133. data/test/test_Callback.cpp +2 -3
  134. data/test/test_Data_Object.cpp +88 -34
  135. data/test/test_Data_Type.cpp +106 -65
  136. data/test/test_Director.cpp +7 -3
  137. data/test/test_Enum.cpp +5 -2
  138. data/test/test_File.cpp +1 -1
  139. data/test/test_From_Ruby.cpp +181 -114
  140. data/test/test_Iterator.cpp +1 -1
  141. data/test/{test_JumpException.cpp → test_Jump_Exception.cpp} +1 -0
  142. data/test/test_Keep_Alive.cpp +7 -18
  143. data/test/test_Keep_Alive_No_Wrapper.cpp +0 -1
  144. data/test/test_Module.cpp +13 -6
  145. data/test/test_Native_Registry.cpp +0 -1
  146. data/test/test_Overloads.cpp +180 -5
  147. data/test/test_Ownership.cpp +100 -57
  148. data/test/test_Proc.cpp +0 -1
  149. data/test/test_Self.cpp +4 -4
  150. data/test/test_Stl_Map.cpp +37 -39
  151. data/test/test_Stl_Multimap.cpp +693 -0
  152. data/test/test_Stl_Pair.cpp +8 -8
  153. data/test/test_Stl_Reference_Wrapper.cpp +4 -2
  154. data/test/test_Stl_Set.cpp +790 -0
  155. data/test/{test_Stl_SmartPointer.cpp → test_Stl_SharedPtr.cpp} +97 -127
  156. data/test/test_Stl_Tuple.cpp +116 -0
  157. data/test/test_Stl_Type.cpp +1 -1
  158. data/test/test_Stl_UniquePtr.cpp +202 -0
  159. data/test/test_Stl_Unordered_Map.cpp +28 -34
  160. data/test/test_Stl_Variant.cpp +217 -89
  161. data/test/test_Stl_Vector.cpp +209 -83
  162. data/test/test_To_Ruby.cpp +373 -1
  163. data/test/test_Type.cpp +85 -14
  164. data/test/test_global_functions.cpp +17 -4
  165. metadata +94 -10
  166. data/rice/detail/TupleIterator.hpp +0 -14
data/rice/stl/pair.ipp ADDED
@@ -0,0 +1,155 @@
1
+ #include <utility>
2
+
3
+ namespace Rice
4
+ {
5
+ namespace stl
6
+ {
7
+ template<typename T>
8
+ class PairHelper
9
+ {
10
+ public:
11
+ PairHelper(Data_Type<T> klass) : klass_(klass)
12
+ {
13
+ this->define_constructor();
14
+ this->define_copyable_methods();
15
+ this->define_access_methods();
16
+ this->define_modify_methods();
17
+ this->define_to_s();
18
+ }
19
+
20
+ private:
21
+ void define_constructor()
22
+ {
23
+ klass_.define_constructor(Constructor<T, typename T::first_type&, typename T::second_type&>());
24
+ }
25
+
26
+ void define_copyable_methods()
27
+ {
28
+ if constexpr (std::is_copy_constructible_v<typename T::first_type> && std::is_copy_constructible_v<typename T::second_type>)
29
+ {
30
+ klass_.define_method("copy", [](T& pair) -> T
31
+ {
32
+ return pair;
33
+ });
34
+ }
35
+ else
36
+ {
37
+ klass_.define_method("copy", [](T& pair) -> T
38
+ {
39
+ throw std::runtime_error("Cannot copy pair with non-copy constructible types");
40
+ return pair;
41
+ });
42
+ }
43
+ }
44
+
45
+ void define_access_methods()
46
+ {
47
+ // Access methods
48
+ klass_.define_method("first", [](T& pair) -> typename T::first_type&
49
+ {
50
+ return pair.first;
51
+ })
52
+ .define_method("second", [](T& pair) -> typename T::second_type&
53
+ {
54
+ return pair.second;
55
+ });
56
+ }
57
+
58
+ void define_modify_methods()
59
+ {
60
+ // Access methods
61
+ klass_.define_method("first=", [](T& pair, typename T::first_type& value) -> typename T::first_type&
62
+ {
63
+ if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::first_type>>>)
64
+ {
65
+ throw std::runtime_error("Cannot set pair.first since it is a constant");
66
+ }
67
+ else
68
+ {
69
+ pair.first = value;
70
+ return pair.first;
71
+ }
72
+ })
73
+ .define_method("second=", [](T& pair, typename T::second_type& value) -> typename T::second_type&
74
+ {
75
+ if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::second_type>>>)
76
+ {
77
+ throw std::runtime_error("Cannot set pair.second since it is a constant");
78
+ }
79
+ else
80
+ {
81
+ pair.second = value;
82
+ return pair.second;
83
+ }
84
+ });
85
+ }
86
+
87
+ void define_to_s()
88
+ {
89
+ if constexpr (detail::is_ostreamable_v<typename T::first_type> && detail::is_ostreamable_v<typename T::second_type>)
90
+ {
91
+ klass_.define_method("to_s", [](const T& pair)
92
+ {
93
+ std::stringstream stream;
94
+ stream << "[" << pair.first << ", " << pair.second << "]";
95
+ return stream.str();
96
+ });
97
+ }
98
+ else
99
+ {
100
+ klass_.define_method("to_s", [](const T& pair)
101
+ {
102
+ return "[Not printable]";
103
+ });
104
+ }
105
+ }
106
+
107
+ private:
108
+ Data_Type<T> klass_;
109
+ };
110
+ } // namespace
111
+
112
+ template<typename T1, typename T2>
113
+ Data_Type<std::pair<T1, T2>> define_pair(std::string klassName)
114
+ {
115
+ using Pair_T = std::pair<T1, T2>;
116
+ using Data_Type_T = Data_Type<Pair_T>;
117
+
118
+ if (klassName.empty())
119
+ {
120
+ std::string typeName = detail::typeName(typeid(Pair_T));
121
+ klassName = detail::rubyClassName(typeName);
122
+ }
123
+
124
+ Module rb_mStd = define_module("Std");
125
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
126
+ {
127
+ return Data_Type_T();
128
+ }
129
+
130
+ Identifier id(klassName);
131
+ Data_Type_T result = define_class_under<detail::intrinsic_type<Pair_T>>(rb_mStd, id);
132
+ stl::PairHelper helper(result);
133
+ return result;
134
+ }
135
+
136
+ namespace detail
137
+ {
138
+ template<typename T1, typename T2>
139
+ struct Type<std::pair<T1, T2>>
140
+ {
141
+ static bool verify()
142
+ {
143
+ detail::verifyType<T1>();
144
+ detail::verifyType<T2>();
145
+
146
+ if (!Data_Type<std::pair<T1, T2>>::is_defined())
147
+ {
148
+ define_pair<T1, T2>();
149
+ }
150
+
151
+ return true;
152
+ }
153
+ };
154
+ }
155
+ }
@@ -0,0 +1,6 @@
1
+ #ifndef Rice__stl__reference_wrapper__hpp_
2
+ #define Rice__stl__reference_wrapper__hpp_
3
+
4
+ #include "reference_wrapper.ipp"
5
+
6
+ #endif // Rice__stl__reference_wrapper__hpp_
@@ -0,0 +1,41 @@
1
+ #include <functional>
2
+
3
+ namespace Rice::detail
4
+ {
5
+ template<typename T>
6
+ struct Type<std::reference_wrapper<T>>
7
+ {
8
+ constexpr static bool verify()
9
+ {
10
+ return Type<T>::verify();
11
+ }
12
+ };
13
+
14
+ template<typename T>
15
+ class To_Ruby<std::reference_wrapper<T>>
16
+ {
17
+ public:
18
+ VALUE convert(const std::reference_wrapper<T>& data, bool takeOwnership = false)
19
+ {
20
+ return To_Ruby<T&>().convert(data.get());
21
+ }
22
+ };
23
+
24
+ template<typename T>
25
+ class From_Ruby<std::reference_wrapper<T>>
26
+ {
27
+ public:
28
+ Convertible is_convertible(VALUE value)
29
+ {
30
+ return this->converter_.is_convertible(value);
31
+ }
32
+
33
+ std::reference_wrapper<T> convert(VALUE value)
34
+ {
35
+ return this->converter_.convert(value);
36
+ }
37
+
38
+ private:
39
+ From_Ruby<T&> converter_;
40
+ };
41
+ }
data/rice/stl/set.hpp ADDED
@@ -0,0 +1,12 @@
1
+ #ifndef Rice__stl__set__hpp_
2
+ #define Rice__stl__set__hpp_
3
+
4
+ namespace Rice
5
+ {
6
+ template<typename T>
7
+ Data_Type<std::set<T>> define_set(std::string klassName = "");
8
+ }
9
+
10
+ #include "set.ipp"
11
+
12
+ #endif // Rice__stl__set__hpp_
data/rice/stl/set.ipp ADDED
@@ -0,0 +1,495 @@
1
+ #include <set>
2
+
3
+ namespace Rice
4
+ {
5
+ namespace stl
6
+ {
7
+ template<typename T>
8
+ class SetHelper
9
+ {
10
+ // We do NOT use Reference_T and instead use Parameter_T to avoid the weirdness
11
+ // of std::set<bool>. Reference_T is actually a proxy class that we do not
12
+ // want to have to register with Rice nor do we want to pass it around.
13
+ using Key_T = typename T::key_type;
14
+ using Value_T = typename T::value_type;
15
+ using Size_T = typename T::size_type;
16
+ using Difference_T = typename T::difference_type;
17
+ // For To_Ruby_T however we do need to use reference type because this is what
18
+ // will be passed by an interator to To_Ruby#convert
19
+ using Reference_T = typename T::reference;
20
+ using Parameter_T = std::conditional_t<std::is_pointer_v<Value_T>, Value_T, Value_T&>;
21
+ using To_Ruby_T = detail::remove_cv_recursive_t<typename T::reference>;
22
+
23
+ public:
24
+ SetHelper(Data_Type<T> klass) : klass_(klass)
25
+ {
26
+ this->define_constructors();
27
+ this->define_capacity_methods();
28
+ this->define_comparable_methods();
29
+ this->define_modify_methods();
30
+ this->define_operators();
31
+ this->define_enumerable();
32
+ this->define_to_array();
33
+ this->define_to_s();
34
+ }
35
+
36
+ private:
37
+
38
+ void define_constructors()
39
+ {
40
+ klass_.define_constructor(Constructor<T>())
41
+ .define_constructor(Constructor<T, const T&>());
42
+ }
43
+
44
+ void define_capacity_methods()
45
+ {
46
+ klass_.define_method("empty?", &T::empty)
47
+ .define_method("max_size", &T::max_size)
48
+ .define_method("size", &T::size);
49
+
50
+ rb_define_alias(klass_, "count", "size");
51
+ rb_define_alias(klass_, "length", "size");
52
+ }
53
+
54
+ void define_comparable_methods()
55
+ {
56
+ klass_
57
+ .define_method("include?", [](T& self, const Key_T element) -> bool
58
+ {
59
+ auto iter = self.find(element);
60
+ return iter != self.end();
61
+ })
62
+ .define_method("count", [](T& self, const Key_T element) -> Size_T
63
+ {
64
+ return self.count(element);
65
+ });
66
+ }
67
+
68
+ void define_modify_methods()
69
+ {
70
+ klass_
71
+ .define_method("clear", &T::clear)
72
+ .define_method("delete", [](T& self, const Key_T key) -> T&
73
+ {
74
+ self.erase(key);
75
+ return self;
76
+ })
77
+ .define_method("insert", [](T& self, const Value_T value) -> T&
78
+ {
79
+ self.insert(value);
80
+ return self;
81
+ })
82
+ .define_method("merge", [](T& self, T& other) -> T&
83
+ {
84
+ self.merge(other);
85
+ return self;
86
+ });
87
+
88
+ rb_define_alias(klass_, "erase", "delete");
89
+ }
90
+
91
+ void define_operators()
92
+ {
93
+ klass_
94
+ .define_method("<<", [](T& self, const Value_T value) -> T&
95
+ {
96
+ self.insert(value);
97
+ return self;
98
+ })
99
+ .define_method("==", [](const T& self, const T& other) -> bool
100
+ {
101
+ if constexpr (detail::is_comparable_v<Value_T>)
102
+ {
103
+ return self == other;
104
+ }
105
+ else
106
+ {
107
+ return false;
108
+ }
109
+ })
110
+ .define_method("&", [](const T& self, const T& other) -> T
111
+ {
112
+ T result;
113
+ std::set_intersection(self.begin(), self.end(),
114
+ other.begin(), other.end(),
115
+ std::inserter(result, result.begin()));
116
+
117
+ return result;
118
+ })
119
+ .define_method("|", [](const T& self, const T& other) -> T
120
+ {
121
+ T result;
122
+ std::set_union(self.begin(), self.end(),
123
+ other.begin(), other.end(),
124
+ std::inserter(result, result.begin()));
125
+
126
+ return result;
127
+ })
128
+ .define_method("-", [](const T& self, const T& other) -> T
129
+ {
130
+ T result;
131
+ std::set_difference(self.begin(), self.end(),
132
+ other.begin(), other.end(),
133
+ std::inserter(result, result.begin()));
134
+
135
+ return result;
136
+ })
137
+ .define_method("^", [](const T& self, const T& other) -> T
138
+ {
139
+ T result;
140
+ std::set_symmetric_difference(self.begin(), self.end(),
141
+ other.begin(), other.end(),
142
+ std::inserter(result, result.begin()));
143
+
144
+ return result;
145
+ })
146
+ .define_method("<", [](const T& self, const T& other) -> bool
147
+ {
148
+ return std::includes(other.begin(), other.end(),
149
+ self.begin(), self.end());
150
+ })
151
+ .define_method(">", [](const T& self, const T& other) -> bool
152
+ {
153
+ return std::includes(self.begin(), self.end(),
154
+ other.begin(), other.end());
155
+ });
156
+
157
+ rb_define_alias(klass_, "eql?", "==");
158
+ rb_define_alias(klass_, "intersection", "&");
159
+ rb_define_alias(klass_, "union", "|");
160
+ rb_define_alias(klass_, "difference", "-");
161
+ rb_define_alias(klass_, "proper_subset?", "<");
162
+ rb_define_alias(klass_, "subset?", "<");
163
+ rb_define_alias(klass_, "proper_superset?", ">");
164
+ rb_define_alias(klass_, "superset?", ">");
165
+ }
166
+
167
+ void define_enumerable()
168
+ {
169
+ // Add enumerable support
170
+ klass_.template define_iterator<typename T::iterator(T::*)() const>(&T::begin, &T::end);
171
+ }
172
+
173
+ void define_to_array()
174
+ {
175
+ // Add enumerable support
176
+ klass_.define_method("to_a", [](T& self) -> VALUE
177
+ {
178
+ Array array;
179
+ for (const Value_T& element: self)
180
+ {
181
+ array.push(element);
182
+ }
183
+
184
+ return array.value();
185
+ }, Return().setValue());
186
+ }
187
+
188
+ void define_to_s()
189
+ {
190
+ if constexpr (detail::is_ostreamable_v<Value_T>)
191
+ {
192
+ klass_.define_method("to_s", [](const T& self)
193
+ {
194
+ auto iter = self.begin();
195
+ auto finish = self.end();
196
+
197
+ std::stringstream stream;
198
+ stream << "<" << detail::rubyClassName(detail::typeName(typeid(T))) << ":";
199
+ stream << "{";
200
+
201
+ for (; iter != finish; iter++)
202
+ {
203
+ if (iter == self.begin())
204
+ {
205
+ stream << *iter;
206
+ }
207
+ else
208
+ {
209
+ stream << ", " << *iter;
210
+ }
211
+ }
212
+
213
+ stream << "}>";
214
+ return stream.str();
215
+ });
216
+ }
217
+ else
218
+ {
219
+ klass_.define_method("to_s", [](const T& self)
220
+ {
221
+ return "[Not printable]";
222
+ });
223
+ }
224
+ }
225
+
226
+ private:
227
+ Data_Type<T> klass_;
228
+ };
229
+ } // namespace
230
+
231
+ template<typename T>
232
+ Data_Type<std::set<T>> define_set(std::string klassName)
233
+ {
234
+ using Set_T = std::set<T>;
235
+ using Data_Type_T = Data_Type<Set_T>;
236
+
237
+ if (klassName.empty())
238
+ {
239
+ std::string typeName = detail::typeName(typeid(Set_T));
240
+ klassName = detail::rubyClassName(typeName);
241
+ }
242
+
243
+ Module rb_mStd = define_module("Std");
244
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
245
+ {
246
+ return Data_Type_T();
247
+ }
248
+
249
+ Identifier id(klassName);
250
+ Data_Type_T result = define_class_under<detail::intrinsic_type<Set_T>>(rb_mStd, id);
251
+ stl::SetHelper helper(result);
252
+ return result;
253
+ }
254
+
255
+ namespace detail
256
+ {
257
+ // Helper method - maybe someday create a C++ Ruby set wrapper
258
+ template<typename T>
259
+ std::set<T> toSet(VALUE rubySet)
260
+ {
261
+ using Function_T = VALUE(*)(VALUE, ID, int, const VALUE*, rb_block_call_func_t, VALUE);
262
+ static Identifier identifier("each");
263
+
264
+ std::set<T> result;
265
+ auto block = [&result](const typename std::set<T>::value_type element) -> VALUE
266
+ {
267
+ result.insert(element);
268
+ return Qnil;
269
+ };
270
+
271
+ using NativeFunction_T = NativeFunction<void, decltype(block), false>;
272
+
273
+ // It is ok to use the address of native because it will remain valid while we iterate the set
274
+ NativeFunction_T native(block);
275
+ detail::protect<Function_T>(rb_block_call, rubySet, identifier.id(), 0, nullptr, NativeFunction_T::procEntry, (VALUE)&native);
276
+
277
+ return result;
278
+ }
279
+
280
+ template<typename T>
281
+ struct Type<std::set<T>>
282
+ {
283
+ static bool verify()
284
+ {
285
+ Type<intrinsic_type<T>>::verify();
286
+
287
+ if (!Data_Type<std::set<T>>::is_defined())
288
+ {
289
+ define_set<T>();
290
+ }
291
+
292
+ return true;
293
+ }
294
+ };
295
+
296
+ template<typename T>
297
+ class From_Ruby<std::set<T>>
298
+ {
299
+ private:
300
+ static inline std::string setName = "Set";
301
+
302
+ public:
303
+ From_Ruby() = default;
304
+
305
+ explicit From_Ruby(Arg * arg) : arg_(arg)
306
+ {
307
+ }
308
+
309
+ Convertible is_convertible(VALUE value)
310
+ {
311
+ switch (rb_type(value))
312
+ {
313
+ case RUBY_T_DATA:
314
+ return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
315
+ break;
316
+ case RUBY_T_OBJECT:
317
+ {
318
+ Object object(value);
319
+ if (object.class_name().str() == setName)
320
+ {
321
+ return Convertible::Cast;
322
+ }
323
+ }
324
+ default:
325
+ return Convertible::None;
326
+ }
327
+ }
328
+
329
+ std::set<T> convert(VALUE value)
330
+ {
331
+ switch (rb_type(value))
332
+ {
333
+ case RUBY_T_DATA:
334
+ {
335
+ // This is a wrapped self (hopefully!)
336
+ return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
337
+ }
338
+ case RUBY_T_OBJECT:
339
+ {
340
+ Object object(value);
341
+ if (object.class_name().str() == setName)
342
+ {
343
+ return toSet<T>(value);
344
+ }
345
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
346
+ detail::protect(rb_obj_classname, value), "std::set");
347
+ }
348
+ default:
349
+ {
350
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
351
+ detail::protect(rb_obj_classname, value), "std::set");
352
+ }
353
+ }
354
+ }
355
+
356
+ private:
357
+ Arg* arg_ = nullptr;
358
+ };
359
+
360
+ template<typename T>
361
+ class From_Ruby<std::set<T>&>
362
+ {
363
+ private:
364
+ static inline std::string setName = "Set";
365
+
366
+ public:
367
+ From_Ruby() = default;
368
+
369
+ explicit From_Ruby(Arg * arg) : arg_(arg)
370
+ {
371
+ }
372
+
373
+ Convertible is_convertible(VALUE value)
374
+ {
375
+ switch (rb_type(value))
376
+ {
377
+ case RUBY_T_DATA:
378
+ return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
379
+ break;
380
+ case RUBY_T_OBJECT:
381
+ {
382
+ Object object(value);
383
+ if (object.class_name().str() == setName)
384
+ {
385
+ return Convertible::Cast;
386
+ }
387
+ }
388
+ default:
389
+ return Convertible::None;
390
+ }
391
+ }
392
+
393
+ std::set<T>& convert(VALUE value)
394
+ {
395
+ switch (rb_type(value))
396
+ {
397
+ case RUBY_T_DATA:
398
+ {
399
+ // This is a wrapped self (hopefully!)
400
+ return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
401
+ }
402
+ case RUBY_T_OBJECT:
403
+ {
404
+ Object object(value);
405
+ if (object.class_name().str() == setName)
406
+ {
407
+ // If this an Ruby array and the vector type is copyable
408
+ if constexpr (std::is_default_constructible_v<T>)
409
+ {
410
+ this->converted_ = toSet<T>(value);
411
+ return this->converted_;
412
+ }
413
+ }
414
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
415
+ detail::protect(rb_obj_classname, value), "std::set");
416
+ }
417
+ default:
418
+ {
419
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
420
+ detail::protect(rb_obj_classname, value), "std::set");
421
+ }
422
+ }
423
+ }
424
+
425
+ private:
426
+ Arg* arg_ = nullptr;
427
+ std::set<T> converted_;
428
+ };
429
+
430
+ template<typename T>
431
+ class From_Ruby<std::set<T>*>
432
+ {
433
+ private:
434
+ static inline std::string setName = "Set";
435
+ public:
436
+ Convertible is_convertible(VALUE value)
437
+ {
438
+ switch (rb_type(value))
439
+ {
440
+ case RUBY_T_DATA:
441
+ return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
442
+ break;
443
+ case RUBY_T_NIL:
444
+ return Convertible::Exact;
445
+ break;
446
+ case RUBY_T_OBJECT:
447
+ {
448
+ Object object(value);
449
+ if (object.class_name().str() == setName)
450
+ {
451
+ return Convertible::Cast;
452
+ }
453
+ }
454
+ default:
455
+ return Convertible::None;
456
+ }
457
+ }
458
+
459
+ std::set<T>* convert(VALUE value)
460
+ {
461
+ switch (rb_type(value))
462
+ {
463
+ case RUBY_T_DATA:
464
+ {
465
+ // This is a wrapped self (hopefully!)
466
+ return detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
467
+ }
468
+ case RUBY_T_OBJECT:
469
+ {
470
+ Object object(value);
471
+ if (object.class_name().str() == setName)
472
+ {
473
+ // If this an Ruby array and the vector type is copyable
474
+ if constexpr (std::is_default_constructible_v<T>)
475
+ {
476
+ this->converted_ = toSet<T>(value);
477
+ return &this->converted_;
478
+ }
479
+ }
480
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
481
+ detail::protect(rb_obj_classname, value), "std::set");
482
+ }
483
+ default:
484
+ {
485
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
486
+ detail::protect(rb_obj_classname, value), "std::set");
487
+ }
488
+ }
489
+ }
490
+
491
+ private:
492
+ std::set<T> converted_;
493
+ };
494
+ }
495
+ }