carray 3.0.4 → 3.0.6
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 +438 -0
- data/README.md +1 -1
- data/carray.gemspec +3 -2
- data/ext/ca_array_pool.c +25 -1
- data/ext/ca_axis_dispatch.c +19 -20
- data/ext/ca_axis_group.c +1 -1
- data/ext/ca_categorical_iterator.c +34 -27
- data/ext/ca_compare.c +4 -4
- data/ext/ca_composite_dispatch.c +9 -9
- data/ext/ca_kernel_iterator.c +122 -237
- data/ext/ca_kernel_iterator.h +522 -337
- data/ext/ca_obj_array.c +69 -19
- data/ext/ca_obj_bincmp.c +10 -1
- data/ext/ca_obj_binop.c +11 -1
- data/ext/ca_obj_bitarray.c +5 -1
- data/ext/ca_obj_bitfield.c +60 -43
- data/ext/ca_obj_byte_swap.c +4 -1
- data/ext/ca_obj_const_string.c +15 -3
- data/ext/ca_obj_face.c +44 -1
- data/ext/ca_obj_fake.c +3 -1
- data/ext/ca_obj_field.c +13 -3
- data/ext/ca_obj_grid.c +219 -17
- data/ext/ca_obj_meld.c +69 -113
- data/ext/ca_obj_moncmp.c +9 -1
- data/ext/ca_obj_monop.c +86 -12
- data/ext/ca_obj_object.c +118 -32
- data/ext/ca_obj_record.c +3 -0
- data/ext/ca_obj_reduce.c +19 -1
- data/ext/ca_obj_refer.c +80 -26
- data/ext/ca_obj_remap.c +69 -10
- data/ext/ca_obj_roll.c +27 -6
- data/ext/ca_obj_select.c +38 -6
- data/ext/ca_obj_select_axis.c +1 -0
- data/ext/ca_obj_shift.c +32 -7
- data/ext/ca_obj_stack.c +311 -111
- data/ext/ca_obj_stride.c +159 -64
- data/ext/ca_obj_string.c +27 -2
- data/ext/ca_obj_tile.c +28 -7
- data/ext/ca_obj_transpose.c +8 -4
- data/ext/ca_obj_triop.c +12 -1
- data/ext/ca_obj_window.c +80 -50
- data/ext/ca_op_ipower.c +12 -12
- data/ext/ca_sort_kernels.h +6 -3
- data/ext/caframe_csv_reader.c +1 -1
- data/ext/carray.h +35 -1
- data/ext/carray_access.c +43 -67
- data/ext/carray_address_basis.c +134 -0
- data/ext/carray_attribute.c +32 -0
- data/ext/carray_broadcast.c +3 -4
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_cast.c +251 -93
- data/ext/carray_cast_func.rb +56 -26
- data/ext/carray_conversion.c +11 -7
- data/ext/carray_core.c +814 -72
- data/ext/carray_count.c +6 -0
- data/ext/carray_element.c +22 -13
- data/ext/carray_factorize.c +20 -20
- data/ext/carray_generate.c +8 -2
- data/ext/carray_histogram.c +26 -4
- data/ext/carray_index_classifier.c +4 -4
- data/ext/carray_internal.h +159 -12
- data/ext/carray_kernels_bincmp.c +2174 -170
- data/ext/carray_kernels_binop.c +25653 -5487
- data/ext/carray_kernels_init.c +8 -8
- data/ext/carray_kernels_moncmp.c +96 -96
- data/ext/carray_kernels_monop.c +12253 -5235
- data/ext/carray_kernels_reduce_aggregate.c +6150 -2423
- data/ext/carray_kernels_reduce_boolean.c +1533 -15
- data/ext/carray_kernels_reduce_cumulative.c +2442 -882
- data/ext/carray_kernels_reduce_extreme.c +5658 -1661
- data/ext/carray_kernels_reduce_variance.c +2534 -402
- data/ext/carray_kernels_scan.c +368 -368
- data/ext/carray_kernels_search.c +4551 -604
- data/ext/carray_kernels_sort.c +659 -751
- data/ext/carray_kernels_triop.c +114 -114
- data/ext/carray_key_windows.c +4 -0
- data/ext/carray_lazy.c +47 -0
- data/ext/carray_loop.c +1 -1
- data/ext/carray_mask.c +175 -161
- data/ext/carray_median_percentile.c +4 -4
- data/ext/carray_memory_view.c +15 -9
- data/ext/carray_operator.c +152 -49
- data/ext/carray_order.c +230 -10
- data/ext/carray_random.c +22 -19
- data/ext/carray_scatter.c +24 -7
- data/ext/carray_slab.c +128 -29
- data/ext/carray_sort.c +224 -16
- data/ext/carray_sort_kernel.c +5 -7
- data/ext/carray_struct.c +35 -43
- data/ext/carray_test.c +74 -19
- data/ext/carray_time_text.c +6 -4
- data/ext/carray_utils.c +63 -21
- data/ext/extconf.rb +11 -0
- data/ext/mkkernel.rb +546 -199
- data/ext/ruby_carray.c +4 -1
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +42 -5
- data/lib/carray/autoload_carray.rb +3 -3
- data/lib/carray/autoload_method_extension.rb +5 -3
- data/lib/carray/axis_group.rb +13 -7
- data/lib/carray/basics.rb +28 -8
- data/lib/carray/block_iterator.rb +17 -3
- data/lib/carray/categorical.rb +35 -23
- data/lib/carray/categorical_iterator.rb +8 -8
- data/lib/carray/complex.rb +2 -2
- data/lib/carray/conditional.rb +3 -2
- data/lib/carray/const_string.rb +10 -0
- data/lib/carray/data_type_extension.rb +8 -1
- data/lib/carray/fixlen_string.rb +41 -2
- data/lib/carray/frame/column_verbs.rb +48 -16
- data/lib/carray/frame/concat.rb +17 -3
- data/lib/carray/frame/convert.rb +19 -0
- data/lib/carray/frame/csv_parser.rb +32 -32
- data/lib/carray/frame/describe.rb +4 -2
- data/lib/carray/frame/frame.rb +405 -85
- data/lib/carray/frame/group.rb +777 -64
- data/lib/carray/frame/io.rb +212 -72
- data/lib/carray/frame/join.rb +146 -37
- data/lib/carray/frame/records.rb +3 -3
- data/lib/carray/frame/reshape.rb +89 -11
- data/lib/carray/frame/sort.rb +57 -9
- data/lib/carray/frame/verbs.rb +384 -49
- data/lib/carray/frame/windows.rb +44 -6
- data/lib/carray/fuse_source.rb +31 -2
- data/lib/carray/inspect.rb +7 -2
- data/lib/carray/iterator.rb +32 -0
- data/lib/carray/lazy.rb +52 -8
- data/lib/carray/mask_gap_fill.rb +37 -17
- data/lib/carray/meld_reduce.rb +1 -1
- data/lib/carray/methods/choose.rb +3 -2
- data/lib/carray/methods/is_in.rb +8 -1
- data/lib/carray/methods/meshgrid.rb +3 -1
- data/lib/carray/runtime.rb +47 -8
- data/lib/carray/segment_iterator.rb +35 -16
- data/lib/carray/serialize.rb +53 -19
- data/lib/carray/stack.rb +33 -18
- data/lib/carray/string.rb +8 -0
- data/lib/carray/string_operation_extension.rb +13 -5
- data/lib/carray/struct_builder.rb +5 -3
- data/lib/carray/time.rb +112 -68
- data/lib/carray/window_iterator.rb +16 -4
- data/yard-stubs/ca_obj_array.rb +26 -1
- data/yard-stubs/ca_obj_transpose.rb +5 -4
- data/yard-stubs/carray_attribute.rb +3 -1
- data/yard-stubs/carray_cast.rb +10 -5
- data/yard-stubs/carray_conversion.rb +13 -3
- data/yard-stubs/carray_element.rb +7 -6
- data/yard-stubs/carray_mask.rb +28 -4
- data/yard-stubs/carray_math.rb +45 -20
- data/yard-stubs/carray_memory_view.rb +7 -0
- data/yard-stubs/carray_order.rb +100 -4
- data/yard-stubs/carray_scatter.rb +7 -5
- data/yard-stubs/carray_test.rb +7 -4
- metadata +18 -4
data/ext/carray_mask.c
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
#include "carray.h"
|
|
14
14
|
#include "carray_internal.h" /* ca_lazy_arena_* */
|
|
15
15
|
#include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE for the mask-lift path */
|
|
16
|
+
#include <ruby/ractor.h>
|
|
16
17
|
|
|
17
18
|
/* ============================================================================
|
|
18
19
|
* Word-bulk mask substrate helpers.
|
|
@@ -37,16 +38,32 @@
|
|
|
37
38
|
#define CA_MASK_WORD_BYTES 8
|
|
38
39
|
#define CA_MASK_WORD_LSB 0x0101010101010101ULL
|
|
39
40
|
|
|
41
|
+
/* A mask may start at any byte (a window or a block view offsets it), so a
|
|
42
|
+
word is read and written through memcpy, never through a uint64_t
|
|
43
|
+
pointer; the compiler still lowers each to a single load or store. */
|
|
44
|
+
static inline uint64_t
|
|
45
|
+
ca_mask_word_load (const boolean8_t *p)
|
|
46
|
+
{
|
|
47
|
+
uint64_t w;
|
|
48
|
+
memcpy(&w, p, sizeof(w));
|
|
49
|
+
return w;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static inline void
|
|
53
|
+
ca_mask_word_store (boolean8_t *p, uint64_t w)
|
|
54
|
+
{
|
|
55
|
+
memcpy(p, &w, sizeof(w));
|
|
56
|
+
}
|
|
57
|
+
|
|
40
58
|
/* ma[i] |= ms[i] for i in [0, n) -- used by ca_copy_mask_overlay_n */
|
|
41
59
|
static inline void
|
|
42
60
|
ca_mask_word_or (boolean8_t *ma, const boolean8_t *ms, ca_size_t n)
|
|
43
61
|
{
|
|
44
62
|
ca_size_t nw = n / CA_MASK_WORD_BYTES;
|
|
45
63
|
ca_size_t i;
|
|
46
|
-
uint64_t *wa = (uint64_t *) ma;
|
|
47
|
-
const uint64_t *ws = (const uint64_t *) ms;
|
|
48
64
|
for (i = 0; i < nw; i++) {
|
|
49
|
-
|
|
65
|
+
ca_mask_word_store(ma + i*CA_MASK_WORD_BYTES,
|
|
66
|
+
ca_mask_word_load(ma + i*CA_MASK_WORD_BYTES) | ca_mask_word_load(ms + i*CA_MASK_WORD_BYTES));
|
|
50
67
|
}
|
|
51
68
|
for (i = nw * CA_MASK_WORD_BYTES; i < n; i++) {
|
|
52
69
|
ma[i] |= ms[i];
|
|
@@ -62,11 +79,9 @@ ca_mask_word_and (boolean8_t *md,
|
|
|
62
79
|
{
|
|
63
80
|
ca_size_t nw = n / CA_MASK_WORD_BYTES;
|
|
64
81
|
ca_size_t i;
|
|
65
|
-
uint64_t *wd = (uint64_t *) md;
|
|
66
|
-
const uint64_t *wa = (const uint64_t *) ma;
|
|
67
|
-
const uint64_t *wb = (const uint64_t *) mb;
|
|
68
82
|
for (i = 0; i < nw; i++) {
|
|
69
|
-
|
|
83
|
+
ca_mask_word_store(md + i*CA_MASK_WORD_BYTES,
|
|
84
|
+
ca_mask_word_load(ma + i*CA_MASK_WORD_BYTES) & ca_mask_word_load(mb + i*CA_MASK_WORD_BYTES));
|
|
70
85
|
}
|
|
71
86
|
for (i = nw * CA_MASK_WORD_BYTES; i < n; i++) {
|
|
72
87
|
md[i] = ma[i] & mb[i];
|
|
@@ -82,11 +97,9 @@ ca_mask_word_xor (boolean8_t *md,
|
|
|
82
97
|
{
|
|
83
98
|
ca_size_t nw = n / CA_MASK_WORD_BYTES;
|
|
84
99
|
ca_size_t i;
|
|
85
|
-
uint64_t *wd = (uint64_t *) md;
|
|
86
|
-
const uint64_t *wa = (const uint64_t *) ma;
|
|
87
|
-
const uint64_t *wb = (const uint64_t *) mb;
|
|
88
100
|
for (i = 0; i < nw; i++) {
|
|
89
|
-
|
|
101
|
+
ca_mask_word_store(md + i*CA_MASK_WORD_BYTES,
|
|
102
|
+
ca_mask_word_load(ma + i*CA_MASK_WORD_BYTES) ^ ca_mask_word_load(mb + i*CA_MASK_WORD_BYTES));
|
|
90
103
|
}
|
|
91
104
|
for (i = nw * CA_MASK_WORD_BYTES; i < n; i++) {
|
|
92
105
|
md[i] = ma[i] ^ mb[i];
|
|
@@ -99,10 +112,8 @@ ca_mask_word_not (boolean8_t *md, const boolean8_t *ms, ca_size_t n)
|
|
|
99
112
|
{
|
|
100
113
|
ca_size_t nw = n / CA_MASK_WORD_BYTES;
|
|
101
114
|
ca_size_t i;
|
|
102
|
-
uint64_t *wd = (uint64_t *) md;
|
|
103
|
-
const uint64_t *ws = (const uint64_t *) ms;
|
|
104
115
|
for (i = 0; i < nw; i++) {
|
|
105
|
-
|
|
116
|
+
ca_mask_word_store(md + i*CA_MASK_WORD_BYTES, ca_mask_word_load(ms + i*CA_MASK_WORD_BYTES) ^ CA_MASK_WORD_LSB);
|
|
106
117
|
}
|
|
107
118
|
for (i = nw * CA_MASK_WORD_BYTES; i < n; i++) {
|
|
108
119
|
md[i] = ms[i] ^ (boolean8_t) 1;
|
|
@@ -116,9 +127,8 @@ ca_mask_word_any (const boolean8_t *m, ca_size_t n)
|
|
|
116
127
|
{
|
|
117
128
|
ca_size_t nw = n / CA_MASK_WORD_BYTES;
|
|
118
129
|
ca_size_t i;
|
|
119
|
-
const uint64_t *w = (const uint64_t *) m;
|
|
120
130
|
for (i = 0; i < nw; i++) {
|
|
121
|
-
if (
|
|
131
|
+
if ( ca_mask_word_load(m + i*CA_MASK_WORD_BYTES) != 0 ) return 1;
|
|
122
132
|
}
|
|
123
133
|
for (i = nw * CA_MASK_WORD_BYTES; i < n; i++) {
|
|
124
134
|
if ( m[i] ) return 1;
|
|
@@ -134,9 +144,8 @@ ca_mask_word_all_set (const boolean8_t *m, ca_size_t n)
|
|
|
134
144
|
{
|
|
135
145
|
ca_size_t nw = n / CA_MASK_WORD_BYTES;
|
|
136
146
|
ca_size_t i;
|
|
137
|
-
const uint64_t *w = (const uint64_t *) m;
|
|
138
147
|
for (i = 0; i < nw; i++) {
|
|
139
|
-
if (
|
|
148
|
+
if ( ca_mask_word_load(m + i*CA_MASK_WORD_BYTES) != CA_MASK_WORD_LSB ) return 0;
|
|
140
149
|
}
|
|
141
150
|
for (i = nw * CA_MASK_WORD_BYTES; i < n; i++) {
|
|
142
151
|
if ( ! m[i] ) return 0;
|
|
@@ -293,7 +302,13 @@ ca_has_mask (void *ap)
|
|
|
293
302
|
if ( ca->mask ) { /* mask array already created */
|
|
294
303
|
return 1;
|
|
295
304
|
}
|
|
296
|
-
else if (
|
|
305
|
+
else if ( ca_test_flag(ca, CA_FLAG_VALUE_ARRAY) ) {
|
|
306
|
+
/* Only this array's own mark, not ca_is_value_array, which walks to
|
|
307
|
+
the root and would make every level of a view pay again for the
|
|
308
|
+
levels above it. A view below a value array still answers 0: it
|
|
309
|
+
asks its parent, and the question reaches the marked array. No
|
|
310
|
+
level in between has a mask, since ca_create_mask refuses one for
|
|
311
|
+
anything below a value array. */
|
|
297
312
|
return 0; /* array itself is returned by CArray#value */
|
|
298
313
|
}
|
|
299
314
|
else if ( ca_is_entity(ca) ) { /* entity array */
|
|
@@ -308,6 +323,11 @@ ca_has_mask (void *ap)
|
|
|
308
323
|
}
|
|
309
324
|
return 0;
|
|
310
325
|
}
|
|
326
|
+
/* The one level that answers without asking its parent: a value
|
|
327
|
+
array above it has to be looked for here. */
|
|
328
|
+
if ( ca_is_value_array(ca) ) {
|
|
329
|
+
return 0;
|
|
330
|
+
}
|
|
311
331
|
if ( rb_obj_respond_to(co->self, rb_intern("mask_created?"), Qtrue) ) {
|
|
312
332
|
return RTEST(rb_funcall(co->self, rb_intern("mask_created?"), 0));
|
|
313
333
|
}
|
|
@@ -404,6 +424,45 @@ ca_view_func_create_mask (void *ap)
|
|
|
404
424
|
CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
|
|
405
425
|
}
|
|
406
426
|
|
|
427
|
+
/* The sync slot of a view whose mask came from ca_view_func_create_mask
|
|
428
|
+
calls this after syncing its parent. The view's mask is a refer over
|
|
429
|
+
the parent's mask, and when the parent's mask is itself a view, both
|
|
430
|
+
hold a buffer while the window is open; the refer writes past the
|
|
431
|
+
parent's buffer to the root. Syncing the parent then writes its
|
|
432
|
+
buffer, from before the view's mask was written, back over the root,
|
|
433
|
+
so the view's mask is synced once more. */
|
|
434
|
+
|
|
435
|
+
/* The sync slot of a view that maps its cells one to one onto its parent's
|
|
436
|
+
(a fake, a cast, a byte swap, a Face) calls this before syncing its
|
|
437
|
+
parent. The view's mask may have been written past the parent's mask
|
|
438
|
+
buffer, straight to the root (by a view over it), so the parent's
|
|
439
|
+
buffer can still hold the bits from before. The parent's own sync
|
|
440
|
+
decides from that buffer which cells it sends back, so the view's bits
|
|
441
|
+
are copied into it first. */
|
|
442
|
+
|
|
443
|
+
void
|
|
444
|
+
ca_view_pass_mask_to_parent (void *ap)
|
|
445
|
+
{
|
|
446
|
+
CAView *ca = (CAView *) ap;
|
|
447
|
+
if ( ca->mask != NULL && ca->mask->ptr != NULL
|
|
448
|
+
&& ca->parent->mask != NULL && ca->parent->mask->ptr != NULL
|
|
449
|
+
&& ca->mask->ptr != ca->parent->mask->ptr
|
|
450
|
+
&& ca->elements == ca->parent->elements ) {
|
|
451
|
+
memmove(ca->parent->mask->ptr, ca->mask->ptr, (size_t) ca->elements);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
void
|
|
456
|
+
ca_view_sync_mask_after_parent (void *ap)
|
|
457
|
+
{
|
|
458
|
+
CAView *ca = (CAView *) ap;
|
|
459
|
+
if ( ca->mask != NULL && ca->mask->ptr != NULL
|
|
460
|
+
&& ca->parent->mask != NULL && ca->parent->mask->ptr != NULL
|
|
461
|
+
&& ca_is_view(ca->parent->mask) ) {
|
|
462
|
+
ca_sync(ca->mask);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
407
466
|
/* create mask array if array has mask but has not mask array */
|
|
408
467
|
|
|
409
468
|
void
|
|
@@ -433,20 +492,27 @@ ca_mask_standin_new (CArray *parent)
|
|
|
433
492
|
return z;
|
|
434
493
|
}
|
|
435
494
|
|
|
436
|
-
/* A value array or a mask array
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
495
|
+
/* A stack or meld refuses a value array or a mask array as a part: such an
|
|
496
|
+
array can have no mask, and a part of a stack or meld is an array like
|
|
497
|
+
any other, which can. */
|
|
498
|
+
void
|
|
499
|
+
ca_multi_parent_check_part (CArray *part, const char *name)
|
|
440
500
|
{
|
|
441
|
-
|
|
501
|
+
if ( ca_is_value_array(part) ) {
|
|
502
|
+
rb_raise(rb_eArgError,
|
|
503
|
+
"%s: a value array can have no mask and can not be a part", name);
|
|
504
|
+
}
|
|
505
|
+
if ( ca_is_mask_array(part) ) {
|
|
506
|
+
rb_raise(rb_eArgError,
|
|
507
|
+
"%s: a mask array can have no mask and can not be a part", name);
|
|
508
|
+
}
|
|
442
509
|
}
|
|
443
510
|
|
|
444
511
|
CArray *
|
|
445
512
|
ca_mask_standin_current (CArray *mask_view, CArray *reading, CArray *parent,
|
|
446
513
|
CArray *standin)
|
|
447
514
|
{
|
|
448
|
-
if ( standin == NULL || reading != standin
|
|
449
|
-
|| ca_mask_standin_parent_unmaskable(parent) ) {
|
|
515
|
+
if ( standin == NULL || reading != standin ) {
|
|
450
516
|
return reading;
|
|
451
517
|
}
|
|
452
518
|
/* Not inside an attach window whose buffer is out: that buffer and the
|
|
@@ -482,23 +548,21 @@ ca_mask_standin_settle (CArray *parent, CArray *standin)
|
|
|
482
548
|
if ( i == n ) {
|
|
483
549
|
return;
|
|
484
550
|
}
|
|
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
551
|
/* 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.
|
|
552
|
+
parent may have come to have masked cells of its own meanwhile. The
|
|
553
|
+
stand-in is cleared before the parent is asked for a mask, so a
|
|
554
|
+
parent that refuses one leaves it all false, as its readers take it
|
|
555
|
+
to be at rest. */
|
|
493
556
|
addrs = ALLOCV_N(ca_size_t, holder, n);
|
|
494
557
|
for ( ; i < n; i++ ) {
|
|
495
558
|
if ( z[i] ) {
|
|
496
559
|
addrs[m++] = i;
|
|
497
560
|
}
|
|
498
561
|
}
|
|
562
|
+
MEMZERO(z, boolean8_t, n);
|
|
563
|
+
ca_create_mask(parent);
|
|
499
564
|
ca_fill_addrs(parent->mask, m, addrs, &one);
|
|
500
565
|
ALLOCV_END(holder);
|
|
501
|
-
MEMZERO(z, boolean8_t, n);
|
|
502
566
|
}
|
|
503
567
|
|
|
504
568
|
CArray *
|
|
@@ -531,114 +595,37 @@ ca_multi_parent_mask_refresh (CArray *mask, CArray **parents,
|
|
|
531
595
|
CAVIEW(mask)->parent = mp->parents[0];
|
|
532
596
|
}
|
|
533
597
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
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
|
-
|
|
598
|
+
/* Before a write that puts a true into the mask of a stack or meld (not one
|
|
599
|
+
with its buffer out): each part still reading its stand-in that shares
|
|
600
|
+
its root with another part is given its own mask, and the write goes to
|
|
601
|
+
those parts' masks in their order. Parts that share cells then take the
|
|
602
|
+
write of the last of them, as they do for values; through stand-ins,
|
|
603
|
+
settled afterwards, the trues would be added together. A part that
|
|
604
|
+
shares nothing keeps its stand-in, and gets no mask from falses. */
|
|
580
605
|
void
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
VALUE (*body)(VALUE), VALUE arg)
|
|
606
|
+
ca_multi_parent_mask_adopt (CArray *mask, CArray **parents,
|
|
607
|
+
CArray **standins, int32_t n)
|
|
584
608
|
{
|
|
585
609
|
CAMultiParent *mp = (CAMultiParent *) mask;
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
int32_t k, refused = -1;
|
|
589
|
-
if ( standins == NULL ) {
|
|
610
|
+
int32_t k, j;
|
|
611
|
+
if ( standins == NULL || mask->ptr != NULL ) {
|
|
590
612
|
return;
|
|
591
613
|
}
|
|
592
614
|
for ( k = 0; k < n; k++ ) {
|
|
593
|
-
if ( standins[k]
|
|
594
|
-
|
|
595
|
-
|
|
615
|
+
if ( standins[k] == NULL || mp->parents[k] != standins[k]
|
|
616
|
+
|| ca_test_flag(standins[k], CA_FLAG_READ_ONLY) ) {
|
|
617
|
+
continue;
|
|
596
618
|
}
|
|
597
|
-
|
|
598
|
-
|
|
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]) ) {
|
|
619
|
+
for ( j = 0; j < n && ( j == k || ! ca_shares_root(parents[j], parents[k]) ); j++ ) ;
|
|
620
|
+
if ( j == n ) {
|
|
628
621
|
continue;
|
|
629
622
|
}
|
|
630
|
-
|
|
631
|
-
if (
|
|
632
|
-
|
|
623
|
+
ca_create_mask(parents[k]);
|
|
624
|
+
if ( parents[k]->mask != NULL ) {
|
|
625
|
+
mp->parents[k] = parents[k]->mask;
|
|
633
626
|
}
|
|
634
627
|
}
|
|
635
|
-
|
|
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
|
-
}
|
|
628
|
+
CAVIEW(mask)->parent = mp->parents[0];
|
|
642
629
|
}
|
|
643
630
|
|
|
644
631
|
void
|
|
@@ -646,18 +633,12 @@ ca_multi_parent_mask_settle (CArray *mask, CArray **parents,
|
|
|
646
633
|
CArray **standins, int32_t n)
|
|
647
634
|
{
|
|
648
635
|
CAMultiParent *mp = (CAMultiParent *) mask;
|
|
649
|
-
int32_t k
|
|
636
|
+
int32_t k;
|
|
650
637
|
if ( standins == NULL ) {
|
|
651
638
|
return;
|
|
652
639
|
}
|
|
653
|
-
|
|
654
|
-
|
|
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
|
-
}
|
|
640
|
+
for ( k = 0; k < n; k++ ) {
|
|
641
|
+
if ( standins[k] != NULL && mp->parents[k] == standins[k] ) {
|
|
661
642
|
ca_mask_standin_settle(parents[k], standins[k]);
|
|
662
643
|
}
|
|
663
644
|
}
|
|
@@ -789,6 +770,9 @@ typedef struct {
|
|
|
789
770
|
int k; /* entries in list */
|
|
790
771
|
int ns; /* sources */
|
|
791
772
|
ca_size_t elements;
|
|
773
|
+
CArray *dest; /* the destination */
|
|
774
|
+
int overwrite; /* clear the destination's mask first */
|
|
775
|
+
char *modes; /* attach modes, one per entry of list */
|
|
792
776
|
} ca_mask_overlay_t;
|
|
793
777
|
|
|
794
778
|
static VALUE
|
|
@@ -815,6 +799,31 @@ ca_mask_overlay_body (VALUE arg)
|
|
|
815
799
|
return Qnil;
|
|
816
800
|
}
|
|
817
801
|
|
|
802
|
+
/* Clear the destination's mask if asked, and OR the sources into it. */
|
|
803
|
+
static VALUE
|
|
804
|
+
ca_mask_overlay_write (VALUE arg)
|
|
805
|
+
{
|
|
806
|
+
ca_mask_overlay_t *o = (ca_mask_overlay_t *) arg;
|
|
807
|
+
CArray *ca = o->dest;
|
|
808
|
+
int i;
|
|
809
|
+
if ( o->overwrite ) {
|
|
810
|
+
boolean8_t zero = 0;
|
|
811
|
+
ca_fill(ca->mask, &zero);
|
|
812
|
+
}
|
|
813
|
+
o->k = 0;
|
|
814
|
+
o->list[o->k] = ca->mask;
|
|
815
|
+
o->modes[o->k++] = 'w';
|
|
816
|
+
for (i=0; i<o->ns; i++) {
|
|
817
|
+
if ( o->att[i] ) {
|
|
818
|
+
o->list[o->k] = o->att[i];
|
|
819
|
+
o->modes[o->k++] = 'r';
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
o->modes[o->k] = '\0';
|
|
823
|
+
ca_attach_window(o->k, o->list, o->modes, ca_mask_overlay_body, arg);
|
|
824
|
+
return Qnil;
|
|
825
|
+
}
|
|
826
|
+
|
|
818
827
|
/* overwrite: the destination's mask is cleared before the sources are
|
|
819
828
|
OR'd in (and left alone when it has none and no source has a mask). */
|
|
820
829
|
static void
|
|
@@ -899,22 +908,10 @@ ca_copy_mask_overlay_core (CArray *ca, ca_size_t elements, int n,
|
|
|
899
908
|
}
|
|
900
909
|
|
|
901
910
|
ca_create_mask(ca);
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
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';
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
modes[o.k] = '\0';
|
|
917
|
-
ca_attach_window(o.k, o.list, modes, ca_mask_overlay_body, (VALUE) &o);
|
|
911
|
+
o.dest = ca;
|
|
912
|
+
o.overwrite = overwrite;
|
|
913
|
+
o.modes = modes;
|
|
914
|
+
ca_mask_overlay_write((VALUE) &o);
|
|
918
915
|
|
|
919
916
|
for (i=0; i<n; i++) {
|
|
920
917
|
if ( holders[i] ) {
|
|
@@ -1840,7 +1837,9 @@ ca_mask_copy_where (VALUE self, int argc, VALUE *argv)
|
|
|
1840
1837
|
obj = rb_ca_copy(self);
|
|
1841
1838
|
memcpy(all_args, argv, argc * sizeof(VALUE));
|
|
1842
1839
|
all_args[argc] = CA_UNDEF;
|
|
1843
|
-
|
|
1840
|
+
/* a CScalar takes no index; its one-cell view does */
|
|
1841
|
+
rb_funcallv(ca_is_scalar(ca) ? rb_funcall(obj, rb_intern("flatten"), 0) : obj,
|
|
1842
|
+
rb_intern("[]="), argc + 1, all_args);
|
|
1844
1843
|
return obj;
|
|
1845
1844
|
}
|
|
1846
1845
|
|
|
@@ -1872,6 +1871,19 @@ rb_ca_mask_where (int argc, VALUE *argv, VALUE self)
|
|
|
1872
1871
|
return ca_mask_copy_where(self, argc, argv);
|
|
1873
1872
|
}
|
|
1874
1873
|
|
|
1874
|
+
/* inherit_mask's sources are read cell by cell over self, so an array
|
|
1875
|
+
source has self's number of cells (a scalar's one cell applies to all). */
|
|
1876
|
+
static void
|
|
1877
|
+
ca_inherit_mask_check_source (CArray *ca, CArray *cs)
|
|
1878
|
+
{
|
|
1879
|
+
if ( ! ca_is_scalar(cs) && cs->elements != ca->elements ) {
|
|
1880
|
+
rb_raise(rb_eArgError,
|
|
1881
|
+
"%s: mask source has %lld elements, the receiver %lld",
|
|
1882
|
+
ca_calling_method_name(),
|
|
1883
|
+
(long long) cs->elements, (long long) ca->elements);
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1875
1887
|
/* @overload inherit_mask (*others):
|
|
1876
1888
|
|
|
1877
1889
|
(Masking, Destructive)
|
|
@@ -1895,6 +1907,7 @@ rb_ca_inherit_mask_method (int argc, VALUE *argv, VALUE self)
|
|
|
1895
1907
|
for (i=0; i<argc; i++) {
|
|
1896
1908
|
if ( rb_obj_is_carray(argv[i]) ) {
|
|
1897
1909
|
TypedData_Get_Struct(argv[i], CArray, &carray_data_type, cs);
|
|
1910
|
+
ca_inherit_mask_check_source(ca, cs);
|
|
1898
1911
|
slist[i] = cs;
|
|
1899
1912
|
}
|
|
1900
1913
|
else {
|
|
@@ -1938,6 +1951,7 @@ rb_ca_inherit_mask (VALUE self, int n, ...)
|
|
|
1938
1951
|
other = va_arg(rothers, VALUE);
|
|
1939
1952
|
if ( rb_obj_is_carray(other) ) {
|
|
1940
1953
|
TypedData_Get_Struct(other, CArray, &carray_data_type, cs);
|
|
1954
|
+
ca_inherit_mask_check_source(ca, cs);
|
|
1941
1955
|
slist[i] = cs;
|
|
1942
1956
|
}
|
|
1943
1957
|
else {
|
|
@@ -1976,6 +1990,7 @@ rb_ca_inherit_mask_replace_method (int argc, VALUE *argv, VALUE self)
|
|
|
1976
1990
|
for (i=0; i<argc; i++) {
|
|
1977
1991
|
if ( rb_obj_is_carray(argv[i]) ) {
|
|
1978
1992
|
TypedData_Get_Struct(argv[i], CArray, &carray_data_type, cs);
|
|
1993
|
+
ca_inherit_mask_check_source(ca, cs);
|
|
1979
1994
|
slist[i] = cs;
|
|
1980
1995
|
}
|
|
1981
1996
|
else {
|
|
@@ -2019,6 +2034,7 @@ rb_ca_inherit_mask_replace (VALUE self, int n, ...)
|
|
|
2019
2034
|
other = va_arg(rothers, VALUE);
|
|
2020
2035
|
if ( rb_obj_is_carray(other) ) {
|
|
2021
2036
|
TypedData_Get_Struct(other, CArray, &carray_data_type, cs);
|
|
2037
|
+
ca_inherit_mask_check_source(ca, cs);
|
|
2022
2038
|
slist[i] = cs;
|
|
2023
2039
|
}
|
|
2024
2040
|
else {
|
|
@@ -2266,11 +2282,9 @@ ca_binop_bit_or_i_boolean8_fast (ca_size_t n, boolean8_t *m,
|
|
|
2266
2282
|
accumulating; here we need 3-arg). */
|
|
2267
2283
|
ca_size_t nw = n / CA_MASK_WORD_BYTES;
|
|
2268
2284
|
ca_size_t j;
|
|
2269
|
-
uint64_t *wd = (uint64_t *) q3;
|
|
2270
|
-
const uint64_t *wa = (const uint64_t *) q1;
|
|
2271
|
-
const uint64_t *wb = (const uint64_t *) q2;
|
|
2272
2285
|
for (j = 0; j < nw; j++) {
|
|
2273
|
-
|
|
2286
|
+
ca_mask_word_store(q3 + j*CA_MASK_WORD_BYTES,
|
|
2287
|
+
ca_mask_word_load(q1 + j*CA_MASK_WORD_BYTES) | ca_mask_word_load(q2 + j*CA_MASK_WORD_BYTES));
|
|
2274
2288
|
}
|
|
2275
2289
|
for (j = nw * CA_MASK_WORD_BYTES; j < n; j++) {
|
|
2276
2290
|
q3[j] = q1[j] | q2[j];
|
|
@@ -907,10 +907,10 @@ rb_ca_median_m_body (int argc, VALUE *argv, VALUE self)
|
|
|
907
907
|
if ( n == 0 ) return mp_axis_all_masked(self, axis, keep_axis);
|
|
908
908
|
/* mask / min_count / fill_value require the per-fiber select (each fiber
|
|
909
909
|
has its own n_present); the plain partition path assumes a uniform n.
|
|
910
|
-
Switch
|
|
910
|
+
Switch ca_fast_path(CA_SC_MEDIAN_PARTITION): off, the per-fiber select. */
|
|
911
911
|
VALUE res;
|
|
912
912
|
if ( RTEST(rb_ca_has_mask(self)) || min_count > 0 || !NIL_P(fill_value)
|
|
913
|
-
|| !
|
|
913
|
+
|| ! ca_fast_path(CA_SC_MEDIAN_PARTITION) )
|
|
914
914
|
res = is_obj
|
|
915
915
|
? median_object_axis_masked(self, axis, min_count, fill_value, keep_axis)
|
|
916
916
|
: median_axis_masked(self, axis, min_count, fill_value, keep_axis);
|
|
@@ -1364,9 +1364,9 @@ rb_ca_percentile_kw (int argc, VALUE *argv, VALUE ropt, VALUE self)
|
|
|
1364
1364
|
/* mask / min_count / fill_value require the per-fiber select (each fiber
|
|
1365
1365
|
has its own n_present); the plain partition/sort path assumes a
|
|
1366
1366
|
uniform n. These paths bake keep_axis into the reduced output.
|
|
1367
|
-
Switch
|
|
1367
|
+
Switch ca_fast_path(CA_SC_PERCENTILE_PARTITION): off, the per-fiber select. */
|
|
1368
1368
|
int per_fiber = RTEST(rb_ca_has_mask(self)) || min_count > 0
|
|
1369
|
-
|| !NIL_P(fill_value) || !
|
|
1369
|
+
|| !NIL_P(fill_value) || ! ca_fast_path(CA_SC_PERCENTILE_PARTITION);
|
|
1370
1370
|
if ( !is_obj ) {
|
|
1371
1371
|
result = per_fiber
|
|
1372
1372
|
? pct_axis_masked(self, pers, axis, method, min_count, fill_value, keep_axis)
|
data/ext/carray_memory_view.c
CHANGED
|
@@ -202,7 +202,9 @@ ca_mv_record_member_spec (VALUE info, char *out, size_t outlen,
|
|
|
202
202
|
a member it has no item for (see above), or members that overlap or come
|
|
203
203
|
out of offset order (a union).
|
|
204
204
|
|
|
205
|
-
The result is frozen and cached on the data_class.
|
|
205
|
+
The result is frozen and cached on the data_class. Only the main Ractor
|
|
206
|
+
may set an instance variable on a class, so another Ractor builds the
|
|
207
|
+
format each time until the main one has cached it. It is an ordinary
|
|
206
208
|
String that compaction can move, so a view takes a copy of its bytes
|
|
207
209
|
rather than its pointer (ca_mv_get). */
|
|
208
210
|
static VALUE
|
|
@@ -245,11 +247,11 @@ ca_mv_struct_format_for_data_class (VALUE data_class)
|
|
|
245
247
|
}
|
|
246
248
|
|
|
247
249
|
rb_obj_freeze(buf);
|
|
248
|
-
rb_ivar_set(data_class, iv, buf);
|
|
250
|
+
if (ca_in_main_ractor()) rb_ivar_set(data_class, iv, buf);
|
|
249
251
|
return buf;
|
|
250
252
|
|
|
251
253
|
unsupported:
|
|
252
|
-
rb_ivar_set(data_class, iv, Qfalse);
|
|
254
|
+
if (ca_in_main_ractor()) rb_ivar_set(data_class, iv, Qfalse);
|
|
253
255
|
return Qnil;
|
|
254
256
|
}
|
|
255
257
|
|
|
@@ -900,7 +902,7 @@ ca_mv_release (VALUE obj, rb_memory_view_t *view)
|
|
|
900
902
|
}
|
|
901
903
|
|
|
902
904
|
/* ---------------- importer ----------------
|
|
903
|
-
Two-tier API
|
|
905
|
+
Two-tier API:
|
|
904
906
|
|
|
905
907
|
CArray.from_memory_view(obj) -> CArray (copy, independent buffer)
|
|
906
908
|
CArray.wrap_memory_view(obj) -> CAWrap (zero-copy, shared memory)
|
|
@@ -1410,7 +1412,7 @@ ca_mv_wrap_body (VALUE arg)
|
|
|
1410
1412
|
a->target_class);
|
|
1411
1413
|
rb_ivar_set(wrap, rb_intern("memory_view_source"), a->obj);
|
|
1412
1414
|
rb_ivar_set(wrap, rb_intern("memory_view_holder"), a->data_holder_obj);
|
|
1413
|
-
|
|
1415
|
+
GetCArray(wrap, ca);
|
|
1414
1416
|
if ( v->readonly ) {
|
|
1415
1417
|
ca_set_flag(ca, CA_FLAG_READ_ONLY);
|
|
1416
1418
|
}
|
|
@@ -1527,7 +1529,7 @@ ca_mv_from_body (VALUE arg)
|
|
|
1527
1529
|
|
|
1528
1530
|
result = rb_carray_new(data_type, d->ndim, d->dim,
|
|
1529
1531
|
ca_mv_carray_bytes_for(data_type, v->item_size), NULL);
|
|
1530
|
-
|
|
1532
|
+
GetCArray(result, ca);
|
|
1531
1533
|
|
|
1532
1534
|
if ( d->contiguous ) {
|
|
1533
1535
|
memcpy(ca->ptr, v->data, (size_t) ca_length(ca));
|
|
@@ -1621,9 +1623,13 @@ rb_ca_s_memory_view_reject_reason (VALUE klass, VALUE obj)
|
|
|
1621
1623
|
"producer cannot express yet (nested struct, "
|
|
1622
1624
|
"CArray template, :fixlen, or :object)");
|
|
1623
1625
|
}
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1626
|
+
if (ca->data_type == CA_OBJECT) {
|
|
1627
|
+
return rb_str_new_cstr("an object array holds Ruby objects, not bytes "
|
|
1628
|
+
"a consumer can read; convert it with to_type "
|
|
1629
|
+
"first");
|
|
1630
|
+
}
|
|
1631
|
+
return rb_sprintf("data_type %s has no MemoryView format",
|
|
1632
|
+
ca_type_name[ca->data_type]);
|
|
1627
1633
|
}
|
|
1628
1634
|
if (ca_has_mask(ca)) {
|
|
1629
1635
|
return rb_str_new_cstr("array has a mask; use arr.value (mask-ignoring CARefer) "
|