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