rice 4.0.4 → 4.1.0

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