carray 3.0.3 → 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 (212) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +1 -6
  7. data/ext/ca_axis_group.c +27 -27
  8. data/ext/ca_binop_dispatch.c +1 -29
  9. data/ext/ca_binop_dispatch.h +0 -1
  10. data/ext/ca_categorical_iterator.c +205 -134
  11. data/ext/ca_compare.c +7 -18
  12. data/ext/ca_group_iter.c +16 -17
  13. data/ext/ca_kernel_iterator.c +1234 -1994
  14. data/ext/ca_kernel_iterator.h +391 -437
  15. data/ext/ca_monop_dispatch.c +82 -59
  16. data/ext/ca_monop_dispatch.h +1 -0
  17. data/ext/ca_obj_array.c +96 -39
  18. data/ext/ca_obj_bincmp.c +24 -21
  19. data/ext/ca_obj_binop.c +15 -26
  20. data/ext/ca_obj_bitarray.c +3 -2
  21. data/ext/ca_obj_bitfield.c +5 -6
  22. data/ext/ca_obj_block.c +18 -9
  23. data/ext/ca_obj_byte_swap.c +5 -6
  24. data/ext/ca_obj_const_string.c +173 -19
  25. data/ext/ca_obj_face.c +238 -57
  26. data/ext/ca_obj_face.h +19 -0
  27. data/ext/ca_obj_fake.c +15 -29
  28. data/ext/ca_obj_farray.c +6 -3
  29. data/ext/ca_obj_field.c +17 -5
  30. data/ext/ca_obj_fixlen_string.c +2 -3
  31. data/ext/ca_obj_grid.c +406 -132
  32. data/ext/ca_obj_meld.c +172 -34
  33. data/ext/ca_obj_moncmp.c +23 -8
  34. data/ext/ca_obj_monop.c +67 -57
  35. data/ext/ca_obj_object.c +157 -51
  36. data/ext/ca_obj_record.c +12 -7
  37. data/ext/ca_obj_reduce.c +13 -8
  38. data/ext/ca_obj_refer.c +25 -27
  39. data/ext/ca_obj_remap.c +30 -9
  40. data/ext/ca_obj_repeat.c +9 -10
  41. data/ext/ca_obj_roll.c +6 -5
  42. data/ext/ca_obj_select.c +14 -9
  43. data/ext/ca_obj_select_axis.c +15 -47
  44. data/ext/ca_obj_shift.c +11 -1
  45. data/ext/ca_obj_stack.c +179 -34
  46. data/ext/ca_obj_stride.c +162 -115
  47. data/ext/ca_obj_string.c +71 -4
  48. data/ext/ca_obj_tile.c +6 -5
  49. data/ext/ca_obj_time.c +22 -6
  50. data/ext/ca_obj_timedelta.c +22 -6
  51. data/ext/ca_obj_transpose.c +5 -3
  52. data/ext/ca_obj_triop.c +23 -32
  53. data/ext/ca_obj_window.c +190 -26
  54. data/ext/ca_sweep_engine.c +2 -2
  55. data/ext/caframe_csv_reader.c +80 -1
  56. data/ext/carray.h +181 -75
  57. data/ext/carray_access.c +184 -96
  58. data/ext/carray_address_basis.c +343 -87
  59. data/ext/carray_attribute.c +89 -6
  60. data/ext/carray_bincount.c +10 -8
  61. data/ext/carray_broadcast.c +13 -8
  62. data/ext/carray_build_flags.h +3 -0
  63. data/ext/carray_call_cfunc.c +108 -0
  64. data/ext/carray_cast.c +142 -24
  65. data/ext/carray_cast_func.rb +46 -6
  66. data/ext/carray_class.c +4 -3
  67. data/ext/carray_config.h +28 -0
  68. data/ext/carray_conversion.c +16 -7
  69. data/ext/carray_copy.c +51 -14
  70. data/ext/carray_core.c +147 -55
  71. data/ext/carray_count.c +50 -20
  72. data/ext/carray_element.c +76 -33
  73. data/ext/carray_factorize.c +118 -64
  74. data/ext/carray_generate.c +191 -50
  75. data/ext/carray_histogram.c +62 -17
  76. data/ext/carray_hold.c +12 -15
  77. data/ext/carray_index_classifier.c +388 -176
  78. data/ext/carray_internal.h +336 -29
  79. data/ext/carray_kernels_bincmp.c +4453 -0
  80. data/ext/carray_kernels_binop.c +11368 -0
  81. data/ext/carray_kernels_init.c +1734 -0
  82. data/ext/carray_kernels_moncmp.c +2104 -0
  83. data/ext/carray_kernels_monop.c +18369 -0
  84. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  85. data/ext/carray_kernels_reduce_boolean.c +406 -0
  86. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  87. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  88. data/ext/carray_kernels_reduce_variance.c +3849 -0
  89. data/ext/carray_kernels_scan.c +4302 -0
  90. data/ext/carray_kernels_search.c +33829 -0
  91. data/ext/carray_kernels_sort.c +10906 -0
  92. data/ext/carray_kernels_triop.c +1864 -0
  93. data/ext/carray_key_windows.c +216 -0
  94. data/ext/carray_lazy.c +170 -111
  95. data/ext/carray_mask.c +292 -72
  96. data/ext/carray_median_percentile.c +82 -28
  97. data/ext/carray_memory_view.c +669 -561
  98. data/ext/carray_operator.c +124 -47
  99. data/ext/carray_order.c +384 -76
  100. data/ext/carray_partition.c +28 -27
  101. data/ext/carray_random.c +67 -13
  102. data/ext/carray_round.c +273 -0
  103. data/ext/carray_scatter.c +63 -38
  104. data/ext/carray_segment.c +3 -3
  105. data/ext/carray_slab.c +91 -28
  106. data/ext/carray_sort.c +35 -35
  107. data/ext/carray_struct.c +19 -18
  108. data/ext/carray_test.c +26 -5
  109. data/ext/carray_undef.c +4 -0
  110. data/ext/carray_utils.c +246 -45
  111. data/ext/mk_call_cfunc.rb +19 -2
  112. data/ext/mkkernel.rb +198 -240
  113. data/ext/ruby_carray.c +10 -4
  114. data/ext/version.h +4 -4
  115. data/lib/carray/attribute.rb +126 -22
  116. data/lib/carray/autoload_carray.rb +8 -31
  117. data/lib/carray/autoload_method_extension.rb +14 -5
  118. data/lib/carray/axis_group.rb +255 -106
  119. data/lib/carray/basics.rb +78 -10
  120. data/lib/carray/bincount_nd.rb +12 -2
  121. data/lib/carray/block_iterator.rb +126 -23
  122. data/lib/carray/boolean_reduce.rb +17 -17
  123. data/lib/carray/categorical.rb +165 -43
  124. data/lib/carray/categorical_iterator.rb +130 -27
  125. data/lib/carray/complex.rb +5 -5
  126. data/lib/carray/conditional.rb +67 -18
  127. data/lib/carray/const_string.rb +14 -5
  128. data/lib/carray/construct.rb +15 -11
  129. data/lib/carray/data_type_extension.rb +1 -0
  130. data/lib/carray/distance_limit.rb +77 -0
  131. data/lib/carray/fixlen_string.rb +7 -1
  132. data/lib/carray/frame/column_verbs.rb +70 -0
  133. data/lib/carray/frame/convert.rb +69 -0
  134. data/lib/carray/frame/csv_parser.rb +111 -17
  135. data/lib/carray/frame/describe.rb +3 -2
  136. data/lib/carray/frame/frame.rb +246 -21
  137. data/lib/carray/frame/group.rb +510 -95
  138. data/lib/carray/frame/io.rb +115 -28
  139. data/lib/carray/frame/join.rb +312 -51
  140. data/lib/carray/frame/records.rb +83 -7
  141. data/lib/carray/frame/reshape.rb +42 -35
  142. data/lib/carray/frame/sort.rb +7 -19
  143. data/lib/carray/frame/verbs.rb +188 -48
  144. data/lib/carray/frame/windows.rb +117 -0
  145. data/lib/carray/frame.rb +2 -0
  146. data/lib/carray/fuse_source.rb +11 -4
  147. data/lib/carray/fusion.rb +40 -16
  148. data/lib/carray/histogram.rb +6 -1
  149. data/lib/carray/inspect.rb +31 -8
  150. data/lib/carray/iterator.rb +85 -7
  151. data/lib/carray/key_windows.rb +620 -0
  152. data/lib/carray/lazy.rb +182 -183
  153. data/lib/carray/mask_gap_fill.rb +63 -57
  154. data/lib/carray/meld_reduce.rb +12 -14
  155. data/lib/carray/methods/bin.rb +26 -18
  156. data/lib/carray/methods/bincount.rb +16 -0
  157. data/lib/carray/methods/bit_string.rb +1 -1
  158. data/lib/carray/methods/choose.rb +16 -3
  159. data/lib/carray/methods/composition.rb +3 -1
  160. data/lib/carray/methods/gather_nd.rb +14 -5
  161. data/lib/carray/methods/insert_block.rb +2 -2
  162. data/lib/carray/methods/is_between.rb +59 -0
  163. data/lib/carray/methods/is_in.rb +53 -36
  164. data/lib/carray/methods/join.rb +1 -6
  165. data/lib/carray/methods/lag.rb +49 -0
  166. data/lib/carray/methods/locate_addr.rb +47 -51
  167. data/lib/carray/methods/mode.rb +1 -1
  168. data/lib/carray/methods/nunique.rb +11 -6
  169. data/lib/carray/methods/resize.rb +3 -3
  170. data/lib/carray/methods/value_counts.rb +4 -11
  171. data/lib/carray/record_order.rb +3 -3
  172. data/lib/carray/rng.rb +3 -0
  173. data/lib/carray/runtime.rb +53 -8
  174. data/lib/carray/segment_iterator.rb +313 -82
  175. data/lib/carray/serialize.rb +24 -10
  176. data/lib/carray/slab_iterator.rb +50 -0
  177. data/lib/carray/string.rb +105 -5
  178. data/lib/carray/string_operation_extension.rb +8 -1
  179. data/lib/carray/struct.rb +9 -21
  180. data/lib/carray/struct_builder.rb +19 -8
  181. data/lib/carray/time.rb +726 -104
  182. data/lib/carray/window_iterator.rb +122 -16
  183. data/lib/carray.rb +7 -0
  184. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  185. data/yard-stubs/ca_obj_field.rb +4 -0
  186. data/yard-stubs/ca_obj_grid.rb +21 -10
  187. data/yard-stubs/ca_obj_refer.rb +2 -1
  188. data/yard-stubs/ca_obj_roll.rb +2 -2
  189. data/yard-stubs/ca_obj_shift.rb +5 -1
  190. data/yard-stubs/ca_obj_tile.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +8 -3
  192. data/yard-stubs/carray_access.rb +6 -1
  193. data/yard-stubs/carray_attribute.rb +0 -5
  194. data/yard-stubs/carray_cast.rb +10 -0
  195. data/yard-stubs/carray_conversion.rb +2 -1
  196. data/yard-stubs/carray_copy.rb +4 -2
  197. data/yard-stubs/carray_count.rb +4 -4
  198. data/yard-stubs/carray_element.rb +10 -4
  199. data/yard-stubs/carray_generate.rb +21 -1
  200. data/yard-stubs/carray_mask.rb +26 -2
  201. data/yard-stubs/carray_math.rb +27 -1
  202. data/yard-stubs/carray_median_percentile.rb +5 -2
  203. data/yard-stubs/carray_memory_view.rb +40 -23
  204. data/yard-stubs/carray_order.rb +29 -18
  205. data/yard-stubs/carray_random.rb +13 -4
  206. data/yard-stubs/carray_scatter.rb +14 -9
  207. data/yard-stubs/carray_slab.rb +9 -2
  208. data/yard-stubs/carray_sort.rb +6 -5
  209. data/yard-stubs/carray_test.rb +5 -3
  210. metadata +25 -3
  211. data/lib/carray/arrow_tensor.rb +0 -401
  212. data/lib/carray/table.rb +0 -108
data/ext/carray_mask.c CHANGED
@@ -423,85 +423,221 @@ ca_create_mask_attach (VALUE arg)
423
423
  }
424
424
 
425
425
  CArray *
426
- ca_multi_parent_mask (CArray *p, CArray **standin)
426
+ ca_mask_standin_new (CArray *parent)
427
427
  {
428
- *standin = NULL;
429
- if ( ! ca_has_mask(p) ) {
430
- CArray *z = carray_new(CA_BOOLEAN, p->ndim, p->dim, 0, NULL);
431
- MEMZERO(z->ptr, boolean8_t, z->elements);
432
- if ( ca_is_readonly(p) ) {
433
- ca_set_flag(z, CA_FLAG_READ_ONLY);
434
- }
435
- *standin = z;
436
- return z;
428
+ CArray *z = carray_new(CA_BOOLEAN, parent->ndim, parent->dim, 0, NULL);
429
+ MEMZERO(z->ptr, boolean8_t, z->elements);
430
+ if ( ca_is_readonly(parent) ) {
431
+ ca_set_flag(z, CA_FLAG_READ_ONLY);
437
432
  }
438
- ca_create_mask(p);
439
- return p->mask;
433
+ return z;
440
434
  }
441
435
 
442
436
  /* A value array or a mask array: a parent that can never be given a mask,
443
437
  whose stand-in therefore stays in place for good. */
444
438
  static int
445
- ca_multi_parent_mask_unmaskable (CArray *p)
439
+ ca_mask_standin_parent_unmaskable (CArray *parent)
440
+ {
441
+ return ca_is_value_array(parent) || ca_is_mask_array(parent);
442
+ }
443
+
444
+ CArray *
445
+ ca_mask_standin_current (CArray *mask_view, CArray *reading, CArray *parent,
446
+ CArray *standin)
446
447
  {
447
- return ca_is_value_array(p) || ca_is_mask_array(p);
448
+ if ( standin == NULL || reading != standin
449
+ || ca_mask_standin_parent_unmaskable(parent) ) {
450
+ return reading;
451
+ }
452
+ /* Not inside an attach window whose buffer is out: that buffer and the
453
+ detach to come are those of the stand-in. The attach and allocate
454
+ slots run before the buffer is published, and may still give way. */
455
+ if ( CAVIEW(mask_view)->attach > 0 && mask_view->ptr != NULL ) {
456
+ return reading;
457
+ }
458
+ /* A read-only parent (a lazy expression, a broadcast) is never given a
459
+ mask by a write, but can still have one later through its operand or
460
+ root. */
461
+ if ( ! ca_has_mask(parent) ) {
462
+ return reading;
463
+ }
464
+ ca_create_mask(parent);
465
+ return ( parent->mask != NULL ) ? parent->mask : reading;
466
+ }
467
+
468
+ void
469
+ ca_mask_standin_settle (CArray *parent, CArray *standin)
470
+ {
471
+ volatile VALUE holder = 0;
472
+ boolean8_t *z, one = 1;
473
+ ca_size_t *addrs;
474
+ ca_size_t i, m = 0, n;
475
+
476
+ if ( standin == NULL || ca_test_flag(standin, CA_FLAG_READ_ONLY) ) {
477
+ return;
478
+ }
479
+ z = (boolean8_t *) standin->ptr;
480
+ n = standin->elements;
481
+ for ( i = 0; i < n && ! z[i]; i++ ) ;
482
+ if ( i == n ) {
483
+ return;
484
+ }
485
+ if ( ca_mask_standin_parent_unmaskable(parent) ) {
486
+ MEMZERO(z, boolean8_t, n);
487
+ rb_raise(rb_eTypeError, "can not create mask array for the %s array",
488
+ ca_is_value_array(parent) ? "value" : "mask");
489
+ }
490
+ ca_create_mask(parent);
491
+ /* The trues are added to the parent's mask, not copied over it: the
492
+ parent may have come to have masked cells of its own meanwhile. */
493
+ addrs = ALLOCV_N(ca_size_t, holder, n);
494
+ for ( ; i < n; i++ ) {
495
+ if ( z[i] ) {
496
+ addrs[m++] = i;
497
+ }
498
+ }
499
+ ca_fill_addrs(parent->mask, m, addrs, &one);
500
+ ALLOCV_END(holder);
501
+ MEMZERO(z, boolean8_t, n);
502
+ }
503
+
504
+ CArray *
505
+ ca_multi_parent_mask (CArray *p, CArray **standin)
506
+ {
507
+ *standin = NULL;
508
+ if ( ! ca_has_mask(p) ) {
509
+ *standin = ca_mask_standin_new(p);
510
+ return *standin;
511
+ }
512
+ ca_create_mask(p);
513
+ return p->mask;
448
514
  }
449
515
 
450
516
  void
451
517
  ca_multi_parent_mask_refresh (CArray *mask, CArray **parents,
452
- CArray **standins, int32_t n, int for_write)
518
+ CArray **standins, int32_t n)
453
519
  {
454
520
  CAMultiParent *mp = (CAMultiParent *) mask;
455
521
  int32_t k;
456
- /* Not inside an attach window: its buffer and its detach are those of
457
- the parents it was opened with. The attach and allocate slots run
458
- before the buffer is published, and replace the stand-ins then. */
459
- if ( standins == NULL || ( CAVIEW(mask)->attach > 0 && mask->ptr != NULL ) ) {
522
+ if ( standins == NULL ) {
460
523
  return;
461
524
  }
462
525
  /* A replaced stand-in stays allocated until the view is freed: a copy
463
526
  of the mask (dup) may still point at it. */
464
527
  for ( k = 0; k < n; k++ ) {
465
- CArray *z = standins[k];
466
- if ( z == NULL || mp->parents[k] != z
467
- || ca_test_flag(z, CA_FLAG_READ_ONLY)
468
- || ca_multi_parent_mask_unmaskable(parents[k]) ) {
469
- continue;
470
- }
471
- if ( ! ( for_write || ca_has_mask(parents[k]) ) ) {
472
- continue;
473
- }
474
- ca_create_mask(parents[k]);
475
- mp->parents[k] = parents[k]->mask;
476
- if ( k == 0 ) {
477
- CAVIEW(mask)->parent = parents[k]->mask;
478
- }
528
+ mp->parents[k] = ca_mask_standin_current(mask, mp->parents[k], parents[k],
529
+ standins[k]);
479
530
  }
531
+ CAVIEW(mask)->parent = mp->parents[0];
532
+ }
533
+
534
+ typedef struct {
535
+ CArray *mask;
536
+ CArray **blanks;
537
+ CArray **saved;
538
+ CArray *saved_parent;
539
+ int32_t n;
540
+ int finished;
541
+ VALUE (*body)(VALUE);
542
+ VALUE arg;
543
+ } ca_mp_trial_t;
544
+
545
+ static VALUE
546
+ ca_mp_trial_body (VALUE p)
547
+ {
548
+ ca_mp_trial_t *t = (ca_mp_trial_t *) p;
549
+ t->body(t->arg);
550
+ t->finished = 1;
551
+ return Qnil;
552
+ }
553
+
554
+ static void
555
+ ca_mp_trial_free_blanks (ca_mp_trial_t *t)
556
+ {
557
+ int32_t k;
558
+ for ( k = 0; k < t->n; k++ ) {
559
+ ca_free(t->blanks[k]);
560
+ t->blanks[k] = NULL;
561
+ }
562
+ }
563
+
564
+ static VALUE
565
+ ca_mp_trial_restore (VALUE p)
566
+ {
567
+ ca_mp_trial_t *t = (ca_mp_trial_t *) p;
568
+ CAMultiParent *mp = (CAMultiParent *) t->mask;
569
+ int32_t k;
570
+ for ( k = 0; k < t->n; k++ ) {
571
+ mp->parents[k] = t->saved[k];
572
+ }
573
+ CAVIEW(t->mask)->parent = t->saved_parent;
574
+ if ( ! t->finished ) {
575
+ ca_mp_trial_free_blanks(t);
576
+ }
577
+ return Qnil;
480
578
  }
481
579
 
482
580
  void
483
- ca_multi_parent_mask_check (CArray *mask, CArray **parents,
484
- CArray **standins, int32_t n)
581
+ ca_multi_parent_mask_refuse_first (CArray *mask, CArray **parents,
582
+ CArray **standins, int32_t n,
583
+ VALUE (*body)(VALUE), VALUE arg)
485
584
  {
486
585
  CAMultiParent *mp = (CAMultiParent *) mask;
487
- int32_t k;
586
+ volatile VALUE h_blank = 0, h_saved = 0;
587
+ ca_mp_trial_t t;
588
+ int32_t k, refused = -1;
488
589
  if ( standins == NULL ) {
489
590
  return;
490
591
  }
491
592
  for ( k = 0; k < n; k++ ) {
492
- CArray *z = standins[k];
593
+ if ( standins[k] != NULL && mp->parents[k] == standins[k]
594
+ && ca_mask_standin_parent_unmaskable(parents[k]) ) {
595
+ break;
596
+ }
597
+ }
598
+ if ( k == n ) {
599
+ return;
600
+ }
601
+ t.mask = mask;
602
+ t.n = n;
603
+ t.finished = 0;
604
+ t.body = body;
605
+ t.arg = arg;
606
+ t.saved_parent = CAVIEW(mask)->parent;
607
+ t.blanks = ALLOCV_N(CArray *, h_blank, n);
608
+ t.saved = ALLOCV_N(CArray *, h_saved, n);
609
+ for ( k = 0; k < n; k++ ) {
610
+ t.blanks[k] = NULL;
611
+ }
612
+ for ( k = 0; k < n; k++ ) {
613
+ CArray *m = mp->parents[k];
614
+ t.saved[k] = m;
615
+ t.blanks[k] = carray_new(CA_BOOLEAN, m->ndim, m->dim, 0, NULL);
616
+ MEMZERO(t.blanks[k]->ptr, boolean8_t, t.blanks[k]->elements);
617
+ }
618
+ for ( k = 0; k < n; k++ ) {
619
+ mp->parents[k] = t.blanks[k];
620
+ }
621
+ CAVIEW(mask)->parent = t.blanks[0];
622
+ rb_ensure(ca_mp_trial_body, (VALUE) &t, ca_mp_trial_restore, (VALUE) &t);
623
+ for ( k = 0; k < n && refused < 0; k++ ) {
624
+ CArray *z = t.blanks[k];
493
625
  ca_size_t i;
494
- if ( z == NULL || mp->parents[k] != z
495
- || ! ca_multi_parent_mask_unmaskable(parents[k]) ) {
626
+ if ( standins[k] == NULL || t.saved[k] != standins[k]
627
+ || ! ca_mask_standin_parent_unmaskable(parents[k]) ) {
496
628
  continue;
497
629
  }
498
630
  for ( i = 0; i < z->elements && ! ((boolean8_t *) z->ptr)[i]; i++ ) ;
499
- if ( i == z->elements ) {
500
- continue;
631
+ if ( i < z->elements ) {
632
+ refused = k;
501
633
  }
502
- MEMZERO(z->ptr, boolean8_t, z->elements);
634
+ }
635
+ ca_mp_trial_free_blanks(&t);
636
+ ALLOCV_END(h_blank);
637
+ ALLOCV_END(h_saved);
638
+ if ( refused >= 0 ) {
503
639
  rb_raise(rb_eTypeError, "can not create mask array for the %s array",
504
- ca_is_value_array(parents[k]) ? "value" : "mask");
640
+ ca_is_value_array(parents[refused]) ? "value" : "mask");
505
641
  }
506
642
  }
507
643
 
@@ -510,26 +646,20 @@ ca_multi_parent_mask_settle (CArray *mask, CArray **parents,
510
646
  CArray **standins, int32_t n)
511
647
  {
512
648
  CAMultiParent *mp = (CAMultiParent *) mask;
513
- int32_t k;
649
+ int32_t k, pass;
514
650
  if ( standins == NULL ) {
515
651
  return;
516
652
  }
517
- ca_multi_parent_mask_check(mask, parents, standins, n);
518
- for ( k = 0; k < n; k++ ) {
519
- CArray *z = standins[k];
520
- ca_size_t i;
521
- if ( z == NULL || mp->parents[k] != z
522
- || ca_test_flag(z, CA_FLAG_READ_ONLY)
523
- || ca_multi_parent_mask_unmaskable(parents[k]) ) {
524
- continue;
525
- }
526
- for ( i = 0; i < z->elements && ! ((boolean8_t *) z->ptr)[i]; i++ ) ;
527
- if ( i == z->elements ) {
528
- continue;
653
+ /* The parts that can have no mask first, so that a refused true leaves
654
+ the other parts as they were. */
655
+ for ( pass = 0; pass < 2; pass++ ) {
656
+ for ( k = 0; k < n; k++ ) {
657
+ if ( standins[k] == NULL || mp->parents[k] != standins[k]
658
+ || ca_mask_standin_parent_unmaskable(parents[k]) != ( pass == 0 ) ) {
659
+ continue;
660
+ }
661
+ ca_mask_standin_settle(parents[k], standins[k]);
529
662
  }
530
- ca_create_mask(parents[k]);
531
- ca_xfer_all(parents[k]->mask, z->ptr, CA_XFER_PUT);
532
- MEMZERO(z->ptr, boolean8_t, z->elements);
533
663
  }
534
664
  }
535
665
 
@@ -553,6 +683,10 @@ ca_create_mask (void *ap)
553
683
  }
554
684
 
555
685
  ca_func[ca->obj_type].create_mask(ca);
686
+ if ( ! ca->mask ) {
687
+ /* a lazy expression with no masked operand has no mask to make */
688
+ return;
689
+ }
556
690
  ca_set_flag(ca->mask, CA_FLAG_MASK_ARRAY); /* set array as mask array */
557
691
  if ( ca_is_view(ca) ) {
558
692
  if ( CAVIEW(ca)->attach ) {
@@ -561,6 +695,7 @@ ca_create_mask (void *ap)
561
695
  then comes off again, since the view's sync and detach would
562
696
  find it attached to nothing. */
563
697
  int tag = 0;
698
+ /* protect: the mask comes off its view before it is freed */
564
699
  rb_protect(ca_create_mask_attach, (VALUE) ca->mask, &tag);
565
700
  if ( tag ) {
566
701
  CArray *mask = ca->mask;
@@ -606,6 +741,13 @@ ca_setup_mask (void *ap, CArray *mask)
606
741
  {
607
742
  CArray *ca = (CArray *) ap;
608
743
 
744
+ if ( mask ) {
745
+ if ( ! ca_is_boolean_type(mask) ) {
746
+ rb_raise(rb_eCADataTypeError, "a mask is a boolean array");
747
+ }
748
+ ca_check_same_elements(ca, mask);
749
+ }
750
+
609
751
  ca_update_mask(ca);
610
752
 
611
753
  if ( mask ) {
@@ -685,6 +827,21 @@ ca_copy_mask_overlay_core (CArray *ca, ca_size_t elements, int n,
685
827
  char *modes;
686
828
  int i, some_has_mask = 0;
687
829
 
830
+ if ( elements > ca->elements ) {
831
+ elements = ca->elements;
832
+ }
833
+
834
+ /* An array source is read cell by cell over the destination's cells;
835
+ a scalar source's one cell applies to all of them. */
836
+ for (i=0; i<n; i++) {
837
+ cs = slist[i];
838
+ if ( cs && ! ca_is_scalar(cs) && cs->elements < elements ) {
839
+ rb_raise(rb_eArgError,
840
+ "mask source has %lld elements, fewer than the %lld of the destination",
841
+ (long long) cs->elements, (long long) elements);
842
+ }
843
+ }
844
+
688
845
  for (i=0; i<n; i++) {
689
846
  if ( slist[i] && ca_has_mask(slist[i]) ) {
690
847
  some_has_mask = 1;
@@ -703,10 +860,6 @@ ca_copy_mask_overlay_core (CArray *ca, ca_size_t elements, int n,
703
860
  return;
704
861
  }
705
862
 
706
- if ( elements > ca->elements ) {
707
- elements = ca->elements;
708
- }
709
-
710
863
  o.list = ALLOCA_N(CArray *, n + 1);
711
864
  o.snap = ALLOCA_N(boolean8_t *, n);
712
865
  o.att = ALLOCA_N(CArray *, n);
@@ -900,6 +1053,10 @@ ca_unmask (void *ap, char *fill_value)
900
1053
  {
901
1054
  CArray *ca = (CArray *) ap;
902
1055
 
1056
+ if ( ca_is_readonly(ca) ) {
1057
+ ca_refuse_read_only();
1058
+ }
1059
+
903
1060
  ca_update_mask(ca);
904
1061
  if ( ca->mask ) {
905
1062
  if ( ! fill_value ) {
@@ -1258,6 +1415,72 @@ rb_ca_mask_array (VALUE self)
1258
1415
  }
1259
1416
  }
1260
1417
 
1418
+ /* dup / clone of a mask. The mask of a view is a view over its parent's
1419
+ mask, and its dup, like the dup of any view, is another view onto the
1420
+ same parent mask: it follows later changes and a write to it lands in
1421
+ the parent's mask (copy makes a mask of its own). A mask over a cast, a
1422
+ byte swap, a Face or a lazy expression is shown as CArrayMask, whose
1423
+ allocator makes an entity, so Object#dup would copy its cells; it is
1424
+ rebuilt here from its own view instead. The mask of an entity is an
1425
+ entity and is copied. */
1426
+ static VALUE
1427
+ ca_mask_view_dup (VALUE self)
1428
+ {
1429
+ volatile VALUE obj;
1430
+ const rb_data_type_t *type;
1431
+ CArray *ca, *cp;
1432
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1433
+ cp = (CArray *) ca_func[ca->obj_type].clone(ca);
1434
+ ca_keep_chain_flags(cp, ca);
1435
+ type = ca_typeddata[ca->obj_type];
1436
+ if ( type->function.dfree != ca_free ) {
1437
+ type = &carray_data_type; /* the copy is this object's to free */
1438
+ }
1439
+ obj = TypedData_Wrap_Struct(rb_obj_class(self), type, cp);
1440
+ rb_ivar_set(obj, rb_intern("masked_array"),
1441
+ rb_ivar_get(self, rb_intern("masked_array")));
1442
+ return obj;
1443
+ }
1444
+
1445
+ static VALUE
1446
+ rb_ca_mask_dup (VALUE self)
1447
+ {
1448
+ CArray *ca;
1449
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1450
+ if ( ! ca_is_view(ca) ) {
1451
+ return rb_call_super(0, NULL);
1452
+ }
1453
+ return ca_mask_view_dup(self);
1454
+ }
1455
+
1456
+ static VALUE
1457
+ rb_ca_mask_clone (int argc, VALUE *argv, VALUE self)
1458
+ {
1459
+ VALUE opts = Qnil, vfreeze = Qnil;
1460
+ volatile VALUE obj;
1461
+ CArray *ca;
1462
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1463
+ if ( ! ca_is_view(ca) ) {
1464
+ return rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
1465
+ }
1466
+ rb_scan_args(argc, argv, "0:", &opts);
1467
+ if ( ! NIL_P(opts) ) {
1468
+ /* rb_get_kwargs refuses any key but freeze:, as Kernel#clone does. */
1469
+ ID kw[1];
1470
+ VALUE val[1];
1471
+ kw[0] = rb_intern("freeze");
1472
+ rb_get_kwargs(opts, kw, 0, 1, val);
1473
+ if ( val[0] != Qundef ) {
1474
+ vfreeze = val[0];
1475
+ }
1476
+ }
1477
+ obj = ca_mask_view_dup(self);
1478
+ if ( RTEST(vfreeze) || ( NIL_P(vfreeze) && OBJ_FROZEN(self) ) ) {
1479
+ rb_obj_freeze(obj);
1480
+ }
1481
+ return obj;
1482
+ }
1483
+
1261
1484
  /* @overload mask= (new_mask)
1262
1485
 
1263
1486
  (Mask, Modification)
@@ -1491,14 +1714,9 @@ rb_ca_mask_fill (VALUE self, VALUE fval)
1491
1714
  return rb_ca_unmask_method(1, &fval, self);
1492
1715
  }
1493
1716
 
1494
- /* @overload unmask_copy (fill_value = nil)
1495
-
1496
- (Masking, Conversion)
1497
- Returns new unmasked array.
1498
- If the optional argument <code>fill_value</code> is given,
1499
- the masked elements are filled by <code>fill_value</code>.
1500
- The returned array doesn't have the mask array.
1501
- */
1717
+ /* A copy without the mask: with a fill value, the masked cells hold it.
1718
+ Behind rb_ca_unmask_copy / rb_ca_mask_fill_copy (C only; the Ruby
1719
+ surface is strip_mask). */
1502
1720
 
1503
1721
  static VALUE
1504
1722
  rb_ca_unmask_copy_method (int argc, VALUE *argv, VALUE self)
@@ -2202,7 +2420,7 @@ rb_ca_inherit_mask_replace_ruby (int argc, VALUE *argv, VALUE self)
2202
2420
  void
2203
2421
  Init_carray_mask (void)
2204
2422
  {
2205
- rb_define_private_method(rb_cCArray, "__create_mask__", rb_ca_create_mask, 0);
2423
+ rb_define_private_method(rb_cCArray, "add_mask", rb_ca_create_mask, 0);
2206
2424
  /*
2207
2425
  rb_define_private_method(rb_cCArray, "__update_mask__", rb_ca_update_mask, 0);
2208
2426
  */
@@ -2213,6 +2431,8 @@ Init_carray_mask (void)
2213
2431
 
2214
2432
  rb_define_method(rb_cCArray, "value", rb_ca_value_array, 0);
2215
2433
  rb_define_method(rb_cCArray, "mask", rb_ca_mask_array, 0);
2434
+ rb_define_method(rb_cCArrayMask, "dup", rb_ca_mask_dup, 0);
2435
+ rb_define_method(rb_cCArrayMask, "clone", rb_ca_mask_clone, -1);
2216
2436
  rb_define_method(rb_cCArray, "mask=", rb_ca_set_mask, 1);
2217
2437
  rb_define_method(rb_cCArray, "is_masked", rb_ca_is_masked, 0);
2218
2438
  rb_define_method(rb_cCArray, "is_not_masked", rb_ca_is_not_masked, 0);