carray 3.0.5 → 3.0.6

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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +233 -0
  3. data/README.md +1 -1
  4. data/carray.gemspec +3 -2
  5. data/ext/ca_axis_dispatch.c +6 -0
  6. data/ext/ca_axis_group.c +1 -1
  7. data/ext/ca_categorical_iterator.c +7 -7
  8. data/ext/ca_kernel_iterator.c +116 -231
  9. data/ext/ca_kernel_iterator.h +410 -254
  10. data/ext/ca_obj_bincmp.c +9 -1
  11. data/ext/ca_obj_binop.c +10 -1
  12. data/ext/ca_obj_bitfield.c +2 -0
  13. data/ext/ca_obj_byte_swap.c +2 -0
  14. data/ext/ca_obj_face.c +2 -0
  15. data/ext/ca_obj_fake.c +3 -1
  16. data/ext/ca_obj_grid.c +167 -12
  17. data/ext/ca_obj_meld.c +69 -113
  18. data/ext/ca_obj_moncmp.c +9 -1
  19. data/ext/ca_obj_monop.c +40 -2
  20. data/ext/ca_obj_object.c +54 -20
  21. data/ext/ca_obj_reduce.c +15 -1
  22. data/ext/ca_obj_refer.c +65 -20
  23. data/ext/ca_obj_remap.c +69 -10
  24. data/ext/ca_obj_roll.c +1 -0
  25. data/ext/ca_obj_select.c +4 -1
  26. data/ext/ca_obj_select_axis.c +1 -0
  27. data/ext/ca_obj_shift.c +1 -0
  28. data/ext/ca_obj_stack.c +310 -111
  29. data/ext/ca_obj_stride.c +131 -45
  30. data/ext/ca_obj_string.c +18 -2
  31. data/ext/ca_obj_tile.c +1 -0
  32. data/ext/ca_obj_triop.c +9 -1
  33. data/ext/ca_obj_window.c +1 -0
  34. data/ext/ca_op_ipower.c +8 -8
  35. data/ext/caframe_csv_reader.c +1 -1
  36. data/ext/carray.h +2 -1
  37. data/ext/carray_access.c +27 -64
  38. data/ext/carray_address_basis.c +134 -0
  39. data/ext/carray_attribute.c +8 -0
  40. data/ext/carray_broadcast.c +3 -4
  41. data/ext/carray_build_flags.h +1 -1
  42. data/ext/carray_cast.c +8 -11
  43. data/ext/carray_conversion.c +9 -5
  44. data/ext/carray_core.c +811 -72
  45. data/ext/carray_element.c +13 -9
  46. data/ext/carray_histogram.c +25 -3
  47. data/ext/carray_internal.h +147 -12
  48. data/ext/carray_kernels_bincmp.c +2007 -3
  49. data/ext/carray_kernels_binop.c +25365 -5199
  50. data/ext/carray_kernels_init.c +8 -8
  51. data/ext/carray_kernels_monop.c +10696 -3678
  52. data/ext/carray_kernels_reduce_aggregate.c +4429 -702
  53. data/ext/carray_kernels_reduce_boolean.c +1533 -15
  54. data/ext/carray_kernels_reduce_cumulative.c +1808 -248
  55. data/ext/carray_kernels_reduce_extreme.c +4508 -511
  56. data/ext/carray_kernels_reduce_variance.c +2284 -152
  57. data/ext/carray_kernels_scan.c +240 -240
  58. data/ext/carray_kernels_search.c +4211 -264
  59. data/ext/carray_kernels_sort.c +367 -450
  60. data/ext/carray_lazy.c +47 -0
  61. data/ext/carray_loop.c +1 -1
  62. data/ext/carray_mask.c +130 -139
  63. data/ext/carray_median_percentile.c +4 -4
  64. data/ext/carray_memory_view.c +13 -7
  65. data/ext/carray_operator.c +147 -44
  66. data/ext/carray_order.c +3 -2
  67. data/ext/carray_random.c +4 -1
  68. data/ext/carray_slab.c +97 -21
  69. data/ext/carray_sort.c +1 -1
  70. data/ext/carray_test.c +74 -19
  71. data/ext/carray_time_text.c +2 -2
  72. data/ext/extconf.rb +11 -0
  73. data/ext/mkkernel.rb +346 -94
  74. data/ext/ruby_carray.c +4 -1
  75. data/ext/version.h +4 -4
  76. data/lib/carray/attribute.rb +25 -1
  77. data/lib/carray/autoload_carray.rb +3 -3
  78. data/lib/carray/autoload_method_extension.rb +5 -3
  79. data/lib/carray/axis_group.rb +13 -7
  80. data/lib/carray/basics.rb +1 -1
  81. data/lib/carray/block_iterator.rb +17 -3
  82. data/lib/carray/categorical.rb +6 -8
  83. data/lib/carray/categorical_iterator.rb +2 -2
  84. data/lib/carray/complex.rb +2 -2
  85. data/lib/carray/conditional.rb +3 -2
  86. data/lib/carray/frame/column_verbs.rb +45 -14
  87. data/lib/carray/frame/convert.rb +19 -0
  88. data/lib/carray/frame/csv_parser.rb +32 -32
  89. data/lib/carray/frame/describe.rb +4 -2
  90. data/lib/carray/frame/frame.rb +399 -78
  91. data/lib/carray/frame/group.rb +679 -53
  92. data/lib/carray/frame/io.rb +209 -71
  93. data/lib/carray/frame/join.rb +146 -37
  94. data/lib/carray/frame/records.rb +3 -3
  95. data/lib/carray/frame/reshape.rb +89 -11
  96. data/lib/carray/frame/sort.rb +57 -9
  97. data/lib/carray/frame/verbs.rb +384 -49
  98. data/lib/carray/frame/windows.rb +44 -6
  99. data/lib/carray/inspect.rb +7 -2
  100. data/lib/carray/iterator.rb +32 -0
  101. data/lib/carray/lazy.rb +17 -8
  102. data/lib/carray/mask_gap_fill.rb +37 -17
  103. data/lib/carray/meld_reduce.rb +1 -1
  104. data/lib/carray/methods/choose.rb +3 -2
  105. data/lib/carray/methods/meshgrid.rb +3 -1
  106. data/lib/carray/runtime.rb +47 -8
  107. data/lib/carray/segment_iterator.rb +23 -8
  108. data/lib/carray/serialize.rb +34 -17
  109. data/lib/carray/stack.rb +18 -6
  110. data/lib/carray/time.rb +5 -0
  111. data/lib/carray/window_iterator.rb +16 -4
  112. data/yard-stubs/ca_obj_array.rb +26 -1
  113. data/yard-stubs/carray_cast.rb +8 -5
  114. data/yard-stubs/carray_conversion.rb +8 -2
  115. data/yard-stubs/carray_mask.rb +20 -1
  116. data/yard-stubs/carray_math.rb +31 -16
  117. data/yard-stubs/carray_memory_view.rb +7 -0
  118. data/yard-stubs/carray_test.rb +7 -4
  119. metadata +18 -4
data/ext/ca_obj_bincmp.c CHANGED
@@ -291,9 +291,11 @@ ca_bincmp_try_leaf_inplace (CArray *op, int8_t common_dt,
291
291
 
292
292
  /* Evaluate the cells a request names into `data` (packed, n cells). */
293
293
  static void
294
- ca_bincmp_eval (CABinCmp *bc, const ca_lazy_req_t *req, void *data)
294
+ ca_bincmp_eval_cells (void *node, const ca_lazy_req_t *req, void *data, int dir)
295
295
  {
296
+ CABinCmp *bc = (CABinCmp *) node;
296
297
  ca_size_t slab_n = req->n;
298
+ (void) dir;
297
299
  int8_t k;
298
300
  void *left_scratch, *right_scratch;
299
301
  ca_size_t left_bytes, right_bytes;
@@ -437,6 +439,12 @@ ca_bincmp_eval (CABinCmp *bc, const ca_lazy_req_t *req, void *data)
437
439
  if ( ! left_is_inplace ) ca_lazy_arena_release(left_scratch);
438
440
  }
439
441
 
442
+ static void
443
+ ca_bincmp_eval (CABinCmp *bc, const ca_lazy_req_t *req, void *data)
444
+ {
445
+ ca_lazy_eval_recorded(bc, 2, bc->operands, 0, NULL, ca_bincmp_eval_cells, req, data, CA_XFER_GET);
446
+ }
447
+
440
448
  static void
441
449
  ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
442
450
  ca_size_t *strides, void *data, int dir)
data/ext/ca_obj_binop.c CHANGED
@@ -249,9 +249,11 @@ ca_size_t ca_binop_materialise_call_count = 0;
249
249
 
250
250
  /* Evaluate the cells a request names into `data` (packed, n cells). */
251
251
  static void
252
- ca_binop_eval (CABinOp *bo, const ca_lazy_req_t *req, void *data)
252
+ ca_binop_eval_cells (void *node, const ca_lazy_req_t *req, void *data, int dir)
253
253
  {
254
+ CABinOp *bo = (CABinOp *) node;
254
255
  ca_size_t slab_n = req->n;
256
+ (void) dir;
255
257
  int8_t k;
256
258
  void *scratch;
257
259
  volatile VALUE holder;
@@ -350,6 +352,13 @@ ca_binop_eval (CABinOp *bo, const ca_lazy_req_t *req, void *data)
350
352
  ca_lazy_arena_release(scratch);
351
353
  }
352
354
 
355
+ static void
356
+ ca_binop_eval (CABinOp *bo, const ca_lazy_req_t *req, void *data)
357
+ {
358
+ ca_lazy_eval_recorded(bo, 2, bo->operands, 0, NULL, ca_binop_eval_cells,
359
+ req, data, CA_XFER_GET);
360
+ }
361
+
353
362
  static void
354
363
  ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
355
364
  ca_size_t *strides, void *data, int dir)
@@ -480,7 +480,9 @@ ca_bitfield_func_sync (void *ap)
480
480
  {
481
481
  CABitfield *ca = (CABitfield *) ap;
482
482
  ca_bitfield_sync(ca);
483
+ ca_view_pass_mask_to_parent(ca);
483
484
  ca_sync(ca->parent);
485
+ ca_view_sync_mask_after_parent(ca);
484
486
  }
485
487
 
486
488
  static void
@@ -491,7 +491,9 @@ ca_byte_swap_func_sync (void *ap)
491
491
  ca_byte_swap_apply(ca, tmp);
492
492
  memcpy(ca->parent->ptr, tmp, ca_length(ca));
493
493
  ALLOCV_END(holder);
494
+ ca_view_pass_mask_to_parent(ca);
494
495
  ca_sync(ca->parent);
496
+ ca_view_sync_mask_after_parent(ca);
495
497
  }
496
498
 
497
499
  static void
data/ext/ca_obj_face.c CHANGED
@@ -49,7 +49,9 @@ ca_face_sync (void *ap)
49
49
  {
50
50
  CAView *cav = (CAView *) ap;
51
51
  /* alias means no copy-back is needed; parent sync propagates */
52
+ ca_view_pass_mask_to_parent(cav);
52
53
  ca_sync(cav->parent);
54
+ ca_view_sync_mask_after_parent(cav);
53
55
  }
54
56
 
55
57
  void
data/ext/ca_obj_fake.c CHANGED
@@ -310,12 +310,14 @@ ca_fake_func_sync (void *ap)
310
310
  ca_update_mask(ca);
311
311
  if ( ca->mask ) {
312
312
  ca_cast_block_with_mask(ca->elements, ca, ca->ptr, ca->parent, ca->parent->ptr,
313
- (boolean8_t *)ca->parent->mask->ptr);
313
+ (boolean8_t *)ca->mask->ptr);
314
314
  }
315
315
  else {
316
316
  ca_cast_block(ca->elements, ca, ca->ptr, ca->parent, ca->parent->ptr);
317
317
  }
318
+ ca_view_pass_mask_to_parent(ca);
318
319
  ca_sync(ca->parent);
320
+ ca_view_sync_mask_after_parent(ca);
319
321
  }
320
322
 
321
323
  static void
data/ext/ca_obj_grid.c CHANGED
@@ -490,11 +490,86 @@ cag_parent_addr (const CAGrid *ca, const ca_size_t *idx, ca_size_t *paddr)
490
490
  return hole;
491
491
  }
492
492
 
493
+ /* The parent addresses (paddrs, may be NULL) and the hole marks of every
494
+ view cell in address order: a walk over the outer axes with the
495
+ innermost axis a run, its indices and holes read off the axis. A 1-D
496
+ index axis is its own index and hole arrays. */
497
+ static void
498
+ cag_parent_addrs_whole (const CAGrid *ca, ca_size_t *paddrs, uint8_t *hole)
499
+ {
500
+ int8_t ndim = ca->ndim;
501
+ int8_t inner = ndim - 1;
502
+ const cag_axis_t *last = &ca->axes[inner];
503
+ ca_size_t count = last->count;
504
+ ca_size_t pdim = ca->parent->dim[inner];
505
+ ca_size_t idx[CA_RANK_MAX];
506
+ ca_size_t i = 0, j;
507
+ int8_t k;
508
+
509
+ if ( ndim == 1 && last->kind == CAG_AXIS_INDEX ) {
510
+ if ( paddrs ) {
511
+ memcpy(paddrs, last->indices, (size_t) count * sizeof(ca_size_t));
512
+ }
513
+ if ( last->holes ) {
514
+ memcpy(hole, last->holes, (size_t) count);
515
+ }
516
+ else {
517
+ memset(hole, 0, (size_t) count);
518
+ }
519
+ return;
520
+ }
521
+ if ( count == 0 || ca->elements == 0 ) {
522
+ return;
523
+ }
524
+ for (k = 0; k < ndim; k++) {
525
+ idx[k] = 0;
526
+ }
527
+ /* empty: returned above when the view has no cell */
528
+ while ( 1 ) {
529
+ ca_size_t base = 0;
530
+ uint8_t outer_hole = 0;
531
+ for (k = 0; k < inner; k++) {
532
+ const cag_axis_t *ax = &ca->axes[k];
533
+ if ( ax->kind == CAG_AXIS_INDEX && ax->holes && ax->holes[idx[k]] ) {
534
+ outer_hole = 1;
535
+ }
536
+ base = base * ca->parent->dim[k] + cag_parent_index_for(ax, idx[k]);
537
+ }
538
+ base *= pdim;
539
+ if ( last->kind == CAG_AXIS_INDEX ) {
540
+ const ca_size_t *ix = last->indices;
541
+ const uint8_t *hx = last->holes;
542
+ for (j = 0; j < count; j++) {
543
+ if ( paddrs ) {
544
+ paddrs[i + j] = base + ix[j];
545
+ }
546
+ hole[i + j] = (uint8_t) (outer_hole | (hx ? hx[j] : 0));
547
+ }
548
+ }
549
+ else {
550
+ for (j = 0; j < count; j++) {
551
+ if ( paddrs ) {
552
+ paddrs[i + j] = base + last->start + j * last->step;
553
+ }
554
+ hole[i + j] = outer_hole;
555
+ }
556
+ }
557
+ i += count;
558
+ for (k = inner - 1; k >= 0; k--) {
559
+ if ( ++idx[k] < ca->dim[k] ) break;
560
+ idx[k] = 0;
561
+ }
562
+ if ( k < 0 ) break;
563
+ }
564
+ }
565
+
493
566
  /* The transfer of a grid with holes, for the view cells at addrs (NULL:
494
- the whole view in order). The parent is asked for one batch of
495
- addresses. A GET reads every cell, a hole reading the cell at index 0
496
- of its holed axes (in a mask grid it is then set true); a PUT leaves
497
- the holes out. */
567
+ the whole view in order, walked axis by axis). The parent is asked
568
+ for one batch of addresses. A GET reads every cell, a hole reading the
569
+ cell at index 0 of its holed axes (in a mask grid it is then set true); a
570
+ PUT leaves the holes out. A mask grid reading its owner's stand-in reads
571
+ nothing: the stand-in is all false at rest (a write to it is settled
572
+ into the parent's mask at once), so the holes are the whole answer. */
498
573
  static void
499
574
  ca_grid_holed_xfer (CAGrid *ca, ca_size_t n, const ca_size_t *addrs,
500
575
  char *data, int dir)
@@ -511,11 +586,43 @@ ca_grid_holed_xfer (CAGrid *ca, ca_size_t n, const ca_size_t *addrs,
511
586
  }
512
587
  cag_mask_current(ca);
513
588
  parent = ca->parent;
514
- paddrs = ALLOCV_N(ca_size_t, h_addr, n);
515
- hole = ALLOCV_N(uint8_t, h_hole, n);
516
- for (i = 0; i < n; i++) {
517
- ca_addr2index((CArray *) ca, addrs ? addrs[i] : i, idx);
518
- hole[i] = (uint8_t) cag_parent_addr(ca, idx, &paddrs[i]);
589
+
590
+ if ( dir == CA_XFER_GET && ca->holes_read_masked && ca->mask_owner != NULL
591
+ && parent == ca->mask_owner->mask_standin ) {
592
+ if ( ! addrs ) {
593
+ cag_parent_addrs_whole(ca, NULL, (uint8_t *) data);
594
+ }
595
+ else {
596
+ for (i = 0; i < n; i++) {
597
+ ca_addr2index((CArray *) ca, addrs[i], idx);
598
+ ((boolean8_t *) data)[i] = (boolean8_t) cag_parent_addr(ca, idx, &m);
599
+ }
600
+ }
601
+ return;
602
+ }
603
+
604
+ if ( dir == CA_XFER_GET && ! addrs && ca->ndim == 1
605
+ && ( parent->obj_type == CA_OBJ_ARRAY || parent->obj_type == CA_OBJ_ARRAY_WRAP
606
+ || parent->obj_type == CA_OBJ_SCALAR ) ) {
607
+ /* A 1-D grid read whole from an array of its own: its index axis's
608
+ index and hole arrays are the batch as they are. Another parent's
609
+ transfer (a view, a CAObject's hook) takes a copy it may write on,
610
+ as a PUT does, which compacts the batch. */
611
+ paddrs = ca->axes[0].indices;
612
+ hole = ca->axes[0].holes;
613
+ }
614
+ else {
615
+ paddrs = ALLOCV_N(ca_size_t, h_addr, n);
616
+ hole = ALLOCV_N(uint8_t, h_hole, n);
617
+ if ( ! addrs ) {
618
+ cag_parent_addrs_whole(ca, paddrs, hole);
619
+ }
620
+ else {
621
+ for (i = 0; i < n; i++) {
622
+ ca_addr2index((CArray *) ca, addrs[i], idx);
623
+ hole[i] = (uint8_t) cag_parent_addr(ca, idx, &paddrs[i]);
624
+ }
625
+ }
519
626
  }
520
627
 
521
628
  if ( dir == CA_XFER_GET ) {
@@ -712,6 +819,50 @@ ca_grid_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
712
819
  return 1;
713
820
  }
714
821
 
822
+ /* A region of a grid with holes: its view addresses as one batch to the
823
+ holed transfer, or none when the region is the whole view in order. */
824
+ static void
825
+ cag_holed_xfer_stride (CAGrid *g, const ca_size_t *starts, const ca_size_t *counts,
826
+ const ca_size_t *strides, char *data, int dir)
827
+ {
828
+ int8_t ndim = g->ndim;
829
+ ca_size_t gnative[CA_RANK_MAX], idx[CA_RANK_MAX];
830
+ ca_size_t n = 1, i, s, base = 0;
831
+ ca_size_t *addrs;
832
+ volatile VALUE holder = 0;
833
+ int whole = 1;
834
+ int8_t k;
835
+
836
+ s = g->bytes;
837
+ for (k = ndim - 1; k >= 0; k--) { gnative[k] = s; s *= g->dim[k]; }
838
+ for (k = 0; k < ndim; k++) {
839
+ n *= counts[k];
840
+ base += starts[k] * gnative[k];
841
+ if ( starts[k] != 0 || counts[k] != g->dim[k] || strides[k] != gnative[k] ) {
842
+ whole = 0;
843
+ }
844
+ idx[k] = 0;
845
+ }
846
+ if ( whole ) {
847
+ ca_grid_holed_xfer(g, n, NULL, data, dir);
848
+ return;
849
+ }
850
+ addrs = ALLOCV_N(ca_size_t, holder, n);
851
+ for (i = 0; i < n; i++) {
852
+ ca_size_t goff = base;
853
+ for (k = 0; k < ndim; k++) {
854
+ goff += idx[k] * strides[k];
855
+ }
856
+ addrs[i] = goff / g->bytes;
857
+ for (k = ndim - 1; k >= 0; k--) {
858
+ if ( ++idx[k] < counts[k] ) break;
859
+ idx[k] = 0;
860
+ }
861
+ }
862
+ ca_grid_holed_xfer(g, n, addrs, data, dir);
863
+ ALLOCV_END(holder);
864
+ }
865
+
715
866
  /* xfer_stride: structural region delivery when CAGrid is the (declining)
716
867
  fold boundary -- a multi-element INDEX axis. Instead of materialising
717
868
  the whole grid, deliver only the requested region using the per-axis
@@ -763,9 +914,12 @@ ca_grid_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
763
914
  /* The request is over the view's addresses, so a transposed / flat request
764
915
  is legal and must not be composed axis-by-axis; see
765
916
  ca_xfer_stride_request_is_axis_box (carray.h). */
766
- if ( cag_has_holes(g)
767
- || ! ca_xfer_stride_request_is_axis_box(g, starts, counts, strides) ) {
768
- aligned = 0; /* a grid with holes goes cell by cell (xfer_index) */
917
+ if ( cag_has_holes(g) ) {
918
+ cag_holed_xfer_stride(g, starts, counts, strides, d, dir);
919
+ return;
920
+ }
921
+ if ( ! ca_xfer_stride_request_is_axis_box(g, starts, counts, strides) ) {
922
+ aligned = 0;
769
923
  }
770
924
  else {
771
925
  for (k = 0; k < ndim; k++) {
@@ -1548,6 +1702,7 @@ Init_ca_obj_grid (void)
1548
1702
  &cagrid_data_type,
1549
1703
  rb_cCAGridMask,
1550
1704
  &cagrid_mask_data_type, &ca_grid_func, sizeof(ca_grid_func));
1705
+ ca_register_cell_moving_view(CA_OBJ_GRID);
1551
1706
  rb_define_const(rb_cObject, "CA_OBJ_GRID", INT2NUM(CA_OBJ_GRID));
1552
1707
 
1553
1708
  rb_define_method(rb_cCArray, "grid", rb_ca_grid, -1);
data/ext/ca_obj_meld.c CHANGED
@@ -686,7 +686,7 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
686
686
  structural = 0;
687
687
  }
688
688
 
689
- if ( ! structural || ! ca_fast_paths_enabled() ) {
689
+ if ( ! structural || ! ca_fast_path(CA_SC_MELD_STRIDE_BOX) ) {
690
690
  ca_meld_xfer_stride_per_cell(ca, starts, counts, strides, data, dir);
691
691
  return;
692
692
  }
@@ -702,16 +702,23 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
702
702
  /* xfer_all */
703
703
  /* ------------------------------------------------------------------- */
704
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. */
705
+ /* A parent's cells, delivered (PUT). A non-NULL sync_error writes them
706
+ into the buffer the parent's attach handed out, rather than through the
707
+ parent to what is behind it, and syncs the parent: the sync of an
708
+ attached meld. 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
+ A parent with no buffer out (a stand-in the trial of a write puts in
711
+ place, which is never attached) has nothing to go stale: the cells go
712
+ through it. */
710
713
  static void
711
- ca_meld_put_parent (CArray *p, char *src, int into_buffers)
714
+ ca_meld_put_parent (CArray *p, char *src, volatile VALUE *sync_error)
712
715
  {
713
- if ( into_buffers ) {
716
+ if ( sync_error != NULL && p->ptr != NULL ) {
717
+ /* Synced at once, before the next part is written: parts that share
718
+ cells then take the write of the last of them, as a write through
719
+ the parts does. */
714
720
  memcpy(p->ptr, src, (size_t) (p->elements * p->bytes));
721
+ ca_sync_carry_on(p, sync_error);
715
722
  }
716
723
  else {
717
724
  ca_xfer_all(p, src, CA_XFER_PUT);
@@ -720,7 +727,7 @@ ca_meld_put_parent (CArray *p, char *src, int into_buffers)
720
727
 
721
728
  /* meld_axis == 0 best path: K contig xfer_all at prefix-sum offsets. */
722
729
  static void
723
- ca_meld_xfer_all_ma0 (CAMeld *ca, void *data, int dir, int into_buffers)
730
+ ca_meld_xfer_all_ma0 (CAMeld *ca, void *data, int dir, volatile VALUE *sync_error)
724
731
  {
725
732
  ca_size_t tail_bytes = ca_meld_tail_elements(ca) * ca->bytes;
726
733
  char *d = (char *) data;
@@ -728,7 +735,7 @@ ca_meld_xfer_all_ma0 (CAMeld *ca, void *data, int dir, int into_buffers)
728
735
  for ( k = 0; k < ca->n_parents; k++ ) {
729
736
  char *seg = d + ca->seg_offset[k] * tail_bytes;
730
737
  if ( dir == CA_XFER_PUT ) {
731
- ca_meld_put_parent(ca->parents[k], seg, into_buffers);
738
+ ca_meld_put_parent(ca->parents[k], seg, sync_error);
732
739
  }
733
740
  else {
734
741
  ca_xfer_all(ca->parents[k], seg, dir);
@@ -750,7 +757,7 @@ ca_meld_xfer_all_ma0 (CAMeld *ca, void *data, int dir, int into_buffers)
750
757
  chunked memcpy approaches memcpy bandwidth (eager parity target). */
751
758
  static void
752
759
  ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir,
753
- int into_buffers)
760
+ volatile VALUE *sync_error)
754
761
  {
755
762
  int8_t ma = ca->meld_axis;
756
763
  int8_t ndim = ca->ndim;
@@ -780,6 +787,12 @@ ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir,
780
787
  ca_size_t voff;
781
788
  int8_t i;
782
789
 
790
+ /* A parent with no cells moves nothing. The walks below copy one
791
+ chunk before they look at the outer extents, so a parent empty along
792
+ an outer axis would copy a chunk out of a 0-byte buffer. sync comes
793
+ here without the slot's own check on the view. */
794
+ if ( p->elements == 0 ) continue;
795
+
783
796
  buf = ALLOCV_N(char, holder, slab_bytes);
784
797
 
785
798
  if ( dir == CA_XFER_GET ) {
@@ -837,19 +850,19 @@ ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir,
837
850
  }
838
851
 
839
852
  if ( dir == CA_XFER_PUT ) {
840
- ca_meld_put_parent(p, buf, into_buffers);
853
+ ca_meld_put_parent(p, buf, sync_error);
841
854
  }
842
855
  ALLOCV_END(holder);
843
856
  }
844
857
  }
845
858
 
846
859
  static void
847
- ca_meld_xfer_parents (CAMeld *ca, void *data, int dir, int into_buffers)
860
+ ca_meld_xfer_parents (CAMeld *ca, void *data, int dir, volatile VALUE *sync_error)
848
861
  {
849
- if ( ca->meld_axis == 0 && ca_fast_paths_enabled() ) {
850
- ca_meld_xfer_all_ma0(ca, data, dir, into_buffers);
862
+ if ( ca->meld_axis == 0 && ca_fast_path(CA_SC_MELD_PARENTS_AXIS0) ) {
863
+ ca_meld_xfer_all_ma0(ca, data, dir, sync_error);
851
864
  } else {
852
- ca_meld_xfer_all_ma_internal(ca, data, dir, into_buffers);
865
+ ca_meld_xfer_all_ma_internal(ca, data, dir, sync_error);
853
866
  }
854
867
  }
855
868
 
@@ -858,7 +871,7 @@ ca_meld_func_xfer_all (void *ap, void *data, int dir)
858
871
  {
859
872
  if ( ((CArray *) ap)->elements == 0 ) return;
860
873
  ca_meld_mask_refresh((CAMeld *) ap);
861
- ca_meld_xfer_parents((CAMeld *) ap, data, dir, 0);
874
+ ca_meld_xfer_parents((CAMeld *) ap, data, dir, NULL);
862
875
  }
863
876
 
864
877
  /* ------------------------------------------------------------------- */
@@ -890,15 +903,19 @@ ca_meld_func_attach (void *ap)
890
903
  ca_fill_or_detach(ca->n_parents, ca->parents, ca_meld_attach_owned, (VALUE) ca);
891
904
  }
892
905
 
893
- static void ca_meld_mask_refuse_sync (CAMeld *ca);
894
-
895
906
  static void
896
907
  ca_meld_func_sync (void *ap)
897
908
  {
898
909
  CAMeld *ca = (CAMeld *) ap;
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);
910
+ CA_MULTI_PARENT_VALUE_TRIAL(ca, t,
911
+ ca_meld_xfer_parents((CAMeld *) t, ca->ptr, CA_XFER_PUT, NULL));
912
+ {
913
+ volatile VALUE error = Qnil;
914
+ ca_meld_xfer_parents(ca, ca->ptr, CA_XFER_PUT, &error);
915
+ if ( ! NIL_P(error) ) {
916
+ rb_exc_raise(error);
917
+ }
918
+ }
902
919
  ca_meld_mask_settle(ca);
903
920
  }
904
921
 
@@ -971,79 +988,21 @@ ca_meld_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
971
988
  /* ------------------------------------------------------------------- */
972
989
 
973
990
  /* 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
-
991
+ stand-in, the true goes on to the parent's mask (ca_mask_standin_settle).
992
+ Only the mask of a CAMeld has stand-ins. */
993
+ /* After a write of n cells of `data` to the mask of a CAMeld: a true
994
+ that went into a stand-in goes on to its parent's mask. */
1027
995
  static void
1028
- ca_meld_mask_refuse_first (ca_meld_put_t *a)
996
+ ca_meld_mask_adopt_before (void *ap, const void *data, ca_size_t n)
1029
997
  {
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);
998
+ CAMeld *ca = (CAMeld *) ap;
999
+ CAMeld *o = (CAMeld *) ca->mask_owner;
1000
+ if ( o != NULL && ca_mask_any_true(data, n) ) {
1001
+ ca_multi_parent_mask_adopt((CArray *) ca, o->parents, o->mask_standins,
1002
+ o->n_parents);
1035
1003
  }
1036
1004
  }
1037
1005
 
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
1006
  static void
1048
1007
  ca_meld_mask_settle_after (CAMeld *ca, const void *data, ca_size_t n)
1049
1008
  {
@@ -1055,10 +1014,7 @@ ca_meld_mask_settle_after (CAMeld *ca, const void *data, ca_size_t n)
1055
1014
  static void
1056
1015
  ca_meld_put_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
1057
1016
  {
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
- }
1017
+ if ( dir == CA_XFER_PUT ) ca_meld_mask_adopt_before(ap, data, 1);
1062
1018
  ca_meld_func_xfer_index(ap, idx, data, dir);
1063
1019
  if ( dir == CA_XFER_PUT ) ca_meld_mask_settle_after((CAMeld *) ap, data, 1);
1064
1020
  }
@@ -1068,8 +1024,9 @@ ca_meld_put_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *data,
1068
1024
  int dir)
1069
1025
  {
1070
1026
  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);
1027
+ CA_MULTI_PARENT_VALUE_TRIAL(ap, t,
1028
+ ca_meld_func_xfer_addrs(t, n, addrs, data, dir));
1029
+ ca_meld_mask_adopt_before(ap, data, n);
1073
1030
  }
1074
1031
  ca_meld_func_xfer_addrs(ap, n, addrs, data, dir);
1075
1032
  if ( dir == CA_XFER_PUT ) ca_meld_mask_settle_after((CAMeld *) ap, data, n);
@@ -1080,8 +1037,10 @@ ca_meld_put_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
1080
1037
  ca_size_t *strides, void *data, int dir)
1081
1038
  {
1082
1039
  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);
1040
+ CA_MULTI_PARENT_VALUE_TRIAL(ap, t,
1041
+ ca_meld_func_xfer_stride(t, starts, counts, strides, data, dir));
1042
+ ca_meld_mask_adopt_before(ap, data,
1043
+ ca_shape_elements(((CArray *) ap)->ndim, counts, 1));
1085
1044
  }
1086
1045
  ca_meld_func_xfer_stride(ap, starts, counts, strides, data, dir);
1087
1046
  if ( dir == CA_XFER_PUT ) {
@@ -1094,8 +1053,8 @@ static void
1094
1053
  ca_meld_put_xfer_all (void *ap, void *data, int dir)
1095
1054
  {
1096
1055
  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);
1056
+ CA_MULTI_PARENT_VALUE_TRIAL(ap, t, ca_meld_func_xfer_all(t, data, dir));
1057
+ ca_meld_mask_adopt_before(ap, data, ((CArray *) ap)->elements);
1099
1058
  }
1100
1059
  ca_meld_func_xfer_all(ap, data, dir);
1101
1060
  if ( dir == CA_XFER_PUT ) {
@@ -1106,23 +1065,17 @@ ca_meld_put_xfer_all (void *ap, void *data, int dir)
1106
1065
  static void
1107
1066
  ca_meld_put_fill_data (void *ap, void *ptr)
1108
1067
  {
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
- }
1068
+ CA_MULTI_PARENT_VALUE_TRIAL(ap, t, ca_meld_func_fill_data(t, ptr));
1069
+ ca_meld_mask_adopt_before(ap, ptr, 1);
1113
1070
  ca_meld_func_fill_data(ap, ptr);
1114
1071
  ca_meld_mask_settle_after((CAMeld *) ap, ptr, 1);
1115
1072
  }
1116
1073
 
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
1074
  static void
1121
1075
  ca_meld_put_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
1122
1076
  {
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);
1077
+ CA_MULTI_PARENT_VALUE_TRIAL(ap, t, ca_fill_addrs_default(t, n, addrs, ptr));
1078
+ ca_meld_mask_adopt_before(ap, ptr, 1);
1126
1079
  ca_fill_addrs_default(ap, n, addrs, ptr);
1127
1080
  ca_meld_mask_settle_after((CAMeld *) ap, ptr, 1);
1128
1081
  }
@@ -1131,9 +1084,9 @@ static void
1131
1084
  ca_meld_put_fill_stride (void *ap, ca_size_t base, int8_t ndim,
1132
1085
  ca_size_t *counts, ca_size_t *steps, void *ptr)
1133
1086
  {
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);
1087
+ CA_MULTI_PARENT_VALUE_TRIAL(ap, t,
1088
+ ca_fill_stride_default(t, base, ndim, counts, steps, ptr));
1089
+ ca_meld_mask_adopt_before(ap, ptr, 1);
1137
1090
  ca_fill_stride_default(ap, base, ndim, counts, steps, ptr);
1138
1091
  ca_meld_mask_settle_after((CAMeld *) ap, ptr, 1);
1139
1092
  }
@@ -1179,6 +1132,7 @@ rb_ca_meld_new (VALUE parents_ary, int8_t meld_axis)
1179
1132
  VALUE p = rb_ary_entry(parents_ary, i);
1180
1133
  rb_check_carray_object(p);
1181
1134
  TypedData_Get_Struct(p, CArray, &carray_data_type, parents[i]);
1135
+ ca_multi_parent_check_part(parents[i], "meld");
1182
1136
  }
1183
1137
  ca = ca_meld_new((int32_t) n, parents, meld_axis);
1184
1138
  obj = ca_wrap_struct(ca);
@@ -1244,6 +1198,7 @@ rb_ca_meld_initialize (int argc, VALUE *argv, VALUE self)
1244
1198
  VALUE p = rb_ary_entry(list, i);
1245
1199
  rb_check_carray_object(p);
1246
1200
  TypedData_Get_Struct(p, CArray, &carray_data_type, parents[i]);
1201
+ ca_multi_parent_check_part(parents[i], "meld");
1247
1202
  }
1248
1203
  ca_meld_setup(ca, (int32_t) n, parents, meld_axis);
1249
1204
  rb_ivar_set(self, id_parents, rb_ary_dup(list));
@@ -1339,6 +1294,7 @@ Init_ca_obj_meld (void)
1339
1294
  &cameld_data_type,
1340
1295
  rb_cCAMeldMask,
1341
1296
  &cameld_mask_data_type, &ca_meld_func, sizeof(ca_meld_func));
1297
+ ca_register_cell_moving_view(CA_OBJ_MELD);
1342
1298
  rb_define_const(rb_cObject, "CA_OBJ_MELD", INT2NUM(CA_OBJ_MELD));
1343
1299
 
1344
1300
  id_parents = rb_intern("parents");
data/ext/ca_obj_moncmp.c CHANGED
@@ -227,9 +227,11 @@ ca_moncmp_try_leaf_inplace (CArray *p,
227
227
 
228
228
  /* Evaluate the cells a request names into `data` (packed, n cells). */
229
229
  static void
230
- ca_moncmp_eval (CAMonCmp *mc, const ca_lazy_req_t *req, void *data)
230
+ ca_moncmp_eval_cells (void *node, const ca_lazy_req_t *req, void *data, int dir)
231
231
  {
232
+ CAMonCmp *mc = (CAMonCmp *) node;
232
233
  ca_size_t slab_n = req->n;
234
+ (void) dir;
233
235
  void *scratch;
234
236
  ca_size_t operand_bytes;
235
237
  int is_contig;
@@ -295,6 +297,12 @@ ca_moncmp_eval (CAMonCmp *mc, const ca_lazy_req_t *req, void *data)
295
297
  if ( ! scratch_is_inplace ) ca_lazy_arena_release(scratch);
296
298
  }
297
299
 
300
+ static void
301
+ ca_moncmp_eval (CAMonCmp *mc, const ca_lazy_req_t *req, void *data)
302
+ {
303
+ ca_lazy_eval_recorded(mc, 1, &mc->parent, 0, NULL, ca_moncmp_eval_cells, req, data, CA_XFER_GET);
304
+ }
305
+
298
306
  static void
299
307
  ca_moncmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
300
308
  ca_size_t *strides, void *data, int dir)