carray 3.0.1 → 3.0.3

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 (229) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +824 -0
  3. data/README.md +5 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +258 -4
  6. data/ext/ca_axis_group.c +368 -184
  7. data/ext/ca_binop_dispatch.c +54 -32
  8. data/ext/ca_binop_dispatch.h +1 -0
  9. data/ext/ca_categorical_iterator.c +90 -41
  10. data/ext/ca_compare.c +8 -2
  11. data/ext/ca_for_buffer.h +21 -68
  12. data/ext/ca_group_iter.c +27 -11
  13. data/ext/ca_kernel_iterator.c +960 -245
  14. data/ext/ca_kernel_iterator.h +352 -181
  15. data/ext/ca_monop_dispatch.c +4 -4
  16. data/ext/ca_monop_dispatch.h +4 -0
  17. data/ext/ca_obj_array.c +194 -42
  18. data/ext/ca_obj_bincmp.c +152 -121
  19. data/ext/ca_obj_binop.c +107 -210
  20. data/ext/ca_obj_bitarray.c +37 -24
  21. data/ext/ca_obj_bitfield.c +95 -62
  22. data/ext/ca_obj_block.c +5 -4
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +180 -50
  25. data/ext/ca_obj_face.c +428 -62
  26. data/ext/ca_obj_face.h +107 -47
  27. data/ext/ca_obj_fake.c +21 -50
  28. data/ext/ca_obj_farray.c +1 -0
  29. data/ext/ca_obj_field.c +16 -3
  30. data/ext/ca_obj_fixlen_string.c +39 -26
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +235 -55
  33. data/ext/ca_obj_moncmp.c +61 -61
  34. data/ext/ca_obj_monop.c +125 -107
  35. data/ext/ca_obj_object.c +551 -233
  36. data/ext/ca_obj_record.c +51 -16
  37. data/ext/ca_obj_reduce.c +5 -8
  38. data/ext/ca_obj_refer.c +117 -33
  39. data/ext/ca_obj_remap.c +57 -17
  40. data/ext/ca_obj_repeat.c +21 -5
  41. data/ext/ca_obj_roll.c +115 -11
  42. data/ext/ca_obj_select.c +88 -75
  43. data/ext/ca_obj_select_axis.c +58 -60
  44. data/ext/ca_obj_shift.c +22 -102
  45. data/ext/ca_obj_stack.c +223 -123
  46. data/ext/ca_obj_stride.c +267 -35
  47. data/ext/ca_obj_string.c +25 -22
  48. data/ext/ca_obj_tile.c +32 -16
  49. data/ext/ca_obj_time.c +23 -25
  50. data/ext/ca_obj_timedelta.c +21 -23
  51. data/ext/ca_obj_transpose.c +12 -3
  52. data/ext/ca_obj_triop.c +110 -117
  53. data/ext/ca_obj_window.c +157 -29
  54. data/ext/ca_op_ipower.c +25 -13
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_rng_normal.h +42 -0
  58. data/ext/ca_rng_xoshiro256pp.h +105 -0
  59. data/ext/ca_sort_kernels.h +70 -0
  60. data/ext/ca_sweep_engine.c +385 -198
  61. data/ext/ca_sweep_engine.h +31 -23
  62. data/ext/ca_triop_dispatch.c +4 -1
  63. data/ext/ca_triop_dispatch.h +5 -2
  64. data/ext/caframe_csv_reader.c +463 -0
  65. data/ext/carray.h +90 -28
  66. data/ext/carray_access.c +487 -231
  67. data/ext/carray_address_basis.c +731 -0
  68. data/ext/carray_attribute.c +45 -3
  69. data/ext/carray_bincount.c +32 -2
  70. data/ext/carray_broadcast.c +49 -17
  71. data/ext/carray_call_cfunc.c +667 -511
  72. data/ext/carray_cast.c +1556 -247
  73. data/ext/carray_cast_func.rb +34 -21
  74. data/ext/carray_conversion.c +197 -73
  75. data/ext/carray_copy.c +84 -38
  76. data/ext/carray_core.c +591 -119
  77. data/ext/carray_count.c +148 -96
  78. data/ext/carray_element.c +18 -27
  79. data/ext/carray_factorize.c +604 -291
  80. data/ext/carray_generate.c +76 -40
  81. data/ext/carray_histogram.c +152 -94
  82. data/ext/carray_hold.c +2 -1
  83. data/ext/carray_index_classifier.c +63 -96
  84. data/ext/carray_internal.h +400 -1
  85. data/ext/carray_lazy.c +834 -79
  86. data/ext/carray_loop.c +88 -66
  87. data/ext/carray_mask.c +705 -324
  88. data/ext/carray_math_kernel.h +1 -0
  89. data/ext/carray_median_percentile.c +263 -63
  90. data/ext/carray_memory_view.c +254 -248
  91. data/ext/carray_operator.c +1093 -363
  92. data/ext/carray_order.c +133 -69
  93. data/ext/carray_partition.c +102 -56
  94. data/ext/carray_random.c +582 -204
  95. data/ext/carray_scatter.c +308 -65
  96. data/ext/carray_segment.c +257 -0
  97. data/ext/carray_slab.c +183 -70
  98. data/ext/carray_sort.c +235 -240
  99. data/ext/carray_sort_kernel.c +8 -1
  100. data/ext/carray_struct.c +99 -21
  101. data/ext/carray_test.c +167 -64
  102. data/ext/carray_time_text.c +1182 -0
  103. data/ext/carray_utils.c +363 -98
  104. data/ext/extconf.rb +27 -2
  105. data/ext/mk_call_cfunc.rb +103 -118
  106. data/ext/mk_pow5_table.rb +35 -0
  107. data/ext/mkkernel.rb +1349 -851
  108. data/ext/ruby_carray.c +17 -2
  109. data/ext/version.h +4 -4
  110. data/ext/version.rb +4 -2
  111. data/lib/carray/attribute.rb +39 -0
  112. data/lib/carray/autoload_carray.rb +24 -3
  113. data/lib/carray/autoload_method_extension.rb +18 -0
  114. data/lib/carray/axis_group.rb +245 -20
  115. data/lib/carray/basics.rb +95 -25
  116. data/lib/carray/bincount_nd.rb +6 -0
  117. data/lib/carray/block_iterator.rb +200 -54
  118. data/lib/carray/boolean_reduce.rb +21 -29
  119. data/lib/carray/categorical.rb +244 -59
  120. data/lib/carray/categorical_iterator.rb +391 -757
  121. data/lib/carray/complex.rb +36 -29
  122. data/lib/carray/conditional.rb +94 -7
  123. data/lib/carray/const_string.rb +177 -27
  124. data/lib/carray/construct.rb +40 -0
  125. data/lib/carray/data_type_extension.rb +3 -0
  126. data/lib/carray/data_type_limits.rb +91 -0
  127. data/lib/carray/fixlen_string.rb +1 -1
  128. data/lib/carray/frame/concat.rb +157 -6
  129. data/lib/carray/frame/convert.rb +13 -7
  130. data/lib/carray/frame/csv_parser.rb +590 -76
  131. data/lib/carray/frame/describe.rb +79 -0
  132. data/lib/carray/frame/frame.rb +205 -35
  133. data/lib/carray/frame/group.rb +199 -40
  134. data/lib/carray/frame/io.rb +452 -60
  135. data/lib/carray/frame/join.rb +134 -46
  136. data/lib/carray/frame/records.rb +54 -19
  137. data/lib/carray/frame/reshape.rb +448 -0
  138. data/lib/carray/frame/sort.rb +26 -2
  139. data/lib/carray/frame/verbs.rb +726 -56
  140. data/lib/carray/frame.rb +2 -0
  141. data/lib/carray/fuse_source.rb +111 -2
  142. data/lib/carray/fusion.rb +229 -38
  143. data/lib/carray/inspect.rb +71 -20
  144. data/lib/carray/iterator.rb +157 -2
  145. data/lib/carray/lazy.rb +54 -67
  146. data/lib/carray/mask_gap_fill.rb +66 -50
  147. data/lib/carray/math.rb +32 -19
  148. data/lib/carray/meld_reduce.rb +40 -7
  149. data/lib/carray/methods/align_addr.rb +8 -4
  150. data/lib/carray/methods/bincount.rb +2 -2
  151. data/lib/carray/methods/bit_string.rb +14 -3
  152. data/lib/carray/methods/composition.rb +16 -10
  153. data/lib/carray/methods/discovery_along.rb +74 -0
  154. data/lib/carray/methods/factorize.rb +50 -0
  155. data/lib/carray/methods/gather_nd.rb +13 -2
  156. data/lib/carray/methods/insert_block.rb +9 -14
  157. data/lib/carray/methods/is_in.rb +130 -6
  158. data/lib/carray/methods/join.rb +1 -1
  159. data/lib/carray/methods/locate_addr.rb +235 -21
  160. data/lib/carray/methods/mask_duplicates.rb +35 -1
  161. data/lib/carray/methods/mode.rb +18 -1
  162. data/lib/carray/methods/nunique.rb +22 -1
  163. data/lib/carray/methods/repeat.rb +91 -0
  164. data/lib/carray/methods/resize.rb +21 -23
  165. data/lib/carray/methods/snap.rb +34 -12
  166. data/lib/carray/methods/unique.rb +52 -3
  167. data/lib/carray/record_order.rb +208 -0
  168. data/lib/carray/rng.rb +86 -0
  169. data/lib/carray/runtime.rb +14 -11
  170. data/lib/carray/segment_iterator.rb +990 -0
  171. data/lib/carray/serialize.rb +197 -27
  172. data/lib/carray/slab_iterator.rb +109 -40
  173. data/lib/carray/stack.rb +10 -4
  174. data/lib/carray/string_operation_extension.rb +9 -4
  175. data/lib/carray/struct.rb +142 -51
  176. data/lib/carray/struct_builder.rb +110 -14
  177. data/lib/carray/table.rb +2 -2
  178. data/lib/carray/time.rb +535 -105
  179. data/lib/carray/window_iterator.rb +259 -82
  180. data/lib/carray.rb +4 -2
  181. data/yard-stubs/ca_obj_array.rb +4 -4
  182. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  183. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  184. data/yard-stubs/ca_obj_block.rb +2 -7
  185. data/yard-stubs/ca_obj_fake.rb +1 -1
  186. data/yard-stubs/ca_obj_field.rb +1 -1
  187. data/yard-stubs/ca_obj_refer.rb +3 -3
  188. data/yard-stubs/ca_obj_roll.rb +0 -1
  189. data/yard-stubs/ca_obj_stride.rb +10 -7
  190. data/yard-stubs/ca_obj_transpose.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +11 -4
  192. data/yard-stubs/carray_access.rb +6 -5
  193. data/yard-stubs/carray_broadcast.rb +2 -2
  194. data/yard-stubs/carray_cast.rb +78 -43
  195. data/yard-stubs/carray_conversion.rb +13 -1
  196. data/yard-stubs/carray_copy.rb +8 -3
  197. data/yard-stubs/carray_core.rb +3 -83
  198. data/yard-stubs/carray_count.rb +16 -2
  199. data/yard-stubs/carray_lazy.rb +210 -1
  200. data/yard-stubs/carray_loop.rb +4 -1
  201. data/yard-stubs/carray_mask.rb +34 -10
  202. data/yard-stubs/carray_math.rb +1499 -4
  203. data/yard-stubs/carray_median_percentile.rb +26 -8
  204. data/yard-stubs/carray_order.rb +43 -82
  205. data/yard-stubs/carray_scatter.rb +10 -3
  206. data/yard-stubs/carray_segment.rb +72 -0
  207. data/yard-stubs/carray_slab.rb +11 -8
  208. data/yard-stubs/carray_sort.rb +50 -8
  209. data/yard-stubs/carray_test.rb +10 -0
  210. data/yard-stubs/carray_utils.rb +0 -26
  211. metadata +19 -19
  212. data/ext/ca_for_each_element.h +0 -239
  213. data/ext/carray_build_flags.h +0 -3
  214. data/ext/carray_config.h +0 -28
  215. data/ext/carray_kernels_bincmp.c +0 -4446
  216. data/ext/carray_kernels_binop.c +0 -11001
  217. data/ext/carray_kernels_init.c +0 -1131
  218. data/ext/carray_kernels_map.c +0 -3467
  219. data/ext/carray_kernels_moncmp.c +0 -2097
  220. data/ext/carray_kernels_monop.c +0 -18313
  221. data/ext/carray_kernels_reduce_aggregate.c +0 -25837
  222. data/ext/carray_kernels_reduce_boolean.c +0 -330
  223. data/ext/carray_kernels_reduce_cumulative.c +0 -14593
  224. data/ext/carray_kernels_reduce_extreme.c +0 -16948
  225. data/ext/carray_kernels_reduce_variance.c +0 -3910
  226. data/ext/carray_kernels_scan.c +0 -3693
  227. data/ext/carray_kernels_search.c +0 -32138
  228. data/ext/carray_kernels_sort.c +0 -10626
  229. data/ext/carray_kernels_triop.c +0 -1392
data/README.md CHANGED
@@ -4,17 +4,16 @@ Ruby/CArray is an extension library for the multi-dimensional array class. It pr
4
4
 
5
5
  ## Status
6
6
 
7
- 3.0.x still moves: behavior can change between releases — see [CHANGELOG.md](CHANGELOG.md). 3.1 is the first release meant to be depended on. Until then, treat it as a place to try things out.
7
+ 3.0.x still moves: behavior can change between releases. 3.1 is the first release meant to be depended on. Until then, treat it as a place to try things out.
8
8
 
9
9
  ## Features
10
10
 
11
11
  * Every array carries a per-element mask for missing values, respected by reductions and statistics
12
12
  * Views compose without copying — a write through the outermost view reaches the source data
13
13
  * MemoryView protocol on both sides: share buffers with other numerical libraries without copying
14
- * Kernel-style iteration: run a Ruby block over each sub-array spanning the axes you choose
15
- * Attach domain meaning (time, angle, quantity with units…) without changing storage — a Face
16
14
  * Define your own array class in pure Ruby while keeping the full CArray interface
17
- * Pack multiple values into one element as a record type
15
+ * Kernel-style iteration: run a Ruby block over each sub-array spanning the axes you choose
16
+ * Faces: array types for time, strings and categories, with methods of their own on top of everything CArray does
18
17
  * Comes with a DataFrame (`CAFrame`) whose columns are plain CArrays, so masks and views keep working on them
19
18
 
20
19
  Each of these is shown, briefly and with a runnable example, in [A tour of the features](docs/FeatureTour.md).
@@ -129,9 +128,9 @@ Bug reports and feature requests are welcome — please open an issue.
129
128
 
130
129
  ## Credits
131
130
 
132
- Up to version 2.0, CArray was authored by himotoyoshi.
131
+ CArray is created and maintained by himotoyoshi.
133
132
 
134
- CArray 3.0 was designed and reviewed by a human developer; the implementation was produced in collaboration with AI coding tools.
133
+ Versions up to 2.0 were written by the author. For version 3.0, the author provided the design, and most of the implementation was rewritten with AI coding tools; it has been verified primarily through the test suite and practical use.
135
134
 
136
135
  ## License
137
136
 
data/carray.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "carray"
3
- s.version = "3.0.1"
3
+ s.version = "3.0.3"
4
4
  s.authors = ["himotoyoshi"]
5
5
  s.email = ["himotoyoshi@users.noreply.github.com"]
6
6
  s.summary = "Multi-dimensional numerical array class for Ruby"
@@ -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
 
@@ -339,13 +340,27 @@ ca_axis_dispatch_scatter_cb (ca_size_t off, int oob, ca_size_t n, void *vctx)
339
340
  /* Callback context for fill_value (broadcast a single value). parent is set
340
341
  when the value goes through the parent's own fill_stride instead of a
341
342
  buffer this side has attached. */
343
+ /* Same size as the window ca_fill_stride_via_addrs collects into. */
344
+ #define CA_AXIS_FILL_ADDR_WINDOW 1024
345
+
342
346
  typedef struct {
343
347
  const void *val;
344
348
  ca_size_t bytes;
345
349
  char *parent_ptr;
346
350
  CArray *parent;
351
+ ca_size_t window[CA_AXIS_FILL_ADDR_WINDOW];
352
+ ca_size_t nw;
347
353
  } ca_axis_fill_ctx_t;
348
354
 
355
+ static void
356
+ ca_axis_dispatch_fill_flush (ca_axis_fill_ctx_t *c)
357
+ {
358
+ if ( c->nw ) {
359
+ ca_fill_addrs(c->parent, c->nw, c->window, (void *) c->val);
360
+ c->nw = 0;
361
+ }
362
+ }
363
+
349
364
  static void
350
365
  ca_axis_dispatch_fill_value_cb (ca_size_t off, int oob, ca_size_t n, void *vctx)
351
366
  {
@@ -354,17 +369,125 @@ ca_axis_dispatch_fill_value_cb (ca_size_t off, int oob, ca_size_t n, void *vctx)
354
369
  if ( c->parent ) {
355
370
  /* One slab is one contiguous run of parent cells, which is a region the
356
371
  parent can fill for itself -- no borrowed buffer, so nothing outside
357
- the run is read or written. */
372
+ the run is read or written. A run of one cell is not worth a call of
373
+ its own, though: when the innermost selected axis picks individual
374
+ indices every run is one cell, and the same cell count that costs the
375
+ parent eight calls on an outer axis cost it one per cell here. Collect
376
+ those and hand them over as a list. The value is the same for every
377
+ cell and the walk visits each cell once, so batching cannot change
378
+ which cells are written. */
358
379
  ca_size_t count = n / c->bytes;
359
- ca_size_t step = 1;
360
- ca_fill_stride(c->parent, off / c->bytes, 1, &count, &step,
361
- (void *) c->val);
380
+ if ( count == 1 ) {
381
+ c->window[c->nw++] = off / c->bytes;
382
+ if ( c->nw == CA_AXIS_FILL_ADDR_WINDOW ) {
383
+ ca_axis_dispatch_fill_flush(c);
384
+ }
385
+ }
386
+ else {
387
+ ca_size_t step = 1;
388
+ ca_fill_stride(c->parent, off / c->bytes, 1, &count, &step,
389
+ (void *) c->val);
390
+ }
362
391
  }
363
392
  else {
364
393
  ca_axis_dispatch_fill_slab(c->parent_ptr + off, c->val, c->bytes, n);
365
394
  }
366
395
  }
367
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
+
368
491
  /* Generic per-slab driver. Walks the (post-merge / post-layout)
369
492
  prefix axes row-major and invokes `cb` once per slab iteration.
370
493
  The all-slab case degenerates to a single `cb` invocation with
@@ -409,6 +532,17 @@ ca_axis_dispatch_for_each_slab (CArray *parent,
409
532
  return;
410
533
  }
411
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
+
412
546
  /* Pre-classify prefix axes once. Inner loop becomes branchless
413
547
  modulo a per-axis kind tag whose value is constant across
414
548
  iters. */
@@ -895,6 +1029,7 @@ ca_axis_dispatch_fill_value_via_parent (CArray *parent,
895
1029
  ca_axis_dispatch_for_each_slab(parent, parent_axis_dims, axes, ndim,
896
1030
  bytes, total_elements,
897
1031
  ca_axis_dispatch_fill_value_cb, &ctx);
1032
+ ca_axis_dispatch_fill_flush(&ctx);
898
1033
  }
899
1034
 
900
1035
  /* ==========================================================================
@@ -922,3 +1057,122 @@ ca_axis_dispatch_outer_has_shift (const ca_axis_desc_t *descs,
922
1057
  }
923
1058
  return 0;
924
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
+ int tag = 0;
1162
+
1163
+ args[0] = ca;
1164
+ args[1] = buf;
1165
+ rb_protect(ca_axis_view_fill_owned, (VALUE) args, &tag);
1166
+ if ( tag ) {
1167
+ xfree(buf);
1168
+ rb_jump_tag(tag);
1169
+ }
1170
+ ca->ptr = buf;
1171
+ }
1172
+
1173
+ void
1174
+ ca_axis_view_sync_owned (void *ap)
1175
+ {
1176
+ CArray *ca = (CArray *) ap;
1177
+ ca_func[ca->obj_type].xfer_all(ca, ca->ptr, CA_XFER_PUT);
1178
+ }