carray 3.0.2 → 3.0.3
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 +304 -0
- data/README.md +3 -4
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +225 -0
- data/ext/ca_axis_group.c +177 -99
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +66 -71
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +663 -214
- data/ext/ca_kernel_iterator.h +231 -167
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +132 -22
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +1 -0
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +96 -25
- data/ext/ca_obj_face.c +406 -64
- data/ext/ca_obj_face.h +92 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +21 -21
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +189 -107
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +543 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +47 -49
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -118
- data/ext/ca_obj_stride.c +195 -34
- data/ext/ca_obj_string.c +17 -18
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +149 -27
- 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 +102 -79
- 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 +463 -0
- data/ext/carray.h +70 -27
- data/ext/carray_access.c +455 -211
- data/ext/carray_address_basis.c +177 -36
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +46 -14
- data/ext/carray_call_cfunc.c +0 -28
- data/ext/carray_cast.c +1444 -209
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +32 -11
- data/ext/carray_core.c +514 -122
- data/ext/carray_count.c +140 -87
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +569 -277
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +385 -3
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +682 -316
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +221 -76
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1089 -359
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +273 -239
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +170 -70
- data/ext/carray_sort.c +215 -218
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +0 -2
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1076 -846
- data/ext/ruby_carray.c +7 -1
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +19 -0
- data/lib/carray/autoload_method_extension.rb +6 -0
- data/lib/carray/axis_group.rb +174 -26
- data/lib/carray/basics.rb +91 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +118 -48
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +94 -26
- data/lib/carray/categorical_iterator.rb +333 -826
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +46 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +589 -82
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +124 -25
- data/lib/carray/frame/group.rb +189 -63
- data/lib/carray/frame/io.rb +412 -72
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +37 -16
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +715 -48
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +29 -11
- data/lib/carray/iterator.rb +14 -2
- data/lib/carray/lazy.rb +54 -30
- data/lib/carray/mask_gap_fill.rb +66 -52
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +117 -4
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +177 -36
- data/lib/carray/methods/mode.rb +18 -1
- 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/record_order.rb +208 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +51 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +4 -3
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +517 -103
- data/lib/carray/window_iterator.rb +127 -72
- data/lib/carray.rb +2 -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 +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +1 -2
- data/yard-stubs/carray_access.rb +5 -4
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +25 -13
- data/yard-stubs/carray_median_percentile.rb +10 -6
- data/yard-stubs/carray_order.rb +34 -13
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +2 -1
- data/yard-stubs/carray_sort.rb +43 -3
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +11 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -26005
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14862
- data/ext/carray_kernels_reduce_extreme.c +0 -17494
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32218
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
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
|
-
}
|
|
233
|
-
|
|
234
|
-
ca_xfer_stride(mask, starts, counts, native, scratch, CA_XFER_GET);
|
|
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;
|
|
235
274
|
|
|
236
|
-
|
|
237
|
-
|
|
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,161 @@ 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_multi_parent_mask (CArray *p, CArray **standin)
|
|
427
|
+
{
|
|
428
|
+
*standin = NULL;
|
|
429
|
+
if ( ! ca_has_mask(p) ) {
|
|
430
|
+
CArray *z = carray_new(CA_BOOLEAN, p->ndim, p->dim, 0, NULL);
|
|
431
|
+
MEMZERO(z->ptr, boolean8_t, z->elements);
|
|
432
|
+
if ( ca_is_readonly(p) ) {
|
|
433
|
+
ca_set_flag(z, CA_FLAG_READ_ONLY);
|
|
434
|
+
}
|
|
435
|
+
*standin = z;
|
|
436
|
+
return z;
|
|
437
|
+
}
|
|
438
|
+
ca_create_mask(p);
|
|
439
|
+
return p->mask;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/* A value array or a mask array: a parent that can never be given a mask,
|
|
443
|
+
whose stand-in therefore stays in place for good. */
|
|
444
|
+
static int
|
|
445
|
+
ca_multi_parent_mask_unmaskable (CArray *p)
|
|
446
|
+
{
|
|
447
|
+
return ca_is_value_array(p) || ca_is_mask_array(p);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
void
|
|
451
|
+
ca_multi_parent_mask_refresh (CArray *mask, CArray **parents,
|
|
452
|
+
CArray **standins, int32_t n, int for_write)
|
|
453
|
+
{
|
|
454
|
+
CAMultiParent *mp = (CAMultiParent *) mask;
|
|
455
|
+
int32_t k;
|
|
456
|
+
/* Not inside an attach window: its buffer and its detach are those of
|
|
457
|
+
the parents it was opened with. The attach and allocate slots run
|
|
458
|
+
before the buffer is published, and replace the stand-ins then. */
|
|
459
|
+
if ( standins == NULL || ( CAVIEW(mask)->attach > 0 && mask->ptr != NULL ) ) {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
/* A replaced stand-in stays allocated until the view is freed: a copy
|
|
463
|
+
of the mask (dup) may still point at it. */
|
|
464
|
+
for ( k = 0; k < n; k++ ) {
|
|
465
|
+
CArray *z = standins[k];
|
|
466
|
+
if ( z == NULL || mp->parents[k] != z
|
|
467
|
+
|| ca_test_flag(z, CA_FLAG_READ_ONLY)
|
|
468
|
+
|| ca_multi_parent_mask_unmaskable(parents[k]) ) {
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
if ( ! ( for_write || ca_has_mask(parents[k]) ) ) {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
ca_create_mask(parents[k]);
|
|
475
|
+
mp->parents[k] = parents[k]->mask;
|
|
476
|
+
if ( k == 0 ) {
|
|
477
|
+
CAVIEW(mask)->parent = parents[k]->mask;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
void
|
|
483
|
+
ca_multi_parent_mask_check (CArray *mask, CArray **parents,
|
|
484
|
+
CArray **standins, int32_t n)
|
|
485
|
+
{
|
|
486
|
+
CAMultiParent *mp = (CAMultiParent *) mask;
|
|
487
|
+
int32_t k;
|
|
488
|
+
if ( standins == NULL ) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
for ( k = 0; k < n; k++ ) {
|
|
492
|
+
CArray *z = standins[k];
|
|
493
|
+
ca_size_t i;
|
|
494
|
+
if ( z == NULL || mp->parents[k] != z
|
|
495
|
+
|| ! ca_multi_parent_mask_unmaskable(parents[k]) ) {
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
for ( i = 0; i < z->elements && ! ((boolean8_t *) z->ptr)[i]; i++ ) ;
|
|
499
|
+
if ( i == z->elements ) {
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
MEMZERO(z->ptr, boolean8_t, z->elements);
|
|
503
|
+
rb_raise(rb_eTypeError, "can not create mask array for the %s array",
|
|
504
|
+
ca_is_value_array(parents[k]) ? "value" : "mask");
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
void
|
|
509
|
+
ca_multi_parent_mask_settle (CArray *mask, CArray **parents,
|
|
510
|
+
CArray **standins, int32_t n)
|
|
511
|
+
{
|
|
512
|
+
CAMultiParent *mp = (CAMultiParent *) mask;
|
|
513
|
+
int32_t k;
|
|
514
|
+
if ( standins == NULL ) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
ca_multi_parent_mask_check(mask, parents, standins, n);
|
|
518
|
+
for ( k = 0; k < n; k++ ) {
|
|
519
|
+
CArray *z = standins[k];
|
|
520
|
+
ca_size_t i;
|
|
521
|
+
if ( z == NULL || mp->parents[k] != z
|
|
522
|
+
|| ca_test_flag(z, CA_FLAG_READ_ONLY)
|
|
523
|
+
|| ca_multi_parent_mask_unmaskable(parents[k]) ) {
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
for ( i = 0; i < z->elements && ! ((boolean8_t *) z->ptr)[i]; i++ ) ;
|
|
527
|
+
if ( i == z->elements ) {
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
ca_create_mask(parents[k]);
|
|
531
|
+
ca_xfer_all(parents[k]->mask, z->ptr, CA_XFER_PUT);
|
|
532
|
+
MEMZERO(z->ptr, boolean8_t, z->elements);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
377
536
|
void
|
|
378
537
|
ca_create_mask (void *ap)
|
|
379
538
|
{
|
|
380
539
|
CArray *ca = (CArray *) ap;
|
|
381
540
|
|
|
541
|
+
if ( ca->mask ) {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
|
|
382
545
|
if ( ca_is_value_array(ca) ) {
|
|
383
|
-
rb_raise(
|
|
546
|
+
rb_raise(rb_eTypeError,
|
|
384
547
|
"can not create mask array for the value array");
|
|
385
548
|
}
|
|
386
549
|
|
|
387
550
|
if ( ca_is_mask_array(ca) ) {
|
|
388
|
-
rb_raise(
|
|
551
|
+
rb_raise(rb_eTypeError,
|
|
389
552
|
"can not create mask array for the mask array");
|
|
390
553
|
}
|
|
391
554
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
if (
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
555
|
+
ca_func[ca->obj_type].create_mask(ca);
|
|
556
|
+
ca_set_flag(ca->mask, CA_FLAG_MASK_ARRAY); /* set array as mask array */
|
|
557
|
+
if ( ca_is_view(ca) ) {
|
|
558
|
+
if ( CAVIEW(ca)->attach ) {
|
|
559
|
+
/* The new mask joins its view's level. Its attach reads the
|
|
560
|
+
parent's mask, which can raise (a Ruby-backed parent); the mask
|
|
561
|
+
then comes off again, since the view's sync and detach would
|
|
562
|
+
find it attached to nothing. */
|
|
563
|
+
int tag = 0;
|
|
564
|
+
rb_protect(ca_create_mask_attach, (VALUE) ca->mask, &tag);
|
|
565
|
+
if ( tag ) {
|
|
566
|
+
CArray *mask = ca->mask;
|
|
567
|
+
ca->mask = NULL;
|
|
568
|
+
ca_free(mask);
|
|
569
|
+
rb_jump_tag(tag);
|
|
570
|
+
}
|
|
571
|
+
if ( ca_is_view(ca->mask) ) {
|
|
572
|
+
CAVIEW(ca->mask)->attach = CAVIEW(ca)->attach;
|
|
401
573
|
}
|
|
402
574
|
}
|
|
403
575
|
}
|
|
@@ -415,6 +587,20 @@ ca_clear_mask (void *ap)
|
|
|
415
587
|
}
|
|
416
588
|
}
|
|
417
589
|
|
|
590
|
+
typedef struct {
|
|
591
|
+
CArray *ca;
|
|
592
|
+
CArray *mask;
|
|
593
|
+
} ca_setup_mask_t;
|
|
594
|
+
|
|
595
|
+
/* Pushing the cells into ca's mask can raise (a CAObject's mask hooks). */
|
|
596
|
+
static VALUE
|
|
597
|
+
ca_setup_mask_body (VALUE arg)
|
|
598
|
+
{
|
|
599
|
+
ca_setup_mask_t *c = (ca_setup_mask_t *) arg;
|
|
600
|
+
ca_sync_data(c->ca->mask, c->mask->ptr);
|
|
601
|
+
return Qnil;
|
|
602
|
+
}
|
|
603
|
+
|
|
418
604
|
void
|
|
419
605
|
ca_setup_mask (void *ap, CArray *mask)
|
|
420
606
|
{
|
|
@@ -423,12 +609,13 @@ ca_setup_mask (void *ap, CArray *mask)
|
|
|
423
609
|
ca_update_mask(ca);
|
|
424
610
|
|
|
425
611
|
if ( mask ) {
|
|
612
|
+
ca_setup_mask_t c;
|
|
426
613
|
if ( ! ca->mask ) {
|
|
427
614
|
ca_create_mask(ca);
|
|
428
615
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
616
|
+
c.ca = ca;
|
|
617
|
+
c.mask = mask;
|
|
618
|
+
ca_attach_window(1, &c.mask, "r", ca_setup_mask_body, (VALUE) &c);
|
|
432
619
|
}
|
|
433
620
|
else if ( ca->mask ) {
|
|
434
621
|
boolean8_t zero = 0;
|
|
@@ -443,12 +630,59 @@ ca_setup_mask (void *ap, CArray *mask)
|
|
|
443
630
|
|
|
444
631
|
*/
|
|
445
632
|
|
|
446
|
-
|
|
447
|
-
|
|
633
|
+
/* The overlay reads each source's mask into the destination's. A
|
|
634
|
+
source's mask can be made or read by calling Ruby (a CAObject's mask
|
|
635
|
+
hooks) and raise, so every mask is made first and the lot are read
|
|
636
|
+
inside one attach window.
|
|
637
|
+
|
|
638
|
+
A source whose cells live in the destination's root has its mask read
|
|
639
|
+
into a snapshot before the destination's mask is made, cleared or
|
|
640
|
+
written: the destination's mask may be that same memory, and the word
|
|
641
|
+
OR would otherwise read bytes it has already set. */
|
|
642
|
+
typedef struct {
|
|
643
|
+
CArray **list; /* [0] the destination mask, then the attached sources' */
|
|
644
|
+
boolean8_t **snap; /* per source: its mask read in advance, or NULL */
|
|
645
|
+
CArray **att; /* per source: its attached mask when not snapped */
|
|
646
|
+
char *scalar; /* per source: the source is a scalar */
|
|
647
|
+
int k; /* entries in list */
|
|
648
|
+
int ns; /* sources */
|
|
649
|
+
ca_size_t elements;
|
|
650
|
+
} ca_mask_overlay_t;
|
|
651
|
+
|
|
652
|
+
static VALUE
|
|
653
|
+
ca_mask_overlay_body (VALUE arg)
|
|
654
|
+
{
|
|
655
|
+
ca_mask_overlay_t *o = (ca_mask_overlay_t *) arg;
|
|
656
|
+
boolean8_t *ma = (boolean8_t *) o->list[0]->ptr;
|
|
657
|
+
int i;
|
|
658
|
+
for (i=0; i<o->ns; i++) {
|
|
659
|
+
boolean8_t *ms = o->snap[i] ? o->snap[i] : (boolean8_t *) o->att[i]->ptr;
|
|
660
|
+
/* scalar masked source -> broadcast to all (memset); array source
|
|
661
|
+
-> pure word OR (ca_mask_word_or). A defensive `if (*ms)` is
|
|
662
|
+
unnecessary: under the {0,1} invariant, `*ma |= *ms` equals
|
|
663
|
+
`if (*ms) *ma = 1`. Post-condition: the mask byte stays in {0,1}. */
|
|
664
|
+
if ( o->scalar[i] ) {
|
|
665
|
+
if ( *ms ) {
|
|
666
|
+
memset(ma, 1, o->elements);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
ca_mask_word_or(ma, ms, o->elements);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
return Qnil;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/* overwrite: the destination's mask is cleared before the sources are
|
|
677
|
+
OR'd in (and left alone when it has none and no source has a mask). */
|
|
678
|
+
static void
|
|
679
|
+
ca_copy_mask_overlay_core (CArray *ca, ca_size_t elements, int n,
|
|
680
|
+
CArray **slist, int overwrite)
|
|
448
681
|
{
|
|
449
|
-
CArray *ca = (CArray *) ap;
|
|
450
682
|
CArray *cs;
|
|
451
|
-
|
|
683
|
+
ca_mask_overlay_t o;
|
|
684
|
+
volatile VALUE *holders;
|
|
685
|
+
char *modes;
|
|
452
686
|
int i, some_has_mask = 0;
|
|
453
687
|
|
|
454
688
|
for (i=0; i<n; i++) {
|
|
@@ -458,81 +692,115 @@ ca_copy_mask_overlay_n (void *ap, ca_size_t elements, int n, CArray **slist)
|
|
|
458
692
|
}
|
|
459
693
|
}
|
|
460
694
|
|
|
461
|
-
if ( some_has_mask ) {
|
|
695
|
+
if ( ! some_has_mask ) {
|
|
696
|
+
if ( overwrite ) {
|
|
697
|
+
ca_update_mask(ca);
|
|
698
|
+
if ( ca->mask ) {
|
|
699
|
+
boolean8_t zero = 0;
|
|
700
|
+
ca_fill(ca->mask, &zero);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
462
705
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
706
|
+
if ( elements > ca->elements ) {
|
|
707
|
+
elements = ca->elements;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
o.list = ALLOCA_N(CArray *, n + 1);
|
|
711
|
+
o.snap = ALLOCA_N(boolean8_t *, n);
|
|
712
|
+
o.att = ALLOCA_N(CArray *, n);
|
|
713
|
+
o.scalar = ALLOCA_N(char, n);
|
|
714
|
+
holders = ALLOCA_N(VALUE, n);
|
|
715
|
+
modes = ALLOCA_N(char, n + 2);
|
|
716
|
+
o.elements = elements;
|
|
717
|
+
o.ns = 0;
|
|
718
|
+
for (i=0; i<n; i++) {
|
|
719
|
+
holders[i] = 0;
|
|
720
|
+
}
|
|
721
|
+
ca_update_mask(ca);
|
|
722
|
+
|
|
723
|
+
/* Every source mask is made, and those in the destination's root are
|
|
724
|
+
read, before the destination's mask is touched. */
|
|
725
|
+
for (i=0; i<n; i++) {
|
|
726
|
+
cs = slist[i];
|
|
727
|
+
if ( ! cs ) {
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
ca_update_mask(cs);
|
|
731
|
+
if ( ! cs->mask ) {
|
|
732
|
+
continue;
|
|
733
|
+
}
|
|
734
|
+
o.scalar[o.ns] = (char) ca_is_scalar(cs);
|
|
735
|
+
o.att[o.ns] = NULL;
|
|
736
|
+
o.snap[o.ns] = NULL;
|
|
737
|
+
if ( ca_shares_root(cs, ca) || ca_shares_root(cs->mask, ca) ||
|
|
738
|
+
( ca->mask && ca_shares_root(cs->mask, ca->mask) ) ) {
|
|
739
|
+
o.snap[o.ns] = ALLOCV_N(boolean8_t, holders[o.ns], cs->mask->elements);
|
|
740
|
+
ca_xfer_all(cs->mask, (char *) o.snap[o.ns], CA_XFER_GET);
|
|
741
|
+
}
|
|
742
|
+
else {
|
|
743
|
+
o.att[o.ns] = cs->mask;
|
|
466
744
|
}
|
|
745
|
+
o.ns++;
|
|
746
|
+
}
|
|
467
747
|
|
|
468
|
-
|
|
469
|
-
|
|
748
|
+
ca_create_mask(ca);
|
|
749
|
+
if ( overwrite ) {
|
|
750
|
+
boolean8_t zero = 0;
|
|
751
|
+
ca_fill(ca->mask, &zero);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
o.k = 0;
|
|
755
|
+
o.list[o.k] = ca->mask;
|
|
756
|
+
modes[o.k++] = 'w';
|
|
757
|
+
for (i=0; i<o.ns; i++) {
|
|
758
|
+
if ( o.att[i] ) {
|
|
759
|
+
o.list[o.k] = o.att[i];
|
|
760
|
+
modes[o.k++] = 'r';
|
|
470
761
|
}
|
|
762
|
+
}
|
|
763
|
+
modes[o.k] = '\0';
|
|
764
|
+
ca_attach_window(o.k, o.list, modes, ca_mask_overlay_body, (VALUE) &o);
|
|
471
765
|
|
|
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);
|
|
766
|
+
for (i=0; i<n; i++) {
|
|
767
|
+
if ( holders[i] ) {
|
|
768
|
+
ALLOCV_END(holders[i]);
|
|
498
769
|
}
|
|
499
|
-
ca_sync(ca->mask);
|
|
500
|
-
ca_detach(ca->mask);
|
|
501
770
|
}
|
|
502
771
|
}
|
|
503
772
|
|
|
773
|
+
void
|
|
774
|
+
ca_copy_mask_overlay_n (void *ap, ca_size_t elements, int n, CArray **slist)
|
|
775
|
+
{
|
|
776
|
+
ca_copy_mask_overlay_core((CArray *) ap, elements, n, slist, 0);
|
|
777
|
+
}
|
|
778
|
+
|
|
504
779
|
void
|
|
505
780
|
ca_copy_mask_overlay (void *ap, ca_size_t elements, int n, ...)
|
|
506
781
|
{
|
|
507
782
|
CArray *ca = (CArray *) ap;
|
|
508
783
|
CArray **slist;
|
|
784
|
+
volatile VALUE holder;
|
|
509
785
|
va_list args;
|
|
510
786
|
int i;
|
|
511
787
|
|
|
512
|
-
slist =
|
|
788
|
+
slist = ALLOCV_N(CArray *, holder, n);
|
|
513
789
|
va_start(args, n);
|
|
514
790
|
for (i=0; i<n; i++) {
|
|
515
791
|
slist[i] = va_arg(args, CArray *);
|
|
516
792
|
}
|
|
517
793
|
va_end(args);
|
|
518
794
|
|
|
519
|
-
|
|
795
|
+
ca_copy_mask_overlay_core(ca, elements, n, slist, 0);
|
|
520
796
|
|
|
521
|
-
|
|
797
|
+
ALLOCV_END(holder);
|
|
522
798
|
}
|
|
523
799
|
|
|
524
800
|
void
|
|
525
801
|
ca_copy_mask_overwrite_n (void *ap, ca_size_t elements, int n, CArray **slist)
|
|
526
802
|
{
|
|
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);
|
|
803
|
+
ca_copy_mask_overlay_core((CArray *) ap, elements, n, slist, 1);
|
|
536
804
|
}
|
|
537
805
|
|
|
538
806
|
void
|
|
@@ -540,25 +808,20 @@ ca_copy_mask_overwrite (void *ap, ca_size_t elements, int n, ...)
|
|
|
540
808
|
{
|
|
541
809
|
CArray *ca = (CArray *) ap;
|
|
542
810
|
CArray **slist;
|
|
811
|
+
volatile VALUE holder;
|
|
543
812
|
va_list args;
|
|
544
813
|
int i;
|
|
545
814
|
|
|
546
|
-
slist =
|
|
815
|
+
slist = ALLOCV_N(CArray *, holder, n);
|
|
547
816
|
va_start(args, n);
|
|
548
817
|
for (i=0; i<n; i++) {
|
|
549
818
|
slist[i] = va_arg(args, CArray*);
|
|
550
819
|
}
|
|
551
820
|
va_end(args);
|
|
552
821
|
|
|
553
|
-
|
|
554
|
-
if ( ca->mask ) {
|
|
555
|
-
boolean8_t zero = 0;
|
|
556
|
-
ca_fill(ca->mask, &zero);
|
|
557
|
-
}
|
|
822
|
+
ca_copy_mask_overlay_core(ca, elements, n, slist, 1);
|
|
558
823
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
xfree(slist);
|
|
824
|
+
ALLOCV_END(holder);
|
|
562
825
|
}
|
|
563
826
|
|
|
564
827
|
void
|
|
@@ -582,7 +845,7 @@ ca_count_masked (void *ap)
|
|
|
582
845
|
if ( ca->mask ) {
|
|
583
846
|
if ( ca_attach_is_alias(ca->mask) ) {
|
|
584
847
|
/* cheap mask: O(1) alias attach + word-bulk count. */
|
|
585
|
-
ca_attach(ca->mask);
|
|
848
|
+
ca_attach(ca->mask); /* window: nothing raises inside */
|
|
586
849
|
m = (boolean8_t *) ca->mask->ptr;
|
|
587
850
|
count = ca_mask_word_count(m, ca->elements);
|
|
588
851
|
ca_detach(ca->mask);
|
|
@@ -644,7 +907,7 @@ ca_unmask (void *ap, char *fill_value)
|
|
|
644
907
|
ca_fill(ca->mask, &zero);
|
|
645
908
|
}
|
|
646
909
|
else {
|
|
647
|
-
ca_attach(ca);
|
|
910
|
+
ca_attach(ca); /* window: nothing raises inside */
|
|
648
911
|
|
|
649
912
|
switch ( ca->bytes ) {
|
|
650
913
|
case 1: proc_fill_bang_width(uint8_t); break;
|
|
@@ -654,8 +917,7 @@ ca_unmask (void *ap, char *fill_value)
|
|
|
654
917
|
default: proc_fill_bang_bytes(); break; /* cmplx128 (16) + fixlen */
|
|
655
918
|
}
|
|
656
919
|
|
|
657
|
-
|
|
658
|
-
ca_detach(ca);
|
|
920
|
+
ca_sync_detach(ca);
|
|
659
921
|
}
|
|
660
922
|
}
|
|
661
923
|
}
|
|
@@ -677,17 +939,21 @@ ca_unmask_copy_fill (VALUE arg)
|
|
|
677
939
|
|
|
678
940
|
ca_copy_data(ca, co->ptr);
|
|
679
941
|
|
|
942
|
+
/* Only the mask is needed now that the values are in co, so read the
|
|
943
|
+
mask alone rather than producing the view's cells a second time. */
|
|
680
944
|
if ( a->fill_value && ca_has_mask(ca) ) {
|
|
681
|
-
|
|
945
|
+
volatile VALUE holder = 0;
|
|
946
|
+
ca_update_mask(ca);
|
|
947
|
+
m = ALLOCV_N(boolean8_t, holder, ca->elements);
|
|
948
|
+
ca_copy_data(ca->mask, (char *) m);
|
|
682
949
|
q = co->ptr;
|
|
683
|
-
m = (boolean8_t *) ca->mask->ptr;
|
|
684
950
|
for (i=0; i<ca->elements; i++) {
|
|
685
|
-
if (
|
|
951
|
+
if ( m[i] ) {
|
|
686
952
|
memcpy(q, a->fill_value, ca->bytes);
|
|
687
953
|
}
|
|
688
|
-
|
|
954
|
+
q+=co->bytes;
|
|
689
955
|
}
|
|
690
|
-
|
|
956
|
+
ALLOCV_END(holder);
|
|
691
957
|
}
|
|
692
958
|
return Qnil;
|
|
693
959
|
}
|
|
@@ -709,16 +975,12 @@ ca_invert_mask (void *ap)
|
|
|
709
975
|
CArray *ca = (CArray *) ap;
|
|
710
976
|
boolean8_t *m;
|
|
711
977
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
if ( ! ca->mask ) {
|
|
715
|
-
ca_create_mask(ca);
|
|
716
|
-
}
|
|
978
|
+
ca_create_mask(ca);
|
|
717
979
|
|
|
718
|
-
ca_attach(ca->mask);
|
|
980
|
+
ca_attach(ca->mask); /* window: nothing raises inside */
|
|
719
981
|
m = (boolean8_t *) ca->mask->ptr;
|
|
720
982
|
ca_mask_word_not(m, m, ca->elements); /* in-place 1 - m, LSB-XOR word loop */
|
|
721
|
-
|
|
983
|
+
ca_sync_detach(ca->mask);
|
|
722
984
|
|
|
723
985
|
return;
|
|
724
986
|
}
|
|
@@ -727,9 +989,10 @@ boolean8_t *
|
|
|
727
989
|
ca_allocate_mask_iterator_n (int n, CArray **slist)
|
|
728
990
|
{
|
|
729
991
|
boolean8_t *m, *mp, *ms;
|
|
730
|
-
CArray *cs;
|
|
992
|
+
CArray *cs, **masks;
|
|
993
|
+
char *scalar;
|
|
731
994
|
ca_size_t j, elements = -1;
|
|
732
|
-
int i, some_has_mask = 0;
|
|
995
|
+
int i, k = 0, some_has_mask = 0;
|
|
733
996
|
|
|
734
997
|
for (i=0; i<n; i++) {
|
|
735
998
|
if ( slist[i] ) {
|
|
@@ -743,7 +1006,7 @@ ca_allocate_mask_iterator_n (int n, CArray **slist)
|
|
|
743
1006
|
elements = slist[i]->elements;
|
|
744
1007
|
}
|
|
745
1008
|
else if ( ! ca_is_scalar(slist[i]) ) {
|
|
746
|
-
rb_raise(
|
|
1009
|
+
rb_raise(rb_eArgError,
|
|
747
1010
|
"# of elements is different among the given arrays");
|
|
748
1011
|
}
|
|
749
1012
|
}
|
|
@@ -758,13 +1021,18 @@ ca_allocate_mask_iterator_n (int n, CArray **slist)
|
|
|
758
1021
|
(degenerate call); guard so the alloc/memset never see a negative size
|
|
759
1022
|
(which would wrap to a huge bound). Also silences GCC's VRP warnings. */
|
|
760
1023
|
if ( elements < 0 ) elements = 0;
|
|
761
|
-
m = xmalloc(sizeof(boolean8_t)*elements);
|
|
762
|
-
memset(m, 0, elements);
|
|
763
1024
|
|
|
764
1025
|
if ( ! some_has_mask ) {
|
|
1026
|
+
m = xmalloc(sizeof(boolean8_t)*elements);
|
|
1027
|
+
memset(m, 0, elements);
|
|
765
1028
|
return m;
|
|
766
1029
|
}
|
|
767
1030
|
|
|
1031
|
+
/* The sources' masks, made and attached before the result is allocated:
|
|
1032
|
+
making or reading one can call Ruby (a CAObject's mask hooks) and
|
|
1033
|
+
raise, and then nothing is left attached or allocated. */
|
|
1034
|
+
masks = ALLOCA_N(CArray *, n);
|
|
1035
|
+
scalar = ALLOCA_N(char, n);
|
|
768
1036
|
for (i=0; i<n; i++) {
|
|
769
1037
|
cs = slist[i];
|
|
770
1038
|
if ( ! cs ) {
|
|
@@ -774,10 +1042,17 @@ ca_allocate_mask_iterator_n (int n, CArray **slist)
|
|
|
774
1042
|
if ( ! cs->mask ) {
|
|
775
1043
|
continue;
|
|
776
1044
|
}
|
|
777
|
-
|
|
778
|
-
|
|
1045
|
+
masks[k] = cs->mask;
|
|
1046
|
+
scalar[k++] = (char) ca_is_scalar(cs);
|
|
1047
|
+
}
|
|
1048
|
+
ca_attach_all(masks, k); /* window: nothing raises inside */
|
|
1049
|
+
|
|
1050
|
+
m = xmalloc(sizeof(boolean8_t)*elements);
|
|
1051
|
+
memset(m, 0, elements);
|
|
1052
|
+
for (i=0; i<k; i++) {
|
|
1053
|
+
ms = (boolean8_t *) masks[i]->ptr;
|
|
779
1054
|
mp = m;
|
|
780
|
-
if (
|
|
1055
|
+
if ( scalar[i] ) {
|
|
781
1056
|
if ( *ms ) {
|
|
782
1057
|
for (j=0; j<elements; j++) {
|
|
783
1058
|
*mp = 1;
|
|
@@ -788,7 +1063,9 @@ ca_allocate_mask_iterator_n (int n, CArray **slist)
|
|
|
788
1063
|
else {
|
|
789
1064
|
ca_mask_word_or(mp, ms, elements); /* m[j] |= ms[j], word-bulk OR */
|
|
790
1065
|
}
|
|
791
|
-
|
|
1066
|
+
}
|
|
1067
|
+
while ( k > 0 ) {
|
|
1068
|
+
ca_detach(masks[--k]);
|
|
792
1069
|
}
|
|
793
1070
|
return m;
|
|
794
1071
|
}
|
|
@@ -798,10 +1075,11 @@ ca_allocate_mask_iterator (int n, ...)
|
|
|
798
1075
|
{
|
|
799
1076
|
boolean8_t *m;
|
|
800
1077
|
CArray **slist;
|
|
1078
|
+
volatile VALUE holder;
|
|
801
1079
|
va_list args;
|
|
802
1080
|
int i;
|
|
803
1081
|
|
|
804
|
-
slist =
|
|
1082
|
+
slist = ALLOCV_N(CArray *, holder, n);
|
|
805
1083
|
va_start(args, n);
|
|
806
1084
|
for (i=0; i<n; i++) {
|
|
807
1085
|
slist[i] = va_arg(args, CArray *);
|
|
@@ -810,7 +1088,7 @@ ca_allocate_mask_iterator (int n, ...)
|
|
|
810
1088
|
|
|
811
1089
|
m = ca_allocate_mask_iterator_n(n, slist);
|
|
812
1090
|
|
|
813
|
-
|
|
1091
|
+
ALLOCV_END(holder);
|
|
814
1092
|
|
|
815
1093
|
return m;
|
|
816
1094
|
}
|
|
@@ -964,12 +1242,15 @@ rb_ca_mask_array (VALUE self)
|
|
|
964
1242
|
|
|
965
1243
|
ca_update_mask(ca);
|
|
966
1244
|
if ( ca->mask ) {
|
|
1245
|
+
/* The mask is reached from its array, not through a parent link, so
|
|
1246
|
+
ca_is_readonly on the mask never sees the array's read-only state.
|
|
1247
|
+
Pass it on here, where the mask is handed out. */
|
|
1248
|
+
if ( ca_is_readonly(ca) ) {
|
|
1249
|
+
ca_set_flag(ca->mask, CA_FLAG_READ_ONLY);
|
|
1250
|
+
}
|
|
967
1251
|
obj = TypedData_Wrap_Struct(ca_mask_class[ca->obj_type],
|
|
968
|
-
ca_mask_typeddata[ca->obj_type], ca->mask);
|
|
1252
|
+
ca_mask_typeddata[ca->obj_type], ca->mask);
|
|
969
1253
|
rb_ivar_set(obj, rb_intern("masked_array"), self);
|
|
970
|
-
if ( OBJ_FROZEN(self) ) {
|
|
971
|
-
rb_ca_freeze(obj);
|
|
972
|
-
}
|
|
973
1254
|
return obj;
|
|
974
1255
|
}
|
|
975
1256
|
else {
|
|
@@ -996,30 +1277,54 @@ rb_ca_set_mask (VALUE self, VALUE rval)
|
|
|
996
1277
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
997
1278
|
|
|
998
1279
|
if ( ca_is_value_array(ca) ) {
|
|
999
|
-
rb_raise(
|
|
1280
|
+
rb_raise(rb_eTypeError,
|
|
1000
1281
|
"can not create mask for the value array");
|
|
1001
1282
|
}
|
|
1002
1283
|
|
|
1003
1284
|
if ( ca_is_mask_array(ca) ) {
|
|
1004
|
-
rb_raise(
|
|
1285
|
+
rb_raise(rb_eTypeError,
|
|
1005
1286
|
"can not create mask for the mask array");
|
|
1006
1287
|
}
|
|
1007
1288
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1289
|
+
if ( TYPE(rmask) == T_ARRAY ) {
|
|
1290
|
+
/* Flattened as a store into a boolean array of this shape flattens
|
|
1291
|
+
it, and then taken as a 1-D boolean array (UNDEF becomes a masked
|
|
1292
|
+
cell, as in any boolean array made from it). */
|
|
1293
|
+
CArray shape = *ca;
|
|
1294
|
+
shape.data_type = CA_BOOLEAN;
|
|
1295
|
+
shape.bytes = ca_sizeof[CA_BOOLEAN];
|
|
1296
|
+
rmask = rb_ary_flatten_for_elements(rmask, ca->elements, &shape);
|
|
1297
|
+
if ( NIL_P(rmask) ) {
|
|
1298
|
+
rb_raise(rb_eArgError, "failed to guess data size of given array");
|
|
1299
|
+
}
|
|
1300
|
+
rmask = rb_ca_wrap_readonly(rmask, INT2NUM(CA_BOOLEAN));
|
|
1011
1301
|
}
|
|
1012
1302
|
|
|
1013
1303
|
if ( rb_obj_is_carray(rmask) ) {
|
|
1304
|
+
/* The array owns the shape, as in a store: the new mask agrees with
|
|
1305
|
+
it, is 1-D or squeezes to it, or broadcasts along size-1 axes.
|
|
1306
|
+
Checked before the mask exists, so a refused one leaves none. */
|
|
1307
|
+
ca_broadcast_to_destination(self, &rmask);
|
|
1014
1308
|
TypedData_Get_Struct(rmask, CArray, &carray_data_type, cv);
|
|
1309
|
+
/* A new mask taken from self's own root, or from self's mask, is
|
|
1310
|
+
read from a copy: making and writing self's mask would change it
|
|
1311
|
+
before it is read. */
|
|
1312
|
+
ca_update_mask(ca);
|
|
1313
|
+
if ( ca_shares_root(cv, ca) ||
|
|
1314
|
+
( ca->mask && ca_shares_root(cv, ca->mask) ) ) {
|
|
1315
|
+
rmask = rb_ca_copy(rmask);
|
|
1316
|
+
TypedData_Get_Struct(rmask, CArray, &carray_data_type, cv);
|
|
1317
|
+
}
|
|
1015
1318
|
if ( ! ca_is_boolean_type(cv) ) {
|
|
1016
|
-
cv = ca_wrap_readonly(
|
|
1319
|
+
cv = ca_wrap_readonly(rmask, CA_BOOLEAN);
|
|
1017
1320
|
}
|
|
1321
|
+
ca_create_mask(ca);
|
|
1018
1322
|
ca_setup_mask(ca, cv);
|
|
1019
1323
|
ca_copy_mask_overlay(ca, ca->elements, 1, cv);
|
|
1020
1324
|
return rval;
|
|
1021
1325
|
}
|
|
1022
1326
|
else {
|
|
1327
|
+
ca_create_mask(ca);
|
|
1023
1328
|
return rb_ca_store_all(rb_ca_mask_array(self), rmask);
|
|
1024
1329
|
}
|
|
1025
1330
|
}
|
|
@@ -1035,39 +1340,36 @@ with <code>self</code>. The returned array has 1 for the masked elements and
|
|
|
1035
1340
|
VALUE
|
|
1036
1341
|
rb_ca_is_masked (VALUE self)
|
|
1037
1342
|
{
|
|
1038
|
-
volatile VALUE
|
|
1039
|
-
CArray *ca, *
|
|
1343
|
+
volatile VALUE out;
|
|
1344
|
+
CArray *ca, *co;
|
|
1040
1345
|
boolean8_t zero = 0;
|
|
1041
|
-
boolean8_t *
|
|
1346
|
+
boolean8_t *p;
|
|
1042
1347
|
ca_size_t i;
|
|
1043
1348
|
|
|
1044
1349
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1045
1350
|
|
|
1046
1351
|
if ( ca_is_scalar(ca) ) {
|
|
1047
|
-
co = (CArray *)cscalar_new(CA_BOOLEAN, ca->bytes, NULL);
|
|
1352
|
+
co = (CArray *)cscalar_new(CA_BOOLEAN, ca->bytes, NULL);
|
|
1048
1353
|
}
|
|
1049
1354
|
else {
|
|
1050
|
-
co = carray_new(CA_BOOLEAN, ca->ndim, ca->dim, ca->bytes, NULL);
|
|
1355
|
+
co = carray_new(CA_BOOLEAN, ca->ndim, ca->dim, ca->bytes, NULL);
|
|
1051
1356
|
}
|
|
1357
|
+
out = ca_wrap_struct(co); /* owned by Ruby before anything can raise */
|
|
1052
1358
|
|
|
1053
1359
|
ca_update_mask(ca);
|
|
1054
1360
|
if ( ! ca->mask ) {
|
|
1055
1361
|
ca_fill(co, &zero);
|
|
1056
1362
|
}
|
|
1057
1363
|
else {
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
ca_attach(cm);
|
|
1061
|
-
m = (boolean8_t *) cm->ptr;
|
|
1364
|
+
/* Copied straight into the result, then normalised in place. */
|
|
1365
|
+
ca_copy_data(ca->mask, co->ptr);
|
|
1062
1366
|
p = (boolean8_t *) co->ptr;
|
|
1063
1367
|
for (i=0; i<ca->elements; i++) {
|
|
1064
|
-
|
|
1065
|
-
m++; p++;
|
|
1368
|
+
p[i] = ( p[i] ) ? 1 : 0;
|
|
1066
1369
|
}
|
|
1067
|
-
ca_detach(cm);
|
|
1068
1370
|
}
|
|
1069
1371
|
|
|
1070
|
-
return
|
|
1372
|
+
return out;
|
|
1071
1373
|
}
|
|
1072
1374
|
|
|
1073
1375
|
/* @overload is_not_masked
|
|
@@ -1081,39 +1383,52 @@ The returned array has 0 for the masked elements and
|
|
|
1081
1383
|
VALUE
|
|
1082
1384
|
rb_ca_is_not_masked (VALUE self)
|
|
1083
1385
|
{
|
|
1084
|
-
volatile VALUE
|
|
1085
|
-
CArray *ca, *
|
|
1386
|
+
volatile VALUE out;
|
|
1387
|
+
CArray *ca, *co;
|
|
1086
1388
|
boolean8_t one = 1;
|
|
1087
|
-
boolean8_t *
|
|
1389
|
+
boolean8_t *p;
|
|
1088
1390
|
ca_size_t i;
|
|
1089
1391
|
|
|
1090
1392
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1091
1393
|
|
|
1092
1394
|
if ( ca_is_scalar(ca) ) {
|
|
1093
|
-
co = (CArray *)
|
|
1395
|
+
co = (CArray *)cscalar_new(CA_BOOLEAN, ca->bytes, NULL);
|
|
1094
1396
|
}
|
|
1095
1397
|
else {
|
|
1096
|
-
co = carray_new(CA_BOOLEAN, ca->ndim, ca->dim, ca->bytes, NULL);
|
|
1398
|
+
co = carray_new(CA_BOOLEAN, ca->ndim, ca->dim, ca->bytes, NULL);
|
|
1097
1399
|
}
|
|
1400
|
+
out = ca_wrap_struct(co); /* owned by Ruby before anything can raise */
|
|
1098
1401
|
|
|
1099
1402
|
ca_update_mask(ca);
|
|
1100
1403
|
if ( ! ca->mask ) {
|
|
1101
1404
|
ca_fill(co, &one);
|
|
1102
1405
|
}
|
|
1103
1406
|
else {
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
ca_attach(cm);
|
|
1107
|
-
m = (boolean8_t *) cm->ptr;
|
|
1407
|
+
/* Copied straight into the result, then normalised in place. */
|
|
1408
|
+
ca_copy_data(ca->mask, co->ptr);
|
|
1108
1409
|
p = (boolean8_t *) co->ptr;
|
|
1109
1410
|
for (i=0; i<ca->elements; i++) {
|
|
1110
|
-
|
|
1111
|
-
m++; p++;
|
|
1411
|
+
p[i] = ( p[i] ) ? 0 : 1;
|
|
1112
1412
|
}
|
|
1113
|
-
ca_detach(cm);
|
|
1114
1413
|
}
|
|
1115
1414
|
|
|
1116
|
-
return
|
|
1415
|
+
return out;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
VALUE
|
|
1419
|
+
rb_ca_scan_mask_count (VALUE self, VALUE axis)
|
|
1420
|
+
{
|
|
1421
|
+
VALUE present = rb_funcall(self, rb_intern("is_not_masked"), 0);
|
|
1422
|
+
VALUE count;
|
|
1423
|
+
if ( NIL_P(axis) ) {
|
|
1424
|
+
count = rb_funcall(present, rb_intern("cumsum"), 0);
|
|
1425
|
+
}
|
|
1426
|
+
else {
|
|
1427
|
+
VALUE kw = rb_hash_new();
|
|
1428
|
+
rb_hash_aset(kw, ID2SYM(rb_intern("axis")), axis);
|
|
1429
|
+
count = rb_funcallv_kw(present, rb_intern("cumsum"), 1, &kw, RB_PASS_KEYWORDS);
|
|
1430
|
+
}
|
|
1431
|
+
return rb_funcall(count, rb_intern("to_type"), 1, INT2NUM(CA_INT64));
|
|
1117
1432
|
}
|
|
1118
1433
|
|
|
1119
1434
|
/* @overload unmask (fill_value = nil)
|
|
@@ -1139,19 +1454,20 @@ rb_ca_unmask_method (int argc, VALUE *argv, VALUE self)
|
|
|
1139
1454
|
rfval = argv[0];
|
|
1140
1455
|
}
|
|
1141
1456
|
|
|
1457
|
+
/* Filling with UNDEF leaves the cells undefined, as storing UNDEF does. */
|
|
1458
|
+
if ( rfval == CA_UNDEF ) {
|
|
1459
|
+
return self;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1142
1462
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1143
1463
|
|
|
1144
1464
|
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);
|
|
1465
|
+
/* The fill is a value of the array (a struct, an instant for a Face):
|
|
1466
|
+
rb_ca_obj2ptr writes it as one cell of the storage. */
|
|
1467
|
+
rcs = rb_cscalar_new(ca_strip_face(ca)->data_type, ca->bytes, NULL);
|
|
1153
1468
|
TypedData_Get_Struct(rcs, CScalar, &cscalar_data_type, cv);
|
|
1154
1469
|
fval = cv->ptr;
|
|
1470
|
+
rb_ca_obj2ptr(self, rfval, fval);
|
|
1155
1471
|
}
|
|
1156
1472
|
|
|
1157
1473
|
ca_unmask(ca, fval);
|
|
@@ -1196,19 +1512,21 @@ rb_ca_unmask_copy_method (int argc, VALUE *argv, VALUE self)
|
|
|
1196
1512
|
rfval = argv[0];
|
|
1197
1513
|
}
|
|
1198
1514
|
|
|
1515
|
+
/* Filling with UNDEF leaves the cells undefined, as storing UNDEF does:
|
|
1516
|
+
the copy keeps the mask. */
|
|
1517
|
+
if ( rfval == CA_UNDEF ) {
|
|
1518
|
+
return rb_ca_copy(self);
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1199
1521
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1200
1522
|
|
|
1201
1523
|
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);
|
|
1524
|
+
/* The fill is a value of the array (a struct, an instant for a Face):
|
|
1525
|
+
rb_ca_obj2ptr writes it as one cell of the storage. */
|
|
1526
|
+
rcs = rb_cscalar_new(ca_strip_face(ca)->data_type, ca->bytes, NULL);
|
|
1210
1527
|
TypedData_Get_Struct(rcs, CScalar, &cscalar_data_type, cv);
|
|
1211
1528
|
fval = cv->ptr;
|
|
1529
|
+
rb_ca_obj2ptr(self, rfval, fval);
|
|
1212
1530
|
}
|
|
1213
1531
|
|
|
1214
1532
|
co = ca_unmask_copy(ca, fval);
|
|
@@ -1243,6 +1561,7 @@ VALUE
|
|
|
1243
1561
|
rb_ca_invert_mask (VALUE self)
|
|
1244
1562
|
{
|
|
1245
1563
|
CArray *ca;
|
|
1564
|
+
rb_ca_modify(self);
|
|
1246
1565
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1247
1566
|
ca_invert_mask(ca);
|
|
1248
1567
|
return self;
|
|
@@ -1274,24 +1593,53 @@ rb_ca_s_guard_undef(int argc, VALUE *argv, VALUE klass)
|
|
|
1274
1593
|
|
|
1275
1594
|
/* mask_eq(v) — return form of "mask cells equal to v".
|
|
1276
1595
|
Equivalent to: obj = copy; obj[:eq, v] = UNDEF; obj */
|
|
1596
|
+
/* Masks a copy of self at the cells the store key `argv` selects. A
|
|
1597
|
+
read-only Face (CAConstString, CACategorical) copies read-only, so the
|
|
1598
|
+
mask goes on a copy of its storage and the Face is put back; a predicate
|
|
1599
|
+
key (`:eq, v`) is evaluated on the Face, where it compares values rather
|
|
1600
|
+
than storage. */
|
|
1277
1601
|
static VALUE
|
|
1278
|
-
|
|
1602
|
+
ca_mask_copy_where (VALUE self, int argc, VALUE *argv)
|
|
1279
1603
|
{
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1604
|
+
CArray *ca;
|
|
1605
|
+
volatile VALUE obj;
|
|
1606
|
+
VALUE *all_args = ALLOCA_N(VALUE, argc + 1);
|
|
1607
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1608
|
+
if ( ca_is_face(ca) && ca_is_readonly(ca) ) {
|
|
1609
|
+
obj = rb_ca_copy(rb_ca_strip_face_value(self));
|
|
1610
|
+
if ( argc >= 1 && SYMBOL_P(argv[0]) ) {
|
|
1611
|
+
all_args[0] = rb_funcallv(self, SYM2ID(argv[0]), argc - 1, argv + 1);
|
|
1612
|
+
all_args[1] = CA_UNDEF;
|
|
1613
|
+
rb_funcallv(obj, rb_intern("[]="), 2, all_args);
|
|
1614
|
+
}
|
|
1615
|
+
else {
|
|
1616
|
+
memcpy(all_args, argv, argc * sizeof(VALUE));
|
|
1617
|
+
all_args[argc] = CA_UNDEF;
|
|
1618
|
+
rb_funcallv(obj, rb_intern("[]="), argc + 1, all_args);
|
|
1619
|
+
}
|
|
1620
|
+
return rb_funcall(obj, rb_intern("face_lift"), 1, self);
|
|
1621
|
+
}
|
|
1622
|
+
obj = rb_ca_copy(self);
|
|
1623
|
+
memcpy(all_args, argv, argc * sizeof(VALUE));
|
|
1624
|
+
all_args[argc] = CA_UNDEF;
|
|
1625
|
+
rb_funcallv(obj, rb_intern("[]="), argc + 1, all_args);
|
|
1283
1626
|
return obj;
|
|
1284
1627
|
}
|
|
1285
1628
|
|
|
1629
|
+
static VALUE
|
|
1630
|
+
rb_ca_mask_eq (VALUE self, VALUE v)
|
|
1631
|
+
{
|
|
1632
|
+
VALUE args[2] = { ID2SYM(rb_intern("eq")), v };
|
|
1633
|
+
return ca_mask_copy_where(self, 2, args);
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1286
1636
|
/* mask_invalid — return form of "mask NaN/Inf cells".
|
|
1287
1637
|
Equivalent to: obj = copy; obj[:is_invalid] = UNDEF; obj */
|
|
1288
1638
|
static VALUE
|
|
1289
1639
|
rb_ca_mask_invalid (VALUE self)
|
|
1290
1640
|
{
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
ID2SYM(rb_intern("is_invalid")), CA_UNDEF);
|
|
1294
|
-
return obj;
|
|
1641
|
+
VALUE args[1] = { ID2SYM(rb_intern("is_invalid")) };
|
|
1642
|
+
return ca_mask_copy_where(self, 1, args);
|
|
1295
1643
|
}
|
|
1296
1644
|
|
|
1297
1645
|
/* mask_where(*args) — generic return form predicate masking.
|
|
@@ -1300,17 +1648,10 @@ rb_ca_mask_invalid (VALUE self)
|
|
|
1300
1648
|
static VALUE
|
|
1301
1649
|
rb_ca_mask_where (int argc, VALUE *argv, VALUE self)
|
|
1302
1650
|
{
|
|
1303
|
-
volatile VALUE obj;
|
|
1304
|
-
VALUE *all_args;
|
|
1305
1651
|
if (argc == 0) {
|
|
1306
1652
|
rb_raise(rb_eArgError, "mask_where requires at least 1 argument");
|
|
1307
1653
|
}
|
|
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;
|
|
1654
|
+
return ca_mask_copy_where(self, argc, argv);
|
|
1314
1655
|
}
|
|
1315
1656
|
|
|
1316
1657
|
/* @overload inherit_mask (*others):
|
|
@@ -1324,6 +1665,7 @@ static VALUE
|
|
|
1324
1665
|
rb_ca_inherit_mask_method (int argc, VALUE *argv, VALUE self)
|
|
1325
1666
|
{
|
|
1326
1667
|
CArray **slist;
|
|
1668
|
+
volatile VALUE holder;
|
|
1327
1669
|
CArray *ca, *cs;
|
|
1328
1670
|
int i;
|
|
1329
1671
|
|
|
@@ -1331,7 +1673,7 @@ rb_ca_inherit_mask_method (int argc, VALUE *argv, VALUE self)
|
|
|
1331
1673
|
|
|
1332
1674
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1333
1675
|
|
|
1334
|
-
slist =
|
|
1676
|
+
slist = ALLOCV_N(CArray *, holder, argc);
|
|
1335
1677
|
for (i=0; i<argc; i++) {
|
|
1336
1678
|
if ( rb_obj_is_carray(argv[i]) ) {
|
|
1337
1679
|
TypedData_Get_Struct(argv[i], CArray, &carray_data_type, cs);
|
|
@@ -1343,7 +1685,7 @@ rb_ca_inherit_mask_method (int argc, VALUE *argv, VALUE self)
|
|
|
1343
1685
|
}
|
|
1344
1686
|
ca_copy_mask_overlay_n(ca, ca->elements, argc, slist);
|
|
1345
1687
|
|
|
1346
|
-
|
|
1688
|
+
ALLOCV_END(holder);
|
|
1347
1689
|
|
|
1348
1690
|
return self;
|
|
1349
1691
|
}
|
|
@@ -1363,6 +1705,7 @@ rb_ca_inherit_mask (VALUE self, int n, ...)
|
|
|
1363
1705
|
{
|
|
1364
1706
|
VALUE other;
|
|
1365
1707
|
CArray **slist;
|
|
1708
|
+
volatile VALUE holder;
|
|
1366
1709
|
CArray *ca, *cs;
|
|
1367
1710
|
int i;
|
|
1368
1711
|
va_list rothers;
|
|
@@ -1372,7 +1715,7 @@ rb_ca_inherit_mask (VALUE self, int n, ...)
|
|
|
1372
1715
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1373
1716
|
|
|
1374
1717
|
va_start(rothers, n);
|
|
1375
|
-
slist =
|
|
1718
|
+
slist = ALLOCV_N(CArray *, holder, n);
|
|
1376
1719
|
for (i=0; i<n; i++) {
|
|
1377
1720
|
other = va_arg(rothers, VALUE);
|
|
1378
1721
|
if ( rb_obj_is_carray(other) ) {
|
|
@@ -1387,7 +1730,7 @@ rb_ca_inherit_mask (VALUE self, int n, ...)
|
|
|
1387
1730
|
|
|
1388
1731
|
ca_copy_mask_overlay_n(ca, ca->elements, n, slist);
|
|
1389
1732
|
|
|
1390
|
-
|
|
1733
|
+
ALLOCV_END(holder);
|
|
1391
1734
|
|
|
1392
1735
|
return self;
|
|
1393
1736
|
}
|
|
@@ -1403,6 +1746,7 @@ static VALUE
|
|
|
1403
1746
|
rb_ca_inherit_mask_replace_method (int argc, VALUE *argv, VALUE self)
|
|
1404
1747
|
{
|
|
1405
1748
|
CArray **slist;
|
|
1749
|
+
volatile VALUE holder;
|
|
1406
1750
|
CArray *ca, *cs;
|
|
1407
1751
|
int i;
|
|
1408
1752
|
|
|
@@ -1410,7 +1754,7 @@ rb_ca_inherit_mask_replace_method (int argc, VALUE *argv, VALUE self)
|
|
|
1410
1754
|
|
|
1411
1755
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1412
1756
|
|
|
1413
|
-
slist =
|
|
1757
|
+
slist = ALLOCV_N(CArray *, holder, argc);
|
|
1414
1758
|
for (i=0; i<argc; i++) {
|
|
1415
1759
|
if ( rb_obj_is_carray(argv[i]) ) {
|
|
1416
1760
|
TypedData_Get_Struct(argv[i], CArray, &carray_data_type, cs);
|
|
@@ -1422,7 +1766,7 @@ rb_ca_inherit_mask_replace_method (int argc, VALUE *argv, VALUE self)
|
|
|
1422
1766
|
}
|
|
1423
1767
|
ca_copy_mask_overwrite_n(ca, ca->elements, argc, slist);
|
|
1424
1768
|
|
|
1425
|
-
|
|
1769
|
+
ALLOCV_END(holder);
|
|
1426
1770
|
|
|
1427
1771
|
return self;
|
|
1428
1772
|
}
|
|
@@ -1442,6 +1786,7 @@ rb_ca_inherit_mask_replace (VALUE self, int n, ...)
|
|
|
1442
1786
|
{
|
|
1443
1787
|
VALUE other;
|
|
1444
1788
|
CArray **slist;
|
|
1789
|
+
volatile VALUE holder;
|
|
1445
1790
|
CArray *ca, *cs;
|
|
1446
1791
|
int i;
|
|
1447
1792
|
va_list rothers;
|
|
@@ -1451,7 +1796,7 @@ rb_ca_inherit_mask_replace (VALUE self, int n, ...)
|
|
|
1451
1796
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1452
1797
|
|
|
1453
1798
|
va_start(rothers, n);
|
|
1454
|
-
slist =
|
|
1799
|
+
slist = ALLOCV_N(CArray *, holder, n);
|
|
1455
1800
|
for (i=0; i<n; i++) {
|
|
1456
1801
|
other = va_arg(rothers, VALUE);
|
|
1457
1802
|
if ( rb_obj_is_carray(other) ) {
|
|
@@ -1466,34 +1811,34 @@ rb_ca_inherit_mask_replace (VALUE self, int n, ...)
|
|
|
1466
1811
|
|
|
1467
1812
|
ca_copy_mask_overwrite_n(ca, ca->elements, n, slist);
|
|
1468
1813
|
|
|
1469
|
-
|
|
1814
|
+
ALLOCV_END(holder);
|
|
1470
1815
|
|
|
1471
1816
|
return self;
|
|
1472
1817
|
}
|
|
1473
1818
|
|
|
1474
|
-
/*
|
|
1475
|
-
|
|
1476
|
-
|
|
1819
|
+
/* The no-mask answer of count_masked / count_not_masked along `axes`:
|
|
1820
|
+
every reduced cell holds `fill`. A reduction over every axis is the
|
|
1821
|
+
number itself. */
|
|
1477
1822
|
static VALUE
|
|
1478
|
-
|
|
1823
|
+
ca_count_uniform (CArray *ca, const int8_t *axes, int8_t naxes, ca_size_t fill)
|
|
1479
1824
|
{
|
|
1480
1825
|
ca_size_t dim[CA_RANK_MAX];
|
|
1481
1826
|
int8_t ndim = 0;
|
|
1482
1827
|
int i, j;
|
|
1483
|
-
int64_t v = (int64_t)
|
|
1828
|
+
int64_t v = (int64_t) fill;
|
|
1484
1829
|
VALUE result;
|
|
1485
1830
|
CArray *co;
|
|
1486
1831
|
|
|
1832
|
+
if ( naxes == ca->ndim ) {
|
|
1833
|
+
return SIZE2NUM(fill);
|
|
1834
|
+
}
|
|
1487
1835
|
for (i = 0; i < ca->ndim; i++) {
|
|
1488
1836
|
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; }
|
|
1837
|
+
for (j = 0; j < naxes; j++) {
|
|
1838
|
+
if ( axes[j] == i ) { is_axis = 1; break; }
|
|
1493
1839
|
}
|
|
1494
1840
|
if (!is_axis) dim[ndim++] = ca->dim[i];
|
|
1495
1841
|
}
|
|
1496
|
-
|
|
1497
1842
|
result = rb_carray_new(CA_INT64, ndim, dim, 0, NULL);
|
|
1498
1843
|
TypedData_Get_Struct(result, CArray, &carray_data_type, co);
|
|
1499
1844
|
ca_fill(co, &v);
|
|
@@ -1507,111 +1852,95 @@ ca_make_reduced_int64 (CArray *ca, int argc, VALUE *argv, ca_size_t fill_val)
|
|
|
1507
1852
|
extern VALUE rb_ca_count_true_ki (int argc, VALUE *argv, VALUE self);
|
|
1508
1853
|
extern VALUE rb_ca_count_false_ki (int argc, VALUE *argv, VALUE self);
|
|
1509
1854
|
|
|
1510
|
-
/* count_masked
|
|
1511
|
-
|
|
1512
|
-
|
|
1855
|
+
/* count_masked / count_not_masked -- the number of masked (present)
|
|
1856
|
+
cells, over every axis (an Integer) or along `axis:` (an int64 CArray).
|
|
1857
|
+
The keywords are those of the count kernels (axis:, keep_axis:,
|
|
1858
|
+
min_count:, fill_value:), checked by them: the mask is counted with
|
|
1859
|
+
count_true_ki / count_false_ki. Without a mask the answer is known
|
|
1860
|
+
from the shape; an axis: alone takes that short cut after the same
|
|
1861
|
+
axis check the kernels make, and any other keyword runs the kernel on
|
|
1862
|
+
an all-false view that occupies one cell.
|
|
1513
1863
|
|
|
1514
1864
|
Public (non-static) linkage so rb_ca_count in carray_count.c can forward
|
|
1515
1865
|
count(UNDEF) here directly without going through Ruby method dispatch. */
|
|
1516
|
-
VALUE
|
|
1517
|
-
|
|
1866
|
+
static VALUE
|
|
1867
|
+
ca_count_by_mask (int argc, VALUE *argv, VALUE self, int masked)
|
|
1518
1868
|
{
|
|
1519
1869
|
CArray *ca;
|
|
1870
|
+
VALUE kw_hash = Qnil, mask_obj;
|
|
1520
1871
|
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
1872
|
rb_scan_args(argc, argv, "0:", &kw_hash);
|
|
1526
|
-
rb_scan_options(kw_hash, "axis", &axis_val);
|
|
1527
1873
|
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
if (NIL_P(
|
|
1532
|
-
|
|
1874
|
+
if ( ! ca_has_mask(ca) ) {
|
|
1875
|
+
VALUE axis_val = Qnil;
|
|
1876
|
+
int only_axis = 1;
|
|
1877
|
+
if ( ! NIL_P(kw_hash) ) {
|
|
1878
|
+
VALUE given = rb_hash_lookup2(kw_hash, ID2SYM(rb_intern("axis")), Qundef);
|
|
1879
|
+
axis_val = ( given == Qundef ) ? Qnil : given;
|
|
1880
|
+
only_axis = ( RHASH_SIZE(kw_hash) == ( given == Qundef ? 0u : 1u ) );
|
|
1881
|
+
}
|
|
1882
|
+
if ( only_axis ) {
|
|
1883
|
+
int8_t axes[CA_RANK_MAX];
|
|
1884
|
+
int8_t naxes = rb_ca_parse_reduce_axes_kw(axis_val, ca, axes);
|
|
1885
|
+
ca_size_t vol = 1;
|
|
1886
|
+
int i;
|
|
1887
|
+
for ( i = 0; i < naxes; i++ ) vol *= ca->dim[axes[i]];
|
|
1888
|
+
return ca_count_uniform(ca, axes, naxes, masked ? 0 : vol);
|
|
1889
|
+
}
|
|
1890
|
+
{
|
|
1891
|
+
ca_size_t one[CA_RANK_MAX];
|
|
1892
|
+
VALUE shape = rb_ary_new_capa(ca->ndim), cell;
|
|
1893
|
+
boolean8_t zero = 0;
|
|
1894
|
+
CArray *cc;
|
|
1895
|
+
int i;
|
|
1896
|
+
for ( i = 0; i < ca->ndim; i++ ) {
|
|
1897
|
+
one[i] = 1;
|
|
1898
|
+
rb_ary_push(shape, SIZE2NUM(ca->dim[i]));
|
|
1899
|
+
}
|
|
1900
|
+
cell = rb_carray_new(CA_BOOLEAN, ca->ndim, one, 0, NULL);
|
|
1901
|
+
TypedData_Get_Struct(cell, CArray, &carray_data_type, cc);
|
|
1902
|
+
ca_fill(cc, &zero);
|
|
1903
|
+
mask_obj = rb_funcallv(cell, rb_intern("broadcast_to"),
|
|
1904
|
+
(int) RARRAY_LEN(shape), RARRAY_CONST_PTR(shape));
|
|
1533
1905
|
}
|
|
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
1906
|
}
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1907
|
+
else {
|
|
1908
|
+
mask_obj = rb_ca_mask_array(self);
|
|
1909
|
+
}
|
|
1910
|
+
if ( NIL_P(kw_hash) ) {
|
|
1911
|
+
return masked ? rb_ca_count_true_ki(0, NULL, mask_obj)
|
|
1912
|
+
: rb_ca_count_false_ki(0, NULL, mask_obj);
|
|
1913
|
+
}
|
|
1914
|
+
{
|
|
1915
|
+
VALUE kargv[1] = { kw_hash };
|
|
1916
|
+
return masked ? rb_ca_count_true_ki(1, kargv, mask_obj)
|
|
1917
|
+
: rb_ca_count_false_ki(1, kargv, mask_obj);
|
|
1547
1918
|
}
|
|
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
1919
|
}
|
|
1553
1920
|
|
|
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
1921
|
VALUE
|
|
1566
|
-
|
|
1922
|
+
rb_ca_count_masked (int argc, VALUE *argv, VALUE self)
|
|
1567
1923
|
{
|
|
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);
|
|
1924
|
+
return ca_count_by_mask(argc, argv, self, 1);
|
|
1604
1925
|
}
|
|
1605
1926
|
|
|
1606
|
-
/* Ruby binding entry: parses (axis: kwarg) -> forwards to _c. */
|
|
1607
1927
|
VALUE
|
|
1608
1928
|
rb_ca_count_not_masked (int argc, VALUE *argv, VALUE self)
|
|
1609
1929
|
{
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1930
|
+
return ca_count_by_mask(argc, argv, self, 0);
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
/* count_not_masked(axis: axis_val) for C callers. */
|
|
1934
|
+
VALUE
|
|
1935
|
+
rb_ca_count_not_masked_c (VALUE self, VALUE axis_val)
|
|
1936
|
+
{
|
|
1937
|
+
VALUE kw;
|
|
1938
|
+
if ( NIL_P(axis_val) ) {
|
|
1939
|
+
return ca_count_by_mask(0, NULL, self, 0);
|
|
1940
|
+
}
|
|
1941
|
+
kw = rb_hash_new();
|
|
1942
|
+
rb_hash_aset(kw, ID2SYM(rb_intern("axis")), axis_val);
|
|
1943
|
+
return rb_funcall_with_block_kw(self, rb_intern("count_not_masked"), 1, &kw, Qnil, RB_PASS_KEYWORDS);
|
|
1615
1944
|
}
|
|
1616
1945
|
|
|
1617
1946
|
/* ============================================================================
|
|
@@ -1833,6 +2162,43 @@ Init_carray_mask_fast_paths (void)
|
|
|
1833
2162
|
}
|
|
1834
2163
|
|
|
1835
2164
|
|
|
2165
|
+
/* The Ruby forms of inherit_mask take CArray arguments only: refuse a
|
|
2166
|
+
keyword and any argument that is not a CArray, which the C API would
|
|
2167
|
+
pass over as maskless. Returns the arguments without the keyword Hash. */
|
|
2168
|
+
static VALUE
|
|
2169
|
+
ca_inherit_mask_check_args (int argc, VALUE *argv, const char *name)
|
|
2170
|
+
{
|
|
2171
|
+
VALUE rest, ropt;
|
|
2172
|
+
long i;
|
|
2173
|
+
rb_scan_args(argc, argv, "*:", &rest, &ropt);
|
|
2174
|
+
rb_reject_options(ropt);
|
|
2175
|
+
for (i=0; i<RARRAY_LEN(rest); i++) {
|
|
2176
|
+
VALUE v = RARRAY_AREF(rest, i);
|
|
2177
|
+
if ( ! rb_obj_is_carray(v) ) {
|
|
2178
|
+
rb_raise(rb_eTypeError, "%s: argument %ld must be a CArray (got %s)",
|
|
2179
|
+
name, i, rb_obj_classname(v));
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
return rest;
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
static VALUE
|
|
2186
|
+
rb_ca_inherit_mask_ruby (int argc, VALUE *argv, VALUE self)
|
|
2187
|
+
{
|
|
2188
|
+
volatile VALUE rest = ca_inherit_mask_check_args(argc, argv, "inherit_mask");
|
|
2189
|
+
return rb_ca_inherit_mask_method((int) RARRAY_LEN(rest),
|
|
2190
|
+
(VALUE *) RARRAY_CONST_PTR(rest), self);
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
static VALUE
|
|
2194
|
+
rb_ca_inherit_mask_replace_ruby (int argc, VALUE *argv, VALUE self)
|
|
2195
|
+
{
|
|
2196
|
+
volatile VALUE rest = ca_inherit_mask_check_args(argc, argv,
|
|
2197
|
+
"inherit_mask_replace");
|
|
2198
|
+
return rb_ca_inherit_mask_replace_method((int) RARRAY_LEN(rest),
|
|
2199
|
+
(VALUE *) RARRAY_CONST_PTR(rest), self);
|
|
2200
|
+
}
|
|
2201
|
+
|
|
1836
2202
|
void
|
|
1837
2203
|
Init_carray_mask (void)
|
|
1838
2204
|
{
|
|
@@ -1869,9 +2235,9 @@ Init_carray_mask (void)
|
|
|
1869
2235
|
rb_define_method(rb_cCArray, "mask_invalid", rb_ca_mask_invalid, 0);
|
|
1870
2236
|
rb_define_method(rb_cCArray, "mask_where", rb_ca_mask_where, -1);
|
|
1871
2237
|
|
|
1872
|
-
rb_define_method(rb_cCArray, "inherit_mask",
|
|
2238
|
+
rb_define_method(rb_cCArray, "inherit_mask", rb_ca_inherit_mask_ruby, -1);
|
|
1873
2239
|
rb_define_method(rb_cCArray, "inherit_mask_replace",
|
|
1874
|
-
|
|
2240
|
+
rb_ca_inherit_mask_replace_ruby, -1);
|
|
1875
2241
|
|
|
1876
2242
|
rb_define_method(rb_cCArray, "count_masked", rb_ca_count_masked, -1);
|
|
1877
2243
|
rb_define_method(rb_cCArray, "count_not_masked", rb_ca_count_not_masked, -1);
|