carray 3.0.3 → 3.0.4

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 (212) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +1 -6
  7. data/ext/ca_axis_group.c +27 -27
  8. data/ext/ca_binop_dispatch.c +1 -29
  9. data/ext/ca_binop_dispatch.h +0 -1
  10. data/ext/ca_categorical_iterator.c +205 -134
  11. data/ext/ca_compare.c +7 -18
  12. data/ext/ca_group_iter.c +16 -17
  13. data/ext/ca_kernel_iterator.c +1234 -1994
  14. data/ext/ca_kernel_iterator.h +391 -437
  15. data/ext/ca_monop_dispatch.c +82 -59
  16. data/ext/ca_monop_dispatch.h +1 -0
  17. data/ext/ca_obj_array.c +96 -39
  18. data/ext/ca_obj_bincmp.c +24 -21
  19. data/ext/ca_obj_binop.c +15 -26
  20. data/ext/ca_obj_bitarray.c +3 -2
  21. data/ext/ca_obj_bitfield.c +5 -6
  22. data/ext/ca_obj_block.c +18 -9
  23. data/ext/ca_obj_byte_swap.c +5 -6
  24. data/ext/ca_obj_const_string.c +173 -19
  25. data/ext/ca_obj_face.c +238 -57
  26. data/ext/ca_obj_face.h +19 -0
  27. data/ext/ca_obj_fake.c +15 -29
  28. data/ext/ca_obj_farray.c +6 -3
  29. data/ext/ca_obj_field.c +17 -5
  30. data/ext/ca_obj_fixlen_string.c +2 -3
  31. data/ext/ca_obj_grid.c +406 -132
  32. data/ext/ca_obj_meld.c +172 -34
  33. data/ext/ca_obj_moncmp.c +23 -8
  34. data/ext/ca_obj_monop.c +67 -57
  35. data/ext/ca_obj_object.c +157 -51
  36. data/ext/ca_obj_record.c +12 -7
  37. data/ext/ca_obj_reduce.c +13 -8
  38. data/ext/ca_obj_refer.c +25 -27
  39. data/ext/ca_obj_remap.c +30 -9
  40. data/ext/ca_obj_repeat.c +9 -10
  41. data/ext/ca_obj_roll.c +6 -5
  42. data/ext/ca_obj_select.c +14 -9
  43. data/ext/ca_obj_select_axis.c +15 -47
  44. data/ext/ca_obj_shift.c +11 -1
  45. data/ext/ca_obj_stack.c +179 -34
  46. data/ext/ca_obj_stride.c +162 -115
  47. data/ext/ca_obj_string.c +71 -4
  48. data/ext/ca_obj_tile.c +6 -5
  49. data/ext/ca_obj_time.c +22 -6
  50. data/ext/ca_obj_timedelta.c +22 -6
  51. data/ext/ca_obj_transpose.c +5 -3
  52. data/ext/ca_obj_triop.c +23 -32
  53. data/ext/ca_obj_window.c +190 -26
  54. data/ext/ca_sweep_engine.c +2 -2
  55. data/ext/caframe_csv_reader.c +80 -1
  56. data/ext/carray.h +181 -75
  57. data/ext/carray_access.c +184 -96
  58. data/ext/carray_address_basis.c +343 -87
  59. data/ext/carray_attribute.c +89 -6
  60. data/ext/carray_bincount.c +10 -8
  61. data/ext/carray_broadcast.c +13 -8
  62. data/ext/carray_build_flags.h +3 -0
  63. data/ext/carray_call_cfunc.c +108 -0
  64. data/ext/carray_cast.c +142 -24
  65. data/ext/carray_cast_func.rb +46 -6
  66. data/ext/carray_class.c +4 -3
  67. data/ext/carray_config.h +28 -0
  68. data/ext/carray_conversion.c +16 -7
  69. data/ext/carray_copy.c +51 -14
  70. data/ext/carray_core.c +147 -55
  71. data/ext/carray_count.c +50 -20
  72. data/ext/carray_element.c +76 -33
  73. data/ext/carray_factorize.c +118 -64
  74. data/ext/carray_generate.c +191 -50
  75. data/ext/carray_histogram.c +62 -17
  76. data/ext/carray_hold.c +12 -15
  77. data/ext/carray_index_classifier.c +388 -176
  78. data/ext/carray_internal.h +336 -29
  79. data/ext/carray_kernels_bincmp.c +4453 -0
  80. data/ext/carray_kernels_binop.c +11368 -0
  81. data/ext/carray_kernels_init.c +1734 -0
  82. data/ext/carray_kernels_moncmp.c +2104 -0
  83. data/ext/carray_kernels_monop.c +18369 -0
  84. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  85. data/ext/carray_kernels_reduce_boolean.c +406 -0
  86. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  87. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  88. data/ext/carray_kernels_reduce_variance.c +3849 -0
  89. data/ext/carray_kernels_scan.c +4302 -0
  90. data/ext/carray_kernels_search.c +33829 -0
  91. data/ext/carray_kernels_sort.c +10906 -0
  92. data/ext/carray_kernels_triop.c +1864 -0
  93. data/ext/carray_key_windows.c +216 -0
  94. data/ext/carray_lazy.c +170 -111
  95. data/ext/carray_mask.c +292 -72
  96. data/ext/carray_median_percentile.c +82 -28
  97. data/ext/carray_memory_view.c +669 -561
  98. data/ext/carray_operator.c +124 -47
  99. data/ext/carray_order.c +384 -76
  100. data/ext/carray_partition.c +28 -27
  101. data/ext/carray_random.c +67 -13
  102. data/ext/carray_round.c +273 -0
  103. data/ext/carray_scatter.c +63 -38
  104. data/ext/carray_segment.c +3 -3
  105. data/ext/carray_slab.c +91 -28
  106. data/ext/carray_sort.c +35 -35
  107. data/ext/carray_struct.c +19 -18
  108. data/ext/carray_test.c +26 -5
  109. data/ext/carray_undef.c +4 -0
  110. data/ext/carray_utils.c +246 -45
  111. data/ext/mk_call_cfunc.rb +19 -2
  112. data/ext/mkkernel.rb +198 -240
  113. data/ext/ruby_carray.c +10 -4
  114. data/ext/version.h +4 -4
  115. data/lib/carray/attribute.rb +126 -22
  116. data/lib/carray/autoload_carray.rb +8 -31
  117. data/lib/carray/autoload_method_extension.rb +14 -5
  118. data/lib/carray/axis_group.rb +255 -106
  119. data/lib/carray/basics.rb +78 -10
  120. data/lib/carray/bincount_nd.rb +12 -2
  121. data/lib/carray/block_iterator.rb +126 -23
  122. data/lib/carray/boolean_reduce.rb +17 -17
  123. data/lib/carray/categorical.rb +165 -43
  124. data/lib/carray/categorical_iterator.rb +130 -27
  125. data/lib/carray/complex.rb +5 -5
  126. data/lib/carray/conditional.rb +67 -18
  127. data/lib/carray/const_string.rb +14 -5
  128. data/lib/carray/construct.rb +15 -11
  129. data/lib/carray/data_type_extension.rb +1 -0
  130. data/lib/carray/distance_limit.rb +77 -0
  131. data/lib/carray/fixlen_string.rb +7 -1
  132. data/lib/carray/frame/column_verbs.rb +70 -0
  133. data/lib/carray/frame/convert.rb +69 -0
  134. data/lib/carray/frame/csv_parser.rb +111 -17
  135. data/lib/carray/frame/describe.rb +3 -2
  136. data/lib/carray/frame/frame.rb +246 -21
  137. data/lib/carray/frame/group.rb +510 -95
  138. data/lib/carray/frame/io.rb +115 -28
  139. data/lib/carray/frame/join.rb +312 -51
  140. data/lib/carray/frame/records.rb +83 -7
  141. data/lib/carray/frame/reshape.rb +42 -35
  142. data/lib/carray/frame/sort.rb +7 -19
  143. data/lib/carray/frame/verbs.rb +188 -48
  144. data/lib/carray/frame/windows.rb +117 -0
  145. data/lib/carray/frame.rb +2 -0
  146. data/lib/carray/fuse_source.rb +11 -4
  147. data/lib/carray/fusion.rb +40 -16
  148. data/lib/carray/histogram.rb +6 -1
  149. data/lib/carray/inspect.rb +31 -8
  150. data/lib/carray/iterator.rb +85 -7
  151. data/lib/carray/key_windows.rb +620 -0
  152. data/lib/carray/lazy.rb +182 -183
  153. data/lib/carray/mask_gap_fill.rb +63 -57
  154. data/lib/carray/meld_reduce.rb +12 -14
  155. data/lib/carray/methods/bin.rb +26 -18
  156. data/lib/carray/methods/bincount.rb +16 -0
  157. data/lib/carray/methods/bit_string.rb +1 -1
  158. data/lib/carray/methods/choose.rb +16 -3
  159. data/lib/carray/methods/composition.rb +3 -1
  160. data/lib/carray/methods/gather_nd.rb +14 -5
  161. data/lib/carray/methods/insert_block.rb +2 -2
  162. data/lib/carray/methods/is_between.rb +59 -0
  163. data/lib/carray/methods/is_in.rb +53 -36
  164. data/lib/carray/methods/join.rb +1 -6
  165. data/lib/carray/methods/lag.rb +49 -0
  166. data/lib/carray/methods/locate_addr.rb +47 -51
  167. data/lib/carray/methods/mode.rb +1 -1
  168. data/lib/carray/methods/nunique.rb +11 -6
  169. data/lib/carray/methods/resize.rb +3 -3
  170. data/lib/carray/methods/value_counts.rb +4 -11
  171. data/lib/carray/record_order.rb +3 -3
  172. data/lib/carray/rng.rb +3 -0
  173. data/lib/carray/runtime.rb +53 -8
  174. data/lib/carray/segment_iterator.rb +313 -82
  175. data/lib/carray/serialize.rb +24 -10
  176. data/lib/carray/slab_iterator.rb +50 -0
  177. data/lib/carray/string.rb +105 -5
  178. data/lib/carray/string_operation_extension.rb +8 -1
  179. data/lib/carray/struct.rb +9 -21
  180. data/lib/carray/struct_builder.rb +19 -8
  181. data/lib/carray/time.rb +726 -104
  182. data/lib/carray/window_iterator.rb +122 -16
  183. data/lib/carray.rb +7 -0
  184. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  185. data/yard-stubs/ca_obj_field.rb +4 -0
  186. data/yard-stubs/ca_obj_grid.rb +21 -10
  187. data/yard-stubs/ca_obj_refer.rb +2 -1
  188. data/yard-stubs/ca_obj_roll.rb +2 -2
  189. data/yard-stubs/ca_obj_shift.rb +5 -1
  190. data/yard-stubs/ca_obj_tile.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +8 -3
  192. data/yard-stubs/carray_access.rb +6 -1
  193. data/yard-stubs/carray_attribute.rb +0 -5
  194. data/yard-stubs/carray_cast.rb +10 -0
  195. data/yard-stubs/carray_conversion.rb +2 -1
  196. data/yard-stubs/carray_copy.rb +4 -2
  197. data/yard-stubs/carray_count.rb +4 -4
  198. data/yard-stubs/carray_element.rb +10 -4
  199. data/yard-stubs/carray_generate.rb +21 -1
  200. data/yard-stubs/carray_mask.rb +26 -2
  201. data/yard-stubs/carray_math.rb +27 -1
  202. data/yard-stubs/carray_median_percentile.rb +5 -2
  203. data/yard-stubs/carray_memory_view.rb +40 -23
  204. data/yard-stubs/carray_order.rb +29 -18
  205. data/yard-stubs/carray_random.rb +13 -4
  206. data/yard-stubs/carray_scatter.rb +14 -9
  207. data/yard-stubs/carray_slab.rb +9 -2
  208. data/yard-stubs/carray_sort.rb +6 -5
  209. data/yard-stubs/carray_test.rb +5 -3
  210. metadata +25 -3
  211. data/lib/carray/arrow_tensor.rb +0 -401
  212. data/lib/carray/table.rb +0 -108
data/ext/ca_obj_grid.c CHANGED
@@ -35,9 +35,14 @@ typedef struct {
35
35
  /* INDEX-only. Owned in the non-share case (xfree'd by free_ca_grid),
36
36
  aliased in the share case (parent owns; CA_FLAG_SHARE_INDEX). */
37
37
  ca_size_t *indices;
38
+ /* INDEX-only, NULL when no cell is a hole. holes[i] marks a position
39
+ whose index cell was masked: it selects no parent cell. Its entry in
40
+ indices is 0 and is never range-checked. Owned and aliased as
41
+ indices is. */
42
+ uint8_t *holes;
38
43
  } cag_axis_t;
39
44
 
40
- typedef struct {
45
+ typedef struct _CAGrid {
41
46
  int16_t obj_type;
42
47
  int8_t data_type;
43
48
  int8_t ndim;
@@ -53,6 +58,18 @@ typedef struct {
53
58
  uint8_t nosync;
54
59
  /* -------------*/
55
60
  cag_axis_t *axes; /* [ndim], owned (non-share) or aliased (share) */
61
+ /* A grid with holes (cag_axis_t.holes): set on its mask grid, whose
62
+ holes read as masked. The data grid's holes read the cell at index 0
63
+ of each holed axis, as project and gather_nd do. */
64
+ int8_t holes_read_masked;
65
+ /* A grid with holes over a parent that has no mask: the all-false mask
66
+ its mask grid reads instead, so that showing the holes gives the
67
+ parent no mask. Owned by this grid; NULL otherwise. */
68
+ CArray *mask_standin;
69
+ /* On a mask grid: the grid whose mask it is, which holds the stand-in
70
+ and the parent whose mask replaces it. A Ruby copy of the mask keeps
71
+ that grid alive (rb_ca_mask_array sets masked_array). */
72
+ struct _CAGrid *mask_owner;
56
73
  } CAGrid;
57
74
 
58
75
  static size_t
@@ -70,6 +87,9 @@ ca_grid_dsize (const void *ap)
70
87
  if (ca->axes[k].kind == CAG_AXIS_INDEX && ca->axes[k].indices) {
71
88
  total += ca->axes[k].count * sizeof(ca_size_t);
72
89
  }
90
+ if (ca->axes[k].kind == CAG_AXIS_INDEX && ca->axes[k].holes) {
91
+ total += ca->axes[k].count;
92
+ }
73
93
  }
74
94
  return total;
75
95
  }
@@ -160,13 +180,15 @@ ca_grid_check_protos (CArray *parent, int8_t ndim, const cag_axis_t *protos)
160
180
  if (protos[k].kind == CAG_AXIS_STRIDE) {
161
181
  ca_size_t first = protos[k].start;
162
182
  ca_size_t last = first + (protos[k].count - 1) * protos[k].step;
163
- CA_CHECK_INDEX(first, parent->dim[k]);
164
- if (protos[k].count > 1) CA_CHECK_INDEX(last, parent->dim[k]);
183
+ ca_index_in_range_at(first, parent->dim[k], k);
184
+ if (protos[k].count > 1) ca_index_in_range_at(last, parent->dim[k], k);
165
185
  }
166
186
  else {
167
187
  for (j = 0; j < protos[k].count; j++) {
168
- ca_size_t v = protos[k].indices[j];
169
- CA_CHECK_INDEX(v, parent->dim[k]);
188
+ if ( protos[k].holes && protos[k].holes[j] ) {
189
+ continue;
190
+ }
191
+ ca_index_in_range_at(protos[k].indices[j], parent->dim[k], k);
170
192
  }
171
193
  }
172
194
  }
@@ -207,6 +229,9 @@ ca_grid_setup (CAGrid *ca, CArray *parent, int8_t ndim,
207
229
  ca->parent = parent;
208
230
  ca->attach = 0;
209
231
  ca->nosync = 0;
232
+ ca->holes_read_masked = 0;
233
+ ca->mask_standin = NULL;
234
+ ca->mask_owner = NULL;
210
235
 
211
236
  for (k = 0; k < ndim; k++) ca->dim[k] = protos[k].count;
212
237
 
@@ -225,42 +250,104 @@ ca_grid_setup (CAGrid *ca, CArray *parent, int8_t ndim,
225
250
  ca->axes[k].start = protos[k].start;
226
251
  ca->axes[k].step = protos[k].step;
227
252
  ca->axes[k].indices = NULL;
253
+ ca->axes[k].holes = NULL;
228
254
  } else {
229
255
  ca->axes[k].start = 0;
230
256
  ca->axes[k].step = 0;
231
257
  ca->axes[k].indices = ALLOC_N(ca_size_t,
232
258
  protos[k].count > 0 ? protos[k].count : 1);
259
+ ca->axes[k].holes = NULL;
233
260
  ca_size_t j;
261
+ if ( protos[k].holes ) {
262
+ for (j = 0; j < protos[k].count && ! protos[k].holes[j]; j++) ;
263
+ if ( j < protos[k].count ) {
264
+ ca->axes[k].holes = ALLOC_N(uint8_t, protos[k].count);
265
+ memcpy(ca->axes[k].holes, protos[k].holes, protos[k].count);
266
+ }
267
+ }
234
268
  for (j = 0; j < protos[k].count; j++) {
235
269
  ca_size_t v = protos[k].indices[j];
270
+ if ( ca->axes[k].holes && ca->axes[k].holes[j] ) {
271
+ ca->axes[k].indices[j] = 0;
272
+ continue;
273
+ }
236
274
  ca->axes[k].indices[j] = ( v < 0 ) ? v + parent->dim[k] : v;
237
275
  }
238
276
  }
239
277
  }
240
278
  }
241
279
 
242
- if ( ca_has_mask(parent) ) {
243
- ca_create_mask(ca);
244
- }
280
+ return 0;
281
+ }
245
282
 
283
+ /* Whether any position of the grid is a hole (cag_axis_t.holes). */
284
+ static int
285
+ cag_has_holes (const CAGrid *ca)
286
+ {
287
+ int8_t k;
288
+ for (k = 0; k < ca->ndim; k++) {
289
+ if ( ca->axes[k].kind == CAG_AXIS_INDEX && ca->axes[k].holes ) {
290
+ return 1;
291
+ }
292
+ }
246
293
  return 0;
247
294
  }
248
295
 
249
- CAGrid *
250
- ca_grid_new (CArray *parent, int8_t ndim, cag_axis_t *protos)
296
+ int
297
+ ca_grid_has_holes (void *ap)
298
+ {
299
+ return cag_has_holes((const CAGrid *) ap);
300
+ }
301
+
302
+ /* A grid with holes has a mask from the start: its holes read as masked
303
+ whatever the parent holds. A mask grid (holes_read_masked) takes none.
304
+ A view of a value array or a mask array can never carry a mask, so it
305
+ can not show a hole. */
306
+ static VALUE
307
+ ca_grid_inherit_mask (VALUE view)
308
+ {
309
+ CAGrid *ca = (CAGrid *) view;
310
+ if ( cag_has_holes(ca) && ! ca->holes_read_masked ) {
311
+ if ( ca_is_value_array(ca) || ca_is_mask_array(ca) ) {
312
+ rb_raise(rb_eArgError,
313
+ "a masked index cell reads as masked, which a view of the %s "
314
+ "array can not hold", ca_is_value_array(ca) ? "value" : "mask");
315
+ }
316
+ ca_create_mask((CArray *) ca);
317
+ return Qnil;
318
+ }
319
+ return ca_view_inherit_mask(view);
320
+ }
321
+
322
+ /* holes_read_masked is the copied grid's: a copy of a mask grid is one. */
323
+ static CAGrid *
324
+ ca_grid_new_as (CArray *parent, int8_t ndim, cag_axis_t *protos,
325
+ int8_t holes_read_masked, CAGrid *mask_owner)
251
326
  {
252
327
  CAGrid *ca;
253
328
  ca_grid_check_protos(parent, ndim, protos);
329
+ /* check: ca_grid_check_protos above */
254
330
  ca = (CAGrid *) ca_array_alloc(CA_OBJ_GRID, ndim);
255
331
  ca_grid_setup(ca, parent, ndim, protos, 0);
332
+ ca->holes_read_masked = holes_read_masked;
333
+ ca->mask_owner = mask_owner;
334
+ ca_fill_or_free((CArray *) ca, ca_grid_inherit_mask, (VALUE) ca);
256
335
  return ca;
257
336
  }
258
337
 
338
+ CAGrid *
339
+ ca_grid_new (CArray *parent, int8_t ndim, cag_axis_t *protos)
340
+ {
341
+ return ca_grid_new_as(parent, ndim, protos, 0, NULL);
342
+ }
343
+
259
344
  CAGrid *
260
345
  ca_grid_new_share (CArray *parent, int8_t ndim, cag_axis_t *protos)
261
346
  {
347
+ /* check: the mask grid copies its own grid's checked axes */
262
348
  CAGrid *ca = (CAGrid *) ca_array_alloc(CA_OBJ_GRID, ndim);
263
349
  ca_grid_setup(ca, parent, ndim, protos, 1);
350
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
264
351
  return ca;
265
352
  }
266
353
 
@@ -270,12 +357,16 @@ free_ca_grid (void *ap)
270
357
  CAGrid *ca = (CAGrid *) ap;
271
358
  if ( ca != NULL ) {
272
359
  ca_free(ca->mask);
360
+ ca_free(ca->mask_standin);
273
361
  if ( ! (ca->flags & CA_FLAG_SHARE_INDEX) ) {
274
362
  int8_t k;
275
363
  for (k = 0; k < ca->ndim; k++) {
276
364
  if ( ca->axes[k].kind == CAG_AXIS_INDEX && ca->axes[k].indices ) {
277
365
  xfree(ca->axes[k].indices);
278
366
  }
367
+ if ( ca->axes[k].kind == CAG_AXIS_INDEX && ca->axes[k].holes ) {
368
+ xfree(ca->axes[k].holes);
369
+ }
279
370
  }
280
371
  xfree(ca->axes);
281
372
  }
@@ -301,7 +392,8 @@ static void *
301
392
  ca_grid_func_clone (void *ap)
302
393
  {
303
394
  CAGrid *ca = (CAGrid *) ap;
304
- return ca_grid_new(ca->parent, ca->ndim, ca->axes);
395
+ return ca_grid_new_as(ca->parent, ca->ndim, ca->axes, ca->holes_read_masked,
396
+ ca->mask_owner);
305
397
  }
306
398
 
307
399
  /* Per-axis parent-index lookup. STRIDE = one multiply, INDEX = one
@@ -315,6 +407,124 @@ cag_parent_index_for (const cag_axis_t *ax, ca_size_t i)
315
407
  return ax->indices[i];
316
408
  }
317
409
 
410
+ /* A mask grid over its owner's stand-in (ca_mask_standin_current): what
411
+ it reads from now on. */
412
+ static void
413
+ cag_mask_current (CAGrid *m)
414
+ {
415
+ CAGrid *o = m->mask_owner;
416
+ if ( o != NULL ) {
417
+ m->parent = ca_mask_standin_current((CArray *) m, m->parent, o->parent,
418
+ o->mask_standin);
419
+ }
420
+ }
421
+
422
+ /* After a write of n cells of `data` to a mask grid: a true that went
423
+ into the stand-in goes on to the parent's mask. */
424
+ static void
425
+ cag_mask_settle_after (CAGrid *m, const void *data, ca_size_t n)
426
+ {
427
+ CAGrid *o = m->mask_owner;
428
+ if ( o != NULL && m->parent == o->mask_standin && ca_mask_any_true(data, n) ) {
429
+ ca_mask_standin_settle(o->parent, o->mask_standin);
430
+ }
431
+ }
432
+
433
+ /* What the GET of a hole writes when it reads no parent cell: true in a
434
+ mask grid, an empty cell otherwise (a parent with no cell to read). */
435
+ static void
436
+ cag_hole_cells (const CAGrid *ca, char *data, ca_size_t n)
437
+ {
438
+ ca_size_t i;
439
+ if ( ca->holes_read_masked ) {
440
+ memset(data, 1, (size_t) n);
441
+ }
442
+ else if ( ca->data_type == CA_OBJECT ) {
443
+ for (i = 0; i < n; i++) ((VALUE *) data)[i] = INT2FIX(0);
444
+ }
445
+ else {
446
+ memset(data, 0, (size_t) (n * ca->bytes));
447
+ }
448
+ }
449
+
450
+ /* The parent address of the view cell at idx. A hole takes index 0 on its
451
+ holed axes; the return says whether the cell is one. */
452
+ static int
453
+ cag_parent_addr (const CAGrid *ca, const ca_size_t *idx, ca_size_t *paddr)
454
+ {
455
+ ca_size_t pa = 0;
456
+ int hole = 0;
457
+ int8_t k;
458
+ for (k = 0; k < ca->ndim; k++) {
459
+ const cag_axis_t *ax = &ca->axes[k];
460
+ if ( ax->kind == CAG_AXIS_INDEX && ax->holes && ax->holes[idx[k]] ) {
461
+ hole = 1;
462
+ }
463
+ pa = pa * ca->parent->dim[k] + cag_parent_index_for(ax, idx[k]);
464
+ }
465
+ *paddr = pa;
466
+ return hole;
467
+ }
468
+
469
+ /* The transfer of a grid with holes, for the view cells at addrs (NULL:
470
+ the whole view in order). The parent is asked for one batch of
471
+ addresses. A GET reads every cell, a hole reading the cell at index 0
472
+ of its holed axes (in a mask grid it is then set true); a PUT leaves
473
+ the holes out. */
474
+ static void
475
+ ca_grid_holed_xfer (CAGrid *ca, ca_size_t n, const ca_size_t *addrs,
476
+ char *data, int dir)
477
+ {
478
+ CArray *parent;
479
+ ca_size_t bytes = ca->bytes;
480
+ volatile VALUE h_addr = 0, h_hole = 0, h_data = 0;
481
+ ca_size_t *paddrs;
482
+ uint8_t *hole;
483
+ ca_size_t i, m, idx[CA_RANK_MAX];
484
+
485
+ if ( n <= 0 ) {
486
+ return;
487
+ }
488
+ cag_mask_current(ca);
489
+ parent = ca->parent;
490
+ paddrs = ALLOCV_N(ca_size_t, h_addr, n);
491
+ hole = ALLOCV_N(uint8_t, h_hole, n);
492
+ for (i = 0; i < n; i++) {
493
+ ca_addr2index((CArray *) ca, addrs ? addrs[i] : i, idx);
494
+ hole[i] = (uint8_t) cag_parent_addr(ca, idx, &paddrs[i]);
495
+ }
496
+
497
+ if ( dir == CA_XFER_GET ) {
498
+ if ( parent->elements == 0 ) {
499
+ cag_hole_cells(ca, data, n); /* every cell is a hole */
500
+ }
501
+ else {
502
+ ca_xfer_addrs(parent, n, paddrs, data, CA_XFER_GET);
503
+ if ( ca->holes_read_masked ) {
504
+ for (i = 0; i < n; i++) {
505
+ if ( hole[i] ) cag_hole_cells(ca, data + i * bytes, 1);
506
+ }
507
+ }
508
+ }
509
+ }
510
+ else {
511
+ char *pdata = ALLOCV_N(char, h_data, n * bytes);
512
+ for (i = 0, m = 0; i < n; i++) {
513
+ if ( hole[i] ) continue;
514
+ paddrs[m] = paddrs[i];
515
+ memcpy(pdata + m * bytes, data + i * bytes, (size_t) bytes);
516
+ m++;
517
+ }
518
+ if ( m > 0 ) {
519
+ ca_xfer_addrs(parent, m, paddrs, pdata, CA_XFER_PUT);
520
+ cag_mask_settle_after(ca, pdata, m);
521
+ }
522
+ ALLOCV_END(h_data);
523
+ }
524
+ ALLOCV_END(h_hole);
525
+ ALLOCV_END(h_addr);
526
+ }
527
+
318
528
  /* per-cell logic lives in ca_grid_func_xfer_index; forward-declared for
319
529
  the region-delivery paths below. */
320
530
  static void ca_grid_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir);
@@ -327,10 +537,28 @@ ca_grid_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
327
537
  CAGrid *ca = (CAGrid *) ap;
328
538
  ca_size_t idx0[CA_RANK_MAX];
329
539
  int8_t i;
540
+ int hole = 0;
330
541
  for (i = 0; i < ca->ndim; i++) {
331
- idx0[i] = cag_parent_index_for(&ca->axes[i], idx[i]);
542
+ const cag_axis_t *ax = &ca->axes[i];
543
+ idx0[i] = cag_parent_index_for(ax, idx[i]);
544
+ if ( ax->kind == CAG_AXIS_INDEX && ax->holes && ax->holes[idx[i]] ) {
545
+ hole = 1;
546
+ }
547
+ }
548
+ if ( hole ) {
549
+ if ( dir == CA_XFER_PUT ) {
550
+ return;
551
+ }
552
+ if ( ca->holes_read_masked || ca->parent->elements == 0 ) {
553
+ cag_hole_cells(ca, (char *) data, 1);
554
+ return;
555
+ }
332
556
  }
557
+ cag_mask_current(ca);
333
558
  ca_xfer_index(ca->parent, idx0, data, dir);
559
+ if ( dir == CA_XFER_PUT ) {
560
+ cag_mask_settle_after(ca, data, 1);
561
+ }
334
562
  }
335
563
 
336
564
  /* Batched address gather/scatter. Per-axis index remap
@@ -354,6 +582,11 @@ ca_grid_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
354
582
  int8_t k;
355
583
  volatile VALUE holder;
356
584
 
585
+ if ( cag_has_holes(ca) ) {
586
+ ca_grid_holed_xfer(ca, n, addrs, (char *) data, dir);
587
+ return;
588
+ }
589
+
357
590
  /* Opportunistic fast path. ca_resolve_attached_root_via_identity lifts
358
591
  parent->ptr through an identity CAStride compose-fold (handles a
359
592
  flatten[idx].reshape(*) chain etc.). */
@@ -409,8 +642,9 @@ ca_grid_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
409
642
  int8_t k;
410
643
 
411
644
  for (k = 0; k < g->ndim; k++) {
412
- if (g->axes[k].kind == CAG_AXIS_INDEX && g->axes[k].count != 1) {
413
- return 0; /* multi-INDEX axis -> true gather, decline */
645
+ if (g->axes[k].kind == CAG_AXIS_INDEX
646
+ && (g->axes[k].count != 1 || g->axes[k].holes)) {
647
+ return 0; /* multi-INDEX axis -> true gather, decline; a hole is no stride */
414
648
  }
415
649
  }
416
650
 
@@ -505,8 +739,9 @@ ca_grid_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
505
739
  /* The request is over the view's addresses, so a transposed / flat request
506
740
  is legal and must not be composed axis-by-axis; see
507
741
  ca_xfer_stride_request_is_axis_box (carray.h). */
508
- if ( ! ca_xfer_stride_request_is_axis_box(g, starts, counts, strides) ) {
509
- aligned = 0;
742
+ if ( cag_has_holes(g)
743
+ || ! ca_xfer_stride_request_is_axis_box(g, starts, counts, strides) ) {
744
+ aligned = 0; /* a grid with holes goes cell by cell (xfer_index) */
510
745
  }
511
746
  else {
512
747
  for (k = 0; k < ndim; k++) {
@@ -519,6 +754,7 @@ ca_grid_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
519
754
  ca_size_t idx[CA_RANK_MAX], doff = 0, base = 0;
520
755
  for (k = 0; k < ndim; k++) base += starts[k] * gnative[k];
521
756
  for (k = 0; k < ndim; k++) idx[k] = 0;
757
+ /* empty: the slot returns on an empty region at its entry */
522
758
  while (1) {
523
759
  ca_size_t goff = base, gidx[CA_RANK_MAX];
524
760
  for (k = 0; k < ndim; k++) goff += idx[k] * strides[k];
@@ -607,6 +843,7 @@ ca_grid_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
607
843
  ca_xfer_stride/ca_xfer_addrs. */
608
844
  for (k = 0; k < ndim; k++) o[k] = 0;
609
845
 
846
+ /* empty: the slot returns on an empty region at its entry */
610
847
  while (1) {
611
848
  ca_size_t pbase = 0, doff = 0;
612
849
  for (k = 0; k < inner; k++) {
@@ -659,14 +896,22 @@ ca_grid_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
659
896
  The predicate asks what the parent is, not whether it is attached now,
660
897
  so attach, sync and detach all take the same branch. */
661
898
 
899
+ /* A grid with holes fills and writes back its buffer through its own
900
+ transfers too: the descriptor engine has no hole. */
901
+ static int
902
+ cag_owns_buffer (CAGrid *ca)
903
+ {
904
+ return cag_has_holes(ca) || ca_parent_lends_no_memory(ca->parent);
905
+ }
906
+
662
907
  static void
663
908
  ca_grid_func_allocate (void *ap)
664
909
  {
665
910
  CAGrid *ca = (CAGrid *) ap;
666
- if ( ! ca_parent_lends_no_memory(ca->parent) ) {
911
+ if ( ! cag_owns_buffer(ca) ) {
667
912
  ca_attach(ca->parent);
668
913
  }
669
- ca->ptr = xmalloc(ca_length(ca));
914
+ ca->ptr = ca_alloc_cells((CArray *) ca);
670
915
  }
671
916
 
672
917
  static void
@@ -676,7 +921,7 @@ ca_grid_func_attach (void *ap)
676
921
  ca_axis_desc_t desc[CA_RANK_MAX];
677
922
  ca_size_t pdims[CA_RANK_MAX];
678
923
 
679
- if ( ca_parent_lends_no_memory(ca->parent) ) {
924
+ if ( cag_owns_buffer(ca) ) {
680
925
  ca_axis_view_attach_owned(ca);
681
926
  return;
682
927
  }
@@ -694,7 +939,7 @@ ca_grid_func_sync (void *ap)
694
939
  ca_axis_desc_t desc[CA_RANK_MAX];
695
940
  ca_size_t pdims[CA_RANK_MAX];
696
941
 
697
- if ( ca_parent_lends_no_memory(ca->parent) ) {
942
+ if ( cag_owns_buffer(ca) ) {
698
943
  ca_axis_view_sync_owned(ca);
699
944
  return;
700
945
  }
@@ -711,7 +956,7 @@ ca_grid_func_detach (void *ap)
711
956
  CAGrid *ca = (CAGrid *) ap;
712
957
  xfree(ca->ptr);
713
958
  ca->ptr = NULL;
714
- if ( ! ca_parent_lends_no_memory(ca->parent) ) {
959
+ if ( ! cag_owns_buffer(ca) ) {
715
960
  ca_detach(ca->parent);
716
961
  }
717
962
  }
@@ -736,9 +981,41 @@ ca_grid_func_run_fast_path (void *ap, char *data, int dir)
736
981
  static void
737
982
  ca_grid_func_xfer_all (void *ap, void *data, int dir)
738
983
  {
984
+ CAGrid *ca = (CAGrid *) ap;
985
+ if ( cag_has_holes(ca) ) {
986
+ ca_grid_holed_xfer(ca, ca->elements, NULL, (char *) data, dir);
987
+ return;
988
+ }
739
989
  ca_axis_view_xfer_all(ap, ca_grid_func_run_fast_path, 1, data, dir);
740
990
  }
741
991
 
992
+ /* The fill of a grid with holes: the parent cells of the positions that
993
+ are not holes, as one address batch. */
994
+ static void
995
+ ca_grid_holed_fill (CAGrid *ca, void *ptr)
996
+ {
997
+ volatile VALUE holder = 0;
998
+ ca_size_t *paddrs;
999
+ ca_size_t i, m = 0, pa, idx[CA_RANK_MAX];
1000
+
1001
+ if ( ca->elements <= 0 ) {
1002
+ return;
1003
+ }
1004
+ cag_mask_current(ca);
1005
+ paddrs = ALLOCV_N(ca_size_t, holder, ca->elements);
1006
+ for (i = 0; i < ca->elements; i++) {
1007
+ ca_addr2index((CArray *) ca, i, idx);
1008
+ if ( ! cag_parent_addr(ca, idx, &pa) ) {
1009
+ paddrs[m++] = pa;
1010
+ }
1011
+ }
1012
+ if ( m > 0 ) {
1013
+ ca_fill_addrs(ca->parent, m, paddrs, ptr);
1014
+ cag_mask_settle_after(ca, ptr, 1);
1015
+ }
1016
+ ALLOCV_END(holder);
1017
+ }
1018
+
742
1019
  static void
743
1020
  ca_grid_func_fill_data (void *ap, void *ptr)
744
1021
  {
@@ -746,6 +1023,11 @@ ca_grid_func_fill_data (void *ap, void *ptr)
746
1023
  ca_axis_desc_t desc[CA_RANK_MAX];
747
1024
  ca_size_t pdims[CA_RANK_MAX];
748
1025
 
1026
+ if ( cag_has_holes(ca) ) {
1027
+ ca_grid_holed_fill(ca, ptr);
1028
+ return;
1029
+ }
1030
+
749
1031
  ca_grid_describe_axes(ca, desc, pdims);
750
1032
 
751
1033
  /* Writing the selected cells used to go through a whole-parent attach and
@@ -765,15 +1047,32 @@ ca_grid_func_fill_data (void *ap, void *ptr)
765
1047
  ca_sync_detach(ca->parent);
766
1048
  }
767
1049
 
1050
+ /* The mask is a grid over the parent's mask with the same axes, holes
1051
+ included; there the holes read as masked. */
768
1052
  static void
769
1053
  ca_grid_func_create_mask (void *ap)
770
1054
  {
771
1055
  CAGrid *ca = (CAGrid *) ap;
1056
+ CArray *mparent;
1057
+ int holed = cag_has_holes(ca);
1058
+
1059
+ /* A grid with holes shows them without giving a parent that has no mask
1060
+ one: its mask grid reads an all-false stand-in until a true is written
1061
+ outside the holes (ca_mask_standin_new). */
1062
+ if ( holed && ! ca_has_mask(ca->parent) ) {
1063
+ if ( ! ca->mask_standin ) {
1064
+ ca->mask_standin = ca_mask_standin_new(ca->parent);
1065
+ }
1066
+ mparent = ca->mask_standin;
1067
+ }
1068
+ else {
1069
+ ca_create_mask(ca->parent);
1070
+ mparent = ca->parent->mask;
1071
+ }
772
1072
 
773
- ca_create_mask(ca->parent);
774
-
775
- ca->mask = (CArray *) ca_grid_new_share(ca->parent->mask,
776
- ca->ndim, ca->axes);
1073
+ ca->mask = (CArray *) ca_grid_new_share(mparent, ca->ndim, ca->axes);
1074
+ ((CAGrid *) ca->mask)->holes_read_masked = (int8_t) holed;
1075
+ ((CAGrid *) ca->mask)->mask_owner = holed ? ca : NULL;
777
1076
  }
778
1077
 
779
1078
  ca_operation_function_t ca_grid_func = {
@@ -810,41 +1109,6 @@ rb_ca_grid_new (VALUE cary, int8_t ndim, cag_axis_t *protos)
810
1109
  return obj;
811
1110
  }
812
1111
 
813
- /* Detect a plain Ruby Range (Integer first/last, exclude_end?, step=1
814
- implicit) and convert it to STRIDE (start, count, step=1).
815
- Returns 1 on success (fills *out_start, *out_count), 0 on fallback
816
- (caller should materialise to INDEX). Negative endpoints are
817
- normalised against dim_size like everywhere else in CArray. */
818
- static int
819
- cag_range_to_stride (VALUE range, ca_size_t dim_size,
820
- ca_size_t *out_start, ca_size_t *out_count)
821
- {
822
- VALUE rb_first, rb_last;
823
- ca_size_t first, last, count;
824
- int exclude_end;
825
-
826
- if ( ! rb_obj_is_kind_of(range, rb_cRange) ) return 0;
827
- rb_first = rb_funcall(range, rb_intern("first"), 0);
828
- rb_last = rb_funcall(range, rb_intern("last"), 0);
829
- if ( ! FIXNUM_P(rb_first) || ! FIXNUM_P(rb_last) ) return 0;
830
- exclude_end = RTEST(rb_funcall(range, rb_intern("exclude_end?"), 0));
831
-
832
- first = NUM2SIZE(rb_first);
833
- last = NUM2SIZE(rb_last);
834
- if (first < 0) first += dim_size;
835
- if (last < 0) last += dim_size;
836
- if (exclude_end) last -= 1;
837
-
838
- if (first < 0 || first >= dim_size) return 0;
839
- if (last < first - 1) return 0; /* empty range */
840
- if (last >= dim_size) return 0;
841
- count = last - first + 1;
842
-
843
- *out_start = first;
844
- *out_count = count;
845
- return 1;
846
- }
847
-
848
1112
  /* The INDEX axes of rb_ca_grid, read with their index arrays attached,
849
1113
  and the view built from them. */
850
1114
 
@@ -859,90 +1123,96 @@ static VALUE
859
1123
  ca_grid_build_body (VALUE arg)
860
1124
  {
861
1125
  ca_grid_build_ctx_t *c = (ca_grid_build_ctx_t *) arg;
862
- volatile VALUE holders[CA_RANK_MAX];
863
- volatile VALUE obj;
864
1126
  int8_t i;
865
1127
 
866
1128
  for (i = 0; i < c->ca->ndim; i++) {
867
1129
  CArray *ci = c->ci[i];
868
- holders[i] = Qfalse;
869
1130
  if ( ! ci ) {
870
1131
  continue;
871
1132
  }
872
- c->protos[i].kind = CAG_AXIS_INDEX;
1133
+ c->protos[i].kind = CAG_AXIS_INDEX;
1134
+ c->protos[i].count = ci->elements;
1135
+ c->protos[i].indices = (ca_size_t *) ci->ptr;
1136
+ c->protos[i].holes = NULL;
873
1137
  if ( ca_is_any_masked(ci) ) {
874
- /* mask-filtered snapshot: skip masked cells. setup copies the
875
- indices into its own buffer, so the snapshot only has to live
876
- until ca_grid_new returns. */
877
- ca_size_t gsize = ci->elements - ca_count_masked(ci);
878
- ca_size_t *src = (ca_size_t *) ci->ptr;
879
- boolean8_t *m = (boolean8_t *) ci->mask->ptr;
880
- ca_size_t *tmp = ALLOCV_N(ca_size_t, holders[i], gsize > 0 ? gsize : 1);
881
- ca_size_t j, n = 0;
882
- for (j = 0; j < ci->elements; j++) {
883
- if ( ! m[j] ) tmp[n++] = src[j];
884
- }
885
- c->protos[i].count = gsize;
886
- c->protos[i].indices = tmp;
887
- } else {
888
- c->protos[i].count = ci->elements;
889
- c->protos[i].indices = (ca_size_t *) ci->ptr;
1138
+ /* A masked index cell selects nothing: its position stays, as a hole
1139
+ (masked on read, skipped on write). setup copies the mask into
1140
+ its own buffer. */
1141
+ c->protos[i].holes = (uint8_t *) ci->mask->ptr;
890
1142
  }
891
1143
  c->protos[i].start = 0;
892
1144
  c->protos[i].step = 0;
893
1145
  }
894
1146
 
895
- obj = rb_ca_grid_new(c->self, c->ca->ndim, c->protos);
1147
+ return rb_ca_grid_new(c->self, c->ca->ndim, c->protos);
1148
+ }
896
1149
 
897
- for (i = 0; i < c->ca->ndim; i++) {
898
- if ( c->ci[i] && holders[i] != Qfalse ) {
899
- ALLOCV_END(holders[i]);
1150
+ /* A scalar key (an Integer or a Float) picks one cell along its axis, and that axis is
1151
+ not in the result -- as it is not in a block reference. The view is
1152
+ built with the axis at length 1 and the axis then dropped. */
1153
+ static VALUE
1154
+ ca_grid_drop_scalar_axes (VALUE obj, int argc, VALUE *argv)
1155
+ {
1156
+ VALUE idx[CA_RANK_MAX];
1157
+ int i, any = 0;
1158
+ for (i = 0; i < argc; i++) {
1159
+ if ( ca_index_key_is_scalar(argv[i]) ) {
1160
+ idx[i] = INT2FIX(0);
1161
+ any = 1;
1162
+ }
1163
+ else {
1164
+ idx[i] = Qnil;
900
1165
  }
901
1166
  }
902
- return obj;
1167
+ if ( ! any ) {
1168
+ return obj;
1169
+ }
1170
+ return rb_ca_fetch2(obj, argc, idx);
903
1171
  }
904
1172
 
1173
+ /* ca[k0, k1, ...] with a CArray among the keys. An integer CArray picks
1174
+ the cells it lists along its axis, a boolean one the cells it marks (it
1175
+ must be as long as the axis). Every other key is read as the indexer
1176
+ reads it (ca_index_axis_key): an Integer picks one cell and drops the
1177
+ axis, a Range / ArithmeticSequence / Array form a run, nil the axis. */
905
1178
  VALUE
906
1179
  rb_ca_grid (int argc, VALUE *argv, VALUE self)
907
1180
  {
908
- volatile VALUE obj, ridx, rval;
1181
+ volatile VALUE obj, rval;
909
1182
  volatile VALUE list = rb_ary_new();
910
1183
  CArray *ca;
911
1184
  CArray *ci[CA_RANK_MAX]; /* CAWrap holders for INDEX axes; NULL for STRIDE */
912
1185
  cag_axis_t protos[CA_RANK_MAX];
1186
+ VALUE expanded[CA_RANK_MAX];
1187
+ long n;
913
1188
  ca_size_t i;
914
1189
 
915
- /* Dispatch hook: route mixed AP + single boolean to CASelectAxis
916
- (slab-copy optimised path). Falls through to per-cell CAGrid gather
917
- when not eligible (integer index, multiple INDIRECT axes, indirect
918
- not on axis 0). Inline argv[0] type check avoids the function call
919
- when axis 0 is nil/Integer (most patterns with INDIRECT on inner axes). */
920
- extern int ca_csa_dispatch_bypass;
921
- if ( ! ca_csa_dispatch_bypass && argc > 0 && TYPE(argv[0]) == T_DATA ) {
922
- if ( rb_ca_select_axis_eligible_p(argc, argv, self) ) {
923
- return rb_ca_select_axis(argc, argv, self);
924
- }
925
- }
926
-
927
1190
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
928
1191
 
929
- ridx = rb_ary_new4(argc, argv);
1192
+ n = ca_index_expand_rubber(ca->ndim, argc, argv, expanded);
1193
+ if ( n >= 0 ) {
1194
+ argc = (int) n;
1195
+ argv = expanded;
1196
+ }
930
1197
 
931
- if ( RARRAY_LEN(ridx) > ca->ndim ) {
1198
+ if ( argc > ca->ndim ) {
932
1199
  rb_raise(rb_eArgError, "# of arguments doesn't equal to the ndim");
933
1200
  }
934
- else if ( RARRAY_LEN(ridx) < ca->ndim ) {
1201
+ else if ( argc < ca->ndim ) {
935
1202
  volatile VALUE ref;
936
1203
  CArray *cv;
937
1204
  ca_size_t rdim[CA_RANK_MAX];
938
- ca_size_t rndim = RARRAY_LEN(ridx);
1205
+ ca_size_t rndim = argc;
939
1206
  ca_size_t j = 0, k;
940
1207
  for (i=0; i<rndim; i++) {
941
- rval = rb_ary_entry(ridx, i);
1208
+ rval = argv[i];
942
1209
  if ( rb_obj_is_carray(rval) ) {
943
1210
  TypedData_Get_Struct(rval, CArray, &carray_data_type, cv);
944
1211
  rdim[i] = 1;
945
1212
  for (k=0; k<cv->ndim; k++) {
1213
+ if ( j >= ca->ndim ) {
1214
+ rb_raise(rb_eArgError, "invalid total ndim of args");
1215
+ }
946
1216
  rdim[i] *= ca->dim[j];
947
1217
  j += 1;
948
1218
  }
@@ -959,42 +1229,43 @@ rb_ca_grid (int argc, VALUE *argv, VALUE self)
959
1229
  return rb_ca_grid(argc, argv, ref);
960
1230
  }
961
1231
 
962
- /* Build per-axis protos:
963
- nil -> STRIDE(0, parent.dim, 1), no CArray
964
- Range -> STRIDE if plain integer Range, else fall through to INDEX
965
- CArray -> INDEX with indices = (ca_size_t*)ca_wrap_readonly(...)->ptr */
1232
+ /* Dispatch hook: route a boolean on axis 0 with plain keys elsewhere to
1233
+ CASelectAxis (slab-copy optimised path). Falls through to CAGrid when
1234
+ not eligible. The inline argv[0] type check avoids the call when axis
1235
+ 0 is nil / Integer (most patterns with the CArray on an inner axis). */
1236
+ extern int ca_csa_dispatch_bypass;
1237
+ if ( ! ca_csa_dispatch_bypass && argc > 0 && TYPE(argv[0]) == T_DATA ) {
1238
+ if ( rb_ca_select_axis_eligible_p(argc, argv, self) ) {
1239
+ return ca_grid_drop_scalar_axes(rb_ca_select_axis(argc, argv, self),
1240
+ argc, argv);
1241
+ }
1242
+ }
1243
+
966
1244
  for (i = 0; i < ca->ndim; i++) {
967
1245
  ca_size_t dim_size = ca->dim[i];
968
- rval = rb_ary_entry(ridx, i);
1246
+ rval = argv[i];
969
1247
  ci[i] = NULL;
970
- if ( NIL_P(rval) ) {
1248
+ if ( ! rb_obj_is_carray(rval) ) {
1249
+ ca_size_t start, count, step;
1250
+ ca_index_axis_key(rval, dim_size, (int) i, &start, &count, &step);
971
1251
  protos[i].kind = CAG_AXIS_STRIDE;
972
- protos[i].count = dim_size;
973
- protos[i].start = 0;
974
- protos[i].step = 1;
1252
+ protos[i].count = count;
1253
+ protos[i].start = start;
1254
+ protos[i].step = step;
975
1255
  protos[i].indices = NULL;
1256
+ protos[i].holes = NULL;
976
1257
  continue;
977
1258
  }
978
- if ( rb_obj_is_kind_of(rval, rb_cRange) ) {
979
- ca_size_t start, count;
980
- if ( cag_range_to_stride(rval, dim_size, &start, &count) ) {
981
- protos[i].kind = CAG_AXIS_STRIDE;
982
- protos[i].count = count;
983
- protos[i].start = start;
984
- protos[i].step = 1;
985
- protos[i].indices = NULL;
986
- continue;
1259
+ if ( rb_ca_is_boolean_type(rval) ) {
1260
+ CArray *cb;
1261
+ TypedData_Get_Struct(rval, CArray, &carray_data_type, cb);
1262
+ if ( cb->elements != dim_size ) {
1263
+ rb_raise(rb_eArgError,
1264
+ "mismatch of # of elements ( %lld <=> %lld ) in reference "
1265
+ "by selection on axis %d",
1266
+ (long long) cb->elements, (long long) dim_size, (int) i);
987
1267
  }
988
- /* fallback: materialise to integer array */
989
- rval = rb_funcall(rb_mKernel, rb_intern("CA_SIZE"), 1, rval);
990
- }
991
- else if ( rb_obj_is_carray(rval) ) {
992
- if ( rb_ca_is_boolean_type(rval) ) {
993
- rval = rb_ca_where(rval);
994
- }
995
- }
996
- else if ( TYPE(rval) == T_ARRAY ) {
997
- rb_raise(rb_eTypeError, "grid: an axis is an Integer, a Range, nil or a CArray of indices (got Array)");
1268
+ rval = rb_ca_where(rval);
998
1269
  }
999
1270
 
1000
1271
  /* INDEX axis: converted here, read once the window below opens */
@@ -1020,7 +1291,7 @@ rb_ca_grid (int argc, VALUE *argv, VALUE self)
1020
1291
  (VALUE) &c);
1021
1292
  }
1022
1293
 
1023
- return obj;
1294
+ return ca_grid_drop_scalar_axes(obj, argc, argv);
1024
1295
  }
1025
1296
 
1026
1297
  static VALUE
@@ -1044,6 +1315,9 @@ rb_ca_grid_initialize_copy (VALUE self, VALUE other)
1044
1315
  }
1045
1316
  /* Copy the axes: the source may be collected before the copy. */
1046
1317
  ca_grid_setup(ca, cs->parent, cs->ndim, cs->axes, 0);
1318
+ ca->holes_read_masked = cs->holes_read_masked;
1319
+ ca->mask_owner = cs->mask_owner;
1320
+ ca_grid_inherit_mask((VALUE) ca);
1047
1321
 
1048
1322
  return self;
1049
1323
  }