carray 3.0.2 → 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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +568 -0
  3. data/README.md +6 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +220 -0
  7. data/ext/ca_axis_group.c +201 -123
  8. data/ext/ca_binop_dispatch.c +46 -52
  9. data/ext/ca_binop_dispatch.h +1 -1
  10. data/ext/ca_categorical_iterator.c +249 -183
  11. data/ext/ca_compare.c +7 -12
  12. data/ext/ca_for_buffer.h +21 -68
  13. data/ext/ca_group_iter.c +38 -23
  14. data/ext/ca_kernel_iterator.c +1765 -2076
  15. data/ext/ca_kernel_iterator.h +584 -566
  16. data/ext/ca_monop_dispatch.c +86 -63
  17. data/ext/ca_monop_dispatch.h +5 -0
  18. data/ext/ca_obj_array.c +223 -56
  19. data/ext/ca_obj_bincmp.c +172 -138
  20. data/ext/ca_obj_binop.c +116 -230
  21. data/ext/ca_obj_bitarray.c +40 -26
  22. data/ext/ca_obj_bitfield.c +100 -68
  23. data/ext/ca_obj_block.c +19 -9
  24. data/ext/ca_obj_byte_swap.c +45 -46
  25. data/ext/ca_obj_const_string.c +269 -44
  26. data/ext/ca_obj_face.c +612 -89
  27. data/ext/ca_obj_face.h +111 -47
  28. data/ext/ca_obj_fake.c +36 -79
  29. data/ext/ca_obj_farray.c +7 -3
  30. data/ext/ca_obj_field.c +33 -8
  31. data/ext/ca_obj_fixlen_string.c +23 -24
  32. data/ext/ca_obj_grid.c +541 -210
  33. data/ext/ca_obj_meld.c +331 -111
  34. data/ext/ca_obj_moncmp.c +80 -65
  35. data/ext/ca_obj_monop.c +177 -149
  36. data/ext/ca_obj_object.c +664 -248
  37. data/ext/ca_obj_record.c +63 -23
  38. data/ext/ca_obj_reduce.c +18 -16
  39. data/ext/ca_obj_refer.c +140 -58
  40. data/ext/ca_obj_remap.c +85 -24
  41. data/ext/ca_obj_repeat.c +24 -9
  42. data/ext/ca_obj_roll.c +121 -16
  43. data/ext/ca_obj_select.c +61 -58
  44. data/ext/ca_obj_select_axis.c +73 -107
  45. data/ext/ca_obj_shift.c +32 -102
  46. data/ext/ca_obj_stack.c +372 -122
  47. data/ext/ca_obj_stride.c +348 -140
  48. data/ext/ca_obj_string.c +88 -22
  49. data/ext/ca_obj_tile.c +38 -21
  50. data/ext/ca_obj_time.c +45 -31
  51. data/ext/ca_obj_timedelta.c +43 -29
  52. data/ext/ca_obj_transpose.c +17 -6
  53. data/ext/ca_obj_triop.c +125 -141
  54. data/ext/ca_obj_window.c +330 -44
  55. data/ext/ca_op_ipower.c +24 -11
  56. data/ext/ca_op_powi.h +57 -30
  57. data/ext/ca_pow5_table.h +656 -0
  58. data/ext/ca_sort_kernels.h +70 -0
  59. data/ext/ca_sweep_engine.c +104 -81
  60. data/ext/ca_sweep_engine.h +7 -20
  61. data/ext/ca_triop_dispatch.c +4 -1
  62. data/ext/ca_triop_dispatch.h +5 -2
  63. data/ext/caframe_csv_reader.c +542 -0
  64. data/ext/carray.h +241 -92
  65. data/ext/carray_access.c +608 -276
  66. data/ext/carray_address_basis.c +494 -97
  67. data/ext/carray_attribute.c +129 -4
  68. data/ext/carray_bincount.c +39 -7
  69. data/ext/carray_broadcast.c +56 -19
  70. data/ext/carray_build_flags.h +1 -1
  71. data/ext/carray_call_cfunc.c +108 -28
  72. data/ext/carray_cast.c +1576 -223
  73. data/ext/carray_cast_func.rb +77 -24
  74. data/ext/carray_class.c +4 -3
  75. data/ext/carray_conversion.c +208 -75
  76. data/ext/carray_copy.c +82 -24
  77. data/ext/carray_core.c +646 -162
  78. data/ext/carray_count.c +171 -88
  79. data/ext/carray_element.c +94 -60
  80. data/ext/carray_factorize.c +670 -324
  81. data/ext/carray_generate.c +260 -83
  82. data/ext/carray_histogram.c +209 -106
  83. data/ext/carray_hold.c +14 -16
  84. data/ext/carray_index_classifier.c +422 -243
  85. data/ext/carray_internal.h +692 -3
  86. data/ext/carray_kernels_bincmp.c +7 -0
  87. data/ext/carray_kernels_binop.c +487 -120
  88. data/ext/carray_kernels_init.c +653 -50
  89. data/ext/carray_kernels_moncmp.c +15 -8
  90. data/ext/carray_kernels_monop.c +99 -43
  91. data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
  92. data/ext/carray_kernels_reduce_boolean.c +112 -36
  93. data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
  94. data/ext/carray_kernels_reduce_extreme.c +3032 -2892
  95. data/ext/carray_kernels_reduce_variance.c +439 -500
  96. data/ext/carray_kernels_scan.c +1097 -488
  97. data/ext/carray_kernels_search.c +3787 -2176
  98. data/ext/carray_kernels_sort.c +1200 -920
  99. data/ext/carray_kernels_triop.c +479 -7
  100. data/ext/carray_key_windows.c +216 -0
  101. data/ext/carray_lazy.c +967 -153
  102. data/ext/carray_loop.c +81 -65
  103. data/ext/carray_mask.c +910 -324
  104. data/ext/carray_math_kernel.h +1 -0
  105. data/ext/carray_median_percentile.c +299 -100
  106. data/ext/carray_memory_view.c +872 -758
  107. data/ext/carray_operator.c +1171 -364
  108. data/ext/carray_order.c +505 -133
  109. data/ext/carray_partition.c +112 -65
  110. data/ext/carray_random.c +327 -239
  111. data/ext/carray_round.c +273 -0
  112. data/ext/carray_scatter.c +346 -78
  113. data/ext/carray_segment.c +257 -0
  114. data/ext/carray_slab.c +249 -86
  115. data/ext/carray_sort.c +224 -227
  116. data/ext/carray_sort_kernel.c +8 -1
  117. data/ext/carray_struct.c +118 -39
  118. data/ext/carray_test.c +193 -69
  119. data/ext/carray_time_text.c +1182 -0
  120. data/ext/carray_undef.c +4 -0
  121. data/ext/carray_utils.c +579 -113
  122. data/ext/extconf.rb +27 -2
  123. data/ext/mk_call_cfunc.rb +19 -4
  124. data/ext/mk_pow5_table.rb +35 -0
  125. data/ext/mkkernel.rb +1202 -1014
  126. data/ext/ruby_carray.c +17 -5
  127. data/ext/version.h +4 -4
  128. data/ext/version.rb +4 -2
  129. data/lib/carray/attribute.rb +160 -17
  130. data/lib/carray/autoload_carray.rb +23 -27
  131. data/lib/carray/autoload_method_extension.rb +20 -5
  132. data/lib/carray/axis_group.rb +360 -63
  133. data/lib/carray/basics.rb +162 -28
  134. data/lib/carray/bincount_nd.rb +18 -2
  135. data/lib/carray/block_iterator.rb +231 -58
  136. data/lib/carray/boolean_reduce.rb +34 -42
  137. data/lib/carray/categorical.rb +242 -52
  138. data/lib/carray/categorical_iterator.rb +437 -827
  139. data/lib/carray/complex.rb +41 -34
  140. data/lib/carray/conditional.rb +150 -14
  141. data/lib/carray/const_string.rb +59 -4
  142. data/lib/carray/construct.rb +15 -11
  143. data/lib/carray/data_type_extension.rb +1 -0
  144. data/lib/carray/distance_limit.rb +77 -0
  145. data/lib/carray/fixlen_string.rb +7 -1
  146. data/lib/carray/frame/column_verbs.rb +70 -0
  147. data/lib/carray/frame/concat.rb +157 -6
  148. data/lib/carray/frame/convert.rb +82 -7
  149. data/lib/carray/frame/csv_parser.rb +688 -87
  150. data/lib/carray/frame/describe.rb +80 -0
  151. data/lib/carray/frame/frame.rb +369 -45
  152. data/lib/carray/frame/group.rb +631 -90
  153. data/lib/carray/frame/io.rb +506 -79
  154. data/lib/carray/frame/join.rb +411 -62
  155. data/lib/carray/frame/records.rb +116 -19
  156. data/lib/carray/frame/reshape.rb +455 -0
  157. data/lib/carray/frame/sort.rb +30 -18
  158. data/lib/carray/frame/verbs.rb +868 -61
  159. data/lib/carray/frame/windows.rb +117 -0
  160. data/lib/carray/frame.rb +4 -0
  161. data/lib/carray/fuse_source.rb +118 -2
  162. data/lib/carray/fusion.rb +257 -42
  163. data/lib/carray/histogram.rb +6 -1
  164. data/lib/carray/inspect.rb +54 -13
  165. data/lib/carray/iterator.rb +99 -9
  166. data/lib/carray/key_windows.rb +620 -0
  167. data/lib/carray/lazy.rb +216 -193
  168. data/lib/carray/mask_gap_fill.rb +112 -92
  169. data/lib/carray/math.rb +32 -19
  170. data/lib/carray/meld_reduce.rb +52 -21
  171. data/lib/carray/methods/align_addr.rb +8 -4
  172. data/lib/carray/methods/bin.rb +26 -18
  173. data/lib/carray/methods/bincount.rb +18 -2
  174. data/lib/carray/methods/bit_string.rb +15 -4
  175. data/lib/carray/methods/choose.rb +16 -3
  176. data/lib/carray/methods/composition.rb +18 -10
  177. data/lib/carray/methods/factorize.rb +2 -2
  178. data/lib/carray/methods/gather_nd.rb +25 -5
  179. data/lib/carray/methods/insert_block.rb +9 -14
  180. data/lib/carray/methods/is_between.rb +59 -0
  181. data/lib/carray/methods/is_in.rb +140 -10
  182. data/lib/carray/methods/join.rb +2 -7
  183. data/lib/carray/methods/lag.rb +49 -0
  184. data/lib/carray/methods/locate_addr.rb +182 -45
  185. data/lib/carray/methods/mode.rb +18 -1
  186. data/lib/carray/methods/nunique.rb +11 -6
  187. data/lib/carray/methods/repeat.rb +1 -20
  188. data/lib/carray/methods/resize.rb +21 -23
  189. data/lib/carray/methods/snap.rb +34 -12
  190. data/lib/carray/methods/unique.rb +11 -2
  191. data/lib/carray/methods/value_counts.rb +4 -11
  192. data/lib/carray/record_order.rb +208 -0
  193. data/lib/carray/rng.rb +3 -0
  194. data/lib/carray/runtime.rb +65 -17
  195. data/lib/carray/segment_iterator.rb +1221 -0
  196. data/lib/carray/serialize.rb +214 -30
  197. data/lib/carray/slab_iterator.rb +101 -27
  198. data/lib/carray/stack.rb +10 -4
  199. data/lib/carray/string.rb +105 -5
  200. data/lib/carray/string_operation_extension.rb +12 -4
  201. data/lib/carray/struct.rb +137 -58
  202. data/lib/carray/struct_builder.rb +124 -17
  203. data/lib/carray/time.rb +1222 -186
  204. data/lib/carray/window_iterator.rb +242 -81
  205. data/lib/carray.rb +9 -2
  206. data/yard-stubs/ca_obj_array.rb +4 -4
  207. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  208. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  209. data/yard-stubs/ca_obj_fake.rb +1 -1
  210. data/yard-stubs/ca_obj_field.rb +5 -1
  211. data/yard-stubs/ca_obj_grid.rb +21 -10
  212. data/yard-stubs/ca_obj_refer.rb +5 -4
  213. data/yard-stubs/ca_obj_roll.rb +2 -3
  214. data/yard-stubs/ca_obj_shift.rb +5 -1
  215. data/yard-stubs/ca_obj_stride.rb +10 -7
  216. data/yard-stubs/ca_obj_tile.rb +1 -1
  217. data/yard-stubs/ca_obj_transpose.rb +1 -1
  218. data/yard-stubs/ca_obj_window.rb +9 -5
  219. data/yard-stubs/carray_access.rb +11 -5
  220. data/yard-stubs/carray_attribute.rb +0 -5
  221. data/yard-stubs/carray_broadcast.rb +1 -1
  222. data/yard-stubs/carray_cast.rb +88 -43
  223. data/yard-stubs/carray_conversion.rb +15 -2
  224. data/yard-stubs/carray_copy.rb +12 -5
  225. data/yard-stubs/carray_core.rb +3 -3
  226. data/yard-stubs/carray_count.rb +9 -0
  227. data/yard-stubs/carray_element.rb +10 -4
  228. data/yard-stubs/carray_generate.rb +21 -1
  229. data/yard-stubs/carray_lazy.rb +5 -1
  230. data/yard-stubs/carray_loop.rb +4 -1
  231. data/yard-stubs/carray_mask.rb +60 -12
  232. data/yard-stubs/carray_math.rb +52 -14
  233. data/yard-stubs/carray_median_percentile.rb +15 -8
  234. data/yard-stubs/carray_memory_view.rb +40 -23
  235. data/yard-stubs/carray_order.rb +61 -29
  236. data/yard-stubs/carray_random.rb +13 -4
  237. data/yard-stubs/carray_scatter.rb +21 -9
  238. data/yard-stubs/carray_segment.rb +72 -0
  239. data/yard-stubs/carray_slab.rb +10 -2
  240. data/yard-stubs/carray_sort.rb +49 -8
  241. data/yard-stubs/carray_test.rb +15 -3
  242. data/yard-stubs/carray_utils.rb +0 -26
  243. metadata +19 -5
  244. data/ext/ca_for_each_element.h +0 -239
  245. data/ext/carray_kernels_map.c +0 -3467
  246. data/lib/carray/arrow_tensor.rb +0 -401
  247. data/lib/carray/table.rb +0 -108
@@ -2,13 +2,10 @@
2
2
 
3
3
  ca_axis_descriptor.h
4
4
 
5
- Per-axis descriptor framework (D1 + D2 + D3) — shared C-level vocabulary
6
- that lets CSA, CAGrid, CASelectAxis, CAWindow, CAShift, and future
5
+ Per-axis descriptor framework — shared C-level vocabulary that lets
6
+ CASelectAxis, CAGrid, CASelect, CAWindow, CAShift, and future
7
7
  per-axis-mixed views describe each axis the same way so a common
8
- attach dispatch engine (D3, ca_axis_dispatch.c) can drive them
9
- uniformly.
10
-
11
- See devel/PROPOSAL_AXIS_DESCRIPTOR_FRAMEWORK.md for the design.
8
+ attach dispatch engine (ca_axis_dispatch.c) can drive them uniformly.
12
9
 
13
10
  Status: TWO-TIER FREEZE CONTRACT (3.0 onward), the same split
14
11
  ca_kernel_iterator.h declares, for the same reason: this header is
@@ -50,14 +47,14 @@
50
47
  When this header is included from carray.h mid-file, those typedefs
51
48
  are already in scope by the time we reach the include site. */
52
49
 
53
- /* ---- D1: per-axis descriptor types ----------------------------------------
50
+ /* ---- per-axis descriptor types --------------------------------------------
54
51
 
55
52
  STRIDE = linear stride axis: parent index = start + i*step,
56
53
  i in [0, count). Subsumes nil / Integer / Range index args.
57
54
  INDEX = integer index axis: parent index = indices[i],
58
55
  i in [0, count). Subsumes integer-array (CAGrid)
59
56
  and boolean-mask-after-snapshot (CASelectAxis) axes.
60
- SHIFT = bound-aware stride axis (CAWindow/CAShift, Tier 2.B):
57
+ SHIFT = bound-aware stride axis (CAWindow/CAShift):
61
58
  parent index = start + i*step normalised by `policy`
62
59
  (CA_BOUNDS_FILL / PERIODIC / REFLECT / NEAREST / ...)
63
60
  against `size0` (= parent dim along this axis). When
@@ -86,16 +83,17 @@ typedef struct {
86
83
  uint8_t policy; /* CA_BOUNDS_FILL / PERIODIC / REFLECT / ... */
87
84
  } ca_axis_desc_t;
88
85
 
89
- /* ---- D2: producer interface ----------------------------------------------
86
+ /* ---- producer interface --------------------------------------------------
90
87
 
91
- Both implementations write ndim entries into `out` (caller-allocated)
92
- and `out_parent_dims` (caller-allocated, sized CA_RANK_MAX). See
93
- devel/PROPOSAL_AXIS_DESCRIPTOR_FRAMEWORK.md §5 Framework Phase 1 and
94
- devel/PROPOSAL_FLAT_INDEX_VIEWS.md §2.3 for rationale.
88
+ A producer writes one entry per descriptor axis into `out`
89
+ (caller-allocated) and `out_parent_dims` (caller-allocated, sized
90
+ CA_RANK_MAX). The producers declared here are CASelectAxis and CAGrid;
91
+ CASelect and CAWindow have their own (ca_select_describe_axes /
92
+ ca_window_describe_axes).
95
93
 
96
94
  `out_parent_dims[k]` is the **effective** parent dim along descriptor
97
- axis k — for CSA / CAGrid this is just `parent->dim[k]`, but for
98
- flat-index views (CASelect / CAMapping, Tier 2.A.3+) it is
95
+ axis k — for CASelectAxis / CAGrid this is just `parent->dim[k]`, but
96
+ for a flat-index view (CASelect) it is
99
97
  `{parent->elements}` (a single-axis flat view of parent). This
100
98
  decouples descriptor.ndim from parent.ndim so the engine can drive
101
99
  views whose iteration axes don't match the parent's physical shape.
@@ -103,13 +101,17 @@ typedef struct {
103
101
  Pointer arguments are typed `void *` here to avoid pulling the
104
102
  private CASelectAxis / CAGrid struct definitions (which live in
105
103
  their respective .c files) into this header. Each implementation
106
- casts to its concrete type inside the .c file. */
104
+ casts to its concrete type inside the .c file.
105
+
106
+ An INDEX axis has no way to say "no cell": a CAGrid index that is
107
+ masked (a hole) is written as index 0, so a caller driving a holed grid
108
+ through the engine reads and writes parent cell 0 there. */
107
109
  void ca_select_axis_describe_axes (void *ca, ca_axis_desc_t *out,
108
110
  ca_size_t *out_parent_dims);
109
111
  void ca_grid_describe_axes (void *ca, ca_axis_desc_t *out,
110
112
  ca_size_t *out_parent_dims);
111
113
 
112
- /* ---- D3: common attach engine --------------------------------------------
114
+ /* ---- common attach engine -------------------------------------------------
113
115
 
114
116
  Drives gather from `parent` into an output buffer driven by the
115
117
  per-axis descriptor array. Caller must have parent attached before
@@ -119,14 +121,15 @@ void ca_grid_describe_axes (void *ca, ca_axis_desc_t *out,
119
121
  descriptor axis (see producer interface above). The engine never
120
122
  reads `parent->dim` directly — it only reads `parent->ptr` for
121
123
  data access — which is what allows flat-index views to lie about
122
- parent's apparent shape (Tier 2.A, PROPOSAL_FLAT_INDEX_VIEWS.md).
124
+ parent's apparent shape.
123
125
 
124
126
  `bound_fill` is the bytes-wide value written into gather output
125
- cells whose SHIFT axes resolve to an out-of-bounds parent index
126
- (Tier 2.B, PROPOSAL_BOUND_AWARE_VIEWS.md). Pass NULL when no
127
- SHIFT axis is present (CSA / CAGrid / CASelect / CAMapping); the
128
- engine ignores it. On scatter, the engine simply skips parent
129
- writes for OOB cells regardless of bound_fill.
127
+ cells whose SHIFT axes resolve to an out-of-bounds parent index.
128
+ Pass NULL when no SHIFT axis is present (CASelectAxis / CAGrid /
129
+ CASelect); the engine ignores it. On scatter, the engine simply skips
130
+ parent writes for OOB cells regardless of bound_fill. A SHIFT axis
131
+ under the RUBY or STRICT policy raises IndexError part way through the
132
+ walk for an index outside the parent.
130
133
 
131
134
  _gather — caller provides out_buf (must be sized total_elements*bytes)
132
135
  _attach — wrapper that mallocs the buffer; caller xfrees
@@ -160,7 +163,7 @@ void ca_axis_dispatch_scatter (struct _CArray *parent,
160
163
  ca_size_t total_elements,
161
164
  const char *in_buf);
162
165
  /* Broadcast scatter: write the single value `val` (bytes wide) into
163
- every selected parent cell. See D6 of the framework piece.
166
+ every selected parent cell.
164
167
  (SHIFT axis OOB cells are skipped — fill semantics aren't
165
168
  meaningful for broadcast-write since the destination value already
166
169
  IS the broadcast value.) */
@@ -42,6 +42,7 @@
42
42
  #include "carray.h"
43
43
  #include "ca_iter_substrate.h"
44
44
  #include "ca_composite_dispatch.h"
45
+ #include "carray_internal.h" /* ca_parent_lends_no_memory */
45
46
 
46
47
  #include <string.h>
47
48
 
@@ -393,6 +394,100 @@ ca_axis_dispatch_fill_value_cb (ca_size_t off, int oob, ca_size_t n, void *vctx)
393
394
  }
394
395
  }
395
396
 
397
+ /* Rows whose innermost axis is a step-1 SHIFT axis. View cell i of the row
398
+ reads parent cell start + i, so the cells with 0 <= start + i < size0 form
399
+ one run and go to cb together. The cells before and after it are out of
400
+ range: under FILL / MASK every one of them is (cb gets each side as one
401
+ oob slab), under the other policies each maps to a cell of its own. */
402
+ static void
403
+ ca_axis_dispatch_shift_cell (const ca_axis_desc_t *ax, ca_size_t pstride,
404
+ ca_size_t row_off, ca_size_t i, ca_size_t bytes,
405
+ ca_slab_cb_t cb, void *ctx)
406
+ {
407
+ ca_size_t pi = ca_bounds_normalize_index(ax->policy, ax->size0,
408
+ ax->start + i);
409
+ if ( pi < 0 || pi >= ax->size0 ) {
410
+ cb(row_off, 1, bytes, ctx);
411
+ }
412
+ else {
413
+ cb(row_off + pi * pstride, 0, bytes, ctx);
414
+ }
415
+ }
416
+
417
+ static void
418
+ ca_axis_dispatch_for_each_shift_row (ca_axis_desc_t *laxes,
419
+ const ca_size_t *pstrides,
420
+ int8_t lndim,
421
+ ca_size_t bytes,
422
+ ca_size_t total_elements,
423
+ ca_slab_cb_t cb,
424
+ void *ctx)
425
+ {
426
+ int8_t inner = lndim - 1;
427
+ const ca_axis_desc_t *ax = &laxes[inner];
428
+ ca_size_t pstride = pstrides[inner];
429
+ ca_size_t count = ax->count;
430
+ int coalesce = ( ax->policy == CA_BOUNDS_FILL
431
+ || ax->policy == CA_BOUNDS_MASK );
432
+ ca_op_prefix_axis_t prefix[CA_RANK_MAX];
433
+ ca_size_t idx[CA_RANK_MAX];
434
+ ca_size_t lo, hi, n_rows, r, i;
435
+ int8_t k;
436
+
437
+ /* In-range view cells: lo <= i < hi. */
438
+ lo = -ax->start;
439
+ if ( lo < 0 ) lo = 0;
440
+ if ( lo > count ) lo = count;
441
+ hi = ax->size0 - ax->start;
442
+ if ( hi > count ) hi = count;
443
+ if ( hi < lo ) hi = lo;
444
+
445
+ ca_axis_dispatch_classify_prefix(laxes, pstrides, inner, prefix);
446
+ for ( k = 0; k < inner; k++ ) idx[k] = 0;
447
+
448
+ n_rows = total_elements / count;
449
+ for ( r = 0; r < n_rows; r++ ) {
450
+ int oob;
451
+ ca_size_t row_off = ca_axis_dispatch_prefix_offset(prefix, idx, inner,
452
+ &oob);
453
+ if ( oob ) {
454
+ cb(row_off, 1, count * bytes, ctx);
455
+ }
456
+ else {
457
+ if ( lo > 0 ) {
458
+ if ( coalesce ) {
459
+ cb(row_off, 1, lo * bytes, ctx);
460
+ }
461
+ else {
462
+ for ( i = 0; i < lo; i++ ) {
463
+ ca_axis_dispatch_shift_cell(ax, pstride, row_off, i, bytes,
464
+ cb, ctx);
465
+ }
466
+ }
467
+ }
468
+ if ( hi > lo ) {
469
+ cb(row_off + (ax->start + lo) * pstride, 0, (hi - lo) * bytes, ctx);
470
+ }
471
+ if ( hi < count ) {
472
+ if ( coalesce ) {
473
+ cb(row_off, 1, (count - hi) * bytes, ctx);
474
+ }
475
+ else {
476
+ for ( i = hi; i < count; i++ ) {
477
+ ca_axis_dispatch_shift_cell(ax, pstride, row_off, i, bytes,
478
+ cb, ctx);
479
+ }
480
+ }
481
+ }
482
+ }
483
+
484
+ for ( k = inner - 1; k >= 0; k-- ) {
485
+ if ( ++idx[k] < prefix[k].count ) break;
486
+ idx[k] = 0;
487
+ }
488
+ }
489
+ }
490
+
396
491
  /* Generic per-slab driver. Walks the (post-merge / post-layout)
397
492
  prefix axes row-major and invokes `cb` once per slab iteration.
398
493
  The all-slab case degenerates to a single `cb` invocation with
@@ -437,6 +532,17 @@ ca_axis_dispatch_for_each_slab (CArray *parent,
437
532
  return;
438
533
  }
439
534
 
535
+ /* Innermost SHIFT axis with step 1: the in-range part of each row is one
536
+ contiguous run of parent cells, so it goes to cb as one slab instead of
537
+ one cell at a time. */
538
+ if ( slab_start == lndim
539
+ && laxes[lndim - 1].kind == CA_AXIS_KIND_SHIFT
540
+ && laxes[lndim - 1].step == 1 ) {
541
+ ca_axis_dispatch_for_each_shift_row(laxes, pstrides, lndim, bytes,
542
+ total_elements, cb, ctx);
543
+ return;
544
+ }
545
+
440
546
  /* Pre-classify prefix axes once. Inner loop becomes branchless
441
547
  modulo a per-axis kind tag whose value is constant across
442
548
  iters. */
@@ -951,3 +1057,117 @@ ca_axis_dispatch_outer_has_shift (const ca_axis_desc_t *descs,
951
1057
  }
952
1058
  return 0;
953
1059
  }
1060
+
1061
+ /* ==========================================================================
1062
+ Transfers of a descriptor view (CAGrid, CASelect, CASelectAxis, CAWindow)
1063
+ whose parent holds no ptr.
1064
+
1065
+ The engine above walks parent->ptr. A cold parent is handled by what it
1066
+ is:
1067
+
1068
+ - one ca_attach_is_alias accepts already has the memory: borrow it;
1069
+ - one with no memory to lend (ca_parent_lends_no_memory) is asked for
1070
+ the selected cells only, through the view's own xfer_stride over the
1071
+ whole view -- producing every cell of the parent to serve a selection
1072
+ would make the cost follow the parent's size;
1073
+ - anything else is gathered into a parent-shaped scratch that stands in
1074
+ for parent->ptr, and pushed back for PUT.
1075
+ ========================================================================== */
1076
+
1077
+ /* The whole view as one region request to its own xfer_stride slot. */
1078
+ static void
1079
+ ca_axis_view_xfer_region (CArray *ca, void *data, int dir)
1080
+ {
1081
+ ca_size_t starts[CA_RANK_MAX], strides[CA_RANK_MAX], s;
1082
+ int8_t k;
1083
+
1084
+ /* The slot is called directly, past ca_xfer_stride's empty-region check. */
1085
+ if ( ca->elements == 0 ) return;
1086
+
1087
+ s = ca->bytes;
1088
+ for ( k = ca->ndim - 1; k >= 0; k-- ) {
1089
+ starts[k] = 0;
1090
+ strides[k] = s;
1091
+ s *= ca->dim[k];
1092
+ }
1093
+ ca_func[ca->obj_type].xfer_stride(ca, starts, ca->dim, strides, data, dir);
1094
+ }
1095
+
1096
+ void
1097
+ ca_axis_view_xfer_all (void *ap, ca_axis_view_fast_t fast, int region_ok,
1098
+ void *data, int dir)
1099
+ {
1100
+ CArray *ca = (CArray *) ap;
1101
+ CArray *parent = ((CAView *) ca)->parent;
1102
+
1103
+ if ( parent->ptr ) {
1104
+ fast(ca, (char *) data, dir);
1105
+ return;
1106
+ }
1107
+
1108
+ if ( ca_attach_is_alias(parent) ) {
1109
+ ca_attach(parent); /* window: an alias attach, cannot raise */
1110
+ fast(ca, (char *) data, dir);
1111
+ ca_detach(parent);
1112
+ return;
1113
+ }
1114
+
1115
+ if ( region_ok && ca_parent_lends_no_memory(parent) ) {
1116
+ ca_axis_view_xfer_region(ca, data, dir);
1117
+ return;
1118
+ }
1119
+
1120
+ {
1121
+ volatile VALUE holder;
1122
+ ca_size_t plen = parent->elements * parent->bytes;
1123
+ char *parent_scratch = ALLOCV_N(char, holder, plen);
1124
+ ca_xfer_all(parent, parent_scratch, CA_XFER_GET);
1125
+ parent->ptr = parent_scratch;
1126
+ fast(ca, (char *) data, dir);
1127
+ /* Put parent->ptr back before the PUT: the PUT can raise (a lazy
1128
+ backing's sync failing), and the scratch is gone once this frame
1129
+ is. */
1130
+ parent->ptr = NULL;
1131
+ if ( dir == CA_XFER_PUT ) {
1132
+ ca_xfer_all(parent, parent_scratch, CA_XFER_PUT);
1133
+ }
1134
+ ALLOCV_END(holder);
1135
+ }
1136
+ }
1137
+
1138
+ /* The attach of a view that owns its buffer and fills it through its own
1139
+ transfers (a descriptor view whose parent has no memory to lend, CARemap,
1140
+ CAStack, CAMeld). The buffer is published only once filled -- a view
1141
+ with a live ptr makes the per-cell dispatchers bypass the transfer slots,
1142
+ and for CA_OBJECT the garbage cells of an unfilled buffer would be marked
1143
+ -- and a raise while filling frees it. The fill goes through ca_xfer_all,
1144
+ which holds the object cells against a collection while the transfers
1145
+ call Ruby. */
1146
+
1147
+ static VALUE
1148
+ ca_axis_view_fill_owned (VALUE arg)
1149
+ {
1150
+ void **args = (void **) arg;
1151
+ ca_xfer_all((CArray *) args[0], args[1], CA_XFER_GET);
1152
+ return Qnil;
1153
+ }
1154
+
1155
+ void
1156
+ ca_axis_view_attach_owned (void *ap)
1157
+ {
1158
+ CArray *ca = (CArray *) ap;
1159
+ char *buf = xmalloc(ca_length(ca) > 0 ? ca_length(ca) : 1);
1160
+ void *args[2];
1161
+
1162
+ args[0] = ca;
1163
+ args[1] = buf;
1164
+ ca_fill_or_xfree(buf, ca_axis_view_fill_owned, (VALUE) args);
1165
+ ca->ptr = buf;
1166
+ }
1167
+
1168
+ void
1169
+ ca_axis_view_sync_owned (void *ap)
1170
+ {
1171
+ CArray *ca = (CArray *) ap;
1172
+ ca_func[ca->obj_type].xfer_all(ca, ca->ptr, CA_XFER_PUT);
1173
+ }