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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +568 -0
- data/README.md +6 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +220 -0
- data/ext/ca_axis_group.c +201 -123
- data/ext/ca_binop_dispatch.c +46 -52
- data/ext/ca_binop_dispatch.h +1 -1
- data/ext/ca_categorical_iterator.c +249 -183
- data/ext/ca_compare.c +7 -12
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +38 -23
- data/ext/ca_kernel_iterator.c +1765 -2076
- data/ext/ca_kernel_iterator.h +584 -566
- data/ext/ca_monop_dispatch.c +86 -63
- data/ext/ca_monop_dispatch.h +5 -0
- data/ext/ca_obj_array.c +223 -56
- data/ext/ca_obj_bincmp.c +172 -138
- data/ext/ca_obj_binop.c +116 -230
- data/ext/ca_obj_bitarray.c +40 -26
- data/ext/ca_obj_bitfield.c +100 -68
- data/ext/ca_obj_block.c +19 -9
- data/ext/ca_obj_byte_swap.c +45 -46
- data/ext/ca_obj_const_string.c +269 -44
- data/ext/ca_obj_face.c +612 -89
- data/ext/ca_obj_face.h +111 -47
- data/ext/ca_obj_fake.c +36 -79
- data/ext/ca_obj_farray.c +7 -3
- data/ext/ca_obj_field.c +33 -8
- data/ext/ca_obj_fixlen_string.c +23 -24
- data/ext/ca_obj_grid.c +541 -210
- data/ext/ca_obj_meld.c +331 -111
- data/ext/ca_obj_moncmp.c +80 -65
- data/ext/ca_obj_monop.c +177 -149
- data/ext/ca_obj_object.c +664 -248
- data/ext/ca_obj_record.c +63 -23
- data/ext/ca_obj_reduce.c +18 -16
- data/ext/ca_obj_refer.c +140 -58
- data/ext/ca_obj_remap.c +85 -24
- data/ext/ca_obj_repeat.c +24 -9
- data/ext/ca_obj_roll.c +121 -16
- data/ext/ca_obj_select.c +61 -58
- data/ext/ca_obj_select_axis.c +73 -107
- data/ext/ca_obj_shift.c +32 -102
- data/ext/ca_obj_stack.c +372 -122
- data/ext/ca_obj_stride.c +348 -140
- data/ext/ca_obj_string.c +88 -22
- data/ext/ca_obj_tile.c +38 -21
- data/ext/ca_obj_time.c +45 -31
- data/ext/ca_obj_timedelta.c +43 -29
- data/ext/ca_obj_transpose.c +17 -6
- data/ext/ca_obj_triop.c +125 -141
- data/ext/ca_obj_window.c +330 -44
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +104 -81
- data/ext/ca_sweep_engine.h +7 -20
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +542 -0
- data/ext/carray.h +241 -92
- data/ext/carray_access.c +608 -276
- data/ext/carray_address_basis.c +494 -97
- data/ext/carray_attribute.c +129 -4
- data/ext/carray_bincount.c +39 -7
- data/ext/carray_broadcast.c +56 -19
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_call_cfunc.c +108 -28
- data/ext/carray_cast.c +1576 -223
- data/ext/carray_cast_func.rb +77 -24
- data/ext/carray_class.c +4 -3
- data/ext/carray_conversion.c +208 -75
- data/ext/carray_copy.c +82 -24
- data/ext/carray_core.c +646 -162
- data/ext/carray_count.c +171 -88
- data/ext/carray_element.c +94 -60
- data/ext/carray_factorize.c +670 -324
- data/ext/carray_generate.c +260 -83
- data/ext/carray_histogram.c +209 -106
- data/ext/carray_hold.c +14 -16
- data/ext/carray_index_classifier.c +422 -243
- data/ext/carray_internal.h +692 -3
- data/ext/carray_kernels_bincmp.c +7 -0
- data/ext/carray_kernels_binop.c +487 -120
- data/ext/carray_kernels_init.c +653 -50
- data/ext/carray_kernels_moncmp.c +15 -8
- data/ext/carray_kernels_monop.c +99 -43
- data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
- data/ext/carray_kernels_reduce_boolean.c +112 -36
- data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
- data/ext/carray_kernels_reduce_extreme.c +3032 -2892
- data/ext/carray_kernels_reduce_variance.c +439 -500
- data/ext/carray_kernels_scan.c +1097 -488
- data/ext/carray_kernels_search.c +3787 -2176
- data/ext/carray_kernels_sort.c +1200 -920
- data/ext/carray_kernels_triop.c +479 -7
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +967 -153
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +910 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +299 -100
- data/ext/carray_memory_view.c +872 -758
- data/ext/carray_operator.c +1171 -364
- data/ext/carray_order.c +505 -133
- data/ext/carray_partition.c +112 -65
- data/ext/carray_random.c +327 -239
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +346 -78
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +249 -86
- data/ext/carray_sort.c +224 -227
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +118 -39
- data/ext/carray_test.c +193 -69
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +579 -113
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +19 -4
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1202 -1014
- data/ext/ruby_carray.c +17 -5
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +160 -17
- data/lib/carray/autoload_carray.rb +23 -27
- data/lib/carray/autoload_method_extension.rb +20 -5
- data/lib/carray/axis_group.rb +360 -63
- data/lib/carray/basics.rb +162 -28
- data/lib/carray/bincount_nd.rb +18 -2
- data/lib/carray/block_iterator.rb +231 -58
- data/lib/carray/boolean_reduce.rb +34 -42
- data/lib/carray/categorical.rb +242 -52
- data/lib/carray/categorical_iterator.rb +437 -827
- data/lib/carray/complex.rb +41 -34
- data/lib/carray/conditional.rb +150 -14
- data/lib/carray/const_string.rb +59 -4
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +7 -1
- data/lib/carray/frame/column_verbs.rb +70 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +82 -7
- data/lib/carray/frame/csv_parser.rb +688 -87
- data/lib/carray/frame/describe.rb +80 -0
- data/lib/carray/frame/frame.rb +369 -45
- data/lib/carray/frame/group.rb +631 -90
- data/lib/carray/frame/io.rb +506 -79
- data/lib/carray/frame/join.rb +411 -62
- data/lib/carray/frame/records.rb +116 -19
- data/lib/carray/frame/reshape.rb +455 -0
- data/lib/carray/frame/sort.rb +30 -18
- data/lib/carray/frame/verbs.rb +868 -61
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +4 -0
- data/lib/carray/fuse_source.rb +118 -2
- data/lib/carray/fusion.rb +257 -42
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +54 -13
- data/lib/carray/iterator.rb +99 -9
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +216 -193
- data/lib/carray/mask_gap_fill.rb +112 -92
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +52 -21
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +18 -2
- data/lib/carray/methods/bit_string.rb +15 -4
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +18 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +25 -5
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +140 -10
- data/lib/carray/methods/join.rb +2 -7
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +182 -45
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +65 -17
- data/lib/carray/segment_iterator.rb +1221 -0
- data/lib/carray/serialize.rb +214 -30
- data/lib/carray/slab_iterator.rb +101 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +12 -4
- data/lib/carray/struct.rb +137 -58
- data/lib/carray/struct_builder.rb +124 -17
- data/lib/carray/time.rb +1222 -186
- data/lib/carray/window_iterator.rb +242 -81
- data/lib/carray.rb +9 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +5 -1
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +5 -4
- data/yard-stubs/ca_obj_roll.rb +2 -3
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +9 -5
- data/yard-stubs/carray_access.rb +11 -5
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +88 -43
- data/yard-stubs/carray_conversion.rb +15 -2
- data/yard-stubs/carray_copy.rb +12 -5
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +60 -12
- data/yard-stubs/carray_math.rb +52 -14
- data/yard-stubs/carray_median_percentile.rb +15 -8
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +61 -29
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +21 -9
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +10 -2
- data/yard-stubs/carray_sort.rb +49 -8
- data/yard-stubs/carray_test.rb +15 -3
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -5
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_kernels_map.c +0 -3467
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_mask.c
CHANGED
|
@@ -185,16 +185,67 @@ ca_mask_word_count (const boolean8_t *m, ca_size_t n)
|
|
|
185
185
|
|
|
186
186
|
enum { CA_MASK_SCAN_ANY, CA_MASK_SCAN_ALL, CA_MASK_SCAN_COUNT };
|
|
187
187
|
|
|
188
|
+
/* The block walk runs under ca_lazy_arena_protect: the transfer from a
|
|
189
|
+
virtual mask can raise, and the arena must be left however it ends. */
|
|
190
|
+
typedef struct {
|
|
191
|
+
boolean8_t *scratch; /* first: released by ca_lazy_arena_release_held */
|
|
192
|
+
CArray *mask;
|
|
193
|
+
int op;
|
|
194
|
+
ca_size_t rows;
|
|
195
|
+
ca_size_t inner;
|
|
196
|
+
ca_size_t *native;
|
|
197
|
+
ca_size_t result;
|
|
198
|
+
} ca_mask_scan_t;
|
|
199
|
+
|
|
200
|
+
static VALUE
|
|
201
|
+
ca_mask_scan_virtual_body (VALUE arg)
|
|
202
|
+
{
|
|
203
|
+
ca_mask_scan_t *sc = (ca_mask_scan_t *) arg;
|
|
204
|
+
CArray *mask = sc->mask;
|
|
205
|
+
int8_t ndim = mask->ndim;
|
|
206
|
+
ca_size_t outer = mask->dim[0];
|
|
207
|
+
ca_size_t off;
|
|
208
|
+
int8_t k;
|
|
209
|
+
|
|
210
|
+
sc->scratch = (boolean8_t *) ca_lazy_arena_acquire(sc->rows * sc->inner);
|
|
211
|
+
|
|
212
|
+
for (off = 0; off < outer; off += sc->rows) {
|
|
213
|
+
ca_size_t nrow = (outer - off < sc->rows) ? (outer - off) : sc->rows;
|
|
214
|
+
ca_size_t n = nrow * sc->inner;
|
|
215
|
+
ca_size_t starts[CA_RANK_MAX] = {0};
|
|
216
|
+
ca_size_t counts[CA_RANK_MAX];
|
|
217
|
+
|
|
218
|
+
starts[0] = off;
|
|
219
|
+
counts[0] = nrow;
|
|
220
|
+
for (k = 1; k < ndim; k++) {
|
|
221
|
+
counts[k] = mask->dim[k];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
ca_xfer_stride(mask, starts, counts, sc->native, sc->scratch, CA_XFER_GET);
|
|
225
|
+
|
|
226
|
+
if ( sc->op == CA_MASK_SCAN_ANY ) {
|
|
227
|
+
if ( ca_mask_word_any(sc->scratch, n) ) { sc->result = 1; break; }
|
|
228
|
+
}
|
|
229
|
+
else if ( sc->op == CA_MASK_SCAN_ALL ) {
|
|
230
|
+
if ( ! ca_mask_word_all_set(sc->scratch, n) ) { sc->result = 0; break; }
|
|
231
|
+
}
|
|
232
|
+
else { /* CA_MASK_SCAN_COUNT — no early exit */
|
|
233
|
+
sc->result += ca_mask_word_count(sc->scratch, n);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return Qnil;
|
|
237
|
+
}
|
|
238
|
+
|
|
188
239
|
static ca_size_t
|
|
189
240
|
ca_mask_scan_virtual (CArray *mask, int op)
|
|
190
241
|
{
|
|
191
|
-
int8_t
|
|
192
|
-
ca_size_t
|
|
193
|
-
ca_size_t
|
|
194
|
-
ca_size_t
|
|
195
|
-
ca_size_t
|
|
196
|
-
|
|
197
|
-
int8_t
|
|
242
|
+
int8_t ndim = mask->ndim;
|
|
243
|
+
ca_size_t outer = mask->dim[0];
|
|
244
|
+
ca_size_t inner = 1;
|
|
245
|
+
ca_size_t native[CA_RANK_MAX];
|
|
246
|
+
ca_size_t rows;
|
|
247
|
+
ca_mask_scan_t sc;
|
|
248
|
+
int8_t k;
|
|
198
249
|
|
|
199
250
|
for (k = 1; k < ndim; k++) {
|
|
200
251
|
inner *= mask->dim[k];
|
|
@@ -212,41 +263,18 @@ ca_mask_scan_virtual (CArray *mask, int op)
|
|
|
212
263
|
if ( rows < 1 ) rows = 1;
|
|
213
264
|
if ( rows > outer ) rows = outer;
|
|
214
265
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
ca_size_t nrow = (outer - off < rows) ? (outer - off) : rows;
|
|
224
|
-
ca_size_t n = nrow * inner;
|
|
225
|
-
ca_size_t starts[CA_RANK_MAX] = {0};
|
|
226
|
-
ca_size_t counts[CA_RANK_MAX];
|
|
227
|
-
|
|
228
|
-
starts[0] = off;
|
|
229
|
-
counts[0] = nrow;
|
|
230
|
-
for (k = 1; k < ndim; k++) {
|
|
231
|
-
counts[k] = mask->dim[k];
|
|
232
|
-
}
|
|
266
|
+
sc.scratch = NULL;
|
|
267
|
+
sc.mask = mask;
|
|
268
|
+
sc.op = op;
|
|
269
|
+
sc.rows = rows;
|
|
270
|
+
sc.inner = inner;
|
|
271
|
+
sc.native = native;
|
|
272
|
+
/* ALL is vacuously all-set until a non-set cell is found */
|
|
273
|
+
sc.result = ( op == CA_MASK_SCAN_ALL ) ? 1 : 0;
|
|
233
274
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if ( ca_mask_word_any(scratch, n) ) { result = 1; break; }
|
|
238
|
-
}
|
|
239
|
-
else if ( op == CA_MASK_SCAN_ALL ) {
|
|
240
|
-
if ( ! ca_mask_word_all_set(scratch, n) ) { result = 0; break; }
|
|
241
|
-
}
|
|
242
|
-
else { /* CA_MASK_SCAN_COUNT — no early exit */
|
|
243
|
-
result += ca_mask_word_count(scratch, n);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
ca_lazy_arena_release(scratch);
|
|
248
|
-
ca_lazy_arena_exit();
|
|
249
|
-
return result;
|
|
275
|
+
ca_lazy_arena_protect(ca_mask_scan_virtual_body, ca_lazy_arena_release_held,
|
|
276
|
+
(VALUE) &sc);
|
|
277
|
+
return sc.result;
|
|
250
278
|
}
|
|
251
279
|
|
|
252
280
|
boolean8_t *
|
|
@@ -323,7 +351,7 @@ ca_is_any_masked (void *ap)
|
|
|
323
351
|
non-zero word (the typical "all zero, no mask actually set" hot
|
|
324
352
|
pattern). An O(n) scan cache is not viable here: the mask is
|
|
325
353
|
dynamic and a view chain can introduce a mask mid-chain. */
|
|
326
|
-
ca_attach(ca->mask);
|
|
354
|
+
ca_attach(ca->mask); /* window: nothing raises inside */
|
|
327
355
|
flag = ca_mask_word_any((boolean8_t *) ca->mask->ptr, ca->elements);
|
|
328
356
|
ca_detach(ca->mask);
|
|
329
357
|
}
|
|
@@ -350,7 +378,7 @@ ca_is_all_masked (void *ap)
|
|
|
350
378
|
/* cheap mask: O(1) alias attach + word-level all_set with early exit.
|
|
351
379
|
The word check uses (w == 0x0101...01ULL) under the {0,1}
|
|
352
380
|
invariant; returns on the first non-fully-set word. */
|
|
353
|
-
ca_attach(ca->mask);
|
|
381
|
+
ca_attach(ca->mask); /* window: nothing raises inside */
|
|
354
382
|
flag = ca_mask_word_all_set((boolean8_t *) ca->mask->ptr, ca->elements);
|
|
355
383
|
ca_detach(ca->mask);
|
|
356
384
|
}
|
|
@@ -363,6 +391,19 @@ ca_is_all_masked (void *ap)
|
|
|
363
391
|
return flag;
|
|
364
392
|
}
|
|
365
393
|
|
|
394
|
+
/* The create_mask slot of a view whose cells map one-to-one onto its
|
|
395
|
+
parent's in address order (a cast, a byte swap, a Face over its storage):
|
|
396
|
+
the mask is the parent's mask seen in the view's shape. */
|
|
397
|
+
|
|
398
|
+
void
|
|
399
|
+
ca_view_func_create_mask (void *ap)
|
|
400
|
+
{
|
|
401
|
+
CAView *ca = (CAView *) ap;
|
|
402
|
+
ca_create_mask(ca->parent);
|
|
403
|
+
ca->mask = (CArray *) ca_refer_new(ca->parent->mask,
|
|
404
|
+
CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
|
|
405
|
+
}
|
|
406
|
+
|
|
366
407
|
/* create mask array if array has mask but has not mask array */
|
|
367
408
|
|
|
368
409
|
void
|
|
@@ -374,30 +415,296 @@ ca_update_mask (void *ap)
|
|
|
374
415
|
}
|
|
375
416
|
}
|
|
376
417
|
|
|
418
|
+
static VALUE
|
|
419
|
+
ca_create_mask_attach (VALUE arg)
|
|
420
|
+
{
|
|
421
|
+
ca_attach((CArray *) arg); /* window: released by the view's detach */
|
|
422
|
+
return Qnil;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
CArray *
|
|
426
|
+
ca_mask_standin_new (CArray *parent)
|
|
427
|
+
{
|
|
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);
|
|
432
|
+
}
|
|
433
|
+
return z;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/* A value array or a mask array: a parent that can never be given a mask,
|
|
437
|
+
whose stand-in therefore stays in place for good. */
|
|
438
|
+
static int
|
|
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)
|
|
447
|
+
{
|
|
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;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
void
|
|
517
|
+
ca_multi_parent_mask_refresh (CArray *mask, CArray **parents,
|
|
518
|
+
CArray **standins, int32_t n)
|
|
519
|
+
{
|
|
520
|
+
CAMultiParent *mp = (CAMultiParent *) mask;
|
|
521
|
+
int32_t k;
|
|
522
|
+
if ( standins == NULL ) {
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
/* A replaced stand-in stays allocated until the view is freed: a copy
|
|
526
|
+
of the mask (dup) may still point at it. */
|
|
527
|
+
for ( k = 0; k < n; k++ ) {
|
|
528
|
+
mp->parents[k] = ca_mask_standin_current(mask, mp->parents[k], parents[k],
|
|
529
|
+
standins[k]);
|
|
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;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
void
|
|
581
|
+
ca_multi_parent_mask_refuse_first (CArray *mask, CArray **parents,
|
|
582
|
+
CArray **standins, int32_t n,
|
|
583
|
+
VALUE (*body)(VALUE), VALUE arg)
|
|
584
|
+
{
|
|
585
|
+
CAMultiParent *mp = (CAMultiParent *) mask;
|
|
586
|
+
volatile VALUE h_blank = 0, h_saved = 0;
|
|
587
|
+
ca_mp_trial_t t;
|
|
588
|
+
int32_t k, refused = -1;
|
|
589
|
+
if ( standins == NULL ) {
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
for ( k = 0; k < n; 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];
|
|
625
|
+
ca_size_t i;
|
|
626
|
+
if ( standins[k] == NULL || t.saved[k] != standins[k]
|
|
627
|
+
|| ! ca_mask_standin_parent_unmaskable(parents[k]) ) {
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
for ( i = 0; i < z->elements && ! ((boolean8_t *) z->ptr)[i]; i++ ) ;
|
|
631
|
+
if ( i < z->elements ) {
|
|
632
|
+
refused = k;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
ca_mp_trial_free_blanks(&t);
|
|
636
|
+
ALLOCV_END(h_blank);
|
|
637
|
+
ALLOCV_END(h_saved);
|
|
638
|
+
if ( refused >= 0 ) {
|
|
639
|
+
rb_raise(rb_eTypeError, "can not create mask array for the %s array",
|
|
640
|
+
ca_is_value_array(parents[refused]) ? "value" : "mask");
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
void
|
|
645
|
+
ca_multi_parent_mask_settle (CArray *mask, CArray **parents,
|
|
646
|
+
CArray **standins, int32_t n)
|
|
647
|
+
{
|
|
648
|
+
CAMultiParent *mp = (CAMultiParent *) mask;
|
|
649
|
+
int32_t k, pass;
|
|
650
|
+
if ( standins == NULL ) {
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
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]);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
377
666
|
void
|
|
378
667
|
ca_create_mask (void *ap)
|
|
379
668
|
{
|
|
380
669
|
CArray *ca = (CArray *) ap;
|
|
381
670
|
|
|
671
|
+
if ( ca->mask ) {
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
|
|
382
675
|
if ( ca_is_value_array(ca) ) {
|
|
383
|
-
rb_raise(
|
|
676
|
+
rb_raise(rb_eTypeError,
|
|
384
677
|
"can not create mask array for the value array");
|
|
385
678
|
}
|
|
386
679
|
|
|
387
680
|
if ( ca_is_mask_array(ca) ) {
|
|
388
|
-
rb_raise(
|
|
681
|
+
rb_raise(rb_eTypeError,
|
|
389
682
|
"can not create mask array for the mask array");
|
|
390
683
|
}
|
|
391
684
|
|
|
685
|
+
ca_func[ca->obj_type].create_mask(ca);
|
|
392
686
|
if ( ! ca->mask ) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
687
|
+
/* a lazy expression with no masked operand has no mask to make */
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
ca_set_flag(ca->mask, CA_FLAG_MASK_ARRAY); /* set array as mask array */
|
|
691
|
+
if ( ca_is_view(ca) ) {
|
|
692
|
+
if ( CAVIEW(ca)->attach ) {
|
|
693
|
+
/* The new mask joins its view's level. Its attach reads the
|
|
694
|
+
parent's mask, which can raise (a Ruby-backed parent); the mask
|
|
695
|
+
then comes off again, since the view's sync and detach would
|
|
696
|
+
find it attached to nothing. */
|
|
697
|
+
int tag = 0;
|
|
698
|
+
/* protect: the mask comes off its view before it is freed */
|
|
699
|
+
rb_protect(ca_create_mask_attach, (VALUE) ca->mask, &tag);
|
|
700
|
+
if ( tag ) {
|
|
701
|
+
CArray *mask = ca->mask;
|
|
702
|
+
ca->mask = NULL;
|
|
703
|
+
ca_free(mask);
|
|
704
|
+
rb_jump_tag(tag);
|
|
705
|
+
}
|
|
706
|
+
if ( ca_is_view(ca->mask) ) {
|
|
707
|
+
CAVIEW(ca->mask)->attach = CAVIEW(ca)->attach;
|
|
401
708
|
}
|
|
402
709
|
}
|
|
403
710
|
}
|
|
@@ -415,20 +722,42 @@ ca_clear_mask (void *ap)
|
|
|
415
722
|
}
|
|
416
723
|
}
|
|
417
724
|
|
|
725
|
+
typedef struct {
|
|
726
|
+
CArray *ca;
|
|
727
|
+
CArray *mask;
|
|
728
|
+
} ca_setup_mask_t;
|
|
729
|
+
|
|
730
|
+
/* Pushing the cells into ca's mask can raise (a CAObject's mask hooks). */
|
|
731
|
+
static VALUE
|
|
732
|
+
ca_setup_mask_body (VALUE arg)
|
|
733
|
+
{
|
|
734
|
+
ca_setup_mask_t *c = (ca_setup_mask_t *) arg;
|
|
735
|
+
ca_sync_data(c->ca->mask, c->mask->ptr);
|
|
736
|
+
return Qnil;
|
|
737
|
+
}
|
|
738
|
+
|
|
418
739
|
void
|
|
419
740
|
ca_setup_mask (void *ap, CArray *mask)
|
|
420
741
|
{
|
|
421
742
|
CArray *ca = (CArray *) ap;
|
|
422
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
|
+
|
|
423
751
|
ca_update_mask(ca);
|
|
424
752
|
|
|
425
753
|
if ( mask ) {
|
|
754
|
+
ca_setup_mask_t c;
|
|
426
755
|
if ( ! ca->mask ) {
|
|
427
756
|
ca_create_mask(ca);
|
|
428
757
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
758
|
+
c.ca = ca;
|
|
759
|
+
c.mask = mask;
|
|
760
|
+
ca_attach_window(1, &c.mask, "r", ca_setup_mask_body, (VALUE) &c);
|
|
432
761
|
}
|
|
433
762
|
else if ( ca->mask ) {
|
|
434
763
|
boolean8_t zero = 0;
|
|
@@ -443,14 +772,76 @@ ca_setup_mask (void *ap, CArray *mask)
|
|
|
443
772
|
|
|
444
773
|
*/
|
|
445
774
|
|
|
446
|
-
|
|
447
|
-
|
|
775
|
+
/* The overlay reads each source's mask into the destination's. A
|
|
776
|
+
source's mask can be made or read by calling Ruby (a CAObject's mask
|
|
777
|
+
hooks) and raise, so every mask is made first and the lot are read
|
|
778
|
+
inside one attach window.
|
|
779
|
+
|
|
780
|
+
A source whose cells live in the destination's root has its mask read
|
|
781
|
+
into a snapshot before the destination's mask is made, cleared or
|
|
782
|
+
written: the destination's mask may be that same memory, and the word
|
|
783
|
+
OR would otherwise read bytes it has already set. */
|
|
784
|
+
typedef struct {
|
|
785
|
+
CArray **list; /* [0] the destination mask, then the attached sources' */
|
|
786
|
+
boolean8_t **snap; /* per source: its mask read in advance, or NULL */
|
|
787
|
+
CArray **att; /* per source: its attached mask when not snapped */
|
|
788
|
+
char *scalar; /* per source: the source is a scalar */
|
|
789
|
+
int k; /* entries in list */
|
|
790
|
+
int ns; /* sources */
|
|
791
|
+
ca_size_t elements;
|
|
792
|
+
} ca_mask_overlay_t;
|
|
793
|
+
|
|
794
|
+
static VALUE
|
|
795
|
+
ca_mask_overlay_body (VALUE arg)
|
|
796
|
+
{
|
|
797
|
+
ca_mask_overlay_t *o = (ca_mask_overlay_t *) arg;
|
|
798
|
+
boolean8_t *ma = (boolean8_t *) o->list[0]->ptr;
|
|
799
|
+
int i;
|
|
800
|
+
for (i=0; i<o->ns; i++) {
|
|
801
|
+
boolean8_t *ms = o->snap[i] ? o->snap[i] : (boolean8_t *) o->att[i]->ptr;
|
|
802
|
+
/* scalar masked source -> broadcast to all (memset); array source
|
|
803
|
+
-> pure word OR (ca_mask_word_or). A defensive `if (*ms)` is
|
|
804
|
+
unnecessary: under the {0,1} invariant, `*ma |= *ms` equals
|
|
805
|
+
`if (*ms) *ma = 1`. Post-condition: the mask byte stays in {0,1}. */
|
|
806
|
+
if ( o->scalar[i] ) {
|
|
807
|
+
if ( *ms ) {
|
|
808
|
+
memset(ma, 1, o->elements);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
else {
|
|
812
|
+
ca_mask_word_or(ma, ms, o->elements);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
return Qnil;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/* overwrite: the destination's mask is cleared before the sources are
|
|
819
|
+
OR'd in (and left alone when it has none and no source has a mask). */
|
|
820
|
+
static void
|
|
821
|
+
ca_copy_mask_overlay_core (CArray *ca, ca_size_t elements, int n,
|
|
822
|
+
CArray **slist, int overwrite)
|
|
448
823
|
{
|
|
449
|
-
CArray *ca = (CArray *) ap;
|
|
450
824
|
CArray *cs;
|
|
451
|
-
|
|
825
|
+
ca_mask_overlay_t o;
|
|
826
|
+
volatile VALUE *holders;
|
|
827
|
+
char *modes;
|
|
452
828
|
int i, some_has_mask = 0;
|
|
453
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
|
+
|
|
454
845
|
for (i=0; i<n; i++) {
|
|
455
846
|
if ( slist[i] && ca_has_mask(slist[i]) ) {
|
|
456
847
|
some_has_mask = 1;
|
|
@@ -458,81 +849,111 @@ ca_copy_mask_overlay_n (void *ap, ca_size_t elements, int n, CArray **slist)
|
|
|
458
849
|
}
|
|
459
850
|
}
|
|
460
851
|
|
|
461
|
-
if ( some_has_mask ) {
|
|
852
|
+
if ( ! some_has_mask ) {
|
|
853
|
+
if ( overwrite ) {
|
|
854
|
+
ca_update_mask(ca);
|
|
855
|
+
if ( ca->mask ) {
|
|
856
|
+
boolean8_t zero = 0;
|
|
857
|
+
ca_fill(ca->mask, &zero);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
462
862
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
863
|
+
o.list = ALLOCA_N(CArray *, n + 1);
|
|
864
|
+
o.snap = ALLOCA_N(boolean8_t *, n);
|
|
865
|
+
o.att = ALLOCA_N(CArray *, n);
|
|
866
|
+
o.scalar = ALLOCA_N(char, n);
|
|
867
|
+
holders = ALLOCA_N(VALUE, n);
|
|
868
|
+
modes = ALLOCA_N(char, n + 2);
|
|
869
|
+
o.elements = elements;
|
|
870
|
+
o.ns = 0;
|
|
871
|
+
for (i=0; i<n; i++) {
|
|
872
|
+
holders[i] = 0;
|
|
873
|
+
}
|
|
874
|
+
ca_update_mask(ca);
|
|
875
|
+
|
|
876
|
+
/* Every source mask is made, and those in the destination's root are
|
|
877
|
+
read, before the destination's mask is touched. */
|
|
878
|
+
for (i=0; i<n; i++) {
|
|
879
|
+
cs = slist[i];
|
|
880
|
+
if ( ! cs ) {
|
|
881
|
+
continue;
|
|
882
|
+
}
|
|
883
|
+
ca_update_mask(cs);
|
|
884
|
+
if ( ! cs->mask ) {
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
o.scalar[o.ns] = (char) ca_is_scalar(cs);
|
|
888
|
+
o.att[o.ns] = NULL;
|
|
889
|
+
o.snap[o.ns] = NULL;
|
|
890
|
+
if ( ca_shares_root(cs, ca) || ca_shares_root(cs->mask, ca) ||
|
|
891
|
+
( ca->mask && ca_shares_root(cs->mask, ca->mask) ) ) {
|
|
892
|
+
o.snap[o.ns] = ALLOCV_N(boolean8_t, holders[o.ns], cs->mask->elements);
|
|
893
|
+
ca_xfer_all(cs->mask, (char *) o.snap[o.ns], CA_XFER_GET);
|
|
466
894
|
}
|
|
895
|
+
else {
|
|
896
|
+
o.att[o.ns] = cs->mask;
|
|
897
|
+
}
|
|
898
|
+
o.ns++;
|
|
899
|
+
}
|
|
467
900
|
|
|
468
|
-
|
|
469
|
-
|
|
901
|
+
ca_create_mask(ca);
|
|
902
|
+
if ( overwrite ) {
|
|
903
|
+
boolean8_t zero = 0;
|
|
904
|
+
ca_fill(ca->mask, &zero);
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
o.k = 0;
|
|
908
|
+
o.list[o.k] = ca->mask;
|
|
909
|
+
modes[o.k++] = 'w';
|
|
910
|
+
for (i=0; i<o.ns; i++) {
|
|
911
|
+
if ( o.att[i] ) {
|
|
912
|
+
o.list[o.k] = o.att[i];
|
|
913
|
+
modes[o.k++] = 'r';
|
|
470
914
|
}
|
|
915
|
+
}
|
|
916
|
+
modes[o.k] = '\0';
|
|
917
|
+
ca_attach_window(o.k, o.list, modes, ca_mask_overlay_body, (VALUE) &o);
|
|
471
918
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
if ( ! cs ) {
|
|
476
|
-
continue;
|
|
477
|
-
}
|
|
478
|
-
ca_update_mask(cs);
|
|
479
|
-
if ( ! cs->mask ) {
|
|
480
|
-
continue;
|
|
481
|
-
}
|
|
482
|
-
ca_attach(cs->mask);
|
|
483
|
-
ma = (boolean8_t *) ca->mask->ptr;
|
|
484
|
-
ms = (boolean8_t *) cs->mask->ptr;
|
|
485
|
-
/* scalar masked source -> broadcast to all (memset); array source
|
|
486
|
-
-> pure word OR (ca_mask_word_or). A defensive `if (*ms)` is
|
|
487
|
-
unnecessary: under the {0,1} invariant, `*ma |= *ms` equals
|
|
488
|
-
`if (*ms) *ma = 1`. Post-condition: the mask byte stays in {0,1}. */
|
|
489
|
-
if ( ca_is_scalar(cs) ) {
|
|
490
|
-
if ( *ms ) {
|
|
491
|
-
memset(ma, 1, elements);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
else {
|
|
495
|
-
ca_mask_word_or(ma, ms, elements);
|
|
496
|
-
}
|
|
497
|
-
ca_detach(cs->mask);
|
|
919
|
+
for (i=0; i<n; i++) {
|
|
920
|
+
if ( holders[i] ) {
|
|
921
|
+
ALLOCV_END(holders[i]);
|
|
498
922
|
}
|
|
499
|
-
ca_sync(ca->mask);
|
|
500
|
-
ca_detach(ca->mask);
|
|
501
923
|
}
|
|
502
924
|
}
|
|
503
925
|
|
|
926
|
+
void
|
|
927
|
+
ca_copy_mask_overlay_n (void *ap, ca_size_t elements, int n, CArray **slist)
|
|
928
|
+
{
|
|
929
|
+
ca_copy_mask_overlay_core((CArray *) ap, elements, n, slist, 0);
|
|
930
|
+
}
|
|
931
|
+
|
|
504
932
|
void
|
|
505
933
|
ca_copy_mask_overlay (void *ap, ca_size_t elements, int n, ...)
|
|
506
934
|
{
|
|
507
935
|
CArray *ca = (CArray *) ap;
|
|
508
936
|
CArray **slist;
|
|
937
|
+
volatile VALUE holder;
|
|
509
938
|
va_list args;
|
|
510
939
|
int i;
|
|
511
940
|
|
|
512
|
-
slist =
|
|
941
|
+
slist = ALLOCV_N(CArray *, holder, n);
|
|
513
942
|
va_start(args, n);
|
|
514
943
|
for (i=0; i<n; i++) {
|
|
515
944
|
slist[i] = va_arg(args, CArray *);
|
|
516
945
|
}
|
|
517
946
|
va_end(args);
|
|
518
947
|
|
|
519
|
-
|
|
948
|
+
ca_copy_mask_overlay_core(ca, elements, n, slist, 0);
|
|
520
949
|
|
|
521
|
-
|
|
950
|
+
ALLOCV_END(holder);
|
|
522
951
|
}
|
|
523
952
|
|
|
524
953
|
void
|
|
525
954
|
ca_copy_mask_overwrite_n (void *ap, ca_size_t elements, int n, CArray **slist)
|
|
526
955
|
{
|
|
527
|
-
CArray *
|
|
528
|
-
|
|
529
|
-
ca_update_mask(ca);
|
|
530
|
-
if ( ca->mask ) {
|
|
531
|
-
boolean8_t zero = 0;
|
|
532
|
-
ca_fill(ca->mask, &zero);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
ca_copy_mask_overlay_n(ca, elements, n, slist);
|
|
956
|
+
ca_copy_mask_overlay_core((CArray *) ap, elements, n, slist, 1);
|
|
536
957
|
}
|
|
537
958
|
|
|
538
959
|
void
|
|
@@ -540,25 +961,20 @@ ca_copy_mask_overwrite (void *ap, ca_size_t elements, int n, ...)
|
|
|
540
961
|
{
|
|
541
962
|
CArray *ca = (CArray *) ap;
|
|
542
963
|
CArray **slist;
|
|
964
|
+
volatile VALUE holder;
|
|
543
965
|
va_list args;
|
|
544
966
|
int i;
|
|
545
967
|
|
|
546
|
-
slist =
|
|
968
|
+
slist = ALLOCV_N(CArray *, holder, n);
|
|
547
969
|
va_start(args, n);
|
|
548
970
|
for (i=0; i<n; i++) {
|
|
549
971
|
slist[i] = va_arg(args, CArray*);
|
|
550
972
|
}
|
|
551
973
|
va_end(args);
|
|
552
974
|
|
|
553
|
-
|
|
554
|
-
if ( ca->mask ) {
|
|
555
|
-
boolean8_t zero = 0;
|
|
556
|
-
ca_fill(ca->mask, &zero);
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
ca_copy_mask_overlay_n(ca, elements, n, slist);
|
|
975
|
+
ca_copy_mask_overlay_core(ca, elements, n, slist, 1);
|
|
560
976
|
|
|
561
|
-
|
|
977
|
+
ALLOCV_END(holder);
|
|
562
978
|
}
|
|
563
979
|
|
|
564
980
|
void
|
|
@@ -582,7 +998,7 @@ ca_count_masked (void *ap)
|
|
|
582
998
|
if ( ca->mask ) {
|
|
583
999
|
if ( ca_attach_is_alias(ca->mask) ) {
|
|
584
1000
|
/* cheap mask: O(1) alias attach + word-bulk count. */
|
|
585
|
-
ca_attach(ca->mask);
|
|
1001
|
+
ca_attach(ca->mask); /* window: nothing raises inside */
|
|
586
1002
|
m = (boolean8_t *) ca->mask->ptr;
|
|
587
1003
|
count = ca_mask_word_count(m, ca->elements);
|
|
588
1004
|
ca_detach(ca->mask);
|
|
@@ -637,6 +1053,10 @@ ca_unmask (void *ap, char *fill_value)
|
|
|
637
1053
|
{
|
|
638
1054
|
CArray *ca = (CArray *) ap;
|
|
639
1055
|
|
|
1056
|
+
if ( ca_is_readonly(ca) ) {
|
|
1057
|
+
ca_refuse_read_only();
|
|
1058
|
+
}
|
|
1059
|
+
|
|
640
1060
|
ca_update_mask(ca);
|
|
641
1061
|
if ( ca->mask ) {
|
|
642
1062
|
if ( ! fill_value ) {
|
|
@@ -644,7 +1064,7 @@ ca_unmask (void *ap, char *fill_value)
|
|
|
644
1064
|
ca_fill(ca->mask, &zero);
|
|
645
1065
|
}
|
|
646
1066
|
else {
|
|
647
|
-
ca_attach(ca);
|
|
1067
|
+
ca_attach(ca); /* window: nothing raises inside */
|
|
648
1068
|
|
|
649
1069
|
switch ( ca->bytes ) {
|
|
650
1070
|
case 1: proc_fill_bang_width(uint8_t); break;
|
|
@@ -654,8 +1074,7 @@ ca_unmask (void *ap, char *fill_value)
|
|
|
654
1074
|
default: proc_fill_bang_bytes(); break; /* cmplx128 (16) + fixlen */
|
|
655
1075
|
}
|
|
656
1076
|
|
|
657
|
-
|
|
658
|
-
ca_detach(ca);
|
|
1077
|
+
ca_sync_detach(ca);
|
|
659
1078
|
}
|
|
660
1079
|
}
|
|
661
1080
|
}
|
|
@@ -677,17 +1096,21 @@ ca_unmask_copy_fill (VALUE arg)
|
|
|
677
1096
|
|
|
678
1097
|
ca_copy_data(ca, co->ptr);
|
|
679
1098
|
|
|
1099
|
+
/* Only the mask is needed now that the values are in co, so read the
|
|
1100
|
+
mask alone rather than producing the view's cells a second time. */
|
|
680
1101
|
if ( a->fill_value && ca_has_mask(ca) ) {
|
|
681
|
-
|
|
1102
|
+
volatile VALUE holder = 0;
|
|
1103
|
+
ca_update_mask(ca);
|
|
1104
|
+
m = ALLOCV_N(boolean8_t, holder, ca->elements);
|
|
1105
|
+
ca_copy_data(ca->mask, (char *) m);
|
|
682
1106
|
q = co->ptr;
|
|
683
|
-
m = (boolean8_t *) ca->mask->ptr;
|
|
684
1107
|
for (i=0; i<ca->elements; i++) {
|
|
685
|
-
if (
|
|
1108
|
+
if ( m[i] ) {
|
|
686
1109
|
memcpy(q, a->fill_value, ca->bytes);
|
|
687
1110
|
}
|
|
688
|
-
|
|
1111
|
+
q+=co->bytes;
|
|
689
1112
|
}
|
|
690
|
-
|
|
1113
|
+
ALLOCV_END(holder);
|
|
691
1114
|
}
|
|
692
1115
|
return Qnil;
|
|
693
1116
|
}
|
|
@@ -709,16 +1132,12 @@ ca_invert_mask (void *ap)
|
|
|
709
1132
|
CArray *ca = (CArray *) ap;
|
|
710
1133
|
boolean8_t *m;
|
|
711
1134
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
if ( ! ca->mask ) {
|
|
715
|
-
ca_create_mask(ca);
|
|
716
|
-
}
|
|
1135
|
+
ca_create_mask(ca);
|
|
717
1136
|
|
|
718
|
-
ca_attach(ca->mask);
|
|
1137
|
+
ca_attach(ca->mask); /* window: nothing raises inside */
|
|
719
1138
|
m = (boolean8_t *) ca->mask->ptr;
|
|
720
1139
|
ca_mask_word_not(m, m, ca->elements); /* in-place 1 - m, LSB-XOR word loop */
|
|
721
|
-
|
|
1140
|
+
ca_sync_detach(ca->mask);
|
|
722
1141
|
|
|
723
1142
|
return;
|
|
724
1143
|
}
|
|
@@ -727,9 +1146,10 @@ boolean8_t *
|
|
|
727
1146
|
ca_allocate_mask_iterator_n (int n, CArray **slist)
|
|
728
1147
|
{
|
|
729
1148
|
boolean8_t *m, *mp, *ms;
|
|
730
|
-
CArray *cs;
|
|
1149
|
+
CArray *cs, **masks;
|
|
1150
|
+
char *scalar;
|
|
731
1151
|
ca_size_t j, elements = -1;
|
|
732
|
-
int i, some_has_mask = 0;
|
|
1152
|
+
int i, k = 0, some_has_mask = 0;
|
|
733
1153
|
|
|
734
1154
|
for (i=0; i<n; i++) {
|
|
735
1155
|
if ( slist[i] ) {
|
|
@@ -743,7 +1163,7 @@ ca_allocate_mask_iterator_n (int n, CArray **slist)
|
|
|
743
1163
|
elements = slist[i]->elements;
|
|
744
1164
|
}
|
|
745
1165
|
else if ( ! ca_is_scalar(slist[i]) ) {
|
|
746
|
-
rb_raise(
|
|
1166
|
+
rb_raise(rb_eArgError,
|
|
747
1167
|
"# of elements is different among the given arrays");
|
|
748
1168
|
}
|
|
749
1169
|
}
|
|
@@ -758,13 +1178,18 @@ ca_allocate_mask_iterator_n (int n, CArray **slist)
|
|
|
758
1178
|
(degenerate call); guard so the alloc/memset never see a negative size
|
|
759
1179
|
(which would wrap to a huge bound). Also silences GCC's VRP warnings. */
|
|
760
1180
|
if ( elements < 0 ) elements = 0;
|
|
761
|
-
m = xmalloc(sizeof(boolean8_t)*elements);
|
|
762
|
-
memset(m, 0, elements);
|
|
763
1181
|
|
|
764
1182
|
if ( ! some_has_mask ) {
|
|
1183
|
+
m = xmalloc(sizeof(boolean8_t)*elements);
|
|
1184
|
+
memset(m, 0, elements);
|
|
765
1185
|
return m;
|
|
766
1186
|
}
|
|
767
1187
|
|
|
1188
|
+
/* The sources' masks, made and attached before the result is allocated:
|
|
1189
|
+
making or reading one can call Ruby (a CAObject's mask hooks) and
|
|
1190
|
+
raise, and then nothing is left attached or allocated. */
|
|
1191
|
+
masks = ALLOCA_N(CArray *, n);
|
|
1192
|
+
scalar = ALLOCA_N(char, n);
|
|
768
1193
|
for (i=0; i<n; i++) {
|
|
769
1194
|
cs = slist[i];
|
|
770
1195
|
if ( ! cs ) {
|
|
@@ -774,10 +1199,17 @@ ca_allocate_mask_iterator_n (int n, CArray **slist)
|
|
|
774
1199
|
if ( ! cs->mask ) {
|
|
775
1200
|
continue;
|
|
776
1201
|
}
|
|
777
|
-
|
|
778
|
-
|
|
1202
|
+
masks[k] = cs->mask;
|
|
1203
|
+
scalar[k++] = (char) ca_is_scalar(cs);
|
|
1204
|
+
}
|
|
1205
|
+
ca_attach_all(masks, k); /* window: nothing raises inside */
|
|
1206
|
+
|
|
1207
|
+
m = xmalloc(sizeof(boolean8_t)*elements);
|
|
1208
|
+
memset(m, 0, elements);
|
|
1209
|
+
for (i=0; i<k; i++) {
|
|
1210
|
+
ms = (boolean8_t *) masks[i]->ptr;
|
|
779
1211
|
mp = m;
|
|
780
|
-
if (
|
|
1212
|
+
if ( scalar[i] ) {
|
|
781
1213
|
if ( *ms ) {
|
|
782
1214
|
for (j=0; j<elements; j++) {
|
|
783
1215
|
*mp = 1;
|
|
@@ -788,7 +1220,9 @@ ca_allocate_mask_iterator_n (int n, CArray **slist)
|
|
|
788
1220
|
else {
|
|
789
1221
|
ca_mask_word_or(mp, ms, elements); /* m[j] |= ms[j], word-bulk OR */
|
|
790
1222
|
}
|
|
791
|
-
|
|
1223
|
+
}
|
|
1224
|
+
while ( k > 0 ) {
|
|
1225
|
+
ca_detach(masks[--k]);
|
|
792
1226
|
}
|
|
793
1227
|
return m;
|
|
794
1228
|
}
|
|
@@ -798,10 +1232,11 @@ ca_allocate_mask_iterator (int n, ...)
|
|
|
798
1232
|
{
|
|
799
1233
|
boolean8_t *m;
|
|
800
1234
|
CArray **slist;
|
|
1235
|
+
volatile VALUE holder;
|
|
801
1236
|
va_list args;
|
|
802
1237
|
int i;
|
|
803
1238
|
|
|
804
|
-
slist =
|
|
1239
|
+
slist = ALLOCV_N(CArray *, holder, n);
|
|
805
1240
|
va_start(args, n);
|
|
806
1241
|
for (i=0; i<n; i++) {
|
|
807
1242
|
slist[i] = va_arg(args, CArray *);
|
|
@@ -810,7 +1245,7 @@ ca_allocate_mask_iterator (int n, ...)
|
|
|
810
1245
|
|
|
811
1246
|
m = ca_allocate_mask_iterator_n(n, slist);
|
|
812
1247
|
|
|
813
|
-
|
|
1248
|
+
ALLOCV_END(holder);
|
|
814
1249
|
|
|
815
1250
|
return m;
|
|
816
1251
|
}
|
|
@@ -964,12 +1399,15 @@ rb_ca_mask_array (VALUE self)
|
|
|
964
1399
|
|
|
965
1400
|
ca_update_mask(ca);
|
|
966
1401
|
if ( ca->mask ) {
|
|
1402
|
+
/* The mask is reached from its array, not through a parent link, so
|
|
1403
|
+
ca_is_readonly on the mask never sees the array's read-only state.
|
|
1404
|
+
Pass it on here, where the mask is handed out. */
|
|
1405
|
+
if ( ca_is_readonly(ca) ) {
|
|
1406
|
+
ca_set_flag(ca->mask, CA_FLAG_READ_ONLY);
|
|
1407
|
+
}
|
|
967
1408
|
obj = TypedData_Wrap_Struct(ca_mask_class[ca->obj_type],
|
|
968
|
-
ca_mask_typeddata[ca->obj_type], ca->mask);
|
|
1409
|
+
ca_mask_typeddata[ca->obj_type], ca->mask);
|
|
969
1410
|
rb_ivar_set(obj, rb_intern("masked_array"), self);
|
|
970
|
-
if ( OBJ_FROZEN(self) ) {
|
|
971
|
-
rb_ca_freeze(obj);
|
|
972
|
-
}
|
|
973
1411
|
return obj;
|
|
974
1412
|
}
|
|
975
1413
|
else {
|
|
@@ -977,6 +1415,72 @@ rb_ca_mask_array (VALUE self)
|
|
|
977
1415
|
}
|
|
978
1416
|
}
|
|
979
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
|
+
|
|
980
1484
|
/* @overload mask= (new_mask)
|
|
981
1485
|
|
|
982
1486
|
(Mask, Modification)
|
|
@@ -996,30 +1500,54 @@ rb_ca_set_mask (VALUE self, VALUE rval)
|
|
|
996
1500
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
997
1501
|
|
|
998
1502
|
if ( ca_is_value_array(ca) ) {
|
|
999
|
-
rb_raise(
|
|
1503
|
+
rb_raise(rb_eTypeError,
|
|
1000
1504
|
"can not create mask for the value array");
|
|
1001
1505
|
}
|
|
1002
1506
|
|
|
1003
1507
|
if ( ca_is_mask_array(ca) ) {
|
|
1004
|
-
rb_raise(
|
|
1508
|
+
rb_raise(rb_eTypeError,
|
|
1005
1509
|
"can not create mask for the mask array");
|
|
1006
1510
|
}
|
|
1007
1511
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1512
|
+
if ( TYPE(rmask) == T_ARRAY ) {
|
|
1513
|
+
/* Flattened as a store into a boolean array of this shape flattens
|
|
1514
|
+
it, and then taken as a 1-D boolean array (UNDEF becomes a masked
|
|
1515
|
+
cell, as in any boolean array made from it). */
|
|
1516
|
+
CArray shape = *ca;
|
|
1517
|
+
shape.data_type = CA_BOOLEAN;
|
|
1518
|
+
shape.bytes = ca_sizeof[CA_BOOLEAN];
|
|
1519
|
+
rmask = rb_ary_flatten_for_elements(rmask, ca->elements, &shape);
|
|
1520
|
+
if ( NIL_P(rmask) ) {
|
|
1521
|
+
rb_raise(rb_eArgError, "failed to guess data size of given array");
|
|
1522
|
+
}
|
|
1523
|
+
rmask = rb_ca_wrap_readonly(rmask, INT2NUM(CA_BOOLEAN));
|
|
1011
1524
|
}
|
|
1012
1525
|
|
|
1013
1526
|
if ( rb_obj_is_carray(rmask) ) {
|
|
1527
|
+
/* The array owns the shape, as in a store: the new mask agrees with
|
|
1528
|
+
it, is 1-D or squeezes to it, or broadcasts along size-1 axes.
|
|
1529
|
+
Checked before the mask exists, so a refused one leaves none. */
|
|
1530
|
+
ca_broadcast_to_destination(self, &rmask);
|
|
1014
1531
|
TypedData_Get_Struct(rmask, CArray, &carray_data_type, cv);
|
|
1532
|
+
/* A new mask taken from self's own root, or from self's mask, is
|
|
1533
|
+
read from a copy: making and writing self's mask would change it
|
|
1534
|
+
before it is read. */
|
|
1535
|
+
ca_update_mask(ca);
|
|
1536
|
+
if ( ca_shares_root(cv, ca) ||
|
|
1537
|
+
( ca->mask && ca_shares_root(cv, ca->mask) ) ) {
|
|
1538
|
+
rmask = rb_ca_copy(rmask);
|
|
1539
|
+
TypedData_Get_Struct(rmask, CArray, &carray_data_type, cv);
|
|
1540
|
+
}
|
|
1015
1541
|
if ( ! ca_is_boolean_type(cv) ) {
|
|
1016
|
-
cv = ca_wrap_readonly(
|
|
1542
|
+
cv = ca_wrap_readonly(rmask, CA_BOOLEAN);
|
|
1017
1543
|
}
|
|
1544
|
+
ca_create_mask(ca);
|
|
1018
1545
|
ca_setup_mask(ca, cv);
|
|
1019
1546
|
ca_copy_mask_overlay(ca, ca->elements, 1, cv);
|
|
1020
1547
|
return rval;
|
|
1021
1548
|
}
|
|
1022
1549
|
else {
|
|
1550
|
+
ca_create_mask(ca);
|
|
1023
1551
|
return rb_ca_store_all(rb_ca_mask_array(self), rmask);
|
|
1024
1552
|
}
|
|
1025
1553
|
}
|
|
@@ -1035,39 +1563,36 @@ with <code>self</code>. The returned array has 1 for the masked elements and
|
|
|
1035
1563
|
VALUE
|
|
1036
1564
|
rb_ca_is_masked (VALUE self)
|
|
1037
1565
|
{
|
|
1038
|
-
volatile VALUE
|
|
1039
|
-
CArray *ca, *
|
|
1566
|
+
volatile VALUE out;
|
|
1567
|
+
CArray *ca, *co;
|
|
1040
1568
|
boolean8_t zero = 0;
|
|
1041
|
-
boolean8_t *
|
|
1569
|
+
boolean8_t *p;
|
|
1042
1570
|
ca_size_t i;
|
|
1043
1571
|
|
|
1044
1572
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1045
1573
|
|
|
1046
1574
|
if ( ca_is_scalar(ca) ) {
|
|
1047
|
-
co = (CArray *)cscalar_new(CA_BOOLEAN, ca->bytes, NULL);
|
|
1575
|
+
co = (CArray *)cscalar_new(CA_BOOLEAN, ca->bytes, NULL);
|
|
1048
1576
|
}
|
|
1049
1577
|
else {
|
|
1050
|
-
co = carray_new(CA_BOOLEAN, ca->ndim, ca->dim, ca->bytes, NULL);
|
|
1578
|
+
co = carray_new(CA_BOOLEAN, ca->ndim, ca->dim, ca->bytes, NULL);
|
|
1051
1579
|
}
|
|
1580
|
+
out = ca_wrap_struct(co); /* owned by Ruby before anything can raise */
|
|
1052
1581
|
|
|
1053
1582
|
ca_update_mask(ca);
|
|
1054
1583
|
if ( ! ca->mask ) {
|
|
1055
1584
|
ca_fill(co, &zero);
|
|
1056
1585
|
}
|
|
1057
1586
|
else {
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
ca_attach(cm);
|
|
1061
|
-
m = (boolean8_t *) cm->ptr;
|
|
1587
|
+
/* Copied straight into the result, then normalised in place. */
|
|
1588
|
+
ca_copy_data(ca->mask, co->ptr);
|
|
1062
1589
|
p = (boolean8_t *) co->ptr;
|
|
1063
1590
|
for (i=0; i<ca->elements; i++) {
|
|
1064
|
-
|
|
1065
|
-
m++; p++;
|
|
1591
|
+
p[i] = ( p[i] ) ? 1 : 0;
|
|
1066
1592
|
}
|
|
1067
|
-
ca_detach(cm);
|
|
1068
1593
|
}
|
|
1069
1594
|
|
|
1070
|
-
return
|
|
1595
|
+
return out;
|
|
1071
1596
|
}
|
|
1072
1597
|
|
|
1073
1598
|
/* @overload is_not_masked
|
|
@@ -1081,39 +1606,52 @@ The returned array has 0 for the masked elements and
|
|
|
1081
1606
|
VALUE
|
|
1082
1607
|
rb_ca_is_not_masked (VALUE self)
|
|
1083
1608
|
{
|
|
1084
|
-
volatile VALUE
|
|
1085
|
-
CArray *ca, *
|
|
1609
|
+
volatile VALUE out;
|
|
1610
|
+
CArray *ca, *co;
|
|
1086
1611
|
boolean8_t one = 1;
|
|
1087
|
-
boolean8_t *
|
|
1612
|
+
boolean8_t *p;
|
|
1088
1613
|
ca_size_t i;
|
|
1089
1614
|
|
|
1090
1615
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1091
1616
|
|
|
1092
1617
|
if ( ca_is_scalar(ca) ) {
|
|
1093
|
-
co = (CArray *)
|
|
1618
|
+
co = (CArray *)cscalar_new(CA_BOOLEAN, ca->bytes, NULL);
|
|
1094
1619
|
}
|
|
1095
1620
|
else {
|
|
1096
|
-
co = carray_new(CA_BOOLEAN, ca->ndim, ca->dim, ca->bytes, NULL);
|
|
1621
|
+
co = carray_new(CA_BOOLEAN, ca->ndim, ca->dim, ca->bytes, NULL);
|
|
1097
1622
|
}
|
|
1623
|
+
out = ca_wrap_struct(co); /* owned by Ruby before anything can raise */
|
|
1098
1624
|
|
|
1099
1625
|
ca_update_mask(ca);
|
|
1100
1626
|
if ( ! ca->mask ) {
|
|
1101
1627
|
ca_fill(co, &one);
|
|
1102
1628
|
}
|
|
1103
1629
|
else {
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
ca_attach(cm);
|
|
1107
|
-
m = (boolean8_t *) cm->ptr;
|
|
1630
|
+
/* Copied straight into the result, then normalised in place. */
|
|
1631
|
+
ca_copy_data(ca->mask, co->ptr);
|
|
1108
1632
|
p = (boolean8_t *) co->ptr;
|
|
1109
1633
|
for (i=0; i<ca->elements; i++) {
|
|
1110
|
-
|
|
1111
|
-
m++; p++;
|
|
1634
|
+
p[i] = ( p[i] ) ? 0 : 1;
|
|
1112
1635
|
}
|
|
1113
|
-
ca_detach(cm);
|
|
1114
1636
|
}
|
|
1115
1637
|
|
|
1116
|
-
return
|
|
1638
|
+
return out;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
VALUE
|
|
1642
|
+
rb_ca_scan_mask_count (VALUE self, VALUE axis)
|
|
1643
|
+
{
|
|
1644
|
+
VALUE present = rb_funcall(self, rb_intern("is_not_masked"), 0);
|
|
1645
|
+
VALUE count;
|
|
1646
|
+
if ( NIL_P(axis) ) {
|
|
1647
|
+
count = rb_funcall(present, rb_intern("cumsum"), 0);
|
|
1648
|
+
}
|
|
1649
|
+
else {
|
|
1650
|
+
VALUE kw = rb_hash_new();
|
|
1651
|
+
rb_hash_aset(kw, ID2SYM(rb_intern("axis")), axis);
|
|
1652
|
+
count = rb_funcallv_kw(present, rb_intern("cumsum"), 1, &kw, RB_PASS_KEYWORDS);
|
|
1653
|
+
}
|
|
1654
|
+
return rb_funcall(count, rb_intern("to_type"), 1, INT2NUM(CA_INT64));
|
|
1117
1655
|
}
|
|
1118
1656
|
|
|
1119
1657
|
/* @overload unmask (fill_value = nil)
|
|
@@ -1139,19 +1677,20 @@ rb_ca_unmask_method (int argc, VALUE *argv, VALUE self)
|
|
|
1139
1677
|
rfval = argv[0];
|
|
1140
1678
|
}
|
|
1141
1679
|
|
|
1680
|
+
/* Filling with UNDEF leaves the cells undefined, as storing UNDEF does. */
|
|
1681
|
+
if ( rfval == CA_UNDEF ) {
|
|
1682
|
+
return self;
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1142
1685
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1143
1686
|
|
|
1144
1687
|
if ( rfval != CA_UNSPECIFIED ) {
|
|
1145
|
-
/*
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
CArray *root = ca;
|
|
1149
|
-
while (root && ca_is_face(root)) root = ((CAView *) root)->parent;
|
|
1150
|
-
if (root) conv_type = root->data_type;
|
|
1151
|
-
}
|
|
1152
|
-
rcs = rb_cscalar_new_with_value(conv_type, ca->bytes, rfval);
|
|
1688
|
+
/* The fill is a value of the array (a struct, an instant for a Face):
|
|
1689
|
+
rb_ca_obj2ptr writes it as one cell of the storage. */
|
|
1690
|
+
rcs = rb_cscalar_new(ca_strip_face(ca)->data_type, ca->bytes, NULL);
|
|
1153
1691
|
TypedData_Get_Struct(rcs, CScalar, &cscalar_data_type, cv);
|
|
1154
1692
|
fval = cv->ptr;
|
|
1693
|
+
rb_ca_obj2ptr(self, rfval, fval);
|
|
1155
1694
|
}
|
|
1156
1695
|
|
|
1157
1696
|
ca_unmask(ca, fval);
|
|
@@ -1175,14 +1714,9 @@ rb_ca_mask_fill (VALUE self, VALUE fval)
|
|
|
1175
1714
|
return rb_ca_unmask_method(1, &fval, self);
|
|
1176
1715
|
}
|
|
1177
1716
|
|
|
1178
|
-
/*
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
Returns new unmasked array.
|
|
1182
|
-
If the optional argument <code>fill_value</code> is given,
|
|
1183
|
-
the masked elements are filled by <code>fill_value</code>.
|
|
1184
|
-
The returned array doesn't have the mask array.
|
|
1185
|
-
*/
|
|
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). */
|
|
1186
1720
|
|
|
1187
1721
|
static VALUE
|
|
1188
1722
|
rb_ca_unmask_copy_method (int argc, VALUE *argv, VALUE self)
|
|
@@ -1196,19 +1730,21 @@ rb_ca_unmask_copy_method (int argc, VALUE *argv, VALUE self)
|
|
|
1196
1730
|
rfval = argv[0];
|
|
1197
1731
|
}
|
|
1198
1732
|
|
|
1733
|
+
/* Filling with UNDEF leaves the cells undefined, as storing UNDEF does:
|
|
1734
|
+
the copy keeps the mask. */
|
|
1735
|
+
if ( rfval == CA_UNDEF ) {
|
|
1736
|
+
return rb_ca_copy(self);
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1199
1739
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1200
1740
|
|
|
1201
1741
|
if ( rfval != CA_UNSPECIFIED ) {
|
|
1202
|
-
/*
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
CArray *root = ca;
|
|
1206
|
-
while (root && ca_is_face(root)) root = ((CAView *) root)->parent;
|
|
1207
|
-
if (root) conv_type = root->data_type;
|
|
1208
|
-
}
|
|
1209
|
-
rcs = rb_cscalar_new_with_value(conv_type, ca->bytes, rfval);
|
|
1742
|
+
/* The fill is a value of the array (a struct, an instant for a Face):
|
|
1743
|
+
rb_ca_obj2ptr writes it as one cell of the storage. */
|
|
1744
|
+
rcs = rb_cscalar_new(ca_strip_face(ca)->data_type, ca->bytes, NULL);
|
|
1210
1745
|
TypedData_Get_Struct(rcs, CScalar, &cscalar_data_type, cv);
|
|
1211
1746
|
fval = cv->ptr;
|
|
1747
|
+
rb_ca_obj2ptr(self, rfval, fval);
|
|
1212
1748
|
}
|
|
1213
1749
|
|
|
1214
1750
|
co = ca_unmask_copy(ca, fval);
|
|
@@ -1243,6 +1779,7 @@ VALUE
|
|
|
1243
1779
|
rb_ca_invert_mask (VALUE self)
|
|
1244
1780
|
{
|
|
1245
1781
|
CArray *ca;
|
|
1782
|
+
rb_ca_modify(self);
|
|
1246
1783
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1247
1784
|
ca_invert_mask(ca);
|
|
1248
1785
|
return self;
|
|
@@ -1274,24 +1811,53 @@ rb_ca_s_guard_undef(int argc, VALUE *argv, VALUE klass)
|
|
|
1274
1811
|
|
|
1275
1812
|
/* mask_eq(v) — return form of "mask cells equal to v".
|
|
1276
1813
|
Equivalent to: obj = copy; obj[:eq, v] = UNDEF; obj */
|
|
1814
|
+
/* Masks a copy of self at the cells the store key `argv` selects. A
|
|
1815
|
+
read-only Face (CAConstString, CACategorical) copies read-only, so the
|
|
1816
|
+
mask goes on a copy of its storage and the Face is put back; a predicate
|
|
1817
|
+
key (`:eq, v`) is evaluated on the Face, where it compares values rather
|
|
1818
|
+
than storage. */
|
|
1277
1819
|
static VALUE
|
|
1278
|
-
|
|
1820
|
+
ca_mask_copy_where (VALUE self, int argc, VALUE *argv)
|
|
1279
1821
|
{
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1822
|
+
CArray *ca;
|
|
1823
|
+
volatile VALUE obj;
|
|
1824
|
+
VALUE *all_args = ALLOCA_N(VALUE, argc + 1);
|
|
1825
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1826
|
+
if ( ca_is_face(ca) && ca_is_readonly(ca) ) {
|
|
1827
|
+
obj = rb_ca_copy(rb_ca_strip_face_value(self));
|
|
1828
|
+
if ( argc >= 1 && SYMBOL_P(argv[0]) ) {
|
|
1829
|
+
all_args[0] = rb_funcallv(self, SYM2ID(argv[0]), argc - 1, argv + 1);
|
|
1830
|
+
all_args[1] = CA_UNDEF;
|
|
1831
|
+
rb_funcallv(obj, rb_intern("[]="), 2, all_args);
|
|
1832
|
+
}
|
|
1833
|
+
else {
|
|
1834
|
+
memcpy(all_args, argv, argc * sizeof(VALUE));
|
|
1835
|
+
all_args[argc] = CA_UNDEF;
|
|
1836
|
+
rb_funcallv(obj, rb_intern("[]="), argc + 1, all_args);
|
|
1837
|
+
}
|
|
1838
|
+
return rb_funcall(obj, rb_intern("face_lift"), 1, self);
|
|
1839
|
+
}
|
|
1840
|
+
obj = rb_ca_copy(self);
|
|
1841
|
+
memcpy(all_args, argv, argc * sizeof(VALUE));
|
|
1842
|
+
all_args[argc] = CA_UNDEF;
|
|
1843
|
+
rb_funcallv(obj, rb_intern("[]="), argc + 1, all_args);
|
|
1283
1844
|
return obj;
|
|
1284
1845
|
}
|
|
1285
1846
|
|
|
1847
|
+
static VALUE
|
|
1848
|
+
rb_ca_mask_eq (VALUE self, VALUE v)
|
|
1849
|
+
{
|
|
1850
|
+
VALUE args[2] = { ID2SYM(rb_intern("eq")), v };
|
|
1851
|
+
return ca_mask_copy_where(self, 2, args);
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1286
1854
|
/* mask_invalid — return form of "mask NaN/Inf cells".
|
|
1287
1855
|
Equivalent to: obj = copy; obj[:is_invalid] = UNDEF; obj */
|
|
1288
1856
|
static VALUE
|
|
1289
1857
|
rb_ca_mask_invalid (VALUE self)
|
|
1290
1858
|
{
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
ID2SYM(rb_intern("is_invalid")), CA_UNDEF);
|
|
1294
|
-
return obj;
|
|
1859
|
+
VALUE args[1] = { ID2SYM(rb_intern("is_invalid")) };
|
|
1860
|
+
return ca_mask_copy_where(self, 1, args);
|
|
1295
1861
|
}
|
|
1296
1862
|
|
|
1297
1863
|
/* mask_where(*args) — generic return form predicate masking.
|
|
@@ -1300,17 +1866,10 @@ rb_ca_mask_invalid (VALUE self)
|
|
|
1300
1866
|
static VALUE
|
|
1301
1867
|
rb_ca_mask_where (int argc, VALUE *argv, VALUE self)
|
|
1302
1868
|
{
|
|
1303
|
-
volatile VALUE obj;
|
|
1304
|
-
VALUE *all_args;
|
|
1305
1869
|
if (argc == 0) {
|
|
1306
1870
|
rb_raise(rb_eArgError, "mask_where requires at least 1 argument");
|
|
1307
1871
|
}
|
|
1308
|
-
|
|
1309
|
-
all_args = ALLOCA_N(VALUE, argc + 1);
|
|
1310
|
-
memcpy(all_args, argv, argc * sizeof(VALUE));
|
|
1311
|
-
all_args[argc] = CA_UNDEF;
|
|
1312
|
-
rb_funcallv(obj, rb_intern("[]="), argc + 1, all_args);
|
|
1313
|
-
return obj;
|
|
1872
|
+
return ca_mask_copy_where(self, argc, argv);
|
|
1314
1873
|
}
|
|
1315
1874
|
|
|
1316
1875
|
/* @overload inherit_mask (*others):
|
|
@@ -1324,6 +1883,7 @@ static VALUE
|
|
|
1324
1883
|
rb_ca_inherit_mask_method (int argc, VALUE *argv, VALUE self)
|
|
1325
1884
|
{
|
|
1326
1885
|
CArray **slist;
|
|
1886
|
+
volatile VALUE holder;
|
|
1327
1887
|
CArray *ca, *cs;
|
|
1328
1888
|
int i;
|
|
1329
1889
|
|
|
@@ -1331,7 +1891,7 @@ rb_ca_inherit_mask_method (int argc, VALUE *argv, VALUE self)
|
|
|
1331
1891
|
|
|
1332
1892
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1333
1893
|
|
|
1334
|
-
slist =
|
|
1894
|
+
slist = ALLOCV_N(CArray *, holder, argc);
|
|
1335
1895
|
for (i=0; i<argc; i++) {
|
|
1336
1896
|
if ( rb_obj_is_carray(argv[i]) ) {
|
|
1337
1897
|
TypedData_Get_Struct(argv[i], CArray, &carray_data_type, cs);
|
|
@@ -1343,7 +1903,7 @@ rb_ca_inherit_mask_method (int argc, VALUE *argv, VALUE self)
|
|
|
1343
1903
|
}
|
|
1344
1904
|
ca_copy_mask_overlay_n(ca, ca->elements, argc, slist);
|
|
1345
1905
|
|
|
1346
|
-
|
|
1906
|
+
ALLOCV_END(holder);
|
|
1347
1907
|
|
|
1348
1908
|
return self;
|
|
1349
1909
|
}
|
|
@@ -1363,6 +1923,7 @@ rb_ca_inherit_mask (VALUE self, int n, ...)
|
|
|
1363
1923
|
{
|
|
1364
1924
|
VALUE other;
|
|
1365
1925
|
CArray **slist;
|
|
1926
|
+
volatile VALUE holder;
|
|
1366
1927
|
CArray *ca, *cs;
|
|
1367
1928
|
int i;
|
|
1368
1929
|
va_list rothers;
|
|
@@ -1372,7 +1933,7 @@ rb_ca_inherit_mask (VALUE self, int n, ...)
|
|
|
1372
1933
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1373
1934
|
|
|
1374
1935
|
va_start(rothers, n);
|
|
1375
|
-
slist =
|
|
1936
|
+
slist = ALLOCV_N(CArray *, holder, n);
|
|
1376
1937
|
for (i=0; i<n; i++) {
|
|
1377
1938
|
other = va_arg(rothers, VALUE);
|
|
1378
1939
|
if ( rb_obj_is_carray(other) ) {
|
|
@@ -1387,7 +1948,7 @@ rb_ca_inherit_mask (VALUE self, int n, ...)
|
|
|
1387
1948
|
|
|
1388
1949
|
ca_copy_mask_overlay_n(ca, ca->elements, n, slist);
|
|
1389
1950
|
|
|
1390
|
-
|
|
1951
|
+
ALLOCV_END(holder);
|
|
1391
1952
|
|
|
1392
1953
|
return self;
|
|
1393
1954
|
}
|
|
@@ -1403,6 +1964,7 @@ static VALUE
|
|
|
1403
1964
|
rb_ca_inherit_mask_replace_method (int argc, VALUE *argv, VALUE self)
|
|
1404
1965
|
{
|
|
1405
1966
|
CArray **slist;
|
|
1967
|
+
volatile VALUE holder;
|
|
1406
1968
|
CArray *ca, *cs;
|
|
1407
1969
|
int i;
|
|
1408
1970
|
|
|
@@ -1410,7 +1972,7 @@ rb_ca_inherit_mask_replace_method (int argc, VALUE *argv, VALUE self)
|
|
|
1410
1972
|
|
|
1411
1973
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1412
1974
|
|
|
1413
|
-
slist =
|
|
1975
|
+
slist = ALLOCV_N(CArray *, holder, argc);
|
|
1414
1976
|
for (i=0; i<argc; i++) {
|
|
1415
1977
|
if ( rb_obj_is_carray(argv[i]) ) {
|
|
1416
1978
|
TypedData_Get_Struct(argv[i], CArray, &carray_data_type, cs);
|
|
@@ -1422,7 +1984,7 @@ rb_ca_inherit_mask_replace_method (int argc, VALUE *argv, VALUE self)
|
|
|
1422
1984
|
}
|
|
1423
1985
|
ca_copy_mask_overwrite_n(ca, ca->elements, argc, slist);
|
|
1424
1986
|
|
|
1425
|
-
|
|
1987
|
+
ALLOCV_END(holder);
|
|
1426
1988
|
|
|
1427
1989
|
return self;
|
|
1428
1990
|
}
|
|
@@ -1442,6 +2004,7 @@ rb_ca_inherit_mask_replace (VALUE self, int n, ...)
|
|
|
1442
2004
|
{
|
|
1443
2005
|
VALUE other;
|
|
1444
2006
|
CArray **slist;
|
|
2007
|
+
volatile VALUE holder;
|
|
1445
2008
|
CArray *ca, *cs;
|
|
1446
2009
|
int i;
|
|
1447
2010
|
va_list rothers;
|
|
@@ -1451,7 +2014,7 @@ rb_ca_inherit_mask_replace (VALUE self, int n, ...)
|
|
|
1451
2014
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1452
2015
|
|
|
1453
2016
|
va_start(rothers, n);
|
|
1454
|
-
slist =
|
|
2017
|
+
slist = ALLOCV_N(CArray *, holder, n);
|
|
1455
2018
|
for (i=0; i<n; i++) {
|
|
1456
2019
|
other = va_arg(rothers, VALUE);
|
|
1457
2020
|
if ( rb_obj_is_carray(other) ) {
|
|
@@ -1466,34 +2029,34 @@ rb_ca_inherit_mask_replace (VALUE self, int n, ...)
|
|
|
1466
2029
|
|
|
1467
2030
|
ca_copy_mask_overwrite_n(ca, ca->elements, n, slist);
|
|
1468
2031
|
|
|
1469
|
-
|
|
2032
|
+
ALLOCV_END(holder);
|
|
1470
2033
|
|
|
1471
2034
|
return self;
|
|
1472
2035
|
}
|
|
1473
2036
|
|
|
1474
|
-
/*
|
|
1475
|
-
|
|
1476
|
-
|
|
2037
|
+
/* The no-mask answer of count_masked / count_not_masked along `axes`:
|
|
2038
|
+
every reduced cell holds `fill`. A reduction over every axis is the
|
|
2039
|
+
number itself. */
|
|
1477
2040
|
static VALUE
|
|
1478
|
-
|
|
2041
|
+
ca_count_uniform (CArray *ca, const int8_t *axes, int8_t naxes, ca_size_t fill)
|
|
1479
2042
|
{
|
|
1480
2043
|
ca_size_t dim[CA_RANK_MAX];
|
|
1481
2044
|
int8_t ndim = 0;
|
|
1482
2045
|
int i, j;
|
|
1483
|
-
int64_t v = (int64_t)
|
|
2046
|
+
int64_t v = (int64_t) fill;
|
|
1484
2047
|
VALUE result;
|
|
1485
2048
|
CArray *co;
|
|
1486
2049
|
|
|
2050
|
+
if ( naxes == ca->ndim ) {
|
|
2051
|
+
return SIZE2NUM(fill);
|
|
2052
|
+
}
|
|
1487
2053
|
for (i = 0; i < ca->ndim; i++) {
|
|
1488
2054
|
int is_axis = 0;
|
|
1489
|
-
for (j = 0; j <
|
|
1490
|
-
|
|
1491
|
-
if (ax < 0) ax += ca->ndim;
|
|
1492
|
-
if (ax == i) { is_axis = 1; break; }
|
|
2055
|
+
for (j = 0; j < naxes; j++) {
|
|
2056
|
+
if ( axes[j] == i ) { is_axis = 1; break; }
|
|
1493
2057
|
}
|
|
1494
2058
|
if (!is_axis) dim[ndim++] = ca->dim[i];
|
|
1495
2059
|
}
|
|
1496
|
-
|
|
1497
2060
|
result = rb_carray_new(CA_INT64, ndim, dim, 0, NULL);
|
|
1498
2061
|
TypedData_Get_Struct(result, CArray, &carray_data_type, co);
|
|
1499
2062
|
ca_fill(co, &v);
|
|
@@ -1507,111 +2070,95 @@ ca_make_reduced_int64 (CArray *ca, int argc, VALUE *argv, ca_size_t fill_val)
|
|
|
1507
2070
|
extern VALUE rb_ca_count_true_ki (int argc, VALUE *argv, VALUE self);
|
|
1508
2071
|
extern VALUE rb_ca_count_false_ki (int argc, VALUE *argv, VALUE self);
|
|
1509
2072
|
|
|
1510
|
-
/* count_masked
|
|
1511
|
-
|
|
1512
|
-
|
|
2073
|
+
/* count_masked / count_not_masked -- the number of masked (present)
|
|
2074
|
+
cells, over every axis (an Integer) or along `axis:` (an int64 CArray).
|
|
2075
|
+
The keywords are those of the count kernels (axis:, keep_axis:,
|
|
2076
|
+
min_count:, fill_value:), checked by them: the mask is counted with
|
|
2077
|
+
count_true_ki / count_false_ki. Without a mask the answer is known
|
|
2078
|
+
from the shape; an axis: alone takes that short cut after the same
|
|
2079
|
+
axis check the kernels make, and any other keyword runs the kernel on
|
|
2080
|
+
an all-false view that occupies one cell.
|
|
1513
2081
|
|
|
1514
2082
|
Public (non-static) linkage so rb_ca_count in carray_count.c can forward
|
|
1515
2083
|
count(UNDEF) here directly without going through Ruby method dispatch. */
|
|
1516
|
-
VALUE
|
|
1517
|
-
|
|
2084
|
+
static VALUE
|
|
2085
|
+
ca_count_by_mask (int argc, VALUE *argv, VALUE self, int masked)
|
|
1518
2086
|
{
|
|
1519
2087
|
CArray *ca;
|
|
2088
|
+
VALUE kw_hash = Qnil, mask_obj;
|
|
1520
2089
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1521
|
-
|
|
1522
|
-
/* Accepts the axis: kwarg only (positional axis is not accepted),
|
|
1523
|
-
matching the aggregate _ki family. */
|
|
1524
|
-
VALUE kw_hash, axis_val = Qnil;
|
|
1525
2090
|
rb_scan_args(argc, argv, "0:", &kw_hash);
|
|
1526
|
-
rb_scan_options(kw_hash, "axis", &axis_val);
|
|
1527
2091
|
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
if (NIL_P(
|
|
1532
|
-
|
|
2092
|
+
if ( ! ca_has_mask(ca) ) {
|
|
2093
|
+
VALUE axis_val = Qnil;
|
|
2094
|
+
int only_axis = 1;
|
|
2095
|
+
if ( ! NIL_P(kw_hash) ) {
|
|
2096
|
+
VALUE given = rb_hash_lookup2(kw_hash, ID2SYM(rb_intern("axis")), Qundef);
|
|
2097
|
+
axis_val = ( given == Qundef ) ? Qnil : given;
|
|
2098
|
+
only_axis = ( RHASH_SIZE(kw_hash) == ( given == Qundef ? 0u : 1u ) );
|
|
2099
|
+
}
|
|
2100
|
+
if ( only_axis ) {
|
|
2101
|
+
int8_t axes[CA_RANK_MAX];
|
|
2102
|
+
int8_t naxes = rb_ca_parse_reduce_axes_kw(axis_val, ca, axes);
|
|
2103
|
+
ca_size_t vol = 1;
|
|
2104
|
+
int i;
|
|
2105
|
+
for ( i = 0; i < naxes; i++ ) vol *= ca->dim[axes[i]];
|
|
2106
|
+
return ca_count_uniform(ca, axes, naxes, masked ? 0 : vol);
|
|
2107
|
+
}
|
|
2108
|
+
{
|
|
2109
|
+
ca_size_t one[CA_RANK_MAX];
|
|
2110
|
+
VALUE shape = rb_ary_new_capa(ca->ndim), cell;
|
|
2111
|
+
boolean8_t zero = 0;
|
|
2112
|
+
CArray *cc;
|
|
2113
|
+
int i;
|
|
2114
|
+
for ( i = 0; i < ca->ndim; i++ ) {
|
|
2115
|
+
one[i] = 1;
|
|
2116
|
+
rb_ary_push(shape, SIZE2NUM(ca->dim[i]));
|
|
2117
|
+
}
|
|
2118
|
+
cell = rb_carray_new(CA_BOOLEAN, ca->ndim, one, 0, NULL);
|
|
2119
|
+
TypedData_Get_Struct(cell, CArray, &carray_data_type, cc);
|
|
2120
|
+
ca_fill(cc, &zero);
|
|
2121
|
+
mask_obj = rb_funcallv(cell, rb_intern("broadcast_to"),
|
|
2122
|
+
(int) RARRAY_LEN(shape), RARRAY_CONST_PTR(shape));
|
|
1533
2123
|
}
|
|
1534
|
-
VALUE axis_ary = (TYPE(axis_val) == T_ARRAY) ? axis_val : rb_ary_new3(1, axis_val);
|
|
1535
|
-
return ca_make_reduced_int64(ca, (int) RARRAY_LEN(axis_ary),
|
|
1536
|
-
(VALUE *) RARRAY_CONST_PTR(axis_ary), 0);
|
|
1537
2124
|
}
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
2125
|
+
else {
|
|
2126
|
+
mask_obj = rb_ca_mask_array(self);
|
|
2127
|
+
}
|
|
2128
|
+
if ( NIL_P(kw_hash) ) {
|
|
2129
|
+
return masked ? rb_ca_count_true_ki(0, NULL, mask_obj)
|
|
2130
|
+
: rb_ca_count_false_ki(0, NULL, mask_obj);
|
|
2131
|
+
}
|
|
2132
|
+
{
|
|
2133
|
+
VALUE kargv[1] = { kw_hash };
|
|
2134
|
+
return masked ? rb_ca_count_true_ki(1, kargv, mask_obj)
|
|
2135
|
+
: rb_ca_count_false_ki(1, kargv, mask_obj);
|
|
1547
2136
|
}
|
|
1548
|
-
VALUE kw = rb_hash_new();
|
|
1549
|
-
rb_hash_aset(kw, ID2SYM(rb_intern("axis")), axis_val);
|
|
1550
|
-
VALUE kargv[1] = { kw };
|
|
1551
|
-
return rb_ca_count_true_ki(1, kargv, mask_obj);
|
|
1552
2137
|
}
|
|
1553
2138
|
|
|
1554
|
-
/* @overload count_not_masked(*axis)
|
|
1555
|
-
|
|
1556
|
-
(Masking, Statistics)
|
|
1557
|
-
Returns the number of not-masked elements, optionally reduced along axes.
|
|
1558
|
-
With no arguments returns an Integer. With axis arguments returns a
|
|
1559
|
-
CArray of int64 with the specified axes collapsed.
|
|
1560
|
-
*/
|
|
1561
|
-
/* C-callable entry: skip rb_scan_args (call-frame state dependency).
|
|
1562
|
-
* axis_val = Qnil -> scalar Integer count over whole array
|
|
1563
|
-
* axis_val = Integer/Array -> reduced CArray int64
|
|
1564
|
-
* For ext authors who need to call count_not_masked from C. */
|
|
1565
2139
|
VALUE
|
|
1566
|
-
|
|
2140
|
+
rb_ca_count_masked (int argc, VALUE *argv, VALUE self)
|
|
1567
2141
|
{
|
|
1568
|
-
|
|
1569
|
-
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1570
|
-
|
|
1571
|
-
/* No mask -> every element is not-masked. Short-circuit without
|
|
1572
|
-
materialising a mask (no axis -> elements; axis form -> reduced int64
|
|
1573
|
-
filled with the product of the reduced-axis extents). */
|
|
1574
|
-
if (!ca_has_mask(ca)) {
|
|
1575
|
-
if (NIL_P(axis_val)) {
|
|
1576
|
-
return SIZE2NUM(ca->elements);
|
|
1577
|
-
}
|
|
1578
|
-
VALUE axis_ary = (TYPE(axis_val) == T_ARRAY) ? axis_val : rb_ary_new3(1, axis_val);
|
|
1579
|
-
int n_axes = (int) RARRAY_LEN(axis_ary);
|
|
1580
|
-
VALUE *axes_argv = (VALUE *) RARRAY_CONST_PTR(axis_ary);
|
|
1581
|
-
ca_size_t axis_vol = 1;
|
|
1582
|
-
int j;
|
|
1583
|
-
for (j = 0; j < n_axes; j++) {
|
|
1584
|
-
int ax = NUM2INT(axes_argv[j]);
|
|
1585
|
-
if (ax < 0) ax += ca->ndim;
|
|
1586
|
-
axis_vol *= ca->dim[ax];
|
|
1587
|
-
}
|
|
1588
|
-
return ca_make_reduced_int64(ca, n_axes, axes_argv, axis_vol);
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
/* Not-masked count = count of `false` in the mask, routed through the
|
|
1592
|
-
count_false_ki kernel for both the flat (no axis -> scalar Integer) and
|
|
1593
|
-
per-axis (-> reduced CArray) forms. The scalar C primitive
|
|
1594
|
-
ca_count_not_masked (= elements - ca_count_masked) stays separately for
|
|
1595
|
-
internal C callers (median / order) that need a raw ca_size_t. */
|
|
1596
|
-
VALUE mask_obj = rb_ca_mask_array(self);
|
|
1597
|
-
if (NIL_P(axis_val)) {
|
|
1598
|
-
return rb_ca_count_false_ki(0, NULL, mask_obj);
|
|
1599
|
-
}
|
|
1600
|
-
VALUE kw = rb_hash_new();
|
|
1601
|
-
rb_hash_aset(kw, ID2SYM(rb_intern("axis")), axis_val);
|
|
1602
|
-
VALUE kargv[1] = { kw };
|
|
1603
|
-
return rb_ca_count_false_ki(1, kargv, mask_obj);
|
|
2142
|
+
return ca_count_by_mask(argc, argv, self, 1);
|
|
1604
2143
|
}
|
|
1605
2144
|
|
|
1606
|
-
/* Ruby binding entry: parses (axis: kwarg) -> forwards to _c. */
|
|
1607
2145
|
VALUE
|
|
1608
2146
|
rb_ca_count_not_masked (int argc, VALUE *argv, VALUE self)
|
|
1609
2147
|
{
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
2148
|
+
return ca_count_by_mask(argc, argv, self, 0);
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
/* count_not_masked(axis: axis_val) for C callers. */
|
|
2152
|
+
VALUE
|
|
2153
|
+
rb_ca_count_not_masked_c (VALUE self, VALUE axis_val)
|
|
2154
|
+
{
|
|
2155
|
+
VALUE kw;
|
|
2156
|
+
if ( NIL_P(axis_val) ) {
|
|
2157
|
+
return ca_count_by_mask(0, NULL, self, 0);
|
|
2158
|
+
}
|
|
2159
|
+
kw = rb_hash_new();
|
|
2160
|
+
rb_hash_aset(kw, ID2SYM(rb_intern("axis")), axis_val);
|
|
2161
|
+
return rb_funcall_with_block_kw(self, rb_intern("count_not_masked"), 1, &kw, Qnil, RB_PASS_KEYWORDS);
|
|
1615
2162
|
}
|
|
1616
2163
|
|
|
1617
2164
|
/* ============================================================================
|
|
@@ -1833,10 +2380,47 @@ Init_carray_mask_fast_paths (void)
|
|
|
1833
2380
|
}
|
|
1834
2381
|
|
|
1835
2382
|
|
|
2383
|
+
/* The Ruby forms of inherit_mask take CArray arguments only: refuse a
|
|
2384
|
+
keyword and any argument that is not a CArray, which the C API would
|
|
2385
|
+
pass over as maskless. Returns the arguments without the keyword Hash. */
|
|
2386
|
+
static VALUE
|
|
2387
|
+
ca_inherit_mask_check_args (int argc, VALUE *argv, const char *name)
|
|
2388
|
+
{
|
|
2389
|
+
VALUE rest, ropt;
|
|
2390
|
+
long i;
|
|
2391
|
+
rb_scan_args(argc, argv, "*:", &rest, &ropt);
|
|
2392
|
+
rb_reject_options(ropt);
|
|
2393
|
+
for (i=0; i<RARRAY_LEN(rest); i++) {
|
|
2394
|
+
VALUE v = RARRAY_AREF(rest, i);
|
|
2395
|
+
if ( ! rb_obj_is_carray(v) ) {
|
|
2396
|
+
rb_raise(rb_eTypeError, "%s: argument %ld must be a CArray (got %s)",
|
|
2397
|
+
name, i, rb_obj_classname(v));
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
return rest;
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
static VALUE
|
|
2404
|
+
rb_ca_inherit_mask_ruby (int argc, VALUE *argv, VALUE self)
|
|
2405
|
+
{
|
|
2406
|
+
volatile VALUE rest = ca_inherit_mask_check_args(argc, argv, "inherit_mask");
|
|
2407
|
+
return rb_ca_inherit_mask_method((int) RARRAY_LEN(rest),
|
|
2408
|
+
(VALUE *) RARRAY_CONST_PTR(rest), self);
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2411
|
+
static VALUE
|
|
2412
|
+
rb_ca_inherit_mask_replace_ruby (int argc, VALUE *argv, VALUE self)
|
|
2413
|
+
{
|
|
2414
|
+
volatile VALUE rest = ca_inherit_mask_check_args(argc, argv,
|
|
2415
|
+
"inherit_mask_replace");
|
|
2416
|
+
return rb_ca_inherit_mask_replace_method((int) RARRAY_LEN(rest),
|
|
2417
|
+
(VALUE *) RARRAY_CONST_PTR(rest), self);
|
|
2418
|
+
}
|
|
2419
|
+
|
|
1836
2420
|
void
|
|
1837
2421
|
Init_carray_mask (void)
|
|
1838
2422
|
{
|
|
1839
|
-
rb_define_private_method(rb_cCArray, "
|
|
2423
|
+
rb_define_private_method(rb_cCArray, "add_mask", rb_ca_create_mask, 0);
|
|
1840
2424
|
/*
|
|
1841
2425
|
rb_define_private_method(rb_cCArray, "__update_mask__", rb_ca_update_mask, 0);
|
|
1842
2426
|
*/
|
|
@@ -1847,6 +2431,8 @@ Init_carray_mask (void)
|
|
|
1847
2431
|
|
|
1848
2432
|
rb_define_method(rb_cCArray, "value", rb_ca_value_array, 0);
|
|
1849
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);
|
|
1850
2436
|
rb_define_method(rb_cCArray, "mask=", rb_ca_set_mask, 1);
|
|
1851
2437
|
rb_define_method(rb_cCArray, "is_masked", rb_ca_is_masked, 0);
|
|
1852
2438
|
rb_define_method(rb_cCArray, "is_not_masked", rb_ca_is_not_masked, 0);
|
|
@@ -1869,9 +2455,9 @@ Init_carray_mask (void)
|
|
|
1869
2455
|
rb_define_method(rb_cCArray, "mask_invalid", rb_ca_mask_invalid, 0);
|
|
1870
2456
|
rb_define_method(rb_cCArray, "mask_where", rb_ca_mask_where, -1);
|
|
1871
2457
|
|
|
1872
|
-
rb_define_method(rb_cCArray, "inherit_mask",
|
|
2458
|
+
rb_define_method(rb_cCArray, "inherit_mask", rb_ca_inherit_mask_ruby, -1);
|
|
1873
2459
|
rb_define_method(rb_cCArray, "inherit_mask_replace",
|
|
1874
|
-
|
|
2460
|
+
rb_ca_inherit_mask_replace_ruby, -1);
|
|
1875
2461
|
|
|
1876
2462
|
rb_define_method(rb_cCArray, "count_masked", rb_ca_count_masked, -1);
|
|
1877
2463
|
rb_define_method(rb_cCArray, "count_not_masked", rb_ca_count_not_masked, -1);
|