rice 4.5.0 → 4.6.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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/CMakeLists.txt +31 -0
  4. data/CMakePresets.json +75 -0
  5. data/COPYING +3 -2
  6. data/FindRuby.cmake +437 -0
  7. data/Rakefile +5 -4
  8. data/include/rice/rice.hpp +5619 -3129
  9. data/include/rice/stl.hpp +2319 -1234
  10. data/lib/make_rice_headers.rb +79 -0
  11. data/lib/mkmf-rice.rb +4 -0
  12. data/lib/rice/version.rb +3 -0
  13. data/lib/rice.rb +1 -0
  14. data/lib/rubygems/builder.rb +11 -0
  15. data/lib/rubygems/cmake_builder.rb +113 -0
  16. data/lib/rubygems_plugin.rb +9 -0
  17. data/rice/Arg.hpp +7 -1
  18. data/rice/Arg.ipp +11 -2
  19. data/rice/Buffer.hpp +168 -0
  20. data/rice/Buffer.ipp +788 -0
  21. data/rice/Constructor.ipp +3 -3
  22. data/rice/Data_Object.hpp +2 -3
  23. data/rice/Data_Object.ipp +188 -188
  24. data/rice/Data_Type.hpp +7 -5
  25. data/rice/Data_Type.ipp +79 -52
  26. data/rice/Enum.hpp +0 -1
  27. data/rice/Enum.ipp +26 -23
  28. data/rice/Init.hpp +8 -0
  29. data/rice/Init.ipp +8 -0
  30. data/rice/MemoryView.ipp +1 -41
  31. data/rice/Return.hpp +1 -1
  32. data/rice/Return.ipp +6 -0
  33. data/rice/cpp_api/Array.hpp +209 -0
  34. data/rice/cpp_api/Array.ipp +304 -0
  35. data/rice/cpp_api/Builtin_Object.hpp +31 -0
  36. data/rice/cpp_api/Builtin_Object.ipp +37 -0
  37. data/rice/cpp_api/Class.hpp +70 -0
  38. data/rice/cpp_api/Class.ipp +97 -0
  39. data/rice/cpp_api/Encoding.hpp +32 -0
  40. data/rice/cpp_api/Encoding.ipp +59 -0
  41. data/rice/cpp_api/Hash.hpp +194 -0
  42. data/rice/cpp_api/Hash.ipp +257 -0
  43. data/rice/cpp_api/Identifier.hpp +46 -0
  44. data/rice/cpp_api/Identifier.ipp +31 -0
  45. data/rice/cpp_api/Module.hpp +72 -0
  46. data/rice/cpp_api/Module.ipp +101 -0
  47. data/rice/cpp_api/Object.hpp +272 -0
  48. data/rice/cpp_api/Object.ipp +235 -0
  49. data/rice/cpp_api/String.hpp +74 -0
  50. data/rice/cpp_api/String.ipp +120 -0
  51. data/rice/cpp_api/Struct.hpp +113 -0
  52. data/rice/cpp_api/Struct.ipp +92 -0
  53. data/rice/cpp_api/Symbol.hpp +46 -0
  54. data/rice/cpp_api/Symbol.ipp +93 -0
  55. data/rice/cpp_api/shared_methods.hpp +134 -0
  56. data/rice/detail/MethodInfo.hpp +1 -9
  57. data/rice/detail/MethodInfo.ipp +5 -72
  58. data/rice/detail/Native.hpp +3 -2
  59. data/rice/detail/Native.ipp +32 -4
  60. data/rice/detail/NativeAttributeGet.hpp +3 -2
  61. data/rice/detail/NativeAttributeGet.ipp +20 -3
  62. data/rice/detail/NativeAttributeSet.hpp +3 -2
  63. data/rice/detail/NativeAttributeSet.ipp +11 -23
  64. data/rice/detail/NativeCallbackFFI.ipp +2 -1
  65. data/rice/detail/NativeFunction.hpp +17 -6
  66. data/rice/detail/NativeFunction.ipp +169 -64
  67. data/rice/detail/NativeIterator.hpp +3 -2
  68. data/rice/detail/NativeIterator.ipp +8 -2
  69. data/rice/detail/RubyFunction.ipp +1 -0
  70. data/rice/detail/RubyType.hpp +2 -5
  71. data/rice/detail/RubyType.ipp +50 -5
  72. data/rice/detail/Type.hpp +3 -1
  73. data/rice/detail/Type.ipp +60 -31
  74. data/rice/detail/Wrapper.hpp +68 -33
  75. data/rice/detail/Wrapper.ipp +103 -113
  76. data/rice/detail/from_ruby.hpp +5 -4
  77. data/rice/detail/from_ruby.ipp +737 -365
  78. data/rice/detail/to_ruby.ipp +1092 -186
  79. data/rice/global_function.ipp +1 -1
  80. data/rice/libc/file.hpp +11 -0
  81. data/rice/libc/file.ipp +32 -0
  82. data/rice/rice.hpp +23 -16
  83. data/rice/stl/complex.hpp +6 -0
  84. data/rice/stl/complex.ipp +93 -0
  85. data/rice/stl/exception.hpp +11 -0
  86. data/rice/stl/exception.ipp +29 -0
  87. data/rice/stl/exception_ptr.hpp +6 -0
  88. data/rice/stl/exception_ptr.ipp +27 -0
  89. data/rice/stl/map.hpp +12 -0
  90. data/rice/stl/map.ipp +469 -0
  91. data/rice/stl/monostate.hpp +6 -0
  92. data/rice/stl/monostate.ipp +80 -0
  93. data/rice/stl/multimap.hpp +14 -0
  94. data/rice/stl/multimap.ipp +448 -0
  95. data/rice/stl/optional.hpp +6 -0
  96. data/rice/stl/optional.ipp +118 -0
  97. data/rice/stl/pair.hpp +13 -0
  98. data/rice/stl/pair.ipp +155 -0
  99. data/rice/stl/reference_wrapper.hpp +6 -0
  100. data/rice/stl/reference_wrapper.ipp +41 -0
  101. data/rice/stl/set.hpp +12 -0
  102. data/rice/stl/set.ipp +495 -0
  103. data/rice/stl/shared_ptr.hpp +28 -0
  104. data/rice/stl/shared_ptr.ipp +224 -0
  105. data/rice/stl/string.hpp +6 -0
  106. data/rice/stl/string.ipp +158 -0
  107. data/rice/stl/string_view.hpp +6 -0
  108. data/rice/stl/string_view.ipp +65 -0
  109. data/rice/stl/tuple.hpp +6 -0
  110. data/rice/stl/tuple.ipp +128 -0
  111. data/rice/stl/type_index.hpp +6 -0
  112. data/rice/stl/type_index.ipp +30 -0
  113. data/rice/stl/type_info.hpp +6 -0
  114. data/rice/stl/type_info.ipp +29 -0
  115. data/rice/stl/unique_ptr.hpp +22 -0
  116. data/rice/stl/unique_ptr.ipp +139 -0
  117. data/rice/stl/unordered_map.hpp +12 -0
  118. data/rice/stl/unordered_map.ipp +469 -0
  119. data/rice/stl/variant.hpp +6 -0
  120. data/rice/stl/variant.ipp +242 -0
  121. data/rice/stl/vector.hpp +12 -0
  122. data/rice/stl/vector.ipp +589 -0
  123. data/rice/stl.hpp +7 -3
  124. data/rice/traits/attribute_traits.hpp +26 -0
  125. data/rice/traits/function_traits.hpp +95 -0
  126. data/rice/traits/method_traits.hpp +47 -0
  127. data/rice/traits/rice_traits.hpp +172 -0
  128. data/rice.gemspec +85 -0
  129. data/test/embed_ruby.cpp +3 -0
  130. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  131. data/test/test_Array.cpp +6 -3
  132. data/test/test_Attribute.cpp +91 -9
  133. data/test/test_Buffer.cpp +340 -0
  134. data/test/test_Callback.cpp +2 -3
  135. data/test/test_Data_Object.cpp +88 -34
  136. data/test/test_Data_Type.cpp +106 -65
  137. data/test/test_Director.cpp +7 -3
  138. data/test/test_Enum.cpp +5 -2
  139. data/test/test_File.cpp +1 -1
  140. data/test/test_From_Ruby.cpp +180 -113
  141. data/test/test_Iterator.cpp +1 -1
  142. data/test/{test_JumpException.cpp → test_Jump_Exception.cpp} +1 -0
  143. data/test/test_Keep_Alive.cpp +7 -18
  144. data/test/test_Keep_Alive_No_Wrapper.cpp +0 -1
  145. data/test/test_Module.cpp +13 -6
  146. data/test/test_Native_Registry.cpp +0 -1
  147. data/test/test_Overloads.cpp +180 -5
  148. data/test/test_Ownership.cpp +100 -57
  149. data/test/test_Proc.cpp +0 -1
  150. data/test/test_Self.cpp +4 -4
  151. data/test/test_Stl_Map.cpp +37 -39
  152. data/test/test_Stl_Multimap.cpp +693 -0
  153. data/test/test_Stl_Pair.cpp +8 -8
  154. data/test/test_Stl_Reference_Wrapper.cpp +4 -2
  155. data/test/test_Stl_Set.cpp +790 -0
  156. data/test/{test_Stl_SmartPointer.cpp → test_Stl_SharedPtr.cpp} +97 -127
  157. data/test/test_Stl_Tuple.cpp +116 -0
  158. data/test/test_Stl_Type.cpp +1 -1
  159. data/test/test_Stl_UniquePtr.cpp +202 -0
  160. data/test/test_Stl_Unordered_Map.cpp +28 -34
  161. data/test/test_Stl_Variant.cpp +217 -89
  162. data/test/test_Stl_Vector.cpp +209 -83
  163. data/test/test_To_Ruby.cpp +373 -1
  164. data/test/test_Type.cpp +85 -14
  165. data/test/test_global_functions.cpp +17 -4
  166. metadata +94 -10
  167. data/rice/detail/TupleIterator.hpp +0 -14
data/rice/Buffer.ipp ADDED
@@ -0,0 +1,788 @@
1
+ namespace Rice
2
+ {
3
+ // ---- Buffer<T> -------
4
+ template<typename T>
5
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::Buffer(T* pointer) : m_buffer(pointer)
6
+ {
7
+ }
8
+
9
+ template<typename T>
10
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::Buffer(T* pointer, size_t size) : m_size(size), m_buffer(pointer)
11
+ {
12
+ }
13
+
14
+ template <typename T>
15
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::Buffer(VALUE value)
16
+ {
17
+ if constexpr (std::is_fundamental_v<T>)
18
+ {
19
+ this->fromBuiltinType(value);
20
+ }
21
+ else
22
+ {
23
+ this->fromWrappedType(value);
24
+ }
25
+ }
26
+
27
+ template <typename T>
28
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::~Buffer()
29
+ {
30
+ if constexpr (std::is_destructible_v<T>)
31
+ {
32
+ if (this->m_owner)
33
+ {
34
+ delete[] this->m_buffer;
35
+ }
36
+ }
37
+ }
38
+
39
+ template <typename T>
40
+ inline void Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::fromBuiltinType(VALUE value)
41
+ {
42
+ using Intrinsic_T = typename detail::intrinsic_type<T>;
43
+ using RubyType_T = typename detail::RubyType<Intrinsic_T>;
44
+ ruby_value_type valueType = rb_type(value);
45
+
46
+ switch (valueType)
47
+ {
48
+ case RUBY_T_ARRAY:
49
+ {
50
+ Array array(value);
51
+ this->m_size = array.size();
52
+ this->m_buffer = new T[this->m_size]();
53
+
54
+ String packed = array.pack<Intrinsic_T>();
55
+ memcpy(this->m_buffer, RSTRING_PTR(packed.value()), RSTRING_LEN(packed.value()));
56
+
57
+ this->m_owner = true;
58
+ break;
59
+ }
60
+ case RUBY_T_STRING:
61
+ {
62
+ this->m_size = RSTRING_LEN(value);
63
+ if constexpr (std::is_same_v<T, char>)
64
+ {
65
+ // Add 2 for null characters (string and wstring)
66
+ this->m_buffer = new T[this->m_size + 2]();
67
+ }
68
+ else
69
+ {
70
+ this->m_buffer = new T[this->m_size]();
71
+ }
72
+ memcpy(this->m_buffer, RSTRING_PTR(value), this->m_size);
73
+
74
+ this->m_owner = true;
75
+ break;
76
+ }
77
+ case RUBY_T_DATA:
78
+ {
79
+ if (Data_Type<T>::is_descendant(value))
80
+ {
81
+ this->m_size = 1;
82
+ this->m_buffer = new T[this->m_size]();
83
+ this->m_buffer[0] = *detail::unwrap<T>(value, Data_Type<T>::ruby_data_type(), false);
84
+ this->m_owner = false;
85
+ break;
86
+ }
87
+ }
88
+ default:
89
+ {
90
+ if (RubyType_T::Exact.find(valueType) != RubyType_T::Exact.end() ||
91
+ RubyType_T::Castable.find(valueType) != RubyType_T::Castable.end() ||
92
+ RubyType_T::Narrowable.find(valueType) != RubyType_T::Narrowable.end())
93
+ {
94
+ T data = detail::protect(RubyType_T::fromRuby, value);
95
+ this->m_size = 1;
96
+ this->m_buffer = new T[this->m_size]();
97
+ memcpy(this->m_buffer, &data, sizeof(T));
98
+ this->m_owner = true;
99
+ break;
100
+ }
101
+ else
102
+ {
103
+ std::string typeName = detail::typeName(typeid(T));
104
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s*)",
105
+ detail::protect(rb_obj_classname, value), typeName.c_str());
106
+ }
107
+ }
108
+ }
109
+ }
110
+
111
+ template <typename T>
112
+ inline void Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::fromWrappedType(VALUE value)
113
+ {
114
+ using Intrinsic_T = typename detail::intrinsic_type<T>;
115
+
116
+ switch (rb_type(value))
117
+ {
118
+ case RUBY_T_ARRAY:
119
+ {
120
+ Array array(value);
121
+ this->m_size = array.size();
122
+
123
+ // Use operator new[] to allocate memory but not call constructors
124
+ this->m_buffer = static_cast<T*>(operator new[](sizeof(T)* this->m_size));
125
+
126
+ detail::From_Ruby<Intrinsic_T> fromRuby;
127
+
128
+ for (size_t i = 0; i < this->m_size; i++)
129
+ {
130
+ this->m_buffer[i] = fromRuby.convert(array[i].value());
131
+ }
132
+ break;
133
+ }
134
+ default:
135
+ {
136
+ std::string typeName = detail::typeName(typeid(T));
137
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s*)",
138
+ detail::protect(rb_obj_classname, value), typeName.c_str());
139
+ }
140
+ }
141
+ }
142
+
143
+ template <typename T>
144
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::Buffer(Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>&& other) : m_owner(other.m_owner), m_size(other.m_size), m_buffer(other.m_buffer)
145
+ {
146
+ other.m_buffer = nullptr;
147
+ other.m_size = 0;
148
+ other.m_owner = false;
149
+ }
150
+
151
+ template <typename T>
152
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>& Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::operator=(Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>&& other)
153
+ {
154
+ this->m_buffer = other.m_buffer;
155
+ other.m_buffer = nullptr;
156
+
157
+ this->m_size = other.m_size;
158
+ other.m_size = 0;
159
+
160
+ this->m_owner = other.m_owner;
161
+ other.m_owner = false;
162
+
163
+ return *this;
164
+ }
165
+
166
+ template <typename T>
167
+ inline size_t Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::size() const
168
+ {
169
+ return this->m_size;
170
+ }
171
+
172
+ template <typename T>
173
+ void Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::setSize(size_t value)
174
+ {
175
+ this->m_size = value;
176
+ }
177
+
178
+ template <typename T>
179
+ inline T* Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::ptr()
180
+ {
181
+ return this->m_buffer;
182
+ }
183
+
184
+ template <typename T>
185
+ inline T& Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::reference()
186
+ {
187
+ return *this->m_buffer;
188
+ }
189
+
190
+ template <typename T>
191
+ inline bool Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::isOwner() const
192
+ {
193
+ return this->m_owner;
194
+ }
195
+
196
+ template <typename T>
197
+ inline void Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::setOwner(bool value)
198
+ {
199
+ this->m_owner = value;
200
+ }
201
+
202
+ template <typename T>
203
+ inline void Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::release()
204
+ {
205
+ this->m_owner = false;
206
+ }
207
+
208
+ template<typename T>
209
+ inline VALUE Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::toString() const
210
+ {
211
+ std::string name = detail::typeName(typeid(T*));
212
+ std::string description = "Buffer<type: " + detail::cppClassName(name) + ", size: " + std::to_string(this->m_size) + ">";
213
+
214
+ // We can't use To_Ruby because To_Ruby depends on Buffer - ie a circular reference
215
+ return detail::protect(rb_utf8_str_new_cstr, description.c_str());
216
+ }
217
+
218
+ template<typename T>
219
+ inline VALUE Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::bytes(size_t count) const
220
+ {
221
+ if (!this->m_buffer)
222
+ {
223
+ return Qnil;
224
+ }
225
+ else
226
+ {
227
+ long length = (long)(count * sizeof(T));
228
+ return detail::protect(rb_str_new_static, (const char*)this->m_buffer, length);
229
+ }
230
+ }
231
+
232
+ template<typename T>
233
+ inline VALUE Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::bytes() const
234
+ {
235
+ return this->bytes(this->m_size);
236
+ }
237
+
238
+ template<typename T>
239
+ inline Array Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::toArray(size_t count) const
240
+ {
241
+ if (!this->m_buffer)
242
+ {
243
+ return Qnil;
244
+ }
245
+ else if constexpr (std::is_fundamental_v<T>)
246
+ {
247
+ VALUE string = this->bytes(count);
248
+ return String(string).unpack<T>();
249
+ }
250
+ else
251
+ {
252
+ Array result;
253
+
254
+ T* ptr = this->m_buffer;
255
+ T* end = this->m_buffer + count;
256
+
257
+ for (; ptr < end; ptr++)
258
+ {
259
+ result.push(*ptr);
260
+ }
261
+ return result;
262
+ }
263
+ }
264
+
265
+ template<typename T>
266
+ inline Array Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::toArray() const
267
+ {
268
+ return this->toArray(this->m_size);
269
+ }
270
+
271
+ template<typename T>
272
+ inline typename Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::Element_T& Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::operator[](size_t index)
273
+ {
274
+ if (index >= this->m_size)
275
+ {
276
+ throw Exception(rb_eIndexError, "index %ld outside of bounds: 0..%ld", index, this->m_size);
277
+ }
278
+
279
+ return this->m_buffer[index];
280
+ }
281
+
282
+ // ---- Buffer<T*> - Builtin -------
283
+ template<typename T>
284
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Buffer(T** pointer) : m_outer(pointer)
285
+ {
286
+ }
287
+
288
+ template<typename T>
289
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Buffer(T** pointer, size_t size) : m_outer(pointer), m_size(size)
290
+ {
291
+ }
292
+
293
+ template <typename T>
294
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Buffer(VALUE value)
295
+ {
296
+ ruby_value_type valueType = rb_type(value);
297
+
298
+ switch (valueType)
299
+ {
300
+ case RUBY_T_ARRAY:
301
+ {
302
+ Array outer(value);
303
+ this->m_size = outer.size();
304
+ this->m_outer = new T * [this->m_size]();
305
+
306
+ for (size_t i = 0; i < this->m_size; i++)
307
+ {
308
+ // Check the inner value is also an array
309
+ Array inner(outer[i].value());
310
+
311
+ // Wrap it with a buffer and add it our list of inner buffers
312
+ Buffer<T> buffer(inner.value());
313
+
314
+ // And update the outer array
315
+ this->m_outer[i] = buffer.ptr();
316
+
317
+ // Now move the buffer into the affer, not the buffer pointer is still valid (it just got moved)
318
+ this->m_inner.push_back(std::move(buffer));
319
+ }
320
+
321
+ this->m_owner = true;
322
+ break;
323
+ }
324
+ default:
325
+ {
326
+ std::string typeName = detail::typeName(typeid(T));
327
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s*)",
328
+ detail::protect(rb_obj_classname, value), typeName.c_str());
329
+ }
330
+ }
331
+ }
332
+
333
+ template <typename T>
334
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::~Buffer()
335
+ {
336
+ if (this->m_owner)
337
+ {
338
+ delete[] this->m_outer;
339
+ }
340
+ }
341
+
342
+ template <typename T>
343
+ 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),
344
+ m_outer(other.m_outer), m_inner(std::move(other.m_inner))
345
+ {
346
+ other.m_outer = nullptr;
347
+ other.m_inner.clear();
348
+ other.m_size = 0;
349
+ other.m_owner = false;
350
+ }
351
+
352
+ template <typename T>
353
+ 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)
354
+ {
355
+ this->m_outer = other.m_outer;
356
+ other.m_outer = nullptr;
357
+
358
+ this->m_inner = std::move(other.m_inner);
359
+ other.m_inner.clear();
360
+
361
+ this->m_size = other.m_size;
362
+ other.m_size = 0;
363
+
364
+ this->m_owner = other.m_owner;
365
+ other.m_owner = false;
366
+
367
+ return *this;
368
+ }
369
+
370
+ template <typename T>
371
+ inline typename Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Element_T& Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::operator[](size_t index)
372
+ {
373
+ return this->m_inner[index];
374
+ }
375
+
376
+ template <typename T>
377
+ inline size_t Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::size() const
378
+ {
379
+ return this->m_size;
380
+ }
381
+
382
+ template <typename T>
383
+ void Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::setSize(size_t value)
384
+ {
385
+ this->m_size = value;
386
+ }
387
+
388
+ template <typename T>
389
+ inline T** Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::ptr()
390
+ {
391
+ return this->m_outer;
392
+ }
393
+
394
+ template <typename T>
395
+ inline bool Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::isOwner() const
396
+ {
397
+ return this->m_owner;
398
+ }
399
+
400
+ template <typename T>
401
+ inline void Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::setOwner(bool value)
402
+ {
403
+ this->m_owner = value;
404
+ }
405
+
406
+ template <typename T>
407
+ inline void Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::release()
408
+ {
409
+ this->m_owner = false;
410
+ }
411
+
412
+ template<typename T>
413
+ inline VALUE Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::toString() const
414
+ {
415
+ std::string name = detail::typeName(typeid(T*));
416
+ std::string description = "Buffer<type: " + detail::cppClassName(name) + ", size: " + std::to_string(this->m_size) + ">";
417
+
418
+ // We can't use To_Ruby because To_Ruby depends on Buffer - ie a circular reference
419
+ return detail::protect(rb_utf8_str_new_cstr, description.c_str());
420
+ }
421
+
422
+ template<typename T>
423
+ inline VALUE Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::bytes(size_t count) const
424
+ {
425
+ if (!this->m_outer)
426
+ {
427
+ return Qnil;
428
+ }
429
+ else
430
+ {
431
+ T** begin = this->m_outer;
432
+ long length = (long)(count * sizeof(T*));
433
+ return detail::protect(rb_str_new_static, (const char*)*begin, length);
434
+ }
435
+ }
436
+
437
+ template<typename T>
438
+ inline VALUE Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::bytes() const
439
+ {
440
+ return this->bytes(this->m_size);
441
+ }
442
+
443
+ template<typename T>
444
+ inline Array Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::toArray(size_t count) const
445
+ {
446
+ if (!this->m_outer)
447
+ {
448
+ return Qnil;
449
+ }
450
+ else
451
+ {
452
+ Array result;
453
+
454
+ T** ptr = this->m_outer;
455
+ T** end = this->m_outer + count;
456
+
457
+ for (; ptr < end; ptr++)
458
+ {
459
+ Buffer<T> buffer(*ptr);
460
+ result.push(std::move(buffer));
461
+ }
462
+ return result;
463
+ }
464
+ }
465
+
466
+ template<typename T>
467
+ inline Array Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::toArray() const
468
+ {
469
+ return this->toArray(this->m_size);
470
+ }
471
+
472
+ // ---- Buffer<T*> - Wrapped -------
473
+ template<typename T>
474
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Buffer(T** pointer) : m_buffer(pointer)
475
+ {
476
+ }
477
+
478
+ template<typename T>
479
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Buffer(T** pointer, size_t size) : m_buffer(pointer), m_size(size)
480
+ {
481
+ }
482
+
483
+ template <typename T>
484
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Buffer(VALUE value)
485
+ {
486
+ ruby_value_type valueType = rb_type(value);
487
+
488
+ switch (valueType)
489
+ {
490
+ case RUBY_T_ARRAY:
491
+ {
492
+ Array array(value);
493
+ this->m_size = array.size();
494
+ this->m_buffer = new T * [this->m_size]();
495
+
496
+ detail::From_Ruby<T> fromRuby;
497
+ for (size_t i = 0; i < this->m_size; i++)
498
+ {
499
+ Data_Object<detail::intrinsic_type<T>> dataObject(array[i].value());
500
+ this->m_buffer[i] = dataObject.get();
501
+ }
502
+
503
+ this->m_owner = true;
504
+ break;
505
+ }
506
+ default:
507
+ {
508
+ std::string typeName = detail::typeName(typeid(T));
509
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s*)",
510
+ detail::protect(rb_obj_classname, value), typeName.c_str());
511
+ }
512
+ }
513
+ }
514
+
515
+ template <typename T>
516
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::~Buffer()
517
+ {
518
+ if (this->m_owner)
519
+ {
520
+ delete[] this->m_buffer;
521
+ }
522
+ }
523
+
524
+ template <typename T>
525
+ 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),
526
+ m_buffer(other.m_buffer)
527
+ {
528
+ other.m_buffer = nullptr;
529
+ other.m_size = 0;
530
+ other.m_owner = false;
531
+ }
532
+
533
+ template <typename T>
534
+ 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)
535
+ {
536
+ this->m_buffer = other.m_buffer;
537
+ other.m_buffer = nullptr;
538
+
539
+ this->m_size = other.m_size;
540
+ other.m_size = 0;
541
+
542
+ this->m_owner = other.m_owner;
543
+ other.m_owner = false;
544
+
545
+ return *this;
546
+ }
547
+
548
+ template <typename T>
549
+ inline typename Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Element_T& Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::operator[](size_t index)
550
+ {
551
+ if (index >= this->m_size)
552
+ {
553
+ throw Exception(rb_eIndexError, "index %ld outside of bounds: 0..%ld", index, this->m_size);
554
+ }
555
+ return this->m_buffer[index];
556
+ }
557
+
558
+ template <typename T>
559
+ inline size_t Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::size() const
560
+ {
561
+ return this->m_size;
562
+ }
563
+
564
+ template <typename T>
565
+ void Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::setSize(size_t value)
566
+ {
567
+ this->m_size = value;
568
+ }
569
+
570
+ template <typename T>
571
+ inline T** Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::ptr()
572
+ {
573
+ return this->m_buffer;
574
+ }
575
+
576
+ template <typename T>
577
+ inline bool Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::isOwner() const
578
+ {
579
+ return this->m_owner;
580
+ }
581
+
582
+ template <typename T>
583
+ inline void Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::setOwner(bool value)
584
+ {
585
+ this->m_owner = value;
586
+ }
587
+
588
+ template <typename T>
589
+ inline void Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::release()
590
+ {
591
+ this->m_owner = false;
592
+ }
593
+
594
+ template<typename T>
595
+ inline VALUE Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::toString() const
596
+ {
597
+ std::string name = detail::typeName(typeid(T*));
598
+ std::string description = "Buffer<type: " + detail::cppClassName(name) + ", size: " + std::to_string(this->m_size) + ">";
599
+
600
+ // We can't use To_Ruby because To_Ruby depends on Buffer - ie a circular reference
601
+ return detail::protect(rb_utf8_str_new_cstr, description.c_str());
602
+ }
603
+
604
+ template<typename T>
605
+ inline VALUE Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::bytes(size_t count) const
606
+ {
607
+ if (!this->m_buffer)
608
+ {
609
+ return Qnil;
610
+ }
611
+ else
612
+ {
613
+ T** begin = this->m_buffer;
614
+ long length = (long)(count * sizeof(T*));
615
+ return detail::protect(rb_str_new_static, (const char*)*begin, length);
616
+ }
617
+ }
618
+
619
+ template<typename T>
620
+ inline VALUE Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::bytes() const
621
+ {
622
+ return this->bytes(this->m_size);
623
+ }
624
+
625
+ template<typename T>
626
+ inline Array Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::toArray(size_t count) const
627
+ {
628
+ if (!this->m_buffer)
629
+ {
630
+ return Qnil;
631
+ }
632
+ else
633
+ {
634
+ Array result;
635
+
636
+ T** ptr = this->m_buffer;
637
+ T** end = this->m_buffer + count;
638
+
639
+ for (; ptr < end; ptr++)
640
+ {
641
+ result.push(*ptr);
642
+ }
643
+ return result;
644
+ }
645
+ }
646
+
647
+ template<typename T>
648
+ inline Array Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::toArray() const
649
+ {
650
+ return this->toArray(this->m_size);
651
+ }
652
+
653
+ // ---- Buffer<void> -------
654
+ inline Buffer<void>::Buffer(void* pointer) : m_buffer(pointer)
655
+ {
656
+ }
657
+
658
+ inline Buffer<void>::Buffer(Buffer<void>&& other) : m_buffer(other.m_buffer)
659
+ {
660
+ other.m_buffer = nullptr;
661
+ }
662
+
663
+ inline Buffer<void>& Buffer<void>::operator=(Buffer<void>&& other)
664
+ {
665
+ this->m_buffer = other.m_buffer;
666
+ other.m_buffer = nullptr;
667
+
668
+ return *this;
669
+ }
670
+
671
+ inline void* Buffer<void>::ptr()
672
+ {
673
+ return this->m_buffer;
674
+ }
675
+
676
+ // ------ define_buffer ----------
677
+ template<typename T>
678
+ inline Data_Type<Buffer<T>> define_buffer(std::string klassName)
679
+ {
680
+ using Buffer_T = Buffer<T>;
681
+
682
+ if (klassName.empty())
683
+ {
684
+ std::string typeName = detail::typeName(typeid(Buffer_T));
685
+ // This will end up as Buffer<T,void>. We want to remove the ,void part.
686
+ auto removeVoidRegex = std::regex(",\\s?void");
687
+ typeName = std::regex_replace(typeName, removeVoidRegex, "");
688
+ klassName = detail::rubyClassName(typeName);
689
+ }
690
+
691
+ Module rb_mRice = define_module("Rice");
692
+
693
+ if constexpr (std::is_void_v<T>)
694
+ {
695
+ return define_class_under<Buffer_T>(rb_mRice, klassName);
696
+ }
697
+ else
698
+ {
699
+ Data_Type<Buffer_T> klass = define_class_under<Buffer_T>(rb_mRice, klassName).
700
+ define_constructor(Constructor<Buffer_T, VALUE>(), Arg("value").setValue()).
701
+ define_method("size", &Buffer_T::size).
702
+ define_method("size=", &Buffer_T::setSize).
703
+ template define_method<VALUE(Buffer_T::*)() const>("to_s", &Buffer_T::toString, Return().setValue()).
704
+ template define_method<VALUE(Buffer_T::*)(size_t) const>("bytes", &Buffer_T::bytes, Return().setValue()).
705
+ template define_method<VALUE(Buffer_T::*)() const>("bytes", &Buffer_T::bytes, Return().setValue()).
706
+ template define_method<Array(Buffer_T::*)(size_t) const>("to_ary", &Buffer_T::toArray, Return().setValue()).
707
+ template define_method<Array(Buffer_T::*)() const>("to_ary", &Buffer_T::toArray, Return().setValue());
708
+
709
+ klass.
710
+ define_method("[]", &Buffer_T::operator[], Arg("index"));
711
+
712
+ if constexpr (std::is_pointer_v<T> && detail::is_wrapped_v<T>)
713
+ {
714
+ klass.define_method("[]=", [](Buffer_T& self, size_t index, typename Buffer_T::Element_T element) -> void
715
+ {
716
+ self[index] = element;
717
+ });
718
+ }
719
+ else if constexpr (std::is_pointer_v<T> && !detail::is_wrapped_v<T>)
720
+ {
721
+ klass.define_method("[]=", [](Buffer_T& self, size_t index, typename Buffer_T::Element_T& element) -> void
722
+ {
723
+ self[index] = std::move(element);
724
+ });
725
+ }
726
+ else
727
+ {
728
+ klass.define_method("[]=", [](Buffer_T& self, size_t index, typename Buffer_T::Element_T& element) -> void
729
+ {
730
+ self[index] = element;
731
+ });
732
+ }
733
+
734
+ return klass;
735
+ }
736
+ }
737
+
738
+ inline void define_fundamental_buffer_types()
739
+ {
740
+ define_buffer<bool>();
741
+ define_buffer<int>();
742
+ define_buffer<int*>();
743
+ define_buffer<unsigned int>();
744
+ define_buffer<unsigned int*>();
745
+ define_buffer<char>();
746
+ define_buffer<char*>();
747
+ define_buffer<unsigned char>();
748
+ define_buffer<unsigned char*>();
749
+ define_buffer<signed char>();
750
+ define_buffer<signed char*>();
751
+ define_buffer<double>();
752
+ define_buffer<double*>();
753
+ define_buffer<float>();
754
+ define_buffer<float*>();
755
+ define_buffer<long>();
756
+ define_buffer<long*>();
757
+ define_buffer<unsigned long>();
758
+ define_buffer<unsigned long*>();
759
+ define_buffer<long long>();
760
+ define_buffer<long long*>();
761
+ define_buffer<unsigned long long>();
762
+ define_buffer<unsigned long long*>();
763
+ define_buffer<short>();
764
+ define_buffer<short*>();
765
+ define_buffer<unsigned short>();
766
+ define_buffer<unsigned short*>();
767
+ define_buffer<void>();
768
+ }
769
+ }
770
+
771
+ namespace Rice::detail
772
+ {
773
+ template<typename T>
774
+ struct Type<Buffer<T>>
775
+ {
776
+ static bool verify()
777
+ {
778
+ Type<intrinsic_type<T>>::verify();
779
+
780
+ if (!Data_Type<Buffer<T>>::is_defined())
781
+ {
782
+ define_buffer<T>();
783
+ }
784
+
785
+ return true;
786
+ }
787
+ };
788
+ }