carray 3.0.2 → 3.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +568 -0
  3. data/README.md +6 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +220 -0
  7. data/ext/ca_axis_group.c +201 -123
  8. data/ext/ca_binop_dispatch.c +46 -52
  9. data/ext/ca_binop_dispatch.h +1 -1
  10. data/ext/ca_categorical_iterator.c +249 -183
  11. data/ext/ca_compare.c +7 -12
  12. data/ext/ca_for_buffer.h +21 -68
  13. data/ext/ca_group_iter.c +38 -23
  14. data/ext/ca_kernel_iterator.c +1765 -2076
  15. data/ext/ca_kernel_iterator.h +584 -566
  16. data/ext/ca_monop_dispatch.c +86 -63
  17. data/ext/ca_monop_dispatch.h +5 -0
  18. data/ext/ca_obj_array.c +223 -56
  19. data/ext/ca_obj_bincmp.c +172 -138
  20. data/ext/ca_obj_binop.c +116 -230
  21. data/ext/ca_obj_bitarray.c +40 -26
  22. data/ext/ca_obj_bitfield.c +100 -68
  23. data/ext/ca_obj_block.c +19 -9
  24. data/ext/ca_obj_byte_swap.c +45 -46
  25. data/ext/ca_obj_const_string.c +269 -44
  26. data/ext/ca_obj_face.c +612 -89
  27. data/ext/ca_obj_face.h +111 -47
  28. data/ext/ca_obj_fake.c +36 -79
  29. data/ext/ca_obj_farray.c +7 -3
  30. data/ext/ca_obj_field.c +33 -8
  31. data/ext/ca_obj_fixlen_string.c +23 -24
  32. data/ext/ca_obj_grid.c +541 -210
  33. data/ext/ca_obj_meld.c +331 -111
  34. data/ext/ca_obj_moncmp.c +80 -65
  35. data/ext/ca_obj_monop.c +177 -149
  36. data/ext/ca_obj_object.c +664 -248
  37. data/ext/ca_obj_record.c +63 -23
  38. data/ext/ca_obj_reduce.c +18 -16
  39. data/ext/ca_obj_refer.c +140 -58
  40. data/ext/ca_obj_remap.c +85 -24
  41. data/ext/ca_obj_repeat.c +24 -9
  42. data/ext/ca_obj_roll.c +121 -16
  43. data/ext/ca_obj_select.c +61 -58
  44. data/ext/ca_obj_select_axis.c +73 -107
  45. data/ext/ca_obj_shift.c +32 -102
  46. data/ext/ca_obj_stack.c +372 -122
  47. data/ext/ca_obj_stride.c +348 -140
  48. data/ext/ca_obj_string.c +88 -22
  49. data/ext/ca_obj_tile.c +38 -21
  50. data/ext/ca_obj_time.c +45 -31
  51. data/ext/ca_obj_timedelta.c +43 -29
  52. data/ext/ca_obj_transpose.c +17 -6
  53. data/ext/ca_obj_triop.c +125 -141
  54. data/ext/ca_obj_window.c +330 -44
  55. data/ext/ca_op_ipower.c +24 -11
  56. data/ext/ca_op_powi.h +57 -30
  57. data/ext/ca_pow5_table.h +656 -0
  58. data/ext/ca_sort_kernels.h +70 -0
  59. data/ext/ca_sweep_engine.c +104 -81
  60. data/ext/ca_sweep_engine.h +7 -20
  61. data/ext/ca_triop_dispatch.c +4 -1
  62. data/ext/ca_triop_dispatch.h +5 -2
  63. data/ext/caframe_csv_reader.c +542 -0
  64. data/ext/carray.h +241 -92
  65. data/ext/carray_access.c +608 -276
  66. data/ext/carray_address_basis.c +494 -97
  67. data/ext/carray_attribute.c +129 -4
  68. data/ext/carray_bincount.c +39 -7
  69. data/ext/carray_broadcast.c +56 -19
  70. data/ext/carray_build_flags.h +1 -1
  71. data/ext/carray_call_cfunc.c +108 -28
  72. data/ext/carray_cast.c +1576 -223
  73. data/ext/carray_cast_func.rb +77 -24
  74. data/ext/carray_class.c +4 -3
  75. data/ext/carray_conversion.c +208 -75
  76. data/ext/carray_copy.c +82 -24
  77. data/ext/carray_core.c +646 -162
  78. data/ext/carray_count.c +171 -88
  79. data/ext/carray_element.c +94 -60
  80. data/ext/carray_factorize.c +670 -324
  81. data/ext/carray_generate.c +260 -83
  82. data/ext/carray_histogram.c +209 -106
  83. data/ext/carray_hold.c +14 -16
  84. data/ext/carray_index_classifier.c +422 -243
  85. data/ext/carray_internal.h +692 -3
  86. data/ext/carray_kernels_bincmp.c +7 -0
  87. data/ext/carray_kernels_binop.c +487 -120
  88. data/ext/carray_kernels_init.c +653 -50
  89. data/ext/carray_kernels_moncmp.c +15 -8
  90. data/ext/carray_kernels_monop.c +99 -43
  91. data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
  92. data/ext/carray_kernels_reduce_boolean.c +112 -36
  93. data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
  94. data/ext/carray_kernels_reduce_extreme.c +3032 -2892
  95. data/ext/carray_kernels_reduce_variance.c +439 -500
  96. data/ext/carray_kernels_scan.c +1097 -488
  97. data/ext/carray_kernels_search.c +3787 -2176
  98. data/ext/carray_kernels_sort.c +1200 -920
  99. data/ext/carray_kernels_triop.c +479 -7
  100. data/ext/carray_key_windows.c +216 -0
  101. data/ext/carray_lazy.c +967 -153
  102. data/ext/carray_loop.c +81 -65
  103. data/ext/carray_mask.c +910 -324
  104. data/ext/carray_math_kernel.h +1 -0
  105. data/ext/carray_median_percentile.c +299 -100
  106. data/ext/carray_memory_view.c +872 -758
  107. data/ext/carray_operator.c +1171 -364
  108. data/ext/carray_order.c +505 -133
  109. data/ext/carray_partition.c +112 -65
  110. data/ext/carray_random.c +327 -239
  111. data/ext/carray_round.c +273 -0
  112. data/ext/carray_scatter.c +346 -78
  113. data/ext/carray_segment.c +257 -0
  114. data/ext/carray_slab.c +249 -86
  115. data/ext/carray_sort.c +224 -227
  116. data/ext/carray_sort_kernel.c +8 -1
  117. data/ext/carray_struct.c +118 -39
  118. data/ext/carray_test.c +193 -69
  119. data/ext/carray_time_text.c +1182 -0
  120. data/ext/carray_undef.c +4 -0
  121. data/ext/carray_utils.c +579 -113
  122. data/ext/extconf.rb +27 -2
  123. data/ext/mk_call_cfunc.rb +19 -4
  124. data/ext/mk_pow5_table.rb +35 -0
  125. data/ext/mkkernel.rb +1202 -1014
  126. data/ext/ruby_carray.c +17 -5
  127. data/ext/version.h +4 -4
  128. data/ext/version.rb +4 -2
  129. data/lib/carray/attribute.rb +160 -17
  130. data/lib/carray/autoload_carray.rb +23 -27
  131. data/lib/carray/autoload_method_extension.rb +20 -5
  132. data/lib/carray/axis_group.rb +360 -63
  133. data/lib/carray/basics.rb +162 -28
  134. data/lib/carray/bincount_nd.rb +18 -2
  135. data/lib/carray/block_iterator.rb +231 -58
  136. data/lib/carray/boolean_reduce.rb +34 -42
  137. data/lib/carray/categorical.rb +242 -52
  138. data/lib/carray/categorical_iterator.rb +437 -827
  139. data/lib/carray/complex.rb +41 -34
  140. data/lib/carray/conditional.rb +150 -14
  141. data/lib/carray/const_string.rb +59 -4
  142. data/lib/carray/construct.rb +15 -11
  143. data/lib/carray/data_type_extension.rb +1 -0
  144. data/lib/carray/distance_limit.rb +77 -0
  145. data/lib/carray/fixlen_string.rb +7 -1
  146. data/lib/carray/frame/column_verbs.rb +70 -0
  147. data/lib/carray/frame/concat.rb +157 -6
  148. data/lib/carray/frame/convert.rb +82 -7
  149. data/lib/carray/frame/csv_parser.rb +688 -87
  150. data/lib/carray/frame/describe.rb +80 -0
  151. data/lib/carray/frame/frame.rb +369 -45
  152. data/lib/carray/frame/group.rb +631 -90
  153. data/lib/carray/frame/io.rb +506 -79
  154. data/lib/carray/frame/join.rb +411 -62
  155. data/lib/carray/frame/records.rb +116 -19
  156. data/lib/carray/frame/reshape.rb +455 -0
  157. data/lib/carray/frame/sort.rb +30 -18
  158. data/lib/carray/frame/verbs.rb +868 -61
  159. data/lib/carray/frame/windows.rb +117 -0
  160. data/lib/carray/frame.rb +4 -0
  161. data/lib/carray/fuse_source.rb +118 -2
  162. data/lib/carray/fusion.rb +257 -42
  163. data/lib/carray/histogram.rb +6 -1
  164. data/lib/carray/inspect.rb +54 -13
  165. data/lib/carray/iterator.rb +99 -9
  166. data/lib/carray/key_windows.rb +620 -0
  167. data/lib/carray/lazy.rb +216 -193
  168. data/lib/carray/mask_gap_fill.rb +112 -92
  169. data/lib/carray/math.rb +32 -19
  170. data/lib/carray/meld_reduce.rb +52 -21
  171. data/lib/carray/methods/align_addr.rb +8 -4
  172. data/lib/carray/methods/bin.rb +26 -18
  173. data/lib/carray/methods/bincount.rb +18 -2
  174. data/lib/carray/methods/bit_string.rb +15 -4
  175. data/lib/carray/methods/choose.rb +16 -3
  176. data/lib/carray/methods/composition.rb +18 -10
  177. data/lib/carray/methods/factorize.rb +2 -2
  178. data/lib/carray/methods/gather_nd.rb +25 -5
  179. data/lib/carray/methods/insert_block.rb +9 -14
  180. data/lib/carray/methods/is_between.rb +59 -0
  181. data/lib/carray/methods/is_in.rb +140 -10
  182. data/lib/carray/methods/join.rb +2 -7
  183. data/lib/carray/methods/lag.rb +49 -0
  184. data/lib/carray/methods/locate_addr.rb +182 -45
  185. data/lib/carray/methods/mode.rb +18 -1
  186. data/lib/carray/methods/nunique.rb +11 -6
  187. data/lib/carray/methods/repeat.rb +1 -20
  188. data/lib/carray/methods/resize.rb +21 -23
  189. data/lib/carray/methods/snap.rb +34 -12
  190. data/lib/carray/methods/unique.rb +11 -2
  191. data/lib/carray/methods/value_counts.rb +4 -11
  192. data/lib/carray/record_order.rb +208 -0
  193. data/lib/carray/rng.rb +3 -0
  194. data/lib/carray/runtime.rb +65 -17
  195. data/lib/carray/segment_iterator.rb +1221 -0
  196. data/lib/carray/serialize.rb +214 -30
  197. data/lib/carray/slab_iterator.rb +101 -27
  198. data/lib/carray/stack.rb +10 -4
  199. data/lib/carray/string.rb +105 -5
  200. data/lib/carray/string_operation_extension.rb +12 -4
  201. data/lib/carray/struct.rb +137 -58
  202. data/lib/carray/struct_builder.rb +124 -17
  203. data/lib/carray/time.rb +1222 -186
  204. data/lib/carray/window_iterator.rb +242 -81
  205. data/lib/carray.rb +9 -2
  206. data/yard-stubs/ca_obj_array.rb +4 -4
  207. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  208. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  209. data/yard-stubs/ca_obj_fake.rb +1 -1
  210. data/yard-stubs/ca_obj_field.rb +5 -1
  211. data/yard-stubs/ca_obj_grid.rb +21 -10
  212. data/yard-stubs/ca_obj_refer.rb +5 -4
  213. data/yard-stubs/ca_obj_roll.rb +2 -3
  214. data/yard-stubs/ca_obj_shift.rb +5 -1
  215. data/yard-stubs/ca_obj_stride.rb +10 -7
  216. data/yard-stubs/ca_obj_tile.rb +1 -1
  217. data/yard-stubs/ca_obj_transpose.rb +1 -1
  218. data/yard-stubs/ca_obj_window.rb +9 -5
  219. data/yard-stubs/carray_access.rb +11 -5
  220. data/yard-stubs/carray_attribute.rb +0 -5
  221. data/yard-stubs/carray_broadcast.rb +1 -1
  222. data/yard-stubs/carray_cast.rb +88 -43
  223. data/yard-stubs/carray_conversion.rb +15 -2
  224. data/yard-stubs/carray_copy.rb +12 -5
  225. data/yard-stubs/carray_core.rb +3 -3
  226. data/yard-stubs/carray_count.rb +9 -0
  227. data/yard-stubs/carray_element.rb +10 -4
  228. data/yard-stubs/carray_generate.rb +21 -1
  229. data/yard-stubs/carray_lazy.rb +5 -1
  230. data/yard-stubs/carray_loop.rb +4 -1
  231. data/yard-stubs/carray_mask.rb +60 -12
  232. data/yard-stubs/carray_math.rb +52 -14
  233. data/yard-stubs/carray_median_percentile.rb +15 -8
  234. data/yard-stubs/carray_memory_view.rb +40 -23
  235. data/yard-stubs/carray_order.rb +61 -29
  236. data/yard-stubs/carray_random.rb +13 -4
  237. data/yard-stubs/carray_scatter.rb +21 -9
  238. data/yard-stubs/carray_segment.rb +72 -0
  239. data/yard-stubs/carray_slab.rb +10 -2
  240. data/yard-stubs/carray_sort.rb +49 -8
  241. data/yard-stubs/carray_test.rb +15 -3
  242. data/yard-stubs/carray_utils.rb +0 -26
  243. metadata +19 -5
  244. data/ext/ca_for_each_element.h +0 -239
  245. data/ext/carray_kernels_map.c +0 -3467
  246. data/lib/carray/arrow_tensor.rb +0 -401
  247. data/lib/carray/table.rb +0 -108
data/ext/ca_obj_binop.c CHANGED
@@ -34,6 +34,7 @@
34
34
  #include "carray_internal.h" /* ca_lazy_arena_* */
35
35
  #include "ca_binop_dispatch.h"
36
36
  #include "ca_monop_dispatch.h" /* CA_MONOP_CAST_BASE */
37
+ #include "carray_math_kernel.h" /* ca_binop_not_implement */
37
38
 
38
39
  /* carray_broadcast.c */
39
40
  extern VALUE ca_broadcast_view (VALUE src, int8_t ndim,
@@ -48,7 +49,6 @@ extern int8_t CA_OBJ_LAZY_MARKER;
48
49
 
49
50
  /* Defined in carray_lazy.c: wrap a non-CArray Ruby value as a
50
51
  CScalar carrying the other operand's natural data_type. */
51
- extern VALUE ca_lazy_wrap_scalar (VALUE other, CArray *self_ca);
52
52
 
53
53
  /* ------------------------------------------------------------------- */
54
54
  /* CABinOp struct */
@@ -177,6 +177,7 @@ ca_binop_setup (CABinOp *ca, CArray *left, CArray *right, uint16_t op_id)
177
177
  CABinOp *
178
178
  ca_binop_new (CArray *left, CArray *right, uint16_t op_id)
179
179
  {
180
+ /* check: the setup checks nothing */
180
181
  CABinOp *ca = (CABinOp *) ca_array_alloc(CA_OBJ_BINOP, left->ndim);
181
182
  ca_binop_setup(ca, left, right, op_id);
182
183
  return ca;
@@ -227,7 +228,7 @@ ca_binop_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
227
228
  ca_size_t s;
228
229
 
229
230
  if ( dir != CA_XFER_GET ) {
230
- rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_index PUT)");
231
+ ca_refuse_read_only();
231
232
  }
232
233
 
233
234
  s = ca->bytes;
@@ -239,58 +240,30 @@ ca_binop_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
239
240
  ca_binop_func_xfer_stride(ca, starts, counts, strides, data, CA_XFER_GET);
240
241
  }
241
242
 
242
- static void
243
- ca_binop_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
244
- void *data, int dir)
245
- {
246
- CABinOp *ca = (CABinOp *) ap;
247
- ca_size_t i;
248
- char *out = (char *) data;
249
-
250
- if ( dir != CA_XFER_GET ) {
251
- rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_addrs PUT)");
252
- }
253
-
254
- for ( i = 0; i < n; i++ ) {
255
- ca_size_t idx[CA_RANK_MAX];
256
- ca_addr2index((CArray *)ca, addrs[i], idx);
257
- ca_binop_func_xfer_index(ca, idx, out + i * ca->bytes, CA_XFER_GET);
258
- }
259
- }
260
-
261
- /* Test / observability counters bumped from the xfer_stride hot
262
- path so specs can assert scratch acquisition (one per node,
263
- independent of left-chain depth) and materialise vs
264
- non-materialise behaviour without attaching the view. */
243
+ /* Test / observability counters bumped from the evaluation hot path
244
+ so specs can assert scratch acquisition (one per node, independent
245
+ of left-chain depth) and materialise vs non-materialise behaviour
246
+ without attaching the view. */
265
247
  ca_size_t ca_binop_scratch_acquire_count = 0;
266
248
  ca_size_t ca_binop_materialise_call_count = 0;
267
249
 
250
+ /* Evaluate the cells a request names into `data` (packed, n cells). */
268
251
  static void
269
- ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
270
- ca_size_t *strides, void *data, int dir)
252
+ ca_binop_eval (CABinOp *bo, const ca_lazy_req_t *req, void *data)
271
253
  {
272
- CABinOp *bo = (CABinOp *) ap;
273
- ca_size_t slab_n;
254
+ ca_size_t slab_n = req->n;
274
255
  int8_t k;
275
256
  void *scratch;
276
257
  volatile VALUE holder;
277
258
  ca_size_t right_bytes;
278
259
  ca_size_t right_step; /* element-stride for the kernel walk */
279
260
 
280
- if ( dir != CA_XFER_GET ) {
281
- rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_stride PUT)");
282
- }
283
261
  ca_binop_materialise_call_count++;
284
262
 
285
- slab_n = 1;
286
- for ( k = 0; k < bo->ndim; k++ ) slab_n *= counts[k];
287
-
288
263
  /* === 1. Pull left into the output buffer ===
289
- CAREFUL: left.data_type == output.data_type by the cast-before
290
- invariant, so the caller's `strides` (output byte layout) is
291
- also valid for left. A mismatch would silently write past the
292
- output row. */
293
- ca_xfer_stride(bo->parent, starts, counts, strides, data, CA_XFER_GET);
264
+ left.data_type == output.data_type by the cast-before invariant,
265
+ so the output buffer holds left's cells as they are. */
266
+ ca_lazy_req_pull(bo->parent, req, data, CA_XFER_GET);
294
267
 
295
268
  /* === 2. Pull right into an arena scratch === */
296
269
  right_bytes = bo->right->bytes;
@@ -315,17 +288,12 @@ ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
315
288
  right_step = 0;
316
289
  }
317
290
  else {
318
- /* Same-shape right. `strides` is the step through the operand, the
319
- same one the left was pulled with -- recomputing a packed one here
320
- reads the right operand's cells 0, 1, 2 against the left's 0, 2, 4.
321
- right.bytes matches output.bytes because right.data_type ==
322
- out.data_type by cast-before, so the same steps serve both. */
291
+ /* Same-shape right, pulled over the same cells as the left. */
323
292
  scratch = ( bo->data_type == CA_OBJECT )
324
293
  ? ca_lazy_arena_acquire_object(slab_n)
325
294
  : ca_lazy_arena_acquire(slab_n * right_bytes);
326
295
  ca_binop_scratch_acquire_count++;
327
- ca_xfer_stride(bo->right, starts, counts, strides, scratch,
328
- CA_XFER_GET);
296
+ ca_lazy_req_pull(bo->right, req, scratch, CA_XFER_GET);
329
297
  right_step = 1;
330
298
  }
331
299
 
@@ -337,8 +305,9 @@ ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
337
305
  * Mask handling:
338
306
  * - non-trapping op → m = NULL (SIMD fast path; garbage compute
339
307
  * on masked cells is allowed).
340
- * - trapping op with any operand mask → build a per-slab OR
341
- * mask from the operand-side masks.
308
+ * - trapping op (one that can raise on a cell, or an object cell)
309
+ * with any operand mask → the cells either operand masks
310
+ * (ca_lazy_req_mask), which the kernel skips.
342
311
  *
343
312
  * CAREFUL: the trapping-op mask is built from left.mask and
344
313
  * right.mask directly, NOT from out->mask. The output's mask
@@ -353,67 +322,13 @@ ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
353
322
  {
354
323
  boolean8_t *slab_mask = NULL;
355
324
  void *mscratch = NULL;
356
- volatile VALUE mholder = Qnil;
357
- int is_trapping = ca_binop_is_trapping(bo->op_id, bo->data_type);
358
-
359
- if ( is_trapping && ( ca_has_mask(bo->parent) ||
360
- ca_has_mask(bo->right) ) ) {
361
- /* Build a slab-shaped mask = left.slab_mask | right.slab_mask.
362
- Pull each operand's mask (or fill with 0 if absent) into the
363
- output-shaped layout, then OR them in place. */
364
- ca_size_t k_;
365
- ca_size_t right_mask_strides[CA_RANK_MAX];
366
- (void) mholder; /* Kept for stack-shape compatibility; arena
367
- replaces the ALLOCV path here. */
368
-
369
- mscratch = ca_lazy_arena_acquire(slab_n);
370
- slab_mask = (boolean8_t *) mscratch;
371
-
372
- if ( ca_has_mask(bo->parent) ) {
373
- ca_size_t mstrides[CA_RANK_MAX];
374
- ca_size_t s = 1;
375
- for ( k_ = bo->ndim - 1; k_ >= 0; k_-- ) {
376
- mstrides[k_] = s; s *= counts[k_];
377
- }
378
- ca_xfer_stride(bo->parent->mask, starts, counts, mstrides,
379
- slab_mask, CA_XFER_GET);
380
- }
381
- else {
382
- memset(slab_mask, 0, slab_n);
383
- }
384
325
 
385
- if ( ca_has_mask(bo->right) ) {
386
- boolean8_t *rm = NULL;
387
- ca_size_t i_;
388
- if ( bo->right_is_scalar ) {
389
- /* CScalar right: pull the single mask bit and broadcast OR. */
390
- ca_size_t one_starts[CA_RANK_MAX] = {0};
391
- ca_size_t one_counts[CA_RANK_MAX];
392
- ca_size_t one_strides[CA_RANK_MAX];
393
- boolean8_t one_bit = 0;
394
- for ( k_ = 0; k_ < bo->right->ndim; k_++ ) {
395
- one_counts[k_] = 1;
396
- one_strides[k_] = 1;
397
- }
398
- ca_xfer_stride(bo->right->mask, one_starts, one_counts,
399
- one_strides, &one_bit, CA_XFER_GET);
400
- if ( one_bit ) {
401
- for ( i_ = 0; i_ < slab_n; i_++ ) slab_mask[i_] = 1;
402
- }
403
- }
404
- else {
405
- ca_size_t s = 1;
406
- for ( k_ = bo->ndim - 1; k_ >= 0; k_-- ) {
407
- right_mask_strides[k_] = s; s *= counts[k_];
408
- }
409
- /* Small mask-scratch for right; OR into slab_mask in
410
- place to avoid a persistent second buffer. */
411
- rm = (boolean8_t *) ALLOCA_N(boolean8_t, slab_n);
412
- ca_xfer_stride(bo->right->mask, starts, counts,
413
- right_mask_strides, rm, CA_XFER_GET);
414
- for ( i_ = 0; i_ < slab_n; i_++ ) slab_mask[i_] |= rm[i_];
415
- }
416
- }
326
+ if ( ca_op_raises_on_cell(CA_OP_KIND_BINOP, bo->op_id, bo->data_type) ) {
327
+ CArray *ops[2];
328
+ ops[0] = bo->parent;
329
+ ops[1] = bo->right;
330
+ slab_mask = ca_lazy_req_mask(req, 2, ops);
331
+ mscratch = slab_mask;
417
332
  }
418
333
 
419
334
  ca_binop_func_t fn = ca_binop_kernel_lookup_vv(bo->op_id, bo->data_type);
@@ -435,6 +350,33 @@ ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
435
350
  ca_lazy_arena_release(scratch);
436
351
  }
437
352
 
353
+ static void
354
+ ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
355
+ ca_size_t *strides, void *data, int dir)
356
+ {
357
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
358
+ ca_lazy_req_t req;
359
+ if ( dir != CA_XFER_GET ) {
360
+ ca_refuse_read_only();
361
+ }
362
+ ca_lazy_req_region(&req, ap, starts, counts, strides);
363
+ ca_binop_eval((CABinOp *) ap, &req, data);
364
+ }
365
+
366
+ /* An address list is evaluated in one pass: each operand is gathered at
367
+ the same addresses and the kernel runs once over all of them. */
368
+ static void
369
+ ca_binop_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
370
+ void *data, int dir)
371
+ {
372
+ ca_lazy_req_t req;
373
+ if ( dir != CA_XFER_GET ) {
374
+ ca_refuse_read_only();
375
+ }
376
+ ca_lazy_req_addrs(&req, n, addrs);
377
+ ca_binop_eval((CABinOp *) ap, &req, data);
378
+ }
379
+
438
380
  static void
439
381
  ca_binop_func_xfer_all (void *ap, void *data, int dir)
440
382
  {
@@ -452,15 +394,7 @@ static void
452
394
  ca_binop_func_allocate (void *ap)
453
395
  {
454
396
  CABinOp *ca = (CABinOp *) ap;
455
- ca->ptr = xmalloc(ca_length(ca));
456
- /* CA_OBJECT cells are VALUEs and this buffer is about to be marked as
457
- soon as the view is, so it must not be handed to the GC as raw
458
- xmalloc garbage. */
459
- if ( ca->data_type == CA_OBJECT ) {
460
- VALUE *p = (VALUE *) ca->ptr;
461
- ca_size_t i;
462
- for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
463
- }
397
+ ca->ptr = ca_alloc_cells((CArray *) ca);
464
398
  }
465
399
 
466
400
  static void
@@ -477,19 +411,11 @@ ca_binop_func_attach (void *ap)
477
411
  int8_t k;
478
412
  ca_size_t s;
479
413
 
480
- ca->ptr = xmalloc(ca_length(ca));
414
+ ca->ptr = ca_alloc_cells((CArray *) ca);
481
415
 
482
416
  s = ca->bytes;
483
417
  for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
484
418
  for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
485
- /* CA_OBJECT cells are VALUEs and this buffer is about to be marked as
486
- soon as the view is, so it must not be handed to the GC as raw
487
- xmalloc garbage. */
488
- if ( ca->data_type == CA_OBJECT ) {
489
- VALUE *p = (VALUE *) ca->ptr;
490
- ca_size_t i;
491
- for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
492
- }
493
419
  ca_binop_func_xfer_stride(ca, starts, ca->dim, native, ca->ptr, CA_XFER_GET);
494
420
  }
495
421
 
@@ -511,107 +437,28 @@ NORETURN(static void ca_binop_func_fill_data (void *ap, void *ptr));
511
437
  static void
512
438
  ca_binop_func_fill_data (void *ap, void *ptr)
513
439
  {
514
- rb_raise(rb_eRuntimeError, "CABinOp is read-only (fill_data)");
440
+ ca_refuse_read_only();
515
441
  }
516
442
 
517
- /* Build out.mask. When either parent has a mask, materialise a
518
- freshly-allocated boolean8_t buffer. For most ops this is the blind
519
- OR `left.mask | right.mask`.
443
+ /* Build out.mask: the operands' masks ORed on each read (CAMaskOfOperands), so
444
+ that it follows them as the values do.
520
445
 
521
446
  Boolean AND / OR are three-valued (Kleene): a masked cell is resolved by
522
447
  the *known* side (`unknown | true = true`, `unknown & false = false`), so
523
- it is NOT masked in the result. This needs operand VALUES, not just
524
- masks, so both operands are attached; the blind value the value kernel
525
- later writes is already correct on a resolved cell because the absorbing
526
- element (true for OR, false for AND) dominates whatever garbage sits on
527
- the masked side. Nested trees compose: an inner boolean `&`/`|` node's
528
- mask is already Kleene-resolved by the time an outer node reads it.
529
-
530
- Not memory-optimal (a CARepeat-like view would share pages), but correct
531
- and decoupled from xfer_stride ordering. */
448
+ it is NOT masked in the result. The blind value the value kernel writes
449
+ is already correct on a resolved cell because the absorbing element (true
450
+ for OR, false for AND) dominates whatever sits on the masked side. */
532
451
  static void
533
452
  ca_binop_func_create_mask (void *ap)
534
453
  {
535
454
  CABinOp *bo = (CABinOp *) ap;
536
- CArray *l = bo->parent;
537
- CArray *r = bo->right;
538
- boolean8_t *dst;
539
- ca_size_t i, n;
540
- int has_l, has_r, kleene, need_l, need_r, is_or;
541
- boolean8_t *lm, *rm, *lv, *rv;
542
-
543
- has_l = ca_has_mask(l);
544
- has_r = ca_has_mask(r);
545
- if ( ! has_l && ! has_r ) return;
546
-
547
- kleene = ( bo->data_type == CA_BOOLEAN &&
548
- ( bo->op_id == CA_BINOP_BIT_AND || bo->op_id == CA_BINOP_BIT_OR ) );
549
- is_or = ( bo->op_id == CA_BINOP_BIT_OR );
550
-
551
- /* One masked operand and no Kleene resolution: the answer is that
552
- operand's mask, cell for cell. Share it the way CAMonOp shares its
553
- parent's, rather than allocating a copy per node -- a chain of k
554
- binops over one masked array then holds one boolean array, not k. */
555
- if ( ! kleene && ( has_l != has_r ) ) {
556
- CArray *src = has_l ? l : r;
557
- if ( src->elements == bo->elements ) {
558
- bo->mask = (CArray *) ca_refer_new(src->mask, CA_BOOLEAN,
559
- bo->ndim, bo->dim, 0, 0);
560
- return;
561
- }
562
- }
563
-
564
- bo->mask = (CArray *) carray_new(CA_BOOLEAN, bo->ndim, bo->dim, 0, NULL);
565
- dst = (boolean8_t *) bo->mask->ptr;
566
- n = bo->elements;
567
-
568
- /* Kleene needs operand values even where an operand is unmasked. */
569
- need_l = has_l || kleene;
570
- need_r = has_r || kleene;
571
- /* Only Kleene reads operand values. Every other op reads the operand
572
- masks alone, and attaching the operand to reach its mask materialises
573
- the whole subexpression under it -- so a chain of k masked binops
574
- evaluates its own subtree k times over. Attach what is read. */
575
- if ( kleene ) {
576
- if ( need_l ) ca_attach(l);
577
- if ( need_r ) ca_attach(r);
578
- }
579
- else {
580
- if ( has_l ) ca_attach(l->mask);
581
- if ( has_r ) ca_attach(r->mask);
582
- }
583
-
584
- lm = has_l ? (boolean8_t *) l->mask->ptr : NULL;
585
- rm = has_r ? (boolean8_t *) r->mask->ptr : NULL;
586
- lv = kleene ? (boolean8_t *) l->ptr : NULL;
587
- rv = kleene ? (boolean8_t *) r->ptr : NULL;
588
-
589
- for ( i = 0; i < n; i++ ) {
590
- /* right broadcast: repeat element 0 when right was a scalar. */
591
- ca_size_t ri = bo->right_is_scalar ? 0 : i;
592
- boolean8_t am = lm ? lm[i] : 0;
593
- boolean8_t bm = rm ? rm[ri] : 0;
594
- boolean8_t m = (boolean8_t)( am | bm );
595
- if ( kleene && m ) {
596
- boolean8_t av = lv[i], bv = rv[ri];
597
- if ( is_or ) {
598
- if ( ( ! am && av ) || ( ! bm && bv ) ) m = 0; /* known TRUE */
599
- }
600
- else {
601
- if ( ( ! am && ! av ) || ( ! bm && ! bv ) ) m = 0; /* known FALSE */
602
- }
603
- }
604
- dst[i] = m;
605
- }
455
+ int mode = CA_LAZY_MASK_OR;
606
456
 
607
- if ( kleene ) {
608
- if ( need_r ) ca_detach(r);
609
- if ( need_l ) ca_detach(l);
610
- }
611
- else {
612
- if ( has_r ) ca_detach(r->mask);
613
- if ( has_l ) ca_detach(l->mask);
457
+ if ( bo->data_type == CA_BOOLEAN ) {
458
+ if ( bo->op_id == CA_BINOP_BIT_OR ) mode = CA_LAZY_MASK_KLEENE_OR;
459
+ if ( bo->op_id == CA_BINOP_BIT_AND ) mode = CA_LAZY_MASK_KLEENE_AND;
614
460
  }
461
+ bo->mask = ca_lazy_operation_mask((CArray *) bo, mode);
615
462
  }
616
463
 
617
464
  ca_operation_function_t ca_binop_func = {
@@ -704,17 +551,22 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
704
551
  l_resolved = collapse_marker(l_cary);
705
552
  r_resolved = collapse_marker(r_cary);
706
553
 
707
- /* Promote a non-CArray Ruby value to a CScalar carrying the
708
- other side's natural data_type. */
709
- if ( ! rb_obj_is_carray(l_resolved) ) {
710
- rb_check_carray_object(r_resolved);
711
- TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
712
- l_resolved = ca_lazy_wrap_scalar(l_resolved, r);
713
- }
714
- if ( ! rb_obj_is_carray(r_resolved) ) {
715
- rb_check_carray_object(l_resolved);
716
- TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
717
- r_resolved = ca_lazy_wrap_scalar(r_resolved, l);
554
+ ca_binop_read_boolean_as_truth(
555
+ ca_binop_kernel_lookup_vv(op_id, CA_BOOLEAN) != ca_binop_not_implement,
556
+ &l_resolved, &r_resolved);
557
+
558
+ /* A scalar beside the array (a Ruby value or a CScalar) takes the
559
+ data_type the eager binop gives it, and the pair is promoted as the
560
+ eager binop promotes it. An integer power keeps its int64 exponent
561
+ (ca_binop_kernel_input_data_types). */
562
+ if ( op_id != CA_BINOP_IPOWER &&
563
+ ( ! rb_obj_is_carray(l_resolved) || ! rb_obj_is_carray(r_resolved) ||
564
+ rb_obj_is_cscalar(l_resolved) || rb_obj_is_cscalar(r_resolved) ) ) {
565
+ int l_scalar = ! rb_obj_is_carray(l_resolved) || rb_obj_is_cscalar(l_resolved);
566
+ int r_scalar = ! rb_obj_is_carray(r_resolved) || rb_obj_is_cscalar(r_resolved);
567
+ rb_ca_cast_self_or_other(&l_resolved, &r_resolved);
568
+ l_resolved = ca_lazy_settle_scalar(l_resolved, l_scalar);
569
+ r_resolved = ca_lazy_settle_scalar(r_resolved, r_scalar);
718
570
  }
719
571
 
720
572
  TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
@@ -725,6 +577,22 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
725
577
  ca_binop_kernel_input_data_types(op_id, l->data_type, r->data_type,
726
578
  &l_in_dt, &r_in_dt);
727
579
 
580
+ /* A boolean operand of an op with no boolean kernel (arithmetic) is
581
+ read as its 0/1 storage in int64, as rb_ca_call_binop does. */
582
+ if ( l_in_dt == CA_BOOLEAN &&
583
+ ca_binop_kernel_lookup_vv(op_id, CA_BOOLEAN) == ca_binop_not_implement ) {
584
+ l_in_dt = CA_INT64;
585
+ if ( r_in_dt == CA_BOOLEAN ) {
586
+ r_in_dt = CA_INT64;
587
+ }
588
+ }
589
+
590
+ /* No kernel for that data_type (fixlen arithmetic, ...): raise as the
591
+ eager binop does, before a view is built over it. */
592
+ if ( ca_binop_kernel_lookup_vv(op_id, l_in_dt) == ca_binop_not_implement ) {
593
+ ca_op_refuse_unimplemented(l_cary, l_in_dt, rb_eCADataTypeError);
594
+ }
595
+
728
596
  if ( l_in_dt != l->data_type ) {
729
597
  VALUE cast_op = INT2NUM(CA_MONOP_CAST_BASE + l_in_dt);
730
598
  l_resolved = rb_funcall(rb_const_get(rb_cObject, rb_intern("CAMonOp")),
@@ -757,11 +625,11 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
757
625
  shape so the kernel sees matched shapes; cost is N
758
626
  reads of the scalar cell with stride 0. */
759
627
  if ( l->elements != r->elements ) {
760
- if ( r->elements == 1 && l->elements > 1 ) {
628
+ if ( r->elements == 1 ) {
761
629
  /* CScalar-vs-array, right. xfer_stride handles this with
762
630
  right_step = 0. */
763
631
  }
764
- else if ( l->elements == 1 && r->elements > 1 ) {
632
+ else if ( l->elements == 1 ) {
765
633
  int commutes = ( op_id == CA_BINOP_ADD ||
766
634
  op_id == CA_BINOP_MUL ||
767
635
  op_id == CA_BINOP_BIT_AND ||
@@ -810,12 +678,24 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
810
678
  static VALUE
811
679
  rb_ca_binop_s_build (VALUE klass, VALUE l_cary, VALUE r_cary, VALUE op_id_val)
812
680
  {
681
+ /* fits: an operation number from the library's own table */
813
682
  uint16_t op_id = (uint16_t) NUM2UINT(op_id_val);
814
683
  (void) klass;
815
684
  return rb_ca_binop_build(l_cary, r_cary, op_id);
816
685
  }
817
686
 
818
687
  /* op_id accessor for inspect / dump_tree consumers in Ruby. */
688
+ /* Whether this node's kernel skips the cells its operands mask, rather
689
+ than computing them: a kernel that can raise on a cell or calls Ruby
690
+ for it. CArray::Fusion reads it so a plan carries the same rule. */
691
+ static VALUE
692
+ rb_ca_binop_trapping (VALUE self)
693
+ {
694
+ CABinOp *bo;
695
+ TypedData_Get_Struct(self, CABinOp, &cabinop_data_type, bo);
696
+ return ca_op_raises_on_cell(CA_OP_KIND_BINOP, bo->op_id, bo->data_type) ? Qtrue : Qfalse;
697
+ }
698
+
819
699
  static VALUE
820
700
  rb_ca_binop_op_id (VALUE self)
821
701
  {
@@ -834,6 +714,7 @@ rb_ca_binop_right (VALUE self)
834
714
  }
835
715
 
836
716
  /* Test instrumentation (mirrors CAMonOp counters). */
717
+ #ifdef CARRAY_DEV_BUILD
837
718
  static VALUE
838
719
  rb_ca_binop_s_reset_scratch_counter (VALUE klass)
839
720
  {
@@ -859,6 +740,7 @@ rb_ca_binop_s_materialise_count (VALUE klass)
859
740
  {
860
741
  return SIZE2NUM(ca_binop_materialise_call_count);
861
742
  }
743
+ #endif /* CARRAY_DEV_BUILD */
862
744
 
863
745
  static VALUE
864
746
  rb_ca_binop_s_allocate (VALUE klass)
@@ -872,6 +754,7 @@ rb_ca_binop_initialize_copy (VALUE self, VALUE other)
872
754
  {
873
755
  CABinOp *ca, *cs;
874
756
  TypedData_Get_Struct(self, CABinOp, &cabinop_data_type, ca);
757
+ ca_check_uninitialized(ca);
875
758
  TypedData_Get_Struct(other, CABinOp, &cabinop_data_type, cs);
876
759
  if ( ca_func[CA_OBJ_BINOP].pool_init ) {
877
760
  ca_array_pool_alloc(ca, CA_OBJ_BINOP, cs->parent->ndim);
@@ -933,10 +816,12 @@ Init_ca_obj_binop (void)
933
816
 
934
817
  rb_define_method(rb_cCABinOp, "__op_id__",
935
818
  rb_ca_binop_op_id, 0);
819
+ rb_define_method(rb_cCABinOp, "__trapping__", rb_ca_binop_trapping, 0);
936
820
  rb_define_method(rb_cCABinOp, "__binop_right__",
937
821
  rb_ca_binop_right, 0);
938
822
 
939
823
  /* Test instrumentation, not user-facing. */
824
+ #ifdef CARRAY_DEV_BUILD
940
825
  rb_define_singleton_method(rb_cCABinOp, "__reset_scratch_counter__",
941
826
  rb_ca_binop_s_reset_scratch_counter, 0);
942
827
  rb_define_singleton_method(rb_cCABinOp, "__scratch_count__",
@@ -945,4 +830,5 @@ Init_ca_obj_binop (void)
945
830
  rb_ca_binop_s_reset_materialise_counter, 0);
946
831
  rb_define_singleton_method(rb_cCABinOp, "__materialise_count__",
947
832
  rb_ca_binop_s_materialise_count, 0);
833
+ #endif
948
834
  }
@@ -96,6 +96,22 @@ ca_bitarray_setup (CABitarray *ca, CArray *parent)
96
96
  rb_raise(rb_eCADataTypeError, "invalid data_type for bitarray");
97
97
  }
98
98
 
99
+ /* The bits of one byte would share that byte's one mask cell, so a bit
100
+ view takes no masked array and holds no mask of its own. */
101
+ /* mask: the constructor asks first, before it allocates (ca == NULL) */
102
+ if ( ca_has_mask(parent) ) {
103
+ rb_raise(rb_eArgError,
104
+ "bitarray: the array has a mask, which a bit view can not "
105
+ "carry (its bits would share one mask per byte); "
106
+ "use .value.bitarray to read the bits without it");
107
+ }
108
+
109
+ /* ca == NULL asks for the checks above only, so that a constructor can
110
+ run them before it allocates. */
111
+ if ( ca == NULL ) {
112
+ return 0;
113
+ }
114
+
99
115
  ndim = parent->ndim + 1;
100
116
  bitlen = 8 * parent->bytes;
101
117
  elements = bitlen * parent->elements;
@@ -122,17 +138,15 @@ ca_bitarray_setup (CABitarray *ca, CArray *parent)
122
138
  memcpy(ca->dim, parent->dim, (ndim-1) * sizeof(ca_size_t));
123
139
  ca->dim[ndim-1] = bitlen;
124
140
 
125
- if ( ca_has_mask(parent) ) {
126
- ca_create_mask(ca);
127
- }
128
-
129
141
  return 0;
130
142
  }
131
143
 
132
144
  CABitarray *
133
145
  ca_bitarray_new (CArray *parent)
134
146
  {
135
- CABitarray *ca = (CABitarray *) ca_array_alloc(CA_OBJ_BITARRAY, parent->ndim + 1);
147
+ CABitarray *ca;
148
+ ca_bitarray_setup(NULL, parent);
149
+ ca = (CABitarray *) ca_array_alloc(CA_OBJ_BITARRAY, parent->ndim + 1);
136
150
  ca_bitarray_setup(ca, parent);
137
151
  return ca;
138
152
  }
@@ -178,7 +192,7 @@ ca_bitarray_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
178
192
  ca_size_t bytes = ca->parent->bytes;
179
193
  ca_size_t offset = idx[ca->ndim-1];
180
194
  ca_size_t major, minor;
181
- uint8_t sbuf[32];
195
+ volatile VALUE holder;
182
196
  uint8_t *v;
183
197
 
184
198
  if ( ca_endian == CA_BIG_ENDIAN &&
@@ -191,7 +205,7 @@ ca_bitarray_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
191
205
  }
192
206
  minor = offset % 8;
193
207
 
194
- v = (ca->parent->bytes <= 32) ? sbuf : xmalloc(ca->parent->bytes);
208
+ v = ALLOCV_N(uint8_t, holder, ca->parent->bytes);
195
209
 
196
210
  if ( dir == CA_XFER_GET ) {
197
211
  ca_fetch_index(ca->parent, idx, v);
@@ -209,7 +223,7 @@ ca_bitarray_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
209
223
  ca_store_index(ca->parent, idx, v);
210
224
  }
211
225
 
212
- if ( v != sbuf ) xfree(v);
226
+ ALLOCV_END(holder);
213
227
  }
214
228
 
215
229
  /* Batched gather / scatter.
@@ -315,6 +329,7 @@ static void
315
329
  ca_bitarray_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
316
330
  ca_size_t *strides, void *data, int dir)
317
331
  {
332
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
318
333
  CABitarray *ca = (CABitarray *) ap;
319
334
  int8_t ndim = ca->ndim;
320
335
  ca_size_t native[CA_RANK_MAX], idx[CA_RANK_MAX];
@@ -381,7 +396,7 @@ ca_bitarray_func_allocate (void *ap)
381
396
  {
382
397
  CABitarray *ca = (CABitarray *) ap;
383
398
  ca_attach(ca->parent);
384
- ca->ptr = xmalloc(ca_length(ca));
399
+ ca->ptr = ca_alloc_cells((CArray *) ca);
385
400
  }
386
401
 
387
402
  static void
@@ -389,7 +404,7 @@ ca_bitarray_func_attach (void *ap)
389
404
  {
390
405
  CABitarray *ca = (CABitarray *) ap;
391
406
  ca_attach(ca->parent);
392
- ca->ptr = xmalloc(ca_length(ca));
407
+ ca->ptr = ca_alloc_cells((CArray *) ca);
393
408
  ca_bitarray_attach(ca);
394
409
  }
395
410
 
@@ -478,29 +493,27 @@ ca_bitarray_func_fill_data (void *ap, void *ptr)
478
493
  CABitarray *ca = (CABitarray *) ap;
479
494
  ca_attach(ca->parent);
480
495
  ca_bitarray_fill(ca, ptr);
481
- ca_sync(ca->parent);
482
- ca_detach(ca->parent);
496
+ ca_sync_detach(ca->parent);
483
497
  }
484
498
 
499
+ /* Reached when a mask is about to be put on the view (mask=, storing UNDEF
500
+ or a masked array), or when the array it views has gained a mask since
501
+ the view was made. */
502
+ NORETURN(static void ca_bitarray_func_create_mask (void *ap));
503
+
485
504
  static void
486
505
  ca_bitarray_func_create_mask (void *ap)
487
506
  {
488
507
  CABitarray *ca = (CABitarray *) ap;
489
- ca_size_t count[CA_RANK_MAX];
490
- int8_t i;
491
-
492
- for (i=0; i<ca->ndim-1; i++) {
493
- count[i] = 0;
494
- }
495
- count[ca->ndim-1] = ca->bitlen;
496
-
497
- ca_update_mask(ca->parent);
498
- if ( ! ca->parent->mask ) {
499
- ca_create_mask(ca->parent);
508
+ if ( ca_has_mask(ca->parent) ) {
509
+ rb_raise(rb_eArgError,
510
+ "bitarray: the array this view reads has gained a mask, which "
511
+ "a bit view can not carry (its bits would share one mask per "
512
+ "byte); use .value.bitarray to read the bits without it");
500
513
  }
501
- ca->mask = (CArray *) ca_repeat_new(ca->parent->mask, ca->ndim, count);
502
-
503
- ca_unset_flag(ca->mask, CA_FLAG_READ_ONLY);
514
+ rb_raise(rb_eArgError,
515
+ "a bitarray view can not hold a mask "
516
+ "(its bits would share one mask per byte)");
504
517
  }
505
518
 
506
519
  ca_operation_function_t ca_bitarray_func = {
@@ -703,6 +716,7 @@ rb_ca_bitarray_initialize_copy (VALUE self, VALUE other)
703
716
  CABitarray *ca, *cs;
704
717
 
705
718
  TypedData_Get_Struct(self, CABitarray, &cabitarray_data_type, ca);
719
+ ca_check_uninitialized(ca);
706
720
  TypedData_Get_Struct(other, CABitarray, &cabitarray_data_type, cs);
707
721
 
708
722
  if ( ca_func[CA_OBJ_BITARRAY].pool_init ) {