carray 3.0.0 → 3.0.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 (180) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -1
  3. data/CHANGELOG.md +325 -3
  4. data/{NEWS.md → CHANGELOG.v1.md} +1 -1
  5. data/README.md +32 -32
  6. data/carray.gemspec +12 -8
  7. data/ext/ca_axis_group.c +55 -19
  8. data/ext/ca_binop_dispatch.c +5 -6
  9. data/ext/ca_binop_dispatch.h +0 -7
  10. data/ext/ca_categorical_iterator.c +13 -13
  11. data/ext/ca_for_each_element.h +6 -8
  12. data/ext/ca_group_iter.c +1 -1
  13. data/ext/ca_kernel_iterator.c +69 -23
  14. data/ext/ca_kernel_iterator.h +3 -10
  15. data/ext/ca_obj_bincmp.c +57 -27
  16. data/ext/ca_obj_binop.c +86 -30
  17. data/ext/ca_obj_const_string.c +3 -1
  18. data/ext/ca_obj_face.c +80 -0
  19. data/ext/ca_obj_face.h +33 -1
  20. data/ext/ca_obj_fake.c +11 -0
  21. data/ext/ca_obj_fixlen_string.c +3 -1
  22. data/ext/ca_obj_grid.c +11 -3
  23. data/ext/ca_obj_meld.c +13 -8
  24. data/ext/ca_obj_moncmp.c +33 -14
  25. data/ext/ca_obj_monop.c +19 -7
  26. data/ext/ca_obj_object.c +99 -4
  27. data/ext/ca_obj_record.c +3 -1
  28. data/ext/ca_obj_refer.c +30 -6
  29. data/ext/ca_obj_roll.c +13 -5
  30. data/ext/ca_obj_select_axis.c +16 -6
  31. data/ext/ca_obj_shift.c +3 -3
  32. data/ext/ca_obj_stride.c +106 -23
  33. data/ext/ca_obj_string.c +3 -1
  34. data/ext/ca_obj_tile.c +13 -5
  35. data/ext/ca_obj_time.c +3 -1
  36. data/ext/ca_obj_timedelta.c +3 -1
  37. data/ext/ca_obj_transpose.c +1 -1
  38. data/ext/ca_obj_triop.c +62 -23
  39. data/ext/ca_obj_window.c +86 -17
  40. data/ext/ca_op_cmplx64.h +123 -0
  41. data/ext/ca_op_ipower.c +0 -3
  42. data/ext/ca_sort_kernels.h +5 -5
  43. data/ext/ca_sweep_engine.c +78 -35
  44. data/ext/ca_sweep_engine.h +13 -4
  45. data/ext/ca_transform_common.c +7 -0
  46. data/ext/carray.h +127 -130
  47. data/ext/carray_access.c +56 -34
  48. data/ext/carray_bincount.c +8 -8
  49. data/ext/carray_broadcast.c +99 -6
  50. data/ext/carray_build_flags.h +3 -0
  51. data/ext/carray_call_cfunc.c +1491 -0
  52. data/ext/carray_call_cfunc.h +153 -0
  53. data/ext/carray_cast.c +69 -31
  54. data/ext/carray_conversion.c +22 -22
  55. data/ext/carray_copy.c +12 -2
  56. data/ext/carray_core.c +57 -10
  57. data/ext/carray_count.c +1 -1
  58. data/ext/carray_element.c +7 -7
  59. data/ext/carray_factorize.c +28 -28
  60. data/ext/carray_hold.c +1 -1
  61. data/ext/carray_index_classifier.c +7 -21
  62. data/ext/carray_internal.h +19 -3
  63. data/ext/carray_kernels_bincmp.c +1 -0
  64. data/ext/carray_kernels_binop.c +320 -298
  65. data/ext/carray_kernels_init.c +1095 -0
  66. data/ext/carray_kernels_map.c +1 -0
  67. data/ext/carray_kernels_moncmp.c +1 -0
  68. data/ext/carray_kernels_monop.c +412 -411
  69. data/ext/carray_kernels_reduce_aggregate.c +88 -87
  70. data/ext/carray_kernels_reduce_boolean.c +1 -0
  71. data/ext/carray_kernels_reduce_cumulative.c +54 -53
  72. data/ext/carray_kernels_reduce_extreme.c +51 -50
  73. data/ext/carray_kernels_reduce_variance.c +1 -0
  74. data/ext/carray_kernels_scan.c +1 -0
  75. data/ext/carray_kernels_search.c +93 -92
  76. data/ext/carray_kernels_sort.c +1 -0
  77. data/ext/carray_kernels_triop.c +1 -0
  78. data/ext/carray_lazy.c +175 -5
  79. data/ext/carray_mask.c +6 -5
  80. data/ext/carray_median_percentile.c +1 -1
  81. data/ext/carray_memory_view.c +46 -21
  82. data/ext/carray_operator.c +46 -49
  83. data/ext/carray_partition.c +4 -4
  84. data/ext/carray_random.c +7 -7
  85. data/ext/carray_scatter.c +1 -1
  86. data/ext/carray_sort.c +3 -3
  87. data/ext/carray_sort_kernel.c +10 -10
  88. data/ext/carray_test.c +1 -1
  89. data/ext/extconf.rb +18 -0
  90. data/ext/mk_call_cfunc.rb +243 -52
  91. data/ext/mkkernel.rb +354 -100
  92. data/ext/ruby_carray.c +18 -16
  93. data/ext/version.h +4 -4
  94. data/lib/carray/autoload_carray.rb +19 -0
  95. data/lib/carray/autoload_method_extension.rb +2 -1
  96. data/lib/carray/axis_group.rb +7 -7
  97. data/lib/carray/basics.rb +59 -59
  98. data/lib/carray/bincount_nd.rb +12 -12
  99. data/lib/carray/block_iterator.rb +24 -14
  100. data/lib/carray/categorical.rb +4 -4
  101. data/lib/carray/categorical_iterator.rb +98 -76
  102. data/lib/carray/conditional.rb +14 -14
  103. data/lib/carray/construct.rb +21 -0
  104. data/lib/carray/core_extensions.rb +62 -5
  105. data/lib/carray/data_type_extension.rb +18 -1
  106. data/lib/carray/frame/concat.rb +3 -3
  107. data/lib/carray/frame/convert.rb +1 -1
  108. data/lib/carray/frame/frame.rb +4 -11
  109. data/lib/carray/frame/io.rb +159 -2
  110. data/lib/carray/frame/sort.rb +1 -1
  111. data/lib/carray/frame/verbs.rb +18 -1
  112. data/lib/carray/fuse_source.rb +123 -0
  113. data/lib/carray/fusion.rb +218 -0
  114. data/lib/carray/histogram.rb +16 -16
  115. data/lib/carray/inspect.rb +1 -7
  116. data/lib/carray/iterator.rb +4 -3
  117. data/lib/carray/lazy.rb +125 -73
  118. data/lib/carray/meld_reduce.rb +2 -2
  119. data/lib/carray/methods/align_addr.rb +1 -1
  120. data/lib/carray/methods/composition.rb +1 -1
  121. data/lib/carray/methods/is_in.rb +12 -12
  122. data/lib/carray/methods/locate_addr.rb +6 -1
  123. data/lib/carray/methods/mask_duplicates.rb +1 -1
  124. data/lib/carray/methods/meshgrid.rb +4 -5
  125. data/lib/carray/methods/mode.rb +2 -2
  126. data/lib/carray/methods/nunique.rb +1 -1
  127. data/lib/carray/methods/snap.rb +7 -2
  128. data/lib/carray/methods/unique.rb +3 -3
  129. data/lib/carray/methods/value_counts.rb +2 -2
  130. data/lib/carray/runtime.rb +0 -19
  131. data/lib/carray/slab_iterator.rb +20 -7
  132. data/lib/carray/string_operation_extension.rb +5 -5
  133. data/lib/carray/time.rb +890 -491
  134. data/lib/carray/window_iterator.rb +285 -13
  135. data/lib/carray.rb +5 -5
  136. data/yard-stubs/ca_obj_array.rb +385 -0
  137. data/yard-stubs/ca_obj_bitarray.rb +38 -0
  138. data/yard-stubs/ca_obj_bitfield.rb +43 -0
  139. data/yard-stubs/ca_obj_block.rb +73 -0
  140. data/yard-stubs/ca_obj_byte_swap.rb +56 -0
  141. data/yard-stubs/ca_obj_fake.rb +31 -0
  142. data/yard-stubs/ca_obj_farray.rb +32 -0
  143. data/yard-stubs/ca_obj_field.rb +45 -0
  144. data/yard-stubs/ca_obj_grid.rb +35 -0
  145. data/yard-stubs/ca_obj_refer.rb +72 -0
  146. data/yard-stubs/ca_obj_roll.rb +45 -0
  147. data/yard-stubs/ca_obj_shift.rb +43 -0
  148. data/yard-stubs/ca_obj_stride.rb +181 -0
  149. data/yard-stubs/ca_obj_tile.rb +29 -0
  150. data/yard-stubs/ca_obj_transpose.rb +40 -0
  151. data/yard-stubs/ca_obj_window.rb +49 -0
  152. data/yard-stubs/carray_access.rb +131 -0
  153. data/yard-stubs/carray_attribute.rb +246 -0
  154. data/yard-stubs/carray_broadcast.rb +37 -0
  155. data/yard-stubs/carray_cast.rb +489 -0
  156. data/yard-stubs/carray_class.rb +65 -0
  157. data/yard-stubs/carray_conversion.rb +76 -0
  158. data/yard-stubs/carray_copy.rb +79 -0
  159. data/yard-stubs/carray_core.rb +114 -0
  160. data/yard-stubs/carray_count.rb +79 -0
  161. data/yard-stubs/carray_element.rb +108 -0
  162. data/yard-stubs/carray_generate.rb +66 -0
  163. data/yard-stubs/carray_lazy.rb +23 -0
  164. data/yard-stubs/carray_loop.rb +140 -0
  165. data/yard-stubs/carray_mask.rb +259 -0
  166. data/yard-stubs/carray_math.rb +132 -0
  167. data/yard-stubs/carray_mathfunc.rb +45 -0
  168. data/yard-stubs/carray_median_percentile.rb +89 -0
  169. data/yard-stubs/carray_memory_view.rb +163 -0
  170. data/yard-stubs/carray_order.rb +312 -0
  171. data/yard-stubs/carray_random.rb +89 -0
  172. data/yard-stubs/carray_scatter.rb +106 -0
  173. data/yard-stubs/carray_slab.rb +57 -0
  174. data/yard-stubs/carray_sort.rb +163 -0
  175. data/yard-stubs/carray_test.rb +85 -0
  176. data/yard-stubs/carray_undef.rb +64 -0
  177. data/yard-stubs/carray_utils.rb +97 -0
  178. data/yard-stubs/ruby_carray.rb +193 -0
  179. metadata +59 -10
  180. data/ext/ca_obj_unbound_repeat.c +0 -496
@@ -16,6 +16,18 @@
16
16
  #ifndef CARRAY_CALL_CFUNC_H
17
17
  #define CARRAY_CALL_CFUNC_H
18
18
 
19
+ /* Chunk callback for the ca_call_cslab_N family. `base` and `stride` are
20
+ one entry per operand, in the order the operands were passed; `n` is the
21
+ number of cells in this chunk; `m0` is the chunk's slice of the mask,
22
+ one byte per cell, or NULL when no INPUT carried a mask. The arity does
23
+ not appear in the signature -- the operands arrive through `base` -- so
24
+ one typedef serves every arity. */
25
+ typedef void (*ca_cslab_t) (char **base, ca_size_t *stride, ca_size_t n,
26
+ const boolean8_t *m0);
27
+
28
+ typedef void (*ca_cslab_r_t) (char **base, ca_size_t *stride, ca_size_t n,
29
+ const boolean8_t *m0, void *userdata);
30
+
19
31
  VALUE
20
32
  ca_call_cfunc_1 (void (*func)(void *p0), const char *fsync,
21
33
  VALUE rcx0);
@@ -157,4 +169,145 @@ ca_call_cfunc_3_2_r (int8_t dty1, int8_t dty2, int8_t dty3, int8_t dtx1, int8_t
157
169
  VALUE
158
170
  ca_call_cfunc_3_3_r (int8_t dty1, int8_t dty2, int8_t dty3, int8_t dtx1, int8_t dtx2, int8_t dtx3, void (*mathfunc)(void*, void*, void*, void*, void*, void*, void *userdata), volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3, void *userdata);
159
171
 
172
+ VALUE
173
+ ca_call_cslab_1 (ca_cslab_t func, const char *fsync,
174
+ VALUE rcx0);
175
+
176
+ VALUE
177
+ ca_call_cslab_2 (ca_cslab_t func, const char *fsync,
178
+ VALUE rcx0, VALUE rcx1);
179
+
180
+ VALUE
181
+ ca_call_cslab_3 (ca_cslab_t func, const char *fsync,
182
+ VALUE rcx0, VALUE rcx1, VALUE rcx2);
183
+
184
+ VALUE
185
+ ca_call_cslab_4 (ca_cslab_t func, const char *fsync,
186
+ VALUE rcx0, VALUE rcx1, VALUE rcx2, VALUE rcx3);
187
+
188
+ VALUE
189
+ ca_call_cslab_5 (ca_cslab_t func, const char *fsync,
190
+ VALUE rcx0, VALUE rcx1, VALUE rcx2, VALUE rcx3, VALUE rcx4);
191
+
192
+ VALUE
193
+ ca_call_cslab_6 (ca_cslab_t func, const char *fsync,
194
+ VALUE rcx0, VALUE rcx1, VALUE rcx2, VALUE rcx3, VALUE rcx4, VALUE rcx5);
195
+
196
+ VALUE
197
+ ca_call_cslab_7 (ca_cslab_t func, const char *fsync,
198
+ VALUE rcx0, VALUE rcx1, VALUE rcx2, VALUE rcx3, VALUE rcx4, VALUE rcx5, VALUE rcx6);
199
+
200
+ VALUE
201
+ ca_call_cslab_1_r (ca_cslab_r_t func, const char *fsync,
202
+ VALUE rcx0,
203
+ void *userdata);
204
+
205
+ VALUE
206
+ ca_call_cslab_2_r (ca_cslab_r_t func, const char *fsync,
207
+ VALUE rcx0, VALUE rcx1,
208
+ void *userdata);
209
+
210
+ VALUE
211
+ ca_call_cslab_3_r (ca_cslab_r_t func, const char *fsync,
212
+ VALUE rcx0, VALUE rcx1, VALUE rcx2,
213
+ void *userdata);
214
+
215
+ VALUE
216
+ ca_call_cslab_4_r (ca_cslab_r_t func, const char *fsync,
217
+ VALUE rcx0, VALUE rcx1, VALUE rcx2, VALUE rcx3,
218
+ void *userdata);
219
+
220
+ VALUE
221
+ ca_call_cslab_5_r (ca_cslab_r_t func, const char *fsync,
222
+ VALUE rcx0, VALUE rcx1, VALUE rcx2, VALUE rcx3, VALUE rcx4,
223
+ void *userdata);
224
+
225
+ VALUE
226
+ ca_call_cslab_6_r (ca_cslab_r_t func, const char *fsync,
227
+ VALUE rcx0, VALUE rcx1, VALUE rcx2, VALUE rcx3, VALUE rcx4, VALUE rcx5,
228
+ void *userdata);
229
+
230
+ VALUE
231
+ ca_call_cslab_7_r (ca_cslab_r_t func, const char *fsync,
232
+ VALUE rcx0, VALUE rcx1, VALUE rcx2, VALUE rcx3, VALUE rcx4, VALUE rcx5, VALUE rcx6,
233
+ void *userdata);
234
+
235
+ VALUE
236
+ ca_call_cslab_1_1 (int8_t dty, int8_t dtx1, ca_cslab_t slabfunc, volatile VALUE rx1);
237
+
238
+ VALUE
239
+ ca_call_cslab_1_2 (int8_t dty, int8_t dtx1, int8_t dtx2, ca_cslab_t slabfunc, volatile VALUE rx1, volatile VALUE rx2);
240
+
241
+ VALUE
242
+ ca_call_cslab_1_3 (int8_t dty, int8_t dtx1, int8_t dtx2, int8_t dtx3, ca_cslab_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3);
243
+
244
+ VALUE
245
+ ca_call_cslab_1_4 (int8_t dty, int8_t dtx1, int8_t dtx2, int8_t dtx3, int8_t dtx4, ca_cslab_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3, volatile VALUE rx4);
246
+
247
+ VALUE
248
+ ca_call_cslab_1_5 (int8_t dty, int8_t dtx1, int8_t dtx2, int8_t dtx3, int8_t dtx4, int8_t dtx5, ca_cslab_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3, volatile VALUE rx4, volatile VALUE rx5);
249
+
250
+ VALUE
251
+ ca_call_cslab_1_6 (int8_t dty, int8_t dtx1, int8_t dtx2, int8_t dtx3, int8_t dtx4, int8_t dtx5, int8_t dtx6, ca_cslab_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3, volatile VALUE rx4, volatile VALUE rx5, volatile VALUE rx6);
252
+
253
+ VALUE
254
+ ca_call_cslab_2_1 (int8_t dty1, int8_t dty2, int8_t dtx1, ca_cslab_t slabfunc, volatile VALUE rx1);
255
+
256
+ VALUE
257
+ ca_call_cslab_2_2 (int8_t dty1, int8_t dty2, int8_t dtx1, int8_t dtx2, ca_cslab_t slabfunc, volatile VALUE rx1, volatile VALUE rx2);
258
+
259
+ VALUE
260
+ ca_call_cslab_2_3 (int8_t dty1, int8_t dty2, int8_t dtx1, int8_t dtx2, int8_t dtx3, ca_cslab_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3);
261
+
262
+ VALUE
263
+ ca_call_cslab_2_4 (int8_t dty1, int8_t dty2, int8_t dtx1, int8_t dtx2, int8_t dtx3, int8_t dtx4, ca_cslab_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3, volatile VALUE rx4);
264
+
265
+ VALUE
266
+ ca_call_cslab_3_1 (int8_t dty1, int8_t dty2, int8_t dty3, int8_t dtx1, ca_cslab_t slabfunc, volatile VALUE rx1);
267
+
268
+ VALUE
269
+ ca_call_cslab_3_2 (int8_t dty1, int8_t dty2, int8_t dty3, int8_t dtx1, int8_t dtx2, ca_cslab_t slabfunc, volatile VALUE rx1, volatile VALUE rx2);
270
+
271
+ VALUE
272
+ ca_call_cslab_3_3 (int8_t dty1, int8_t dty2, int8_t dty3, int8_t dtx1, int8_t dtx2, int8_t dtx3, ca_cslab_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3);
273
+
274
+ VALUE
275
+ ca_call_cslab_1_1_r (int8_t dty, int8_t dtx1, ca_cslab_r_t slabfunc, volatile VALUE rx1, void *userdata);
276
+
277
+ VALUE
278
+ ca_call_cslab_1_2_r (int8_t dty, int8_t dtx1, int8_t dtx2, ca_cslab_r_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, void *userdata);
279
+
280
+ VALUE
281
+ ca_call_cslab_1_3_r (int8_t dty, int8_t dtx1, int8_t dtx2, int8_t dtx3, ca_cslab_r_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3, void *userdata);
282
+
283
+ VALUE
284
+ ca_call_cslab_1_4_r (int8_t dty, int8_t dtx1, int8_t dtx2, int8_t dtx3, int8_t dtx4, ca_cslab_r_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3, volatile VALUE rx4, void *userdata);
285
+
286
+ VALUE
287
+ ca_call_cslab_1_5_r (int8_t dty, int8_t dtx1, int8_t dtx2, int8_t dtx3, int8_t dtx4, int8_t dtx5, ca_cslab_r_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3, volatile VALUE rx4, volatile VALUE rx5, void *userdata);
288
+
289
+ VALUE
290
+ ca_call_cslab_1_6_r (int8_t dty, int8_t dtx1, int8_t dtx2, int8_t dtx3, int8_t dtx4, int8_t dtx5, int8_t dtx6, ca_cslab_r_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3, volatile VALUE rx4, volatile VALUE rx5, volatile VALUE rx6, void *userdata);
291
+
292
+ VALUE
293
+ ca_call_cslab_2_1_r (int8_t dty1, int8_t dty2, int8_t dtx1, ca_cslab_r_t slabfunc, volatile VALUE rx1, void *userdata);
294
+
295
+ VALUE
296
+ ca_call_cslab_2_2_r (int8_t dty1, int8_t dty2, int8_t dtx1, int8_t dtx2, ca_cslab_r_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, void *userdata);
297
+
298
+ VALUE
299
+ ca_call_cslab_2_3_r (int8_t dty1, int8_t dty2, int8_t dtx1, int8_t dtx2, int8_t dtx3, ca_cslab_r_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3, void *userdata);
300
+
301
+ VALUE
302
+ ca_call_cslab_2_4_r (int8_t dty1, int8_t dty2, int8_t dtx1, int8_t dtx2, int8_t dtx3, int8_t dtx4, ca_cslab_r_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3, volatile VALUE rx4, void *userdata);
303
+
304
+ VALUE
305
+ ca_call_cslab_3_1_r (int8_t dty1, int8_t dty2, int8_t dty3, int8_t dtx1, ca_cslab_r_t slabfunc, volatile VALUE rx1, void *userdata);
306
+
307
+ VALUE
308
+ ca_call_cslab_3_2_r (int8_t dty1, int8_t dty2, int8_t dty3, int8_t dtx1, int8_t dtx2, ca_cslab_r_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, void *userdata);
309
+
310
+ VALUE
311
+ ca_call_cslab_3_3_r (int8_t dty1, int8_t dty2, int8_t dty3, int8_t dtx1, int8_t dtx2, int8_t dtx3, ca_cslab_r_t slabfunc, volatile VALUE rx1, volatile VALUE rx2, volatile VALUE rx3, void *userdata);
312
+
160
313
  #endif /* CARRAY_CALL_CFUNC_H */
data/ext/carray_cast.c CHANGED
@@ -2,9 +2,11 @@
2
2
 
3
3
  Cast surface (3 layers):
4
4
 
5
- to_<type> `a.to_int32` etc. Returns a fresh entity CArray
6
- of the target data_type. Independent storage from
7
- `self`.
5
+ <type> `a.int32` etc., and the general `a.to_type(:int32)`.
6
+ Returns a fresh entity CArray of the target
7
+ data_type. Independent storage from `self`. (The
8
+ C functions are named rb_ca_to_<type>, but the
9
+ methods they register carry no `to_` prefix.)
8
10
 
9
11
  as_<type> `a.as_int32` etc. Returns a writable CAMonOp view
10
12
  that reinterprets `self` cell-by-cell at the target
@@ -773,16 +775,62 @@ extern VALUE rb_ca_monop_build (VALUE cary, uint16_t op_id);
773
775
  /* Forward declaration: clip kernel (ext/carray_kernels.c, generated). */
774
776
  extern VALUE rb_ca_clip (VALUE self, VALUE lo, VALUE hi);
775
777
 
778
+ /* Which surface asked for a type-adapt view. A Face's cells do not mean
779
+ their storage bytes and there is no view that decodes them, so each
780
+ caller says what it does instead of reinterpreting the storage. */
781
+ enum {
782
+ CA_ADAPT_VIEW, /* as_type: the values are behind #to_type */
783
+ CA_ADAPT_READONLY, /* wrap_readonly: the eager conversion is the answer */
784
+ CA_ADAPT_WRITABLE /* wrap_writable: writes have nowhere to land */
785
+ };
786
+
776
787
  /* Routes a type-adapt view request to CAMonOp(cast_<dt>) when the
777
788
  target is a plain numeric data_type (NOT CA_FIXLEN, NOT CA_OBJECT,
778
789
  and `rtype` is not a Class). Falls back to CAFake
779
790
  (`rb_ca_fake_type`) for CA_FIXLEN sizing, CA_OBJECT, and class-rtype
780
791
  data_class overlay cases.
781
792
  Called by rb_ca_as_type_internal, rb_ca_wrap_readonly, and
782
- rb_ca_wrap_writable in this file. */
793
+ rb_ca_wrap_writable in this file.
794
+
795
+ A Face whose surface is not its storage reaches neither: reinterpreting
796
+ the storage would hand back the bytes the surface exists to hide (the
797
+ serial instead of the time, the descriptor instead of the string).
798
+ wrap_readonly, which already returns entities for its non-CArray inputs,
799
+ answers with the eager conversion #to_type performs -- the surface values,
800
+ or the Face's own #to_numeric for a numeric target. as_type and
801
+ wrap_writable have no honest answer and say so. */
783
802
  static VALUE
784
- ca_type_adapt_view (VALUE obj, VALUE rtype, int8_t data_type)
803
+ ca_type_adapt_view (VALUE obj, VALUE rtype, int8_t data_type, int mode)
785
804
  {
805
+ CArray *ca;
806
+
807
+ TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
808
+
809
+ /* Same split the eager cast makes: :object is the Face's surface for every
810
+ Face, and a NonNumeric Face (CA_FIXLEN surface) has no reading of its
811
+ storage as a number either. A Numeric Face falls through, because there
812
+ its surface *is* its storage and the ordinary cast below is right. */
813
+ if ( ca_is_face(ca) && ( data_type == CA_OBJECT
814
+ || ca->data_type == CA_FIXLEN ) ) {
815
+ VALUE args[1];
816
+ switch ( mode ) {
817
+ case CA_ADAPT_READONLY:
818
+ args[0] = rtype;
819
+ return rb_ca_to_type_internal(1, args, obj);
820
+ case CA_ADAPT_WRITABLE:
821
+ rb_raise(rb_eTypeError,
822
+ "%s has no writable view in another data_type: the writes "
823
+ "would land on the storage its surface hides -- wrap "
824
+ "#parent to reach that storage",
825
+ rb_obj_classname(obj));
826
+ default:
827
+ rb_raise(rb_eTypeError,
828
+ "%s has no view of its values in another data_type: "
829
+ "#to_type gives the values, #parent the raw storage",
830
+ rb_obj_classname(obj));
831
+ }
832
+ }
833
+
786
834
  if ( data_type != CA_FIXLEN
787
835
  && data_type != CA_OBJECT
788
836
  && TYPE(rtype) != T_CLASS ) {
@@ -815,7 +863,7 @@ rb_ca_as_type_internal (int argc, VALUE *argv, VALUE self)
815
863
  /* Natural-width cast: dispatch via helper (CAMonOp for numeric,
816
864
  CAFake for CA_FIXLEN sizing / CA_OBJECT / class-rtype). */
817
865
  if ( bytes == (ca_size_t) ca_sizeof[data_type] ) {
818
- obj = ca_type_adapt_view(self, rtype, data_type);
866
+ obj = ca_type_adapt_view(self, rtype, data_type, CA_ADAPT_VIEW);
819
867
  return obj;
820
868
  }
821
869
 
@@ -1075,7 +1123,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
1075
1123
  data_type = rb_ca_guess_type(rtype);
1076
1124
  }
1077
1125
  if ( ca->data_type != data_type ) {
1078
- obj = ca_type_adapt_view(obj, rtype, data_type);
1126
+ obj = ca_type_adapt_view(obj, rtype, data_type, CA_ADAPT_WRITABLE);
1079
1127
  }
1080
1128
  }
1081
1129
  else if ( NIL_P(obj) ) { /* obj == nil */
@@ -1113,7 +1161,8 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
1113
1161
  data_type = rb_ca_guess_type(rtype);
1114
1162
  }
1115
1163
  if ( ca->data_type != data_type ) {
1116
- obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type);
1164
+ obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type,
1165
+ CA_ADAPT_WRITABLE);
1117
1166
  }
1118
1167
  }
1119
1168
  else if ( rb_memory_view_available_p(obj) ) { /* MemoryView producer */
@@ -1130,7 +1179,8 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
1130
1179
  data_type = rb_ca_guess_type(rtype);
1131
1180
  }
1132
1181
  if ( ca->data_type != data_type ) {
1133
- obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type);
1182
+ obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type,
1183
+ CA_ADAPT_WRITABLE);
1134
1184
  }
1135
1185
  }
1136
1186
  else {
@@ -1171,7 +1221,7 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
1171
1221
  data_type = rb_ca_guess_type(rtype);
1172
1222
  }
1173
1223
  if ( ca->data_type != data_type ) {
1174
- obj = ca_type_adapt_view(obj, rtype, data_type);
1224
+ obj = ca_type_adapt_view(obj, rtype, data_type, CA_ADAPT_READONLY);
1175
1225
  }
1176
1226
  }
1177
1227
  else if ( rb_obj_is_kind_of(obj, rb_cNumeric) ) { /* number */
@@ -1193,7 +1243,8 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
1193
1243
  data_type = rb_ca_guess_type(rtype);
1194
1244
  }
1195
1245
  if ( ca->data_type != data_type ) {
1196
- obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type);
1246
+ obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type,
1247
+ CA_ADAPT_READONLY);
1197
1248
  }
1198
1249
  }
1199
1250
  else if ( TYPE(obj) == T_STRING ) { /* string */
@@ -1234,7 +1285,8 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
1234
1285
  data_type = rb_ca_guess_type(rtype);
1235
1286
  }
1236
1287
  if ( ca->data_type != data_type ) {
1237
- obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type);
1288
+ obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type,
1289
+ CA_ADAPT_READONLY);
1238
1290
  }
1239
1291
  }
1240
1292
  else if ( rb_memory_view_available_p(obj) ) { /* MemoryView producer */
@@ -1247,7 +1299,8 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
1247
1299
  data_type = rb_ca_guess_type(rtype);
1248
1300
  }
1249
1301
  if ( ca->data_type != data_type ) {
1250
- obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type);
1302
+ obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type,
1303
+ CA_ADAPT_READONLY);
1251
1304
  }
1252
1305
  }
1253
1306
  else { /* object */
@@ -1400,16 +1453,6 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
1400
1453
  TypedData_Get_Struct(*self, CArray, &carray_data_type, ca);
1401
1454
  TypedData_Get_Struct(*other, CArray, &carray_data_type, cb);
1402
1455
 
1403
- if ( ca->obj_type == CA_OBJ_UNBOUND_REPEAT ) {
1404
- *self = ca_ubrep_bind_with(*self, *other);
1405
- TypedData_Get_Struct(*self, CArray, &carray_data_type, ca);
1406
- }
1407
-
1408
- if ( cb->obj_type == CA_OBJ_UNBOUND_REPEAT ) {
1409
- *other = ca_ubrep_bind_with(*other, *self);
1410
- TypedData_Get_Struct(*other, CArray, &carray_data_type, cb);
1411
- }
1412
-
1413
1456
  /* Implicit size-1 broadcasting (case A only). No-op if either side
1414
1457
  is scalar, ndim differs, or shapes are already equal. If shapes
1415
1458
  are incompatible (neither side is 1 nor equal on some axis), also
@@ -1806,11 +1849,6 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
1806
1849
 
1807
1850
  TypedData_Get_Struct(*other, CArray, &carray_data_type, cb);
1808
1851
 
1809
- if ( cb->obj_type == CA_OBJ_UNBOUND_REPEAT ) {
1810
- *other = ca_ubrep_bind_with(*other, *self);
1811
- TypedData_Get_Struct(*other, CArray, &carray_data_type, cb);
1812
- }
1813
-
1814
1852
  test1 = ca_cast_table[cb->data_type][ca->data_type];
1815
1853
 
1816
1854
  if ( test1 == 0 ) {
@@ -1845,8 +1883,8 @@ rb_ca_cast_with (VALUE self, VALUE other)
1845
1883
  }
1846
1884
 
1847
1885
  /* -----------------------------------------------------------------------
1848
- clip_<dtype> family — clip into the target dtype's representable
1849
- range, then cast. Sugar for `clip(lo, hi).as_<dtype>`.
1886
+ clip_<type> family — clip into the target data type's representable
1887
+ range, then cast. Sugar for `clip(lo, hi).as_<type>`.
1850
1888
  ----------------------------------------------------------------------- */
1851
1889
 
1852
1890
  #define CLIP_CAST_FUNC(name, lo_expr, hi_expr, cast_func) \
@@ -1873,7 +1911,7 @@ CLIP_CAST_FUNC(clip_uint32, INT2NUM(0), UINT2NUM(429496729
1873
1911
  an overflowing float source (e.g. 1e20) to 2^64 and the subsequent cast to
1874
1912
  uint64 wraps around to 0. For floating-point sources we take a saturating
1875
1913
  path: compare in float space against 2^64 (which IS representable) and
1876
- saturate to UINT64_MAX above it and 0 below zero. Other source dtypes use
1914
+ saturate to UINT64_MAX above it and 0 below zero. Other source data types use
1877
1915
  the plain clip-then-cast path. */
1878
1916
  static VALUE
1879
1917
  rb_ca_clip_uint64 (VALUE self)
@@ -7,7 +7,7 @@
7
7
  Siblings:
8
8
  carray_copy.c — CArray-to-CArray copy / template family
9
9
  carray_element.c — element-level fetch/store (rb_ca_ptr2obj / obj2ptr)
10
- carray_cast_func.c — dtype cast table used by rb_ca_ptr2obj
10
+ carray_cast_func.c — data type cast table used by rb_ca_ptr2obj
11
11
 
12
12
  ---------------------------------------------------------------------------- */
13
13
 
@@ -16,15 +16,15 @@
16
16
  #include "ruby/io.h"
17
17
 
18
18
  /* to_a dispatch:
19
- numeric / boolean dtype + entity or attach-able view -> fast path
20
- (dtype-direct leaf loop over the attached contig buffer)
19
+ numeric / boolean data type + entity or attach-able view -> fast path
20
+ (data type-direct leaf loop over the attached contig buffer)
21
21
  CA_OBJECT / CA_FIXLEN -> universal
22
22
  (rb_ca_fetch_index per cell; ptr is VALUE or byte string, not
23
23
  directly castable through the leaf switch)
24
24
 
25
25
  Masked cells materialise as CA_UNDEF on both paths. */
26
26
 
27
- /* Leaf macro: dtype-specialized inner loop. Produces `n` VALUE objects
27
+ /* Leaf macro: data type-specialized inner loop. Produces `n` VALUE objects
28
28
  from a contig ptr base + element width, storing into `dst` (Ruby Array). */
29
29
  #define TO_A_LEAF_LOOP(T, TO_VALUE) do { \
30
30
  const T *src = (const T *) base; \
@@ -42,7 +42,7 @@
42
42
 
43
43
  #define TO_A_DISPATCH_LEAF(LOOP) do { \
44
44
  ca_size_t li; \
45
- switch ( dtype ) { \
45
+ switch ( data_type ) { \
46
46
  case CA_FLOAT64: LOOP(double, rb_float_new); break; \
47
47
  case CA_FLOAT32: LOOP(float, rb_float_new); break; \
48
48
  case CA_INT64: LOOP(int64_t, LL2NUM); break; \
@@ -67,13 +67,13 @@
67
67
  } \
68
68
  break; \
69
69
  default: \
70
- rb_bug("to_a fast path: unexpected dtype %d", dtype); \
70
+ rb_bug("to_a fast path: unexpected data type %d", data_type); \
71
71
  } \
72
72
  } while (0)
73
73
 
74
74
  #define TO_A_DISPATCH_LEAF_MASKED(LOOP) do { \
75
75
  ca_size_t li; \
76
- switch ( dtype ) { \
76
+ switch ( data_type ) { \
77
77
  case CA_FLOAT64: LOOP(double, rb_float_new); break; \
78
78
  case CA_FLOAT32: LOOP(float, rb_float_new); break; \
79
79
  case CA_INT64: LOOP(int64_t, LL2NUM); break; \
@@ -95,7 +95,7 @@
95
95
  } \
96
96
  break; \
97
97
  default: \
98
- rb_bug("to_a fast path masked: unexpected dtype %d", dtype); \
98
+ rb_bug("to_a fast path masked: unexpected data type %d", data_type); \
99
99
  } \
100
100
  } while (0)
101
101
 
@@ -105,7 +105,7 @@
105
105
  static void
106
106
  to_a_fast_recurse (CArray *ca, int32_t level, const char *base,
107
107
  const boolean8_t *mask_base, VALUE dst,
108
- int dtype, ca_size_t bytes, int has_mask)
108
+ int data_type, ca_size_t bytes, int has_mask)
109
109
  {
110
110
  ca_size_t i, n, slab_elements, slab_bytes;
111
111
 
@@ -135,7 +135,7 @@ to_a_fast_recurse (CArray *ca, int32_t level, const char *base,
135
135
  to_a_fast_recurse(ca, level + 1,
136
136
  base + i * slab_bytes,
137
137
  has_mask ? mask_base + i * slab_elements : NULL,
138
- child, dtype, bytes, has_mask);
138
+ child, data_type, bytes, has_mask);
139
139
  }
140
140
  }
141
141
 
@@ -172,8 +172,8 @@ rb_ca_to_a_loop_universal (VALUE self, int32_t level, ca_size_t *idx, VALUE ary)
172
172
  * ndim-1 nesting: shape [2, 3] -> 2-element Array of 3-element Arrays.
173
173
  * Masked cells become CA_UNDEF; the mask itself is not preserved on the
174
174
  * result. ca_attach(self) supplies a contig row-major buffer for the
175
- * fast path, so all view kinds land in the dtype-direct leaf loop when
176
- * the dtype is numeric or boolean; CA_OBJECT / CA_FIXLEN fall through
175
+ * fast path, so all view kinds land in the data type-direct leaf loop when
176
+ * the data type is numeric or boolean; CA_OBJECT / CA_FIXLEN fall through
177
177
  * to the universal fetch_index walk. */
178
178
  VALUE
179
179
  rb_ca_to_a (VALUE self)
@@ -181,7 +181,7 @@ rb_ca_to_a (VALUE self)
181
181
  volatile VALUE ary;
182
182
  CArray *ca;
183
183
  ca_size_t idx[CA_RANK_MAX];
184
- int dtype, fast_eligible;
184
+ int data_type, fast_eligible;
185
185
 
186
186
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
187
187
  ary = rb_ca_is_empty(self) ? rb_ary_new() : rb_ary_new2(ca->dim[0]);
@@ -199,22 +199,22 @@ rb_ca_to_a (VALUE self)
199
199
  numeric-storage Face -- CATimedelta serials instead of CATimedelta
200
200
  Elements -- while ca[i] / each / to_type(:object) all decode. The
201
201
  universal loop goes through rb_ca_fetch_addr, which decodes. */
202
- dtype = ca->data_type;
202
+ data_type = ca->data_type;
203
203
  fast_eligible = (ca->elements > 0)
204
204
  && ( ! ca_is_face(ca) )
205
- && (dtype == CA_FLOAT64 || dtype == CA_FLOAT32
206
- || dtype == CA_INT64 || dtype == CA_INT32
207
- || dtype == CA_INT16 || dtype == CA_INT8
208
- || dtype == CA_UINT64 || dtype == CA_UINT32
209
- || dtype == CA_UINT16 || dtype == CA_UINT8
210
- || dtype == CA_BOOLEAN);
205
+ && (data_type == CA_FLOAT64 || data_type == CA_FLOAT32
206
+ || data_type == CA_INT64 || data_type == CA_INT32
207
+ || data_type == CA_INT16 || data_type == CA_INT8
208
+ || data_type == CA_UINT64 || data_type == CA_UINT32
209
+ || data_type == CA_UINT16 || data_type == CA_UINT8
210
+ || data_type == CA_BOOLEAN);
211
211
 
212
212
  if ( fast_eligible ) {
213
213
  int has_mask = (ca->mask != NULL);
214
214
  const boolean8_t *mask_base = has_mask
215
215
  ? (const boolean8_t *) ca->mask->ptr : NULL;
216
216
  to_a_fast_recurse(ca, 0, ca->ptr, mask_base, ary,
217
- dtype, ca->bytes, has_mask);
217
+ data_type, ca->bytes, has_mask);
218
218
  }
219
219
  else if ( ca->elements > 0 ) {
220
220
  rb_ca_to_a_loop_universal(self, 0, idx, ary);
@@ -229,7 +229,7 @@ rb_ca_to_a (VALUE self)
229
229
  #undef TO_A_DISPATCH_LEAF_MASKED
230
230
 
231
231
  /* CArray#convert(data_type=nil, bytes: nil) { |elem| ... } — map every cell
232
- * through the block, into a new array whose dtype is chosen by argv via
232
+ * through the block, into a new array whose data type is chosen by argv via
233
233
  * CArray#template (shape is inherited from self).
234
234
  *
235
235
  * Masked cells skip the block; if the block returns CA_UNDEF, the
data/ext/carray_copy.c CHANGED
@@ -10,6 +10,7 @@
10
10
 
11
11
  #include "carray.h"
12
12
  #include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE */
13
+ #include "carray_internal.h" /* ca_gc_hold_push / ca_gc_hold_pop_to */
13
14
  #include <stdarg.h>
14
15
 
15
16
  /* ------------------------------------------------------------------- */
@@ -57,9 +58,18 @@ VALUE
57
58
  rb_ca_copy (VALUE self)
58
59
  {
59
60
  volatile VALUE obj;
60
- CArray *ca;
61
+ CArray *ca, *co;
62
+ int guard = -1;
61
63
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
62
- obj = ca_wrap_struct(ca_copy(ca));
64
+ co = ca_copy(ca);
65
+ /* The copy holds VALUEs that so far exist only in co->ptr, and
66
+ ca_wrap_struct allocates. Keep them reachable until the wrapper
67
+ that owns them exists. */
68
+ if ( ca_is_object_type(co) ) {
69
+ guard = ca_gc_hold_push(co->ptr, co->elements);
70
+ }
71
+ obj = ca_wrap_struct(co);
72
+ ca_gc_hold_pop_to(guard);
63
73
  CA_FACE_LIFT_IF_FACE(obj, self, ca);
64
74
  return obj;
65
75
  }
data/ext/carray_core.c CHANGED
@@ -231,7 +231,6 @@ ca_cast_table2[CA_NTYPE][CA_NTYPE] = {
231
231
  * CASelect
232
232
  * CAObject
233
233
  * CARepeat
234
- * CAUnboundRepeat
235
234
  */
236
235
 
237
236
  void
@@ -243,7 +242,6 @@ ca_init_obj_type (void)
243
242
  extern ca_operation_function_t ca_select_func;
244
243
  extern ca_operation_function_t ca_object_func;
245
244
  extern ca_operation_function_t ca_stride_func;
246
- extern ca_operation_function_t ca_ubrep_func;
247
245
 
248
246
  /* CArray */
249
247
  ca_func[CA_OBJ_ARRAY] = ca_array_func;
@@ -309,12 +307,6 @@ ca_init_obj_type (void)
309
307
  ca_mask_class[CA_OBJ_REPEAT] = rb_cCARepeatMask;
310
308
  ca_mask_typeddata[CA_OBJ_REPEAT] = &castride_mask_data_type;
311
309
 
312
- /* CAUnboundRepeat */
313
- ca_func[CA_OBJ_UNBOUND_REPEAT] = ca_ubrep_func;
314
- ca_class[CA_OBJ_UNBOUND_REPEAT] = rb_cCAUnboundRepeat;
315
- ca_typeddata[CA_OBJ_UNBOUND_REPEAT] = &caunboundrepeat_data_type;
316
- ca_mask_class[CA_OBJ_UNBOUND_REPEAT] = rb_cCAUnboundRepeatMask;
317
- ca_mask_typeddata[CA_OBJ_UNBOUND_REPEAT] = &caunboundrepeat_mask_data_type;
318
310
 
319
311
  ca_obj_num = 9;
320
312
  }
@@ -432,11 +424,22 @@ ca_attach_is_alias (void *ap)
432
424
  {
433
425
  CArray *ca = (CArray *) ap;
434
426
  extern ca_operation_function_t ca_stride_func;
427
+ extern ca_operation_function_t ca_lazy_marker_func;
435
428
  extern int ca_stride_is_contiguous (CAStride *ca);
436
429
  extern int ca_stride_attach_aliases_root (CAStride *ca);
437
430
 
438
431
  if ( ca == NULL ) return 0;
439
432
  if ( ca_is_entity(ca) ) return 1;
433
+
434
+ /* CALazyMarker's attach is literally `ca->ptr = ca->parent->ptr` after
435
+ attaching the parent — it adds no layout of its own — so it aliases
436
+ exactly when its parent does. Without this a marker looks expensive
437
+ to every caller and views built on it fall onto materialising paths,
438
+ even though there is nothing between the marker and real memory. */
439
+ if ( ca_func[ca->obj_type].attach == ca_lazy_marker_func.attach ) {
440
+ return ca_attach_is_alias(((CAView *) ca)->parent);
441
+ }
442
+
440
443
  /* CAStride family share ca_stride_func.attach (= ca_stride_func_attach).
441
444
  The alias-attach fast path is taken iff composed strides are
442
445
  row-major contiguous. ca_stride_is_contiguous checks the leaf
@@ -1399,6 +1402,30 @@ ca_xfer_strided_walk (char *src_base,
1399
1402
  }
1400
1403
  }
1401
1404
 
1405
+ /* See the comment on the prototype in carray.h. */
1406
+ int
1407
+ ca_xfer_stride_request_is_axis_box (void *ap, ca_size_t *starts,
1408
+ ca_size_t *counts, ca_size_t *strides)
1409
+ {
1410
+ CArray *ca = (CArray *) ap;
1411
+ ca_size_t native[CA_RANK_MAX];
1412
+ ca_size_t s = ca->bytes;
1413
+ int8_t ndim = ca->ndim, k;
1414
+
1415
+ for ( k = ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
1416
+
1417
+ for ( k = 0; k < ndim; k++ ) {
1418
+ ca_size_t q;
1419
+ if ( counts[k] <= 1 ) continue; /* moves nothing */
1420
+ if ( strides[k] <= 0 ) return 0; /* zero / negative: not an axis walk */
1421
+ if ( strides[k] % native[k] != 0 ) return 0;
1422
+ q = strides[k] / native[k];
1423
+ if ( q < 1 ) return 0;
1424
+ if ( starts[k] + (counts[k] - 1) * q >= ca->dim[k] ) return 0; /* runs off axis k */
1425
+ }
1426
+ return 1;
1427
+ }
1428
+
1402
1429
  static void
1403
1430
  ca_xfer_stride_dispatch (CArray *ca, ca_size_t *starts, ca_size_t *counts,
1404
1431
  ca_size_t *strides, void *data, int dir)
@@ -1532,10 +1559,12 @@ ca_xfer_all_body (VALUE arg)
1532
1559
  return Qnil;
1533
1560
  }
1534
1561
 
1562
+ /* `arg` carries the hold depth to unwind to, so nested ca_xfer_all calls
1563
+ each drop their own hold rather than the whole stack. */
1535
1564
  static VALUE
1536
1565
  ca_xfer_all_ensure (VALUE arg)
1537
1566
  {
1538
- (void) arg;
1567
+ ca_gc_hold_pop_to(NUM2INT(arg));
1539
1568
  ca_lazy_arena_exit();
1540
1569
  return Qnil;
1541
1570
  }
@@ -1545,6 +1574,7 @@ ca_xfer_all (void *ap, void *data, int dir)
1545
1574
  {
1546
1575
  CArray *ca = (CArray *) ap;
1547
1576
  ca_xfer_all_args_t args;
1577
+ int guard = -1;
1548
1578
  if ( ! ca_func[ca->obj_type].xfer_all ) {
1549
1579
  rb_raise(rb_eRuntimeError,
1550
1580
  "[BUG] xfer_all not defined for object type <%i>",
@@ -1562,8 +1592,25 @@ ca_xfer_all (void *ap, void *data, int dir)
1562
1592
  next entry. */
1563
1593
  ca_lazy_arena_enter();
1564
1594
  args.ca = ca; args.data = data; args.dir = dir;
1595
+
1596
+ /* A CA_OBJECT cell is a VALUE, and this buffer belongs to no Ruby
1597
+ object yet -- it is the destination `copy` will hand out, or a
1598
+ view's own freshly allocated one. The object lane calls rb_funcall
1599
+ per cell, so a collection partway through would free what has been
1600
+ written so far. ca_xfer_all is the whole-view entry, so the window
1601
+ is exactly ca->elements contiguous cells: the one place where the
1602
+ extent is known without trusting a caller's strides. Sub-windows
1603
+ written by nested transfers land inside it. */
1604
+ if ( ca->data_type == CA_OBJECT && dir == CA_XFER_GET ) {
1605
+ if ( data != (void *) ca->ptr ) {
1606
+ VALUE *p = (VALUE *) data;
1607
+ ca_size_t i;
1608
+ for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
1609
+ }
1610
+ guard = ca_gc_hold_push(data, ca->elements);
1611
+ }
1565
1612
  rb_ensure(ca_xfer_all_body, (VALUE) &args,
1566
- ca_xfer_all_ensure, Qnil);
1613
+ ca_xfer_all_ensure, INT2NUM(guard));
1567
1614
  }
1568
1615
 
1569
1616
  /* ------------------------------------------------------------------- */
data/ext/carray_count.c CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  CArray#count dispatcher (= value-comparison family entry point).
4
4
  Hand-routed because the dispatch decision depends on (self.data_type,
5
- v's runtime class), which the per-dtype mkkernel kernels can't see;
5
+ v's runtime class), which the per-type mkkernel kernels can't see;
6
6
  the actual counting is delegated to the kernel-iterator helpers
7
7
  listed below.
8
8