rice 4.8.0 → 4.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -1
  3. data/CMakePresets.json +77 -50
  4. data/FindRuby.cmake +1 -1
  5. data/bin/rice-doc.rb +2 -0
  6. data/include/rice/api.hpp +14 -1
  7. data/include/rice/rice.hpp +351 -132
  8. data/include/rice/stl.hpp +319 -256
  9. data/lib/rice/doc/config.rb +57 -57
  10. data/lib/rice/doc/cpp_reference.rb +158 -158
  11. data/lib/rice/doc/doxygen.rb +289 -289
  12. data/lib/rice/doc/mkdocs.rb +332 -332
  13. data/lib/rice/doc/rice.rb +48 -47
  14. data/lib/rice/doc/ruby.rb +26 -26
  15. data/lib/rice/native.rb +15 -15
  16. data/lib/rice/native_registry.rb +12 -17
  17. data/lib/rice/parameter.rb +5 -5
  18. data/lib/rice/rbs.rb +72 -72
  19. data/lib/rice/version.rb +1 -1
  20. data/lib/rubygems/builder.rb +9 -9
  21. data/lib/rubygems_plugin.rb +8 -8
  22. data/rice/Data_Type.ipp +12 -7
  23. data/rice/cpp_api/Class.hpp +5 -0
  24. data/rice/cpp_api/Class.ipp +5 -0
  25. data/rice/cpp_api/Object.hpp +6 -0
  26. data/rice/cpp_api/Object.ipp +5 -0
  27. data/rice/detail/Forwards.hpp +18 -0
  28. data/rice/detail/Forwards.ipp +60 -0
  29. data/rice/detail/Native.ipp +2 -4
  30. data/rice/detail/NativeAttributeGet.ipp +1 -1
  31. data/rice/detail/NativeAttributeSet.hpp +5 -3
  32. data/rice/detail/NativeAttributeSet.ipp +41 -33
  33. data/rice/detail/NativeMethod.ipp +25 -22
  34. data/rice/detail/NativeRegistry.hpp +4 -2
  35. data/rice/detail/NativeRegistry.ipp +42 -9
  36. data/rice/detail/Parameter.ipp +3 -4
  37. data/rice/detail/Type.ipp +4 -0
  38. data/rice/detail/Wrapper.hpp +17 -12
  39. data/rice/detail/Wrapper.ipp +95 -36
  40. data/rice/rice.hpp +3 -0
  41. data/rice/rice_api/NativeRegistry.ipp +14 -1
  42. data/rice/stl/exception.ipp +1 -1
  43. data/rice/stl/filesystem.ipp +1 -1
  44. data/rice/stl/map.ipp +13 -11
  45. data/rice/stl/multimap.ipp +13 -11
  46. data/rice/stl/pair.ipp +14 -8
  47. data/rice/stl/set.ipp +16 -16
  48. data/rice/stl/shared_ptr.hpp +16 -0
  49. data/rice/stl/shared_ptr.ipp +74 -37
  50. data/rice/stl/type_index.ipp +1 -1
  51. data/rice/stl/unique_ptr.hpp +9 -3
  52. data/rice/stl/unique_ptr.ipp +80 -124
  53. data/rice/stl/unordered_map.ipp +14 -12
  54. data/rice/stl/vector.ipp +67 -31
  55. data/test/test_Attribute.cpp +72 -0
  56. data/test/test_Callback.cpp +3 -0
  57. data/test/test_Inheritance.cpp +14 -14
  58. data/test/test_Keep_Alive_No_Wrapper.cpp +6 -2
  59. data/test/test_Stl_Map.cpp +46 -0
  60. data/test/test_Stl_Multimap.cpp +46 -0
  61. data/test/test_Stl_Set.cpp +34 -0
  62. data/test/test_Stl_SharedPtr.cpp +160 -45
  63. data/test/test_Stl_UniquePtr.cpp +48 -3
  64. data/test/test_Stl_Unordered_Map.cpp +46 -0
  65. data/test/test_Stl_Variant.cpp +10 -14
  66. data/test/test_Stl_Vector.cpp +140 -13
  67. data/test/test_Tracking.cpp +3 -0
  68. metadata +3 -1
data/include/rice/stl.hpp CHANGED
@@ -53,7 +53,7 @@ namespace Rice::stl
53
53
  define_method("message", &std::exception::what);
54
54
 
55
55
  define_class_under<std::runtime_error>(rb_mStd, "RuntimeError", rb_eRuntimeError).
56
- define_constructor(Constructor<std::runtime_error, const char*>()).
56
+ define_constructor(Constructor<std::runtime_error, const char*>(), Arg("what")).
57
57
  define_method("message", &std::runtime_error::what);
58
58
  }
59
59
  }
@@ -694,7 +694,7 @@ namespace Rice
694
694
 
695
695
  define_class_under<std::filesystem::path>(rb_mFileSystem, "Path").
696
696
  define_constructor(Constructor<std::filesystem::path>()).
697
- define_constructor(Constructor<std::filesystem::path, std::string>());
697
+ define_constructor(Constructor<std::filesystem::path, std::string>(), Arg("source"));
698
698
  }
699
699
  }
700
700
  }
@@ -990,6 +990,12 @@ namespace Rice
990
990
  template<typename T>
991
991
  class PairHelper
992
992
  {
993
+ using First_T = typename T::first_type;
994
+ using Second_T = typename T::second_type;
995
+ // For pointer types, use the pointer directly; for non-pointer types, use a reference
996
+ using First_Parameter_T = std::conditional_t<std::is_pointer_v<First_T>, First_T, First_T&>;
997
+ using Second_Parameter_T = std::conditional_t<std::is_pointer_v<Second_T>, Second_T, Second_T&>;
998
+
993
999
  public:
994
1000
  PairHelper(Data_Type<T> klass) : klass_(klass)
995
1001
  {
@@ -1002,33 +1008,33 @@ namespace Rice
1002
1008
  void define_constructors()
1003
1009
  {
1004
1010
  klass_.define_constructor(Constructor<T>())
1005
- .define_constructor(Constructor<T, typename T::first_type&, typename T::second_type&>());
1006
-
1007
- if constexpr (std::is_copy_constructible_v<typename T::first_type> && std::is_copy_constructible_v<typename T::second_type>)
1011
+ .define_constructor(Constructor<T, First_Parameter_T, Second_Parameter_T>(), Arg("x").keepAlive(), Arg("y").keepAlive());
1012
+
1013
+ if constexpr (std::is_copy_constructible_v<First_T> && std::is_copy_constructible_v<Second_T>)
1008
1014
  {
1009
- klass_.define_constructor(Constructor<T, const T&>());
1015
+ klass_.define_constructor(Constructor<T, const T&>(), Arg("other"));
1010
1016
  }
1011
1017
  }
1012
1018
 
1013
1019
  void define_attributes()
1014
1020
  {
1015
1021
  // Access methods
1016
- if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::first_type>>>)
1022
+ if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<First_T>>>)
1017
1023
  {
1018
1024
  klass_.define_attr("first", &T::first, Rice::AttrAccess::Read);
1019
1025
  }
1020
1026
  else
1021
1027
  {
1022
- klass_.define_attr("first", &T::first, Rice::AttrAccess::ReadWrite);
1028
+ klass_.define_attr("first", &T::first, Rice::AttrAccess::ReadWrite, Arg("value").keepAlive());
1023
1029
  }
1024
1030
 
1025
- if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::second_type>>>)
1031
+ if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<Second_T>>>)
1026
1032
  {
1027
1033
  klass_.define_attr("second", &T::second, Rice::AttrAccess::Read);
1028
1034
  }
1029
1035
  else
1030
1036
  {
1031
- klass_.define_attr("second", &T::second, Rice::AttrAccess::ReadWrite);
1037
+ klass_.define_attr("second", &T::second, Rice::AttrAccess::ReadWrite, Arg("value").keepAlive());
1032
1038
  }
1033
1039
  }
1034
1040
 
@@ -1130,6 +1136,8 @@ namespace Rice
1130
1136
  using Size_T = typename T::size_type;
1131
1137
  using Difference_T = typename T::difference_type;
1132
1138
  using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
1139
+ // For pointer types, use the pointer directly; for non-pointer types, use a reference
1140
+ using Mapped_Parameter_T = std::conditional_t<std::is_pointer_v<Mapped_T>, Mapped_T, Mapped_T&>;
1133
1141
 
1134
1142
  public:
1135
1143
  MapHelper(Data_Type<T> klass) : klass_(klass)
@@ -1158,7 +1166,7 @@ namespace Rice
1158
1166
 
1159
1167
  if constexpr (std::is_copy_constructible_v<Key_T> && std::is_copy_constructible_v<Value_T>)
1160
1168
  {
1161
- klass_.define_constructor(Constructor<T, const T&>());
1169
+ klass_.define_constructor(Constructor<T, const T&>(), Arg("other"));
1162
1170
  }
1163
1171
  }
1164
1172
 
@@ -1187,11 +1195,11 @@ namespace Rice
1187
1195
  {
1188
1196
  return std::nullopt;
1189
1197
  }
1190
- })
1198
+ }, Arg("key"))
1191
1199
  .define_method("include?", [](T& map, Key_T& key) -> bool
1192
1200
  {
1193
1201
  return map.find(key) != map.end();
1194
- })
1202
+ }, Arg("key"))
1195
1203
  .define_method("keys", [](T& map) -> std::vector<Key_T>
1196
1204
  {
1197
1205
  std::vector<Key_T> result;
@@ -1226,8 +1234,8 @@ namespace Rice
1226
1234
  klass_.define_method("==", [](T& map, T& other)->bool
1227
1235
  {
1228
1236
  return map == other;
1229
- })
1230
- .define_method("value?", [](T& map, Mapped_T& value) -> bool
1237
+ }, Arg("other"))
1238
+ .define_method("value?", [](T& map, Mapped_Parameter_T value) -> bool
1231
1239
  {
1232
1240
  auto it = std::find_if(map.begin(), map.end(),
1233
1241
  [&value](auto& pair)
@@ -1236,15 +1244,15 @@ namespace Rice
1236
1244
  });
1237
1245
 
1238
1246
  return it != map.end();
1239
- });
1247
+ }, Arg("value"));
1240
1248
  rb_define_alias(klass_, "eql?", "==");
1241
1249
  }
1242
1250
  else
1243
1251
  {
1244
- klass_.define_method("value?", [](T&, Mapped_T&) -> bool
1252
+ klass_.define_method("value?", [](T&, Mapped_Parameter_T) -> bool
1245
1253
  {
1246
1254
  return false;
1247
- });
1255
+ }, Arg("value"));
1248
1256
  }
1249
1257
 
1250
1258
  rb_define_alias(klass_, "has_value", "value?");
@@ -1267,12 +1275,12 @@ namespace Rice
1267
1275
  {
1268
1276
  return std::nullopt;
1269
1277
  }
1270
- })
1271
- .define_method("[]=", [](T& map, Key_T key, Mapped_T& value) -> Mapped_T
1278
+ }, Arg("key"))
1279
+ .define_method("[]=", [](T& map, Key_T key, Mapped_Parameter_T value) -> Mapped_T
1272
1280
  {
1273
1281
  map[key] = value;
1274
1282
  return value;
1275
- });
1283
+ }, Arg("key").keepAlive(), Arg("value").keepAlive());
1276
1284
 
1277
1285
  rb_define_alias(klass_, "store", "[]=");
1278
1286
  }
@@ -1733,6 +1741,8 @@ namespace Rice
1733
1741
  using Size_T = typename T::size_type;
1734
1742
  using Difference_T = typename T::difference_type;
1735
1743
  using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
1744
+ // For pointer types, use the pointer directly; for non-pointer types, use a reference
1745
+ using Mapped_Parameter_T = std::conditional_t<std::is_pointer_v<Mapped_T>, Mapped_T, Mapped_T&>;
1736
1746
 
1737
1747
  public:
1738
1748
  MultimapHelper(Data_Type<T> klass) : klass_(klass)
@@ -1760,7 +1770,7 @@ namespace Rice
1760
1770
 
1761
1771
  if constexpr (std::is_copy_constructible_v<Key_T> && std::is_copy_constructible_v<Value_T>)
1762
1772
  {
1763
- klass_.define_constructor(Constructor<T, const T&>());
1773
+ klass_.define_constructor(Constructor<T, const T&>(), Arg("other"));
1764
1774
  }
1765
1775
  }
1766
1776
 
@@ -1789,11 +1799,11 @@ namespace Rice
1789
1799
  }
1790
1800
 
1791
1801
  return result;
1792
- })
1802
+ }, Arg("key"))
1793
1803
  .define_method("include?", [](T& multimap, Key_T& key) -> bool
1794
1804
  {
1795
1805
  return multimap.find(key) != multimap.end();
1796
- })
1806
+ }, Arg("key"))
1797
1807
  .define_method("keys", [](T& multimap) -> std::vector<Key_T>
1798
1808
  {
1799
1809
  std::vector<Key_T> result;
@@ -1828,8 +1838,8 @@ namespace Rice
1828
1838
  klass_.define_method("==", [](T& multimap, T& other)->bool
1829
1839
  {
1830
1840
  return multimap == other;
1831
- })
1832
- .define_method("value?", [](T& multimap, Mapped_T& value) -> bool
1841
+ }, Arg("other"))
1842
+ .define_method("value?", [](T& multimap, Mapped_Parameter_T value) -> bool
1833
1843
  {
1834
1844
  auto it = std::find_if(multimap.begin(), multimap.end(),
1835
1845
  [&value](auto& pair)
@@ -1838,15 +1848,15 @@ namespace Rice
1838
1848
  });
1839
1849
 
1840
1850
  return it != multimap.end();
1841
- });
1851
+ }, Arg("value"));
1842
1852
  rb_define_alias(klass_, "eql?", "==");
1843
1853
  }
1844
1854
  else
1845
1855
  {
1846
- klass_.define_method("value?", [](T&, Mapped_T&) -> bool
1856
+ klass_.define_method("value?", [](T&, Mapped_Parameter_T) -> bool
1847
1857
  {
1848
1858
  return false;
1849
- });
1859
+ }, Arg("value"));
1850
1860
  }
1851
1861
 
1852
1862
  rb_define_alias(klass_, "has_value", "value?");
@@ -1869,13 +1879,13 @@ namespace Rice
1869
1879
  {
1870
1880
  return std::nullopt;
1871
1881
  }
1872
- })
1873
- .define_method("insert", [](T& map, Key_T key, Mapped_T& value) -> Mapped_T
1882
+ }, Arg("key"))
1883
+ .define_method("insert", [](T& map, Key_T key, Mapped_Parameter_T value) -> Mapped_T
1874
1884
  {
1875
1885
  Value_T element{ key, value };
1876
1886
  map.insert(element);
1877
1887
  return value;
1878
- });
1888
+ }, Arg("key").keepAlive(), Arg("value").keepAlive());
1879
1889
  }
1880
1890
 
1881
1891
  void define_enumerable()
@@ -2214,7 +2224,7 @@ namespace Rice
2214
2224
  void define_constructors()
2215
2225
  {
2216
2226
  klass_.define_constructor(Constructor<T>())
2217
- .define_constructor(Constructor<T, const T&>());
2227
+ .define_constructor(Constructor<T, const T&>(), Arg("other"));
2218
2228
  }
2219
2229
 
2220
2230
  void define_capacity_methods()
@@ -2234,11 +2244,11 @@ namespace Rice
2234
2244
  {
2235
2245
  auto iter = self.find(element);
2236
2246
  return iter != self.end();
2237
- })
2247
+ }, Arg("key"))
2238
2248
  .define_method("count", [](T& self, const Key_T element) -> Size_T
2239
2249
  {
2240
2250
  return self.count(element);
2241
- });
2251
+ }, Arg("key"));
2242
2252
  }
2243
2253
 
2244
2254
  void define_modify_methods()
@@ -2249,17 +2259,17 @@ namespace Rice
2249
2259
  {
2250
2260
  self.erase(key);
2251
2261
  return self;
2252
- })
2253
- .define_method("insert", [](T& self, const Value_T value) -> T&
2262
+ }, Arg("key"))
2263
+ .define_method("insert", [](T& self, Parameter_T value) -> T&
2254
2264
  {
2255
2265
  self.insert(value);
2256
2266
  return self;
2257
- })
2267
+ }, Arg("value").keepAlive())
2258
2268
  .define_method("merge", [](T& self, T& other) -> T&
2259
2269
  {
2260
2270
  self.merge(other);
2261
2271
  return self;
2262
- });
2272
+ }, Arg("source"));
2263
2273
 
2264
2274
  rb_define_alias(klass_, "erase", "delete");
2265
2275
  }
@@ -2267,11 +2277,11 @@ namespace Rice
2267
2277
  void define_operators()
2268
2278
  {
2269
2279
  klass_
2270
- .define_method("<<", [](T& self, const Value_T value) -> T&
2280
+ .define_method("<<", [](T& self, Parameter_T value) -> T&
2271
2281
  {
2272
2282
  self.insert(value);
2273
2283
  return self;
2274
- })
2284
+ }, Arg("value").keepAlive())
2275
2285
  .define_method("==", [](const T& self, const T& other) -> bool
2276
2286
  {
2277
2287
  if constexpr (detail::is_comparable_v<Value_T>)
@@ -2282,7 +2292,7 @@ namespace Rice
2282
2292
  {
2283
2293
  return false;
2284
2294
  }
2285
- })
2295
+ }, Arg("other"))
2286
2296
  .define_method("&", [](const T& self, const T& other) -> T
2287
2297
  {
2288
2298
  T result;
@@ -2291,7 +2301,7 @@ namespace Rice
2291
2301
  std::inserter(result, result.begin()));
2292
2302
 
2293
2303
  return result;
2294
- })
2304
+ }, Arg("other"))
2295
2305
  .define_method("|", [](const T& self, const T& other) -> T
2296
2306
  {
2297
2307
  T result;
@@ -2300,7 +2310,7 @@ namespace Rice
2300
2310
  std::inserter(result, result.begin()));
2301
2311
 
2302
2312
  return result;
2303
- })
2313
+ }, Arg("other"))
2304
2314
  .define_method("-", [](const T& self, const T& other) -> T
2305
2315
  {
2306
2316
  T result;
@@ -2309,7 +2319,7 @@ namespace Rice
2309
2319
  std::inserter(result, result.begin()));
2310
2320
 
2311
2321
  return result;
2312
- })
2322
+ }, Arg("other"))
2313
2323
  .define_method("^", [](const T& self, const T& other) -> T
2314
2324
  {
2315
2325
  T result;
@@ -2318,17 +2328,17 @@ namespace Rice
2318
2328
  std::inserter(result, result.begin()));
2319
2329
 
2320
2330
  return result;
2321
- })
2331
+ }, Arg("other"))
2322
2332
  .define_method("<", [](const T& self, const T& other) -> bool
2323
2333
  {
2324
2334
  return std::includes(other.begin(), other.end(),
2325
2335
  self.begin(), self.end());
2326
- })
2336
+ }, Arg("other"))
2327
2337
  .define_method(">", [](const T& self, const T& other) -> bool
2328
2338
  {
2329
2339
  return std::includes(self.begin(), self.end(),
2330
2340
  other.begin(), other.end());
2331
- });
2341
+ }, Arg("other"));
2332
2342
 
2333
2343
  rb_define_alias(klass_, "eql?", "==");
2334
2344
  rb_define_alias(klass_, "intersection", "&");
@@ -2687,11 +2697,26 @@ namespace Rice
2687
2697
  Data_Type<std::shared_ptr<T>> define_shared_ptr(std::string klassName = "");
2688
2698
  }
2689
2699
 
2700
+ namespace Rice::detail
2701
+ {
2702
+ template<typename T>
2703
+ class Wrapper<std::shared_ptr<T>> : public WrapperBase
2704
+ {
2705
+ public:
2706
+ Wrapper(rb_data_type_t* rb_data_type, const std::shared_ptr<T>& data);
2707
+ ~Wrapper();
2708
+ void* get(rb_data_type_t* requestedType) override;
2709
+
2710
+ private:
2711
+ std::shared_ptr<T> data_;
2712
+ rb_data_type_t* inner_rb_data_type_;
2713
+ };
2714
+ }
2715
+
2690
2716
 
2691
2717
  // --------- shared_ptr.ipp ---------
2692
2718
  #include <memory>
2693
2719
 
2694
- // --------- Enable creation of std::shared_ptr from Ruby ---------
2695
2720
  namespace Rice
2696
2721
  {
2697
2722
  template<typename T>
@@ -2713,76 +2738,114 @@ namespace Rice
2713
2738
  }
2714
2739
 
2715
2740
  Identifier id(klassName);
2716
- Data_Type_T result = define_class_under<SharedPtr_T>(rb_mStd, id);
2741
+ Data_Type_T result = define_class_under<detail::intrinsic_type<SharedPtr_T>>(rb_mStd, id).
2742
+ define_method("get", &SharedPtr_T::get).
2743
+ define_method("swap", &SharedPtr_T::swap, Arg("r")).
2744
+ define_method("use_count", &SharedPtr_T::use_count).
2745
+ define_method("empty?", [](SharedPtr_T& self)->bool
2746
+ {
2747
+ return !self;
2748
+ });
2717
2749
 
2718
- // std::shared_ptr<void> cannot be constructed from void* because void is incomplete
2719
- // and the deleter cannot be determined. So skip the constructor for void.
2720
- // std::shared_ptr<T[]> (array types) also skip constructor - arrays need special handling.
2721
- if constexpr (!std::is_void_v<T> && !std::is_array_v<T>)
2750
+ if constexpr (!std::is_void_v<T>)
2722
2751
  {
2723
2752
  result.define_constructor(Constructor<SharedPtr_T, typename SharedPtr_T::element_type*>(), Arg("value").takeOwnership());
2724
2753
  }
2725
2754
 
2726
- result.
2727
- define_method("get", &SharedPtr_T::get).
2728
- define_method("use_count", &SharedPtr_T::use_count).
2729
- define_method("empty?", &SharedPtr_T::operator bool);
2755
+ // Setup delegation to forward T's methods via get (only for non-fundamental, non-void types)
2756
+ if constexpr (!std::is_void_v<T> && !std::is_fundamental_v<T>)
2757
+ {
2758
+ detail::define_forwarding(result.klass(), Data_Type<T>::klass());
2759
+ }
2730
2760
 
2731
2761
  return result;
2732
2762
  }
2733
2763
  }
2734
2764
 
2735
- // --------- Type/To_Ruby/From_Ruby ---------
2765
+ // --------- Wrapper ---------
2736
2766
  namespace Rice::detail
2737
2767
  {
2738
2768
  template<typename T>
2739
- struct Type<std::shared_ptr<T>>
2769
+ Wrapper<std::shared_ptr<T>>::Wrapper(rb_data_type_t* rb_data_type, const std::shared_ptr<T>& data)
2770
+ : WrapperBase(rb_data_type), data_(data)
2740
2771
  {
2741
- static bool verify()
2772
+ using Intrinsic_T = intrinsic_type<T>;
2773
+
2774
+ if constexpr (std::is_fundamental_v<Intrinsic_T>)
2742
2775
  {
2743
- if constexpr (std::is_fundamental_v<T>)
2744
- {
2745
- Type<Pointer<T>>::verify();
2746
- Type<Buffer<T>>::verify();
2747
- }
2748
- else
2749
- {
2750
- if (!Type<intrinsic_type<T>>::verify())
2751
- {
2752
- return false;
2753
- }
2754
- }
2776
+ inner_rb_data_type_ = Data_Type<Pointer<Intrinsic_T>>::ruby_data_type();
2777
+ }
2778
+ else
2779
+ {
2780
+ inner_rb_data_type_ = Data_Type<Intrinsic_T>::ruby_data_type();
2781
+ }
2782
+ }
2755
2783
 
2756
- define_shared_ptr<T>();
2784
+ template<typename T>
2785
+ Wrapper<std::shared_ptr<T>>::~Wrapper()
2786
+ {
2787
+ Registries::instance.instances.remove(this->get(this->rb_data_type_));
2788
+ }
2757
2789
 
2758
- return true;
2790
+ template<typename T>
2791
+ void* Wrapper<std::shared_ptr<T>>::get(rb_data_type_t* requestedType)
2792
+ {
2793
+ if (rb_typeddata_inherited_p(this->rb_data_type_, requestedType))
2794
+ {
2795
+ return &this->data_;
2759
2796
  }
2760
- };
2797
+ else if (rb_typeddata_inherited_p(this->inner_rb_data_type_, requestedType))
2798
+ {
2799
+ return this->data_.get();
2800
+ }
2801
+ else
2802
+ {
2803
+ throw Exception(rb_eTypeError, "wrong argument type (expected %s)",
2804
+ requestedType->wrap_struct_name);
2805
+ }
2806
+ }
2807
+ }
2761
2808
 
2762
- // Specialization for array types std::shared_ptr<T[]>
2809
+ // --------- Type ---------
2810
+ namespace Rice::detail
2811
+ {
2763
2812
  template<typename T>
2764
- struct Type<std::shared_ptr<T[]>>
2813
+ struct Type<std::shared_ptr<T>>
2765
2814
  {
2766
2815
  static bool verify()
2767
2816
  {
2817
+ bool result = true;
2768
2818
  if constexpr (std::is_fundamental_v<T>)
2769
2819
  {
2770
- Type<Pointer<T>>::verify();
2771
- Type<Buffer<T>>::verify();
2820
+ result = result && Type<Pointer<T>>::verify();
2772
2821
  }
2773
2822
  else
2774
2823
  {
2775
- if (!Type<intrinsic_type<T>>::verify())
2776
- {
2777
- return false;
2778
- }
2824
+ result = result && Type<T>::verify();
2825
+ }
2826
+
2827
+ if (result)
2828
+ {
2829
+ define_shared_ptr<T>();
2779
2830
  }
2780
2831
 
2781
- define_shared_ptr<T[]>();
2832
+ return result;
2833
+ }
2834
+ };
2782
2835
 
2836
+ #ifdef __GLIBCXX__
2837
+ // libstdc++ implementation detail: std::shared_ptr inherits from
2838
+ // std::__shared_ptr<T, _Lock_policy>. Methods like swap() expose this
2839
+ // internal type through their parameter signatures.
2840
+ template<typename T, __gnu_cxx::_Lock_policy Policy>
2841
+ struct Type<std::__shared_ptr<T, Policy>>
2842
+ {
2843
+ static bool verify()
2844
+ {
2783
2845
  return true;
2784
2846
  }
2785
2847
  };
2848
+ #endif
2786
2849
  }
2787
2850
 
2788
2851
 
@@ -2940,7 +3003,7 @@ namespace Rice::stl
2940
3003
  {
2941
3004
  Module rb_mStd = define_module("Std");
2942
3005
  return define_class_under<std::type_index>(rb_mStd, "TypeIndex").
2943
- define_constructor(Constructor<std::type_index, const std::type_info&>()).
3006
+ define_constructor(Constructor<std::type_index, const std::type_info&>(), Arg("target")).
2944
3007
  define_method("hash_code", &std::type_index::hash_code).
2945
3008
  define_method("name", &std::type_index::name);
2946
3009
  }
@@ -3301,19 +3364,25 @@ namespace Rice::detail
3301
3364
 
3302
3365
  // ========= unique_ptr.hpp =========
3303
3366
 
3367
+ namespace Rice
3368
+ {
3369
+ template<typename T>
3370
+ Data_Type<std::unique_ptr<T>> define_unique_ptr(std::string klassName = "");
3371
+ }
3372
+
3304
3373
  namespace Rice::detail
3305
3374
  {
3306
3375
  template<typename T>
3307
3376
  class Wrapper<std::unique_ptr<T>> : public WrapperBase
3308
3377
  {
3309
3378
  public:
3310
- Wrapper(std::unique_ptr<T>&& data);
3379
+ Wrapper(rb_data_type_t* rb_data_type, std::unique_ptr<T>&& data);
3311
3380
  ~Wrapper();
3312
- void* get() override;
3313
- std::unique_ptr<T>& data();
3381
+ void* get(rb_data_type_t* requestedType) override;
3314
3382
 
3315
3383
  private:
3316
3384
  std::unique_ptr<T> data_;
3385
+ rb_data_type_t* inner_rb_data_type_;
3317
3386
  };
3318
3387
  }
3319
3388
 
@@ -3321,136 +3390,124 @@ namespace Rice::detail
3321
3390
  // --------- unique_ptr.ipp ---------
3322
3391
  #include <memory>
3323
3392
 
3324
- namespace Rice::detail
3393
+ namespace Rice
3325
3394
  {
3326
3395
  template<typename T>
3327
- inline Wrapper<std::unique_ptr<T>>::Wrapper(std::unique_ptr<T>&& data)
3328
- : data_(std::move(data))
3329
- {
3330
- }
3331
-
3332
- template<typename T>
3333
- inline Wrapper<std::unique_ptr<T>>::~Wrapper()
3334
- {
3335
- Registries::instance.instances.remove(this->get());
3336
- }
3337
-
3338
- template<typename T>
3339
- inline void* Wrapper<std::unique_ptr<T>>::get()
3340
- {
3341
- return (void*)this->data_.get();
3342
- }
3343
-
3344
- template<typename T>
3345
- inline std::unique_ptr<T>& Wrapper<std::unique_ptr<T>>::data()
3346
- {
3347
- return data_;
3348
- }
3349
-
3350
- template <typename T>
3351
- class To_Ruby<std::unique_ptr<T>>
3396
+ Data_Type<std::unique_ptr<T>> define_unique_ptr(std::string klassName)
3352
3397
  {
3353
- public:
3354
- To_Ruby() = default;
3398
+ using UniquePtr_T = std::unique_ptr<T>;
3399
+ using Data_Type_T = Data_Type<UniquePtr_T>;
3355
3400
 
3356
- explicit To_Ruby(Arg* arg) : arg_(arg)
3401
+ if (klassName.empty())
3357
3402
  {
3403
+ detail::TypeMapper<UniquePtr_T> typeMapper;
3404
+ klassName = typeMapper.rubyName();
3358
3405
  }
3359
3406
 
3360
- VALUE convert(std::unique_ptr<T>& data)
3407
+ Module rb_mStd = define_module("Std");
3408
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
3361
3409
  {
3362
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
3363
- return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
3410
+ return Data_Type_T();
3364
3411
  }
3365
3412
 
3366
- VALUE convert(std::unique_ptr<T>&& data)
3413
+ Identifier id(klassName);
3414
+ Data_Type_T result = define_class_under<detail::intrinsic_type<UniquePtr_T>>(rb_mStd, id).
3415
+ define_method("get", &UniquePtr_T::get).
3416
+ define_method("release", &UniquePtr_T::release).
3417
+ define_method("reset", &UniquePtr_T::reset, Arg("ptr")).
3418
+ define_method("swap", &UniquePtr_T::swap, Arg("other")).
3419
+ define_method("empty?", [](UniquePtr_T& self)->bool
3420
+ {
3421
+ return !self;
3422
+ });
3423
+
3424
+ // Setup delegation to forward T's methods via get (only for non-fundamental, non-void types)
3425
+ if constexpr (!std::is_void_v<T> && !std::is_fundamental_v<T>)
3367
3426
  {
3368
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
3369
- return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
3427
+ detail::define_forwarding(result.klass(), Data_Type<T>::klass());
3370
3428
  }
3371
3429
 
3372
- private:
3373
- Arg* arg_ = nullptr;
3374
- };
3430
+ return result;
3431
+ }
3432
+ }
3375
3433
 
3376
- template <typename T>
3377
- class To_Ruby<std::unique_ptr<T>&>
3434
+ // --------- Wrapper ---------
3435
+ namespace Rice::detail
3436
+ {
3437
+ template<typename T>
3438
+ Wrapper<std::unique_ptr<T>>::Wrapper(rb_data_type_t* rb_data_type, std::unique_ptr<T>&& data)
3439
+ : WrapperBase(rb_data_type), data_(std::move(data))
3378
3440
  {
3379
- public:
3380
- To_Ruby() = default;
3441
+ using Intrinsic_T = intrinsic_type<T>;
3381
3442
 
3382
- explicit To_Ruby(Arg* arg) : arg_(arg)
3443
+ if constexpr (std::is_fundamental_v<Intrinsic_T>)
3383
3444
  {
3445
+ inner_rb_data_type_ = Data_Type<Pointer<Intrinsic_T>>::ruby_data_type();
3384
3446
  }
3385
-
3386
- VALUE convert(std::unique_ptr<T>& data)
3447
+ else
3387
3448
  {
3388
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
3389
- return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
3449
+ inner_rb_data_type_ = Data_Type<Intrinsic_T>::ruby_data_type();
3390
3450
  }
3451
+ }
3391
3452
 
3392
- private:
3393
- Arg* arg_ = nullptr;
3394
- };
3453
+ template<typename T>
3454
+ Wrapper<std::unique_ptr<T>>::~Wrapper()
3455
+ {
3456
+ Registries::instance.instances.remove(this->get(this->rb_data_type_));
3457
+ }
3395
3458
 
3396
- template <typename T>
3397
- class From_Ruby<std::unique_ptr<T>>
3459
+ template<typename T>
3460
+ void* Wrapper<std::unique_ptr<T>>::get(rb_data_type_t* requestedType)
3398
3461
  {
3399
- public:
3400
- Wrapper<std::unique_ptr<T>>* is_same_smart_ptr(VALUE value)
3462
+ if (rb_typeddata_inherited_p(this->rb_data_type_, requestedType))
3401
3463
  {
3402
- WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
3403
- return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
3464
+ return &this->data_;
3404
3465
  }
3405
-
3406
- From_Ruby() = default;
3407
-
3408
- explicit From_Ruby(Arg* arg) : arg_(arg)
3466
+ else if (rb_typeddata_inherited_p(this->inner_rb_data_type_, requestedType))
3409
3467
  {
3468
+ return this->data_.get();
3410
3469
  }
3470
+ else
3471
+ {
3472
+ throw Exception(rb_eTypeError, "wrong argument type (expected %s)",
3473
+ requestedType->wrap_struct_name);
3474
+ }
3475
+ }
3411
3476
 
3412
- double is_convertible(VALUE value)
3477
+ }
3478
+
3479
+ // --------- Type ---------
3480
+ namespace Rice::detail
3481
+ {
3482
+ template<typename T>
3483
+ struct Type<std::unique_ptr<T>>
3484
+ {
3485
+ static bool verify()
3413
3486
  {
3414
- if (!is_same_smart_ptr(value))
3487
+ bool result = true;
3488
+ if constexpr (std::is_fundamental_v<T>)
3415
3489
  {
3416
- return Convertible::None;
3490
+ result = result && Type<Pointer<T>>::verify();
3417
3491
  }
3418
-
3419
- switch (rb_type(value))
3492
+ else
3420
3493
  {
3421
- case RUBY_T_DATA:
3422
- return Convertible::Exact;
3423
- break;
3424
- default:
3425
- return Convertible::None;
3494
+ result = result && Type<T>::verify();
3426
3495
  }
3427
- }
3428
3496
 
3429
- std::unique_ptr<T> convert(VALUE value)
3430
- {
3431
- Wrapper<std::unique_ptr<T>>* wrapper = is_same_smart_ptr(value);
3432
- if (!wrapper)
3497
+ if (result)
3433
3498
  {
3434
- std::string message = "Invalid smart pointer wrapper";
3435
- throw std::runtime_error(message.c_str());
3499
+ define_unique_ptr<T>();
3436
3500
  }
3437
- return std::move(wrapper->data());
3438
- }
3439
3501
 
3440
- private:
3441
- Arg* arg_ = nullptr;
3502
+ return result;
3503
+ }
3442
3504
  };
3443
3505
 
3506
+ // --------- From_Ruby ---------
3444
3507
  template <typename T>
3445
- class From_Ruby<std::unique_ptr<T>&>
3508
+ class From_Ruby<std::unique_ptr<T>>
3446
3509
  {
3447
3510
  public:
3448
- Wrapper<std::unique_ptr<T>>* is_same_smart_ptr(VALUE value)
3449
- {
3450
- WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
3451
- return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
3452
- }
3453
-
3454
3511
  From_Ruby() = default;
3455
3512
 
3456
3513
  explicit From_Ruby(Arg* arg) : arg_(arg)
@@ -3459,11 +3516,6 @@ namespace Rice::detail
3459
3516
 
3460
3517
  double is_convertible(VALUE value)
3461
3518
  {
3462
- if (!is_same_smart_ptr(value))
3463
- {
3464
- return Convertible::None;
3465
- }
3466
-
3467
3519
  switch (rb_type(value))
3468
3520
  {
3469
3521
  case RUBY_T_DATA:
@@ -3474,43 +3526,16 @@ namespace Rice::detail
3474
3526
  }
3475
3527
  }
3476
3528
 
3477
- std::unique_ptr<T>& convert(VALUE value)
3529
+ std::unique_ptr<T> convert(VALUE value)
3478
3530
  {
3479
- Wrapper<std::unique_ptr<T>>* wrapper = is_same_smart_ptr(value);
3480
- if (!wrapper)
3481
- {
3482
- std::string message = "Invalid smart pointer wrapper";
3483
- throw std::runtime_error(message.c_str());
3484
- }
3485
- return wrapper->data();
3531
+ std::unique_ptr<T>* result = detail::unwrap<std::unique_ptr<T>>(value, Data_Type<std::unique_ptr<T>>::ruby_data_type(), this->arg_ && this->arg_->isOwner());
3532
+ // The reason we need this overriden From_Ruby is to do this std::move.
3533
+ return std::move(*result);
3486
3534
  }
3487
3535
 
3488
3536
  private:
3489
3537
  Arg* arg_ = nullptr;
3490
3538
  };
3491
-
3492
- template<typename T>
3493
- struct Type<std::unique_ptr<T>>
3494
- {
3495
- static bool verify()
3496
- {
3497
- if constexpr (std::is_fundamental_v<T>)
3498
- {
3499
- return Type<Pointer<T>>::verify();
3500
- return Type<Buffer<T>>::verify();
3501
- }
3502
- else
3503
- {
3504
- return Type<T>::verify();
3505
- }
3506
- }
3507
-
3508
- static VALUE rubyKlass()
3509
- {
3510
- TypeMapper<T> typeMapper;
3511
- return typeMapper.rubyKlass();
3512
- }
3513
- };
3514
3539
  }
3515
3540
 
3516
3541
 
@@ -3540,6 +3565,8 @@ namespace Rice
3540
3565
  using Size_T = typename T::size_type;
3541
3566
  using Difference_T = typename T::difference_type;
3542
3567
  using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
3568
+ // For pointer types, use the pointer directly; for non-pointer types, use a reference
3569
+ using Mapped_Parameter_T = std::conditional_t<std::is_pointer_v<Mapped_T>, Mapped_T, Mapped_T&>;
3543
3570
 
3544
3571
  public:
3545
3572
  UnorderedMapHelper(Data_Type<T> klass) : klass_(klass)
@@ -3559,7 +3586,7 @@ namespace Rice
3559
3586
 
3560
3587
  void register_pair()
3561
3588
  {
3562
- define_pair<const Key_T, T>();
3589
+ define_pair<const Key_T, Mapped_T>();
3563
3590
  }
3564
3591
 
3565
3592
  void define_constructors()
@@ -3568,7 +3595,7 @@ namespace Rice
3568
3595
 
3569
3596
  if constexpr (std::is_copy_constructible_v<Key_T> && std::is_copy_constructible_v<Value_T>)
3570
3597
  {
3571
- klass_.define_constructor(Constructor<T, const T&>());
3598
+ klass_.define_constructor(Constructor<T, const T&>(), Arg("other"));
3572
3599
  }
3573
3600
  }
3574
3601
 
@@ -3597,11 +3624,11 @@ namespace Rice
3597
3624
  {
3598
3625
  return std::nullopt;
3599
3626
  }
3600
- })
3627
+ }, Arg("key"))
3601
3628
  .define_method("include?", [](T& unordered_map, Key_T& key) -> bool
3602
3629
  {
3603
3630
  return unordered_map.find(key) != unordered_map.end();
3604
- })
3631
+ }, Arg("key"))
3605
3632
  .define_method("keys", [](T& unordered_map) -> std::vector<Key_T>
3606
3633
  {
3607
3634
  std::vector<Key_T> result;
@@ -3636,8 +3663,8 @@ namespace Rice
3636
3663
  klass_.define_method("==", [](T& unordered_map, T& other)->bool
3637
3664
  {
3638
3665
  return unordered_map == other;
3639
- })
3640
- .define_method("value?", [](T& unordered_map, Mapped_T& value) -> bool
3666
+ }, Arg("other"))
3667
+ .define_method("value?", [](T& unordered_map, Mapped_Parameter_T value) -> bool
3641
3668
  {
3642
3669
  auto it = std::find_if(unordered_map.begin(), unordered_map.end(),
3643
3670
  [&value](auto& pair)
@@ -3646,15 +3673,15 @@ namespace Rice
3646
3673
  });
3647
3674
 
3648
3675
  return it != unordered_map.end();
3649
- });
3676
+ }, Arg("value"));
3650
3677
  rb_define_alias(klass_, "eql?", "==");
3651
3678
  }
3652
3679
  else
3653
3680
  {
3654
- klass_.define_method("value?", [](T&, Mapped_T&) -> bool
3681
+ klass_.define_method("value?", [](T&, Mapped_Parameter_T) -> bool
3655
3682
  {
3656
3683
  return false;
3657
- });
3684
+ }, Arg("value"));
3658
3685
  }
3659
3686
 
3660
3687
  rb_define_alias(klass_, "has_value", "value?");
@@ -3677,12 +3704,12 @@ namespace Rice
3677
3704
  {
3678
3705
  return std::nullopt;
3679
3706
  }
3680
- })
3681
- .define_method("[]=", [](T& unordered_map, Key_T key, Mapped_T& value) -> Mapped_T
3707
+ }, Arg("key"))
3708
+ .define_method("[]=", [](T& unordered_map, Key_T key, Mapped_Parameter_T value) -> Mapped_T
3682
3709
  {
3683
3710
  unordered_map[key] = value;
3684
3711
  return value;
3685
- });
3712
+ }, Arg("key").keepAlive(), Arg("value").keepAlive());
3686
3713
 
3687
3714
  rb_define_alias(klass_, "store", "[]=");
3688
3715
  }
@@ -4061,13 +4088,13 @@ namespace Rice
4061
4088
 
4062
4089
  if constexpr (std::is_copy_constructible_v<Value_T>)
4063
4090
  {
4064
- klass_.define_constructor(Constructor<T, const T&>())
4065
- .define_constructor(Constructor<T, Size_T, const Parameter_T>());
4091
+ klass_.define_constructor(Constructor<T, const T&>(), Arg("other"))
4092
+ .define_constructor(Constructor<T, Size_T, const Parameter_T>(), Arg("count"), Arg("value"));
4066
4093
  }
4067
4094
 
4068
4095
  if constexpr (std::is_default_constructible_v<Value_T>)
4069
4096
  {
4070
- klass_.define_constructor(Constructor<T, Size_T>());
4097
+ klass_.define_constructor(Constructor<T, Size_T>(), Arg("count"));
4071
4098
  }
4072
4099
 
4073
4100
  // Allow creation of a vector from a Ruby Array
@@ -4075,18 +4102,20 @@ namespace Rice
4075
4102
  {
4076
4103
  // Create a new vector from the array
4077
4104
  T* data = new T();
4078
- data->reserve(array.size());
4079
4105
 
4106
+ // Wrap the vector
4107
+ detail::Wrapper<T*>* wrapper = detail::wrapConstructed<T>(self, Data_Type<T>::ruby_data_type(), data);
4108
+
4109
+ // Now populate the vector
4080
4110
  detail::From_Ruby<Value_T> fromRuby;
4111
+ data->reserve(array.size());
4081
4112
 
4082
4113
  for (long i = 0; i < array.size(); i++)
4083
4114
  {
4084
4115
  VALUE element = detail::protect(rb_ary_entry, array, i);
4085
4116
  data->push_back(fromRuby.convert(element));
4117
+ wrapper->addKeepAlive(element);
4086
4118
  }
4087
-
4088
- // Wrap the vector
4089
- detail::wrapConstructed<T>(self, Data_Type<T>::ruby_data_type(), data);
4090
4119
  });
4091
4120
  }
4092
4121
 
@@ -4094,18 +4123,18 @@ namespace Rice
4094
4123
  {
4095
4124
  if constexpr (std::is_default_constructible_v<Value_T> && std::is_same_v<Value_T, bool>)
4096
4125
  {
4097
- klass_.define_method("resize", static_cast<void (T::*)(const size_t, bool)>(&T::resize));
4126
+ klass_.define_method("resize", static_cast<void (T::*)(const size_t, bool)>(&T::resize), Arg("count"), Arg("value"));
4098
4127
  }
4099
4128
  else if constexpr (std::is_default_constructible_v<Value_T>)
4100
4129
  {
4101
- klass_.define_method("resize", static_cast<void (T::*)(const size_t)>(&T::resize));
4130
+ klass_.define_method("resize", static_cast<void (T::*)(const size_t)>(&T::resize), Arg("count"));
4102
4131
  }
4103
4132
  else
4104
4133
  {
4105
4134
  klass_.define_method("resize", [](const T&, Size_T)
4106
4135
  {
4107
4136
  // Do nothing
4108
- });
4137
+ }, Arg("count"));
4109
4138
  }
4110
4139
  }
4111
4140
 
@@ -4114,13 +4143,11 @@ namespace Rice
4114
4143
  klass_.define_method("empty?", &T::empty)
4115
4144
  .define_method("capacity", &T::capacity)
4116
4145
  .define_method("max_size", &T::max_size)
4117
- .define_method("reserve", &T::reserve)
4146
+ .define_method("reserve", &T::reserve, Arg("new_cap"))
4118
4147
  .define_method("size", &T::size);
4119
-
4148
+
4120
4149
  rb_define_alias(klass_, "count", "size");
4121
4150
  rb_define_alias(klass_, "length", "size");
4122
- //detail::protect(rb_define_alias, klass_, "count", "size");
4123
- //detail::protect(rb_define_alias, klass_, "length", "size");
4124
4151
  }
4125
4152
 
4126
4153
  void define_access_methods()
@@ -4161,7 +4188,7 @@ namespace Rice
4161
4188
  {
4162
4189
  return vector[index];
4163
4190
  }
4164
- })
4191
+ }, Arg("pos"))
4165
4192
  .template define_method<Value_T*(T::*)()>("data", &T::data, ReturnBuffer());
4166
4193
  }
4167
4194
  else
@@ -4200,7 +4227,7 @@ namespace Rice
4200
4227
  {
4201
4228
  return vector[index];
4202
4229
  }
4203
- });
4230
+ }, Arg("pos"));
4204
4231
  }
4205
4232
 
4206
4233
  klass_.define_method("[]", [this](T& vector, Difference_T start, Difference_T length) -> VALUE
@@ -4233,7 +4260,7 @@ namespace Rice
4233
4260
 
4234
4261
  return result;
4235
4262
  }
4236
- }, Return().setValue());
4263
+ }, Arg("start"), Arg("length"), Return().setValue());
4237
4264
 
4238
4265
  rb_define_alias(klass_, "at", "[]");
4239
4266
  }
@@ -4246,7 +4273,7 @@ namespace Rice
4246
4273
  klass_.define_method("==", [](T& vector, T& other)->bool
4247
4274
  {
4248
4275
  return vector == other;
4249
- })
4276
+ }, Arg("other"))
4250
4277
  .define_method("delete", [](T& vector, Parameter_T element) -> std::optional<Value_T>
4251
4278
  {
4252
4279
  auto iter = std::find(vector.begin(), vector.end(), element);
@@ -4264,11 +4291,11 @@ namespace Rice
4264
4291
  {
4265
4292
  return std::nullopt;
4266
4293
  }
4267
- })
4294
+ }, Arg("value"))
4268
4295
  .define_method("include?", [](T& vector, Parameter_T element)
4269
4296
  {
4270
4297
  return std::find(vector.begin(), vector.end(), element) != vector.end();
4271
- })
4298
+ }, Arg("value"))
4272
4299
  .define_method("index", [](T& vector, Parameter_T element) -> std::optional<Difference_T>
4273
4300
  {
4274
4301
  auto iter = std::find(vector.begin(), vector.end(), element);
@@ -4280,7 +4307,7 @@ namespace Rice
4280
4307
  {
4281
4308
  return iter - vector.begin();
4282
4309
  }
4283
- });
4310
+ }, Arg("value"));
4284
4311
  rb_define_alias(klass_, "eql?", "==");
4285
4312
  }
4286
4313
  else
@@ -4288,15 +4315,15 @@ namespace Rice
4288
4315
  klass_.define_method("delete", [](T&, Parameter_T) -> std::optional<Value_T>
4289
4316
  {
4290
4317
  return std::nullopt;
4291
- })
4318
+ }, Arg("value"))
4292
4319
  .define_method("include?", [](const T&, Parameter_T)
4293
4320
  {
4294
4321
  return false;
4295
- })
4322
+ }, Arg("value"))
4296
4323
  .define_method("index", [](const T&, Parameter_T) -> std::optional<Difference_T>
4297
4324
  {
4298
4325
  return std::nullopt;
4299
- });
4326
+ }, Arg("value"));
4300
4327
  }
4301
4328
  }
4302
4329
 
@@ -4318,7 +4345,7 @@ namespace Rice
4318
4345
  vector.erase(iter);
4319
4346
  return std::nullopt;
4320
4347
  }
4321
- })
4348
+ }, Arg("pos"))
4322
4349
  .define_method("insert", [this](T& vector, Difference_T index, Parameter_T element) -> T&
4323
4350
  {
4324
4351
  size_t normalized = normalizeIndex(vector.size(), index, true);
@@ -4332,7 +4359,7 @@ namespace Rice
4332
4359
  auto iter = vector.begin() + normalized;
4333
4360
  vector.insert(iter, std::move(element));
4334
4361
  return vector;
4335
- })
4362
+ }, Arg("pos"), Arg("value").keepAlive())
4336
4363
  .define_method("pop", [](T& vector) -> std::optional<Value_T>
4337
4364
  {
4338
4365
  if constexpr (!std::is_copy_assignable_v<Value_T>)
@@ -4355,13 +4382,13 @@ namespace Rice
4355
4382
  {
4356
4383
  vector.push_back(std::move(element));
4357
4384
  return vector;
4358
- })
4385
+ }, Arg("value").keepAlive())
4359
4386
  .define_method("shrink_to_fit", &T::shrink_to_fit)
4360
4387
  .define_method("[]=", [this](T& vector, Difference_T index, Parameter_T element) -> void
4361
4388
  {
4362
4389
  index = normalizeIndex(vector.size(), index, true);
4363
4390
  vector[index] = std::move(element);
4364
- });
4391
+ }, Arg("pos"), Arg("value").keepAlive());
4365
4392
 
4366
4393
  rb_define_alias(klass_, "push_back", "push");
4367
4394
  rb_define_alias(klass_, "<<", "push");
@@ -4495,7 +4522,19 @@ namespace Rice
4495
4522
  case RUBY_T_ARRAY:
4496
4523
  if constexpr (std::is_default_constructible_v<T>)
4497
4524
  {
4498
- return Convertible::Exact;
4525
+ // For proper overload resolution when a function has multiple vector type
4526
+ // overloads (e.g., vector<A>& and vector<B>&), we must check if the array
4527
+ // elements can actually be converted to T. Otherwise all vector overloads
4528
+ // score equally and the wrong one may be selected.
4529
+ long size = RARRAY_LEN(value);
4530
+ if (size == 0)
4531
+ {
4532
+ return Convertible::Exact;
4533
+ }
4534
+
4535
+ From_Ruby<remove_cv_recursive_t<T>> fromRuby;
4536
+ VALUE first = rb_ary_entry(value, 0);
4537
+ return fromRuby.is_convertible(first);
4499
4538
  }
4500
4539
  default:
4501
4540
  return Convertible::None;
@@ -4551,7 +4590,19 @@ namespace Rice
4551
4590
  case RUBY_T_ARRAY:
4552
4591
  if constexpr (std::is_default_constructible_v<T>)
4553
4592
  {
4554
- return Convertible::Exact;
4593
+ // For proper overload resolution when a function has multiple vector type
4594
+ // overloads (e.g., vector<A>& and vector<B>&), we must check if the array
4595
+ // elements can actually be converted to T. Otherwise all vector overloads
4596
+ // score equally and the wrong one may be selected.
4597
+ long size = RARRAY_LEN(value);
4598
+ if (size == 0)
4599
+ {
4600
+ return Convertible::Exact;
4601
+ }
4602
+
4603
+ From_Ruby<remove_cv_recursive_t<T>> fromRuby;
4604
+ VALUE first = rb_ary_entry(value, 0);
4605
+ return fromRuby.is_convertible(first);
4555
4606
  }
4556
4607
  default:
4557
4608
  return Convertible::None;
@@ -4612,7 +4663,19 @@ namespace Rice
4612
4663
  case RUBY_T_ARRAY:
4613
4664
  if constexpr (std::is_default_constructible_v<T>)
4614
4665
  {
4615
- return Convertible::Exact;
4666
+ // For proper overload resolution when a function has multiple vector type
4667
+ // overloads (e.g., vector<A>& and vector<B>&), we must check if the array
4668
+ // elements can actually be converted to T. Otherwise all vector overloads
4669
+ // score equally and the wrong one may be selected.
4670
+ long size = RARRAY_LEN(value);
4671
+ if (size == 0)
4672
+ {
4673
+ return Convertible::Exact;
4674
+ }
4675
+
4676
+ From_Ruby<remove_cv_recursive_t<T>> fromRuby;
4677
+ VALUE first = rb_ary_entry(value, 0);
4678
+ return fromRuby.is_convertible(first);
4616
4679
  }
4617
4680
  default:
4618
4681
  return Convertible::None;