rice 4.6.0 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -0
  3. data/CMakeLists.txt +0 -4
  4. data/Rakefile +2 -8
  5. data/bin/rice-doc.rb +212 -0
  6. data/bin/rice-rbs.rb +93 -0
  7. data/include/rice/rice.hpp +5221 -4009
  8. data/include/rice/stl.hpp +822 -295
  9. data/lib/rice/doc/cpp_reference.rb +166 -0
  10. data/lib/rice/doc/doxygen.rb +294 -0
  11. data/lib/rice/doc/mkdocs.rb +298 -0
  12. data/lib/rice/doc/rice.rb +29 -0
  13. data/lib/rice/doc/ruby.rb +37 -0
  14. data/lib/rice/doc.rb +5 -0
  15. data/lib/{make_rice_headers.rb → rice/make_rice_headers.rb} +3 -0
  16. data/lib/rice/native.rb +18 -0
  17. data/lib/rice/native_registry.rb +21 -0
  18. data/lib/rice/parameter.rb +7 -0
  19. data/lib/rice/rbs.rb +104 -0
  20. data/lib/rice/version.rb +1 -1
  21. data/lib/rice.rb +4 -0
  22. data/lib/rubygems/cmake_builder.rb +24 -27
  23. data/rice/Arg.hpp +4 -4
  24. data/rice/Arg.ipp +4 -4
  25. data/rice/Buffer.hpp +77 -28
  26. data/rice/Buffer.ipp +500 -183
  27. data/rice/Data_Object.ipp +101 -82
  28. data/rice/Data_Type.hpp +7 -6
  29. data/rice/Data_Type.ipp +77 -47
  30. data/rice/Enum.ipp +15 -21
  31. data/rice/Function.hpp +17 -0
  32. data/rice/Function.ipp +13 -0
  33. data/rice/Pointer.hpp +15 -0
  34. data/rice/Pointer.ipp +49 -0
  35. data/rice/Return.hpp +1 -1
  36. data/rice/Return.ipp +2 -2
  37. data/rice/api.hpp +30 -0
  38. data/rice/cpp_api/Array.hpp +2 -2
  39. data/rice/cpp_api/Array.ipp +50 -5
  40. data/rice/cpp_api/Class.hpp +0 -5
  41. data/rice/cpp_api/Class.ipp +19 -0
  42. data/rice/cpp_api/Hash.ipp +20 -0
  43. data/rice/cpp_api/Module.hpp +6 -3
  44. data/rice/cpp_api/Module.ipp +49 -11
  45. data/rice/cpp_api/Object.ipp +31 -2
  46. data/rice/cpp_api/String.hpp +1 -2
  47. data/rice/cpp_api/String.ipp +21 -1
  48. data/rice/cpp_api/Struct.ipp +5 -0
  49. data/rice/cpp_api/Symbol.ipp +34 -0
  50. data/rice/cpp_api/shared_methods.hpp +12 -12
  51. data/rice/detail/MethodInfo.hpp +4 -2
  52. data/rice/detail/MethodInfo.ipp +19 -3
  53. data/rice/detail/ModuleRegistry.hpp +18 -0
  54. data/rice/detail/ModuleRegistry.ipp +25 -0
  55. data/rice/detail/Native.hpp +45 -2
  56. data/rice/detail/Native.ipp +196 -2
  57. data/rice/detail/NativeAttributeGet.hpp +9 -4
  58. data/rice/detail/NativeAttributeGet.ipp +73 -8
  59. data/rice/detail/NativeAttributeSet.hpp +4 -0
  60. data/rice/detail/NativeAttributeSet.ipp +33 -23
  61. data/rice/detail/NativeCallbackFFI.ipp +3 -2
  62. data/rice/detail/NativeCallbackSimple.ipp +1 -1
  63. data/rice/detail/NativeFunction.hpp +11 -49
  64. data/rice/detail/NativeFunction.ipp +83 -379
  65. data/rice/detail/NativeInvoker.hpp +74 -0
  66. data/rice/detail/NativeInvoker.ipp +197 -0
  67. data/rice/detail/NativeIterator.hpp +4 -0
  68. data/rice/detail/NativeIterator.ipp +19 -0
  69. data/rice/detail/NativeMethod.hpp +97 -0
  70. data/rice/detail/NativeMethod.ipp +332 -0
  71. data/rice/detail/NativeProc.hpp +51 -0
  72. data/rice/detail/NativeProc.ipp +133 -0
  73. data/rice/detail/NativeRegistry.hpp +8 -0
  74. data/rice/detail/NativeRegistry.ipp +27 -0
  75. data/rice/detail/Parameter.hpp +47 -0
  76. data/rice/detail/Parameter.ipp +105 -0
  77. data/rice/detail/Proc.ipp +14 -13
  78. data/rice/detail/Registries.hpp +1 -0
  79. data/rice/detail/RubyType.hpp +0 -2
  80. data/rice/detail/RubyType.ipp +15 -33
  81. data/rice/detail/Type.hpp +44 -8
  82. data/rice/detail/Type.ipp +150 -49
  83. data/rice/detail/TypeRegistry.hpp +3 -0
  84. data/rice/detail/TypeRegistry.ipp +17 -27
  85. data/rice/detail/Types.ipp +430 -0
  86. data/rice/detail/Wrapper.hpp +12 -0
  87. data/rice/detail/Wrapper.ipp +45 -2
  88. data/rice/detail/from_ruby.ipp +567 -1073
  89. data/rice/detail/ruby.hpp +1 -0
  90. data/rice/detail/to_ruby.ipp +4 -635
  91. data/rice/libc/file.ipp +3 -6
  92. data/rice/rice.hpp +22 -12
  93. data/rice/rice_api/Arg.hpp +7 -0
  94. data/rice/rice_api/Arg.ipp +9 -0
  95. data/rice/rice_api/ModuleRegistry.hpp +7 -0
  96. data/rice/rice_api/ModuleRegistry.ipp +10 -0
  97. data/rice/rice_api/Native.hpp +7 -0
  98. data/rice/rice_api/Native.ipp +52 -0
  99. data/rice/rice_api/NativeRegistry.hpp +7 -0
  100. data/rice/rice_api/NativeRegistry.ipp +21 -0
  101. data/rice/rice_api/Parameter.hpp +7 -0
  102. data/rice/rice_api/Parameter.ipp +11 -0
  103. data/rice/rice_api/Registries.hpp +6 -0
  104. data/rice/rice_api/Registries.ipp +12 -0
  105. data/rice/rice_api/TypeRegistry.hpp +7 -0
  106. data/rice/rice_api/TypeRegistry.ipp +10 -0
  107. data/rice/stl/complex.ipp +35 -0
  108. data/rice/stl/exception.ipp +20 -7
  109. data/rice/stl/filesystem.hpp +6 -0
  110. data/rice/stl/filesystem.ipp +34 -0
  111. data/rice/stl/map.ipp +13 -21
  112. data/rice/stl/monostate.ipp +37 -1
  113. data/rice/stl/multimap.ipp +17 -24
  114. data/rice/stl/optional.ipp +47 -2
  115. data/rice/stl/pair.ipp +23 -58
  116. data/rice/stl/reference_wrapper.ipp +22 -1
  117. data/rice/stl/set.ipp +17 -9
  118. data/rice/stl/shared_ptr.ipp +44 -17
  119. data/rice/stl/string.ipp +175 -7
  120. data/rice/stl/string_view.ipp +5 -0
  121. data/rice/stl/tuple.ipp +38 -9
  122. data/rice/stl/unique_ptr.ipp +46 -2
  123. data/rice/stl/unordered_map.ipp +13 -21
  124. data/rice/stl/variant.ipp +47 -11
  125. data/rice/stl/vector.ipp +182 -104
  126. data/rice/stl.hpp +1 -0
  127. data/rice/traits/attribute_traits.hpp +6 -6
  128. data/rice/traits/function_traits.hpp +2 -2
  129. data/rice/traits/method_traits.hpp +5 -16
  130. data/rice/traits/rice_traits.hpp +36 -4
  131. data/rice.gemspec +11 -22
  132. data/test/embed_ruby.cpp +0 -3
  133. data/test/test_Array.cpp +38 -38
  134. data/test/test_Attribute.cpp +244 -10
  135. data/test/test_Buffer.cpp +344 -13
  136. data/test/test_Callback.cpp +2 -3
  137. data/test/test_Class.cpp +5 -5
  138. data/test/test_Data_Object.cpp +0 -55
  139. data/test/test_Data_Type.cpp +19 -30
  140. data/test/test_Enum.cpp +4 -46
  141. data/test/test_From_Ruby.cpp +89 -82
  142. data/test/test_GVL.cpp +109 -0
  143. data/test/test_Iterator.cpp +1 -1
  144. data/test/test_Keep_Alive_No_Wrapper.cpp +5 -3
  145. data/test/test_Module.cpp +8 -9
  146. data/test/test_Object.cpp +1 -1
  147. data/test/test_Overloads.cpp +3 -3
  148. data/test/test_Stl_Map.cpp +8 -8
  149. data/test/test_Stl_Multimap.cpp +4 -4
  150. data/test/test_Stl_Pair.cpp +5 -3
  151. data/test/test_Stl_SharedPtr.cpp +24 -12
  152. data/test/test_Stl_Tuple.cpp +1 -1
  153. data/test/test_Stl_UniquePtr.cpp +8 -0
  154. data/test/test_Stl_Unordered_Map.cpp +9 -9
  155. data/test/test_Stl_Variant.cpp +9 -3
  156. data/test/test_Stl_Vector.cpp +118 -13
  157. data/test/test_To_Ruby.cpp +35 -28
  158. data/test/test_Type.cpp +256 -53
  159. data/test/unittest.hpp +35 -0
  160. metadata +66 -34
  161. data/rice/Init.hpp +0 -8
  162. data/rice/Init.ipp +0 -8
  163. data/rice/detail/RubyFunction.hpp +0 -31
  164. data/rice/detail/RubyFunction.ipp +0 -76
  165. data/sample/callbacks/extconf.rb +0 -5
  166. data/sample/callbacks/sample_callbacks.cpp +0 -35
  167. data/sample/callbacks/test.rb +0 -28
  168. data/sample/enum/extconf.rb +0 -5
  169. data/sample/enum/sample_enum.cpp +0 -40
  170. data/sample/enum/test.rb +0 -8
  171. data/sample/inheritance/animals.cpp +0 -82
  172. data/sample/inheritance/extconf.rb +0 -5
  173. data/sample/inheritance/test.rb +0 -7
  174. data/sample/map/extconf.rb +0 -5
  175. data/sample/map/map.cpp +0 -73
  176. data/sample/map/test.rb +0 -7
  177. data/test/ext/t1/Foo.hpp +0 -10
  178. data/test/ext/t1/extconf.rb +0 -4
  179. data/test/ext/t1/t1.cpp +0 -13
  180. data/test/ext/t2/extconf.rb +0 -4
  181. data/test/ext/t2/t2.cpp +0 -11
  182. data/test/ruby/test_callbacks_sample.rb +0 -28
  183. data/test/ruby/test_multiple_extensions.rb +0 -18
  184. data/test/ruby/test_multiple_extensions_same_class.rb +0 -14
  185. data/test/ruby/test_multiple_extensions_with_inheritance.rb +0 -20
  186. /data/test/{test_Stl_Type.cpp → test_Stl_Type_Info.cpp} +0 -0
data/rice/Buffer.ipp CHANGED
@@ -2,35 +2,52 @@ namespace Rice
2
2
  {
3
3
  // ---- Buffer<T> -------
4
4
  template<typename T>
5
- inline Buffer<T>::Buffer(T* pointer) : m_buffer(pointer)
5
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::Buffer(T* pointer) : m_buffer(pointer)
6
6
  {
7
7
  }
8
8
 
9
9
  template<typename T>
10
- inline Buffer<T>::Buffer(T* pointer, size_t size) : m_size(size), m_buffer(pointer)
10
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::Buffer(T* pointer, size_t size) : m_size(size), m_buffer(pointer)
11
11
  {
12
12
  }
13
13
 
14
14
  template <typename T>
15
- inline Buffer<T>::Buffer(VALUE value)
15
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::Buffer(VALUE value) : Buffer(value, 0)
16
+ {
17
+ }
18
+
19
+ template <typename T>
20
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::Buffer(VALUE value, size_t size)
16
21
  {
17
22
  if constexpr (std::is_fundamental_v<T>)
18
23
  {
19
- this->fromRubyType(value);
24
+ this->fromBuiltinType(value, size);
20
25
  }
21
26
  else
22
27
  {
23
- this->fromDataType(value);
28
+ this->fromWrappedType(value, size);
29
+ }
30
+ }
31
+
32
+ template <typename T>
33
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::~Buffer()
34
+ {
35
+ if constexpr (std::is_destructible_v<T>)
36
+ {
37
+ if (this->m_owner)
38
+ {
39
+ delete[] this->m_buffer;
40
+ }
24
41
  }
25
42
  }
26
43
 
27
44
  template <typename T>
28
- inline void Buffer<T>::fromRubyType(VALUE value)
45
+ inline void Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::fromBuiltinType(VALUE value, size_t size)
29
46
  {
30
47
  using Intrinsic_T = typename detail::intrinsic_type<T>;
31
48
  using RubyType_T = typename detail::RubyType<Intrinsic_T>;
32
- ruby_value_type valueType = rb_type(value);
33
49
 
50
+ ruby_value_type valueType = rb_type(value);
34
51
  switch (valueType)
35
52
  {
36
53
  case RUBY_T_ARRAY:
@@ -39,9 +56,19 @@ namespace Rice
39
56
  this->m_size = array.size();
40
57
  this->m_buffer = new T[this->m_size]();
41
58
 
42
- String packed = array.pack<Intrinsic_T>();
43
- memcpy(this->m_buffer, RSTRING_PTR(packed.value()), RSTRING_LEN(packed.value()));
44
-
59
+ if constexpr (std::is_fundamental_v<T>)
60
+ {
61
+ String packed = array.pack<Intrinsic_T>();
62
+ memcpy((void*)this->m_buffer, RSTRING_PTR(packed.value()), RSTRING_LEN(packed.value()));
63
+ }
64
+ else
65
+ {
66
+ detail::From_Ruby<Intrinsic_T> fromRuby;
67
+ for (int i = 0; i < array.size(); i++)
68
+ {
69
+ this->m_buffer[0] = fromRuby.convert(array[i]);
70
+ }
71
+ }
45
72
  this->m_owner = true;
46
73
  break;
47
74
  }
@@ -57,21 +84,21 @@ namespace Rice
57
84
  {
58
85
  this->m_buffer = new T[this->m_size]();
59
86
  }
60
- memcpy(this->m_buffer, RSTRING_PTR(value), this->m_size);
87
+ memcpy((void*)this->m_buffer, RSTRING_PTR(value), this->m_size);
61
88
 
62
89
  this->m_owner = true;
63
90
  break;
64
91
  }
65
92
  case RUBY_T_DATA:
66
93
  {
67
- if (Data_Type<T>::is_descendant(value))
94
+ if (Data_Type<Pointer<T>>::is_descendant(value))
68
95
  {
69
- this->m_size = 1;
70
- this->m_buffer = new T[this->m_size]();
71
- this->m_buffer[0] = *detail::unwrap<T>(value, Data_Type<T>::ruby_data_type(), false);
96
+ this->m_buffer = detail::unwrap<T>(value, Data_Type<Pointer<T>>::ruby_data_type(), false);
72
97
  this->m_owner = false;
98
+ this->m_size = size;
73
99
  break;
74
100
  }
101
+ [[fallthrough]];
75
102
  }
76
103
  default:
77
104
  {
@@ -82,13 +109,14 @@ namespace Rice
82
109
  T data = detail::protect(RubyType_T::fromRuby, value);
83
110
  this->m_size = 1;
84
111
  this->m_buffer = new T[this->m_size]();
85
- memcpy(this->m_buffer, &data, sizeof(T));
112
+ memcpy((void*)this->m_buffer, &data, sizeof(T));
86
113
  this->m_owner = true;
87
114
  break;
88
115
  }
89
116
  else
90
117
  {
91
- std::string typeName = detail::typeName(typeid(T));
118
+ detail::TypeMapper<T> typeMapper;
119
+ std::string typeName = typeMapper.name();
92
120
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s*)",
93
121
  detail::protect(rb_obj_classname, value), typeName.c_str());
94
122
  }
@@ -97,7 +125,7 @@ namespace Rice
97
125
  }
98
126
 
99
127
  template <typename T>
100
- inline void Buffer<T>::fromDataType(VALUE value)
128
+ inline void Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::fromWrappedType(VALUE value, size_t size)
101
129
  {
102
130
  using Intrinsic_T = typename detail::intrinsic_type<T>;
103
131
 
@@ -108,20 +136,68 @@ namespace Rice
108
136
  Array array(value);
109
137
  this->m_size = array.size();
110
138
 
111
- // Use operator new[] to allocate memory but not call constructors
112
- this->m_buffer = static_cast<T*>(operator new[](sizeof(T)* this->m_size));
139
+ // Use operator new[] to allocate memory but not call constructors.
140
+ size_t size = sizeof(T) * this->m_size;
141
+ this->m_buffer = static_cast<T*>(operator new[](size));
113
142
 
114
143
  detail::From_Ruby<Intrinsic_T> fromRuby;
115
144
 
116
145
  for (size_t i = 0; i < this->m_size; i++)
117
146
  {
118
- this->m_buffer[i] = fromRuby.convert(array[i].value());
147
+ // Construct objects in allocated memory using move or copy construction
148
+ if constexpr (std::is_move_constructible_v<T>)
149
+ {
150
+ new (&this->m_buffer[i]) T(std::move(fromRuby.convert(array[i].value())));
151
+ }
152
+ else if constexpr (std::is_copy_constructible_v<T>)
153
+ {
154
+ new (&this->m_buffer[i]) T(fromRuby.convert(array[i].value()));
155
+ }
156
+ else
157
+ {
158
+ throw Exception(rb_eTypeError, "Cannot construct object of type %s - type is not move or copy constructible",
159
+ detail::TypeMapper<Intrinsic_T>().name().c_str());
160
+ }
119
161
  }
120
162
  break;
121
163
  }
164
+ case RUBY_T_DATA:
165
+ {
166
+ if (Data_Type<Pointer<Intrinsic_T>>::is_descendant(value))
167
+ {
168
+ this->m_buffer = detail::unwrap<T>(value, Data_Type<Pointer<Intrinsic_T>>::ruby_data_type(), false);
169
+ this->m_owner = false;
170
+ this->m_size = size;
171
+ break;
172
+ }
173
+ else if (Data_Type<Intrinsic_T>::is_descendant(value))
174
+ {
175
+ this->m_buffer = detail::unwrap<T>(value, Data_Type<Intrinsic_T>::ruby_data_type(), false);
176
+ this->m_owner = false;
177
+ this->m_size = size;
178
+ break;
179
+ }
180
+ }
181
+ case RUBY_T_STRING:
182
+ {
183
+ // This special case is a bit ugly...
184
+ if constexpr (std::is_same_v<detail::intrinsic_type<T>, std::string>)
185
+ {
186
+ // FromRuby owns the converted string so we need to keep it alive until we get to the copy constructor
187
+ // two lines down
188
+ detail::From_Ruby<T*> fromRuby;
189
+ T* converted = fromRuby.convert(value);
190
+ this->m_buffer = new T[1]{ *converted };
191
+ this->m_owner = true;
192
+ this->m_size = 1;
193
+ break;
194
+ }
195
+ [[fallthrough]];
196
+ }
122
197
  default:
123
198
  {
124
- std::string typeName = detail::typeName(typeid(T));
199
+ detail::TypeMapper<T> typeMapper;
200
+ std::string typeName = typeMapper.name();
125
201
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s*)",
126
202
  detail::protect(rb_obj_classname, value), typeName.c_str());
127
203
  }
@@ -129,19 +205,7 @@ namespace Rice
129
205
  }
130
206
 
131
207
  template <typename T>
132
- inline Buffer<T>::~Buffer()
133
- {
134
- if constexpr (std::is_destructible_v<T>)
135
- {
136
- if (this->m_owner)
137
- {
138
- delete[] this->m_buffer;
139
- }
140
- }
141
- }
142
-
143
- template <typename T>
144
- inline Buffer<T>::Buffer(Buffer<T>&& other) : m_owner(other.m_owner), m_size(other.m_size), m_buffer(other.m_buffer)
208
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::Buffer(Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>&& other) : m_owner(other.m_owner), m_size(other.m_size), m_buffer(other.m_buffer)
145
209
  {
146
210
  other.m_buffer = nullptr;
147
211
  other.m_size = 0;
@@ -149,7 +213,7 @@ namespace Rice
149
213
  }
150
214
 
151
215
  template <typename T>
152
- inline Buffer<T>& Buffer<T>::operator=(Buffer<T>&& other)
216
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>& Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::operator=(Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>&& other)
153
217
  {
154
218
  this->m_buffer = other.m_buffer;
155
219
  other.m_buffer = nullptr;
@@ -164,57 +228,54 @@ namespace Rice
164
228
  }
165
229
 
166
230
  template <typename T>
167
- inline size_t Buffer<T>::size() const
231
+ inline size_t Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::size() const
168
232
  {
169
233
  return this->m_size;
170
234
  }
171
235
 
172
236
  template <typename T>
173
- void Buffer<T>::setSize(size_t value)
237
+ inline T* Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::ptr()
174
238
  {
175
- this->m_size = value;
239
+ return this->m_buffer;
176
240
  }
177
241
 
178
242
  template <typename T>
179
- inline T* Buffer<T>::ptr()
243
+ inline T& Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::reference()
180
244
  {
181
- return this->m_buffer;
245
+ return *this->m_buffer;
182
246
  }
183
247
 
184
248
  template <typename T>
185
- inline T& Buffer<T>::reference()
249
+ inline T* Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::release()
186
250
  {
187
- return *this->m_buffer;
251
+ this->m_owner = false;
252
+ return this->m_buffer;
188
253
  }
189
254
 
190
255
  template <typename T>
191
- inline bool Buffer<T>::isOwner() const
256
+ inline bool Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::isOwner() const
192
257
  {
193
258
  return this->m_owner;
194
259
  }
195
260
 
196
261
  template <typename T>
197
- inline void Buffer<T>::setOwner(bool value)
262
+ inline void Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::setOwner(bool value)
198
263
  {
199
264
  this->m_owner = value;
200
265
  }
201
266
 
202
- template <typename T>
203
- inline void Buffer<T>::release()
267
+ template<typename T>
268
+ inline VALUE Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::toString() const
204
269
  {
205
- this->m_owner = false;
206
- }
270
+ detail::TypeMapper<T*> typeMapper;
271
+ std::string description = "Buffer<type: " + typeMapper.simplifiedName() + ", size: " + std::to_string(this->m_size) + ">";
207
272
 
208
- /* template<typename T>
209
- inline VALUE Buffer<T>::toString() const
210
- {
211
- std::string name = detail::typeName(typeid(T));
212
- std::string result = "Buffer<type: " + detail::cppClassName(name) + ", size: " + std::to_string(this->m_size) + ">";
213
- return detail::To_Ruby<std::string>().convert(result);
214
- }*/
273
+ // We can't use To_Ruby because To_Ruby depends on Buffer - ie a circular reference
274
+ return detail::protect(rb_utf8_str_new_cstr, description.c_str());
275
+ }
215
276
 
216
277
  template<typename T>
217
- inline VALUE Buffer<T>::bytes(size_t count) const
278
+ inline VALUE Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::bytes(size_t count) const
218
279
  {
219
280
  if (!this->m_buffer)
220
281
  {
@@ -228,13 +289,13 @@ namespace Rice
228
289
  }
229
290
 
230
291
  template<typename T>
231
- inline VALUE Buffer<T>::bytes() const
292
+ inline VALUE Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::bytes() const
232
293
  {
233
294
  return this->bytes(this->m_size);
234
295
  }
235
296
 
236
297
  template<typename T>
237
- inline Array Buffer<T>::toArray(size_t count) const
298
+ inline Array Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::toArray(size_t count) const
238
299
  {
239
300
  if (!this->m_buffer)
240
301
  {
@@ -254,20 +315,20 @@ namespace Rice
254
315
 
255
316
  for (; ptr < end; ptr++)
256
317
  {
257
- result.push(*ptr);
318
+ result.push(*ptr, false);
258
319
  }
259
320
  return result;
260
321
  }
261
322
  }
262
323
 
263
324
  template<typename T>
264
- inline Array Buffer<T>::toArray() const
325
+ inline Array Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::toArray() const
265
326
  {
266
327
  return this->toArray(this->m_size);
267
328
  }
268
329
 
269
330
  template<typename T>
270
- inline T Buffer<T>::get(size_t index) const
331
+ inline T& Buffer<T, std::enable_if_t<!std::is_pointer_v<T> && !std::is_void_v<T>>>::operator[](size_t index)
271
332
  {
272
333
  if (index >= this->m_size)
273
334
  {
@@ -277,62 +338,79 @@ namespace Rice
277
338
  return this->m_buffer[index];
278
339
  }
279
340
 
341
+ // ---- Buffer<T*> - Builtin -------
280
342
  template<typename T>
281
- inline void Buffer<T>::set(size_t index, T element)
343
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Buffer(T** pointer) : m_buffer(pointer)
282
344
  {
283
- if (index >= this->m_size)
284
- {
285
- throw Exception(rb_eIndexError, "index %ld outside of bounds: 0..%ld", index, this->m_size);
286
- }
287
-
288
- this->m_buffer[index] = element;
289
345
  }
290
346
 
291
- // ---- Buffer<T*> -------
292
347
  template<typename T>
293
- inline Buffer<T*>::Buffer(T** pointer) : m_outer(pointer)
348
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Buffer(T** pointer, size_t size) : m_buffer(pointer), m_size(size)
294
349
  {
295
350
  }
296
351
 
297
- template<typename T>
298
- inline Buffer<T*>::Buffer(T** pointer, size_t size) : m_outer(pointer), m_size(size)
352
+ template <typename T>
353
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Buffer(VALUE value) : Buffer(value, 0)
299
354
  {
300
355
  }
301
-
356
+
302
357
  template <typename T>
303
- inline Buffer<T*>::Buffer(VALUE value)
358
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Buffer(VALUE value, size_t size)
304
359
  {
305
- ruby_value_type valueType = rb_type(value);
360
+ using Intrinsic_T = typename detail::intrinsic_type<T>;
306
361
 
362
+ ruby_value_type valueType = rb_type(value);
307
363
  switch (valueType)
308
364
  {
309
365
  case RUBY_T_ARRAY:
310
366
  {
311
367
  Array outer(value);
368
+
369
+ // Allocate outer buffer
312
370
  this->m_size = outer.size();
313
- this->m_outer = new T * [this->m_size]();
371
+ this->m_buffer = new T*[this->m_size]();
314
372
 
315
373
  for (size_t i = 0; i < this->m_size; i++)
316
374
  {
317
375
  // Check the inner value is also an array
318
376
  Array inner(outer[i].value());
319
377
 
320
- // Wrap it with a buffer and add it our list of inner buffers
321
- Buffer<T> buffer(inner.value());
322
-
323
- // And update the outer array
324
- this->m_outer[i] = buffer.ptr();
378
+ // Allocate inner buffer
379
+ this->m_buffer[i] = new T[inner.size()]();
325
380
 
326
- // Now move the buffer into the affer, not the buffer pointer is still valid (it just got moved)
327
- this->m_inner.push_back(std::move(buffer));
381
+ if constexpr (std::is_fundamental_v<Intrinsic_T>)
382
+ {
383
+ String packed = inner.pack<Intrinsic_T>();
384
+ memcpy((void*)this->m_buffer[i], RSTRING_PTR(packed.value()), RSTRING_LEN(packed.value()));
385
+ }
386
+ else
387
+ {
388
+ detail::From_Ruby<Intrinsic_T*> fromRuby;
389
+ for (int i = 0; i < inner.size(); i++)
390
+ {
391
+ this->m_buffer[0] = fromRuby.convert(inner[i].value());
392
+ }
393
+ }
328
394
  }
329
395
 
330
396
  this->m_owner = true;
331
397
  break;
332
398
  }
399
+ case RUBY_T_DATA:
400
+ {
401
+ if (Data_Type<Pointer<T*>>::is_descendant(value))
402
+ {
403
+ this->m_buffer = detail::unwrap<T*>(value, Data_Type<Pointer<T*>>::ruby_data_type(), false);
404
+ this->m_owner = false;
405
+ this->m_size = size;
406
+ break;
407
+ }
408
+ [[fallthrough]];
409
+ }
333
410
  default:
334
411
  {
335
- std::string typeName = detail::typeName(typeid(T));
412
+ detail::TypeMapper<T> typeMapper;
413
+ std::string typeName = typeMapper.name();
336
414
  throw Exception(rb_eTypeError, "wrong argument type %s (expected % s*)",
337
415
  detail::protect(rb_obj_classname, value), typeName.c_str());
338
416
  }
@@ -340,32 +418,33 @@ namespace Rice
340
418
  }
341
419
 
342
420
  template <typename T>
343
- inline Buffer<T*>::~Buffer()
421
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::~Buffer()
344
422
  {
345
423
  if (this->m_owner)
346
424
  {
347
- delete[] this->m_outer;
425
+ for (size_t i = 0; i < this->m_size; i++)
426
+ {
427
+ delete this->m_buffer[i];
428
+ }
429
+
430
+ delete[] this->m_buffer;
348
431
  }
349
432
  }
350
433
 
351
434
  template <typename T>
352
- inline Buffer<T*>::Buffer(Buffer<T*>&& other) : m_owner(other.m_owner), m_size(other.m_size),
353
- m_outer(other.m_outer), m_inner(std::move(other.m_inner))
435
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Buffer(Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>&& other) : m_owner(other.m_owner), m_size(other.m_size),
436
+ m_buffer(other.m_buffer)
354
437
  {
355
- other.m_outer = nullptr;
356
- other.m_inner.clear();
438
+ other.m_buffer = nullptr;
357
439
  other.m_size = 0;
358
440
  other.m_owner = false;
359
441
  }
360
442
 
361
443
  template <typename T>
362
- inline Buffer<T*>& Buffer<T*>::operator=(Buffer<T*>&& other)
444
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>& Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::operator=(Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>&& other)
363
445
  {
364
- this->m_outer = other.m_outer;
365
- other.m_outer = nullptr;
366
-
367
- this->m_inner = std::move(other.m_inner);
368
- other.m_inner.clear();
446
+ this->m_buffer = other.m_buffer;
447
+ other.m_buffer = nullptr;
369
448
 
370
449
  this->m_size = other.m_size;
371
450
  other.m_size = 0;
@@ -377,80 +456,269 @@ namespace Rice
377
456
  }
378
457
 
379
458
  template <typename T>
380
- inline const Buffer<T>& Buffer<T*>::operator[](size_t index)
459
+ inline T* Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::operator[](size_t index)
381
460
  {
382
- return this->m_inner[index];
461
+ return this->m_buffer[index];
383
462
  }
384
463
 
385
464
  template <typename T>
386
- inline size_t Buffer<T*>::size() const
465
+ inline size_t Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::size() const
387
466
  {
388
467
  return this->m_size;
389
468
  }
390
469
 
391
470
  template <typename T>
392
- void Buffer<T*>::setSize(size_t value)
471
+ inline T** Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::ptr()
393
472
  {
394
- this->m_size = value;
473
+ return this->m_buffer;
395
474
  }
396
475
 
397
476
  template <typename T>
398
- inline T** Buffer<T*>::ptr()
477
+ inline T** Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::release()
399
478
  {
400
- return this->m_outer;
479
+ this->m_owner = false;
480
+ return this->m_buffer;
401
481
  }
402
482
 
403
483
  template <typename T>
404
- inline bool Buffer<T*>::isOwner() const
484
+ inline bool Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::isOwner() const
405
485
  {
406
486
  return this->m_owner;
407
487
  }
408
488
 
409
489
  template <typename T>
410
- inline void Buffer<T*>::setOwner(bool value)
490
+ inline void Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::setOwner(bool value)
411
491
  {
412
492
  this->m_owner = value;
413
493
  }
414
494
 
495
+ template<typename T>
496
+ inline VALUE Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::toString() const
497
+ {
498
+ detail::TypeMapper<T*> typeMapper;
499
+ std::string description = "Buffer<type: " + typeMapper.simplifiedName() + ", size: " + std::to_string(this->m_size) + ">";
500
+
501
+ // We can't use To_Ruby because To_Ruby depends on Buffer - ie a circular reference
502
+ return detail::protect(rb_utf8_str_new_cstr, description.c_str());
503
+ }
504
+
505
+ template<typename T>
506
+ inline VALUE Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::bytes(size_t count) const
507
+ {
508
+ if (!this->m_buffer)
509
+ {
510
+ return Qnil;
511
+ }
512
+ else
513
+ {
514
+ T** begin = this->m_buffer;
515
+ long length = (long)(count * sizeof(T*));
516
+ return detail::protect(rb_str_new_static, (const char*)*begin, length);
517
+ }
518
+ }
519
+
520
+ template<typename T>
521
+ inline VALUE Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::bytes() const
522
+ {
523
+ return this->bytes(this->m_size);
524
+ }
525
+
526
+ template<typename T>
527
+ inline Array Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::toArray(size_t count) const
528
+ {
529
+ if (!this->m_buffer)
530
+ {
531
+ return Qnil;
532
+ }
533
+ else
534
+ {
535
+ Array result;
536
+
537
+ T** ptr = this->m_buffer;
538
+ T** end = this->m_buffer + count;
539
+
540
+ for (; ptr < end; ptr++)
541
+ {
542
+ Buffer<T> buffer(*ptr);
543
+ result.push(std::move(buffer), true);
544
+ }
545
+ return result;
546
+ }
547
+ }
548
+
549
+ template<typename T>
550
+ inline Array Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::toArray() const
551
+ {
552
+ return this->toArray(this->m_size);
553
+ }
554
+
555
+ // ---- Buffer<T*> - Wrapped -------
556
+ template<typename T>
557
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Buffer(T** pointer) : m_buffer(pointer)
558
+ {
559
+ }
560
+
561
+ template<typename T>
562
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Buffer(T** pointer, size_t size) : m_buffer(pointer), m_size(size)
563
+ {
564
+ }
565
+
415
566
  template <typename T>
416
- inline void Buffer<T*>::release()
567
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Buffer(VALUE value) : Buffer(value, 0)
568
+ {
569
+ }
570
+
571
+ template <typename T>
572
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Buffer(VALUE value, size_t size)
573
+ {
574
+ ruby_value_type valueType = rb_type(value);
575
+ switch (valueType)
576
+ {
577
+ case RUBY_T_ARRAY:
578
+ {
579
+ Array array(value);
580
+ this->m_size = array.size();
581
+ this->m_buffer = new T * [this->m_size]();
582
+
583
+ detail::From_Ruby<T*> fromRuby;
584
+
585
+ for (size_t i = 0; i < this->m_size; i++)
586
+ {
587
+ this->m_buffer[i] = fromRuby.convert(array[i].value());
588
+ }
589
+
590
+ this->m_owner = true;
591
+ break;
592
+ }
593
+ case RUBY_T_DATA:
594
+ {
595
+ if (Data_Type<Pointer<T*>>::is_descendant(value))
596
+ {
597
+ this->m_buffer = detail::unwrap<T*>(value, Data_Type<Pointer<T*>>::ruby_data_type(), false);
598
+ this->m_owner = false;
599
+ this->m_size = size;
600
+ break;
601
+ }
602
+ }
603
+ default:
604
+ {
605
+ detail::TypeMapper<T> typeMapper;
606
+ std::string typeName = typeMapper.name();
607
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s*)",
608
+ detail::protect(rb_obj_classname, value), typeName.c_str());
609
+ }
610
+ }
611
+ }
612
+
613
+ template <typename T>
614
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::~Buffer()
615
+ {
616
+ if (this->m_owner)
617
+ {
618
+ delete[] this->m_buffer;
619
+ }
620
+ }
621
+
622
+ template <typename T>
623
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Buffer(Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>&& other) : m_owner(other.m_owner), m_size(other.m_size),
624
+ m_buffer(other.m_buffer)
625
+ {
626
+ other.m_buffer = nullptr;
627
+ other.m_size = 0;
628
+ other.m_owner = false;
629
+ }
630
+
631
+ template <typename T>
632
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>& Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::operator=(Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>&& other)
633
+ {
634
+ this->m_buffer = other.m_buffer;
635
+ other.m_buffer = nullptr;
636
+
637
+ this->m_size = other.m_size;
638
+ other.m_size = 0;
639
+
640
+ this->m_owner = other.m_owner;
641
+ other.m_owner = false;
642
+
643
+ return *this;
644
+ }
645
+
646
+ template <typename T>
647
+ inline T* Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::operator[](size_t index)
648
+ {
649
+ if (index >= this->m_size)
650
+ {
651
+ throw Exception(rb_eIndexError, "index %ld outside of bounds: 0..%ld", index, this->m_size);
652
+ }
653
+ return this->m_buffer[index];
654
+ }
655
+
656
+ template <typename T>
657
+ inline size_t Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::size() const
658
+ {
659
+ return this->m_size;
660
+ }
661
+
662
+ template <typename T>
663
+ inline T** Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::ptr()
664
+ {
665
+ return this->m_buffer;
666
+ }
667
+
668
+ template <typename T>
669
+ inline T** Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::release()
417
670
  {
418
671
  this->m_owner = false;
672
+ return this->m_buffer;
673
+ }
674
+
675
+ template <typename T>
676
+ inline bool Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::isOwner() const
677
+ {
678
+ return this->m_owner;
679
+ }
680
+
681
+ template <typename T>
682
+ inline void Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::setOwner(bool value)
683
+ {
684
+ this->m_owner = value;
419
685
  }
420
686
 
421
- /*template<typename T>
422
- inline VALUE Buffer<T*>::toString() const
687
+ template<typename T>
688
+ inline VALUE Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::toString() const
423
689
  {
424
- std::string name = detail::typeName(typeid(T*));
425
- std::string result = "Buffer<type: " + detail::cppClassName(name) + ", size: " + std::to_string(this->m_size) + ">";
426
- return detail::To_Ruby<std::string>().convert(result);
427
- }*/
690
+ detail::TypeMapper<T*> typeMapper;
691
+ std::string description = "Buffer<type: " + typeMapper.simplifiedName() + ", size: " + std::to_string(this->m_size) + ">";
692
+
693
+ // We can't use To_Ruby because To_Ruby depends on Buffer - ie a circular reference
694
+ return detail::protect(rb_utf8_str_new_cstr, description.c_str());
695
+ }
428
696
 
429
697
  template<typename T>
430
- inline VALUE Buffer<T*>::bytes(size_t count) const
698
+ inline VALUE Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::bytes(size_t count) const
431
699
  {
432
- if (!this->m_outer)
700
+ if (!this->m_buffer)
433
701
  {
434
702
  return Qnil;
435
703
  }
436
704
  else
437
705
  {
438
- T** begin = this->m_outer;
706
+ T** begin = this->m_buffer;
439
707
  long length = (long)(count * sizeof(T*));
440
708
  return detail::protect(rb_str_new_static, (const char*)*begin, length);
441
709
  }
442
710
  }
443
711
 
444
712
  template<typename T>
445
- inline VALUE Buffer<T*>::bytes() const
713
+ inline VALUE Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::bytes() const
446
714
  {
447
715
  return this->bytes(this->m_size);
448
716
  }
449
717
 
450
718
  template<typename T>
451
- inline Array Buffer<T*>::toArray(size_t count) const
719
+ inline Array Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::toArray(size_t count) const
452
720
  {
453
- if (!this->m_outer)
721
+ if (!this->m_buffer)
454
722
  {
455
723
  return Qnil;
456
724
  }
@@ -458,35 +726,70 @@ namespace Rice
458
726
  {
459
727
  Array result;
460
728
 
461
- T** ptr = this->m_outer;
462
- T** end = this->m_outer + count;
729
+ T** ptr = this->m_buffer;
730
+ T** end = this->m_buffer + count;
463
731
 
464
732
  for (; ptr < end; ptr++)
465
733
  {
466
- Buffer<T> buffer(*ptr);
467
- result.push(std::move(buffer));
734
+ result.push(*ptr, false);
468
735
  }
469
736
  return result;
470
737
  }
471
738
  }
472
739
 
473
740
  template<typename T>
474
- inline Array Buffer<T*>::toArray() const
741
+ inline Array Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::toArray() const
475
742
  {
476
743
  return this->toArray(this->m_size);
477
744
  }
478
745
 
479
746
  // ---- Buffer<void> -------
480
- inline Buffer<void>::Buffer(void* pointer) : m_buffer(pointer)
747
+ template<typename T>
748
+ inline Buffer<T, std::enable_if_t<std::is_void_v<T>>>::Buffer(VALUE value) : Buffer(value, 0)
749
+ {
750
+ }
751
+
752
+ template<typename T>
753
+ inline Buffer<T, std::enable_if_t<std::is_void_v<T>>>::Buffer(VALUE value, size_t size)
754
+ {
755
+ ruby_value_type valueType = rb_type(value);
756
+
757
+ switch (valueType)
758
+ {
759
+ case RUBY_T_STRING:
760
+ {
761
+ this->m_size = RSTRING_LEN(value);
762
+ this->m_buffer = ::operator new(this->m_size);
763
+ memcpy((void*)this->m_buffer, RSTRING_PTR(value), this->m_size);
764
+
765
+ this->m_owner = true;
766
+ break;
767
+ }
768
+ default:
769
+ {
770
+ detail::TypeMapper<void> typeMapper;
771
+ std::string typeName = typeMapper.name();
772
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s*)",
773
+ detail::protect(rb_obj_classname, value), typeName.c_str());
774
+ }
775
+ }
776
+ }
777
+
778
+ template<typename T>
779
+ inline Buffer<T, std::enable_if_t<std::is_void_v<T>>>::Buffer(T* pointer) : m_buffer(pointer)
481
780
  {
482
781
  }
483
782
 
484
- inline Buffer<void>::Buffer(Buffer<void>&& other) : m_buffer(other.m_buffer)
783
+ template<typename T>
784
+ inline Buffer<T, std::enable_if_t<std::is_void_v<T>>>::Buffer(Buffer<T, std::enable_if_t<std::is_void_v<T>>>&& other) : m_owner(other.m_owner), m_size(other.m_size), m_buffer(other.m_buffer)
485
785
  {
486
786
  other.m_buffer = nullptr;
787
+ other.m_size = 0;
788
+ other.m_owner = false;
487
789
  }
488
790
 
489
- inline Buffer<void>& Buffer<void>::operator=(Buffer<void>&& other)
791
+ template<typename T>
792
+ inline Buffer<T, std::enable_if_t<std::is_void_v<T>>>& Buffer<T, std::enable_if_t<std::is_void_v<T>>>::operator=(Buffer<T, std::enable_if_t<std::is_void_v<T>>>&& other)
490
793
  {
491
794
  this->m_buffer = other.m_buffer;
492
795
  other.m_buffer = nullptr;
@@ -494,89 +797,108 @@ namespace Rice
494
797
  return *this;
495
798
  }
496
799
 
497
- inline void* Buffer<void>::ptr()
800
+ template<typename T>
801
+ inline size_t Buffer<T, std::enable_if_t<std::is_void_v<T>>>::size() const
802
+ {
803
+ return this->m_size;
804
+ }
805
+
806
+ template<typename T>
807
+ inline T* Buffer<T, std::enable_if_t<std::is_void_v<T>>>::ptr()
498
808
  {
499
809
  return this->m_buffer;
500
810
  }
501
811
 
812
+ template <typename T>
813
+ inline T* Buffer<T, std::enable_if_t<std::is_void_v<T>>>::release()
814
+ {
815
+ this->m_owner = false;
816
+ return this->m_buffer;
817
+ }
818
+
819
+ template<typename T>
820
+ inline VALUE Buffer<T, std::enable_if_t<std::is_void_v<T>>>::bytes(size_t count) const
821
+ {
822
+ if (!this->m_buffer)
823
+ {
824
+ return Qnil;
825
+ }
826
+ else
827
+ {
828
+ return detail::protect(rb_usascii_str_new, (const char*)this->m_buffer, (long)count);
829
+ }
830
+ }
831
+
832
+ template<typename T>
833
+ inline VALUE Buffer<T, std::enable_if_t<std::is_void_v<T>>>::bytes() const
834
+ {
835
+ return this->bytes(this->m_size);
836
+ }
837
+
502
838
  // ------ define_buffer ----------
503
839
  template<typename T>
504
840
  inline Data_Type<Buffer<T>> define_buffer(std::string klassName)
505
841
  {
506
842
  using Buffer_T = Buffer<T>;
843
+ using Data_Type_T = Data_Type<Buffer_T>;
507
844
 
508
845
  if (klassName.empty())
509
846
  {
510
- std::string typeName = detail::typeName(typeid(Buffer_T));
511
- klassName = detail::rubyClassName(typeName);
847
+ detail::TypeMapper<Buffer_T> typeMapper;
848
+ klassName = typeMapper.rubyName();
512
849
  }
513
850
 
514
851
  Module rb_mRice = define_module("Rice");
515
852
 
853
+ if (Data_Type_T::check_defined(klassName, rb_mRice))
854
+ {
855
+ return Data_Type_T();
856
+ }
857
+
516
858
  if constexpr (std::is_void_v<T>)
517
859
  {
518
- return define_class_under<Buffer_T>(rb_mRice, klassName);
860
+ return define_class_under<Buffer_T>(rb_mRice, klassName).
861
+ define_constructor(Constructor<Buffer_T, VALUE>(), Arg("value").setValue()).
862
+ define_constructor(Constructor<Buffer_T, VALUE, size_t>(), Arg("value").setValue(), Arg("size")).
863
+ define_method("size", &Buffer_T::size).
864
+ template define_method<VALUE(Buffer_T::*)(size_t) const>("bytes", &Buffer_T::bytes, Return().setValue()).
865
+ template define_method<VALUE(Buffer_T::*)() const>("bytes", &Buffer_T::bytes, Return().setValue()).
866
+ define_method("data", &Buffer_T::ptr, Return().setBuffer()).
867
+ define_method("release", &Buffer_T::release, Return().setBuffer());
519
868
  }
520
869
  else
521
870
  {
522
871
  Data_Type<Buffer_T> klass = define_class_under<Buffer_T>(rb_mRice, klassName).
523
872
  define_constructor(Constructor<Buffer_T, VALUE>(), Arg("value").setValue()).
873
+ define_constructor(Constructor<Buffer_T, VALUE, size_t>(), Arg("value").setValue(), Arg("size")).
524
874
  define_method("size", &Buffer_T::size).
525
- define_method("size=", &Buffer_T::setSize).
526
- // template define_method<VALUE(Buffer_T::*)() const>("to_s", &Buffer_T::toString, Return().setValue()).
875
+ template define_method<VALUE(Buffer_T::*)() const>("to_s", &Buffer_T::toString, Return().setValue()).
527
876
  template define_method<VALUE(Buffer_T::*)(size_t) const>("bytes", &Buffer_T::bytes, Return().setValue()).
528
877
  template define_method<VALUE(Buffer_T::*)() const>("bytes", &Buffer_T::bytes, Return().setValue()).
529
878
  template define_method<Array(Buffer_T::*)(size_t) const>("to_ary", &Buffer_T::toArray, Return().setValue()).
530
- template define_method<Array(Buffer_T::*)() const>("to_ary", &Buffer_T::toArray, Return().setValue());
879
+ template define_method<Array(Buffer_T::*)() const>("to_ary", &Buffer_T::toArray, Return().setValue()).
880
+ define_method("[]", &Buffer_T::operator[], Arg("index")).
881
+ define_method("data", &Buffer_T::ptr, Return().setBuffer()).
882
+ define_method("release", &Buffer_T::release, Return().setBuffer());
531
883
 
532
- if constexpr (!std::is_pointer_v<T>)
884
+ if constexpr (!std::is_pointer_v<T> && !std::is_void_v<T> && !std::is_const_v<T> && std::is_copy_assignable_v<T>)
533
885
  {
534
- klass.
535
- define_method("[]", [](const Buffer_T& self, size_t index) -> T
536
- {
537
- return self.get(index);
538
- }).
539
- define_method("[]=", [](Buffer_T& self, size_t index, T element) -> void
540
- {
541
- self.set(index, element);
542
- });
886
+ klass.define_method("[]=", [](Buffer_T& self, size_t index, T& value) -> void
887
+ {
888
+ self[index] = value;
889
+ });
890
+ }
891
+ else if constexpr (std::is_pointer_v<T> && !std::is_const_v<std::remove_pointer_t<T>> && std::is_copy_assignable_v<std::remove_pointer_t<T>>)
892
+ {
893
+ klass.define_method("[]=", [](Buffer_T& self, size_t index, T value) -> void
894
+ {
895
+ *self[index] = *value;
896
+ });
543
897
  }
544
898
 
545
899
  return klass;
546
900
  }
547
901
  }
548
-
549
- inline void define_fundamental_buffer_types()
550
- {
551
- define_buffer<bool>();
552
- define_buffer<int>();
553
- define_buffer<int*>();
554
- define_buffer<unsigned int>();
555
- define_buffer<unsigned int*>();
556
- define_buffer<char>();
557
- define_buffer<char*>();
558
- define_buffer<unsigned char>();
559
- define_buffer<unsigned char*>();
560
- define_buffer<signed char>();
561
- define_buffer<signed char*>();
562
- define_buffer<double>();
563
- define_buffer<double*>();
564
- define_buffer<float>();
565
- define_buffer<float*>();
566
- define_buffer<long>();
567
- define_buffer<long*>();
568
- define_buffer<unsigned long>();
569
- define_buffer<unsigned long*>();
570
- define_buffer<long long>();
571
- define_buffer<long long*>();
572
- define_buffer<unsigned long long>();
573
- define_buffer<unsigned long long*>();
574
- define_buffer<short>();
575
- define_buffer<short*>();
576
- define_buffer<unsigned short>();
577
- define_buffer<unsigned short*>();
578
- define_buffer<void>();
579
- }
580
902
  }
581
903
 
582
904
  namespace Rice::detail
@@ -586,13 +908,8 @@ namespace Rice::detail
586
908
  {
587
909
  static bool verify()
588
910
  {
589
- Type<intrinsic_type<T>>::verify();
590
-
591
- if (!Data_Type<Buffer<T>>::is_defined())
592
- {
593
- define_buffer<T>();
594
- }
595
-
911
+ detail::verifyType<T>();
912
+ define_buffer<T>();
596
913
  return true;
597
914
  }
598
915
  };