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