rice 4.0.4 → 4.2.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 +37 -0
- data/CONTRIBUTORS.md +2 -0
- data/Rakefile +1 -1
- data/include/rice/rice.hpp +2851 -1955
- data/include/rice/stl.hpp +1654 -287
- data/lib/mkmf-rice.rb +5 -2
- data/lib/version.rb +1 -1
- data/rice/Arg.hpp +6 -6
- data/rice/Arg.ipp +8 -9
- data/rice/Constructor.hpp +2 -2
- data/rice/Data_Object.ipp +69 -15
- data/rice/Data_Object_defn.hpp +1 -15
- data/rice/Data_Type.ipp +56 -86
- data/rice/Data_Type_defn.hpp +14 -17
- data/rice/Director.hpp +0 -1
- data/rice/Enum.ipp +31 -22
- data/rice/Exception.ipp +2 -3
- data/rice/Exception_defn.hpp +5 -5
- data/rice/HandlerRegistration.hpp +15 -0
- data/rice/Return.hpp +5 -4
- data/rice/Return.ipp +8 -3
- data/rice/detail/ExceptionHandler.hpp +8 -0
- data/rice/detail/ExceptionHandler.ipp +28 -0
- data/rice/detail/{Exception_Handler_defn.hpp → ExceptionHandler_defn.hpp} +17 -21
- data/rice/detail/HandlerRegistry.hpp +51 -0
- data/rice/detail/HandlerRegistry.ipp +20 -0
- data/rice/detail/InstanceRegistry.hpp +34 -0
- data/rice/detail/InstanceRegistry.ipp +50 -0
- data/rice/detail/MethodInfo.ipp +1 -1
- data/rice/detail/NativeAttribute.hpp +26 -15
- data/rice/detail/NativeAttribute.ipp +76 -47
- data/rice/detail/NativeFunction.hpp +64 -14
- data/rice/detail/NativeFunction.ipp +138 -86
- data/rice/detail/NativeIterator.hpp +49 -0
- data/rice/detail/NativeIterator.ipp +102 -0
- data/rice/detail/NativeRegistry.hpp +31 -0
- data/rice/detail/{method_data.ipp → NativeRegistry.ipp} +20 -16
- data/rice/detail/Registries.hpp +26 -0
- data/rice/detail/Registries.ipp +23 -0
- data/rice/detail/RubyFunction.hpp +6 -11
- data/rice/detail/RubyFunction.ipp +10 -22
- data/rice/detail/Type.hpp +1 -1
- data/rice/detail/Type.ipp +2 -2
- data/rice/detail/TypeRegistry.hpp +8 -11
- data/rice/detail/TypeRegistry.ipp +3 -28
- data/rice/detail/Wrapper.hpp +0 -2
- data/rice/detail/Wrapper.ipp +74 -24
- data/rice/detail/cpp_protect.hpp +93 -0
- data/rice/detail/default_allocation_func.ipp +1 -1
- data/rice/detail/from_ruby.ipp +206 -2
- data/rice/detail/to_ruby.ipp +39 -5
- data/rice/detail/to_ruby_defn.hpp +1 -1
- data/rice/forward_declares.ipp +6 -0
- data/rice/global_function.hpp +0 -4
- data/rice/global_function.ipp +0 -6
- data/rice/rice.hpp +29 -24
- data/rice/stl.hpp +6 -1
- data/sample/callbacks/extconf.rb +0 -1
- data/sample/enum/extconf.rb +0 -1
- data/sample/inheritance/extconf.rb +0 -1
- data/sample/map/extconf.rb +0 -1
- data/test/embed_ruby.cpp +6 -15
- data/test/ext/t1/extconf.rb +0 -1
- data/test/ext/t2/extconf.rb +0 -1
- data/test/extconf.rb +0 -1
- data/test/test_Array.cpp +20 -24
- data/test/test_Attribute.cpp +6 -6
- data/test/test_Class.cpp +8 -47
- data/test/test_Constructor.cpp +0 -2
- data/test/test_Data_Object.cpp +25 -11
- data/test/test_Data_Type.cpp +124 -28
- data/test/test_Director.cpp +12 -13
- data/test/test_Enum.cpp +65 -26
- data/test/test_Inheritance.cpp +9 -9
- data/test/test_Iterator.cpp +134 -5
- data/test/test_Keep_Alive.cpp +7 -7
- data/test/test_Keep_Alive_No_Wrapper.cpp +80 -0
- data/test/test_Memory_Management.cpp +1 -1
- data/test/test_Module.cpp +25 -62
- data/test/test_Object.cpp +75 -3
- data/test/test_Ownership.cpp +12 -13
- data/test/test_Self.cpp +12 -13
- data/test/test_Stl_Map.cpp +696 -0
- data/test/test_Stl_Optional.cpp +3 -3
- data/test/test_Stl_Pair.cpp +38 -2
- data/test/test_Stl_Reference_Wrapper.cpp +102 -0
- data/test/test_Stl_SmartPointer.cpp +49 -9
- data/test/test_Stl_String.cpp +5 -2
- data/test/test_Stl_Unordered_Map.cpp +697 -0
- data/test/test_Stl_Variant.cpp +346 -0
- data/test/test_Stl_Vector.cpp +200 -41
- data/test/test_Struct.cpp +3 -3
- data/test/test_To_From_Ruby.cpp +8 -2
- data/test/test_Tracking.cpp +239 -0
- data/test/unittest.hpp +21 -4
- metadata +24 -13
- data/rice/detail/Exception_Handler.hpp +0 -8
- data/rice/detail/Exception_Handler.ipp +0 -28
- data/rice/detail/Iterator.hpp +0 -23
- data/rice/detail/Iterator.ipp +0 -47
- data/rice/detail/function_traits.hpp +0 -124
- data/rice/detail/method_data.hpp +0 -29
- data/rice/detail/rice_traits.hpp +0 -116
- data/rice/ruby_try_catch.hpp +0 -86
data/include/rice/stl.hpp
CHANGED
@@ -49,6 +49,11 @@ namespace Rice::detail
|
|
49
49
|
{
|
50
50
|
}
|
51
51
|
|
52
|
+
bool is_convertible(VALUE value)
|
53
|
+
{
|
54
|
+
return rb_type(value) == RUBY_T_STRING;
|
55
|
+
}
|
56
|
+
|
52
57
|
std::string convert(VALUE value)
|
53
58
|
{
|
54
59
|
if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
|
@@ -70,6 +75,11 @@ namespace Rice::detail
|
|
70
75
|
class From_Ruby<std::string*>
|
71
76
|
{
|
72
77
|
public:
|
78
|
+
bool is_convertible(VALUE value)
|
79
|
+
{
|
80
|
+
return rb_type(value) == RUBY_T_STRING;
|
81
|
+
}
|
82
|
+
|
73
83
|
std::string* convert(VALUE value)
|
74
84
|
{
|
75
85
|
detail::protect(rb_check_type, value, (int)T_STRING);
|
@@ -91,6 +101,11 @@ namespace Rice::detail
|
|
91
101
|
{
|
92
102
|
}
|
93
103
|
|
104
|
+
bool is_convertible(VALUE value)
|
105
|
+
{
|
106
|
+
return rb_type(value) == RUBY_T_STRING;
|
107
|
+
}
|
108
|
+
|
94
109
|
std::string& convert(VALUE value)
|
95
110
|
{
|
96
111
|
if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
|
@@ -138,7 +153,7 @@ namespace Rice::detail
|
|
138
153
|
std::vector<VALUE> args(2);
|
139
154
|
args[0] = To_Ruby<T>().convert(data.real());
|
140
155
|
args[1] = To_Ruby<T>().convert(data.imag());
|
141
|
-
return protect(
|
156
|
+
return protect(rb_funcallv, rb_mKernel, rb_intern("Complex"), (int)args.size(), (const VALUE*)args.data());
|
142
157
|
}
|
143
158
|
};
|
144
159
|
|
@@ -148,11 +163,16 @@ namespace Rice::detail
|
|
148
163
|
public:
|
149
164
|
std::complex<T> convert(VALUE value)
|
150
165
|
{
|
151
|
-
VALUE real = protect(
|
152
|
-
VALUE imaginary = protect(
|
166
|
+
VALUE real = protect(rb_funcallv, value, rb_intern("real"), 0, (const VALUE*)nullptr);
|
167
|
+
VALUE imaginary = protect(rb_funcallv, value, rb_intern("imaginary"), 0, (const VALUE*)nullptr);
|
153
168
|
|
154
169
|
return std::complex<T>(From_Ruby<T>().convert(real), From_Ruby<T>().convert(imaginary));
|
155
170
|
}
|
171
|
+
|
172
|
+
bool is_convertible(VALUE value)
|
173
|
+
{
|
174
|
+
return rb_type(value) == RUBY_T_COMPLEX;
|
175
|
+
}
|
156
176
|
};
|
157
177
|
|
158
178
|
template<typename T>
|
@@ -161,18 +181,24 @@ namespace Rice::detail
|
|
161
181
|
public:
|
162
182
|
std::complex<T>& convert(VALUE value)
|
163
183
|
{
|
164
|
-
VALUE real = protect(
|
165
|
-
VALUE imaginary = protect(
|
184
|
+
VALUE real = protect(rb_funcallv, value, rb_intern("real"), 0, (const VALUE*)nullptr);
|
185
|
+
VALUE imaginary = protect(rb_funcallv, value, rb_intern("imaginary"), 0, (const VALUE*)nullptr);
|
166
186
|
this->converted_ = std::complex<T>(From_Ruby<T>().convert(real), From_Ruby<T>().convert(imaginary));
|
167
187
|
|
168
188
|
return this->converted_;
|
169
189
|
}
|
170
190
|
|
191
|
+
bool is_convertible(VALUE value)
|
192
|
+
{
|
193
|
+
return rb_type(value) == RUBY_T_COMPLEX;
|
194
|
+
}
|
195
|
+
|
171
196
|
private:
|
172
197
|
std::complex<T> converted_;
|
173
198
|
};
|
174
199
|
}
|
175
200
|
|
201
|
+
|
176
202
|
// ========= optional.hpp =========
|
177
203
|
|
178
204
|
|
@@ -204,7 +230,7 @@ namespace Rice::detail
|
|
204
230
|
class To_Ruby<std::optional<T>>
|
205
231
|
{
|
206
232
|
public:
|
207
|
-
static VALUE convert(std::optional<T>& data, bool takeOwnership = false)
|
233
|
+
static VALUE convert(const std::optional<T>& data, bool takeOwnership = false)
|
208
234
|
{
|
209
235
|
if (data.has_value())
|
210
236
|
{
|
@@ -221,7 +247,7 @@ namespace Rice::detail
|
|
221
247
|
class To_Ruby<std::optional<T>&>
|
222
248
|
{
|
223
249
|
public:
|
224
|
-
static VALUE convert(std::optional<T>& data, bool takeOwnership = false)
|
250
|
+
static VALUE convert(const std::optional<T>& data, bool takeOwnership = false)
|
225
251
|
{
|
226
252
|
if (data.has_value())
|
227
253
|
{
|
@@ -273,109 +299,1406 @@ namespace Rice::detail
|
|
273
299
|
};
|
274
300
|
}
|
275
301
|
|
276
|
-
// ========= pair.hpp =========
|
277
302
|
|
303
|
+
// ========= reference_wrapper.hpp =========
|
278
304
|
|
279
|
-
|
305
|
+
|
306
|
+
// --------- reference_wrapper.ipp ---------
|
307
|
+
#include <functional>
|
308
|
+
|
309
|
+
namespace Rice::detail
|
280
310
|
{
|
281
311
|
template<typename T>
|
282
|
-
|
312
|
+
struct Type<std::reference_wrapper<T>>
|
313
|
+
{
|
314
|
+
constexpr static bool verify()
|
315
|
+
{
|
316
|
+
return Type<T>::verify();
|
317
|
+
}
|
318
|
+
};
|
283
319
|
|
284
320
|
template<typename T>
|
285
|
-
|
321
|
+
class To_Ruby<std::reference_wrapper<T>>
|
322
|
+
{
|
323
|
+
public:
|
324
|
+
VALUE convert(const std::reference_wrapper<T>& data, bool takeOwnership = false)
|
325
|
+
{
|
326
|
+
return To_Ruby<T&>().convert(data.get());
|
327
|
+
}
|
328
|
+
};
|
329
|
+
|
330
|
+
template<typename T>
|
331
|
+
class From_Ruby<std::reference_wrapper<T>>
|
332
|
+
{
|
333
|
+
public:
|
334
|
+
bool is_convertible(VALUE value)
|
335
|
+
{
|
336
|
+
return true;
|
337
|
+
}
|
338
|
+
|
339
|
+
std::reference_wrapper<T> convert(VALUE value)
|
340
|
+
{
|
341
|
+
return this->converter_.convert(value);
|
342
|
+
}
|
343
|
+
|
344
|
+
private:
|
345
|
+
From_Ruby<T&> converter_;
|
346
|
+
};
|
286
347
|
}
|
287
348
|
|
288
349
|
|
289
|
-
//
|
350
|
+
// ========= smart_ptr.hpp =========
|
290
351
|
|
291
|
-
#include <sstream>
|
292
|
-
#include <stdexcept>
|
293
|
-
#include <utility>
|
294
352
|
|
295
|
-
namespace Rice
|
353
|
+
namespace Rice::detail
|
296
354
|
{
|
297
|
-
|
355
|
+
template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
|
356
|
+
class WrapperSmartPointer : public Wrapper
|
298
357
|
{
|
299
|
-
|
300
|
-
|
358
|
+
public:
|
359
|
+
WrapperSmartPointer(SmartPointer_T<Arg_Ts...>& data);
|
360
|
+
~WrapperSmartPointer();
|
361
|
+
void* get() override;
|
362
|
+
SmartPointer_T<Arg_Ts...>& data();
|
363
|
+
|
364
|
+
private:
|
365
|
+
SmartPointer_T<Arg_Ts...> data_;
|
366
|
+
};
|
367
|
+
}
|
368
|
+
|
369
|
+
|
370
|
+
// --------- smart_ptr.ipp ---------
|
371
|
+
|
372
|
+
#include <assert.h>
|
373
|
+
#include <memory>
|
374
|
+
|
375
|
+
namespace Rice::detail
|
376
|
+
{
|
377
|
+
// ---- WrapperSmartPointer ------
|
378
|
+
template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
|
379
|
+
inline WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::WrapperSmartPointer(SmartPointer_T<Arg_Ts...>& data)
|
380
|
+
: data_(std::move(data))
|
381
|
+
{
|
382
|
+
}
|
383
|
+
|
384
|
+
template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
|
385
|
+
inline WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::~WrapperSmartPointer()
|
386
|
+
{
|
387
|
+
Registries::instance.instances.remove(this->get());
|
388
|
+
}
|
389
|
+
|
390
|
+
template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
|
391
|
+
inline void* WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::get()
|
392
|
+
{
|
393
|
+
return (void*)this->data_.get();
|
394
|
+
}
|
395
|
+
|
396
|
+
template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
|
397
|
+
inline SmartPointer_T<Arg_Ts...>& WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::data()
|
398
|
+
{
|
399
|
+
return data_;
|
400
|
+
}
|
401
|
+
|
402
|
+
// ---- unique_ptr ------
|
403
|
+
template <typename T>
|
404
|
+
class To_Ruby<std::unique_ptr<T>>
|
405
|
+
{
|
406
|
+
public:
|
407
|
+
VALUE convert(std::unique_ptr<T>& data)
|
301
408
|
{
|
302
|
-
|
303
|
-
|
409
|
+
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
|
410
|
+
|
411
|
+
// Use custom wrapper type
|
412
|
+
using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
|
413
|
+
return detail::wrap<std::unique_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
|
414
|
+
}
|
415
|
+
};
|
416
|
+
|
417
|
+
template <typename T>
|
418
|
+
class From_Ruby<std::unique_ptr<T>&>
|
419
|
+
{
|
420
|
+
public:
|
421
|
+
std::unique_ptr<T>& convert(VALUE value)
|
422
|
+
{
|
423
|
+
Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
|
424
|
+
|
425
|
+
using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
|
426
|
+
Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
|
427
|
+
if (!smartWrapper)
|
304
428
|
{
|
305
|
-
|
306
|
-
|
307
|
-
this->define_access_methods();
|
308
|
-
this->define_modify_methods();
|
309
|
-
this->define_to_s();
|
429
|
+
std::string message = "Invalid smart pointer wrapper";
|
430
|
+
throw std::runtime_error(message.c_str());
|
310
431
|
}
|
432
|
+
return smartWrapper->data();
|
433
|
+
}
|
434
|
+
};
|
311
435
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
436
|
+
template<typename T>
|
437
|
+
struct Type<std::unique_ptr<T>>
|
438
|
+
{
|
439
|
+
static bool verify()
|
440
|
+
{
|
441
|
+
return Type<T>::verify();
|
442
|
+
}
|
443
|
+
};
|
444
|
+
|
445
|
+
// ----- shared_ptr -------------
|
446
|
+
template <typename T>
|
447
|
+
class To_Ruby<std::shared_ptr<T>>
|
448
|
+
{
|
449
|
+
public:
|
450
|
+
VALUE convert(std::shared_ptr<T>& data)
|
451
|
+
{
|
452
|
+
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
|
453
|
+
|
454
|
+
// Use custom wrapper type
|
455
|
+
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
|
456
|
+
return detail::wrap<std::shared_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
|
457
|
+
}
|
458
|
+
};
|
459
|
+
|
460
|
+
template <typename T>
|
461
|
+
class From_Ruby<std::shared_ptr<T>>
|
462
|
+
{
|
463
|
+
public:
|
464
|
+
From_Ruby() = default;
|
465
|
+
|
466
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
467
|
+
{
|
468
|
+
}
|
469
|
+
|
470
|
+
std::shared_ptr<T> convert(VALUE value)
|
471
|
+
{
|
472
|
+
if(value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
|
473
|
+
return this->arg_->template defaultValue<std::shared_ptr<T>>();
|
316
474
|
}
|
317
475
|
|
318
|
-
|
476
|
+
Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
|
477
|
+
|
478
|
+
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
|
479
|
+
Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
|
480
|
+
if (!smartWrapper)
|
319
481
|
{
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
482
|
+
std::string message = "Invalid smart pointer wrapper";
|
483
|
+
throw std::runtime_error(message.c_str());
|
484
|
+
}
|
485
|
+
return smartWrapper->data();
|
486
|
+
}
|
487
|
+
|
488
|
+
private:
|
489
|
+
Arg* arg_ = nullptr;
|
490
|
+
};
|
491
|
+
|
492
|
+
template <typename T>
|
493
|
+
class From_Ruby<std::shared_ptr<T>&>
|
494
|
+
{
|
495
|
+
public:
|
496
|
+
From_Ruby() = default;
|
497
|
+
|
498
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
499
|
+
{
|
500
|
+
}
|
501
|
+
|
502
|
+
std::shared_ptr<T>& convert(VALUE value)
|
503
|
+
{
|
504
|
+
if(value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
|
505
|
+
return this->arg_->template defaultValue<std::shared_ptr<T>>();
|
335
506
|
}
|
336
507
|
|
337
|
-
|
508
|
+
Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
|
509
|
+
|
510
|
+
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
|
511
|
+
Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
|
512
|
+
if (!smartWrapper)
|
338
513
|
{
|
339
|
-
|
340
|
-
|
341
|
-
{
|
342
|
-
return self.first;
|
343
|
-
})
|
344
|
-
.define_method("second", [](T& self) -> typename T::second_type&
|
345
|
-
{
|
346
|
-
return self.second;
|
347
|
-
});
|
514
|
+
std::string message = "Invalid smart pointer wrapper";
|
515
|
+
throw std::runtime_error(message.c_str());
|
348
516
|
}
|
517
|
+
return smartWrapper->data();
|
518
|
+
}
|
349
519
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
520
|
+
private:
|
521
|
+
Arg* arg_ = nullptr;
|
522
|
+
};
|
523
|
+
|
524
|
+
template<typename T>
|
525
|
+
struct Type<std::shared_ptr<T>>
|
526
|
+
{
|
527
|
+
static bool verify()
|
528
|
+
{
|
529
|
+
return Type<T>::verify();
|
530
|
+
}
|
531
|
+
};
|
532
|
+
}
|
533
|
+
|
534
|
+
|
535
|
+
// ========= monostate.hpp =========
|
536
|
+
|
537
|
+
|
538
|
+
// --------- monostate.ipp ---------
|
539
|
+
#include <variant>
|
540
|
+
|
541
|
+
namespace Rice::detail
|
542
|
+
{
|
543
|
+
template<>
|
544
|
+
struct Type<std::monostate>
|
545
|
+
{
|
546
|
+
constexpr static bool verify()
|
547
|
+
{
|
548
|
+
return true;
|
549
|
+
}
|
550
|
+
};
|
551
|
+
|
552
|
+
template<>
|
553
|
+
class To_Ruby<std::monostate>
|
554
|
+
{
|
555
|
+
public:
|
556
|
+
VALUE convert(const std::monostate& _)
|
557
|
+
{
|
558
|
+
return Qnil;
|
559
|
+
}
|
560
|
+
};
|
561
|
+
|
562
|
+
template<>
|
563
|
+
class To_Ruby<std::monostate&>
|
564
|
+
{
|
565
|
+
public:
|
566
|
+
static VALUE convert(const std::monostate& data, bool takeOwnership = false)
|
567
|
+
{
|
568
|
+
return Qnil;
|
569
|
+
}
|
570
|
+
};
|
571
|
+
|
572
|
+
template<>
|
573
|
+
class From_Ruby<std::monostate>
|
574
|
+
{
|
575
|
+
public:
|
576
|
+
bool is_convertible(VALUE value)
|
577
|
+
{
|
578
|
+
return false;
|
579
|
+
}
|
580
|
+
|
581
|
+
std::monostate convert(VALUE value)
|
582
|
+
{
|
583
|
+
return std::monostate();
|
584
|
+
}
|
585
|
+
};
|
586
|
+
|
587
|
+
template<>
|
588
|
+
class From_Ruby<std::monostate&>
|
589
|
+
{
|
590
|
+
public:
|
591
|
+
bool is_convertible(VALUE value)
|
592
|
+
{
|
593
|
+
return false;
|
594
|
+
}
|
595
|
+
|
596
|
+
std::monostate& convert(VALUE value)
|
597
|
+
{
|
598
|
+
return this->converted_;
|
599
|
+
}
|
600
|
+
|
601
|
+
private:
|
602
|
+
std::monostate converted_ = std::monostate();
|
603
|
+
};
|
604
|
+
}
|
605
|
+
|
606
|
+
|
607
|
+
// ========= variant.hpp =========
|
608
|
+
|
609
|
+
|
610
|
+
// --------- variant.ipp ---------
|
611
|
+
#include <variant>
|
612
|
+
|
613
|
+
namespace Rice::detail
|
614
|
+
{
|
615
|
+
template<typename...Types>
|
616
|
+
struct Type<std::variant<Types...>>
|
617
|
+
{
|
618
|
+
using Tuple_T = std::tuple<Types...>;
|
619
|
+
|
620
|
+
template<std::size_t... I>
|
621
|
+
constexpr static bool verifyTypes(std::index_sequence<I...>& indices)
|
622
|
+
{
|
623
|
+
return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
|
624
|
+
}
|
625
|
+
|
626
|
+
template<std::size_t... I>
|
627
|
+
constexpr static bool verify()
|
628
|
+
{
|
629
|
+
auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
|
630
|
+
return verifyTypes(indices);
|
631
|
+
}
|
632
|
+
};
|
633
|
+
|
634
|
+
template<typename...Types>
|
635
|
+
class To_Ruby<std::variant<Types...>>
|
636
|
+
{
|
637
|
+
public:
|
638
|
+
|
639
|
+
template<typename T>
|
640
|
+
static VALUE convertElement(const std::variant<Types...>& data, bool takeOwnership)
|
641
|
+
{
|
642
|
+
return To_Ruby<T>().convert(std::get<T>(data));
|
643
|
+
}
|
644
|
+
|
645
|
+
template<std::size_t... I>
|
646
|
+
static VALUE convertIterator(const std::variant<Types...>& data, bool takeOwnership, std::index_sequence<I...>& indices)
|
647
|
+
{
|
648
|
+
// Create a tuple of the variant types so we can look over the tuple's types
|
649
|
+
using Tuple_T = std::tuple<Types...>;
|
650
|
+
|
651
|
+
/* This is a fold expression. In pseudo code:
|
652
|
+
|
653
|
+
for (type in variant.types)
|
654
|
+
{
|
655
|
+
if (variant.has_value<type>())
|
656
|
+
return ToRuby<type>().convert(variant.getValue<type>)
|
657
|
+
}
|
658
|
+
|
659
|
+
The list of variant types is stored in Tuple_T. The number of types is stored in I.
|
660
|
+
Starting with index 0, get the variant type using td::tuple_element_t<I, Tuple_T>>.
|
661
|
+
Next check if the variant has a value for that type using std::holds_alternative<T>.
|
662
|
+
If yes, then call convertElement and save the return value to result. Then use the
|
663
|
+
comma operator to return true to the fold expression. If the variant does not have
|
664
|
+
a value for the type then return false.
|
665
|
+
|
666
|
+
The fold operator is or (||). If an index returns false, then the next index is evaulated
|
667
|
+
up until I.
|
668
|
+
|
669
|
+
Code inspired by https://www.foonathan.net/2020/05/fold-tricks/ */
|
670
|
+
|
671
|
+
VALUE result = Qnil;
|
672
|
+
((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
|
673
|
+
(result = convertElement<std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
|
674
|
+
|
675
|
+
return result;
|
676
|
+
}
|
677
|
+
|
678
|
+
static VALUE convert(const std::variant<Types...>& data, bool takeOwnership = false)
|
679
|
+
{
|
680
|
+
auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
|
681
|
+
return convertIterator(data, takeOwnership, indices);
|
682
|
+
}
|
683
|
+
};
|
684
|
+
|
685
|
+
template<typename...Types>
|
686
|
+
class To_Ruby<std::variant<Types...>&>
|
687
|
+
{
|
688
|
+
public:
|
689
|
+
template<typename T>
|
690
|
+
static VALUE convertElement(const std::variant<Types...>& data, bool takeOwnership)
|
691
|
+
{
|
692
|
+
return To_Ruby<T>().convert(std::get<T>(data));
|
693
|
+
}
|
694
|
+
|
695
|
+
template<std::size_t... I>
|
696
|
+
static VALUE convertIterator(const std::variant<Types...>& data, bool takeOwnership, std::index_sequence<I...>& indices)
|
697
|
+
{
|
698
|
+
// Create a tuple of the variant types so we can look over the tuple's types
|
699
|
+
using Tuple_T = std::tuple<Types...>;
|
700
|
+
|
701
|
+
// See comments above for explanation of this code
|
702
|
+
VALUE result = Qnil;
|
703
|
+
((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
|
704
|
+
(result = convertElement<std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
|
705
|
+
|
706
|
+
return result;
|
707
|
+
}
|
708
|
+
|
709
|
+
static VALUE convert(const std::variant<Types...>& data, bool takeOwnership = false)
|
710
|
+
{
|
711
|
+
auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
|
712
|
+
return convertIterator(data, takeOwnership, indices);
|
713
|
+
}
|
714
|
+
};
|
715
|
+
|
716
|
+
template<typename...Types>
|
717
|
+
class From_Ruby<std::variant<Types...>>
|
718
|
+
{
|
719
|
+
private:
|
720
|
+
// Possible converters we could use for this variant
|
721
|
+
using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
|
722
|
+
|
723
|
+
public:
|
724
|
+
/* This method loops over each type in the variant, creates a From_Ruby converter,
|
725
|
+
and then check if the converter can work with the provided Rby value (it checks
|
726
|
+
the type of the Ruby object to see if it matches the variant type).
|
727
|
+
If yes, then the converter runs. If no, then the method recursively calls itself
|
728
|
+
increasing the index.
|
729
|
+
|
730
|
+
We use recursion, with a constexpr, to avoid having to instantiate an instance
|
731
|
+
of the variant to store results from a fold expression like the To_Ruby code
|
732
|
+
does above. That allows us to process variants with non default constructible
|
733
|
+
arguments like std::reference_wrapper. */
|
734
|
+
template <std::size_t I = 0>
|
735
|
+
std::variant<Types...> convertInternal(VALUE value)
|
736
|
+
{
|
737
|
+
// Loop over each possible type in the variant.
|
738
|
+
if constexpr (I < std::variant_size_v<std::variant<Types...>>)
|
739
|
+
{
|
740
|
+
// Get the converter for the current index
|
741
|
+
typename std::tuple_element_t<I, From_Ruby_Ts> converter;
|
742
|
+
|
743
|
+
// See if it will work
|
744
|
+
if (converter.is_convertible(value))
|
745
|
+
{
|
746
|
+
return converter.convert(value);
|
747
|
+
}
|
748
|
+
else
|
749
|
+
{
|
750
|
+
return convertInternal<I + 1>(value);
|
751
|
+
}
|
752
|
+
}
|
753
|
+
throw std::runtime_error("Could not find converter for variant");
|
754
|
+
}
|
755
|
+
|
756
|
+
std::variant<Types...> convert(VALUE value)
|
757
|
+
{
|
758
|
+
return convertInternal(value);
|
759
|
+
}
|
760
|
+
};
|
761
|
+
|
762
|
+
template<typename...Types>
|
763
|
+
class From_Ruby<std::variant<Types...>&>
|
764
|
+
{
|
765
|
+
private:
|
766
|
+
// Possible converters we could use for this variant
|
767
|
+
using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
|
768
|
+
|
769
|
+
public:
|
770
|
+
template <std::size_t I = 0>
|
771
|
+
std::variant<Types...> convertInternal(VALUE value)
|
772
|
+
{
|
773
|
+
// Loop over each possible type in the variant
|
774
|
+
if constexpr (I < std::variant_size_v<std::variant<Types...>>)
|
775
|
+
{
|
776
|
+
// Get the converter for the current index
|
777
|
+
typename std::tuple_element_t<I, From_Ruby_Ts> converter;
|
778
|
+
|
779
|
+
// See if it will work
|
780
|
+
if (converter.is_convertible(value))
|
781
|
+
{
|
782
|
+
return converter.convert(value);
|
783
|
+
}
|
784
|
+
else
|
785
|
+
{
|
786
|
+
return convertInternal<I + 1>(value);
|
787
|
+
}
|
788
|
+
}
|
789
|
+
throw std::runtime_error("Could not find converter for variant");
|
790
|
+
}
|
791
|
+
|
792
|
+
std::variant<Types...> convert(VALUE value)
|
793
|
+
{
|
794
|
+
return convertInternal(value);
|
795
|
+
}
|
796
|
+
};
|
797
|
+
}
|
798
|
+
|
799
|
+
|
800
|
+
// ========= pair.hpp =========
|
801
|
+
|
802
|
+
|
803
|
+
namespace Rice
|
804
|
+
{
|
805
|
+
template<typename T>
|
806
|
+
Data_Type<T> define_pair(std::string name);
|
807
|
+
|
808
|
+
template<typename T>
|
809
|
+
Data_Type<T> define_pair_under(Object module, std::string name);
|
810
|
+
}
|
811
|
+
|
812
|
+
|
813
|
+
// --------- pair.ipp ---------
|
814
|
+
|
815
|
+
#include <sstream>
|
816
|
+
#include <stdexcept>
|
817
|
+
#include <utility>
|
818
|
+
|
819
|
+
namespace Rice
|
820
|
+
{
|
821
|
+
namespace stl
|
822
|
+
{
|
823
|
+
template<typename T>
|
824
|
+
class PairHelper
|
825
|
+
{
|
826
|
+
public:
|
827
|
+
PairHelper(Data_Type<T> klass) : klass_(klass)
|
828
|
+
{
|
829
|
+
this->define_constructor();
|
830
|
+
this->define_copyable_methods();
|
831
|
+
this->define_access_methods();
|
832
|
+
this->define_modify_methods();
|
833
|
+
this->define_to_s();
|
834
|
+
}
|
835
|
+
|
836
|
+
private:
|
837
|
+
void define_constructor()
|
838
|
+
{
|
839
|
+
klass_.define_constructor(Constructor<T, typename T::first_type&, typename T::second_type&>());
|
840
|
+
}
|
841
|
+
|
842
|
+
void define_copyable_methods()
|
843
|
+
{
|
844
|
+
if constexpr (std::is_copy_constructible_v<typename T::first_type> && std::is_copy_constructible_v<typename T::second_type>)
|
845
|
+
{
|
846
|
+
klass_.define_method("copy", [](T& pair) -> T
|
847
|
+
{
|
848
|
+
return pair;
|
849
|
+
});
|
850
|
+
}
|
851
|
+
else
|
852
|
+
{
|
853
|
+
klass_.define_method("copy", [](T& pair) -> T
|
854
|
+
{
|
855
|
+
throw std::runtime_error("Cannot copy pair with non-copy constructible types");
|
856
|
+
return pair;
|
857
|
+
});
|
858
|
+
}
|
859
|
+
}
|
860
|
+
|
861
|
+
void define_access_methods()
|
862
|
+
{
|
863
|
+
// Access methods
|
864
|
+
klass_.define_method("first", [](T& pair) -> typename T::first_type&
|
865
|
+
{
|
866
|
+
return pair.first;
|
867
|
+
})
|
868
|
+
.define_method("second", [](T& pair) -> typename T::second_type&
|
869
|
+
{
|
870
|
+
return pair.second;
|
871
|
+
});
|
872
|
+
}
|
873
|
+
|
874
|
+
void define_modify_methods()
|
875
|
+
{
|
876
|
+
// Access methods
|
877
|
+
klass_.define_method("first=", [](T& pair, typename T::first_type& value) -> typename T::first_type&
|
878
|
+
{
|
879
|
+
if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::first_type>>>)
|
880
|
+
{
|
881
|
+
throw std::runtime_error("Cannot set pair.first since it is a constant");
|
882
|
+
}
|
883
|
+
else
|
884
|
+
{
|
885
|
+
pair.first = value;
|
886
|
+
return pair.first;
|
887
|
+
}
|
888
|
+
})
|
889
|
+
.define_method("second=", [](T& pair, typename T::second_type& value) -> typename T::second_type&
|
890
|
+
{
|
891
|
+
if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::second_type>>>)
|
892
|
+
{
|
893
|
+
throw std::runtime_error("Cannot set pair.second since it is a constant");
|
894
|
+
}
|
895
|
+
else
|
896
|
+
{
|
897
|
+
pair.second = value;
|
898
|
+
return pair.second;
|
899
|
+
}
|
900
|
+
});
|
901
|
+
}
|
902
|
+
|
903
|
+
void define_to_s()
|
904
|
+
{
|
905
|
+
if constexpr (detail::is_ostreamable_v<typename T::first_type> && detail::is_ostreamable_v<typename T::second_type>)
|
906
|
+
{
|
907
|
+
klass_.define_method("to_s", [](const T& pair)
|
908
|
+
{
|
909
|
+
std::stringstream stream;
|
910
|
+
stream << "[" << pair.first << ", " << pair.second << "]";
|
911
|
+
return stream.str();
|
912
|
+
});
|
913
|
+
}
|
914
|
+
else
|
915
|
+
{
|
916
|
+
klass_.define_method("to_s", [](const T& pair)
|
917
|
+
{
|
918
|
+
return "[Not printable]";
|
919
|
+
});
|
920
|
+
}
|
921
|
+
}
|
922
|
+
|
923
|
+
private:
|
924
|
+
Data_Type<T> klass_;
|
925
|
+
};
|
926
|
+
} // namespace
|
927
|
+
|
928
|
+
template<typename T>
|
929
|
+
Data_Type<T> define_pair_under(Object module, std::string name)
|
930
|
+
{
|
931
|
+
if (detail::Registries::instance.types.isDefined<T>())
|
932
|
+
{
|
933
|
+
// If the pair has been previously seen it will be registered but may
|
934
|
+
// not be associated with the constant Module::<name>
|
935
|
+
module.const_set_maybe(name, Data_Type<T>().klass());
|
936
|
+
return Data_Type<T>();
|
937
|
+
}
|
938
|
+
|
939
|
+
Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(module, name.c_str());
|
940
|
+
stl::PairHelper helper(result);
|
941
|
+
return result;
|
942
|
+
}
|
943
|
+
|
944
|
+
template<typename T>
|
945
|
+
Data_Type<T> define_pair(std::string name)
|
946
|
+
{
|
947
|
+
if (detail::Registries::instance.types.isDefined<T>())
|
948
|
+
{
|
949
|
+
// If the pair has been previously seen it will be registered but may
|
950
|
+
// not be associated with the constant Object::<name>
|
951
|
+
Object(rb_cObject).const_set_maybe(name, Data_Type<T>().klass());
|
952
|
+
return Data_Type<T>();
|
953
|
+
}
|
954
|
+
|
955
|
+
Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
|
956
|
+
stl::PairHelper<T> helper(result);
|
957
|
+
return result;
|
958
|
+
}
|
959
|
+
|
960
|
+
template<typename T>
|
961
|
+
Data_Type<T> define_pair_auto()
|
962
|
+
{
|
963
|
+
std::string klassName = detail::makeClassName(typeid(T));
|
964
|
+
Module rb_mRice = define_module("Rice");
|
965
|
+
Module rb_mpair = define_module_under(rb_mRice, "Std");
|
966
|
+
return define_pair_under<T>(rb_mpair, klassName);
|
967
|
+
}
|
968
|
+
|
969
|
+
namespace detail
|
970
|
+
{
|
971
|
+
template<typename T1, typename T2>
|
972
|
+
struct Type<std::pair<T1, T2>>
|
973
|
+
{
|
974
|
+
static bool verify()
|
975
|
+
{
|
976
|
+
detail::verifyType<T1>();
|
977
|
+
detail::verifyType<T2>();
|
978
|
+
|
979
|
+
if (!detail::Registries::instance.types.isDefined<std::pair<T1, T2>>())
|
980
|
+
{
|
981
|
+
define_pair_auto<std::pair<T1, T2>>();
|
982
|
+
}
|
983
|
+
|
984
|
+
return true;
|
985
|
+
}
|
986
|
+
};
|
987
|
+
}
|
988
|
+
}
|
989
|
+
|
990
|
+
|
991
|
+
|
992
|
+
// ========= map.hpp =========
|
993
|
+
|
994
|
+
|
995
|
+
namespace Rice
|
996
|
+
{
|
997
|
+
template<typename U>
|
998
|
+
Data_Type<U> define_map(std::string name);
|
999
|
+
|
1000
|
+
template<typename U>
|
1001
|
+
Data_Type<U> define_map_under(Object module, std::string name);
|
1002
|
+
}
|
1003
|
+
|
1004
|
+
|
1005
|
+
// --------- map.ipp ---------
|
1006
|
+
|
1007
|
+
#include <sstream>
|
1008
|
+
#include <stdexcept>
|
1009
|
+
#include <map>
|
1010
|
+
#include <type_traits>
|
1011
|
+
#include <variant>
|
1012
|
+
|
1013
|
+
namespace Rice
|
1014
|
+
{
|
1015
|
+
namespace stl
|
1016
|
+
{
|
1017
|
+
template<typename T>
|
1018
|
+
class MapHelper
|
1019
|
+
{
|
1020
|
+
using Key_T = typename T::key_type;
|
1021
|
+
using Mapped_T = typename T::mapped_type;
|
1022
|
+
using Value_T = typename T::value_type;
|
1023
|
+
using Size_T = typename T::size_type;
|
1024
|
+
using Difference_T = typename T::difference_type;
|
1025
|
+
|
1026
|
+
public:
|
1027
|
+
MapHelper(Data_Type<T> klass) : klass_(klass)
|
1028
|
+
{
|
1029
|
+
this->register_pair();
|
1030
|
+
this->define_constructor();
|
1031
|
+
this->define_copyable_methods();
|
1032
|
+
this->define_capacity_methods();
|
1033
|
+
this->define_access_methods();
|
1034
|
+
this->define_comparable_methods();
|
1035
|
+
this->define_modify_methods();
|
1036
|
+
this->define_enumerable();
|
1037
|
+
this->define_to_s();
|
1038
|
+
this->define_to_hash();
|
1039
|
+
}
|
1040
|
+
|
1041
|
+
private:
|
1042
|
+
|
1043
|
+
void register_pair()
|
1044
|
+
{
|
1045
|
+
define_pair_auto<Value_T>();
|
1046
|
+
}
|
1047
|
+
|
1048
|
+
void define_constructor()
|
1049
|
+
{
|
1050
|
+
klass_.define_constructor(Constructor<T>());
|
1051
|
+
}
|
1052
|
+
|
1053
|
+
void define_copyable_methods()
|
1054
|
+
{
|
1055
|
+
if constexpr (std::is_copy_constructible_v<Value_T>)
|
1056
|
+
{
|
1057
|
+
klass_.define_method("copy", [](T& map) -> T
|
1058
|
+
{
|
1059
|
+
return map;
|
1060
|
+
});
|
1061
|
+
}
|
1062
|
+
else
|
1063
|
+
{
|
1064
|
+
klass_.define_method("copy", [](T& map) -> T
|
1065
|
+
{
|
1066
|
+
throw std::runtime_error("Cannot copy maps with non-copy constructible types");
|
1067
|
+
return map;
|
1068
|
+
});
|
1069
|
+
}
|
1070
|
+
}
|
1071
|
+
|
1072
|
+
void define_capacity_methods()
|
1073
|
+
{
|
1074
|
+
klass_.define_method("empty?", &T::empty)
|
1075
|
+
.define_method("max_size", &T::max_size)
|
1076
|
+
.define_method("size", &T::size);
|
1077
|
+
|
1078
|
+
rb_define_alias(klass_, "count", "size");
|
1079
|
+
rb_define_alias(klass_, "length", "size");
|
1080
|
+
}
|
1081
|
+
|
1082
|
+
void define_access_methods()
|
1083
|
+
{
|
1084
|
+
// Access methods
|
1085
|
+
klass_.define_method("[]", [](const T& map, const Key_T& key) -> std::optional<Mapped_T>
|
1086
|
+
{
|
1087
|
+
auto iter = map.find(key);
|
1088
|
+
|
1089
|
+
if (iter != map.end())
|
1090
|
+
{
|
1091
|
+
return iter->second;
|
1092
|
+
}
|
1093
|
+
else
|
1094
|
+
{
|
1095
|
+
return std::nullopt;
|
1096
|
+
}
|
1097
|
+
})
|
1098
|
+
.define_method("include?", [](T& map, Key_T& key) -> bool
|
1099
|
+
{
|
1100
|
+
return map.find(key) != map.end();
|
1101
|
+
})
|
1102
|
+
.define_method("keys", [](T& map) -> std::vector<Key_T>
|
1103
|
+
{
|
1104
|
+
std::vector<Key_T> result;
|
1105
|
+
std::transform(map.begin(), map.end(), std::back_inserter(result),
|
1106
|
+
[](const auto& pair)
|
1107
|
+
{
|
1108
|
+
return pair.first;
|
1109
|
+
});
|
1110
|
+
|
1111
|
+
return result;
|
1112
|
+
})
|
1113
|
+
.define_method("values", [](T& map) -> std::vector<Mapped_T>
|
1114
|
+
{
|
1115
|
+
std::vector<Mapped_T> result;
|
1116
|
+
std::transform(map.begin(), map.end(), std::back_inserter(result),
|
1117
|
+
[](const auto& pair)
|
1118
|
+
{
|
1119
|
+
return pair.second;
|
1120
|
+
});
|
1121
|
+
|
1122
|
+
return result;
|
1123
|
+
});
|
1124
|
+
|
1125
|
+
rb_define_alias(klass_, "has_key", "include?");
|
1126
|
+
}
|
1127
|
+
|
1128
|
+
// Methods that require Value_T to support operator==
|
1129
|
+
void define_comparable_methods()
|
1130
|
+
{
|
1131
|
+
if constexpr (detail::is_comparable_v<Mapped_T>)
|
1132
|
+
{
|
1133
|
+
klass_.define_method("value?", [](T& map, Mapped_T& value) -> bool
|
1134
|
+
{
|
1135
|
+
auto it = std::find_if(map.begin(), map.end(),
|
1136
|
+
[&value](auto& pair)
|
1137
|
+
{
|
1138
|
+
return pair.second == value;
|
1139
|
+
});
|
1140
|
+
|
1141
|
+
return it != map.end();
|
1142
|
+
});
|
1143
|
+
}
|
1144
|
+
else
|
1145
|
+
{
|
1146
|
+
klass_.define_method("value?", [](T& map, Mapped_T& value) -> bool
|
1147
|
+
{
|
1148
|
+
return false;
|
1149
|
+
});
|
1150
|
+
}
|
1151
|
+
|
1152
|
+
rb_define_alias(klass_, "has_value", "value?");
|
1153
|
+
}
|
1154
|
+
|
1155
|
+
void define_modify_methods()
|
1156
|
+
{
|
1157
|
+
klass_.define_method("clear", &T::clear)
|
1158
|
+
.define_method("delete", [](T& map, Key_T& key) -> std::optional<Mapped_T>
|
1159
|
+
{
|
1160
|
+
auto iter = map.find(key);
|
1161
|
+
|
1162
|
+
if (iter != map.end())
|
1163
|
+
{
|
1164
|
+
Mapped_T result = iter->second;
|
1165
|
+
map.erase(iter);
|
1166
|
+
return result;
|
1167
|
+
}
|
1168
|
+
else
|
1169
|
+
{
|
1170
|
+
return std::nullopt;
|
1171
|
+
}
|
1172
|
+
})
|
1173
|
+
.define_method("[]=", [](T& map, Key_T key, Mapped_T value) -> Mapped_T
|
1174
|
+
{
|
1175
|
+
map[key] = value;
|
1176
|
+
return value;
|
1177
|
+
});
|
1178
|
+
|
1179
|
+
rb_define_alias(klass_, "store", "[]=");
|
1180
|
+
}
|
1181
|
+
|
1182
|
+
void define_enumerable()
|
1183
|
+
{
|
1184
|
+
// Add enumerable support
|
1185
|
+
klass_.template define_iterator<typename T::iterator (T::*)()>(&T::begin, &T::end);
|
1186
|
+
}
|
1187
|
+
|
1188
|
+
void define_to_hash()
|
1189
|
+
{
|
1190
|
+
// Add enumerable support
|
1191
|
+
klass_.define_method("to_h", [](T& map)
|
1192
|
+
{
|
1193
|
+
VALUE result = rb_hash_new();
|
1194
|
+
std::for_each(map.begin(), map.end(), [&result](const typename T::reference pair)
|
1195
|
+
{
|
1196
|
+
VALUE key = detail::To_Ruby<Key_T&>().convert(pair.first);
|
1197
|
+
VALUE value = detail::To_Ruby<Mapped_T&>().convert(pair.second);
|
1198
|
+
rb_hash_aset(result, key, value);
|
1199
|
+
});
|
1200
|
+
|
1201
|
+
return result;
|
1202
|
+
}, Return().setValue());
|
1203
|
+
}
|
1204
|
+
|
1205
|
+
void define_to_s()
|
1206
|
+
{
|
1207
|
+
if constexpr (detail::is_ostreamable_v<Key_T> && detail::is_ostreamable_v<Mapped_T>)
|
1208
|
+
{
|
1209
|
+
klass_.define_method("to_s", [](const T& map)
|
1210
|
+
{
|
1211
|
+
auto iter = map.begin();
|
1212
|
+
|
1213
|
+
std::stringstream stream;
|
1214
|
+
stream << "{";
|
1215
|
+
|
1216
|
+
for (; iter != map.end(); iter++)
|
1217
|
+
{
|
1218
|
+
if (iter != map.begin())
|
1219
|
+
{
|
1220
|
+
stream << ", ";
|
1221
|
+
}
|
1222
|
+
stream << iter->first << " => " << iter->second;
|
1223
|
+
}
|
1224
|
+
|
1225
|
+
stream << "}";
|
1226
|
+
return stream.str();
|
1227
|
+
});
|
1228
|
+
}
|
1229
|
+
else
|
1230
|
+
{
|
1231
|
+
klass_.define_method("to_s", [](const T& map)
|
1232
|
+
{
|
1233
|
+
return "[Not printable]";
|
1234
|
+
});
|
1235
|
+
}
|
1236
|
+
}
|
1237
|
+
|
1238
|
+
private:
|
1239
|
+
Data_Type<T> klass_;
|
1240
|
+
};
|
1241
|
+
} // namespace
|
1242
|
+
|
1243
|
+
template<typename T>
|
1244
|
+
Data_Type<T> define_map_under(Object module, std::string name)
|
1245
|
+
{
|
1246
|
+
if (detail::Registries::instance.types.isDefined<T>())
|
1247
|
+
{
|
1248
|
+
// If the map has been previously seen it will be registered but may
|
1249
|
+
// not be associated with the constant Module::<name>
|
1250
|
+
module.const_set_maybe(name, Data_Type<T>().klass());
|
1251
|
+
return Data_Type<T>();
|
1252
|
+
}
|
1253
|
+
|
1254
|
+
Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(module, name.c_str());
|
1255
|
+
stl::MapHelper helper(result);
|
1256
|
+
return result;
|
1257
|
+
}
|
1258
|
+
|
1259
|
+
template<typename T>
|
1260
|
+
Data_Type<T> define_map(std::string name)
|
1261
|
+
{
|
1262
|
+
if (detail::Registries::instance.types.isDefined<T>())
|
1263
|
+
{
|
1264
|
+
// If the map has been previously seen it will be registered but may
|
1265
|
+
// not be associated with the constant Object::<name>
|
1266
|
+
Object(rb_cObject).const_set_maybe(name, Data_Type<T>().klass());
|
1267
|
+
return Data_Type<T>();
|
1268
|
+
}
|
1269
|
+
|
1270
|
+
Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
|
1271
|
+
stl::MapHelper<T> helper(result);
|
1272
|
+
return result;
|
1273
|
+
}
|
1274
|
+
|
1275
|
+
template<typename T>
|
1276
|
+
Data_Type<T> define_map_auto()
|
1277
|
+
{
|
1278
|
+
std::string klassName = detail::makeClassName(typeid(T));
|
1279
|
+
Module rb_mRice = define_module("Rice");
|
1280
|
+
Module rb_mmap = define_module_under(rb_mRice, "Std");
|
1281
|
+
return define_map_under<T>(rb_mmap, klassName);
|
1282
|
+
}
|
1283
|
+
|
1284
|
+
namespace detail
|
1285
|
+
{
|
1286
|
+
template<typename T, typename U>
|
1287
|
+
struct Type<std::map<T, U>>
|
1288
|
+
{
|
1289
|
+
static bool verify()
|
1290
|
+
{
|
1291
|
+
Type<T>::verify();
|
1292
|
+
Type<U>::verify();
|
1293
|
+
|
1294
|
+
if (!detail::Registries::instance.types.isDefined<std::map<T, U>>())
|
1295
|
+
{
|
1296
|
+
define_map_auto<std::map<T, U>>();
|
1297
|
+
}
|
1298
|
+
|
1299
|
+
return true;
|
1300
|
+
}
|
1301
|
+
};
|
1302
|
+
|
1303
|
+
template<typename T, typename U>
|
1304
|
+
struct MapFromHash
|
1305
|
+
{
|
1306
|
+
static int convertPair(VALUE key, VALUE value, VALUE user_data)
|
1307
|
+
{
|
1308
|
+
std::map<T, U>* result = (std::map<T, U>*)(user_data);
|
1309
|
+
|
1310
|
+
// This method is being called from Ruby so we cannot let any C++
|
1311
|
+
// exceptions propogate back to Ruby
|
1312
|
+
return cpp_protect([&]
|
1313
|
+
{
|
1314
|
+
result->operator[](From_Ruby<T>().convert(key)) = From_Ruby<U>().convert(value);
|
1315
|
+
return ST_CONTINUE;
|
1316
|
+
});
|
1317
|
+
}
|
1318
|
+
|
1319
|
+
static std::map<T, U> convert(VALUE value)
|
1320
|
+
{
|
1321
|
+
std::map<T, U> result;
|
1322
|
+
VALUE user_data = (VALUE)(&result);
|
1323
|
+
|
1324
|
+
// MSVC needs help here, but g++ does not
|
1325
|
+
using Rb_Hash_ForEach_T = void(*)(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE);
|
1326
|
+
detail::protect<Rb_Hash_ForEach_T>(rb_hash_foreach, value, convertPair, user_data);
|
1327
|
+
|
1328
|
+
return result;
|
1329
|
+
}
|
1330
|
+
};
|
1331
|
+
|
1332
|
+
template<typename T, typename U>
|
1333
|
+
class From_Ruby<std::map<T, U>>
|
1334
|
+
{
|
1335
|
+
public:
|
1336
|
+
From_Ruby() = default;
|
1337
|
+
|
1338
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
1339
|
+
{
|
1340
|
+
}
|
1341
|
+
|
1342
|
+
std::map<T, U> convert(VALUE value)
|
1343
|
+
{
|
1344
|
+
switch (rb_type(value))
|
1345
|
+
{
|
1346
|
+
case T_DATA:
|
1347
|
+
{
|
1348
|
+
// This is a wrapped map (hopefully!)
|
1349
|
+
return *Data_Object<std::map<T, U>>::from_ruby(value);
|
1350
|
+
}
|
1351
|
+
case T_HASH:
|
1352
|
+
{
|
1353
|
+
// If this an Ruby hash and the mapped type is copyable
|
1354
|
+
if constexpr (std::is_default_constructible_v<U>)
|
1355
|
+
{
|
1356
|
+
return MapFromHash<T, U>::convert(value);
|
1357
|
+
}
|
1358
|
+
}
|
1359
|
+
case T_NIL:
|
1360
|
+
{
|
1361
|
+
if (this->arg_ && this->arg_->hasDefaultValue())
|
1362
|
+
{
|
1363
|
+
return this->arg_->template defaultValue<std::map<T, U>>();
|
1364
|
+
}
|
1365
|
+
}
|
1366
|
+
default:
|
1367
|
+
{
|
1368
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
1369
|
+
detail::protect(rb_obj_classname, value), "std::map");
|
1370
|
+
}
|
1371
|
+
}
|
1372
|
+
}
|
1373
|
+
|
1374
|
+
private:
|
1375
|
+
Arg* arg_ = nullptr;
|
1376
|
+
};
|
1377
|
+
|
1378
|
+
template<typename T, typename U>
|
1379
|
+
class From_Ruby<std::map<T, U>&>
|
1380
|
+
{
|
1381
|
+
public:
|
1382
|
+
From_Ruby() = default;
|
1383
|
+
|
1384
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
1385
|
+
{
|
1386
|
+
}
|
1387
|
+
|
1388
|
+
std::map<T, U>& convert(VALUE value)
|
1389
|
+
{
|
1390
|
+
switch (rb_type(value))
|
1391
|
+
{
|
1392
|
+
case T_DATA:
|
1393
|
+
{
|
1394
|
+
// This is a wrapped map (hopefully!)
|
1395
|
+
return *Data_Object<std::map<T, U>>::from_ruby(value);
|
1396
|
+
}
|
1397
|
+
case T_HASH:
|
1398
|
+
{
|
1399
|
+
// If this an Ruby array and the map type is copyable
|
1400
|
+
if constexpr (std::is_default_constructible_v<std::map<T, U>>)
|
1401
|
+
{
|
1402
|
+
this->converted_ = MapFromHash<T, U>::convert(value);
|
1403
|
+
return this->converted_;
|
1404
|
+
}
|
1405
|
+
}
|
1406
|
+
case T_NIL:
|
1407
|
+
{
|
1408
|
+
if (this->arg_ && this->arg_->hasDefaultValue())
|
1409
|
+
{
|
1410
|
+
return this->arg_->template defaultValue<std::map<T, U>>();
|
1411
|
+
}
|
1412
|
+
}
|
1413
|
+
default:
|
1414
|
+
{
|
1415
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
1416
|
+
detail::protect(rb_obj_classname, value), "std::map");
|
1417
|
+
}
|
1418
|
+
}
|
1419
|
+
}
|
1420
|
+
|
1421
|
+
private:
|
1422
|
+
Arg* arg_ = nullptr;
|
1423
|
+
std::map<T, U> converted_;
|
1424
|
+
};
|
1425
|
+
|
1426
|
+
template<typename T, typename U>
|
1427
|
+
class From_Ruby<std::map<T, U>*>
|
1428
|
+
{
|
1429
|
+
public:
|
1430
|
+
std::map<T, U>* convert(VALUE value)
|
1431
|
+
{
|
1432
|
+
switch (rb_type(value))
|
1433
|
+
{
|
1434
|
+
case T_DATA:
|
1435
|
+
{
|
1436
|
+
// This is a wrapped map (hopefully!)
|
1437
|
+
return Data_Object<std::map<T, U>>::from_ruby(value);
|
1438
|
+
}
|
1439
|
+
case T_HASH:
|
1440
|
+
{
|
1441
|
+
// If this an Ruby array and the map type is copyable
|
1442
|
+
if constexpr (std::is_default_constructible_v<U>)
|
1443
|
+
{
|
1444
|
+
this->converted_ = MapFromHash<T, U>::convert(value);
|
1445
|
+
return &this->converted_;
|
1446
|
+
}
|
1447
|
+
}
|
1448
|
+
default:
|
1449
|
+
{
|
1450
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
1451
|
+
detail::protect(rb_obj_classname, value), "std::map");
|
1452
|
+
}
|
1453
|
+
}
|
1454
|
+
}
|
1455
|
+
|
1456
|
+
private:
|
1457
|
+
std::map<T, U> converted_;
|
1458
|
+
};
|
1459
|
+
}
|
1460
|
+
}
|
1461
|
+
|
1462
|
+
// ========= unordered_map.hpp =========
|
1463
|
+
|
1464
|
+
|
1465
|
+
namespace Rice
|
1466
|
+
{
|
1467
|
+
template<typename U>
|
1468
|
+
Data_Type<U> define_unordered_map(std::string name);
|
1469
|
+
|
1470
|
+
template<typename U>
|
1471
|
+
Data_Type<U> define_unordered_map_under(Object module, std::string name);
|
1472
|
+
}
|
1473
|
+
|
1474
|
+
|
1475
|
+
// --------- unordered_map.ipp ---------
|
1476
|
+
|
1477
|
+
#include <sstream>
|
1478
|
+
#include <stdexcept>
|
1479
|
+
#include <type_traits>
|
1480
|
+
#include <unordered_map>
|
1481
|
+
#include <variant>
|
1482
|
+
|
1483
|
+
namespace Rice
|
1484
|
+
{
|
1485
|
+
namespace stl
|
1486
|
+
{
|
1487
|
+
template<typename T>
|
1488
|
+
class UnorderedMapHelper
|
1489
|
+
{
|
1490
|
+
using Key_T = typename T::key_type;
|
1491
|
+
using Mapped_T = typename T::mapped_type;
|
1492
|
+
using Value_T = typename T::value_type;
|
1493
|
+
using Size_T = typename T::size_type;
|
1494
|
+
using Difference_T = typename T::difference_type;
|
1495
|
+
|
1496
|
+
public:
|
1497
|
+
UnorderedMapHelper(Data_Type<T> klass) : klass_(klass)
|
1498
|
+
{
|
1499
|
+
this->register_pair();
|
1500
|
+
this->define_constructor();
|
1501
|
+
this->define_copyable_methods();
|
1502
|
+
this->define_capacity_methods();
|
1503
|
+
this->define_access_methods();
|
1504
|
+
this->define_comparable_methods();
|
1505
|
+
this->define_modify_methods();
|
1506
|
+
this->define_enumerable();
|
1507
|
+
this->define_to_s();
|
1508
|
+
this->define_to_hash();
|
1509
|
+
}
|
1510
|
+
|
1511
|
+
private:
|
1512
|
+
|
1513
|
+
void register_pair()
|
1514
|
+
{
|
1515
|
+
define_pair_auto<Value_T>();
|
1516
|
+
}
|
1517
|
+
|
1518
|
+
void define_constructor()
|
1519
|
+
{
|
1520
|
+
klass_.define_constructor(Constructor<T>());
|
1521
|
+
}
|
1522
|
+
|
1523
|
+
void define_copyable_methods()
|
1524
|
+
{
|
1525
|
+
if constexpr (std::is_copy_constructible_v<Value_T>)
|
1526
|
+
{
|
1527
|
+
klass_.define_method("copy", [](T& unordered_map) -> T
|
1528
|
+
{
|
1529
|
+
return unordered_map;
|
1530
|
+
});
|
1531
|
+
}
|
1532
|
+
else
|
1533
|
+
{
|
1534
|
+
klass_.define_method("copy", [](T& unordered_map) -> T
|
1535
|
+
{
|
1536
|
+
throw std::runtime_error("Cannot copy unordered_maps with non-copy constructible types");
|
1537
|
+
return unordered_map;
|
1538
|
+
});
|
1539
|
+
}
|
1540
|
+
}
|
1541
|
+
|
1542
|
+
void define_capacity_methods()
|
1543
|
+
{
|
1544
|
+
klass_.define_method("empty?", &T::empty)
|
1545
|
+
.define_method("max_size", &T::max_size)
|
1546
|
+
.define_method("size", &T::size);
|
1547
|
+
|
1548
|
+
rb_define_alias(klass_, "count", "size");
|
1549
|
+
rb_define_alias(klass_, "length", "size");
|
1550
|
+
}
|
1551
|
+
|
1552
|
+
void define_access_methods()
|
1553
|
+
{
|
1554
|
+
// Access methods
|
1555
|
+
klass_.define_method("[]", [](const T& unordered_map, const Key_T& key) -> std::optional<Mapped_T>
|
1556
|
+
{
|
1557
|
+
auto iter = unordered_map.find(key);
|
1558
|
+
|
1559
|
+
if (iter != unordered_map.end())
|
1560
|
+
{
|
1561
|
+
return iter->second;
|
1562
|
+
}
|
1563
|
+
else
|
1564
|
+
{
|
1565
|
+
return std::nullopt;
|
1566
|
+
}
|
1567
|
+
})
|
1568
|
+
.define_method("include?", [](T& unordered_map, Key_T& key) -> bool
|
1569
|
+
{
|
1570
|
+
return unordered_map.find(key) != unordered_map.end();
|
1571
|
+
})
|
1572
|
+
.define_method("keys", [](T& unordered_map) -> std::vector<Key_T>
|
1573
|
+
{
|
1574
|
+
std::vector<Key_T> result;
|
1575
|
+
std::transform(unordered_map.begin(), unordered_map.end(), std::back_inserter(result),
|
1576
|
+
[](const auto& pair)
|
1577
|
+
{
|
1578
|
+
return pair.first;
|
1579
|
+
});
|
1580
|
+
|
1581
|
+
return result;
|
1582
|
+
})
|
1583
|
+
.define_method("values", [](T& unordered_map) -> std::vector<Mapped_T>
|
1584
|
+
{
|
1585
|
+
std::vector<Mapped_T> result;
|
1586
|
+
std::transform(unordered_map.begin(), unordered_map.end(), std::back_inserter(result),
|
1587
|
+
[](const auto& pair)
|
1588
|
+
{
|
1589
|
+
return pair.second;
|
1590
|
+
});
|
1591
|
+
|
1592
|
+
return result;
|
1593
|
+
});
|
1594
|
+
|
1595
|
+
rb_define_alias(klass_, "has_key", "include?");
|
1596
|
+
}
|
1597
|
+
|
1598
|
+
// Methods that require Value_T to support operator==
|
1599
|
+
void define_comparable_methods()
|
1600
|
+
{
|
1601
|
+
if constexpr (detail::is_comparable_v<Mapped_T>)
|
1602
|
+
{
|
1603
|
+
klass_.define_method("value?", [](T& unordered_map, Mapped_T& value) -> bool
|
1604
|
+
{
|
1605
|
+
auto it = std::find_if(unordered_map.begin(), unordered_map.end(),
|
1606
|
+
[&value](auto& pair)
|
1607
|
+
{
|
1608
|
+
return pair.second == value;
|
1609
|
+
});
|
1610
|
+
|
1611
|
+
return it != unordered_map.end();
|
1612
|
+
});
|
1613
|
+
}
|
1614
|
+
else
|
1615
|
+
{
|
1616
|
+
klass_.define_method("value?", [](T& unordered_map, Mapped_T& value) -> bool
|
1617
|
+
{
|
1618
|
+
return false;
|
1619
|
+
});
|
1620
|
+
}
|
1621
|
+
|
1622
|
+
rb_define_alias(klass_, "has_value", "value?");
|
1623
|
+
}
|
1624
|
+
|
1625
|
+
void define_modify_methods()
|
1626
|
+
{
|
1627
|
+
klass_.define_method("clear", &T::clear)
|
1628
|
+
.define_method("delete", [](T& unordered_map, Key_T& key) -> std::optional<Mapped_T>
|
1629
|
+
{
|
1630
|
+
auto iter = unordered_map.find(key);
|
1631
|
+
|
1632
|
+
if (iter != unordered_map.end())
|
1633
|
+
{
|
1634
|
+
Mapped_T result = iter->second;
|
1635
|
+
unordered_map.erase(iter);
|
1636
|
+
return result;
|
1637
|
+
}
|
1638
|
+
else
|
1639
|
+
{
|
1640
|
+
return std::nullopt;
|
1641
|
+
}
|
1642
|
+
})
|
1643
|
+
.define_method("[]=", [](T& unordered_map, Key_T key, Mapped_T value) -> Mapped_T
|
1644
|
+
{
|
1645
|
+
unordered_map[key] = value;
|
1646
|
+
return value;
|
1647
|
+
});
|
1648
|
+
|
1649
|
+
rb_define_alias(klass_, "store", "[]=");
|
1650
|
+
}
|
1651
|
+
|
1652
|
+
void define_enumerable()
|
1653
|
+
{
|
1654
|
+
// Add enumerable support
|
1655
|
+
klass_.template define_iterator<typename T::iterator (T::*)()>(&T::begin, &T::end);
|
1656
|
+
}
|
1657
|
+
|
1658
|
+
void define_to_hash()
|
1659
|
+
{
|
1660
|
+
// Add enumerable support
|
1661
|
+
klass_.define_method("to_h", [](T& unordered_map)
|
1662
|
+
{
|
1663
|
+
VALUE result = rb_hash_new();
|
1664
|
+
std::for_each(unordered_map.begin(), unordered_map.end(), [&result](const auto& pair)
|
359
1665
|
{
|
360
|
-
|
361
|
-
|
1666
|
+
VALUE key = detail::To_Ruby<Key_T>().convert(pair.first);
|
1667
|
+
VALUE value = detail::To_Ruby<Mapped_T>().convert(pair.second);
|
1668
|
+
rb_hash_aset(result, key, value);
|
362
1669
|
});
|
1670
|
+
|
1671
|
+
return result;
|
1672
|
+
}, Return().setValue());
|
363
1673
|
}
|
364
1674
|
|
365
1675
|
void define_to_s()
|
366
1676
|
{
|
367
|
-
if constexpr (detail::is_ostreamable_v<
|
1677
|
+
if constexpr (detail::is_ostreamable_v<Key_T> && detail::is_ostreamable_v<Mapped_T>)
|
368
1678
|
{
|
369
|
-
klass_.define_method("to_s", [](const T&
|
1679
|
+
klass_.define_method("to_s", [](const T& unordered_map)
|
370
1680
|
{
|
1681
|
+
auto iter = unordered_map.begin();
|
1682
|
+
|
371
1683
|
std::stringstream stream;
|
372
|
-
stream << "
|
1684
|
+
stream << "{";
|
1685
|
+
|
1686
|
+
for (; iter != unordered_map.end(); iter++)
|
1687
|
+
{
|
1688
|
+
if (iter != unordered_map.begin())
|
1689
|
+
{
|
1690
|
+
stream << ", ";
|
1691
|
+
}
|
1692
|
+
stream << iter->first << " => " << iter->second;
|
1693
|
+
}
|
1694
|
+
|
1695
|
+
stream << "}";
|
373
1696
|
return stream.str();
|
374
1697
|
});
|
375
1698
|
}
|
376
1699
|
else
|
377
1700
|
{
|
378
|
-
klass_.define_method("to_s", [](const T&
|
1701
|
+
klass_.define_method("to_s", [](const T& unordered_map)
|
379
1702
|
{
|
380
1703
|
return "[Not printable]";
|
381
1704
|
});
|
@@ -388,212 +1711,222 @@ namespace Rice
|
|
388
1711
|
} // namespace
|
389
1712
|
|
390
1713
|
template<typename T>
|
391
|
-
Data_Type<T>
|
1714
|
+
Data_Type<T> define_unordered_map_under(Object module, std::string name)
|
392
1715
|
{
|
393
|
-
if (detail::
|
1716
|
+
if (detail::Registries::instance.types.isDefined<T>())
|
394
1717
|
{
|
395
|
-
|
1718
|
+
// If the unordered_map has been previously seen it will be registered but may
|
1719
|
+
// not be associated with the constant Module::<name>
|
1720
|
+
module.const_set_maybe(name, Data_Type<T>().klass());
|
1721
|
+
return Data_Type<T>();
|
396
1722
|
}
|
397
1723
|
|
398
1724
|
Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(module, name.c_str());
|
399
|
-
stl::
|
1725
|
+
stl::UnorderedMapHelper helper(result);
|
400
1726
|
return result;
|
401
1727
|
}
|
402
1728
|
|
403
1729
|
template<typename T>
|
404
|
-
Data_Type<T>
|
1730
|
+
Data_Type<T> define_unordered_map(std::string name)
|
405
1731
|
{
|
406
|
-
if (detail::
|
1732
|
+
if (detail::Registries::instance.types.isDefined<T>())
|
407
1733
|
{
|
408
|
-
|
1734
|
+
// If the unordered_map has been previously seen it will be registered but may
|
1735
|
+
// not be associated with the constant Object::<name>
|
1736
|
+
Object(rb_cObject).const_set_maybe(name, Data_Type<T>().klass());
|
1737
|
+
return Data_Type<T>();
|
409
1738
|
}
|
410
1739
|
|
411
1740
|
Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
|
412
|
-
stl::
|
1741
|
+
stl::UnorderedMapHelper<T> helper(result);
|
413
1742
|
return result;
|
414
1743
|
}
|
415
1744
|
|
416
1745
|
template<typename T>
|
417
|
-
Data_Type<T>
|
1746
|
+
Data_Type<T> define_unordered_map_auto()
|
418
1747
|
{
|
419
1748
|
std::string klassName = detail::makeClassName(typeid(T));
|
420
1749
|
Module rb_mRice = define_module("Rice");
|
421
|
-
Module
|
422
|
-
return
|
1750
|
+
Module rb_munordered_map = define_module_under(rb_mRice, "Std");
|
1751
|
+
return define_unordered_map_under<T>(rb_munordered_map, klassName);
|
423
1752
|
}
|
424
1753
|
|
425
1754
|
namespace detail
|
426
1755
|
{
|
427
|
-
template<typename
|
428
|
-
struct Type<std::
|
1756
|
+
template<typename T, typename U>
|
1757
|
+
struct Type<std::unordered_map<T, U>>
|
429
1758
|
{
|
430
1759
|
static bool verify()
|
431
1760
|
{
|
432
|
-
Type<
|
433
|
-
Type<
|
1761
|
+
Type<T>::verify();
|
1762
|
+
Type<U>::verify();
|
434
1763
|
|
435
|
-
if (!detail::
|
1764
|
+
if (!detail::Registries::instance.types.isDefined<std::unordered_map<T, U>>())
|
436
1765
|
{
|
437
|
-
|
1766
|
+
define_unordered_map_auto<std::unordered_map<T, U>>();
|
438
1767
|
}
|
439
1768
|
|
440
1769
|
return true;
|
441
1770
|
}
|
442
1771
|
};
|
443
|
-
}
|
444
|
-
}
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
// ========= smart_ptr.hpp =========
|
449
|
-
|
450
|
-
|
451
|
-
namespace Rice::detail
|
452
|
-
{
|
453
|
-
template <template <typename, typename...> typename SmartPointer_T, typename...Arg_Ts>
|
454
|
-
class WrapperSmartPointer : public Wrapper
|
455
|
-
{
|
456
|
-
public:
|
457
|
-
WrapperSmartPointer(SmartPointer_T<Arg_Ts...>& data);
|
458
|
-
void* get() override;
|
459
|
-
SmartPointer_T<Arg_Ts...>& data();
|
460
|
-
|
461
|
-
private:
|
462
|
-
SmartPointer_T<Arg_Ts...> data_;
|
463
|
-
};
|
464
|
-
}
|
465
1772
|
|
1773
|
+
template<typename T, typename U>
|
1774
|
+
struct UnorderedMapFromHash
|
1775
|
+
{
|
1776
|
+
static int convertPair(VALUE key, VALUE value, VALUE user_data)
|
1777
|
+
{
|
1778
|
+
std::unordered_map<T, U>* result = (std::unordered_map<T, U>*)(user_data);
|
466
1779
|
|
467
|
-
//
|
468
|
-
|
469
|
-
|
470
|
-
|
1780
|
+
// This method is being called from Ruby so we cannot let any C++
|
1781
|
+
// exceptions propogate back to Ruby
|
1782
|
+
return cpp_protect([&]
|
1783
|
+
{
|
1784
|
+
result->operator[](From_Ruby<T>().convert(key)) = From_Ruby<U>().convert(value);
|
1785
|
+
return ST_CONTINUE;
|
1786
|
+
});
|
1787
|
+
}
|
471
1788
|
|
472
|
-
|
473
|
-
{
|
474
|
-
|
475
|
-
|
476
|
-
inline WrapperSmartPointer<SmartPointer_T, Arg_Ts...>::WrapperSmartPointer(SmartPointer_T<Arg_Ts...>& data)
|
477
|
-
: data_(std::move(data))
|
478
|
-
{
|
479
|
-
}
|
1789
|
+
static std::unordered_map<T, U> convert(VALUE value)
|
1790
|
+
{
|
1791
|
+
std::unordered_map<T, U> result;
|
1792
|
+
VALUE user_data = (VALUE)(&result);
|
480
1793
|
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
return (void*)this->data_.get();
|
485
|
-
}
|
1794
|
+
// MSVC needs help here, but g++ does not
|
1795
|
+
using Rb_Hash_ForEach_T = void(*)(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE);
|
1796
|
+
detail::protect<Rb_Hash_ForEach_T>(rb_hash_foreach, value, convertPair, user_data);
|
486
1797
|
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
return data_;
|
491
|
-
}
|
1798
|
+
return result;
|
1799
|
+
}
|
1800
|
+
};
|
492
1801
|
|
493
|
-
|
494
|
-
|
495
|
-
class To_Ruby<std::unique_ptr<T>>
|
496
|
-
{
|
497
|
-
public:
|
498
|
-
VALUE convert(std::unique_ptr<T>& data)
|
1802
|
+
template<typename T, typename U>
|
1803
|
+
class From_Ruby<std::unordered_map<T, U>>
|
499
1804
|
{
|
500
|
-
|
501
|
-
|
502
|
-
// Use custom wrapper type
|
503
|
-
using Wrapper_T = WrapperSmartPointer<std::unique_ptr, T>;
|
504
|
-
return detail::wrap<std::unique_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
|
505
|
-
}
|
506
|
-
};
|
1805
|
+
public:
|
1806
|
+
From_Ruby() = default;
|
507
1807
|
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
public:
|
512
|
-
std::unique_ptr<T>& convert(VALUE value)
|
513
|
-
{
|
514
|
-
Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::rb_type());
|
1808
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
1809
|
+
{
|
1810
|
+
}
|
515
1811
|
|
516
|
-
|
517
|
-
Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
|
518
|
-
if (!smartWrapper)
|
1812
|
+
std::unordered_map<T, U> convert(VALUE value)
|
519
1813
|
{
|
520
|
-
|
521
|
-
|
1814
|
+
switch (rb_type(value))
|
1815
|
+
{
|
1816
|
+
case T_DATA:
|
1817
|
+
{
|
1818
|
+
// This is a wrapped unordered_map (hopefully!)
|
1819
|
+
return *Data_Object<std::unordered_map<T, U>>::from_ruby(value);
|
1820
|
+
}
|
1821
|
+
case T_HASH:
|
1822
|
+
{
|
1823
|
+
// If this an Ruby hash and the unordered_mapped type is copyable
|
1824
|
+
if constexpr (std::is_default_constructible_v<U>)
|
1825
|
+
{
|
1826
|
+
return UnorderedMapFromHash<T, U>::convert(value);
|
1827
|
+
}
|
1828
|
+
}
|
1829
|
+
case T_NIL:
|
1830
|
+
{
|
1831
|
+
if (this->arg_ && this->arg_->hasDefaultValue())
|
1832
|
+
{
|
1833
|
+
return this->arg_->template defaultValue<std::unordered_map<T, U>>();
|
1834
|
+
}
|
1835
|
+
}
|
1836
|
+
default:
|
1837
|
+
{
|
1838
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
1839
|
+
detail::protect(rb_obj_classname, value), "std::unordered_map");
|
1840
|
+
}
|
1841
|
+
}
|
522
1842
|
}
|
523
|
-
return smartWrapper->data();
|
524
|
-
}
|
525
|
-
};
|
526
1843
|
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
static bool verify()
|
531
|
-
{
|
532
|
-
return Type<T>::verify();
|
533
|
-
}
|
534
|
-
};
|
1844
|
+
private:
|
1845
|
+
Arg* arg_ = nullptr;
|
1846
|
+
};
|
535
1847
|
|
536
|
-
|
537
|
-
|
538
|
-
class To_Ruby<std::shared_ptr<T>>
|
539
|
-
{
|
540
|
-
public:
|
541
|
-
VALUE convert(std::shared_ptr<T>& data)
|
1848
|
+
template<typename T, typename U>
|
1849
|
+
class From_Ruby<std::unordered_map<T, U>&>
|
542
1850
|
{
|
543
|
-
|
544
|
-
|
545
|
-
// Use custom wrapper type
|
546
|
-
using Wrapper_T = WrapperSmartPointer<std::shared_ptr, T>;
|
547
|
-
return detail::wrap<std::shared_ptr<T>, Wrapper_T>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
|
548
|
-
}
|
549
|
-
};
|
1851
|
+
public:
|
1852
|
+
From_Ruby() = default;
|
550
1853
|
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
public:
|
555
|
-
std::shared_ptr<T> convert(VALUE value)
|
556
|
-
{
|
557
|
-
Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::rb_type());
|
1854
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
1855
|
+
{
|
1856
|
+
}
|
558
1857
|
|
559
|
-
|
560
|
-
Wrapper_T* smartWrapper = dynamic_cast<Wrapper_T*>(wrapper);
|
561
|
-
if (!smartWrapper)
|
1858
|
+
std::unordered_map<T, U>& convert(VALUE value)
|
562
1859
|
{
|
563
|
-
|
564
|
-
|
1860
|
+
switch (rb_type(value))
|
1861
|
+
{
|
1862
|
+
case T_DATA:
|
1863
|
+
{
|
1864
|
+
// This is a wrapped unordered_map (hopefully!)
|
1865
|
+
return *Data_Object<std::unordered_map<T, U>>::from_ruby(value);
|
1866
|
+
}
|
1867
|
+
case T_HASH:
|
1868
|
+
{
|
1869
|
+
// If this an Ruby array and the unordered_map type is copyable
|
1870
|
+
if constexpr (std::is_default_constructible_v<std::unordered_map<T, U>>)
|
1871
|
+
{
|
1872
|
+
this->converted_ = UnorderedMapFromHash<T, U>::convert(value);
|
1873
|
+
return this->converted_;
|
1874
|
+
}
|
1875
|
+
}
|
1876
|
+
case T_NIL:
|
1877
|
+
{
|
1878
|
+
if (this->arg_ && this->arg_->hasDefaultValue())
|
1879
|
+
{
|
1880
|
+
return this->arg_->template defaultValue<std::unordered_map<T, U>>();
|
1881
|
+
}
|
1882
|
+
}
|
1883
|
+
default:
|
1884
|
+
{
|
1885
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
1886
|
+
detail::protect(rb_obj_classname, value), "std::unordered_map");
|
1887
|
+
}
|
1888
|
+
}
|
565
1889
|
}
|
566
|
-
return smartWrapper->data();
|
567
|
-
}
|
568
|
-
};
|
569
1890
|
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
std::shared_ptr<T>& convert(VALUE value)
|
575
|
-
{
|
576
|
-
Wrapper* wrapper = detail::getWrapper(value, Data_Type<T>::rb_type());
|
1891
|
+
private:
|
1892
|
+
Arg* arg_ = nullptr;
|
1893
|
+
std::unordered_map<T, U> converted_;
|
1894
|
+
};
|
577
1895
|
|
578
|
-
|
579
|
-
|
580
|
-
|
1896
|
+
template<typename T, typename U>
|
1897
|
+
class From_Ruby<std::unordered_map<T, U>*>
|
1898
|
+
{
|
1899
|
+
public:
|
1900
|
+
std::unordered_map<T, U>* convert(VALUE value)
|
581
1901
|
{
|
582
|
-
|
583
|
-
|
1902
|
+
switch (rb_type(value))
|
1903
|
+
{
|
1904
|
+
case T_DATA:
|
1905
|
+
{
|
1906
|
+
// This is a wrapped unordered_map (hopefully!)
|
1907
|
+
return Data_Object<std::unordered_map<T, U>>::from_ruby(value);
|
1908
|
+
}
|
1909
|
+
case T_HASH:
|
1910
|
+
{
|
1911
|
+
// If this an Ruby array and the unordered_map type is copyable
|
1912
|
+
if constexpr (std::is_default_constructible_v<U>)
|
1913
|
+
{
|
1914
|
+
this->converted_ = UnorderedMapFromHash<T, U>::convert(value);
|
1915
|
+
return &this->converted_;
|
1916
|
+
}
|
1917
|
+
}
|
1918
|
+
default:
|
1919
|
+
{
|
1920
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
1921
|
+
detail::protect(rb_obj_classname, value), "std::unordered_map");
|
1922
|
+
}
|
1923
|
+
}
|
584
1924
|
}
|
585
|
-
return smartWrapper->data();
|
586
|
-
}
|
587
|
-
};
|
588
1925
|
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
{
|
594
|
-
return Type<T>::verify();
|
595
|
-
}
|
596
|
-
};
|
1926
|
+
private:
|
1927
|
+
std::unordered_map<T, U> converted_;
|
1928
|
+
};
|
1929
|
+
}
|
597
1930
|
}
|
598
1931
|
|
599
1932
|
// ========= vector.hpp =========
|
@@ -613,7 +1946,9 @@ namespace Rice
|
|
613
1946
|
|
614
1947
|
#include <sstream>
|
615
1948
|
#include <stdexcept>
|
1949
|
+
#include <type_traits>
|
616
1950
|
#include <vector>
|
1951
|
+
#include <variant>
|
617
1952
|
|
618
1953
|
namespace Rice
|
619
1954
|
{
|
@@ -636,8 +1971,9 @@ namespace Rice
|
|
636
1971
|
this->define_access_methods();
|
637
1972
|
this->define_comparable_methods();
|
638
1973
|
this->define_modify_methods();
|
639
|
-
this->define_to_s();
|
640
1974
|
this->define_enumerable();
|
1975
|
+
this->define_to_array();
|
1976
|
+
this->define_to_s();
|
641
1977
|
}
|
642
1978
|
|
643
1979
|
private:
|
@@ -670,17 +2006,17 @@ namespace Rice
|
|
670
2006
|
{
|
671
2007
|
if constexpr (std::is_copy_constructible_v<Value_T>)
|
672
2008
|
{
|
673
|
-
klass_.define_method("copy", [](T&
|
2009
|
+
klass_.define_method("copy", [](T& vector) -> T
|
674
2010
|
{
|
675
|
-
return
|
2011
|
+
return vector;
|
676
2012
|
});
|
677
2013
|
}
|
678
2014
|
else
|
679
2015
|
{
|
680
|
-
klass_.define_method("copy", [](T&
|
2016
|
+
klass_.define_method("copy", [](T& vector) -> T
|
681
2017
|
{
|
682
2018
|
throw std::runtime_error("Cannot copy vectors with non-copy constructible types");
|
683
|
-
return
|
2019
|
+
return vector;
|
684
2020
|
});
|
685
2021
|
}
|
686
2022
|
}
|
@@ -693,7 +2029,7 @@ namespace Rice
|
|
693
2029
|
}
|
694
2030
|
else
|
695
2031
|
{
|
696
|
-
klass_.define_method("resize", [](const T&
|
2032
|
+
klass_.define_method("resize", [](const T& vector, Size_T newSize)
|
697
2033
|
{
|
698
2034
|
// Do nothing
|
699
2035
|
});
|
@@ -717,38 +2053,38 @@ namespace Rice
|
|
717
2053
|
void define_access_methods()
|
718
2054
|
{
|
719
2055
|
// Access methods
|
720
|
-
klass_.define_method("first", [](const T&
|
2056
|
+
klass_.define_method("first", [](const T& vector) -> std::optional<Value_T>
|
721
2057
|
{
|
722
|
-
if (
|
2058
|
+
if (vector.size() > 0)
|
723
2059
|
{
|
724
|
-
return
|
2060
|
+
return vector.front();
|
725
2061
|
}
|
726
2062
|
else
|
727
2063
|
{
|
728
2064
|
return std::nullopt;
|
729
2065
|
}
|
730
2066
|
})
|
731
|
-
.define_method("last", [](const T&
|
2067
|
+
.define_method("last", [](const T& vector) -> std::optional<Value_T>
|
732
2068
|
{
|
733
|
-
if (
|
2069
|
+
if (vector.size() > 0)
|
734
2070
|
{
|
735
|
-
return
|
2071
|
+
return vector.back();
|
736
2072
|
}
|
737
2073
|
else
|
738
2074
|
{
|
739
2075
|
return std::nullopt;
|
740
2076
|
}
|
741
2077
|
})
|
742
|
-
.define_method("[]", [this](const T&
|
2078
|
+
.define_method("[]", [this](const T& vector, Difference_T index) -> std::optional<Value_T>
|
743
2079
|
{
|
744
|
-
index = normalizeIndex(
|
745
|
-
if (index < 0 || index >= (Difference_T)
|
2080
|
+
index = normalizeIndex(vector.size(), index);
|
2081
|
+
if (index < 0 || index >= (Difference_T)vector.size())
|
746
2082
|
{
|
747
2083
|
return std::nullopt;
|
748
2084
|
}
|
749
2085
|
else
|
750
2086
|
{
|
751
|
-
return
|
2087
|
+
return vector[index];
|
752
2088
|
}
|
753
2089
|
});
|
754
2090
|
|
@@ -760,48 +2096,48 @@ namespace Rice
|
|
760
2096
|
{
|
761
2097
|
if constexpr (detail::is_comparable_v<Value_T>)
|
762
2098
|
{
|
763
|
-
klass_.define_method("delete", [](T&
|
2099
|
+
klass_.define_method("delete", [](T& vector, Value_T& element) -> std::optional<Value_T>
|
764
2100
|
{
|
765
|
-
auto iter = std::find(
|
766
|
-
if (iter ==
|
2101
|
+
auto iter = std::find(vector.begin(), vector.end(), element);
|
2102
|
+
if (iter == vector.end())
|
767
2103
|
{
|
768
2104
|
return std::nullopt;
|
769
2105
|
}
|
770
2106
|
else
|
771
2107
|
{
|
772
2108
|
Value_T result = *iter;
|
773
|
-
|
2109
|
+
vector.erase(iter);
|
774
2110
|
return result;
|
775
2111
|
}
|
776
2112
|
})
|
777
|
-
.define_method("include?", [](T&
|
2113
|
+
.define_method("include?", [](T& vector, Value_T& element)
|
778
2114
|
{
|
779
|
-
return std::find(
|
2115
|
+
return std::find(vector.begin(), vector.end(), element) != vector.end();
|
780
2116
|
})
|
781
|
-
.define_method("index", [](T&
|
2117
|
+
.define_method("index", [](T& vector, Value_T& element) -> std::optional<Difference_T>
|
782
2118
|
{
|
783
|
-
auto iter = std::find(
|
784
|
-
if (iter ==
|
2119
|
+
auto iter = std::find(vector.begin(), vector.end(), element);
|
2120
|
+
if (iter == vector.end())
|
785
2121
|
{
|
786
2122
|
return std::nullopt;
|
787
2123
|
}
|
788
2124
|
else
|
789
2125
|
{
|
790
|
-
return iter -
|
2126
|
+
return iter - vector.begin();
|
791
2127
|
}
|
792
2128
|
});
|
793
2129
|
}
|
794
2130
|
else
|
795
2131
|
{
|
796
|
-
klass_.define_method("delete", [](T&
|
2132
|
+
klass_.define_method("delete", [](T& vector, Value_T& element) -> std::optional<Value_T>
|
797
2133
|
{
|
798
2134
|
return std::nullopt;
|
799
2135
|
})
|
800
|
-
.define_method("include?", [](const T&
|
2136
|
+
.define_method("include?", [](const T& vector, Value_T& element)
|
801
2137
|
{
|
802
2138
|
return false;
|
803
2139
|
})
|
804
|
-
.define_method("index", [](const T&
|
2140
|
+
.define_method("index", [](const T& vector, Value_T& element) -> std::optional<Difference_T>
|
805
2141
|
{
|
806
2142
|
return std::nullopt;
|
807
2143
|
});
|
@@ -811,26 +2147,26 @@ namespace Rice
|
|
811
2147
|
void define_modify_methods()
|
812
2148
|
{
|
813
2149
|
klass_.define_method("clear", &T::clear)
|
814
|
-
.define_method("delete_at", [](T&
|
2150
|
+
.define_method("delete_at", [](T& vector, const size_t& pos)
|
815
2151
|
{
|
816
|
-
auto iter =
|
2152
|
+
auto iter = vector.begin() + pos;
|
817
2153
|
Value_T result = *iter;
|
818
|
-
|
2154
|
+
vector.erase(iter);
|
819
2155
|
return result;
|
820
2156
|
})
|
821
|
-
.define_method("insert", [this](T&
|
2157
|
+
.define_method("insert", [this](T& vector, Difference_T index, Value_T& element) -> T&
|
822
2158
|
{
|
823
|
-
index = normalizeIndex(
|
824
|
-
auto iter =
|
825
|
-
|
826
|
-
return
|
2159
|
+
index = normalizeIndex(vector.size(), index, true);
|
2160
|
+
auto iter = vector.begin() + index;
|
2161
|
+
vector.insert(iter, element);
|
2162
|
+
return vector;
|
827
2163
|
})
|
828
|
-
.define_method("pop", [](T&
|
2164
|
+
.define_method("pop", [](T& vector) -> std::optional<Value_T>
|
829
2165
|
{
|
830
|
-
if (
|
2166
|
+
if (vector.size() > 0)
|
831
2167
|
{
|
832
|
-
Value_T result =
|
833
|
-
|
2168
|
+
Value_T result = vector.back();
|
2169
|
+
vector.pop_back();
|
834
2170
|
return result;
|
835
2171
|
}
|
836
2172
|
else
|
@@ -838,16 +2174,16 @@ namespace Rice
|
|
838
2174
|
return std::nullopt;
|
839
2175
|
}
|
840
2176
|
})
|
841
|
-
.define_method("push", [](T&
|
2177
|
+
.define_method("push", [](T& vector, Value_T& element) -> T&
|
842
2178
|
{
|
843
|
-
|
844
|
-
return
|
2179
|
+
vector.push_back(element);
|
2180
|
+
return vector;
|
845
2181
|
})
|
846
2182
|
.define_method("shrink_to_fit", &T::shrink_to_fit)
|
847
|
-
.define_method("[]=", [this](T&
|
2183
|
+
.define_method("[]=", [this](T& vector, Difference_T index, Value_T& element) -> Value_T&
|
848
2184
|
{
|
849
|
-
index = normalizeIndex(
|
850
|
-
|
2185
|
+
index = normalizeIndex(vector.size(), index, true);
|
2186
|
+
vector[index] = element;
|
851
2187
|
return element;
|
852
2188
|
});
|
853
2189
|
|
@@ -858,33 +2194,40 @@ namespace Rice
|
|
858
2194
|
void define_enumerable()
|
859
2195
|
{
|
860
2196
|
// Add enumerable support
|
861
|
-
klass_.
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
2197
|
+
klass_.template define_iterator<typename T::iterator(T::*)()>(&T::begin, &T::end);
|
2198
|
+
}
|
2199
|
+
|
2200
|
+
void define_to_array()
|
2201
|
+
{
|
2202
|
+
// Add enumerable support
|
2203
|
+
klass_.define_method("to_a", [](T& vector)
|
2204
|
+
{
|
2205
|
+
VALUE result = rb_ary_new();
|
2206
|
+
std::for_each(vector.begin(), vector.end(), [&result](const Value_T& element)
|
2207
|
+
{
|
2208
|
+
VALUE value = detail::To_Ruby<Value_T&>().convert(element);
|
2209
|
+
rb_ary_push(result, value);
|
2210
|
+
});
|
2211
|
+
|
2212
|
+
return result;
|
2213
|
+
}, Return().setValue());
|
871
2214
|
}
|
872
2215
|
|
873
2216
|
void define_to_s()
|
874
2217
|
{
|
875
2218
|
if constexpr (detail::is_ostreamable_v<Value_T>)
|
876
2219
|
{
|
877
|
-
klass_.define_method("to_s", [](const T&
|
2220
|
+
klass_.define_method("to_s", [](const T& vector)
|
878
2221
|
{
|
879
|
-
auto iter =
|
880
|
-
auto finish =
|
2222
|
+
auto iter = vector.begin();
|
2223
|
+
auto finish = vector.size() > 1000 ? vector.begin() + 1000 : vector.end();
|
881
2224
|
|
882
2225
|
std::stringstream stream;
|
883
2226
|
stream << "[";
|
884
2227
|
|
885
2228
|
for (; iter != finish; iter++)
|
886
2229
|
{
|
887
|
-
if (iter ==
|
2230
|
+
if (iter == vector.begin())
|
888
2231
|
{
|
889
2232
|
stream << *iter;
|
890
2233
|
}
|
@@ -900,7 +2243,7 @@ namespace Rice
|
|
900
2243
|
}
|
901
2244
|
else
|
902
2245
|
{
|
903
|
-
klass_.define_method("to_s", [](const T&
|
2246
|
+
klass_.define_method("to_s", [](const T& vector)
|
904
2247
|
{
|
905
2248
|
return "[Not printable]";
|
906
2249
|
});
|
@@ -915,9 +2258,13 @@ namespace Rice
|
|
915
2258
|
template<typename T>
|
916
2259
|
Data_Type<T> define_vector_under(Object module, std::string name)
|
917
2260
|
{
|
918
|
-
if (detail::
|
2261
|
+
if (detail::Registries::instance.types.isDefined<T>())
|
919
2262
|
{
|
920
|
-
|
2263
|
+
// If the vector has been previously seen it will be registered but may
|
2264
|
+
// not be associated with the constant Module::<name>
|
2265
|
+
module.const_set_maybe(name, Data_Type<T>().klass());
|
2266
|
+
|
2267
|
+
return Data_Type<T>();
|
921
2268
|
}
|
922
2269
|
|
923
2270
|
Data_Type<T> result = define_class_under<detail::intrinsic_type<T>>(module, name.c_str());
|
@@ -928,9 +2275,13 @@ namespace Rice
|
|
928
2275
|
template<typename T>
|
929
2276
|
Data_Type<T> define_vector(std::string name)
|
930
2277
|
{
|
931
|
-
if (detail::
|
2278
|
+
if (detail::Registries::instance.types.isDefined<T>())
|
932
2279
|
{
|
933
|
-
|
2280
|
+
// If the vector has been previously seen it will be registered but may
|
2281
|
+
// not be associated with the constant Module::<name>
|
2282
|
+
Object(rb_cObject).const_set_maybe(name, Data_Type<T>().klass());
|
2283
|
+
|
2284
|
+
return Data_Type<T>();
|
934
2285
|
}
|
935
2286
|
|
936
2287
|
Data_Type<T> result = define_class<detail::intrinsic_type<T>>(name.c_str());
|
@@ -956,7 +2307,7 @@ namespace Rice
|
|
956
2307
|
{
|
957
2308
|
Type<T>::verify();
|
958
2309
|
|
959
|
-
if (!detail::
|
2310
|
+
if (!detail::Registries::instance.types.isDefined<std::vector<T>>())
|
960
2311
|
{
|
961
2312
|
define_vector_auto<std::vector<T>>();
|
962
2313
|
}
|
@@ -968,7 +2319,7 @@ namespace Rice
|
|
968
2319
|
template<typename T>
|
969
2320
|
std::vector<T> vectorFromArray(VALUE value)
|
970
2321
|
{
|
971
|
-
|
2322
|
+
long length = protect(rb_array_len, value);
|
972
2323
|
std::vector<T> result(length);
|
973
2324
|
|
974
2325
|
for (long i = 0; i < length; i++)
|
@@ -1022,6 +2373,11 @@ namespace Rice
|
|
1022
2373
|
}
|
1023
2374
|
}
|
1024
2375
|
|
2376
|
+
bool is_convertible(VALUE value)
|
2377
|
+
{
|
2378
|
+
return rb_type(value) == RUBY_T_ARRAY;
|
2379
|
+
}
|
2380
|
+
|
1025
2381
|
private:
|
1026
2382
|
Arg* arg_ = nullptr;
|
1027
2383
|
};
|
@@ -1069,6 +2425,11 @@ namespace Rice
|
|
1069
2425
|
}
|
1070
2426
|
}
|
1071
2427
|
|
2428
|
+
bool is_convertible(VALUE value)
|
2429
|
+
{
|
2430
|
+
return rb_type(value) == RUBY_T_ARRAY;
|
2431
|
+
}
|
2432
|
+
|
1072
2433
|
private:
|
1073
2434
|
Arg* arg_ = nullptr;
|
1074
2435
|
std::vector<T> converted_;
|
@@ -1104,10 +2465,16 @@ namespace Rice
|
|
1104
2465
|
}
|
1105
2466
|
}
|
1106
2467
|
|
2468
|
+
bool is_convertible(VALUE value)
|
2469
|
+
{
|
2470
|
+
return rb_type(value) == RUBY_T_ARRAY;
|
2471
|
+
}
|
2472
|
+
|
1107
2473
|
private:
|
1108
2474
|
std::vector<T> converted_;
|
1109
2475
|
};
|
1110
2476
|
}
|
1111
2477
|
}
|
1112
2478
|
|
2479
|
+
|
1113
2480
|
#endif // Rice__stl__hpp_
|