carray 3.0.2 → 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 (218) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +304 -0
  3. data/README.md +3 -4
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +225 -0
  6. data/ext/ca_axis_group.c +177 -99
  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 +66 -71
  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 +663 -214
  14. data/ext/ca_kernel_iterator.h +231 -167
  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 +132 -22
  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 +1 -0
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +96 -25
  25. data/ext/ca_obj_face.c +406 -64
  26. data/ext/ca_obj_face.h +92 -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 +21 -21
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +189 -107
  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 +543 -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 +47 -49
  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 -118
  46. data/ext/ca_obj_stride.c +195 -34
  47. data/ext/ca_obj_string.c +17 -18
  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 +149 -27
  54. data/ext/ca_op_ipower.c +24 -11
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_sort_kernels.h +70 -0
  58. data/ext/ca_sweep_engine.c +102 -79
  59. data/ext/ca_sweep_engine.h +7 -20
  60. data/ext/ca_triop_dispatch.c +4 -1
  61. data/ext/ca_triop_dispatch.h +5 -2
  62. data/ext/caframe_csv_reader.c +463 -0
  63. data/ext/carray.h +70 -27
  64. data/ext/carray_access.c +455 -211
  65. data/ext/carray_address_basis.c +177 -36
  66. data/ext/carray_attribute.c +45 -3
  67. data/ext/carray_bincount.c +32 -2
  68. data/ext/carray_broadcast.c +46 -14
  69. data/ext/carray_call_cfunc.c +0 -28
  70. data/ext/carray_cast.c +1444 -209
  71. data/ext/carray_cast_func.rb +34 -21
  72. data/ext/carray_conversion.c +197 -73
  73. data/ext/carray_copy.c +32 -11
  74. data/ext/carray_core.c +514 -122
  75. data/ext/carray_count.c +140 -87
  76. data/ext/carray_element.c +18 -27
  77. data/ext/carray_factorize.c +569 -277
  78. data/ext/carray_generate.c +76 -40
  79. data/ext/carray_histogram.c +152 -94
  80. data/ext/carray_hold.c +2 -1
  81. data/ext/carray_index_classifier.c +63 -96
  82. data/ext/carray_internal.h +385 -3
  83. data/ext/carray_lazy.c +834 -79
  84. data/ext/carray_loop.c +81 -65
  85. data/ext/carray_mask.c +682 -316
  86. data/ext/carray_math_kernel.h +1 -0
  87. data/ext/carray_median_percentile.c +221 -76
  88. data/ext/carray_memory_view.c +254 -248
  89. data/ext/carray_operator.c +1089 -359
  90. data/ext/carray_order.c +133 -69
  91. data/ext/carray_partition.c +102 -56
  92. data/ext/carray_random.c +273 -239
  93. data/ext/carray_scatter.c +308 -65
  94. data/ext/carray_segment.c +257 -0
  95. data/ext/carray_slab.c +170 -70
  96. data/ext/carray_sort.c +215 -218
  97. data/ext/carray_sort_kernel.c +8 -1
  98. data/ext/carray_struct.c +99 -21
  99. data/ext/carray_test.c +167 -64
  100. data/ext/carray_time_text.c +1182 -0
  101. data/ext/carray_utils.c +363 -98
  102. data/ext/extconf.rb +27 -2
  103. data/ext/mk_call_cfunc.rb +0 -2
  104. data/ext/mk_pow5_table.rb +35 -0
  105. data/ext/mkkernel.rb +1076 -846
  106. data/ext/ruby_carray.c +7 -1
  107. data/ext/version.h +4 -4
  108. data/ext/version.rb +4 -2
  109. data/lib/carray/attribute.rb +39 -0
  110. data/lib/carray/autoload_carray.rb +19 -0
  111. data/lib/carray/autoload_method_extension.rb +6 -0
  112. data/lib/carray/axis_group.rb +174 -26
  113. data/lib/carray/basics.rb +91 -25
  114. data/lib/carray/bincount_nd.rb +6 -0
  115. data/lib/carray/block_iterator.rb +118 -48
  116. data/lib/carray/boolean_reduce.rb +21 -29
  117. data/lib/carray/categorical.rb +94 -26
  118. data/lib/carray/categorical_iterator.rb +333 -826
  119. data/lib/carray/complex.rb +36 -29
  120. data/lib/carray/conditional.rb +94 -7
  121. data/lib/carray/const_string.rb +46 -0
  122. data/lib/carray/frame/concat.rb +157 -6
  123. data/lib/carray/frame/convert.rb +13 -7
  124. data/lib/carray/frame/csv_parser.rb +589 -82
  125. data/lib/carray/frame/describe.rb +79 -0
  126. data/lib/carray/frame/frame.rb +124 -25
  127. data/lib/carray/frame/group.rb +189 -63
  128. data/lib/carray/frame/io.rb +412 -72
  129. data/lib/carray/frame/join.rb +134 -46
  130. data/lib/carray/frame/records.rb +37 -16
  131. data/lib/carray/frame/reshape.rb +448 -0
  132. data/lib/carray/frame/sort.rb +26 -2
  133. data/lib/carray/frame/verbs.rb +715 -48
  134. data/lib/carray/frame.rb +2 -0
  135. data/lib/carray/fuse_source.rb +111 -2
  136. data/lib/carray/fusion.rb +229 -38
  137. data/lib/carray/inspect.rb +29 -11
  138. data/lib/carray/iterator.rb +14 -2
  139. data/lib/carray/lazy.rb +54 -30
  140. data/lib/carray/mask_gap_fill.rb +66 -52
  141. data/lib/carray/math.rb +32 -19
  142. data/lib/carray/meld_reduce.rb +40 -7
  143. data/lib/carray/methods/align_addr.rb +8 -4
  144. data/lib/carray/methods/bincount.rb +2 -2
  145. data/lib/carray/methods/bit_string.rb +14 -3
  146. data/lib/carray/methods/composition.rb +16 -10
  147. data/lib/carray/methods/factorize.rb +2 -2
  148. data/lib/carray/methods/gather_nd.rb +13 -2
  149. data/lib/carray/methods/insert_block.rb +9 -14
  150. data/lib/carray/methods/is_in.rb +117 -4
  151. data/lib/carray/methods/join.rb +1 -1
  152. data/lib/carray/methods/locate_addr.rb +177 -36
  153. data/lib/carray/methods/mode.rb +18 -1
  154. data/lib/carray/methods/repeat.rb +1 -20
  155. data/lib/carray/methods/resize.rb +21 -23
  156. data/lib/carray/methods/snap.rb +34 -12
  157. data/lib/carray/methods/unique.rb +11 -2
  158. data/lib/carray/record_order.rb +208 -0
  159. data/lib/carray/runtime.rb +14 -11
  160. data/lib/carray/segment_iterator.rb +990 -0
  161. data/lib/carray/serialize.rb +197 -27
  162. data/lib/carray/slab_iterator.rb +51 -27
  163. data/lib/carray/stack.rb +10 -4
  164. data/lib/carray/string_operation_extension.rb +4 -3
  165. data/lib/carray/struct.rb +142 -51
  166. data/lib/carray/struct_builder.rb +110 -14
  167. data/lib/carray/table.rb +2 -2
  168. data/lib/carray/time.rb +517 -103
  169. data/lib/carray/window_iterator.rb +127 -72
  170. data/lib/carray.rb +2 -2
  171. data/yard-stubs/ca_obj_array.rb +4 -4
  172. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  173. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  174. data/yard-stubs/ca_obj_fake.rb +1 -1
  175. data/yard-stubs/ca_obj_field.rb +1 -1
  176. data/yard-stubs/ca_obj_refer.rb +3 -3
  177. data/yard-stubs/ca_obj_roll.rb +0 -1
  178. data/yard-stubs/ca_obj_stride.rb +10 -7
  179. data/yard-stubs/ca_obj_transpose.rb +1 -1
  180. data/yard-stubs/ca_obj_window.rb +1 -2
  181. data/yard-stubs/carray_access.rb +5 -4
  182. data/yard-stubs/carray_broadcast.rb +1 -1
  183. data/yard-stubs/carray_cast.rb +78 -43
  184. data/yard-stubs/carray_conversion.rb +13 -1
  185. data/yard-stubs/carray_copy.rb +8 -3
  186. data/yard-stubs/carray_core.rb +3 -3
  187. data/yard-stubs/carray_count.rb +9 -0
  188. data/yard-stubs/carray_lazy.rb +5 -1
  189. data/yard-stubs/carray_loop.rb +4 -1
  190. data/yard-stubs/carray_mask.rb +34 -10
  191. data/yard-stubs/carray_math.rb +25 -13
  192. data/yard-stubs/carray_median_percentile.rb +10 -6
  193. data/yard-stubs/carray_order.rb +34 -13
  194. data/yard-stubs/carray_scatter.rb +10 -3
  195. data/yard-stubs/carray_segment.rb +72 -0
  196. data/yard-stubs/carray_slab.rb +2 -1
  197. data/yard-stubs/carray_sort.rb +43 -3
  198. data/yard-stubs/carray_test.rb +10 -0
  199. data/yard-stubs/carray_utils.rb +0 -26
  200. metadata +11 -19
  201. data/ext/ca_for_each_element.h +0 -239
  202. data/ext/carray_build_flags.h +0 -3
  203. data/ext/carray_config.h +0 -28
  204. data/ext/carray_kernels_bincmp.c +0 -4446
  205. data/ext/carray_kernels_binop.c +0 -11001
  206. data/ext/carray_kernels_init.c +0 -1131
  207. data/ext/carray_kernels_map.c +0 -3467
  208. data/ext/carray_kernels_moncmp.c +0 -2097
  209. data/ext/carray_kernels_monop.c +0 -18313
  210. data/ext/carray_kernels_reduce_aggregate.c +0 -26005
  211. data/ext/carray_kernels_reduce_boolean.c +0 -330
  212. data/ext/carray_kernels_reduce_cumulative.c +0 -14862
  213. data/ext/carray_kernels_reduce_extreme.c +0 -17494
  214. data/ext/carray_kernels_reduce_variance.c +0 -3910
  215. data/ext/carray_kernels_scan.c +0 -3693
  216. data/ext/carray_kernels_search.c +0 -32218
  217. data/ext/carray_kernels_sort.c +0 -10626
  218. data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_obj_meld.c CHANGED
@@ -25,7 +25,7 @@
25
25
  (sortedness-aware O(n+K) merge is a future
26
26
  optimisation, memo §7.3)
27
27
  fill_data: K-fold ca_fill
28
- create_mask: horizontal propagation (mirrors CAStack)
28
+ create_mask: mask CAMeld over the parents' masks (mirrors CAStack)
29
29
  fold_stride: decline (return 0)
30
30
 
31
31
  Design ref: devel/MEMO_CAMELD_SEGMENT_MAJOR_ENGINE.md. Meld-axis reduce
@@ -39,7 +39,7 @@
39
39
  ---------------------------------------------------------------------------- */
40
40
 
41
41
  #include "carray.h"
42
- #include "carray_internal.h" /* ca_attach_all */
42
+ #include "carray_internal.h" /* ca_attach_all / ca_sync_all */
43
43
  #include "ca_obj_face.h" /* ca_face_state_portable */
44
44
 
45
45
  /* ------------------------------------------------------------------- */
@@ -112,9 +112,9 @@ ca_meld_check_uniform (int32_t n_parents, CArray **parents, int8_t meld_axis)
112
112
  CArray *p = parents[i];
113
113
  if ( p->data_type != ref->data_type ) {
114
114
  rb_raise(rb_eArgError,
115
- "CAMeld parents must have uniform data_type "
116
- "(parent[0]=%d, parent[%d]=%d)",
117
- ref->data_type, i, p->data_type);
115
+ "meld: the arrays must have the same data type "
116
+ "(array 0 is %s, array %d is %s)",
117
+ ca_type_name[ref->data_type], i, ca_type_name[p->data_type]);
118
118
  }
119
119
  if ( p->ndim != ref->ndim ) {
120
120
  rb_raise(rb_eArgError,
@@ -181,6 +181,8 @@ ca_meld_setup (CAMeld *ca, int32_t n_parents, CArray **parents, int8_t meld_axis
181
181
  ca->attach = 0;
182
182
  ca->nosync = 0;
183
183
 
184
+ ca->mask_standins = NULL;
185
+ ca->mask_owner = NULL;
184
186
  ca->n_parents = n_parents;
185
187
  ca->parents = ALLOC_N(CArray *, n_parents);
186
188
  for ( i = 0; i < n_parents; i++ ) {
@@ -224,6 +226,13 @@ free_ca_meld (void *ap)
224
226
  CAMeld *ca = (CAMeld *) ap;
225
227
  if ( ca != NULL ) {
226
228
  ca_free(ca->mask);
229
+ if ( ca->mask_standins ) {
230
+ int32_t k;
231
+ for ( k = 0; k < ca->n_parents; k++ ) {
232
+ if ( ca->mask_standins[k] ) ca_free(ca->mask_standins[k]);
233
+ }
234
+ xfree(ca->mask_standins);
235
+ }
227
236
  xfree(ca->seg_offset);
228
237
  xfree(ca->parents);
229
238
  xfree(ca->dim);
@@ -273,10 +282,33 @@ ca_meld_tail_elements (const CAMeld *ca)
273
282
 
274
283
  /* view[..., v at meld_axis, ...] = parents[k][..., v - seg_offset[k], ...]
275
284
  where k = segment_of(v). */
285
+ /* On the mask of a CAMeld: let its stand-ins give way to the parents' own
286
+ masks (see ca_multi_parent_mask_refresh). */
287
+ static void
288
+ ca_meld_mask_refresh (CAMeld *ca, int for_write)
289
+ {
290
+ CAMeld *o = (CAMeld *) ca->mask_owner;
291
+ if ( o != NULL ) {
292
+ ca_multi_parent_mask_refresh((CArray *) ca, o->parents, o->mask_standins,
293
+ o->n_parents, for_write);
294
+ }
295
+ }
296
+
297
+ static void
298
+ ca_meld_mask_settle (CAMeld *ca)
299
+ {
300
+ CAMeld *o = (CAMeld *) ca->mask_owner;
301
+ if ( o != NULL ) {
302
+ ca_multi_parent_mask_settle((CArray *) ca, o->parents, o->mask_standins,
303
+ o->n_parents);
304
+ }
305
+ }
306
+
276
307
  static void
277
308
  ca_meld_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
278
309
  {
279
310
  CAMeld *ca = (CAMeld *) ap;
311
+ ca_meld_mask_refresh(ca, dir == CA_XFER_PUT);
280
312
  int8_t ma = ca->meld_axis;
281
313
  ca_size_t v = idx[ma];
282
314
  int32_t k;
@@ -311,6 +343,7 @@ ca_meld_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
311
343
  void *data, int dir)
312
344
  {
313
345
  CAMeld *ca = (CAMeld *) ap;
346
+ ca_meld_mask_refresh(ca, dir == CA_XFER_PUT);
314
347
  int8_t ma = ca->meld_axis;
315
348
  ca_size_t bytes = ca->bytes;
316
349
  ca_size_t view_div[CA_RANK_MAX]; /* row-major divisor per view axis */
@@ -606,7 +639,9 @@ static void
606
639
  ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
607
640
  ca_size_t *strides, void *data, int dir)
608
641
  {
642
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
609
643
  CAMeld *ca = (CAMeld *) ap;
644
+ ca_meld_mask_refresh(ca, dir == CA_XFER_PUT);
610
645
  int8_t ma = ca->meld_axis;
611
646
  ca_size_t native[CA_RANK_MAX];
612
647
  ca_size_t s;
@@ -616,31 +651,27 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
616
651
  s = ca->bytes;
617
652
  for ( i = ca->ndim - 1; i >= 0; i-- ) { native[i] = s; s *= ca->dim[i]; }
618
653
 
654
+ /* Structural iff strides == native and the request is a box over the
655
+ view's own axes. Equal strides alone are not enough: a size-1 axis
656
+ gives two axes the same native stride, and a flat window reshaped back
657
+ to ndim has native strides yet wraps across an axis. The request is
658
+ over the view's addresses; see ca_xfer_stride_request_is_axis_box
659
+ (carray.h). Inside the gate the step on every axis is 1 and the region
660
+ stays inside each axis, which ca_meld_xfer_stride_ma_internal (handed
661
+ no strides) depends on. */
619
662
  for ( i = 0; i < ca->ndim; i++ ) {
620
663
  if ( strides[i] != native[i] ) { structural = 0; break; }
621
664
  }
665
+ if ( structural &&
666
+ ! ca_xfer_stride_request_is_axis_box(ca, starts, counts, strides) ) {
667
+ structural = 0;
668
+ }
622
669
 
623
- if ( ! structural ) {
670
+ if ( ! structural || ! ca_fast_paths_enabled() ) {
624
671
  ca_meld_xfer_stride_per_cell(ca, starts, counts, strides, data, dir);
625
672
  return;
626
673
  }
627
674
 
628
- /* Bound check on meld_axis, after the gate and not before it. Only once
629
- strides == native is established does request axis ma mean view axis ma;
630
- asked earlier, strides[ma] / native[ma] is not a step along the meld axis
631
- and legal requests get rejected. Inside the gate the step is 1, so the
632
- region is starts[ma] .. starts[ma] + counts[ma]. ca_meld_xfer_stride_ma_
633
- internal below is handed no strides at all and depends on both facts. */
634
- {
635
- ca_size_t req_lo = starts[ma];
636
- ca_size_t req_hi = starts[ma] + counts[ma];
637
- if ( counts[ma] > 0 && ( req_lo < 0 || req_hi > ca->dim[ma] ) ) {
638
- rb_raise(rb_eIndexError,
639
- "CAMeld xfer_stride meld_axis (axis %d) [%lld, %lld) out of range [0, %lld)",
640
- (int) ma, (long long) req_lo, (long long) req_hi, (long long) ca->dim[ma]);
641
- }
642
- }
643
-
644
675
  if ( ma == 0 ) {
645
676
  ca_meld_xfer_stride_ma0(ca, starts, counts, strides, data, dir);
646
677
  } else {
@@ -652,15 +683,37 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
652
683
  /* xfer_all */
653
684
  /* ------------------------------------------------------------------- */
654
685
 
686
+ /* A parent's cells, delivered (PUT). into_buffers writes them into the
687
+ buffer the parent's attach handed out, rather than through the parent to
688
+ what is behind it: the sync of an attached meld, which then syncs each
689
+ parent. Writing past the buffer would leave it stale, and the parent's
690
+ own sync would push the stale buffer back over the cells just written. */
691
+ static void
692
+ ca_meld_put_parent (CArray *p, char *src, int into_buffers)
693
+ {
694
+ if ( into_buffers ) {
695
+ memcpy(p->ptr, src, (size_t) (p->elements * p->bytes));
696
+ }
697
+ else {
698
+ ca_xfer_all(p, src, CA_XFER_PUT);
699
+ }
700
+ }
701
+
655
702
  /* meld_axis == 0 best path: K contig xfer_all at prefix-sum offsets. */
656
703
  static void
657
- ca_meld_xfer_all_ma0 (CAMeld *ca, void *data, int dir)
704
+ ca_meld_xfer_all_ma0 (CAMeld *ca, void *data, int dir, int into_buffers)
658
705
  {
659
706
  ca_size_t tail_bytes = ca_meld_tail_elements(ca) * ca->bytes;
660
707
  char *d = (char *) data;
661
708
  int32_t k;
662
709
  for ( k = 0; k < ca->n_parents; k++ ) {
663
- ca_xfer_all(ca->parents[k], d + ca->seg_offset[k] * tail_bytes, dir);
710
+ char *seg = d + ca->seg_offset[k] * tail_bytes;
711
+ if ( dir == CA_XFER_PUT ) {
712
+ ca_meld_put_parent(ca->parents[k], seg, into_buffers);
713
+ }
714
+ else {
715
+ ca_xfer_all(ca->parents[k], seg, dir);
716
+ }
664
717
  }
665
718
  }
666
719
 
@@ -677,7 +730,8 @@ ca_meld_xfer_all_ma0 (CAMeld *ca, void *data, int dir)
677
730
  The naive per-cell odometer that this replaces cost ~2x eager on M2;
678
731
  chunked memcpy approaches memcpy bandwidth (eager parity target). */
679
732
  static void
680
- ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir)
733
+ ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir,
734
+ int into_buffers)
681
735
  {
682
736
  int8_t ma = ca->meld_axis;
683
737
  int8_t ndim = ca->ndim;
@@ -762,23 +816,29 @@ ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir)
762
816
  }
763
817
 
764
818
  if ( dir == CA_XFER_PUT ) {
765
- ca_xfer_all(p, buf, CA_XFER_PUT);
819
+ ca_meld_put_parent(p, buf, into_buffers);
766
820
  }
767
821
  ALLOCV_END(holder);
768
822
  }
769
823
  }
770
824
 
771
825
  static void
772
- ca_meld_func_xfer_all (void *ap, void *data, int dir)
826
+ ca_meld_xfer_parents (CAMeld *ca, void *data, int dir, int into_buffers)
773
827
  {
774
- CAMeld *ca = (CAMeld *) ap;
775
- if ( ca->meld_axis == 0 ) {
776
- ca_meld_xfer_all_ma0(ca, data, dir);
828
+ if ( ca->meld_axis == 0 && ca_fast_paths_enabled() ) {
829
+ ca_meld_xfer_all_ma0(ca, data, dir, into_buffers);
777
830
  } else {
778
- ca_meld_xfer_all_ma_internal(ca, data, dir);
831
+ ca_meld_xfer_all_ma_internal(ca, data, dir, into_buffers);
779
832
  }
780
833
  }
781
834
 
835
+ static void
836
+ ca_meld_func_xfer_all (void *ap, void *data, int dir)
837
+ {
838
+ ca_meld_mask_refresh((CAMeld *) ap, dir == CA_XFER_PUT);
839
+ ca_meld_xfer_parents((CAMeld *) ap, data, dir, 0);
840
+ }
841
+
782
842
  /* ------------------------------------------------------------------- */
783
843
  /* attach / sync / detach */
784
844
  /* ------------------------------------------------------------------- */
@@ -787,28 +847,42 @@ static void
787
847
  ca_meld_func_allocate (void *ap)
788
848
  {
789
849
  CAMeld *ca = (CAMeld *) ap;
850
+ ca_meld_mask_refresh(ca, 0);
790
851
  ca_attach_all(ca->parents, ca->n_parents);
791
852
  ca->ptr = xmalloc(ca_length(ca));
792
853
  }
793
854
 
855
+ static VALUE
856
+ ca_meld_attach_owned (VALUE arg)
857
+ {
858
+ ca_axis_view_attach_owned((void *) arg);
859
+ return Qnil;
860
+ }
861
+
794
862
  static void
795
863
  ca_meld_func_attach (void *ap)
796
864
  {
797
865
  CAMeld *ca = (CAMeld *) ap;
866
+ ca_meld_mask_refresh(ca, 0);
867
+ int32_t k;
868
+ int tag = 0;
798
869
  ca_attach_all(ca->parents, ca->n_parents);
799
- ca->ptr = xmalloc(ca_length(ca));
800
- ca_meld_func_xfer_all(ca, ca->ptr, CA_XFER_GET);
870
+ rb_protect(ca_meld_attach_owned, (VALUE) ca, &tag);
871
+ if ( tag ) {
872
+ for ( k = 0; k < ca->n_parents; k++ ) {
873
+ ca_detach(ca->parents[k]);
874
+ }
875
+ rb_jump_tag(tag);
876
+ }
801
877
  }
802
878
 
803
879
  static void
804
880
  ca_meld_func_sync (void *ap)
805
881
  {
806
882
  CAMeld *ca = (CAMeld *) ap;
807
- int32_t k;
808
- ca_meld_func_xfer_all(ca, ca->ptr, CA_XFER_PUT);
809
- for ( k = 0; k < ca->n_parents; k++ ) {
810
- ca_sync(ca->parents[k]);
811
- }
883
+ ca_meld_xfer_parents(ca, ca->ptr, CA_XFER_PUT, 1);
884
+ ca_sync_all(ca->parents, ca->n_parents);
885
+ ca_meld_mask_settle(ca);
812
886
  }
813
887
 
814
888
  static void
@@ -831,6 +905,7 @@ static void
831
905
  ca_meld_func_fill_data (void *ap, void *ptr)
832
906
  {
833
907
  CAMeld *ca = (CAMeld *) ap;
908
+ ca_meld_mask_refresh(ca, 1);
834
909
  int32_t k;
835
910
  for ( k = 0; k < ca->n_parents; k++ ) {
836
911
  ca_fill(ca->parents[k], ptr);
@@ -838,7 +913,7 @@ ca_meld_func_fill_data (void *ap, void *ptr)
838
913
  }
839
914
 
840
915
  /* ------------------------------------------------------------------- */
841
- /* create_mask (horizontal propagation, mirrors CAStack) */
916
+ /* create_mask (mirrors CAStack) */
842
917
  /* ------------------------------------------------------------------- */
843
918
 
844
919
  static void
@@ -850,14 +925,16 @@ ca_meld_func_create_mask (void *ap)
850
925
  int32_t k;
851
926
 
852
927
  mask_parents = ALLOCV_N(CArray *, holder, ca->n_parents);
928
+ if ( ! ca->mask_standins ) {
929
+ ca->mask_standins = ALLOC_N(CArray *, ca->n_parents);
930
+ MEMZERO(ca->mask_standins, CArray *, ca->n_parents);
931
+ }
853
932
  for ( k = 0; k < ca->n_parents; k++ ) {
854
- ca_update_mask(ca->parents[k]);
855
- if ( ! ca->parents[k]->mask ) {
856
- ca_create_mask(ca->parents[k]);
857
- }
858
- mask_parents[k] = ca->parents[k]->mask;
933
+ mask_parents[k] = ca_multi_parent_mask(ca->parents[k],
934
+ &ca->mask_standins[k]);
859
935
  }
860
936
  ca->mask = (CArray *) ca_meld_new(ca->n_parents, mask_parents, ca->meld_axis);
937
+ ((CAMeld *) ca->mask)->mask_owner = (CArray *) ca;
861
938
  ALLOCV_END(holder);
862
939
  }
863
940
 
@@ -876,6 +953,56 @@ ca_meld_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
876
953
  /* operation table */
877
954
  /* ------------------------------------------------------------------- */
878
955
 
956
+ /* The table's write slots: after a write, refuse a true that reached the
957
+ stand-in of a value array or a mask array (ca_multi_parent_mask_check).
958
+ Only the mask of a CAMeld has stand-ins to check. */
959
+ static void
960
+ ca_meld_mask_check (CAMeld *ca)
961
+ {
962
+ CAMeld *o = (CAMeld *) ca->mask_owner;
963
+ if ( o != NULL ) {
964
+ ca_multi_parent_mask_check((CArray *) ca, o->parents, o->mask_standins,
965
+ o->n_parents);
966
+ }
967
+ }
968
+
969
+ static void
970
+ ca_meld_put_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
971
+ {
972
+ ca_meld_func_xfer_index(ap, idx, data, dir);
973
+ if ( dir == CA_XFER_PUT ) ca_meld_mask_check((CAMeld *) ap);
974
+ }
975
+
976
+ static void
977
+ ca_meld_put_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *data,
978
+ int dir)
979
+ {
980
+ ca_meld_func_xfer_addrs(ap, n, addrs, data, dir);
981
+ if ( dir == CA_XFER_PUT ) ca_meld_mask_check((CAMeld *) ap);
982
+ }
983
+
984
+ static void
985
+ ca_meld_put_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
986
+ ca_size_t *strides, void *data, int dir)
987
+ {
988
+ ca_meld_func_xfer_stride(ap, starts, counts, strides, data, dir);
989
+ if ( dir == CA_XFER_PUT ) ca_meld_mask_check((CAMeld *) ap);
990
+ }
991
+
992
+ static void
993
+ ca_meld_put_xfer_all (void *ap, void *data, int dir)
994
+ {
995
+ ca_meld_func_xfer_all(ap, data, dir);
996
+ if ( dir == CA_XFER_PUT ) ca_meld_mask_check((CAMeld *) ap);
997
+ }
998
+
999
+ static void
1000
+ ca_meld_put_fill_data (void *ap, void *ptr)
1001
+ {
1002
+ ca_meld_func_fill_data(ap, ptr);
1003
+ ca_meld_mask_check((CAMeld *) ap);
1004
+ }
1005
+
879
1006
  ca_operation_function_t ca_meld_func = {
880
1007
  -1, /* CA_OBJ_MELD */
881
1008
  CA_VIEW_ARRAY,
@@ -885,30 +1012,19 @@ ca_operation_function_t ca_meld_func = {
885
1012
  ca_meld_func_attach,
886
1013
  ca_meld_func_sync,
887
1014
  ca_meld_func_detach,
888
- ca_meld_func_fill_data,
1015
+ ca_meld_put_fill_data,
889
1016
  ca_meld_func_create_mask,
890
- ca_meld_func_xfer_index,
891
- ca_meld_func_xfer_addrs,
1017
+ ca_meld_put_xfer_index,
1018
+ ca_meld_put_xfer_addrs,
892
1019
  ca_meld_func_fold_stride,
893
- ca_meld_func_xfer_stride,
894
- ca_meld_func_xfer_all,
1020
+ ca_meld_put_xfer_stride,
1021
+ ca_meld_put_xfer_all,
895
1022
  };
896
1023
 
897
1024
  /* ------------------------------------------------------------------- */
898
1025
  /* Ruby surface */
899
1026
  /* ------------------------------------------------------------------- */
900
1027
 
901
- /* One-level strip of a Face VALUE to its storage-side parent (non-Face as-is).
902
- Keeps the @parent ivar in step with the pre-stripped C parents, so the
903
- Ruby-visible chain of a melded Face is single-Face too. */
904
- static VALUE
905
- ca_meld_face_parent1 (VALUE v)
906
- {
907
- CArray *c;
908
- TypedData_Get_Struct(v, CArray, &carray_data_type, c);
909
- return ca_is_face(c) ? rb_ca_parent(v) : v;
910
- }
911
-
912
1028
  VALUE
913
1029
  rb_ca_meld_new (VALUE parents_ary, int8_t meld_axis)
914
1030
  {
@@ -932,7 +1048,7 @@ rb_ca_meld_new (VALUE parents_ary, int8_t meld_axis)
932
1048
  ca = ca_meld_new((int32_t) n, parents, meld_axis);
933
1049
  obj = ca_wrap_struct(ca);
934
1050
  rb_ivar_set(obj, id_parents, rb_ary_dup(parents_ary));
935
- rb_ca_set_parent(obj, ca_meld_face_parent1(rb_ary_entry(parents_ary, 0)));
1051
+ rb_ca_set_parent(obj, ca_face_strip_one(rb_ary_entry(parents_ary, 0)));
936
1052
  ALLOCV_END(holder);
937
1053
  return obj;
938
1054
  }
@@ -949,8 +1065,14 @@ rb_ca_meld_initialize_copy (VALUE self, VALUE other)
949
1065
  {
950
1066
  CAMeld *ca, *cs;
951
1067
  TypedData_Get_Struct(self, CAMeld, &cameld_data_type, ca);
1068
+ ca_check_uninitialized(ca);
952
1069
  TypedData_Get_Struct(other, CAMeld, &cameld_data_type, cs);
953
1070
  ca_meld_setup(ca, cs->n_parents, cs->parents, cs->meld_axis);
1071
+ /* A copy of a meld's mask reads and writes the same stand-ins, so it
1072
+ answers to the same owner: its writes reach the parents' masks. The
1073
+ copy holds the owner alive through the masked_array ivar that dup
1074
+ carries over (see rb_ca_mask_array). */
1075
+ ca->mask_owner = cs->mask_owner;
954
1076
  return self;
955
1077
  }
956
1078
 
@@ -981,6 +1103,7 @@ rb_ca_meld_initialize (int argc, VALUE *argv, VALUE self)
981
1103
  NUM2LONG(axis_val), (int) ref->ndim, "CAMeld.new");
982
1104
  }
983
1105
  TypedData_Get_Struct(self, CAMeld, &cameld_data_type, ca);
1106
+ ca_check_uninitialized(ca);
984
1107
  parents = ALLOCV_N(CArray *, holder, n);
985
1108
  for ( i = 0; i < n; i++ ) {
986
1109
  VALUE p = rb_ary_entry(list, i);
@@ -989,7 +1112,7 @@ rb_ca_meld_initialize (int argc, VALUE *argv, VALUE self)
989
1112
  }
990
1113
  ca_meld_setup(ca, (int32_t) n, parents, meld_axis);
991
1114
  rb_ivar_set(self, id_parents, rb_ary_dup(list));
992
- rb_ca_set_parent(self, ca_meld_face_parent1(rb_ary_entry(list, 0)));
1115
+ rb_ca_set_parent(self, ca_face_strip_one(rb_ary_entry(list, 0)));
993
1116
  ALLOCV_END(holder);
994
1117
  return self;
995
1118
  }
@@ -1011,61 +1134,20 @@ rb_ca_meld_initialize (int argc, VALUE *argv, VALUE self)
1011
1134
  static VALUE
1012
1135
  rb_ca_meld_s_new (int argc, VALUE *argv, VALUE klass)
1013
1136
  {
1014
- VALUE list, kwargs;
1015
- long n, i;
1016
- int all_face = 1;
1017
- VALUE face_class = Qnil;
1018
- CArray *ref_face = NULL;
1137
+ VALUE list, kwargs, face_class;
1019
1138
  VALUE obj;
1020
1139
 
1021
1140
  rb_scan_args(argc, argv, "1:", &list, &kwargs);
1022
1141
  Check_Type(list, T_ARRAY);
1023
- n = RARRAY_LEN(list);
1024
- if ( n <= 0 ) {
1142
+ if ( RARRAY_LEN(list) <= 0 ) {
1025
1143
  rb_raise(rb_eArgError, "CAMeld.new requires at least one parent");
1026
1144
  }
1027
-
1028
- for ( i = 0; i < n; i++ ) {
1029
- VALUE p = rb_ary_entry(list, i);
1030
- CArray *ca;
1031
- rb_check_carray_object(p);
1032
- TypedData_Get_Struct(p, CArray, &carray_data_type, ca);
1033
- if ( !ca_is_face(ca) ) { all_face = 0; break; }
1034
- if ( i == 0 ) {
1035
- face_class = rb_obj_class(p);
1036
- ref_face = ca;
1037
- } else if ( rb_obj_class(p) != face_class ) {
1038
- all_face = 0; break;
1039
- }
1040
- }
1041
-
1042
- /* A single parent has nothing to weld against, so its Face rides the
1043
- chain as it always did; refuse and lift only apply from two up. */
1044
- if ( all_face && n > 1
1045
- && !ca_face_state_portable(ref_face->obj_type, face_class) ) {
1046
- rb_raise(rb_eArgError,
1047
- "CAMeld.new: %s state is not portable across multiple "
1048
- "parents (= per-parent storage like CAConstString's buffer); "
1049
- "strip Face with .parent if a storage-level CAMeld is intended",
1050
- rb_class2name(face_class));
1051
- }
1145
+ face_class = ca_face_list_class(list, "CAMeld.new");
1052
1146
 
1053
1147
  obj = rb_obj_alloc(klass);
1054
1148
  rb_obj_call_init_kw(obj, argc, argv, RB_PASS_CALLED_KEYWORDS);
1055
1149
 
1056
- if ( !all_face || n < 2 ) return obj;
1057
-
1058
- for ( i = 1; i < n; i++ ) {
1059
- VALUE p = rb_ary_entry(list, i);
1060
- CArray *ca;
1061
- TypedData_Get_Struct(p, CArray, &carray_data_type, ca);
1062
- if ( !ca_face_state_compatible(rb_ary_entry(list, 0), ref_face, p, ca) ) {
1063
- rb_raise(rb_eArgError,
1064
- "CAMeld.new: Face state mismatch across parents "
1065
- "(= %s instance at index %ld differs in state from index 0)",
1066
- rb_class2name(face_class), i);
1067
- }
1068
- }
1150
+ if ( NIL_P(face_class) ) return obj;
1069
1151
  return ca_face_lift(obj, rb_ary_entry(list, 0));
1070
1152
  }
1071
1153