carray 3.0.3 → 3.0.5

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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +469 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_descriptor.h +27 -24
  7. data/ext/ca_axis_dispatch.c +14 -26
  8. data/ext/ca_axis_group.c +27 -27
  9. data/ext/ca_binop_dispatch.c +1 -29
  10. data/ext/ca_binop_dispatch.h +0 -1
  11. data/ext/ca_categorical_iterator.c +231 -153
  12. data/ext/ca_compare.c +9 -20
  13. data/ext/ca_composite_dispatch.c +9 -9
  14. data/ext/ca_group_iter.c +16 -17
  15. data/ext/ca_kernel_iterator.c +1240 -2000
  16. data/ext/ca_kernel_iterator.h +502 -519
  17. data/ext/ca_monop_dispatch.c +82 -59
  18. data/ext/ca_monop_dispatch.h +1 -0
  19. data/ext/ca_obj_array.c +152 -45
  20. data/ext/ca_obj_bincmp.c +25 -21
  21. data/ext/ca_obj_binop.c +16 -26
  22. data/ext/ca_obj_bitarray.c +8 -3
  23. data/ext/ca_obj_bitfield.c +63 -49
  24. data/ext/ca_obj_block.c +18 -9
  25. data/ext/ca_obj_byte_swap.c +7 -7
  26. data/ext/ca_obj_const_string.c +188 -22
  27. data/ext/ca_obj_face.c +280 -58
  28. data/ext/ca_obj_face.h +19 -0
  29. data/ext/ca_obj_fake.c +15 -29
  30. data/ext/ca_obj_farray.c +6 -3
  31. data/ext/ca_obj_field.c +30 -8
  32. data/ext/ca_obj_fixlen_string.c +2 -3
  33. data/ext/ca_obj_grid.c +455 -134
  34. data/ext/ca_obj_meld.c +172 -34
  35. data/ext/ca_obj_moncmp.c +23 -8
  36. data/ext/ca_obj_monop.c +113 -67
  37. data/ext/ca_obj_object.c +210 -52
  38. data/ext/ca_obj_record.c +15 -7
  39. data/ext/ca_obj_reduce.c +17 -8
  40. data/ext/ca_obj_refer.c +42 -35
  41. data/ext/ca_obj_remap.c +30 -9
  42. data/ext/ca_obj_repeat.c +9 -10
  43. data/ext/ca_obj_roll.c +31 -10
  44. data/ext/ca_obj_select.c +48 -14
  45. data/ext/ca_obj_select_axis.c +15 -47
  46. data/ext/ca_obj_shift.c +41 -7
  47. data/ext/ca_obj_stack.c +180 -34
  48. data/ext/ca_obj_stride.c +190 -134
  49. data/ext/ca_obj_string.c +80 -4
  50. data/ext/ca_obj_tile.c +32 -11
  51. data/ext/ca_obj_time.c +22 -6
  52. data/ext/ca_obj_timedelta.c +22 -6
  53. data/ext/ca_obj_transpose.c +13 -7
  54. data/ext/ca_obj_triop.c +26 -32
  55. data/ext/ca_obj_window.c +267 -74
  56. data/ext/ca_op_ipower.c +4 -4
  57. data/ext/ca_sort_kernels.h +6 -3
  58. data/ext/ca_sweep_engine.c +2 -2
  59. data/ext/caframe_csv_reader.c +80 -1
  60. data/ext/carray.h +214 -75
  61. data/ext/carray_access.c +200 -99
  62. data/ext/carray_address_basis.c +343 -87
  63. data/ext/carray_attribute.c +113 -6
  64. data/ext/carray_bincount.c +10 -8
  65. data/ext/carray_broadcast.c +13 -8
  66. data/ext/carray_build_flags.h +3 -0
  67. data/ext/carray_call_cfunc.c +108 -0
  68. data/ext/carray_cast.c +375 -96
  69. data/ext/carray_cast_func.rb +90 -20
  70. data/ext/carray_class.c +4 -3
  71. data/ext/carray_config.h +28 -0
  72. data/ext/carray_conversion.c +18 -9
  73. data/ext/carray_copy.c +51 -14
  74. data/ext/carray_core.c +150 -55
  75. data/ext/carray_count.c +56 -20
  76. data/ext/carray_element.c +81 -33
  77. data/ext/carray_factorize.c +138 -84
  78. data/ext/carray_generate.c +199 -52
  79. data/ext/carray_histogram.c +63 -18
  80. data/ext/carray_hold.c +12 -15
  81. data/ext/carray_index_classifier.c +388 -176
  82. data/ext/carray_internal.h +348 -29
  83. data/ext/carray_kernels_bincmp.c +4453 -0
  84. data/ext/carray_kernels_binop.c +11368 -0
  85. data/ext/carray_kernels_init.c +1734 -0
  86. data/ext/carray_kernels_moncmp.c +2104 -0
  87. data/ext/carray_kernels_monop.c +18369 -0
  88. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  89. data/ext/carray_kernels_reduce_boolean.c +406 -0
  90. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  91. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  92. data/ext/carray_kernels_reduce_variance.c +3849 -0
  93. data/ext/carray_kernels_scan.c +4302 -0
  94. data/ext/carray_kernels_search.c +33829 -0
  95. data/ext/carray_kernels_sort.c +10897 -0
  96. data/ext/carray_kernels_triop.c +1864 -0
  97. data/ext/carray_key_windows.c +220 -0
  98. data/ext/carray_lazy.c +170 -111
  99. data/ext/carray_mask.c +337 -94
  100. data/ext/carray_median_percentile.c +82 -28
  101. data/ext/carray_memory_view.c +669 -561
  102. data/ext/carray_operator.c +129 -52
  103. data/ext/carray_order.c +604 -77
  104. data/ext/carray_partition.c +28 -27
  105. data/ext/carray_random.c +85 -31
  106. data/ext/carray_round.c +273 -0
  107. data/ext/carray_scatter.c +87 -45
  108. data/ext/carray_segment.c +3 -3
  109. data/ext/carray_slab.c +123 -37
  110. data/ext/carray_sort.c +259 -51
  111. data/ext/carray_sort_kernel.c +5 -7
  112. data/ext/carray_struct.c +54 -61
  113. data/ext/carray_test.c +26 -5
  114. data/ext/carray_time_text.c +4 -2
  115. data/ext/carray_undef.c +4 -0
  116. data/ext/carray_utils.c +309 -66
  117. data/ext/mk_call_cfunc.rb +19 -2
  118. data/ext/mkkernel.rb +403 -350
  119. data/ext/ruby_carray.c +10 -4
  120. data/ext/version.h +4 -4
  121. data/lib/carray/attribute.rb +139 -22
  122. data/lib/carray/autoload_carray.rb +8 -31
  123. data/lib/carray/autoload_method_extension.rb +14 -5
  124. data/lib/carray/axis_group.rb +255 -106
  125. data/lib/carray/basics.rb +105 -17
  126. data/lib/carray/bincount_nd.rb +12 -2
  127. data/lib/carray/block_iterator.rb +126 -23
  128. data/lib/carray/boolean_reduce.rb +17 -17
  129. data/lib/carray/categorical.rb +195 -59
  130. data/lib/carray/categorical_iterator.rb +132 -29
  131. data/lib/carray/complex.rb +5 -5
  132. data/lib/carray/conditional.rb +67 -18
  133. data/lib/carray/const_string.rb +24 -5
  134. data/lib/carray/construct.rb +15 -11
  135. data/lib/carray/data_type_extension.rb +9 -1
  136. data/lib/carray/distance_limit.rb +77 -0
  137. data/lib/carray/fixlen_string.rb +48 -3
  138. data/lib/carray/frame/column_verbs.rb +71 -0
  139. data/lib/carray/frame/concat.rb +17 -3
  140. data/lib/carray/frame/convert.rb +69 -0
  141. data/lib/carray/frame/csv_parser.rb +111 -17
  142. data/lib/carray/frame/describe.rb +3 -2
  143. data/lib/carray/frame/frame.rb +252 -28
  144. data/lib/carray/frame/group.rb +603 -101
  145. data/lib/carray/frame/io.rb +117 -28
  146. data/lib/carray/frame/join.rb +312 -51
  147. data/lib/carray/frame/records.rb +83 -7
  148. data/lib/carray/frame/reshape.rb +42 -35
  149. data/lib/carray/frame/sort.rb +7 -19
  150. data/lib/carray/frame/verbs.rb +188 -48
  151. data/lib/carray/frame/windows.rb +117 -0
  152. data/lib/carray/frame.rb +2 -0
  153. data/lib/carray/fuse_source.rb +42 -6
  154. data/lib/carray/fusion.rb +40 -16
  155. data/lib/carray/histogram.rb +6 -1
  156. data/lib/carray/inspect.rb +31 -8
  157. data/lib/carray/iterator.rb +85 -7
  158. data/lib/carray/key_windows.rb +620 -0
  159. data/lib/carray/lazy.rb +217 -183
  160. data/lib/carray/mask_gap_fill.rb +63 -57
  161. data/lib/carray/meld_reduce.rb +12 -14
  162. data/lib/carray/methods/bin.rb +26 -18
  163. data/lib/carray/methods/bincount.rb +16 -0
  164. data/lib/carray/methods/bit_string.rb +1 -1
  165. data/lib/carray/methods/choose.rb +16 -3
  166. data/lib/carray/methods/composition.rb +3 -1
  167. data/lib/carray/methods/gather_nd.rb +14 -5
  168. data/lib/carray/methods/insert_block.rb +2 -2
  169. data/lib/carray/methods/is_between.rb +59 -0
  170. data/lib/carray/methods/is_in.rb +61 -37
  171. data/lib/carray/methods/join.rb +1 -6
  172. data/lib/carray/methods/lag.rb +49 -0
  173. data/lib/carray/methods/locate_addr.rb +47 -51
  174. data/lib/carray/methods/mode.rb +1 -1
  175. data/lib/carray/methods/nunique.rb +11 -6
  176. data/lib/carray/methods/resize.rb +3 -3
  177. data/lib/carray/methods/value_counts.rb +4 -11
  178. data/lib/carray/record_order.rb +3 -3
  179. data/lib/carray/rng.rb +3 -0
  180. data/lib/carray/runtime.rb +53 -8
  181. data/lib/carray/segment_iterator.rb +323 -88
  182. data/lib/carray/serialize.rb +45 -14
  183. data/lib/carray/slab_iterator.rb +50 -0
  184. data/lib/carray/stack.rb +15 -12
  185. data/lib/carray/string.rb +113 -5
  186. data/lib/carray/string_operation_extension.rb +21 -6
  187. data/lib/carray/struct.rb +9 -21
  188. data/lib/carray/struct_builder.rb +24 -11
  189. data/lib/carray/time.rb +819 -158
  190. data/lib/carray/window_iterator.rb +122 -16
  191. data/lib/carray.rb +7 -0
  192. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  193. data/yard-stubs/ca_obj_field.rb +4 -0
  194. data/yard-stubs/ca_obj_grid.rb +21 -10
  195. data/yard-stubs/ca_obj_refer.rb +2 -1
  196. data/yard-stubs/ca_obj_roll.rb +2 -2
  197. data/yard-stubs/ca_obj_shift.rb +5 -1
  198. data/yard-stubs/ca_obj_tile.rb +1 -1
  199. data/yard-stubs/ca_obj_transpose.rb +5 -4
  200. data/yard-stubs/ca_obj_window.rb +8 -3
  201. data/yard-stubs/carray_access.rb +6 -1
  202. data/yard-stubs/carray_attribute.rb +3 -6
  203. data/yard-stubs/carray_cast.rb +12 -0
  204. data/yard-stubs/carray_conversion.rb +7 -2
  205. data/yard-stubs/carray_copy.rb +4 -2
  206. data/yard-stubs/carray_count.rb +4 -4
  207. data/yard-stubs/carray_element.rb +17 -10
  208. data/yard-stubs/carray_generate.rb +21 -1
  209. data/yard-stubs/carray_mask.rb +32 -3
  210. data/yard-stubs/carray_math.rb +41 -5
  211. data/yard-stubs/carray_median_percentile.rb +5 -2
  212. data/yard-stubs/carray_memory_view.rb +40 -23
  213. data/yard-stubs/carray_order.rb +129 -22
  214. data/yard-stubs/carray_random.rb +13 -4
  215. data/yard-stubs/carray_scatter.rb +17 -10
  216. data/yard-stubs/carray_slab.rb +9 -2
  217. data/yard-stubs/carray_sort.rb +6 -5
  218. data/yard-stubs/carray_test.rb +5 -3
  219. metadata +25 -3
  220. data/lib/carray/arrow_tensor.rb +0 -401
  221. data/lib/carray/table.rb +0 -108
data/ext/carray_mask.c CHANGED
@@ -37,16 +37,32 @@
37
37
  #define CA_MASK_WORD_BYTES 8
38
38
  #define CA_MASK_WORD_LSB 0x0101010101010101ULL
39
39
 
40
+ /* A mask may start at any byte (a window or a block view offsets it), so a
41
+ word is read and written through memcpy, never through a uint64_t
42
+ pointer; the compiler still lowers each to a single load or store. */
43
+ static inline uint64_t
44
+ ca_mask_word_load (const boolean8_t *p)
45
+ {
46
+ uint64_t w;
47
+ memcpy(&w, p, sizeof(w));
48
+ return w;
49
+ }
50
+
51
+ static inline void
52
+ ca_mask_word_store (boolean8_t *p, uint64_t w)
53
+ {
54
+ memcpy(p, &w, sizeof(w));
55
+ }
56
+
40
57
  /* ma[i] |= ms[i] for i in [0, n) -- used by ca_copy_mask_overlay_n */
41
58
  static inline void
42
59
  ca_mask_word_or (boolean8_t *ma, const boolean8_t *ms, ca_size_t n)
43
60
  {
44
61
  ca_size_t nw = n / CA_MASK_WORD_BYTES;
45
62
  ca_size_t i;
46
- uint64_t *wa = (uint64_t *) ma;
47
- const uint64_t *ws = (const uint64_t *) ms;
48
63
  for (i = 0; i < nw; i++) {
49
- wa[i] |= ws[i];
64
+ ca_mask_word_store(ma + i*CA_MASK_WORD_BYTES,
65
+ ca_mask_word_load(ma + i*CA_MASK_WORD_BYTES) | ca_mask_word_load(ms + i*CA_MASK_WORD_BYTES));
50
66
  }
51
67
  for (i = nw * CA_MASK_WORD_BYTES; i < n; i++) {
52
68
  ma[i] |= ms[i];
@@ -62,11 +78,9 @@ ca_mask_word_and (boolean8_t *md,
62
78
  {
63
79
  ca_size_t nw = n / CA_MASK_WORD_BYTES;
64
80
  ca_size_t i;
65
- uint64_t *wd = (uint64_t *) md;
66
- const uint64_t *wa = (const uint64_t *) ma;
67
- const uint64_t *wb = (const uint64_t *) mb;
68
81
  for (i = 0; i < nw; i++) {
69
- wd[i] = wa[i] & wb[i];
82
+ ca_mask_word_store(md + i*CA_MASK_WORD_BYTES,
83
+ ca_mask_word_load(ma + i*CA_MASK_WORD_BYTES) & ca_mask_word_load(mb + i*CA_MASK_WORD_BYTES));
70
84
  }
71
85
  for (i = nw * CA_MASK_WORD_BYTES; i < n; i++) {
72
86
  md[i] = ma[i] & mb[i];
@@ -82,11 +96,9 @@ ca_mask_word_xor (boolean8_t *md,
82
96
  {
83
97
  ca_size_t nw = n / CA_MASK_WORD_BYTES;
84
98
  ca_size_t i;
85
- uint64_t *wd = (uint64_t *) md;
86
- const uint64_t *wa = (const uint64_t *) ma;
87
- const uint64_t *wb = (const uint64_t *) mb;
88
99
  for (i = 0; i < nw; i++) {
89
- wd[i] = wa[i] ^ wb[i];
100
+ ca_mask_word_store(md + i*CA_MASK_WORD_BYTES,
101
+ ca_mask_word_load(ma + i*CA_MASK_WORD_BYTES) ^ ca_mask_word_load(mb + i*CA_MASK_WORD_BYTES));
90
102
  }
91
103
  for (i = nw * CA_MASK_WORD_BYTES; i < n; i++) {
92
104
  md[i] = ma[i] ^ mb[i];
@@ -99,10 +111,8 @@ ca_mask_word_not (boolean8_t *md, const boolean8_t *ms, ca_size_t n)
99
111
  {
100
112
  ca_size_t nw = n / CA_MASK_WORD_BYTES;
101
113
  ca_size_t i;
102
- uint64_t *wd = (uint64_t *) md;
103
- const uint64_t *ws = (const uint64_t *) ms;
104
114
  for (i = 0; i < nw; i++) {
105
- wd[i] = ws[i] ^ CA_MASK_WORD_LSB;
115
+ ca_mask_word_store(md + i*CA_MASK_WORD_BYTES, ca_mask_word_load(ms + i*CA_MASK_WORD_BYTES) ^ CA_MASK_WORD_LSB);
106
116
  }
107
117
  for (i = nw * CA_MASK_WORD_BYTES; i < n; i++) {
108
118
  md[i] = ms[i] ^ (boolean8_t) 1;
@@ -116,9 +126,8 @@ ca_mask_word_any (const boolean8_t *m, ca_size_t n)
116
126
  {
117
127
  ca_size_t nw = n / CA_MASK_WORD_BYTES;
118
128
  ca_size_t i;
119
- const uint64_t *w = (const uint64_t *) m;
120
129
  for (i = 0; i < nw; i++) {
121
- if ( w[i] != 0 ) return 1;
130
+ if ( ca_mask_word_load(m + i*CA_MASK_WORD_BYTES) != 0 ) return 1;
122
131
  }
123
132
  for (i = nw * CA_MASK_WORD_BYTES; i < n; i++) {
124
133
  if ( m[i] ) return 1;
@@ -134,9 +143,8 @@ ca_mask_word_all_set (const boolean8_t *m, ca_size_t n)
134
143
  {
135
144
  ca_size_t nw = n / CA_MASK_WORD_BYTES;
136
145
  ca_size_t i;
137
- const uint64_t *w = (const uint64_t *) m;
138
146
  for (i = 0; i < nw; i++) {
139
- if ( w[i] != CA_MASK_WORD_LSB ) return 0;
147
+ if ( ca_mask_word_load(m + i*CA_MASK_WORD_BYTES) != CA_MASK_WORD_LSB ) return 0;
140
148
  }
141
149
  for (i = nw * CA_MASK_WORD_BYTES; i < n; i++) {
142
150
  if ( ! m[i] ) return 0;
@@ -423,85 +431,221 @@ ca_create_mask_attach (VALUE arg)
423
431
  }
424
432
 
425
433
  CArray *
426
- ca_multi_parent_mask (CArray *p, CArray **standin)
434
+ ca_mask_standin_new (CArray *parent)
427
435
  {
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;
436
+ CArray *z = carray_new(CA_BOOLEAN, parent->ndim, parent->dim, 0, NULL);
437
+ MEMZERO(z->ptr, boolean8_t, z->elements);
438
+ if ( ca_is_readonly(parent) ) {
439
+ ca_set_flag(z, CA_FLAG_READ_ONLY);
437
440
  }
438
- ca_create_mask(p);
439
- return p->mask;
441
+ return z;
440
442
  }
441
443
 
442
444
  /* A value array or a mask array: a parent that can never be given a mask,
443
445
  whose stand-in therefore stays in place for good. */
444
446
  static int
445
- ca_multi_parent_mask_unmaskable (CArray *p)
447
+ ca_mask_standin_parent_unmaskable (CArray *parent)
448
+ {
449
+ return ca_is_value_array(parent) || ca_is_mask_array(parent);
450
+ }
451
+
452
+ CArray *
453
+ ca_mask_standin_current (CArray *mask_view, CArray *reading, CArray *parent,
454
+ CArray *standin)
455
+ {
456
+ if ( standin == NULL || reading != standin
457
+ || ca_mask_standin_parent_unmaskable(parent) ) {
458
+ return reading;
459
+ }
460
+ /* Not inside an attach window whose buffer is out: that buffer and the
461
+ detach to come are those of the stand-in. The attach and allocate
462
+ slots run before the buffer is published, and may still give way. */
463
+ if ( CAVIEW(mask_view)->attach > 0 && mask_view->ptr != NULL ) {
464
+ return reading;
465
+ }
466
+ /* A read-only parent (a lazy expression, a broadcast) is never given a
467
+ mask by a write, but can still have one later through its operand or
468
+ root. */
469
+ if ( ! ca_has_mask(parent) ) {
470
+ return reading;
471
+ }
472
+ ca_create_mask(parent);
473
+ return ( parent->mask != NULL ) ? parent->mask : reading;
474
+ }
475
+
476
+ void
477
+ ca_mask_standin_settle (CArray *parent, CArray *standin)
478
+ {
479
+ volatile VALUE holder = 0;
480
+ boolean8_t *z, one = 1;
481
+ ca_size_t *addrs;
482
+ ca_size_t i, m = 0, n;
483
+
484
+ if ( standin == NULL || ca_test_flag(standin, CA_FLAG_READ_ONLY) ) {
485
+ return;
486
+ }
487
+ z = (boolean8_t *) standin->ptr;
488
+ n = standin->elements;
489
+ for ( i = 0; i < n && ! z[i]; i++ ) ;
490
+ if ( i == n ) {
491
+ return;
492
+ }
493
+ if ( ca_mask_standin_parent_unmaskable(parent) ) {
494
+ MEMZERO(z, boolean8_t, n);
495
+ rb_raise(rb_eTypeError, "can not create mask array for the %s array",
496
+ ca_is_value_array(parent) ? "value" : "mask");
497
+ }
498
+ ca_create_mask(parent);
499
+ /* The trues are added to the parent's mask, not copied over it: the
500
+ parent may have come to have masked cells of its own meanwhile. */
501
+ addrs = ALLOCV_N(ca_size_t, holder, n);
502
+ for ( ; i < n; i++ ) {
503
+ if ( z[i] ) {
504
+ addrs[m++] = i;
505
+ }
506
+ }
507
+ ca_fill_addrs(parent->mask, m, addrs, &one);
508
+ ALLOCV_END(holder);
509
+ MEMZERO(z, boolean8_t, n);
510
+ }
511
+
512
+ CArray *
513
+ ca_multi_parent_mask (CArray *p, CArray **standin)
446
514
  {
447
- return ca_is_value_array(p) || ca_is_mask_array(p);
515
+ *standin = NULL;
516
+ if ( ! ca_has_mask(p) ) {
517
+ *standin = ca_mask_standin_new(p);
518
+ return *standin;
519
+ }
520
+ ca_create_mask(p);
521
+ return p->mask;
448
522
  }
449
523
 
450
524
  void
451
525
  ca_multi_parent_mask_refresh (CArray *mask, CArray **parents,
452
- CArray **standins, int32_t n, int for_write)
526
+ CArray **standins, int32_t n)
453
527
  {
454
528
  CAMultiParent *mp = (CAMultiParent *) mask;
455
529
  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 ) ) {
530
+ if ( standins == NULL ) {
460
531
  return;
461
532
  }
462
533
  /* A replaced stand-in stays allocated until the view is freed: a copy
463
534
  of the mask (dup) may still point at it. */
464
535
  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
- }
536
+ mp->parents[k] = ca_mask_standin_current(mask, mp->parents[k], parents[k],
537
+ standins[k]);
538
+ }
539
+ CAVIEW(mask)->parent = mp->parents[0];
540
+ }
541
+
542
+ typedef struct {
543
+ CArray *mask;
544
+ CArray **blanks;
545
+ CArray **saved;
546
+ CArray *saved_parent;
547
+ int32_t n;
548
+ int finished;
549
+ VALUE (*body)(VALUE);
550
+ VALUE arg;
551
+ } ca_mp_trial_t;
552
+
553
+ static VALUE
554
+ ca_mp_trial_body (VALUE p)
555
+ {
556
+ ca_mp_trial_t *t = (ca_mp_trial_t *) p;
557
+ t->body(t->arg);
558
+ t->finished = 1;
559
+ return Qnil;
560
+ }
561
+
562
+ static void
563
+ ca_mp_trial_free_blanks (ca_mp_trial_t *t)
564
+ {
565
+ int32_t k;
566
+ for ( k = 0; k < t->n; k++ ) {
567
+ ca_free(t->blanks[k]);
568
+ t->blanks[k] = NULL;
479
569
  }
480
570
  }
481
571
 
572
+ static VALUE
573
+ ca_mp_trial_restore (VALUE p)
574
+ {
575
+ ca_mp_trial_t *t = (ca_mp_trial_t *) p;
576
+ CAMultiParent *mp = (CAMultiParent *) t->mask;
577
+ int32_t k;
578
+ for ( k = 0; k < t->n; k++ ) {
579
+ mp->parents[k] = t->saved[k];
580
+ }
581
+ CAVIEW(t->mask)->parent = t->saved_parent;
582
+ if ( ! t->finished ) {
583
+ ca_mp_trial_free_blanks(t);
584
+ }
585
+ return Qnil;
586
+ }
587
+
482
588
  void
483
- ca_multi_parent_mask_check (CArray *mask, CArray **parents,
484
- CArray **standins, int32_t n)
589
+ ca_multi_parent_mask_refuse_first (CArray *mask, CArray **parents,
590
+ CArray **standins, int32_t n,
591
+ VALUE (*body)(VALUE), VALUE arg)
485
592
  {
486
593
  CAMultiParent *mp = (CAMultiParent *) mask;
487
- int32_t k;
594
+ volatile VALUE h_blank = 0, h_saved = 0;
595
+ ca_mp_trial_t t;
596
+ int32_t k, refused = -1;
488
597
  if ( standins == NULL ) {
489
598
  return;
490
599
  }
491
600
  for ( k = 0; k < n; k++ ) {
492
- CArray *z = standins[k];
601
+ if ( standins[k] != NULL && mp->parents[k] == standins[k]
602
+ && ca_mask_standin_parent_unmaskable(parents[k]) ) {
603
+ break;
604
+ }
605
+ }
606
+ if ( k == n ) {
607
+ return;
608
+ }
609
+ t.mask = mask;
610
+ t.n = n;
611
+ t.finished = 0;
612
+ t.body = body;
613
+ t.arg = arg;
614
+ t.saved_parent = CAVIEW(mask)->parent;
615
+ t.blanks = ALLOCV_N(CArray *, h_blank, n);
616
+ t.saved = ALLOCV_N(CArray *, h_saved, n);
617
+ for ( k = 0; k < n; k++ ) {
618
+ t.blanks[k] = NULL;
619
+ }
620
+ for ( k = 0; k < n; k++ ) {
621
+ CArray *m = mp->parents[k];
622
+ t.saved[k] = m;
623
+ t.blanks[k] = carray_new(CA_BOOLEAN, m->ndim, m->dim, 0, NULL);
624
+ MEMZERO(t.blanks[k]->ptr, boolean8_t, t.blanks[k]->elements);
625
+ }
626
+ for ( k = 0; k < n; k++ ) {
627
+ mp->parents[k] = t.blanks[k];
628
+ }
629
+ CAVIEW(mask)->parent = t.blanks[0];
630
+ rb_ensure(ca_mp_trial_body, (VALUE) &t, ca_mp_trial_restore, (VALUE) &t);
631
+ for ( k = 0; k < n && refused < 0; k++ ) {
632
+ CArray *z = t.blanks[k];
493
633
  ca_size_t i;
494
- if ( z == NULL || mp->parents[k] != z
495
- || ! ca_multi_parent_mask_unmaskable(parents[k]) ) {
634
+ if ( standins[k] == NULL || t.saved[k] != standins[k]
635
+ || ! ca_mask_standin_parent_unmaskable(parents[k]) ) {
496
636
  continue;
497
637
  }
498
638
  for ( i = 0; i < z->elements && ! ((boolean8_t *) z->ptr)[i]; i++ ) ;
499
- if ( i == z->elements ) {
500
- continue;
639
+ if ( i < z->elements ) {
640
+ refused = k;
501
641
  }
502
- MEMZERO(z->ptr, boolean8_t, z->elements);
642
+ }
643
+ ca_mp_trial_free_blanks(&t);
644
+ ALLOCV_END(h_blank);
645
+ ALLOCV_END(h_saved);
646
+ if ( refused >= 0 ) {
503
647
  rb_raise(rb_eTypeError, "can not create mask array for the %s array",
504
- ca_is_value_array(parents[k]) ? "value" : "mask");
648
+ ca_is_value_array(parents[refused]) ? "value" : "mask");
505
649
  }
506
650
  }
507
651
 
@@ -510,26 +654,20 @@ ca_multi_parent_mask_settle (CArray *mask, CArray **parents,
510
654
  CArray **standins, int32_t n)
511
655
  {
512
656
  CAMultiParent *mp = (CAMultiParent *) mask;
513
- int32_t k;
657
+ int32_t k, pass;
514
658
  if ( standins == NULL ) {
515
659
  return;
516
660
  }
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;
661
+ /* The parts that can have no mask first, so that a refused true leaves
662
+ the other parts as they were. */
663
+ for ( pass = 0; pass < 2; pass++ ) {
664
+ for ( k = 0; k < n; k++ ) {
665
+ if ( standins[k] == NULL || mp->parents[k] != standins[k]
666
+ || ca_mask_standin_parent_unmaskable(parents[k]) != ( pass == 0 ) ) {
667
+ continue;
668
+ }
669
+ ca_mask_standin_settle(parents[k], standins[k]);
529
670
  }
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
671
  }
534
672
  }
535
673
 
@@ -553,6 +691,10 @@ ca_create_mask (void *ap)
553
691
  }
554
692
 
555
693
  ca_func[ca->obj_type].create_mask(ca);
694
+ if ( ! ca->mask ) {
695
+ /* a lazy expression with no masked operand has no mask to make */
696
+ return;
697
+ }
556
698
  ca_set_flag(ca->mask, CA_FLAG_MASK_ARRAY); /* set array as mask array */
557
699
  if ( ca_is_view(ca) ) {
558
700
  if ( CAVIEW(ca)->attach ) {
@@ -561,6 +703,7 @@ ca_create_mask (void *ap)
561
703
  then comes off again, since the view's sync and detach would
562
704
  find it attached to nothing. */
563
705
  int tag = 0;
706
+ /* protect: the mask comes off its view before it is freed */
564
707
  rb_protect(ca_create_mask_attach, (VALUE) ca->mask, &tag);
565
708
  if ( tag ) {
566
709
  CArray *mask = ca->mask;
@@ -606,6 +749,13 @@ ca_setup_mask (void *ap, CArray *mask)
606
749
  {
607
750
  CArray *ca = (CArray *) ap;
608
751
 
752
+ if ( mask ) {
753
+ if ( ! ca_is_boolean_type(mask) ) {
754
+ rb_raise(rb_eCADataTypeError, "a mask is a boolean array");
755
+ }
756
+ ca_check_same_elements(ca, mask);
757
+ }
758
+
609
759
  ca_update_mask(ca);
610
760
 
611
761
  if ( mask ) {
@@ -685,6 +835,21 @@ ca_copy_mask_overlay_core (CArray *ca, ca_size_t elements, int n,
685
835
  char *modes;
686
836
  int i, some_has_mask = 0;
687
837
 
838
+ if ( elements > ca->elements ) {
839
+ elements = ca->elements;
840
+ }
841
+
842
+ /* An array source is read cell by cell over the destination's cells;
843
+ a scalar source's one cell applies to all of them. */
844
+ for (i=0; i<n; i++) {
845
+ cs = slist[i];
846
+ if ( cs && ! ca_is_scalar(cs) && cs->elements < elements ) {
847
+ rb_raise(rb_eArgError,
848
+ "mask source has %lld elements, fewer than the %lld of the destination",
849
+ (long long) cs->elements, (long long) elements);
850
+ }
851
+ }
852
+
688
853
  for (i=0; i<n; i++) {
689
854
  if ( slist[i] && ca_has_mask(slist[i]) ) {
690
855
  some_has_mask = 1;
@@ -703,10 +868,6 @@ ca_copy_mask_overlay_core (CArray *ca, ca_size_t elements, int n,
703
868
  return;
704
869
  }
705
870
 
706
- if ( elements > ca->elements ) {
707
- elements = ca->elements;
708
- }
709
-
710
871
  o.list = ALLOCA_N(CArray *, n + 1);
711
872
  o.snap = ALLOCA_N(boolean8_t *, n);
712
873
  o.att = ALLOCA_N(CArray *, n);
@@ -900,6 +1061,10 @@ ca_unmask (void *ap, char *fill_value)
900
1061
  {
901
1062
  CArray *ca = (CArray *) ap;
902
1063
 
1064
+ if ( ca_is_readonly(ca) ) {
1065
+ ca_refuse_read_only();
1066
+ }
1067
+
903
1068
  ca_update_mask(ca);
904
1069
  if ( ca->mask ) {
905
1070
  if ( ! fill_value ) {
@@ -1258,6 +1423,72 @@ rb_ca_mask_array (VALUE self)
1258
1423
  }
1259
1424
  }
1260
1425
 
1426
+ /* dup / clone of a mask. The mask of a view is a view over its parent's
1427
+ mask, and its dup, like the dup of any view, is another view onto the
1428
+ same parent mask: it follows later changes and a write to it lands in
1429
+ the parent's mask (copy makes a mask of its own). A mask over a cast, a
1430
+ byte swap, a Face or a lazy expression is shown as CArrayMask, whose
1431
+ allocator makes an entity, so Object#dup would copy its cells; it is
1432
+ rebuilt here from its own view instead. The mask of an entity is an
1433
+ entity and is copied. */
1434
+ static VALUE
1435
+ ca_mask_view_dup (VALUE self)
1436
+ {
1437
+ volatile VALUE obj;
1438
+ const rb_data_type_t *type;
1439
+ CArray *ca, *cp;
1440
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1441
+ cp = (CArray *) ca_func[ca->obj_type].clone(ca);
1442
+ ca_keep_chain_flags(cp, ca);
1443
+ type = ca_typeddata[ca->obj_type];
1444
+ if ( type->function.dfree != ca_free ) {
1445
+ type = &carray_data_type; /* the copy is this object's to free */
1446
+ }
1447
+ obj = TypedData_Wrap_Struct(rb_obj_class(self), type, cp);
1448
+ rb_ivar_set(obj, rb_intern("masked_array"),
1449
+ rb_ivar_get(self, rb_intern("masked_array")));
1450
+ return obj;
1451
+ }
1452
+
1453
+ static VALUE
1454
+ rb_ca_mask_dup (VALUE self)
1455
+ {
1456
+ CArray *ca;
1457
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1458
+ if ( ! ca_is_view(ca) ) {
1459
+ return rb_call_super(0, NULL);
1460
+ }
1461
+ return ca_mask_view_dup(self);
1462
+ }
1463
+
1464
+ static VALUE
1465
+ rb_ca_mask_clone (int argc, VALUE *argv, VALUE self)
1466
+ {
1467
+ VALUE opts = Qnil, vfreeze = Qnil;
1468
+ volatile VALUE obj;
1469
+ CArray *ca;
1470
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1471
+ if ( ! ca_is_view(ca) ) {
1472
+ return rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
1473
+ }
1474
+ rb_scan_args(argc, argv, "0:", &opts);
1475
+ if ( ! NIL_P(opts) ) {
1476
+ /* rb_get_kwargs refuses any key but freeze:, as Kernel#clone does. */
1477
+ ID kw[1];
1478
+ VALUE val[1];
1479
+ kw[0] = rb_intern("freeze");
1480
+ rb_get_kwargs(opts, kw, 0, 1, val);
1481
+ if ( val[0] != Qundef ) {
1482
+ vfreeze = val[0];
1483
+ }
1484
+ }
1485
+ obj = ca_mask_view_dup(self);
1486
+ if ( RTEST(vfreeze) || ( NIL_P(vfreeze) && OBJ_FROZEN(self) ) ) {
1487
+ rb_obj_freeze(obj);
1488
+ }
1489
+ return obj;
1490
+ }
1491
+
1261
1492
  /* @overload mask= (new_mask)
1262
1493
 
1263
1494
  (Mask, Modification)
@@ -1491,14 +1722,9 @@ rb_ca_mask_fill (VALUE self, VALUE fval)
1491
1722
  return rb_ca_unmask_method(1, &fval, self);
1492
1723
  }
1493
1724
 
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
- */
1725
+ /* A copy without the mask: with a fill value, the masked cells hold it.
1726
+ Behind rb_ca_unmask_copy / rb_ca_mask_fill_copy (C only; the Ruby
1727
+ surface is strip_mask). */
1502
1728
 
1503
1729
  static VALUE
1504
1730
  rb_ca_unmask_copy_method (int argc, VALUE *argv, VALUE self)
@@ -1654,6 +1880,19 @@ rb_ca_mask_where (int argc, VALUE *argv, VALUE self)
1654
1880
  return ca_mask_copy_where(self, argc, argv);
1655
1881
  }
1656
1882
 
1883
+ /* inherit_mask's sources are read cell by cell over self, so an array
1884
+ source has self's number of cells (a scalar's one cell applies to all). */
1885
+ static void
1886
+ ca_inherit_mask_check_source (CArray *ca, CArray *cs)
1887
+ {
1888
+ if ( ! ca_is_scalar(cs) && cs->elements != ca->elements ) {
1889
+ rb_raise(rb_eArgError,
1890
+ "%s: mask source has %lld elements, the receiver %lld",
1891
+ ca_calling_method_name(),
1892
+ (long long) cs->elements, (long long) ca->elements);
1893
+ }
1894
+ }
1895
+
1657
1896
  /* @overload inherit_mask (*others):
1658
1897
 
1659
1898
  (Masking, Destructive)
@@ -1677,6 +1916,7 @@ rb_ca_inherit_mask_method (int argc, VALUE *argv, VALUE self)
1677
1916
  for (i=0; i<argc; i++) {
1678
1917
  if ( rb_obj_is_carray(argv[i]) ) {
1679
1918
  TypedData_Get_Struct(argv[i], CArray, &carray_data_type, cs);
1919
+ ca_inherit_mask_check_source(ca, cs);
1680
1920
  slist[i] = cs;
1681
1921
  }
1682
1922
  else {
@@ -1720,6 +1960,7 @@ rb_ca_inherit_mask (VALUE self, int n, ...)
1720
1960
  other = va_arg(rothers, VALUE);
1721
1961
  if ( rb_obj_is_carray(other) ) {
1722
1962
  TypedData_Get_Struct(other, CArray, &carray_data_type, cs);
1963
+ ca_inherit_mask_check_source(ca, cs);
1723
1964
  slist[i] = cs;
1724
1965
  }
1725
1966
  else {
@@ -1758,6 +1999,7 @@ rb_ca_inherit_mask_replace_method (int argc, VALUE *argv, VALUE self)
1758
1999
  for (i=0; i<argc; i++) {
1759
2000
  if ( rb_obj_is_carray(argv[i]) ) {
1760
2001
  TypedData_Get_Struct(argv[i], CArray, &carray_data_type, cs);
2002
+ ca_inherit_mask_check_source(ca, cs);
1761
2003
  slist[i] = cs;
1762
2004
  }
1763
2005
  else {
@@ -1801,6 +2043,7 @@ rb_ca_inherit_mask_replace (VALUE self, int n, ...)
1801
2043
  other = va_arg(rothers, VALUE);
1802
2044
  if ( rb_obj_is_carray(other) ) {
1803
2045
  TypedData_Get_Struct(other, CArray, &carray_data_type, cs);
2046
+ ca_inherit_mask_check_source(ca, cs);
1804
2047
  slist[i] = cs;
1805
2048
  }
1806
2049
  else {
@@ -2048,11 +2291,9 @@ ca_binop_bit_or_i_boolean8_fast (ca_size_t n, boolean8_t *m,
2048
2291
  accumulating; here we need 3-arg). */
2049
2292
  ca_size_t nw = n / CA_MASK_WORD_BYTES;
2050
2293
  ca_size_t j;
2051
- uint64_t *wd = (uint64_t *) q3;
2052
- const uint64_t *wa = (const uint64_t *) q1;
2053
- const uint64_t *wb = (const uint64_t *) q2;
2054
2294
  for (j = 0; j < nw; j++) {
2055
- wd[j] = wa[j] | wb[j];
2295
+ ca_mask_word_store(q3 + j*CA_MASK_WORD_BYTES,
2296
+ ca_mask_word_load(q1 + j*CA_MASK_WORD_BYTES) | ca_mask_word_load(q2 + j*CA_MASK_WORD_BYTES));
2056
2297
  }
2057
2298
  for (j = nw * CA_MASK_WORD_BYTES; j < n; j++) {
2058
2299
  q3[j] = q1[j] | q2[j];
@@ -2202,7 +2443,7 @@ rb_ca_inherit_mask_replace_ruby (int argc, VALUE *argv, VALUE self)
2202
2443
  void
2203
2444
  Init_carray_mask (void)
2204
2445
  {
2205
- rb_define_private_method(rb_cCArray, "__create_mask__", rb_ca_create_mask, 0);
2446
+ rb_define_private_method(rb_cCArray, "add_mask", rb_ca_create_mask, 0);
2206
2447
  /*
2207
2448
  rb_define_private_method(rb_cCArray, "__update_mask__", rb_ca_update_mask, 0);
2208
2449
  */
@@ -2213,6 +2454,8 @@ Init_carray_mask (void)
2213
2454
 
2214
2455
  rb_define_method(rb_cCArray, "value", rb_ca_value_array, 0);
2215
2456
  rb_define_method(rb_cCArray, "mask", rb_ca_mask_array, 0);
2457
+ rb_define_method(rb_cCArrayMask, "dup", rb_ca_mask_dup, 0);
2458
+ rb_define_method(rb_cCArrayMask, "clone", rb_ca_mask_clone, -1);
2216
2459
  rb_define_method(rb_cCArray, "mask=", rb_ca_set_mask, 1);
2217
2460
  rb_define_method(rb_cCArray, "is_masked", rb_ca_is_masked, 0);
2218
2461
  rb_define_method(rb_cCArray, "is_not_masked", rb_ca_is_not_masked, 0);