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/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,6 +39,8 @@
39
39
  ---------------------------------------------------------------------------- */
40
40
 
41
41
  #include "carray.h"
42
+ #include "carray_internal.h" /* ca_attach_all / ca_sync_all */
43
+ #include "ca_obj_face.h" /* ca_face_state_portable */
42
44
 
43
45
  /* ------------------------------------------------------------------- */
44
46
  /* TypedData */
@@ -110,9 +112,9 @@ ca_meld_check_uniform (int32_t n_parents, CArray **parents, int8_t meld_axis)
110
112
  CArray *p = parents[i];
111
113
  if ( p->data_type != ref->data_type ) {
112
114
  rb_raise(rb_eArgError,
113
- "CAMeld parents must have uniform data_type "
114
- "(parent[0]=%d, parent[%d]=%d)",
115
- 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]);
116
118
  }
117
119
  if ( p->ndim != ref->ndim ) {
118
120
  rb_raise(rb_eArgError,
@@ -150,6 +152,19 @@ ca_meld_setup (CAMeld *ca, int32_t n_parents, CArray **parents, int8_t meld_axis
150
152
  int32_t i;
151
153
  int8_t a;
152
154
 
155
+ /* Pre-strip Face parents one level to storage, as CAStack does, so a
156
+ melded Face lifts to a single-Face chain (CATime[CAMeld[entity, ...]])
157
+ rather than a Face sitting on Face parents. One level, not a full walk,
158
+ preserves any distinct Face a parent melded underneath. A Face is
159
+ storage-transparent, so welding over storage reads the same bytes; the
160
+ lifted top Face (rb_ca_meld_s_new) carries the identity. The @parents
161
+ accessor keeps the originals, which the callers set. */
162
+ for ( i = 0; i < n_parents; i++ ) {
163
+ if ( ca_is_face(parents[i]) ) {
164
+ parents[i] = CAVIEW(parents[i])->parent;
165
+ }
166
+ }
167
+
153
168
  ca_meld_check_uniform(n_parents, parents, meld_axis);
154
169
  ref = parents[0];
155
170
 
@@ -166,6 +181,8 @@ ca_meld_setup (CAMeld *ca, int32_t n_parents, CArray **parents, int8_t meld_axis
166
181
  ca->attach = 0;
167
182
  ca->nosync = 0;
168
183
 
184
+ ca->mask_standins = NULL;
185
+ ca->mask_owner = NULL;
169
186
  ca->n_parents = n_parents;
170
187
  ca->parents = ALLOC_N(CArray *, n_parents);
171
188
  for ( i = 0; i < n_parents; i++ ) {
@@ -209,6 +226,13 @@ free_ca_meld (void *ap)
209
226
  CAMeld *ca = (CAMeld *) ap;
210
227
  if ( ca != NULL ) {
211
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
+ }
212
236
  xfree(ca->seg_offset);
213
237
  xfree(ca->parents);
214
238
  xfree(ca->dim);
@@ -258,10 +282,33 @@ ca_meld_tail_elements (const CAMeld *ca)
258
282
 
259
283
  /* view[..., v at meld_axis, ...] = parents[k][..., v - seg_offset[k], ...]
260
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
+
261
307
  static void
262
308
  ca_meld_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
263
309
  {
264
310
  CAMeld *ca = (CAMeld *) ap;
311
+ ca_meld_mask_refresh(ca, dir == CA_XFER_PUT);
265
312
  int8_t ma = ca->meld_axis;
266
313
  ca_size_t v = idx[ma];
267
314
  int32_t k;
@@ -296,6 +343,7 @@ ca_meld_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
296
343
  void *data, int dir)
297
344
  {
298
345
  CAMeld *ca = (CAMeld *) ap;
346
+ ca_meld_mask_refresh(ca, dir == CA_XFER_PUT);
299
347
  int8_t ma = ca->meld_axis;
300
348
  ca_size_t bytes = ca->bytes;
301
349
  ca_size_t view_div[CA_RANK_MAX]; /* row-major divisor per view axis */
@@ -591,7 +639,9 @@ static void
591
639
  ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
592
640
  ca_size_t *strides, void *data, int dir)
593
641
  {
642
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
594
643
  CAMeld *ca = (CAMeld *) ap;
644
+ ca_meld_mask_refresh(ca, dir == CA_XFER_PUT);
595
645
  int8_t ma = ca->meld_axis;
596
646
  ca_size_t native[CA_RANK_MAX];
597
647
  ca_size_t s;
@@ -601,29 +651,27 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
601
651
  s = ca->bytes;
602
652
  for ( i = ca->ndim - 1; i >= 0; i-- ) { native[i] = s; s *= ca->dim[i]; }
603
653
 
604
- /* Bound check on meld_axis. The step along the axis is strides[ma] /
605
- native[ma] and it can be negative -- a reversed read starts at the far
606
- end and walks down -- so the region runs between the first and last
607
- index, which is not the same as starts[ma] .. starts[ma] + counts[ma]. */
608
- {
609
- ca_size_t step = strides[ma] / native[ma];
610
- ca_size_t last = starts[ma] + (counts[ma] - 1) * step;
611
- ca_size_t req_lo = ( last < starts[ma] ) ? last : starts[ma];
612
- ca_size_t req_hi = (( last < starts[ma] ) ? starts[ma] : last) + 1;
613
- if ( counts[ma] > 0 && ( req_lo < 0 || req_hi > ca->dim[ma] ) ) {
614
- rb_raise(rb_eIndexError,
615
- "CAMeld xfer_stride meld_axis (axis %d) [%lld, %lld) out of range [0, %lld)",
616
- (int) ma, (long long) req_lo, (long long) req_hi, (long long) ca->dim[ma]);
617
- }
618
- }
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
  }
674
+
627
675
  if ( ma == 0 ) {
628
676
  ca_meld_xfer_stride_ma0(ca, starts, counts, strides, data, dir);
629
677
  } else {
@@ -635,15 +683,37 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
635
683
  /* xfer_all */
636
684
  /* ------------------------------------------------------------------- */
637
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
+
638
702
  /* meld_axis == 0 best path: K contig xfer_all at prefix-sum offsets. */
639
703
  static void
640
- 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)
641
705
  {
642
706
  ca_size_t tail_bytes = ca_meld_tail_elements(ca) * ca->bytes;
643
707
  char *d = (char *) data;
644
708
  int32_t k;
645
709
  for ( k = 0; k < ca->n_parents; k++ ) {
646
- 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
+ }
647
717
  }
648
718
  }
649
719
 
@@ -660,7 +730,8 @@ ca_meld_xfer_all_ma0 (CAMeld *ca, void *data, int dir)
660
730
  The naive per-cell odometer that this replaces cost ~2x eager on M2;
661
731
  chunked memcpy approaches memcpy bandwidth (eager parity target). */
662
732
  static void
663
- 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)
664
735
  {
665
736
  int8_t ma = ca->meld_axis;
666
737
  int8_t ndim = ca->ndim;
@@ -745,23 +816,29 @@ ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir)
745
816
  }
746
817
 
747
818
  if ( dir == CA_XFER_PUT ) {
748
- ca_xfer_all(p, buf, CA_XFER_PUT);
819
+ ca_meld_put_parent(p, buf, into_buffers);
749
820
  }
750
821
  ALLOCV_END(holder);
751
822
  }
752
823
  }
753
824
 
754
825
  static void
755
- 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)
756
827
  {
757
- CAMeld *ca = (CAMeld *) ap;
758
- if ( ca->meld_axis == 0 ) {
759
- 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);
760
830
  } else {
761
- ca_meld_xfer_all_ma_internal(ca, data, dir);
831
+ ca_meld_xfer_all_ma_internal(ca, data, dir, into_buffers);
762
832
  }
763
833
  }
764
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
+
765
842
  /* ------------------------------------------------------------------- */
766
843
  /* attach / sync / detach */
767
844
  /* ------------------------------------------------------------------- */
@@ -770,34 +847,42 @@ static void
770
847
  ca_meld_func_allocate (void *ap)
771
848
  {
772
849
  CAMeld *ca = (CAMeld *) ap;
773
- int32_t k;
774
- for ( k = 0; k < ca->n_parents; k++ ) {
775
- ca_attach(ca->parents[k]);
776
- }
850
+ ca_meld_mask_refresh(ca, 0);
851
+ ca_attach_all(ca->parents, ca->n_parents);
777
852
  ca->ptr = xmalloc(ca_length(ca));
778
853
  }
779
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
+
780
862
  static void
781
863
  ca_meld_func_attach (void *ap)
782
864
  {
783
865
  CAMeld *ca = (CAMeld *) ap;
866
+ ca_meld_mask_refresh(ca, 0);
784
867
  int32_t k;
785
- for ( k = 0; k < ca->n_parents; k++ ) {
786
- ca_attach(ca->parents[k]);
868
+ int tag = 0;
869
+ ca_attach_all(ca->parents, ca->n_parents);
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);
787
876
  }
788
- ca->ptr = xmalloc(ca_length(ca));
789
- ca_meld_func_xfer_all(ca, ca->ptr, CA_XFER_GET);
790
877
  }
791
878
 
792
879
  static void
793
880
  ca_meld_func_sync (void *ap)
794
881
  {
795
882
  CAMeld *ca = (CAMeld *) ap;
796
- int32_t k;
797
- ca_meld_func_xfer_all(ca, ca->ptr, CA_XFER_PUT);
798
- for ( k = 0; k < ca->n_parents; k++ ) {
799
- ca_sync(ca->parents[k]);
800
- }
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);
801
886
  }
802
887
 
803
888
  static void
@@ -820,6 +905,7 @@ static void
820
905
  ca_meld_func_fill_data (void *ap, void *ptr)
821
906
  {
822
907
  CAMeld *ca = (CAMeld *) ap;
908
+ ca_meld_mask_refresh(ca, 1);
823
909
  int32_t k;
824
910
  for ( k = 0; k < ca->n_parents; k++ ) {
825
911
  ca_fill(ca->parents[k], ptr);
@@ -827,7 +913,7 @@ ca_meld_func_fill_data (void *ap, void *ptr)
827
913
  }
828
914
 
829
915
  /* ------------------------------------------------------------------- */
830
- /* create_mask (horizontal propagation, mirrors CAStack) */
916
+ /* create_mask (mirrors CAStack) */
831
917
  /* ------------------------------------------------------------------- */
832
918
 
833
919
  static void
@@ -839,14 +925,16 @@ ca_meld_func_create_mask (void *ap)
839
925
  int32_t k;
840
926
 
841
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
+ }
842
932
  for ( k = 0; k < ca->n_parents; k++ ) {
843
- ca_update_mask(ca->parents[k]);
844
- if ( ! ca->parents[k]->mask ) {
845
- ca_create_mask(ca->parents[k]);
846
- }
847
- mask_parents[k] = ca->parents[k]->mask;
933
+ mask_parents[k] = ca_multi_parent_mask(ca->parents[k],
934
+ &ca->mask_standins[k]);
848
935
  }
849
936
  ca->mask = (CArray *) ca_meld_new(ca->n_parents, mask_parents, ca->meld_axis);
937
+ ((CAMeld *) ca->mask)->mask_owner = (CArray *) ca;
850
938
  ALLOCV_END(holder);
851
939
  }
852
940
 
@@ -865,6 +953,56 @@ ca_meld_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
865
953
  /* operation table */
866
954
  /* ------------------------------------------------------------------- */
867
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
+
868
1006
  ca_operation_function_t ca_meld_func = {
869
1007
  -1, /* CA_OBJ_MELD */
870
1008
  CA_VIEW_ARRAY,
@@ -874,13 +1012,13 @@ ca_operation_function_t ca_meld_func = {
874
1012
  ca_meld_func_attach,
875
1013
  ca_meld_func_sync,
876
1014
  ca_meld_func_detach,
877
- ca_meld_func_fill_data,
1015
+ ca_meld_put_fill_data,
878
1016
  ca_meld_func_create_mask,
879
- ca_meld_func_xfer_index,
880
- ca_meld_func_xfer_addrs,
1017
+ ca_meld_put_xfer_index,
1018
+ ca_meld_put_xfer_addrs,
881
1019
  ca_meld_func_fold_stride,
882
- ca_meld_func_xfer_stride,
883
- ca_meld_func_xfer_all,
1020
+ ca_meld_put_xfer_stride,
1021
+ ca_meld_put_xfer_all,
884
1022
  };
885
1023
 
886
1024
  /* ------------------------------------------------------------------- */
@@ -910,7 +1048,7 @@ rb_ca_meld_new (VALUE parents_ary, int8_t meld_axis)
910
1048
  ca = ca_meld_new((int32_t) n, parents, meld_axis);
911
1049
  obj = ca_wrap_struct(ca);
912
1050
  rb_ivar_set(obj, id_parents, rb_ary_dup(parents_ary));
913
- rb_ca_set_parent(obj, rb_ary_entry(parents_ary, 0));
1051
+ rb_ca_set_parent(obj, ca_face_strip_one(rb_ary_entry(parents_ary, 0)));
914
1052
  ALLOCV_END(holder);
915
1053
  return obj;
916
1054
  }
@@ -927,8 +1065,14 @@ rb_ca_meld_initialize_copy (VALUE self, VALUE other)
927
1065
  {
928
1066
  CAMeld *ca, *cs;
929
1067
  TypedData_Get_Struct(self, CAMeld, &cameld_data_type, ca);
1068
+ ca_check_uninitialized(ca);
930
1069
  TypedData_Get_Struct(other, CAMeld, &cameld_data_type, cs);
931
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;
932
1076
  return self;
933
1077
  }
934
1078
 
@@ -959,6 +1103,7 @@ rb_ca_meld_initialize (int argc, VALUE *argv, VALUE self)
959
1103
  NUM2LONG(axis_val), (int) ref->ndim, "CAMeld.new");
960
1104
  }
961
1105
  TypedData_Get_Struct(self, CAMeld, &cameld_data_type, ca);
1106
+ ca_check_uninitialized(ca);
962
1107
  parents = ALLOCV_N(CArray *, holder, n);
963
1108
  for ( i = 0; i < n; i++ ) {
964
1109
  VALUE p = rb_ary_entry(list, i);
@@ -967,11 +1112,45 @@ rb_ca_meld_initialize (int argc, VALUE *argv, VALUE self)
967
1112
  }
968
1113
  ca_meld_setup(ca, (int32_t) n, parents, meld_axis);
969
1114
  rb_ivar_set(self, id_parents, rb_ary_dup(list));
970
- rb_ca_set_parent(self, rb_ary_entry(list, 0));
1115
+ rb_ca_set_parent(self, ca_face_strip_one(rb_ary_entry(list, 0)));
971
1116
  ALLOCV_END(holder);
972
1117
  return self;
973
1118
  }
974
1119
 
1120
+ /* CAMeld.new(list, axis: 0) -- Class#new override, the twin of
1121
+ rb_ca_stack_s_new. A melded view has one surface over many parents, so a
1122
+ homogeneous Face list is treated the way CAStack treats it: refuse a Face
1123
+ whose state is per-parent (the cells of parent i are only readable against
1124
+ parent i's own state -- a CAConstString's cells are byte ranges into ITS
1125
+ buffer), and lift the rest so the Face survives the weld.
1126
+
1127
+ Without this meld was the one multi-parent constructor that neither asked
1128
+ nor lifted: it returned the raw storage of whatever it was given, which for
1129
+ CAConstString meant 16-byte (start,end) pairs presented as the string cells,
1130
+ and for CATime meant raw int64 ticks. Both looked like data.
1131
+
1132
+ Doing it here rather than in CArray.meld covers CAFrame.meld and a direct
1133
+ CAMeld.new by the same check. */
1134
+ static VALUE
1135
+ rb_ca_meld_s_new (int argc, VALUE *argv, VALUE klass)
1136
+ {
1137
+ VALUE list, kwargs, face_class;
1138
+ VALUE obj;
1139
+
1140
+ rb_scan_args(argc, argv, "1:", &list, &kwargs);
1141
+ Check_Type(list, T_ARRAY);
1142
+ if ( RARRAY_LEN(list) <= 0 ) {
1143
+ rb_raise(rb_eArgError, "CAMeld.new requires at least one parent");
1144
+ }
1145
+ face_class = ca_face_list_class(list, "CAMeld.new");
1146
+
1147
+ obj = rb_obj_alloc(klass);
1148
+ rb_obj_call_init_kw(obj, argc, argv, RB_PASS_CALLED_KEYWORDS);
1149
+
1150
+ if ( NIL_P(face_class) ) return obj;
1151
+ return ca_face_lift(obj, rb_ary_entry(list, 0));
1152
+ }
1153
+
975
1154
  static VALUE
976
1155
  rb_ca_meld_n_parents (VALUE self)
977
1156
  {
@@ -1027,6 +1206,7 @@ Init_ca_obj_meld (void)
1027
1206
  id_parents = rb_intern("parents");
1028
1207
 
1029
1208
  rb_define_alloc_func(rb_cCAMeld, rb_ca_meld_s_allocate);
1209
+ rb_define_singleton_method(rb_cCAMeld, "new", rb_ca_meld_s_new, -1);
1030
1210
  rb_define_method(rb_cCAMeld, "initialize",
1031
1211
  rb_ca_meld_initialize, -1);
1032
1212
  rb_define_method(rb_cCAMeld, "initialize_copy",