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
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,
@@ -152,6 +152,20 @@ ca_meld_setup (CAMeld *ca, int32_t n_parents, CArray **parents, int8_t meld_axis
152
152
  int32_t i;
153
153
  int8_t a;
154
154
 
155
+ /* ca == NULL asks for the checks only, so that a constructor can run
156
+ them before it allocates. They see the parents as the setup will,
157
+ one Face level down, without changing the caller's list. */
158
+ if ( ca == NULL ) {
159
+ volatile VALUE holder = 0;
160
+ CArray **seen = ALLOCV_N(CArray *, holder, n_parents > 0 ? n_parents : 1);
161
+ for ( i = 0; i < n_parents; i++ ) {
162
+ seen[i] = ca_is_face(parents[i]) ? CAVIEW(parents[i])->parent : parents[i];
163
+ }
164
+ ca_meld_check_uniform(n_parents, seen, meld_axis);
165
+ ALLOCV_END(holder);
166
+ return 0;
167
+ }
168
+
155
169
  /* Pre-strip Face parents one level to storage, as CAStack does, so a
156
170
  melded Face lifts to a single-Face chain (CATime[CAMeld[entity, ...]])
157
171
  rather than a Face sitting on Face parents. One level, not a full walk,
@@ -181,6 +195,8 @@ ca_meld_setup (CAMeld *ca, int32_t n_parents, CArray **parents, int8_t meld_axis
181
195
  ca->attach = 0;
182
196
  ca->nosync = 0;
183
197
 
198
+ ca->mask_standins = NULL;
199
+ ca->mask_owner = NULL;
184
200
  ca->n_parents = n_parents;
185
201
  ca->parents = ALLOC_N(CArray *, n_parents);
186
202
  for ( i = 0; i < n_parents; i++ ) {
@@ -209,7 +225,9 @@ ca_meld_setup (CAMeld *ca, int32_t n_parents, CArray **parents, int8_t meld_axis
209
225
  CAMeld *
210
226
  ca_meld_new (int32_t n_parents, CArray **parents, int8_t meld_axis)
211
227
  {
212
- CAMeld *ca = ALLOC(CAMeld);
228
+ CAMeld *ca;
229
+ ca_meld_setup(NULL, n_parents, parents, meld_axis);
230
+ ca = ALLOC(CAMeld);
213
231
  ca_meld_setup(ca, n_parents, parents, meld_axis);
214
232
  return ca;
215
233
  }
@@ -224,6 +242,13 @@ free_ca_meld (void *ap)
224
242
  CAMeld *ca = (CAMeld *) ap;
225
243
  if ( ca != NULL ) {
226
244
  ca_free(ca->mask);
245
+ if ( ca->mask_standins ) {
246
+ int32_t k;
247
+ for ( k = 0; k < ca->n_parents; k++ ) {
248
+ if ( ca->mask_standins[k] ) ca_free(ca->mask_standins[k]);
249
+ }
250
+ xfree(ca->mask_standins);
251
+ }
227
252
  xfree(ca->seg_offset);
228
253
  xfree(ca->parents);
229
254
  xfree(ca->dim);
@@ -273,10 +298,33 @@ ca_meld_tail_elements (const CAMeld *ca)
273
298
 
274
299
  /* view[..., v at meld_axis, ...] = parents[k][..., v - seg_offset[k], ...]
275
300
  where k = segment_of(v). */
301
+ /* On the mask of a CAMeld: let its stand-ins give way to the parents' own
302
+ masks (see ca_multi_parent_mask_refresh). */
303
+ static void
304
+ ca_meld_mask_refresh (CAMeld *ca)
305
+ {
306
+ CAMeld *o = (CAMeld *) ca->mask_owner;
307
+ if ( o != NULL ) {
308
+ ca_multi_parent_mask_refresh((CArray *) ca, o->parents, o->mask_standins,
309
+ o->n_parents);
310
+ }
311
+ }
312
+
313
+ static void
314
+ ca_meld_mask_settle (CAMeld *ca)
315
+ {
316
+ CAMeld *o = (CAMeld *) ca->mask_owner;
317
+ if ( o != NULL ) {
318
+ ca_multi_parent_mask_settle((CArray *) ca, o->parents, o->mask_standins,
319
+ o->n_parents);
320
+ }
321
+ }
322
+
276
323
  static void
277
324
  ca_meld_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
278
325
  {
279
326
  CAMeld *ca = (CAMeld *) ap;
327
+ ca_meld_mask_refresh(ca);
280
328
  int8_t ma = ca->meld_axis;
281
329
  ca_size_t v = idx[ma];
282
330
  int32_t k;
@@ -311,6 +359,7 @@ ca_meld_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
311
359
  void *data, int dir)
312
360
  {
313
361
  CAMeld *ca = (CAMeld *) ap;
362
+ ca_meld_mask_refresh(ca);
314
363
  int8_t ma = ca->meld_axis;
315
364
  ca_size_t bytes = ca->bytes;
316
365
  ca_size_t view_div[CA_RANK_MAX]; /* row-major divisor per view axis */
@@ -526,6 +575,7 @@ ca_meld_xfer_stride_ma_internal (CAMeld *ca, ca_size_t *starts,
526
575
  else memcpy(buf, d + voff, chunk_bytes);
527
576
  }
528
577
  else if ( dir == CA_XFER_GET ) {
578
+ /* empty: the slot (ca_meld_func_xfer_stride) returns on an empty region; a parent the request does not reach returns above */
529
579
  while ( 1 ) {
530
580
  memcpy(d + voff, buf + paddr, chunk_bytes);
531
581
  paddr += chunk_bytes;
@@ -539,6 +589,7 @@ ca_meld_xfer_stride_ma_internal (CAMeld *ca, ca_size_t *starts,
539
589
  if ( i < 0 ) break;
540
590
  }
541
591
  } else {
592
+ /* empty: as above */
542
593
  while ( 1 ) {
543
594
  memcpy(buf + paddr, d + voff, chunk_bytes);
544
595
  paddr += chunk_bytes;
@@ -586,6 +637,7 @@ ca_meld_xfer_stride_per_cell (CAMeld *ca, ca_size_t *starts, ca_size_t *counts,
586
637
  for ( i = 0; i < ndim; i++ ) base += starts[i] * native[i];
587
638
  for ( i = 0; i < ndim; i++ ) idx[i] = 0;
588
639
 
640
+ /* empty: the slot (ca_meld_func_xfer_stride) returns on an empty region */
589
641
  while ( 1 ) {
590
642
  ca_size_t toff = base;
591
643
  for ( i = 0; i < ndim; i++ ) toff += idx[i] * strides[i];
@@ -606,7 +658,9 @@ static void
606
658
  ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
607
659
  ca_size_t *strides, void *data, int dir)
608
660
  {
661
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
609
662
  CAMeld *ca = (CAMeld *) ap;
663
+ ca_meld_mask_refresh(ca);
610
664
  int8_t ma = ca->meld_axis;
611
665
  ca_size_t native[CA_RANK_MAX];
612
666
  ca_size_t s;
@@ -616,31 +670,27 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
616
670
  s = ca->bytes;
617
671
  for ( i = ca->ndim - 1; i >= 0; i-- ) { native[i] = s; s *= ca->dim[i]; }
618
672
 
673
+ /* Structural iff strides == native and the request is a box over the
674
+ view's own axes. Equal strides alone are not enough: a size-1 axis
675
+ gives two axes the same native stride, and a flat window reshaped back
676
+ to ndim has native strides yet wraps across an axis. The request is
677
+ over the view's addresses; see ca_xfer_stride_request_is_axis_box
678
+ (carray.h). Inside the gate the step on every axis is 1 and the region
679
+ stays inside each axis, which ca_meld_xfer_stride_ma_internal (handed
680
+ no strides) depends on. */
619
681
  for ( i = 0; i < ca->ndim; i++ ) {
620
682
  if ( strides[i] != native[i] ) { structural = 0; break; }
621
683
  }
684
+ if ( structural &&
685
+ ! ca_xfer_stride_request_is_axis_box(ca, starts, counts, strides) ) {
686
+ structural = 0;
687
+ }
622
688
 
623
- if ( ! structural ) {
689
+ if ( ! structural || ! ca_fast_paths_enabled() ) {
624
690
  ca_meld_xfer_stride_per_cell(ca, starts, counts, strides, data, dir);
625
691
  return;
626
692
  }
627
693
 
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
694
  if ( ma == 0 ) {
645
695
  ca_meld_xfer_stride_ma0(ca, starts, counts, strides, data, dir);
646
696
  } else {
@@ -652,15 +702,37 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
652
702
  /* xfer_all */
653
703
  /* ------------------------------------------------------------------- */
654
704
 
705
+ /* A parent's cells, delivered (PUT). into_buffers writes them into the
706
+ buffer the parent's attach handed out, rather than through the parent to
707
+ what is behind it: the sync of an attached meld, which then syncs each
708
+ parent. Writing past the buffer would leave it stale, and the parent's
709
+ own sync would push the stale buffer back over the cells just written. */
710
+ static void
711
+ ca_meld_put_parent (CArray *p, char *src, int into_buffers)
712
+ {
713
+ if ( into_buffers ) {
714
+ memcpy(p->ptr, src, (size_t) (p->elements * p->bytes));
715
+ }
716
+ else {
717
+ ca_xfer_all(p, src, CA_XFER_PUT);
718
+ }
719
+ }
720
+
655
721
  /* meld_axis == 0 best path: K contig xfer_all at prefix-sum offsets. */
656
722
  static void
657
- ca_meld_xfer_all_ma0 (CAMeld *ca, void *data, int dir)
723
+ ca_meld_xfer_all_ma0 (CAMeld *ca, void *data, int dir, int into_buffers)
658
724
  {
659
725
  ca_size_t tail_bytes = ca_meld_tail_elements(ca) * ca->bytes;
660
726
  char *d = (char *) data;
661
727
  int32_t k;
662
728
  for ( k = 0; k < ca->n_parents; k++ ) {
663
- ca_xfer_all(ca->parents[k], d + ca->seg_offset[k] * tail_bytes, dir);
729
+ char *seg = d + ca->seg_offset[k] * tail_bytes;
730
+ if ( dir == CA_XFER_PUT ) {
731
+ ca_meld_put_parent(ca->parents[k], seg, into_buffers);
732
+ }
733
+ else {
734
+ ca_xfer_all(ca->parents[k], seg, dir);
735
+ }
664
736
  }
665
737
  }
666
738
 
@@ -677,7 +749,8 @@ ca_meld_xfer_all_ma0 (CAMeld *ca, void *data, int dir)
677
749
  The naive per-cell odometer that this replaces cost ~2x eager on M2;
678
750
  chunked memcpy approaches memcpy bandwidth (eager parity target). */
679
751
  static void
680
- ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir)
752
+ ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir,
753
+ int into_buffers)
681
754
  {
682
755
  int8_t ma = ca->meld_axis;
683
756
  int8_t ndim = ca->ndim;
@@ -733,6 +806,7 @@ ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir)
733
806
  else memcpy(buf, d + voff, chunk_bytes);
734
807
  }
735
808
  else if ( dir == CA_XFER_GET ) {
809
+ /* empty: the slot returns on an empty view; the outer axes are the view's, and a parent empty along the meld axis copies chunks of 0 bytes */
736
810
  while ( 1 ) {
737
811
  memcpy(d + voff, buf + paddr, chunk_bytes);
738
812
  paddr += chunk_bytes;
@@ -747,6 +821,7 @@ ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir)
747
821
  }
748
822
  }
749
823
  else {
824
+ /* empty: as above */
750
825
  while ( 1 ) {
751
826
  memcpy(buf + paddr, d + voff, chunk_bytes);
752
827
  paddr += chunk_bytes;
@@ -762,23 +837,30 @@ ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir)
762
837
  }
763
838
 
764
839
  if ( dir == CA_XFER_PUT ) {
765
- ca_xfer_all(p, buf, CA_XFER_PUT);
840
+ ca_meld_put_parent(p, buf, into_buffers);
766
841
  }
767
842
  ALLOCV_END(holder);
768
843
  }
769
844
  }
770
845
 
771
846
  static void
772
- ca_meld_func_xfer_all (void *ap, void *data, int dir)
847
+ ca_meld_xfer_parents (CAMeld *ca, void *data, int dir, int into_buffers)
773
848
  {
774
- CAMeld *ca = (CAMeld *) ap;
775
- if ( ca->meld_axis == 0 ) {
776
- ca_meld_xfer_all_ma0(ca, data, dir);
849
+ if ( ca->meld_axis == 0 && ca_fast_paths_enabled() ) {
850
+ ca_meld_xfer_all_ma0(ca, data, dir, into_buffers);
777
851
  } else {
778
- ca_meld_xfer_all_ma_internal(ca, data, dir);
852
+ ca_meld_xfer_all_ma_internal(ca, data, dir, into_buffers);
779
853
  }
780
854
  }
781
855
 
856
+ static void
857
+ ca_meld_func_xfer_all (void *ap, void *data, int dir)
858
+ {
859
+ if ( ((CArray *) ap)->elements == 0 ) return;
860
+ ca_meld_mask_refresh((CAMeld *) ap);
861
+ ca_meld_xfer_parents((CAMeld *) ap, data, dir, 0);
862
+ }
863
+
782
864
  /* ------------------------------------------------------------------- */
783
865
  /* attach / sync / detach */
784
866
  /* ------------------------------------------------------------------- */
@@ -787,28 +869,37 @@ static void
787
869
  ca_meld_func_allocate (void *ap)
788
870
  {
789
871
  CAMeld *ca = (CAMeld *) ap;
872
+ ca_meld_mask_refresh(ca);
790
873
  ca_attach_all(ca->parents, ca->n_parents);
791
- ca->ptr = xmalloc(ca_length(ca));
874
+ ca->ptr = ca_alloc_cells((CArray *) ca);
875
+ }
876
+
877
+ static VALUE
878
+ ca_meld_attach_owned (VALUE arg)
879
+ {
880
+ ca_axis_view_attach_owned((void *) arg);
881
+ return Qnil;
792
882
  }
793
883
 
794
884
  static void
795
885
  ca_meld_func_attach (void *ap)
796
886
  {
797
887
  CAMeld *ca = (CAMeld *) ap;
888
+ ca_meld_mask_refresh(ca);
798
889
  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);
890
+ ca_fill_or_detach(ca->n_parents, ca->parents, ca_meld_attach_owned, (VALUE) ca);
801
891
  }
802
892
 
893
+ static void ca_meld_mask_refuse_sync (CAMeld *ca);
894
+
803
895
  static void
804
896
  ca_meld_func_sync (void *ap)
805
897
  {
806
898
  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
- }
899
+ ca_meld_mask_refuse_sync(ca);
900
+ ca_meld_xfer_parents(ca, ca->ptr, CA_XFER_PUT, 1);
901
+ ca_sync_all(ca->parents, ca->n_parents);
902
+ ca_meld_mask_settle(ca);
812
903
  }
813
904
 
814
905
  static void
@@ -831,6 +922,7 @@ static void
831
922
  ca_meld_func_fill_data (void *ap, void *ptr)
832
923
  {
833
924
  CAMeld *ca = (CAMeld *) ap;
925
+ ca_meld_mask_refresh(ca);
834
926
  int32_t k;
835
927
  for ( k = 0; k < ca->n_parents; k++ ) {
836
928
  ca_fill(ca->parents[k], ptr);
@@ -838,7 +930,7 @@ ca_meld_func_fill_data (void *ap, void *ptr)
838
930
  }
839
931
 
840
932
  /* ------------------------------------------------------------------- */
841
- /* create_mask (horizontal propagation, mirrors CAStack) */
933
+ /* create_mask (mirrors CAStack) */
842
934
  /* ------------------------------------------------------------------- */
843
935
 
844
936
  static void
@@ -850,14 +942,16 @@ ca_meld_func_create_mask (void *ap)
850
942
  int32_t k;
851
943
 
852
944
  mask_parents = ALLOCV_N(CArray *, holder, ca->n_parents);
945
+ if ( ! ca->mask_standins ) {
946
+ ca->mask_standins = ALLOC_N(CArray *, ca->n_parents);
947
+ MEMZERO(ca->mask_standins, CArray *, ca->n_parents);
948
+ }
853
949
  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;
950
+ mask_parents[k] = ca_multi_parent_mask(ca->parents[k],
951
+ &ca->mask_standins[k]);
859
952
  }
860
953
  ca->mask = (CArray *) ca_meld_new(ca->n_parents, mask_parents, ca->meld_axis);
954
+ ((CAMeld *) ca->mask)->mask_owner = (CArray *) ca;
861
955
  ALLOCV_END(holder);
862
956
  }
863
957
 
@@ -876,6 +970,174 @@ ca_meld_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
876
970
  /* operation table */
877
971
  /* ------------------------------------------------------------------- */
878
972
 
973
+ /* The table's write slots: after a write that may have put a true into a
974
+ stand-in, the true goes on to the parent's mask, or is refused for a
975
+ value array or a mask array (ca_mask_standin_settle). Only the mask of
976
+ a CAMeld has stand-ins. */
977
+ /* A write to the mask of a CAMeld, run once against blank masks first
978
+ (ca_multi_parent_mask_refuse_first), so that a write refused for a value
979
+ array or mask array part changes no other part. */
980
+ enum { CA_MELD_PUT_INDEX, CA_MELD_PUT_ADDRS, CA_MELD_PUT_STRIDE, CA_MELD_PUT_ALL,
981
+ CA_MELD_PUT_FILL, CA_MELD_PUT_SYNC, CA_MELD_PUT_FILL_ADDRS,
982
+ CA_MELD_PUT_FILL_STRIDE };
983
+
984
+ typedef struct {
985
+ int slot;
986
+ void *ap;
987
+ ca_size_t *idx;
988
+ ca_size_t n;
989
+ ca_size_t *addrs;
990
+ ca_size_t *starts;
991
+ ca_size_t *counts;
992
+ ca_size_t *strides;
993
+ void *data;
994
+ ca_size_t base;
995
+ int8_t ndim;
996
+ ca_size_t *steps;
997
+ } ca_meld_put_t;
998
+
999
+ static VALUE
1000
+ ca_meld_put_body (VALUE arg)
1001
+ {
1002
+ ca_meld_put_t *a = (ca_meld_put_t *) arg;
1003
+ switch ( a->slot ) {
1004
+ case CA_MELD_PUT_INDEX:
1005
+ ca_meld_func_xfer_index(a->ap, a->idx, a->data, CA_XFER_PUT); break;
1006
+ case CA_MELD_PUT_ADDRS:
1007
+ ca_meld_func_xfer_addrs(a->ap, a->n, a->addrs, a->data, CA_XFER_PUT); break;
1008
+ case CA_MELD_PUT_STRIDE:
1009
+ ca_meld_func_xfer_stride(a->ap, a->starts, a->counts, a->strides, a->data,
1010
+ CA_XFER_PUT); break;
1011
+ case CA_MELD_PUT_ALL:
1012
+ ca_meld_func_xfer_all(a->ap, a->data, CA_XFER_PUT); break;
1013
+ case CA_MELD_PUT_FILL:
1014
+ ca_meld_func_fill_data(a->ap, a->data); break;
1015
+ case CA_MELD_PUT_FILL_ADDRS:
1016
+ ca_fill_addrs_default(a->ap, a->n, a->addrs, a->data); break;
1017
+ case CA_MELD_PUT_FILL_STRIDE:
1018
+ ca_fill_stride_default(a->ap, a->base, a->ndim, a->counts, a->steps,
1019
+ a->data); break;
1020
+ case CA_MELD_PUT_SYNC:
1021
+ ca_meld_xfer_parents((CAMeld *) a->ap, ((CArray *) a->ap)->ptr, CA_XFER_PUT, 1);
1022
+ break;
1023
+ }
1024
+ return Qnil;
1025
+ }
1026
+
1027
+ static void
1028
+ ca_meld_mask_refuse_first (ca_meld_put_t *a)
1029
+ {
1030
+ CAMeld *o = (CAMeld *) ((CAMeld *) a->ap)->mask_owner;
1031
+ if ( o != NULL ) {
1032
+ ca_multi_parent_mask_refuse_first((CArray *) a->ap, o->parents,
1033
+ o->mask_standins, o->n_parents,
1034
+ ca_meld_put_body, (VALUE) a);
1035
+ }
1036
+ }
1037
+
1038
+ static void
1039
+ ca_meld_mask_refuse_sync (CAMeld *ca)
1040
+ {
1041
+ ca_meld_put_t a = { CA_MELD_PUT_SYNC, ca, NULL, 0, NULL, NULL, NULL, NULL, NULL };
1042
+ ca_meld_mask_refuse_first(&a);
1043
+ }
1044
+
1045
+ /* After a write of n cells of `data` to the mask of a CAMeld: a true
1046
+ that went into a stand-in goes on to its parent's mask. */
1047
+ static void
1048
+ ca_meld_mask_settle_after (CAMeld *ca, const void *data, ca_size_t n)
1049
+ {
1050
+ if ( ca->mask_owner != NULL && ca_mask_any_true(data, n) ) {
1051
+ ca_meld_mask_settle(ca);
1052
+ }
1053
+ }
1054
+
1055
+ static void
1056
+ ca_meld_put_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
1057
+ {
1058
+ if ( dir == CA_XFER_PUT ) {
1059
+ ca_meld_put_t a = { CA_MELD_PUT_INDEX, ap, idx, 0, NULL, NULL, NULL, NULL, data };
1060
+ ca_meld_mask_refuse_first(&a);
1061
+ }
1062
+ ca_meld_func_xfer_index(ap, idx, data, dir);
1063
+ if ( dir == CA_XFER_PUT ) ca_meld_mask_settle_after((CAMeld *) ap, data, 1);
1064
+ }
1065
+
1066
+ static void
1067
+ ca_meld_put_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *data,
1068
+ int dir)
1069
+ {
1070
+ if ( dir == CA_XFER_PUT ) {
1071
+ ca_meld_put_t a = { CA_MELD_PUT_ADDRS, ap, NULL, n, addrs, NULL, NULL, NULL, data };
1072
+ ca_meld_mask_refuse_first(&a);
1073
+ }
1074
+ ca_meld_func_xfer_addrs(ap, n, addrs, data, dir);
1075
+ if ( dir == CA_XFER_PUT ) ca_meld_mask_settle_after((CAMeld *) ap, data, n);
1076
+ }
1077
+
1078
+ static void
1079
+ ca_meld_put_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
1080
+ ca_size_t *strides, void *data, int dir)
1081
+ {
1082
+ if ( dir == CA_XFER_PUT ) {
1083
+ ca_meld_put_t a = { CA_MELD_PUT_STRIDE, ap, NULL, 0, NULL, starts, counts, strides, data };
1084
+ ca_meld_mask_refuse_first(&a);
1085
+ }
1086
+ ca_meld_func_xfer_stride(ap, starts, counts, strides, data, dir);
1087
+ if ( dir == CA_XFER_PUT ) {
1088
+ ca_meld_mask_settle_after((CAMeld *) ap, data,
1089
+ ca_shape_elements(((CArray *) ap)->ndim, counts, 1));
1090
+ }
1091
+ }
1092
+
1093
+ static void
1094
+ ca_meld_put_xfer_all (void *ap, void *data, int dir)
1095
+ {
1096
+ if ( dir == CA_XFER_PUT ) {
1097
+ ca_meld_put_t a = { CA_MELD_PUT_ALL, ap, NULL, 0, NULL, NULL, NULL, NULL, data };
1098
+ ca_meld_mask_refuse_first(&a);
1099
+ }
1100
+ ca_meld_func_xfer_all(ap, data, dir);
1101
+ if ( dir == CA_XFER_PUT ) {
1102
+ ca_meld_mask_settle_after((CAMeld *) ap, data, ((CArray *) ap)->elements);
1103
+ }
1104
+ }
1105
+
1106
+ static void
1107
+ ca_meld_put_fill_data (void *ap, void *ptr)
1108
+ {
1109
+ {
1110
+ ca_meld_put_t a = { CA_MELD_PUT_FILL, ap, NULL, 0, NULL, NULL, NULL, NULL, ptr };
1111
+ ca_meld_mask_refuse_first(&a);
1112
+ }
1113
+ ca_meld_func_fill_data(ap, ptr);
1114
+ ca_meld_mask_settle_after((CAMeld *) ap, ptr, 1);
1115
+ }
1116
+
1117
+ /* A fill of part of the mask goes cell by cell through xfer_index; run
1118
+ the whole of it against blank masks first, so that a cell refused late
1119
+ does not leave the cells before it written. */
1120
+ static void
1121
+ ca_meld_put_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
1122
+ {
1123
+ ca_meld_put_t a = { CA_MELD_PUT_FILL_ADDRS, ap, NULL, n, addrs, NULL, NULL,
1124
+ NULL, ptr };
1125
+ ca_meld_mask_refuse_first(&a);
1126
+ ca_fill_addrs_default(ap, n, addrs, ptr);
1127
+ ca_meld_mask_settle_after((CAMeld *) ap, ptr, 1);
1128
+ }
1129
+
1130
+ static void
1131
+ ca_meld_put_fill_stride (void *ap, ca_size_t base, int8_t ndim,
1132
+ ca_size_t *counts, ca_size_t *steps, void *ptr)
1133
+ {
1134
+ ca_meld_put_t a = { CA_MELD_PUT_FILL_STRIDE, ap, NULL, 0, NULL, NULL, counts,
1135
+ NULL, ptr, base, ndim, steps };
1136
+ ca_meld_mask_refuse_first(&a);
1137
+ ca_fill_stride_default(ap, base, ndim, counts, steps, ptr);
1138
+ ca_meld_mask_settle_after((CAMeld *) ap, ptr, 1);
1139
+ }
1140
+
879
1141
  ca_operation_function_t ca_meld_func = {
880
1142
  -1, /* CA_OBJ_MELD */
881
1143
  CA_VIEW_ARRAY,
@@ -885,30 +1147,19 @@ ca_operation_function_t ca_meld_func = {
885
1147
  ca_meld_func_attach,
886
1148
  ca_meld_func_sync,
887
1149
  ca_meld_func_detach,
888
- ca_meld_func_fill_data,
1150
+ ca_meld_put_fill_data,
889
1151
  ca_meld_func_create_mask,
890
- ca_meld_func_xfer_index,
891
- ca_meld_func_xfer_addrs,
1152
+ ca_meld_put_xfer_index,
1153
+ ca_meld_put_xfer_addrs,
892
1154
  ca_meld_func_fold_stride,
893
- ca_meld_func_xfer_stride,
894
- ca_meld_func_xfer_all,
1155
+ ca_meld_put_xfer_stride,
1156
+ ca_meld_put_xfer_all,
895
1157
  };
896
1158
 
897
1159
  /* ------------------------------------------------------------------- */
898
1160
  /* Ruby surface */
899
1161
  /* ------------------------------------------------------------------- */
900
1162
 
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
1163
  VALUE
913
1164
  rb_ca_meld_new (VALUE parents_ary, int8_t meld_axis)
914
1165
  {
@@ -932,7 +1183,7 @@ rb_ca_meld_new (VALUE parents_ary, int8_t meld_axis)
932
1183
  ca = ca_meld_new((int32_t) n, parents, meld_axis);
933
1184
  obj = ca_wrap_struct(ca);
934
1185
  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)));
1186
+ rb_ca_set_parent(obj, ca_face_strip_one(rb_ary_entry(parents_ary, 0)));
936
1187
  ALLOCV_END(holder);
937
1188
  return obj;
938
1189
  }
@@ -949,8 +1200,14 @@ rb_ca_meld_initialize_copy (VALUE self, VALUE other)
949
1200
  {
950
1201
  CAMeld *ca, *cs;
951
1202
  TypedData_Get_Struct(self, CAMeld, &cameld_data_type, ca);
1203
+ ca_check_uninitialized(ca);
952
1204
  TypedData_Get_Struct(other, CAMeld, &cameld_data_type, cs);
953
1205
  ca_meld_setup(ca, cs->n_parents, cs->parents, cs->meld_axis);
1206
+ /* A copy of a meld's mask reads and writes the same stand-ins, so it
1207
+ answers to the same owner: its writes reach the parents' masks. The
1208
+ copy holds the owner alive through the masked_array ivar that dup
1209
+ carries over (see rb_ca_mask_array). */
1210
+ ca->mask_owner = cs->mask_owner;
954
1211
  return self;
955
1212
  }
956
1213
 
@@ -977,10 +1234,11 @@ rb_ca_meld_initialize (int argc, VALUE *argv, VALUE self)
977
1234
  VALUE first = rb_ary_entry(list, 0);
978
1235
  rb_check_carray_object(first);
979
1236
  TypedData_Get_Struct(first, CArray, &carray_data_type, ref);
980
- meld_axis = (int8_t) rb_ca_normalize_axis_for_ndim(
981
- NUM2LONG(axis_val), (int) ref->ndim, "CAMeld.new");
1237
+ meld_axis = (int8_t) ca_normalize_axis_arg(
1238
+ axis_val, (int) ref->ndim, "CAMeld.new");
982
1239
  }
983
1240
  TypedData_Get_Struct(self, CAMeld, &cameld_data_type, ca);
1241
+ ca_check_uninitialized(ca);
984
1242
  parents = ALLOCV_N(CArray *, holder, n);
985
1243
  for ( i = 0; i < n; i++ ) {
986
1244
  VALUE p = rb_ary_entry(list, i);
@@ -989,7 +1247,7 @@ rb_ca_meld_initialize (int argc, VALUE *argv, VALUE self)
989
1247
  }
990
1248
  ca_meld_setup(ca, (int32_t) n, parents, meld_axis);
991
1249
  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)));
1250
+ rb_ca_set_parent(self, ca_face_strip_one(rb_ary_entry(list, 0)));
993
1251
  ALLOCV_END(holder);
994
1252
  return self;
995
1253
  }
@@ -1011,61 +1269,20 @@ rb_ca_meld_initialize (int argc, VALUE *argv, VALUE self)
1011
1269
  static VALUE
1012
1270
  rb_ca_meld_s_new (int argc, VALUE *argv, VALUE klass)
1013
1271
  {
1014
- VALUE list, kwargs;
1015
- long n, i;
1016
- int all_face = 1;
1017
- VALUE face_class = Qnil;
1018
- CArray *ref_face = NULL;
1272
+ VALUE list, kwargs, face_class;
1019
1273
  VALUE obj;
1020
1274
 
1021
1275
  rb_scan_args(argc, argv, "1:", &list, &kwargs);
1022
1276
  Check_Type(list, T_ARRAY);
1023
- n = RARRAY_LEN(list);
1024
- if ( n <= 0 ) {
1277
+ if ( RARRAY_LEN(list) <= 0 ) {
1025
1278
  rb_raise(rb_eArgError, "CAMeld.new requires at least one parent");
1026
1279
  }
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
- }
1280
+ face_class = ca_face_list_class(list, "CAMeld.new");
1052
1281
 
1053
1282
  obj = rb_obj_alloc(klass);
1054
1283
  rb_obj_call_init_kw(obj, argc, argv, RB_PASS_CALLED_KEYWORDS);
1055
1284
 
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
- }
1285
+ if ( NIL_P(face_class) ) return obj;
1069
1286
  return ca_face_lift(obj, rb_ary_entry(list, 0));
1070
1287
  }
1071
1288
 
@@ -1115,6 +1332,9 @@ Init_ca_obj_meld (void)
1115
1332
  rb_cCAMeld = rb_define_class("CAMeld", rb_cCAView);
1116
1333
  rb_cCAMeldMask = rb_define_class("CAMeldMask", rb_cCAMeld);
1117
1334
 
1335
+ ca_meld_func.fill_addrs = ca_meld_put_fill_addrs;
1336
+ ca_meld_func.fill_stride = ca_meld_put_fill_stride;
1337
+
1118
1338
  CA_OBJ_MELD = ca_install_obj_type(rb_cCAMeld,
1119
1339
  &cameld_data_type,
1120
1340
  rb_cCAMeldMask,