rice 4.5.0 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -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 +5436 -3201
- data/include/rice/stl.hpp +2355 -1269
- 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 +123 -0
- data/rice/Buffer.ipp +599 -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 +4 -5
- data/rice/Data_Type.ipp +42 -26
- 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 +8 -2
- data/rice/detail/NativeAttributeSet.hpp +3 -2
- data/rice/detail/NativeAttributeSet.ipp +8 -2
- data/rice/detail/NativeCallbackFFI.ipp +1 -1
- data/rice/detail/NativeFunction.hpp +17 -6
- data/rice/detail/NativeFunction.ipp +168 -64
- data/rice/detail/NativeIterator.hpp +3 -2
- data/rice/detail/NativeIterator.ipp +8 -2
- 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 +61 -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 +590 -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 +160 -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 +34 -1
- data/test/test_Buffer.cpp +285 -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 +181 -114
- 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,455 +1836,1327 @@ 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
|
-
|
1929
|
+
return result;
|
1930
|
+
})
|
1931
|
+
.define_method("<", [](const T& self, const T& other) -> bool
|
1932
|
+
{
|
1933
|
+
return std::includes(other.begin(), other.end(),
|
1934
|
+
self.begin(), self.end());
|
1935
|
+
})
|
1936
|
+
.define_method(">", [](const T& self, const T& other) -> bool
|
1937
|
+
{
|
1938
|
+
return std::includes(self.begin(), self.end(),
|
1939
|
+
other.begin(), other.end());
|
1940
|
+
});
|
1941
|
+
|
1942
|
+
rb_define_alias(klass_, "eql?", "==");
|
1943
|
+
rb_define_alias(klass_, "intersection", "&");
|
1944
|
+
rb_define_alias(klass_, "union", "|");
|
1945
|
+
rb_define_alias(klass_, "difference", "-");
|
1946
|
+
rb_define_alias(klass_, "proper_subset?", "<");
|
1947
|
+
rb_define_alias(klass_, "subset?", "<");
|
1948
|
+
rb_define_alias(klass_, "proper_superset?", ">");
|
1949
|
+
rb_define_alias(klass_, "superset?", ">");
|
1614
1950
|
}
|
1615
1951
|
|
1616
|
-
|
1617
|
-
void define_comparable_methods()
|
1952
|
+
void define_enumerable()
|
1618
1953
|
{
|
1619
|
-
|
1954
|
+
// Add enumerable support
|
1955
|
+
klass_.template define_iterator<typename T::iterator(T::*)() const>(&T::begin, &T::end);
|
1956
|
+
}
|
1957
|
+
|
1958
|
+
void define_to_array()
|
1959
|
+
{
|
1960
|
+
// Add enumerable support
|
1961
|
+
klass_.define_method("to_a", [](T& self) -> VALUE
|
1620
1962
|
{
|
1621
|
-
|
1963
|
+
Array array;
|
1964
|
+
for (const Value_T& element: self)
|
1965
|
+
{
|
1966
|
+
array.push(element);
|
1967
|
+
}
|
1968
|
+
|
1969
|
+
return array.value();
|
1970
|
+
}, Return().setValue());
|
1971
|
+
}
|
1972
|
+
|
1973
|
+
void define_to_s()
|
1974
|
+
{
|
1975
|
+
if constexpr (detail::is_ostreamable_v<Value_T>)
|
1976
|
+
{
|
1977
|
+
klass_.define_method("to_s", [](const T& self)
|
1978
|
+
{
|
1979
|
+
auto iter = self.begin();
|
1980
|
+
auto finish = self.end();
|
1981
|
+
|
1982
|
+
std::stringstream stream;
|
1983
|
+
stream << "<" << detail::rubyClassName(detail::typeName(typeid(T))) << ":";
|
1984
|
+
stream << "{";
|
1985
|
+
|
1986
|
+
for (; iter != finish; iter++)
|
1622
1987
|
{
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1988
|
+
if (iter == self.begin())
|
1989
|
+
{
|
1990
|
+
stream << *iter;
|
1991
|
+
}
|
1992
|
+
else
|
1993
|
+
{
|
1994
|
+
stream << ", " << *iter;
|
1995
|
+
}
|
1996
|
+
}
|
1628
1997
|
|
1629
|
-
|
1998
|
+
stream << "}>";
|
1999
|
+
return stream.str();
|
1630
2000
|
});
|
1631
2001
|
}
|
1632
2002
|
else
|
1633
2003
|
{
|
1634
|
-
klass_.define_method("
|
2004
|
+
klass_.define_method("to_s", [](const T& self)
|
2005
|
+
{
|
2006
|
+
return "[Not printable]";
|
2007
|
+
});
|
2008
|
+
}
|
2009
|
+
}
|
2010
|
+
|
2011
|
+
private:
|
2012
|
+
Data_Type<T> klass_;
|
2013
|
+
};
|
2014
|
+
} // namespace
|
2015
|
+
|
2016
|
+
template<typename T>
|
2017
|
+
Data_Type<std::set<T>> define_set(std::string klassName)
|
2018
|
+
{
|
2019
|
+
using Set_T = std::set<T>;
|
2020
|
+
using Data_Type_T = Data_Type<Set_T>;
|
2021
|
+
|
2022
|
+
if (klassName.empty())
|
2023
|
+
{
|
2024
|
+
std::string typeName = detail::typeName(typeid(Set_T));
|
2025
|
+
klassName = detail::rubyClassName(typeName);
|
2026
|
+
}
|
2027
|
+
|
2028
|
+
Module rb_mStd = define_module("Std");
|
2029
|
+
if (Data_Type_T::check_defined(klassName, rb_mStd))
|
2030
|
+
{
|
2031
|
+
return Data_Type_T();
|
2032
|
+
}
|
2033
|
+
|
2034
|
+
Identifier id(klassName);
|
2035
|
+
Data_Type_T result = define_class_under<detail::intrinsic_type<Set_T>>(rb_mStd, id);
|
2036
|
+
stl::SetHelper helper(result);
|
2037
|
+
return result;
|
2038
|
+
}
|
2039
|
+
|
2040
|
+
namespace detail
|
2041
|
+
{
|
2042
|
+
// Helper method - maybe someday create a C++ Ruby set wrapper
|
2043
|
+
template<typename T>
|
2044
|
+
std::set<T> toSet(VALUE rubySet)
|
2045
|
+
{
|
2046
|
+
using Function_T = VALUE(*)(VALUE, ID, int, const VALUE*, rb_block_call_func_t, VALUE);
|
2047
|
+
static Identifier identifier("each");
|
2048
|
+
|
2049
|
+
std::set<T> result;
|
2050
|
+
auto block = [&result](const typename std::set<T>::value_type element) -> VALUE
|
2051
|
+
{
|
2052
|
+
result.insert(element);
|
2053
|
+
return Qnil;
|
2054
|
+
};
|
2055
|
+
|
2056
|
+
using NativeFunction_T = NativeFunction<void, decltype(block), false>;
|
2057
|
+
|
2058
|
+
// It is ok to use the address of native because it will remain valid while we iterate the set
|
2059
|
+
NativeFunction_T native(block);
|
2060
|
+
detail::protect<Function_T>(rb_block_call, rubySet, identifier.id(), 0, nullptr, NativeFunction_T::procEntry, (VALUE)&native);
|
2061
|
+
|
2062
|
+
return result;
|
2063
|
+
}
|
2064
|
+
|
2065
|
+
template<typename T>
|
2066
|
+
struct Type<std::set<T>>
|
2067
|
+
{
|
2068
|
+
static bool verify()
|
2069
|
+
{
|
2070
|
+
Type<intrinsic_type<T>>::verify();
|
2071
|
+
|
2072
|
+
if (!Data_Type<std::set<T>>::is_defined())
|
2073
|
+
{
|
2074
|
+
define_set<T>();
|
2075
|
+
}
|
2076
|
+
|
2077
|
+
return true;
|
2078
|
+
}
|
2079
|
+
};
|
2080
|
+
|
2081
|
+
template<typename T>
|
2082
|
+
class From_Ruby<std::set<T>>
|
2083
|
+
{
|
2084
|
+
private:
|
2085
|
+
static inline std::string setName = "Set";
|
2086
|
+
|
2087
|
+
public:
|
2088
|
+
From_Ruby() = default;
|
2089
|
+
|
2090
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
2091
|
+
{
|
2092
|
+
}
|
2093
|
+
|
2094
|
+
Convertible is_convertible(VALUE value)
|
2095
|
+
{
|
2096
|
+
switch (rb_type(value))
|
2097
|
+
{
|
2098
|
+
case RUBY_T_DATA:
|
2099
|
+
return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
|
2100
|
+
break;
|
2101
|
+
case RUBY_T_OBJECT:
|
1635
2102
|
{
|
1636
|
-
|
1637
|
-
|
2103
|
+
Object object(value);
|
2104
|
+
if (object.class_name().str() == setName)
|
2105
|
+
{
|
2106
|
+
return Convertible::Cast;
|
2107
|
+
}
|
2108
|
+
}
|
2109
|
+
default:
|
2110
|
+
return Convertible::None;
|
1638
2111
|
}
|
2112
|
+
}
|
1639
2113
|
|
1640
|
-
|
2114
|
+
std::set<T> convert(VALUE value)
|
2115
|
+
{
|
2116
|
+
switch (rb_type(value))
|
2117
|
+
{
|
2118
|
+
case RUBY_T_DATA:
|
2119
|
+
{
|
2120
|
+
// This is a wrapped self (hopefully!)
|
2121
|
+
return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
|
2122
|
+
}
|
2123
|
+
case RUBY_T_OBJECT:
|
2124
|
+
{
|
2125
|
+
Object object(value);
|
2126
|
+
if (object.class_name().str() == setName)
|
2127
|
+
{
|
2128
|
+
return toSet<T>(value);
|
2129
|
+
}
|
2130
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
2131
|
+
detail::protect(rb_obj_classname, value), "std::set");
|
2132
|
+
}
|
2133
|
+
default:
|
2134
|
+
{
|
2135
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
2136
|
+
detail::protect(rb_obj_classname, value), "std::set");
|
2137
|
+
}
|
2138
|
+
}
|
1641
2139
|
}
|
1642
2140
|
|
1643
|
-
|
2141
|
+
private:
|
2142
|
+
Arg* arg_ = nullptr;
|
2143
|
+
};
|
2144
|
+
|
2145
|
+
template<typename T>
|
2146
|
+
class From_Ruby<std::set<T>&>
|
2147
|
+
{
|
2148
|
+
private:
|
2149
|
+
static inline std::string setName = "Set";
|
2150
|
+
|
2151
|
+
public:
|
2152
|
+
From_Ruby() = default;
|
2153
|
+
|
2154
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
1644
2155
|
{
|
1645
|
-
|
1646
|
-
|
2156
|
+
}
|
2157
|
+
|
2158
|
+
Convertible is_convertible(VALUE value)
|
2159
|
+
{
|
2160
|
+
switch (rb_type(value))
|
2161
|
+
{
|
2162
|
+
case RUBY_T_DATA:
|
2163
|
+
return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
|
2164
|
+
break;
|
2165
|
+
case RUBY_T_OBJECT:
|
2166
|
+
{
|
2167
|
+
Object object(value);
|
2168
|
+
if (object.class_name().str() == setName)
|
1647
2169
|
{
|
1648
|
-
|
2170
|
+
return Convertible::Cast;
|
2171
|
+
}
|
2172
|
+
}
|
2173
|
+
default:
|
2174
|
+
return Convertible::None;
|
2175
|
+
}
|
2176
|
+
}
|
1649
2177
|
|
1650
|
-
|
2178
|
+
std::set<T>& convert(VALUE value)
|
2179
|
+
{
|
2180
|
+
switch (rb_type(value))
|
2181
|
+
{
|
2182
|
+
case RUBY_T_DATA:
|
2183
|
+
{
|
2184
|
+
// This is a wrapped self (hopefully!)
|
2185
|
+
return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
|
2186
|
+
}
|
2187
|
+
case RUBY_T_OBJECT:
|
2188
|
+
{
|
2189
|
+
Object object(value);
|
2190
|
+
if (object.class_name().str() == setName)
|
2191
|
+
{
|
2192
|
+
// If this an Ruby array and the vector type is copyable
|
2193
|
+
if constexpr (std::is_default_constructible_v<T>)
|
1651
2194
|
{
|
1652
|
-
|
1653
|
-
|
1654
|
-
return result;
|
2195
|
+
this->converted_ = toSet<T>(value);
|
2196
|
+
return this->converted_;
|
1655
2197
|
}
|
1656
|
-
|
2198
|
+
}
|
2199
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
2200
|
+
detail::protect(rb_obj_classname, value), "std::set");
|
2201
|
+
}
|
2202
|
+
default:
|
2203
|
+
{
|
2204
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
2205
|
+
detail::protect(rb_obj_classname, value), "std::set");
|
2206
|
+
}
|
2207
|
+
}
|
2208
|
+
}
|
2209
|
+
|
2210
|
+
private:
|
2211
|
+
Arg* arg_ = nullptr;
|
2212
|
+
std::set<T> converted_;
|
2213
|
+
};
|
2214
|
+
|
2215
|
+
template<typename T>
|
2216
|
+
class From_Ruby<std::set<T>*>
|
2217
|
+
{
|
2218
|
+
private:
|
2219
|
+
static inline std::string setName = "Set";
|
2220
|
+
public:
|
2221
|
+
Convertible is_convertible(VALUE value)
|
2222
|
+
{
|
2223
|
+
switch (rb_type(value))
|
2224
|
+
{
|
2225
|
+
case RUBY_T_DATA:
|
2226
|
+
return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
|
2227
|
+
break;
|
2228
|
+
case RUBY_T_NIL:
|
2229
|
+
return Convertible::Exact;
|
2230
|
+
break;
|
2231
|
+
case RUBY_T_OBJECT:
|
2232
|
+
{
|
2233
|
+
Object object(value);
|
2234
|
+
if (object.class_name().str() == setName)
|
2235
|
+
{
|
2236
|
+
return Convertible::Cast;
|
2237
|
+
}
|
2238
|
+
}
|
2239
|
+
default:
|
2240
|
+
return Convertible::None;
|
2241
|
+
}
|
2242
|
+
}
|
2243
|
+
|
2244
|
+
std::set<T>* convert(VALUE value)
|
2245
|
+
{
|
2246
|
+
switch (rb_type(value))
|
2247
|
+
{
|
2248
|
+
case RUBY_T_DATA:
|
2249
|
+
{
|
2250
|
+
// This is a wrapped self (hopefully!)
|
2251
|
+
return detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
|
2252
|
+
}
|
2253
|
+
case RUBY_T_OBJECT:
|
2254
|
+
{
|
2255
|
+
Object object(value);
|
2256
|
+
if (object.class_name().str() == setName)
|
2257
|
+
{
|
2258
|
+
// If this an Ruby array and the vector type is copyable
|
2259
|
+
if constexpr (std::is_default_constructible_v<T>)
|
1657
2260
|
{
|
1658
|
-
|
2261
|
+
this->converted_ = toSet<T>(value);
|
2262
|
+
return &this->converted_;
|
1659
2263
|
}
|
1660
|
-
}
|
1661
|
-
|
1662
|
-
|
1663
|
-
|
1664
|
-
|
1665
|
-
|
2264
|
+
}
|
2265
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
2266
|
+
detail::protect(rb_obj_classname, value), "std::set");
|
2267
|
+
}
|
2268
|
+
default:
|
2269
|
+
{
|
2270
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
2271
|
+
detail::protect(rb_obj_classname, value), "std::set");
|
2272
|
+
}
|
2273
|
+
}
|
2274
|
+
}
|
2275
|
+
|
2276
|
+
private:
|
2277
|
+
std::set<T> converted_;
|
2278
|
+
};
|
2279
|
+
}
|
2280
|
+
}
|
2281
|
+
|
2282
|
+
|
2283
|
+
// ========= shared_ptr.hpp =========
|
2284
|
+
|
2285
|
+
namespace Rice::detail
|
2286
|
+
{
|
2287
|
+
template<typename T>
|
2288
|
+
class Wrapper<std::shared_ptr<T>> : public WrapperBase
|
2289
|
+
{
|
2290
|
+
public:
|
2291
|
+
Wrapper(const std::shared_ptr<T>& data);
|
2292
|
+
~Wrapper();
|
2293
|
+
void* get() override;
|
2294
|
+
std::shared_ptr<T>& data();
|
2295
|
+
|
2296
|
+
private:
|
2297
|
+
std::shared_ptr<T> data_;
|
2298
|
+
};
|
2299
|
+
}
|
2300
|
+
|
2301
|
+
namespace Rice
|
2302
|
+
{
|
2303
|
+
template<typename T>
|
2304
|
+
Data_Type<std::shared_ptr<T>> define_shared_ptr(std::string klassName = "");
|
2305
|
+
}
|
2306
|
+
|
2307
|
+
|
2308
|
+
// --------- shared_ptr.ipp ---------
|
2309
|
+
#include <memory>
|
2310
|
+
|
2311
|
+
// --------- Enable creation of std::shared_ptr from Ruby ---------
|
2312
|
+
namespace Rice
|
2313
|
+
{
|
2314
|
+
template<typename T>
|
2315
|
+
Data_Type<std::shared_ptr<T>> define_shared_ptr(std::string klassName)
|
2316
|
+
{
|
2317
|
+
using SharedPtr_T = std::shared_ptr<T>;
|
2318
|
+
using Data_Type_T = Data_Type<SharedPtr_T>;
|
2319
|
+
|
2320
|
+
if (klassName.empty())
|
2321
|
+
{
|
2322
|
+
std::string typeName = detail::typeName(typeid(SharedPtr_T));
|
2323
|
+
klassName = detail::rubyClassName(typeName);
|
2324
|
+
}
|
2325
|
+
|
2326
|
+
Module rb_mStd = define_module("Std");
|
2327
|
+
if (Data_Type_T::check_defined(klassName, rb_mStd))
|
2328
|
+
{
|
2329
|
+
return Data_Type_T();
|
2330
|
+
}
|
2331
|
+
|
2332
|
+
Identifier id(klassName);
|
2333
|
+
Data_Type_T result = define_class_under<detail::intrinsic_type<SharedPtr_T>>(rb_mStd, id).
|
2334
|
+
define_constructor(Constructor<SharedPtr_T, typename SharedPtr_T::element_type*>(), Arg("value").takeOwnership());
|
2335
|
+
|
2336
|
+
return result;
|
2337
|
+
}
|
2338
|
+
}
|
2339
|
+
|
2340
|
+
// --------- Wrapper ---------
|
2341
|
+
namespace Rice::detail
|
2342
|
+
{
|
2343
|
+
template<typename T>
|
2344
|
+
inline Wrapper<std::shared_ptr<T>>::Wrapper(const std::shared_ptr<T>& data)
|
2345
|
+
: data_(data)
|
2346
|
+
{
|
2347
|
+
}
|
2348
|
+
|
2349
|
+
template<typename T>
|
2350
|
+
inline Wrapper<std::shared_ptr<T>>::~Wrapper()
|
2351
|
+
{
|
2352
|
+
Registries::instance.instances.remove(this->get());
|
2353
|
+
}
|
2354
|
+
|
2355
|
+
template<typename T>
|
2356
|
+
inline void* Wrapper<std::shared_ptr<T>>::get()
|
2357
|
+
{
|
2358
|
+
return (void*)this->data_.get();
|
2359
|
+
}
|
2360
|
+
|
2361
|
+
template<typename T>
|
2362
|
+
inline std::shared_ptr<T>& Wrapper<std::shared_ptr<T>>::data()
|
2363
|
+
{
|
2364
|
+
return data_;
|
2365
|
+
}
|
2366
|
+
}
|
2367
|
+
|
2368
|
+
// --------- Type/To_Ruby/From_Ruby ---------
|
2369
|
+
namespace Rice::detail
|
2370
|
+
{
|
2371
|
+
template<typename T>
|
2372
|
+
struct Type<std::shared_ptr<T>>
|
2373
|
+
{
|
2374
|
+
static bool verify()
|
2375
|
+
{
|
2376
|
+
return Type<T>::verify();
|
2377
|
+
}
|
2378
|
+
};
|
2379
|
+
|
2380
|
+
template <typename T>
|
2381
|
+
class To_Ruby<std::shared_ptr<T>>
|
2382
|
+
{
|
2383
|
+
public:
|
2384
|
+
VALUE convert(std::shared_ptr<T>& data)
|
2385
|
+
{
|
2386
|
+
if constexpr (std::is_fundamental_v<T>)
|
2387
|
+
{
|
2388
|
+
return detail::wrap(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
|
2389
|
+
}
|
2390
|
+
else
|
2391
|
+
{
|
2392
|
+
return detail::wrap<std::shared_ptr<T>>(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
|
2393
|
+
}
|
2394
|
+
}
|
2395
|
+
|
2396
|
+
VALUE convert(std::shared_ptr<T>&& data)
|
2397
|
+
{
|
2398
|
+
if constexpr (std::is_fundamental_v<T>)
|
2399
|
+
{
|
2400
|
+
return detail::wrap(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
|
2401
|
+
}
|
2402
|
+
else
|
2403
|
+
{
|
2404
|
+
return detail::wrap<std::shared_ptr<T>>(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
|
2405
|
+
}
|
2406
|
+
}
|
2407
|
+
};
|
2408
|
+
|
2409
|
+
template <typename T>
|
2410
|
+
class From_Ruby<std::shared_ptr<T>>
|
2411
|
+
{
|
2412
|
+
public:
|
2413
|
+
From_Ruby() = default;
|
2414
|
+
|
2415
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
2416
|
+
{
|
2417
|
+
}
|
2418
|
+
|
2419
|
+
Convertible is_convertible(VALUE value)
|
2420
|
+
{
|
2421
|
+
switch (rb_type(value))
|
2422
|
+
{
|
2423
|
+
case RUBY_T_DATA:
|
2424
|
+
return Convertible::Exact;
|
2425
|
+
break;
|
2426
|
+
default:
|
2427
|
+
return Convertible::None;
|
2428
|
+
}
|
2429
|
+
}
|
2430
|
+
|
2431
|
+
std::shared_ptr<T> convert(VALUE value)
|
2432
|
+
{
|
2433
|
+
// Get the wrapper
|
2434
|
+
WrapperBase* wrapperBase = detail::getWrapper(value);
|
2435
|
+
|
2436
|
+
// Was this shared_ptr created by the user from Ruby? If so it will
|
2437
|
+
// be wrapped as a pointer, std::shared_ptr<T>*. In the case just
|
2438
|
+
// return the shared pointer
|
2439
|
+
if (dynamic_cast<Wrapper<std::shared_ptr<T>*>*>(wrapperBase))
|
2440
|
+
{
|
2441
|
+
// Use unwrap to validate the underlying wrapper is the correct type
|
2442
|
+
std::shared_ptr<T>* ptr = unwrap<std::shared_ptr<T>>(value, Data_Type<std::shared_ptr<T>>::ruby_data_type(), false);
|
2443
|
+
return *ptr;
|
2444
|
+
}
|
2445
|
+
else if constexpr (std::is_fundamental_v<T>)
|
2446
|
+
{
|
2447
|
+
// Get the wrapper again to validate T's type
|
2448
|
+
Wrapper<std::shared_ptr<T>>* wrapper = getWrapper<Wrapper<std::shared_ptr<T>>>(value, Data_Type<T>::ruby_data_type());
|
2449
|
+
return wrapper->data();
|
2450
|
+
}
|
2451
|
+
else
|
2452
|
+
{
|
2453
|
+
// Get the wrapper again to validate T's type
|
2454
|
+
Wrapper<std::shared_ptr<T>>* wrapper = getWrapper<Wrapper<std::shared_ptr<T>>>(value, Data_Type<T>::ruby_data_type());
|
2455
|
+
return wrapper->data();
|
2456
|
+
}
|
2457
|
+
}
|
2458
|
+
private:
|
2459
|
+
Arg* arg_ = nullptr;
|
2460
|
+
};
|
2461
|
+
|
2462
|
+
template <typename T>
|
2463
|
+
class To_Ruby<std::shared_ptr<T>&>
|
2464
|
+
{
|
2465
|
+
public:
|
2466
|
+
VALUE convert(std::shared_ptr<T>& data)
|
2467
|
+
{
|
2468
|
+
if constexpr (std::is_fundamental_v<T>)
|
2469
|
+
{
|
2470
|
+
return detail::wrap(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
|
2471
|
+
}
|
2472
|
+
else
|
2473
|
+
{
|
2474
|
+
return detail::wrap<std::shared_ptr<T>>(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
|
2475
|
+
}
|
2476
|
+
}
|
2477
|
+
};
|
2478
|
+
|
2479
|
+
template <typename T>
|
2480
|
+
class From_Ruby<std::shared_ptr<T>&>
|
2481
|
+
{
|
2482
|
+
public:
|
2483
|
+
From_Ruby() = default;
|
2484
|
+
|
2485
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
2486
|
+
{
|
2487
|
+
}
|
2488
|
+
|
2489
|
+
Convertible is_convertible(VALUE value)
|
2490
|
+
{
|
2491
|
+
switch (rb_type(value))
|
2492
|
+
{
|
2493
|
+
case RUBY_T_DATA:
|
2494
|
+
return Convertible::Exact;
|
2495
|
+
break;
|
2496
|
+
default:
|
2497
|
+
return Convertible::None;
|
2498
|
+
}
|
2499
|
+
}
|
2500
|
+
|
2501
|
+
std::shared_ptr<T>& convert(VALUE value)
|
2502
|
+
{
|
2503
|
+
// Get the wrapper
|
2504
|
+
WrapperBase* wrapperBase = detail::getWrapper(value);
|
2505
|
+
|
2506
|
+
// Was this shared_ptr created by the user from Ruby? If so it will
|
2507
|
+
// be wrapped as a pointer, std::shared_ptr<T>*. In the case just
|
2508
|
+
// return the shared pointer
|
2509
|
+
if (dynamic_cast<Wrapper<std::shared_ptr<T>*>*>(wrapperBase))
|
2510
|
+
{
|
2511
|
+
// Use unwrap to validate the underlying wrapper is the correct type
|
2512
|
+
std::shared_ptr<T>* ptr = unwrap<std::shared_ptr<T>>(value, Data_Type<std::shared_ptr<T>>::ruby_data_type(), false);
|
2513
|
+
return *ptr;
|
2514
|
+
}
|
2515
|
+
else if constexpr (std::is_fundamental_v<T>)
|
2516
|
+
{
|
2517
|
+
// Get the wrapper again to validate T's type
|
2518
|
+
Wrapper<std::shared_ptr<T>>* wrapper = getWrapper<Wrapper<std::shared_ptr<T>>>(value, Data_Type<T>::ruby_data_type());
|
2519
|
+
return wrapper->data();
|
2520
|
+
}
|
2521
|
+
else
|
2522
|
+
{
|
2523
|
+
// Get the wrapper again to validate T's type
|
2524
|
+
Wrapper<std::shared_ptr<T>>* wrapper = getWrapper<Wrapper<std::shared_ptr<T>>>(value, Data_Type<T>::ruby_data_type());
|
2525
|
+
return wrapper->data();
|
2526
|
+
}
|
2527
|
+
}
|
2528
|
+
|
2529
|
+
private:
|
2530
|
+
Arg* arg_ = nullptr;
|
2531
|
+
};
|
2532
|
+
}
|
2533
|
+
|
2534
|
+
|
2535
|
+
// ========= tuple.hpp =========
|
2536
|
+
|
2537
|
+
|
2538
|
+
// --------- tuple.ipp ---------
|
2539
|
+
#include <tuple>
|
2540
|
+
|
2541
|
+
namespace Rice::detail
|
2542
|
+
{
|
2543
|
+
template<typename...Types>
|
2544
|
+
struct Type<std::tuple<Types...>>
|
2545
|
+
{
|
2546
|
+
using Tuple_T = std::tuple<Types...>;
|
2547
|
+
|
2548
|
+
template<std::size_t... I>
|
2549
|
+
constexpr static bool verifyTypes(std::index_sequence<I...>& indices)
|
2550
|
+
{
|
2551
|
+
return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
|
2552
|
+
}
|
2553
|
+
|
2554
|
+
template<std::size_t... I>
|
2555
|
+
constexpr static bool verify()
|
2556
|
+
{
|
2557
|
+
auto indices = std::make_index_sequence<std::tuple_size_v<std::tuple<Types...>>>{};
|
2558
|
+
return verifyTypes(indices);
|
2559
|
+
}
|
2560
|
+
};
|
2561
|
+
|
2562
|
+
template<typename...Types>
|
2563
|
+
class To_Ruby<std::tuple<Types...>>
|
2564
|
+
{
|
2565
|
+
public:
|
2566
|
+
static VALUE convert(const std::tuple<Types...>& data, bool takeOwnership = false)
|
2567
|
+
{
|
2568
|
+
Array result;
|
2569
|
+
|
2570
|
+
for_each_tuple(data, [&](auto element)
|
2571
|
+
{
|
2572
|
+
using Element_T = decltype(element);
|
2573
|
+
result.push<Element_T>((Element_T)element);
|
2574
|
+
});
|
2575
|
+
|
2576
|
+
return result.value();
|
2577
|
+
}
|
2578
|
+
};
|
2579
|
+
|
2580
|
+
template<typename...Types>
|
2581
|
+
class To_Ruby<std::tuple<Types...>&>
|
2582
|
+
{
|
2583
|
+
public:
|
2584
|
+
static VALUE convert(const std::tuple<Types...>& data, bool takeOwnership = false)
|
2585
|
+
{
|
2586
|
+
Array result;
|
2587
|
+
|
2588
|
+
for_each_tuple(data, [&](auto& value)
|
2589
|
+
{
|
2590
|
+
VALUE element = detail::To_Ruby<decltype(value)>().convert(value);
|
2591
|
+
result.push(element);
|
2592
|
+
});
|
2593
|
+
|
2594
|
+
return result.value();
|
2595
|
+
}
|
2596
|
+
};
|
2597
|
+
|
2598
|
+
template<typename...Types>
|
2599
|
+
class From_Ruby<std::tuple<Types...>>
|
2600
|
+
{
|
2601
|
+
public:
|
2602
|
+
using Tuple_T = std::tuple<Types...>;
|
2603
|
+
|
2604
|
+
template<std::size_t... I>
|
2605
|
+
constexpr static bool verifyTypes(Array& array, std::index_sequence<I...>& indices)
|
2606
|
+
{
|
2607
|
+
return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
|
2608
|
+
}
|
2609
|
+
|
2610
|
+
Convertible is_convertible(VALUE value)
|
2611
|
+
{
|
2612
|
+
Convertible result = Convertible::None;
|
2613
|
+
|
2614
|
+
// The ruby value must be an array of the correct size
|
2615
|
+
if (rb_type(value) != RUBY_T_ARRAY || Array(value).size() != std::tuple_size_v<Tuple_T>)
|
2616
|
+
{
|
2617
|
+
return result;
|
2618
|
+
}
|
2619
|
+
|
2620
|
+
// Now check that each tuple type is convertible
|
2621
|
+
Array array(value);
|
2622
|
+
int i = 0;
|
2623
|
+
for_each_tuple(this->fromRubys_,
|
2624
|
+
[&](auto& fromRuby)
|
2625
|
+
{
|
2626
|
+
result = result | fromRuby.is_convertible(array[i].value());
|
2627
|
+
i++;
|
2628
|
+
});
|
2629
|
+
|
2630
|
+
return result;
|
2631
|
+
}
|
2632
|
+
|
2633
|
+
template <std::size_t... I>
|
2634
|
+
std::tuple<Types...> convertInternal(Array array, std::index_sequence<I...>& indices)
|
2635
|
+
{
|
2636
|
+
return std::forward_as_tuple(std::get<I>(this->fromRubys_).convert(array[I].value())...);
|
2637
|
+
}
|
2638
|
+
|
2639
|
+
std::tuple<Types...> convert(VALUE value)
|
2640
|
+
{
|
2641
|
+
Array array(value);
|
2642
|
+
auto indices = std::make_index_sequence<std::tuple_size_v<Tuple_T>>{};
|
2643
|
+
return convertInternal(array, indices);
|
2644
|
+
}
|
2645
|
+
|
2646
|
+
private:
|
2647
|
+
// Possible converters we could use for this variant
|
2648
|
+
using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
|
2649
|
+
From_Ruby_Ts fromRubys_;
|
2650
|
+
};
|
2651
|
+
|
2652
|
+
/* template<typename...Types>
|
2653
|
+
class From_Ruby<std::tuple<Types...>&> : public From_Ruby<std::tuple<Types...>>
|
2654
|
+
{
|
2655
|
+
public:
|
2656
|
+
std::tuple<Types...>& convert(VALUE value)
|
2657
|
+
{
|
2658
|
+
int index = this->figureIndex(value);
|
2659
|
+
this->converted_ = this->convertInternal(value, index);
|
2660
|
+
return this->converted_;
|
2661
|
+
}
|
2662
|
+
|
2663
|
+
private:
|
2664
|
+
std::tuple<Types...> converted_;
|
2665
|
+
};*/
|
2666
|
+
}
|
2667
|
+
|
2668
|
+
|
2669
|
+
// ========= type_index.hpp =========
|
2670
|
+
|
2671
|
+
|
2672
|
+
// --------- type_index.ipp ---------
|
2673
|
+
#include <typeindex>
|
2674
|
+
|
2675
|
+
namespace Rice::stl
|
2676
|
+
{
|
2677
|
+
inline Data_Type<std::type_index> define_type_index()
|
2678
|
+
{
|
2679
|
+
Module rb_mStd = define_module("Std");
|
2680
|
+
return define_class_under<std::type_index>(rb_mStd, "TypeIndex").
|
2681
|
+
define_constructor(Constructor<std::type_index, const std::type_info&>()).
|
2682
|
+
define_method("hash_code", &std::type_index::hash_code).
|
2683
|
+
define_method("name", &std::type_index::name);
|
2684
|
+
}
|
2685
|
+
}
|
2686
|
+
|
2687
|
+
namespace Rice::detail
|
2688
|
+
{
|
2689
|
+
template<>
|
2690
|
+
struct Type<std::type_index>
|
2691
|
+
{
|
2692
|
+
static bool verify()
|
2693
|
+
{
|
2694
|
+
if (!detail::Registries::instance.types.isDefined<std::type_index>())
|
2695
|
+
{
|
2696
|
+
stl::define_type_index();
|
2697
|
+
}
|
2698
|
+
|
2699
|
+
return true;
|
2700
|
+
}
|
2701
|
+
};
|
2702
|
+
}
|
2703
|
+
|
2704
|
+
|
2705
|
+
// ========= type_info.hpp =========
|
2706
|
+
|
2707
|
+
|
2708
|
+
// --------- type_info.ipp ---------
|
2709
|
+
#include <typeinfo>
|
2710
|
+
|
2711
|
+
namespace Rice::stl
|
2712
|
+
{
|
2713
|
+
inline Data_Type<std::type_info> define_type_info()
|
2714
|
+
{
|
2715
|
+
Module rb_mStd = define_module("Std");
|
2716
|
+
return define_class_under<std::type_info>(rb_mStd, "TypeInfo").
|
2717
|
+
define_method("hash_code", &std::type_info::hash_code).
|
2718
|
+
define_method("name", &std::type_info::name);
|
2719
|
+
}
|
2720
|
+
}
|
2721
|
+
|
2722
|
+
namespace Rice::detail
|
2723
|
+
{
|
2724
|
+
template<>
|
2725
|
+
struct Type<std::type_info>
|
2726
|
+
{
|
2727
|
+
static inline bool verify()
|
2728
|
+
{
|
2729
|
+
if (!detail::Registries::instance.types.isDefined<std::type_info>())
|
2730
|
+
{
|
2731
|
+
stl::define_type_info();
|
2732
|
+
}
|
2733
|
+
|
2734
|
+
return true;
|
2735
|
+
}
|
2736
|
+
};
|
2737
|
+
}
|
2738
|
+
|
2739
|
+
|
2740
|
+
// ========= variant.hpp =========
|
2741
|
+
|
2742
|
+
|
2743
|
+
// --------- variant.ipp ---------
|
2744
|
+
#include <variant>
|
2745
|
+
|
2746
|
+
namespace Rice::detail
|
2747
|
+
{
|
2748
|
+
template<typename...Types>
|
2749
|
+
struct Type<std::variant<Types...>>
|
2750
|
+
{
|
2751
|
+
using Tuple_T = std::tuple<Types...>;
|
2752
|
+
|
2753
|
+
template<std::size_t... I>
|
2754
|
+
constexpr static bool verifyTypes(std::index_sequence<I...>& indices)
|
2755
|
+
{
|
2756
|
+
return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
|
2757
|
+
}
|
2758
|
+
|
2759
|
+
template<std::size_t... I>
|
2760
|
+
constexpr static bool verify()
|
2761
|
+
{
|
2762
|
+
auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
|
2763
|
+
return verifyTypes(indices);
|
2764
|
+
}
|
2765
|
+
};
|
2766
|
+
|
2767
|
+
template<typename...Types>
|
2768
|
+
class To_Ruby<std::variant<Types...>>
|
2769
|
+
{
|
2770
|
+
public:
|
2771
|
+
|
2772
|
+
template<typename U, typename V>
|
2773
|
+
static VALUE convertElement(U& data, bool takeOwnership)
|
2774
|
+
{
|
2775
|
+
return To_Ruby<V>().convert(std::forward<V>(std::get<V>(data)));
|
2776
|
+
}
|
2777
|
+
|
2778
|
+
template<typename U, std::size_t... I>
|
2779
|
+
static VALUE convertIterator(U& data, bool takeOwnership, std::index_sequence<I...>& indices)
|
2780
|
+
{
|
2781
|
+
// Create a tuple of the variant types so we can look over the tuple's types
|
2782
|
+
using Tuple_T = std::tuple<Types...>;
|
2783
|
+
|
2784
|
+
/* This is a fold expression. In pseudo code:
|
2785
|
+
|
2786
|
+
for (type in variant.types)
|
2787
|
+
{
|
2788
|
+
if (variant.has_value<type>())
|
2789
|
+
return ToRuby<type>().convert(variant.getValue<type>)
|
2790
|
+
}
|
2791
|
+
|
2792
|
+
The list of variant types is stored in Tuple_T. The number of types is stored in I.
|
2793
|
+
Starting with index 0, get the variant type using td::tuple_element_t<I, Tuple_T>>.
|
2794
|
+
Next check if the variant has a value for that type using std::holds_alternative<T>.
|
2795
|
+
If yes, then call convertElement and save the return value to result. Then use the
|
2796
|
+
comma operator to return true to the fold expression. If the variant does not have
|
2797
|
+
a value for the type then return false.
|
2798
|
+
|
2799
|
+
The fold operator is or (||). If an index returns false, then the next index is evaluated
|
2800
|
+
up until I.
|
2801
|
+
|
2802
|
+
Code inspired by https://www.foonathan.net/2020/05/fold-tricks/ */
|
2803
|
+
|
2804
|
+
VALUE result = Qnil;
|
2805
|
+
|
2806
|
+
#if defined(__GNUC__) || defined(__clang__)
|
2807
|
+
#pragma GCC diagnostic push
|
2808
|
+
#pragma GCC diagnostic ignored "-Wunused-value"
|
2809
|
+
#endif
|
2810
|
+
|
2811
|
+
((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
|
2812
|
+
(result = convertElement<U, std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
|
2813
|
+
|
2814
|
+
#if defined(__GNUC__) || defined(__clang__)
|
2815
|
+
#pragma GCC diagnostic pop
|
2816
|
+
#endif
|
2817
|
+
|
2818
|
+
return result;
|
2819
|
+
}
|
2820
|
+
|
2821
|
+
template<typename U>
|
2822
|
+
static VALUE convert(U& data, bool takeOwnership = false)
|
2823
|
+
{
|
2824
|
+
auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
|
2825
|
+
return convertIterator(data, takeOwnership, indices);
|
2826
|
+
}
|
2827
|
+
|
2828
|
+
template<typename U>
|
2829
|
+
static VALUE convert(U&& data, bool takeOwnership = false)
|
2830
|
+
{
|
2831
|
+
auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
|
2832
|
+
return convertIterator(data, takeOwnership, indices);
|
2833
|
+
}
|
2834
|
+
};
|
2835
|
+
|
2836
|
+
template<typename...Types>
|
2837
|
+
class To_Ruby<std::variant<Types...>&>
|
2838
|
+
{
|
2839
|
+
public:
|
2840
|
+
template<typename U, typename V>
|
2841
|
+
static VALUE convertElement(U& data, bool takeOwnership)
|
2842
|
+
{
|
2843
|
+
if constexpr (std::is_const_v<U>)
|
2844
|
+
{
|
2845
|
+
return To_Ruby<V>().convert(std::get<V>(data));
|
2846
|
+
}
|
2847
|
+
else
|
2848
|
+
{
|
2849
|
+
return To_Ruby<V>().convert(std::forward<V>(std::get<V>(data)));
|
2850
|
+
}
|
2851
|
+
}
|
2852
|
+
|
2853
|
+
template<typename U, std::size_t... I>
|
2854
|
+
static VALUE convertIterator(U& data, bool takeOwnership, std::index_sequence<I...>& indices)
|
2855
|
+
{
|
2856
|
+
// Create a tuple of the variant types so we can look over the tuple's types
|
2857
|
+
using Tuple_T = std::tuple<Types...>;
|
2858
|
+
|
2859
|
+
// See comments above for explanation of this code
|
2860
|
+
VALUE result = Qnil;
|
2861
|
+
|
2862
|
+
#if defined(__GNUC__) || defined(__clang__)
|
2863
|
+
#pragma GCC diagnostic push
|
2864
|
+
#pragma GCC diagnostic ignored "-Wunused-value"
|
2865
|
+
#endif
|
2866
|
+
|
2867
|
+
((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
|
2868
|
+
(result = convertElement<U, std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
|
2869
|
+
|
2870
|
+
#if defined(__GNUC__) || defined(__clang__)
|
2871
|
+
#pragma GCC diagnostic pop
|
2872
|
+
#endif
|
2873
|
+
|
2874
|
+
return result;
|
2875
|
+
}
|
2876
|
+
|
2877
|
+
template<typename U>
|
2878
|
+
static VALUE convert(U& data, bool takeOwnership = false)
|
2879
|
+
{
|
2880
|
+
auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
|
2881
|
+
return convertIterator(data, takeOwnership, indices);
|
2882
|
+
}
|
2883
|
+
};
|
2884
|
+
|
2885
|
+
template<typename...Types>
|
2886
|
+
class From_Ruby<std::variant<Types...>>
|
2887
|
+
{
|
2888
|
+
public:
|
2889
|
+
Convertible is_convertible(VALUE value)
|
2890
|
+
{
|
2891
|
+
Convertible result = Convertible::None;
|
2892
|
+
|
2893
|
+
for_each_tuple(this->fromRubys_,
|
2894
|
+
[&](auto& fromRuby)
|
2895
|
+
{
|
2896
|
+
result = result | fromRuby.is_convertible(value);
|
2897
|
+
});
|
1666
2898
|
|
1667
|
-
|
1668
|
-
|
2899
|
+
return result;
|
2900
|
+
}
|
1669
2901
|
|
1670
|
-
|
1671
|
-
|
1672
|
-
|
1673
|
-
|
1674
|
-
|
2902
|
+
// This method search through a variant's types to figure out which one the
|
2903
|
+
// currently Ruby value best matches. It then returns the index of the type.
|
2904
|
+
int figureIndex(VALUE value)
|
2905
|
+
{
|
2906
|
+
int i = 0;
|
2907
|
+
int index = -1;
|
2908
|
+
Convertible foundConversion = Convertible::None;
|
1675
2909
|
|
1676
|
-
|
1677
|
-
|
1678
|
-
// Add enumerable support
|
1679
|
-
klass_.define_method("to_h", [](T& map)
|
2910
|
+
for_each_tuple(this->fromRubys_,
|
2911
|
+
[&](auto& fromRuby)
|
1680
2912
|
{
|
1681
|
-
|
1682
|
-
std::for_each(map.begin(), map.end(), [&result](const Reference_T pair)
|
1683
|
-
{
|
1684
|
-
VALUE key = detail::To_Ruby<Key_T&>().convert(pair.first);
|
1685
|
-
VALUE value = detail::To_Ruby<To_Ruby_T&>().convert(pair.second);
|
1686
|
-
rb_hash_aset(result, key, value);
|
1687
|
-
});
|
2913
|
+
Convertible isConvertible = fromRuby.is_convertible(value);
|
1688
2914
|
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
2915
|
+
if (isConvertible > foundConversion)
|
2916
|
+
{
|
2917
|
+
index = i;
|
2918
|
+
foundConversion = isConvertible;
|
2919
|
+
}
|
2920
|
+
i++;
|
2921
|
+
});
|
1692
2922
|
|
1693
|
-
|
2923
|
+
if (index == -1)
|
1694
2924
|
{
|
1695
|
-
|
1696
|
-
|
1697
|
-
klass_.define_method("to_s", [](const T& map)
|
1698
|
-
{
|
1699
|
-
auto iter = map.begin();
|
2925
|
+
rb_raise(rb_eArgError, "Could not find converter for variant");
|
2926
|
+
}
|
1700
2927
|
|
1701
|
-
|
1702
|
-
|
2928
|
+
return index;
|
2929
|
+
}
|
1703
2930
|
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
}
|
1710
|
-
stream << iter->first << " => " << iter->second;
|
1711
|
-
}
|
2931
|
+
/* This method loops over each type in the variant, creates a From_Ruby converter,
|
2932
|
+
and then check if the converter can work with the provided Rby value (it checks
|
2933
|
+
the type of the Ruby object to see if it matches the variant type).
|
2934
|
+
If yes, then the converter runs. If no, then the method recursively calls itself
|
2935
|
+
increasing the index.
|
1712
2936
|
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
2937
|
+
We use recursion, with a constexpr, to avoid having to instantiate an instance
|
2938
|
+
of the variant to store results from a fold expression like the To_Ruby code
|
2939
|
+
does above. That allows us to process variants with non default constructible
|
2940
|
+
arguments like std::reference_wrapper. */
|
2941
|
+
template <std::size_t I = 0>
|
2942
|
+
std::variant<Types...> convertInternal(VALUE value, int index)
|
2943
|
+
{
|
2944
|
+
if constexpr (I < std::variant_size_v<std::variant<Types...>>)
|
2945
|
+
{
|
2946
|
+
if (I == index)
|
2947
|
+
{
|
2948
|
+
auto fromRuby = std::get<I>(this->fromRubys_);
|
2949
|
+
return fromRuby.convert(value);
|
1716
2950
|
}
|
1717
2951
|
else
|
1718
2952
|
{
|
1719
|
-
|
1720
|
-
{
|
1721
|
-
return "[Not printable]";
|
1722
|
-
});
|
2953
|
+
return convertInternal<I + 1>(value, index);
|
1723
2954
|
}
|
1724
2955
|
}
|
2956
|
+
rb_raise(rb_eArgError, "Could not find converter for variant");
|
2957
|
+
}
|
1725
2958
|
|
1726
|
-
|
1727
|
-
Data_Type<T> klass_;
|
1728
|
-
};
|
1729
|
-
} // namespace
|
1730
|
-
|
1731
|
-
template<typename T>
|
1732
|
-
Data_Type<T> define_map_under(Object parent, std::string name)
|
1733
|
-
{
|
1734
|
-
if (detail::Registries::instance.types.isDefined<T>())
|
2959
|
+
std::variant<Types...> convert(VALUE value)
|
1735
2960
|
{
|
1736
|
-
|
1737
|
-
|
1738
|
-
parent.const_set_maybe(name, Data_Type<T>().klass());
|
1739
|
-
return Data_Type<T>();
|
2961
|
+
int index = this->figureIndex(value);
|
2962
|
+
return this->convertInternal(value, index);
|
1740
2963
|
}
|
1741
2964
|
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
2965
|
+
private:
|
2966
|
+
// Possible converters we could use for this variant
|
2967
|
+
using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
|
2968
|
+
From_Ruby_Ts fromRubys_;
|
2969
|
+
};
|
1746
2970
|
|
1747
|
-
template<typename
|
1748
|
-
|
2971
|
+
template<typename...Types>
|
2972
|
+
class From_Ruby<std::variant<Types...>&> : public From_Ruby<std::variant<Types...>>
|
1749
2973
|
{
|
1750
|
-
|
2974
|
+
public:
|
2975
|
+
std::variant<Types...>& convert(VALUE value)
|
1751
2976
|
{
|
1752
|
-
|
1753
|
-
|
1754
|
-
|
1755
|
-
return Data_Type<T>();
|
2977
|
+
int index = this->figureIndex(value);
|
2978
|
+
this->converted_ = this->convertInternal(value, index);
|
2979
|
+
return this->converted_;
|
1756
2980
|
}
|
1757
2981
|
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
2982
|
+
private:
|
2983
|
+
std::variant<Types...> converted_;
|
2984
|
+
};
|
2985
|
+
}
|
2986
|
+
|
1762
2987
|
|
2988
|
+
// ========= unique_ptr.hpp =========
|
2989
|
+
|
2990
|
+
namespace Rice::detail
|
2991
|
+
{
|
1763
2992
|
template<typename T>
|
1764
|
-
|
1765
|
-
{
|
1766
|
-
std::string name = detail::typeName(typeid(T));
|
1767
|
-
std::string klassName = detail::makeClassName(name);
|
1768
|
-
Module rb_mRice = define_module("Rice");
|
1769
|
-
Module rb_mStd = define_module_under(rb_mRice, "Std");
|
1770
|
-
return define_map_under<T>(rb_mStd, klassName);
|
1771
|
-
}
|
1772
|
-
|
1773
|
-
namespace detail
|
2993
|
+
class Wrapper<std::unique_ptr<T>> : public WrapperBase
|
1774
2994
|
{
|
1775
|
-
|
1776
|
-
|
1777
|
-
|
1778
|
-
|
1779
|
-
|
1780
|
-
Type<T>::verify();
|
1781
|
-
Type<U>::verify();
|
2995
|
+
public:
|
2996
|
+
Wrapper(std::unique_ptr<T>&& data);
|
2997
|
+
~Wrapper();
|
2998
|
+
void* get() override;
|
2999
|
+
std::unique_ptr<T>& data();
|
1782
3000
|
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
3001
|
+
private:
|
3002
|
+
std::unique_ptr<T> data_;
|
3003
|
+
};
|
3004
|
+
}
|
1787
3005
|
|
1788
|
-
return true;
|
1789
|
-
}
|
1790
|
-
};
|
1791
3006
|
|
1792
|
-
|
1793
|
-
|
1794
|
-
{
|
1795
|
-
static int convertPair(VALUE key, VALUE value, VALUE user_data)
|
1796
|
-
{
|
1797
|
-
std::map<T, U>* result = (std::map<T, U>*)(user_data);
|
3007
|
+
// --------- unique_ptr.ipp ---------
|
3008
|
+
#include <memory>
|
1798
3009
|
|
1799
|
-
|
1800
|
-
|
1801
|
-
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
1805
|
-
|
1806
|
-
}
|
3010
|
+
namespace Rice::detail
|
3011
|
+
{
|
3012
|
+
template<typename T>
|
3013
|
+
inline Wrapper<std::unique_ptr<T>>::Wrapper(std::unique_ptr<T>&& data)
|
3014
|
+
: data_(std::move(data))
|
3015
|
+
{
|
3016
|
+
}
|
1807
3017
|
|
1808
|
-
|
1809
|
-
|
1810
|
-
|
1811
|
-
|
3018
|
+
template<typename T>
|
3019
|
+
inline Wrapper<std::unique_ptr<T>>::~Wrapper()
|
3020
|
+
{
|
3021
|
+
Registries::instance.instances.remove(this->get());
|
3022
|
+
}
|
1812
3023
|
|
1813
|
-
|
1814
|
-
|
1815
|
-
|
3024
|
+
template<typename T>
|
3025
|
+
inline void* Wrapper<std::unique_ptr<T>>::get()
|
3026
|
+
{
|
3027
|
+
return (void*)this->data_.get();
|
3028
|
+
}
|
1816
3029
|
|
1817
|
-
|
1818
|
-
|
1819
|
-
|
3030
|
+
template<typename T>
|
3031
|
+
inline std::unique_ptr<T>& Wrapper<std::unique_ptr<T>>::data()
|
3032
|
+
{
|
3033
|
+
return data_;
|
3034
|
+
}
|
1820
3035
|
|
1821
|
-
|
1822
|
-
|
3036
|
+
template <typename T>
|
3037
|
+
class To_Ruby<std::unique_ptr<T>>
|
3038
|
+
{
|
3039
|
+
public:
|
3040
|
+
VALUE convert(std::unique_ptr<T>& data)
|
1823
3041
|
{
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
explicit From_Ruby(Arg * arg) : arg_(arg)
|
1828
|
-
{
|
1829
|
-
}
|
1830
|
-
|
1831
|
-
Convertible is_convertible(VALUE value)
|
1832
|
-
{
|
1833
|
-
switch (rb_type(value))
|
1834
|
-
{
|
1835
|
-
case RUBY_T_DATA:
|
1836
|
-
return Convertible::Exact;
|
1837
|
-
break;
|
1838
|
-
case RUBY_T_HASH:
|
1839
|
-
return Convertible::Cast;
|
1840
|
-
break;
|
1841
|
-
default:
|
1842
|
-
return Convertible::None;
|
1843
|
-
}
|
1844
|
-
}
|
3042
|
+
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
|
3043
|
+
return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
|
3044
|
+
}
|
1845
3045
|
|
1846
|
-
|
1847
|
-
|
1848
|
-
|
1849
|
-
|
1850
|
-
|
1851
|
-
|
1852
|
-
// This is a wrapped map (hopefully!)
|
1853
|
-
return *Data_Object<std::map<T, U>>::from_ruby(value);
|
1854
|
-
}
|
1855
|
-
case RUBY_T_HASH:
|
1856
|
-
{
|
1857
|
-
// If this an Ruby hash and the mapped type is copyable
|
1858
|
-
if constexpr (std::is_default_constructible_v<U>)
|
1859
|
-
{
|
1860
|
-
return MapFromHash<T, U>::convert(value);
|
1861
|
-
}
|
1862
|
-
}
|
1863
|
-
case RUBY_T_NIL:
|
1864
|
-
{
|
1865
|
-
if (this->arg_ && this->arg_->hasDefaultValue())
|
1866
|
-
{
|
1867
|
-
return this->arg_->template defaultValue<std::map<T, U>>();
|
1868
|
-
}
|
1869
|
-
}
|
1870
|
-
default:
|
1871
|
-
{
|
1872
|
-
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
1873
|
-
detail::protect(rb_obj_classname, value), "std::map");
|
1874
|
-
}
|
1875
|
-
}
|
1876
|
-
}
|
3046
|
+
VALUE convert(std::unique_ptr<T>&& data)
|
3047
|
+
{
|
3048
|
+
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
|
3049
|
+
return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
|
3050
|
+
}
|
3051
|
+
};
|
1877
3052
|
|
1878
|
-
|
1879
|
-
|
1880
|
-
|
3053
|
+
template <typename T>
|
3054
|
+
class To_Ruby<std::unique_ptr<T>&>
|
3055
|
+
{
|
3056
|
+
public:
|
3057
|
+
VALUE convert(std::unique_ptr<T>& data)
|
3058
|
+
{
|
3059
|
+
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
|
3060
|
+
return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, std::move(data), true);
|
3061
|
+
}
|
3062
|
+
};
|
1881
3063
|
|
1882
|
-
|
1883
|
-
|
3064
|
+
template <typename T>
|
3065
|
+
class From_Ruby<std::unique_ptr<T>>
|
3066
|
+
{
|
3067
|
+
public:
|
3068
|
+
Wrapper<std::unique_ptr<T>>* is_same_smart_ptr(VALUE value)
|
1884
3069
|
{
|
1885
|
-
|
1886
|
-
|
3070
|
+
WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
|
3071
|
+
return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
|
3072
|
+
}
|
1887
3073
|
|
1888
|
-
|
1889
|
-
|
1890
|
-
|
3074
|
+
Convertible is_convertible(VALUE value)
|
3075
|
+
{
|
3076
|
+
if (!is_same_smart_ptr(value))
|
3077
|
+
return Convertible::None;
|
1891
3078
|
|
1892
|
-
|
3079
|
+
switch (rb_type(value))
|
1893
3080
|
{
|
1894
|
-
|
1895
|
-
|
1896
|
-
|
1897
|
-
|
1898
|
-
|
1899
|
-
case RUBY_T_HASH:
|
1900
|
-
return Convertible::Cast;
|
1901
|
-
break;
|
1902
|
-
default:
|
1903
|
-
return Convertible::None;
|
1904
|
-
}
|
3081
|
+
case RUBY_T_DATA:
|
3082
|
+
return Convertible::Exact;
|
3083
|
+
break;
|
3084
|
+
default:
|
3085
|
+
return Convertible::None;
|
1905
3086
|
}
|
3087
|
+
}
|
1906
3088
|
|
1907
|
-
|
3089
|
+
std::unique_ptr<T> convert(VALUE value)
|
3090
|
+
{
|
3091
|
+
Wrapper<std::unique_ptr<T>>* wrapper = is_same_smart_ptr(value);
|
3092
|
+
if (!wrapper)
|
1908
3093
|
{
|
1909
|
-
|
1910
|
-
|
1911
|
-
case RUBY_T_DATA:
|
1912
|
-
{
|
1913
|
-
// This is a wrapped map (hopefully!)
|
1914
|
-
return *Data_Object<std::map<T, U>>::from_ruby(value);
|
1915
|
-
}
|
1916
|
-
case RUBY_T_HASH:
|
1917
|
-
{
|
1918
|
-
// If this an Ruby array and the map type is copyable
|
1919
|
-
if constexpr (std::is_default_constructible_v<std::map<T, U>>)
|
1920
|
-
{
|
1921
|
-
this->converted_ = MapFromHash<T, U>::convert(value);
|
1922
|
-
return this->converted_;
|
1923
|
-
}
|
1924
|
-
}
|
1925
|
-
case RUBY_T_NIL:
|
1926
|
-
{
|
1927
|
-
if (this->arg_ && this->arg_->hasDefaultValue())
|
1928
|
-
{
|
1929
|
-
return this->arg_->template defaultValue<std::map<T, U>>();
|
1930
|
-
}
|
1931
|
-
}
|
1932
|
-
default:
|
1933
|
-
{
|
1934
|
-
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
1935
|
-
detail::protect(rb_obj_classname, value), "std::map");
|
1936
|
-
}
|
1937
|
-
}
|
3094
|
+
std::string message = "Invalid smart pointer wrapper";
|
3095
|
+
throw std::runtime_error(message.c_str());
|
1938
3096
|
}
|
3097
|
+
return std::move(wrapper->data());
|
3098
|
+
}
|
3099
|
+
};
|
1939
3100
|
|
1940
|
-
|
1941
|
-
|
1942
|
-
|
1943
|
-
|
3101
|
+
template <typename T>
|
3102
|
+
class From_Ruby<std::unique_ptr<T>&>
|
3103
|
+
{
|
3104
|
+
public:
|
3105
|
+
Wrapper<std::unique_ptr<T>>* is_same_smart_ptr(VALUE value)
|
3106
|
+
{
|
3107
|
+
WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
|
3108
|
+
return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
|
3109
|
+
}
|
1944
3110
|
|
1945
|
-
|
1946
|
-
class From_Ruby<std::map<T, U>*>
|
3111
|
+
Convertible is_convertible(VALUE value)
|
1947
3112
|
{
|
1948
|
-
|
1949
|
-
|
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()
|
@@ -2699,9 +3805,10 @@ namespace Rice
|
|
2699
3805
|
auto begin = vector.begin() + start;
|
2700
3806
|
|
2701
3807
|
// Ruby does not throw an exception when the length is too long
|
2702
|
-
|
3808
|
+
Difference_T size = (Difference_T)vector.size();
|
3809
|
+
if (start + length > size)
|
2703
3810
|
{
|
2704
|
-
length =
|
3811
|
+
length = size - start;
|
2705
3812
|
}
|
2706
3813
|
|
2707
3814
|
auto finish = vector.begin() + start + length;
|
@@ -2718,13 +3825,20 @@ namespace Rice
|
|
2718
3825
|
}
|
2719
3826
|
}, Return().setValue());
|
2720
3827
|
|
3828
|
+
if constexpr (!std::is_same_v<Value_T, bool>)
|
3829
|
+
{
|
3830
|
+
define_buffer<Value_T>();
|
3831
|
+
define_buffer<Value_T*>();
|
3832
|
+
klass_.template define_method<Value_T*(T::*)()>("data", &T::data);
|
3833
|
+
}
|
3834
|
+
|
2721
3835
|
rb_define_alias(klass_, "at", "[]");
|
2722
3836
|
}
|
2723
3837
|
|
2724
3838
|
// Methods that require Value_T to support operator==
|
2725
3839
|
void define_comparable_methods()
|
2726
3840
|
{
|
2727
|
-
if constexpr (detail::is_comparable_v<
|
3841
|
+
if constexpr (detail::is_comparable_v<T>)
|
2728
3842
|
{
|
2729
3843
|
klass_.define_method("delete", [](T& vector, Parameter_T element) -> std::optional<Value_T>
|
2730
3844
|
{
|
@@ -2817,8 +3931,9 @@ namespace Rice
|
|
2817
3931
|
return element;
|
2818
3932
|
});
|
2819
3933
|
|
2820
|
-
|
2821
|
-
|
3934
|
+
rb_define_alias(klass_, "push_back", "push");
|
3935
|
+
rb_define_alias(klass_, "<<", "push");
|
3936
|
+
rb_define_alias(klass_, "append", "push");
|
2822
3937
|
}
|
2823
3938
|
|
2824
3939
|
void define_enumerable()
|
@@ -2886,50 +4001,30 @@ namespace Rice
|
|
2886
4001
|
} // namespace
|
2887
4002
|
|
2888
4003
|
template<typename T>
|
2889
|
-
Data_Type<T
|
4004
|
+
Data_Type<std::vector<T>> define_vector(std::string klassName)
|
2890
4005
|
{
|
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());
|
4006
|
+
using Vector_T = std::vector<T>;
|
4007
|
+
using Data_Type_T = Data_Type<Vector_T>;
|
2896
4008
|
|
2897
|
-
|
4009
|
+
if (klassName.empty())
|
4010
|
+
{
|
4011
|
+
std::string typeName = detail::typeName(typeid(Vector_T));
|
4012
|
+
klassName = detail::rubyClassName(typeName);
|
2898
4013
|
}
|
2899
4014
|
|
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>())
|
4015
|
+
Module rb_mStd = define_module("Std");
|
4016
|
+
if (Data_Type_T::check_defined(klassName, rb_mStd))
|
2910
4017
|
{
|
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>();
|
4018
|
+
return Data_Type_T();
|
2916
4019
|
}
|
2917
4020
|
|
2918
|
-
|
2919
|
-
|
4021
|
+
Identifier id(klassName);
|
4022
|
+
Data_Type_T result = define_class_under<detail::intrinsic_type<Vector_T>>(rb_mStd, id);
|
4023
|
+
stl::VectorHelper helper(result);
|
2920
4024
|
return result;
|
2921
4025
|
}
|
2922
4026
|
|
2923
|
-
|
2924
|
-
Data_Type<T> define_vector_auto()
|
2925
|
-
{
|
2926
|
-
std::string name = detail::typeName(typeid(T));
|
2927
|
-
std::string klassName = detail::makeClassName(name);
|
2928
|
-
Module rb_mRice = define_module("Rice");
|
2929
|
-
Module rb_mStd = define_module_under(rb_mRice, "Std");
|
2930
|
-
return define_vector_under<T>(rb_mStd, klassName);
|
2931
|
-
}
|
2932
|
-
|
4027
|
+
|
2933
4028
|
namespace detail
|
2934
4029
|
{
|
2935
4030
|
template<typename T>
|
@@ -2939,16 +4034,15 @@ namespace Rice
|
|
2939
4034
|
{
|
2940
4035
|
Type<intrinsic_type<T>>::verify();
|
2941
4036
|
|
2942
|
-
if (!
|
4037
|
+
if (!Data_Type<std::vector<T>>::is_defined())
|
2943
4038
|
{
|
2944
|
-
|
4039
|
+
define_vector<T>();
|
2945
4040
|
}
|
2946
4041
|
|
2947
4042
|
return true;
|
2948
4043
|
}
|
2949
4044
|
};
|
2950
4045
|
|
2951
|
-
|
2952
4046
|
template<typename T>
|
2953
4047
|
class From_Ruby<std::vector<T>>
|
2954
4048
|
{
|
@@ -2964,11 +4058,13 @@ namespace Rice
|
|
2964
4058
|
switch (rb_type(value))
|
2965
4059
|
{
|
2966
4060
|
case RUBY_T_DATA:
|
2967
|
-
return Convertible::Exact;
|
4061
|
+
return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
|
2968
4062
|
break;
|
2969
4063
|
case RUBY_T_ARRAY:
|
2970
|
-
|
2971
|
-
|
4064
|
+
if constexpr (std::is_default_constructible_v<T>)
|
4065
|
+
{
|
4066
|
+
return Convertible::Cast;
|
4067
|
+
}
|
2972
4068
|
default:
|
2973
4069
|
return Convertible::None;
|
2974
4070
|
}
|
@@ -2981,7 +4077,7 @@ namespace Rice
|
|
2981
4077
|
case RUBY_T_DATA:
|
2982
4078
|
{
|
2983
4079
|
// This is a wrapped vector (hopefully!)
|
2984
|
-
return *
|
4080
|
+
return *detail::unwrap<std::vector<T>>(value, Data_Type<std::vector<T>>::ruby_data_type(), false);
|
2985
4081
|
}
|
2986
4082
|
case RUBY_T_ARRAY:
|
2987
4083
|
{
|
@@ -2991,13 +4087,6 @@ namespace Rice
|
|
2991
4087
|
return Array(value).to_vector<T>();
|
2992
4088
|
}
|
2993
4089
|
}
|
2994
|
-
case RUBY_T_NIL:
|
2995
|
-
{
|
2996
|
-
if (this->arg_ && this->arg_->hasDefaultValue())
|
2997
|
-
{
|
2998
|
-
return this->arg_->template defaultValue<std::vector<T>>();
|
2999
|
-
}
|
3000
|
-
}
|
3001
4090
|
default:
|
3002
4091
|
{
|
3003
4092
|
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
@@ -3025,11 +4114,13 @@ namespace Rice
|
|
3025
4114
|
switch (rb_type(value))
|
3026
4115
|
{
|
3027
4116
|
case RUBY_T_DATA:
|
3028
|
-
return Convertible::Exact;
|
4117
|
+
return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
|
3029
4118
|
break;
|
3030
4119
|
case RUBY_T_ARRAY:
|
3031
|
-
|
3032
|
-
|
4120
|
+
if constexpr (std::is_default_constructible_v<T>)
|
4121
|
+
{
|
4122
|
+
return Convertible::Cast;
|
4123
|
+
}
|
3033
4124
|
default:
|
3034
4125
|
return Convertible::None;
|
3035
4126
|
}
|
@@ -3042,7 +4133,7 @@ namespace Rice
|
|
3042
4133
|
case RUBY_T_DATA:
|
3043
4134
|
{
|
3044
4135
|
// This is a wrapped vector (hopefully!)
|
3045
|
-
return *
|
4136
|
+
return *detail::unwrap<std::vector<T>>(value, Data_Type<std::vector<T>>::ruby_data_type(), false);
|
3046
4137
|
}
|
3047
4138
|
case RUBY_T_ARRAY:
|
3048
4139
|
{
|
@@ -3053,13 +4144,6 @@ namespace Rice
|
|
3053
4144
|
return this->converted_;
|
3054
4145
|
}
|
3055
4146
|
}
|
3056
|
-
case RUBY_T_NIL:
|
3057
|
-
{
|
3058
|
-
if (this->arg_ && this->arg_->hasDefaultValue())
|
3059
|
-
{
|
3060
|
-
return this->arg_->template defaultValue<std::vector<T>>();
|
3061
|
-
}
|
3062
|
-
}
|
3063
4147
|
default:
|
3064
4148
|
{
|
3065
4149
|
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
@@ -3082,14 +4166,16 @@ namespace Rice
|
|
3082
4166
|
switch (rb_type(value))
|
3083
4167
|
{
|
3084
4168
|
case RUBY_T_DATA:
|
3085
|
-
return Convertible::Exact;
|
4169
|
+
return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
|
3086
4170
|
break;
|
3087
4171
|
case RUBY_T_NIL:
|
3088
4172
|
return Convertible::Exact;
|
3089
4173
|
break;
|
3090
4174
|
case RUBY_T_ARRAY:
|
3091
|
-
|
3092
|
-
|
4175
|
+
if constexpr (std::is_default_constructible_v<T>)
|
4176
|
+
{
|
4177
|
+
return Convertible::Cast;
|
4178
|
+
}
|
3093
4179
|
default:
|
3094
4180
|
return Convertible::None;
|
3095
4181
|
}
|
@@ -3102,7 +4188,7 @@ namespace Rice
|
|
3102
4188
|
case RUBY_T_DATA:
|
3103
4189
|
{
|
3104
4190
|
// This is a wrapped vector (hopefully!)
|
3105
|
-
return
|
4191
|
+
return detail::unwrap<std::vector<T>>(value, Data_Type<std::vector<T>>::ruby_data_type(), false);
|
3106
4192
|
}
|
3107
4193
|
case RUBY_T_ARRAY:
|
3108
4194
|
{
|