carray 3.0.6 → 3.0.7
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 +110 -0
- data/README.md +24 -3
- data/carray.gemspec +1 -1
- data/ext/ca_axis_group.c +6 -6
- data/ext/ca_binop_dispatch.c +8 -0
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +7 -7
- data/ext/ca_kernel_iterator.h +6 -4
- data/ext/ca_obj_array.c +4 -4
- data/ext/ca_obj_bincmp.c +19 -3
- data/ext/ca_obj_binop.c +36 -11
- data/ext/ca_obj_bitarray.c +2 -4
- data/ext/ca_obj_bitfield.c +86 -4
- data/ext/ca_obj_byte_swap.c +2 -4
- data/ext/ca_obj_const_string.c +422 -257
- data/ext/ca_obj_face.c +71 -33
- data/ext/ca_obj_fake.c +112 -13
- data/ext/ca_obj_farray.c +7 -1
- data/ext/ca_obj_fixlen_string.c +51 -17
- data/ext/ca_obj_grid.c +12 -7
- data/ext/ca_obj_meld.c +5 -5
- data/ext/ca_obj_monop.c +65 -39
- data/ext/ca_obj_object.c +9 -9
- data/ext/ca_obj_reduce.c +2 -4
- data/ext/ca_obj_refer.c +104 -10
- data/ext/ca_obj_repeat.c +1 -1
- data/ext/ca_obj_roll.c +2 -4
- data/ext/ca_obj_select.c +8 -6
- data/ext/ca_obj_select_axis.c +8 -6
- data/ext/ca_obj_stack.c +5 -5
- data/ext/ca_obj_stride.c +46 -8
- data/ext/ca_obj_string.c +2 -2
- data/ext/ca_obj_tile.c +2 -4
- data/ext/ca_obj_triop.c +15 -12
- data/ext/ca_obj_window.c +22 -15
- data/ext/ca_op_ipower.c +63 -15
- data/ext/ca_op_powi.h +6 -29
- data/ext/ca_sort_kernels.h +3 -0
- data/ext/ca_sweep_engine.c +90 -23
- data/ext/ca_sweep_engine.h +5 -6
- data/ext/caframe_csv_reader.c +1 -1
- data/ext/carray.h +3 -1
- data/ext/carray_access.c +98 -39
- data/ext/carray_address_basis.c +98 -24
- data/ext/carray_broadcast.c +2 -2
- data/ext/carray_call_cfunc.c +5 -8
- data/ext/carray_cast.c +311 -37
- data/ext/carray_cast_func.rb +37 -5
- data/ext/carray_conversion.c +56 -2
- data/ext/carray_copy.c +24 -0
- data/ext/carray_core.c +69 -6
- data/ext/carray_count.c +28 -9
- data/ext/carray_element.c +9 -3
- data/ext/carray_factorize.c +11 -11
- data/ext/carray_histogram.c +2 -2
- data/ext/carray_index_classifier.c +7 -5
- data/ext/carray_internal.h +94 -0
- data/ext/carray_kernels_binop.c +55 -55
- data/ext/carray_kernels_init.c +14 -14
- data/ext/carray_kernels_monop.c +90 -140
- data/ext/carray_lazy.c +16 -1
- data/ext/carray_loop.c +9 -2
- data/ext/carray_mask.c +118 -11
- data/ext/carray_median_percentile.c +13 -8
- data/ext/carray_memory_view.c +41 -22
- data/ext/carray_operator.c +72 -11
- data/ext/carray_order.c +52 -9
- data/ext/carray_partition.c +1 -1
- data/ext/carray_random.c +1 -1
- data/ext/carray_round.c +24 -1
- data/ext/carray_scatter.c +4 -0
- data/ext/carray_segment.c +1 -1
- data/ext/carray_slab.c +13 -4
- data/ext/carray_sort.c +6 -3
- data/ext/carray_sort_kernel.c +24 -0
- data/ext/carray_struct.c +21 -6
- data/ext/carray_test.c +85 -39
- data/ext/carray_time_text.c +6 -0
- data/ext/carray_utils.c +124 -54
- data/ext/mk_call_cfunc.rb +6 -11
- data/ext/mkkernel.rb +37 -27
- data/ext/version.h +4 -4
- data/lib/carray/axis_group.rb +9 -6
- data/lib/carray/basics.rb +26 -8
- data/lib/carray/bincount_nd.rb +8 -2
- data/lib/carray/block_iterator.rb +48 -21
- data/lib/carray/categorical.rb +21 -8
- data/lib/carray/categorical_iterator.rb +2 -1
- data/lib/carray/conditional.rb +52 -4
- data/lib/carray/const_string.rb +74 -0
- data/lib/carray/construct.rb +2 -2
- data/lib/carray/core_extensions.rb +19 -68
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/fixlen_string.rb +83 -1
- data/lib/carray/frame/column_verbs.rb +61 -6
- data/lib/carray/frame/concat.rb +50 -6
- data/lib/carray/frame/csv_parser.rb +13 -4
- data/lib/carray/frame/frame.rb +38 -6
- data/lib/carray/frame/group.rb +67 -40
- data/lib/carray/frame/io.rb +10 -5
- data/lib/carray/frame/join.rb +20 -6
- data/lib/carray/frame/records.rb +6 -4
- data/lib/carray/frame/reshape.rb +25 -5
- data/lib/carray/frame/verbs.rb +78 -25
- data/lib/carray/frame/windows.rb +30 -6
- data/lib/carray/fuse_source.rb +4 -2
- data/lib/carray/iterator.rb +8 -0
- data/lib/carray/key_windows.rb +10 -4
- data/lib/carray/lazy.rb +12 -17
- data/lib/carray/methods/bin.rb +3 -0
- data/lib/carray/methods/composition.rb +1 -1
- data/lib/carray/methods/factorize.rb +2 -0
- data/lib/carray/methods/gather_nd.rb +4 -1
- data/lib/carray/methods/is_in.rb +23 -3
- data/lib/carray/methods/locate_addr.rb +63 -12
- data/lib/carray/methods/repeat.rb +11 -1
- data/lib/carray/record_order.rb +35 -6
- data/lib/carray/runtime.rb +10 -0
- data/lib/carray/segment_iterator.rb +19 -16
- data/lib/carray/serialize.rb +22 -0
- data/lib/carray/slab_iterator.rb +1 -1
- data/lib/carray/stack.rb +3 -3
- data/lib/carray/string.rb +6 -6
- data/lib/carray/string_operation_extension.rb +25 -4
- data/lib/carray/struct_builder.rb +4 -1
- data/lib/carray/time.rb +190 -46
- data/lib/carray/window_iterator.rb +48 -12
- data/yard-stubs/ca_obj_bitfield.rb +4 -1
- data/yard-stubs/ca_obj_refer.rb +3 -0
- data/yard-stubs/ca_obj_window.rb +2 -1
- data/yard-stubs/carray_access.rb +4 -2
- data/yard-stubs/carray_cast.rb +6 -0
- data/yard-stubs/carray_count.rb +6 -3
- data/yard-stubs/carray_math.rb +5 -0
- data/yard-stubs/carray_order.rb +6 -0
- data/yard-stubs/carray_scatter.rb +2 -1
- data/yard-stubs/carray_test.rb +18 -5
- metadata +2 -2
data/ext/carray_mask.c
CHANGED
|
@@ -531,11 +531,69 @@ ca_mask_standin_current (CArray *mask_view, CArray *reading, CArray *parent,
|
|
|
531
531
|
return ( parent->mask != NULL ) ? parent->mask : reading;
|
|
532
532
|
}
|
|
533
533
|
|
|
534
|
+
/* The first view from ca up the parent chain whose mask is attached, or
|
|
535
|
+
NULL. An attached mask may alias its root: whether it does is not asked,
|
|
536
|
+
as ca_attach_is_alias answers yes for any view that already has a pointer,
|
|
537
|
+
and the copy made for one that does is a no-op. */
|
|
538
|
+
static CArray *
|
|
539
|
+
ca_mask_buffer_holder (CArray *ca)
|
|
540
|
+
{
|
|
541
|
+
while ( ca != NULL && ca_is_view(ca)
|
|
542
|
+
&& ! ca_test_flag(ca, CA_FLAG_MULTI_PARENTS) ) {
|
|
543
|
+
if ( ca->mask != NULL && ca_is_view(ca->mask)
|
|
544
|
+
&& ca_is_attached(ca->mask) ) {
|
|
545
|
+
return ca;
|
|
546
|
+
}
|
|
547
|
+
ca = CAVIEW(ca)->parent;
|
|
548
|
+
}
|
|
549
|
+
return NULL;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/* Marks the cells addrs of mask, the mask of a view at or below chain. The
|
|
553
|
+
write goes past any buffer an attach window holds on the way to the root,
|
|
554
|
+
and the sync that closes that window sends the buffer: the cells this
|
|
555
|
+
write turned true are copied into it, read as the difference of two
|
|
556
|
+
gathers so that what the window has written there meanwhile stays. */
|
|
557
|
+
static void
|
|
558
|
+
ca_mask_fill_past_buffers (CArray *mask, CArray *chain, ca_size_t m,
|
|
559
|
+
ca_size_t *addrs)
|
|
560
|
+
{
|
|
561
|
+
volatile VALUE holder = 0, reader;
|
|
562
|
+
CArray *owner = ca_mask_buffer_holder(chain);
|
|
563
|
+
CArray *held, *rd;
|
|
564
|
+
boolean8_t *before, *after, *z;
|
|
565
|
+
boolean8_t one = 1;
|
|
566
|
+
ca_size_t i, n;
|
|
567
|
+
|
|
568
|
+
if ( owner == NULL ) {
|
|
569
|
+
ca_fill_addrs(mask, m, addrs, &one);
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
held = owner->mask;
|
|
573
|
+
n = held->elements;
|
|
574
|
+
/* A view answers from its buffer while it has one: the clone has none. */
|
|
575
|
+
rd = (CArray *) ca_clone(held);
|
|
576
|
+
reader = ca_wrap_struct(rd);
|
|
577
|
+
before = ALLOCV_N(boolean8_t, holder, 2 * n);
|
|
578
|
+
after = before + n;
|
|
579
|
+
ca_xfer_all(rd, before, CA_XFER_GET);
|
|
580
|
+
ca_mask_fill_past_buffers(mask, CAVIEW(owner)->parent, m, addrs);
|
|
581
|
+
ca_xfer_all(rd, after, CA_XFER_GET);
|
|
582
|
+
z = (boolean8_t *) held->ptr;
|
|
583
|
+
for ( i = 0; i < n; i++ ) {
|
|
584
|
+
if ( after[i] && ! before[i] ) {
|
|
585
|
+
z[i] = 1;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
ALLOCV_END(holder);
|
|
589
|
+
RB_GC_GUARD(reader);
|
|
590
|
+
}
|
|
591
|
+
|
|
534
592
|
void
|
|
535
593
|
ca_mask_standin_settle (CArray *parent, CArray *standin)
|
|
536
594
|
{
|
|
537
595
|
volatile VALUE holder = 0;
|
|
538
|
-
boolean8_t *z
|
|
596
|
+
boolean8_t *z;
|
|
539
597
|
ca_size_t *addrs;
|
|
540
598
|
ca_size_t i, m = 0, n;
|
|
541
599
|
|
|
@@ -561,7 +619,7 @@ ca_mask_standin_settle (CArray *parent, CArray *standin)
|
|
|
561
619
|
}
|
|
562
620
|
MEMZERO(z, boolean8_t, n);
|
|
563
621
|
ca_create_mask(parent);
|
|
564
|
-
|
|
622
|
+
ca_mask_fill_past_buffers(parent->mask, parent, m, addrs);
|
|
565
623
|
ALLOCV_END(holder);
|
|
566
624
|
}
|
|
567
625
|
|
|
@@ -628,20 +686,52 @@ ca_multi_parent_mask_adopt (CArray *mask, CArray **parents,
|
|
|
628
686
|
CAVIEW(mask)->parent = mp->parents[0];
|
|
629
687
|
}
|
|
630
688
|
|
|
689
|
+
typedef struct {
|
|
690
|
+
CArray *parent;
|
|
691
|
+
CArray *standin;
|
|
692
|
+
} ca_standin_settle_arg;
|
|
693
|
+
|
|
694
|
+
static VALUE
|
|
695
|
+
ca_standin_settle_body (VALUE arg)
|
|
696
|
+
{
|
|
697
|
+
ca_standin_settle_arg *a = (ca_standin_settle_arg *) arg;
|
|
698
|
+
ca_mask_standin_settle(a->parent, a->standin);
|
|
699
|
+
return Qnil;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/* Every part is settled, past a parent that refuses a mask, so no part keeps
|
|
703
|
+
a true in its stand-in; then the first exception is raised. */
|
|
631
704
|
void
|
|
632
705
|
ca_multi_parent_mask_settle (CArray *mask, CArray **parents,
|
|
633
706
|
CArray **standins, int32_t n)
|
|
634
707
|
{
|
|
635
708
|
CAMultiParent *mp = (CAMultiParent *) mask;
|
|
709
|
+
volatile VALUE error = Qnil;
|
|
636
710
|
int32_t k;
|
|
637
711
|
if ( standins == NULL ) {
|
|
638
712
|
return;
|
|
639
713
|
}
|
|
640
714
|
for ( k = 0; k < n; k++ ) {
|
|
641
715
|
if ( standins[k] != NULL && mp->parents[k] == standins[k] ) {
|
|
642
|
-
|
|
716
|
+
ca_standin_settle_arg a = { parents[k], standins[k] };
|
|
717
|
+
int tag = 0;
|
|
718
|
+
/* protect: goes on to the other parts; nothing to give back */
|
|
719
|
+
rb_protect(ca_standin_settle_body, (VALUE) &a, &tag);
|
|
720
|
+
if ( tag ) {
|
|
721
|
+
VALUE err = rb_errinfo();
|
|
722
|
+
if ( ! RTEST(rb_obj_is_kind_of(err, rb_eException)) ) {
|
|
723
|
+
rb_jump_tag(tag);
|
|
724
|
+
}
|
|
725
|
+
if ( NIL_P(error) ) {
|
|
726
|
+
error = err;
|
|
727
|
+
}
|
|
728
|
+
rb_set_errinfo(Qnil);
|
|
729
|
+
}
|
|
643
730
|
}
|
|
644
731
|
}
|
|
732
|
+
if ( ! NIL_P(error) ) {
|
|
733
|
+
rb_exc_raise(error);
|
|
734
|
+
}
|
|
645
735
|
}
|
|
646
736
|
|
|
647
737
|
void
|
|
@@ -1934,7 +2024,7 @@ rb_ca_inherit_mask_n (VALUE self, int n, VALUE *rothers)
|
|
|
1934
2024
|
VALUE
|
|
1935
2025
|
rb_ca_inherit_mask (VALUE self, int n, ...)
|
|
1936
2026
|
{
|
|
1937
|
-
VALUE other;
|
|
2027
|
+
volatile VALUE other;
|
|
1938
2028
|
CArray **slist;
|
|
1939
2029
|
volatile VALUE holder;
|
|
1940
2030
|
CArray *ca, *cs;
|
|
@@ -2017,7 +2107,7 @@ rb_ca_inherit_mask_replace_n (VALUE self, int n, VALUE *rothers)
|
|
|
2017
2107
|
VALUE
|
|
2018
2108
|
rb_ca_inherit_mask_replace (VALUE self, int n, ...)
|
|
2019
2109
|
{
|
|
2020
|
-
VALUE other;
|
|
2110
|
+
volatile VALUE other;
|
|
2021
2111
|
CArray **slist;
|
|
2022
2112
|
volatile VALUE holder;
|
|
2023
2113
|
CArray *ca, *cs;
|
|
@@ -2253,6 +2343,20 @@ ca_binop_bit_and_i_boolean8_fast (ca_size_t n, boolean8_t *m,
|
|
|
2253
2343
|
}
|
|
2254
2344
|
|
|
2255
2345
|
/* ----- bit_or_i (boolean8_t fast) ----- */
|
|
2346
|
+
/* Every cell gets 0 or 1, even beside a masked cell: its byte is not
|
|
2347
|
+
defined (any value), and a cell Kleene resolves to true keeps the value
|
|
2348
|
+
written here. The word path folds each byte's eight bits into its low
|
|
2349
|
+
bit; a shift by less than 8 moves bits of the next byte only into the
|
|
2350
|
+
high bits, which the last mask drops. */
|
|
2351
|
+
static inline uint64_t
|
|
2352
|
+
ca_mask_word_nonzero_bytes (uint64_t w)
|
|
2353
|
+
{
|
|
2354
|
+
w |= w >> 4;
|
|
2355
|
+
w |= w >> 2;
|
|
2356
|
+
w |= w >> 1;
|
|
2357
|
+
return w & CA_MASK_WORD_LSB;
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2256
2360
|
static void
|
|
2257
2361
|
ca_binop_bit_or_i_boolean8_fast (ca_size_t n, boolean8_t *m,
|
|
2258
2362
|
char *ptr1, ca_size_t i1,
|
|
@@ -2273,7 +2377,7 @@ ca_binop_bit_or_i_boolean8_fast (ca_size_t n, boolean8_t *m,
|
|
|
2273
2377
|
p1 = q1 + k*i1;
|
|
2274
2378
|
p2 = q2 + k*i2;
|
|
2275
2379
|
p3 = q3 + k*i3;
|
|
2276
|
-
(*p3) = (*p1) | (*p2);
|
|
2380
|
+
(*p3) = ( (*p1) | (*p2) ) ? 1 : 0;
|
|
2277
2381
|
}
|
|
2278
2382
|
}
|
|
2279
2383
|
}
|
|
@@ -2284,18 +2388,21 @@ ca_binop_bit_or_i_boolean8_fast (ca_size_t n, boolean8_t *m,
|
|
|
2284
2388
|
ca_size_t j;
|
|
2285
2389
|
for (j = 0; j < nw; j++) {
|
|
2286
2390
|
ca_mask_word_store(q3 + j*CA_MASK_WORD_BYTES,
|
|
2287
|
-
|
|
2391
|
+
ca_mask_word_nonzero_bytes(
|
|
2392
|
+
ca_mask_word_load(q1 + j*CA_MASK_WORD_BYTES) |
|
|
2393
|
+
ca_mask_word_load(q2 + j*CA_MASK_WORD_BYTES)));
|
|
2288
2394
|
}
|
|
2289
2395
|
for (j = nw * CA_MASK_WORD_BYTES; j < n; j++) {
|
|
2290
|
-
q3[j] = q1[j] | q2[j];
|
|
2396
|
+
q3[j] = ( q1[j] | q2[j] ) ? 1 : 0;
|
|
2291
2397
|
}
|
|
2292
2398
|
}
|
|
2293
2399
|
else {
|
|
2400
|
+
/* non-contig view: byte loop */
|
|
2294
2401
|
for (k = 0; k < n; k++) {
|
|
2295
2402
|
p1 = q1 + k*i1;
|
|
2296
2403
|
p2 = q2 + k*i2;
|
|
2297
2404
|
p3 = q3 + k*i3;
|
|
2298
|
-
(*p3) = (*p1) | (*p2);
|
|
2405
|
+
(*p3) = ( (*p1) | (*p2) ) ? 1 : 0;
|
|
2299
2406
|
}
|
|
2300
2407
|
}
|
|
2301
2408
|
}
|
|
@@ -2407,8 +2514,8 @@ ca_inherit_mask_check_args (int argc, VALUE *argv, const char *name)
|
|
|
2407
2514
|
for (i=0; i<RARRAY_LEN(rest); i++) {
|
|
2408
2515
|
VALUE v = RARRAY_AREF(rest, i);
|
|
2409
2516
|
if ( ! rb_obj_is_carray(v) ) {
|
|
2410
|
-
rb_raise(rb_eTypeError, "%s: argument %ld must be a CArray (got %
|
|
2411
|
-
name, i,
|
|
2517
|
+
rb_raise(rb_eTypeError, "%s: argument %ld must be a CArray (got %"PRIsVALUE")",
|
|
2518
|
+
name, i, rb_obj_class(v));
|
|
2412
2519
|
}
|
|
2413
2520
|
}
|
|
2414
2521
|
return rest;
|
|
@@ -138,10 +138,11 @@ mp_keep_axis_full_f64 (VALUE self, double v, int is_undef)
|
|
|
138
138
|
/* [shared] all-UNDEF reduced CA_FLOAT64 output for a zero-length reduction
|
|
139
139
|
axis. An order statistic of no elements has no value, so every reduced
|
|
140
140
|
cell is masked -- matching mean / min (which return UNDEF cells), not a
|
|
141
|
-
raise
|
|
142
|
-
|
|
141
|
+
raise, unless fill_value (nil for none) gives the cells a value, as it
|
|
142
|
+
does for a fiber with no present cell. keep_axis controls whether the
|
|
143
|
+
reduced axis is dropped or kept as a length-1 axis. */
|
|
143
144
|
static VALUE
|
|
144
|
-
mp_axis_all_masked (VALUE self, long axis, int keep_axis)
|
|
145
|
+
mp_axis_all_masked (VALUE self, long axis, VALUE fill_value, int keep_axis)
|
|
145
146
|
{
|
|
146
147
|
int8_t ax = (int8_t) axis;
|
|
147
148
|
CArray *ca;
|
|
@@ -150,6 +151,10 @@ mp_axis_all_masked (VALUE self, long axis, int keep_axis)
|
|
|
150
151
|
(ca->data_type == CA_OBJECT) ? CA_OBJECT
|
|
151
152
|
: CA_FLOAT64,
|
|
152
153
|
keep_axis);
|
|
154
|
+
if ( ! NIL_P(fill_value) ) {
|
|
155
|
+
rb_ca_store_all(out, fill_value);
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
153
158
|
CArray *co;
|
|
154
159
|
GetCArray(out, co);
|
|
155
160
|
ca_create_mask(co);
|
|
@@ -680,7 +685,7 @@ percentile_object_axis (VALUE self, VALUE pers, long axis, VALUE method)
|
|
|
680
685
|
is applied by the entry (rb_ca_percentile_m), so build reduced. */
|
|
681
686
|
VALUE res = rb_ary_new_capa(npers);
|
|
682
687
|
for ( long i = 0; i < npers; i++ )
|
|
683
|
-
rb_ary_push(res, mp_axis_all_masked(self, axis, 0));
|
|
688
|
+
rb_ary_push(res, mp_axis_all_masked(self, axis, Qnil, 0));
|
|
684
689
|
return res;
|
|
685
690
|
}
|
|
686
691
|
|
|
@@ -774,7 +779,7 @@ percentile_object_axis_masked (VALUE self, VALUE pers, long axis, VALUE method,
|
|
|
774
779
|
if ( M == 0 ) {
|
|
775
780
|
VALUE res = rb_ary_new_capa(npers);
|
|
776
781
|
for ( long i = 0; i < npers; i++ )
|
|
777
|
-
rb_ary_push(res, mp_axis_all_masked(self, axis, keep_axis));
|
|
782
|
+
rb_ary_push(res, mp_axis_all_masked(self, axis, fill_value, keep_axis));
|
|
778
783
|
return res;
|
|
779
784
|
}
|
|
780
785
|
|
|
@@ -904,7 +909,7 @@ rb_ca_median_m_body (int argc, VALUE *argv, VALUE self)
|
|
|
904
909
|
if ( !NIL_P(raxis) ) {
|
|
905
910
|
long axis = rb_ca_normalize_axis_value(self, raxis, "median");
|
|
906
911
|
long n = (long) ca->dim[axis];
|
|
907
|
-
if ( n == 0 ) return mp_axis_all_masked(self, axis, keep_axis);
|
|
912
|
+
if ( n == 0 ) return mp_axis_all_masked(self, axis, fill_value, keep_axis);
|
|
908
913
|
/* mask / min_count / fill_value require the per-fiber select (each fiber
|
|
909
914
|
has its own n_present); the plain partition path assumes a uniform n.
|
|
910
915
|
Switch ca_fast_path(CA_SC_MEDIAN_PARTITION): off, the per-fiber select. */
|
|
@@ -1138,7 +1143,7 @@ pct_axis (VALUE self, VALUE pers_ary, long axis, VALUE method, int keep_axis)
|
|
|
1138
1143
|
/* zero-length axis: every requested p reduces to an all-UNDEF cell. */
|
|
1139
1144
|
VALUE res = rb_ary_new_capa(npers);
|
|
1140
1145
|
for ( long i = 0; i < npers; i++ )
|
|
1141
|
-
rb_ary_push(res, mp_axis_all_masked(self, axis, keep_axis));
|
|
1146
|
+
rb_ary_push(res, mp_axis_all_masked(self, axis, Qnil, keep_axis));
|
|
1142
1147
|
return res;
|
|
1143
1148
|
}
|
|
1144
1149
|
|
|
@@ -1167,7 +1172,7 @@ pct_axis_masked (VALUE self, VALUE pers_ary, long axis, VALUE method,
|
|
|
1167
1172
|
if ( M == 0 ) {
|
|
1168
1173
|
VALUE res = rb_ary_new_capa(npers);
|
|
1169
1174
|
for ( long i = 0; i < npers; i++ )
|
|
1170
|
-
rb_ary_push(res, mp_axis_all_masked(self, axis, keep_axis));
|
|
1175
|
+
rb_ary_push(res, mp_axis_all_masked(self, axis, fill_value, keep_axis));
|
|
1171
1176
|
return res;
|
|
1172
1177
|
}
|
|
1173
1178
|
|
data/ext/carray_memory_view.c
CHANGED
|
@@ -449,6 +449,22 @@ ca_mv_probe_data_type (VALUE obj)
|
|
|
449
449
|
return data_type;
|
|
450
450
|
}
|
|
451
451
|
|
|
452
|
+
/* True when format is a struct of several members that exactly describes an
|
|
453
|
+
item of item_size bytes. A consumer takes such items as raw bytes: the
|
|
454
|
+
format names no members to rebuild a record from. */
|
|
455
|
+
static bool
|
|
456
|
+
ca_mv_format_is_struct (const char *format, ssize_t item_size)
|
|
457
|
+
{
|
|
458
|
+
rb_memory_view_item_component_t *members = NULL;
|
|
459
|
+
size_t n_members = 0;
|
|
460
|
+
const char *err = NULL;
|
|
461
|
+
ssize_t size;
|
|
462
|
+
if ( format == NULL ) return false;
|
|
463
|
+
size = rb_memory_view_parse_item_format(format, &members, &n_members, &err);
|
|
464
|
+
if ( members != NULL ) xfree(members);
|
|
465
|
+
return size == item_size && n_members >= 2;
|
|
466
|
+
}
|
|
467
|
+
|
|
452
468
|
/* Per-element byte width for consumer-side wrap/from CArray allocation.
|
|
453
469
|
For numeric types it is `ca_sizeof[data_type]`; for CA_FIXLEN it is the
|
|
454
470
|
MemoryView item_size, since fixlen has no compile-time element width. */
|
|
@@ -511,7 +527,7 @@ ca_mv_alloc_strides_contiguous (CArray *ca, ssize_t *shape, bool row_major)
|
|
|
511
527
|
|
|
512
528
|
typedef struct {
|
|
513
529
|
int depth; /* 0 = the view itself, 1 = parent, 2 = grand-, ... */
|
|
514
|
-
|
|
530
|
+
VALUE klass; /* class of the offending link (nil: unknown) */
|
|
515
531
|
const char *reason; /* short explanation */
|
|
516
532
|
int face; /* refused because it is a Face: a copy is
|
|
517
533
|
refused too, so no copy is suggested */
|
|
@@ -528,11 +544,10 @@ ca_mv_is_castride_family (CArray *ca)
|
|
|
528
544
|
return ca_func[ca->obj_type].attach == ca_stride_func.attach;
|
|
529
545
|
}
|
|
530
546
|
|
|
531
|
-
static
|
|
532
|
-
|
|
547
|
+
static VALUE
|
|
548
|
+
ca_mv_class_of (CArray *ca)
|
|
533
549
|
{
|
|
534
|
-
|
|
535
|
-
return NIL_P(klass) ? "(unknown)" : rb_class2name(klass);
|
|
550
|
+
return ca_class[ca->obj_type];
|
|
536
551
|
}
|
|
537
552
|
|
|
538
553
|
static const char *
|
|
@@ -597,7 +612,7 @@ ca_mv_compose_to_entity (CArray *ca, ca_mv_reject_t *rej,
|
|
|
597
612
|
if (ca_is_face(ca)) {
|
|
598
613
|
if (! ca_face_memory_view_exportable(ca)) {
|
|
599
614
|
rej->depth = 0;
|
|
600
|
-
rej->
|
|
615
|
+
rej->klass = ca_mv_class_of(ca);
|
|
601
616
|
rej->reason = "a Face whose storage bytes do not carry its values "
|
|
602
617
|
"without the Face; export its storage instead "
|
|
603
618
|
"(e.g. .ticks, .codes)";
|
|
@@ -609,7 +624,7 @@ ca_mv_compose_to_entity (CArray *ca, ca_mv_reject_t *rej,
|
|
|
609
624
|
if (ca_is_entity(ca)) {
|
|
610
625
|
if (! ca_mv_is_core_entity(ca)) {
|
|
611
626
|
rej->depth = 0;
|
|
612
|
-
rej->
|
|
627
|
+
rej->klass = ca_mv_class_of(ca);
|
|
613
628
|
rej->reason = "installed outside the core; its bytes are not "
|
|
614
629
|
"exported";
|
|
615
630
|
return false;
|
|
@@ -620,7 +635,7 @@ ca_mv_compose_to_entity (CArray *ca, ca_mv_reject_t *rej,
|
|
|
620
635
|
}
|
|
621
636
|
if (!ca_mv_is_castride_family(ca)) {
|
|
622
637
|
rej->depth = 0;
|
|
623
|
-
rej->
|
|
638
|
+
rej->klass = ca_mv_class_of(ca);
|
|
624
639
|
rej->reason = ca_mv_reject_reason_for(ca);
|
|
625
640
|
return false;
|
|
626
641
|
}
|
|
@@ -628,7 +643,7 @@ ca_mv_compose_to_entity (CArray *ca, ca_mv_reject_t *rej,
|
|
|
628
643
|
ca_stride_compose_to_root((CAStride *) ca, &root, out_strides, out_base);
|
|
629
644
|
if (!ca_is_entity(root)) {
|
|
630
645
|
rej->depth = -1;
|
|
631
|
-
rej->
|
|
646
|
+
rej->klass = ca_mv_class_of(root);
|
|
632
647
|
if (ca_mv_is_castride_family(root)) {
|
|
633
648
|
rej->reason = "CAStride chain stride pattern does not compose "
|
|
634
649
|
"linearly into entity (e.g. reshape across non-contig)";
|
|
@@ -639,7 +654,7 @@ ca_mv_compose_to_entity (CArray *ca, ca_mv_reject_t *rej,
|
|
|
639
654
|
}
|
|
640
655
|
if (! ca_mv_is_core_entity(root)) {
|
|
641
656
|
rej->depth = -1;
|
|
642
|
-
rej->
|
|
657
|
+
rej->klass = ca_mv_class_of(root);
|
|
643
658
|
rej->reason = "installed outside the core; its bytes are not exported";
|
|
644
659
|
return false;
|
|
645
660
|
}
|
|
@@ -704,7 +719,7 @@ ca_mv_fixlen_format (ca_size_t bytes)
|
|
|
704
719
|
{
|
|
705
720
|
st_data_t found;
|
|
706
721
|
char *fmt;
|
|
707
|
-
|
|
722
|
+
ca_native_lock_without_gvl(&ca_mv_fixlen_formats_lock);
|
|
708
723
|
if ( st_lookup(ca_mv_fixlen_formats, (st_data_t) bytes, &found) ) {
|
|
709
724
|
rb_nativethread_lock_unlock(&ca_mv_fixlen_formats_lock);
|
|
710
725
|
return (const char *) found;
|
|
@@ -712,7 +727,8 @@ ca_mv_fixlen_format (ca_size_t bytes)
|
|
|
712
727
|
rb_nativethread_lock_unlock(&ca_mv_fixlen_formats_lock);
|
|
713
728
|
fmt = ALLOC_N(char, 24);
|
|
714
729
|
snprintf(fmt, 24, "%llds", (long long) bytes);
|
|
715
|
-
|
|
730
|
+
/* lock: st_insert can run a GC, which does not take this lock */
|
|
731
|
+
ca_native_lock_without_gvl(&ca_mv_fixlen_formats_lock);
|
|
716
732
|
if ( st_lookup(ca_mv_fixlen_formats, (st_data_t) bytes, &found) ) {
|
|
717
733
|
xfree(fmt);
|
|
718
734
|
fmt = (char *) found;
|
|
@@ -1171,6 +1187,9 @@ ca_mv_holder_take_data (ca_mv_imported_holder_t *h, VALUE src,
|
|
|
1171
1187
|
}
|
|
1172
1188
|
|
|
1173
1189
|
data_type = ca_mv_data_type_from_format(v->format, v->item_size);
|
|
1190
|
+
if ( data_type < 0 && ca_mv_format_is_struct(v->format, v->item_size) ) {
|
|
1191
|
+
data_type = CA_FIXLEN;
|
|
1192
|
+
}
|
|
1174
1193
|
if ( data_type < 0 ) {
|
|
1175
1194
|
rb_raise(rb_eArgError, "unsupported MemoryView format: %s (item_size=%ld)",
|
|
1176
1195
|
v->format, (long) v->item_size);
|
|
@@ -1344,10 +1363,10 @@ ca_mv_wrap_body (VALUE arg)
|
|
|
1344
1363
|
for a class would get something that is not it. */
|
|
1345
1364
|
if ( a->target_class != rb_cCAWrap && ! d->contiguous ) {
|
|
1346
1365
|
rb_raise(rb_eArgError,
|
|
1347
|
-
"%
|
|
1366
|
+
"%"PRIsVALUE" was requested, but this producer is strided, so the result "
|
|
1348
1367
|
"would be a CAStride; pass a row-major contiguous producer, or "
|
|
1349
1368
|
"use CArray.from_memory_view for a copy",
|
|
1350
|
-
|
|
1369
|
+
a->target_class);
|
|
1351
1370
|
}
|
|
1352
1371
|
|
|
1353
1372
|
if ( m != NULL ) {
|
|
@@ -1503,8 +1522,8 @@ rb_ca_s_wrap_memory_view (int argc, VALUE *argv, VALUE klass)
|
|
|
1503
1522
|
target_class = ( klass == rb_cCArray ) ? rb_cCAWrap : klass;
|
|
1504
1523
|
if ( ! RTEST(rb_class_inherited_p(target_class, rb_cCAWrap)) ) {
|
|
1505
1524
|
rb_raise(rb_eTypeError,
|
|
1506
|
-
"wrap_memory_view builds a CAWrap; %
|
|
1507
|
-
|
|
1525
|
+
"wrap_memory_view builds a CAWrap; %"PRIsVALUE" is not a subclass of it",
|
|
1526
|
+
target_class);
|
|
1508
1527
|
}
|
|
1509
1528
|
return ca_mv_wrap(obj, mask_obj, target_class, explicit_data_type, -1, 0);
|
|
1510
1529
|
}
|
|
@@ -1585,8 +1604,8 @@ rb_ca_s_from_memory_view (int argc, VALUE *argv, VALUE klass)
|
|
|
1585
1604
|
if ( klass != rb_cCArray &&
|
|
1586
1605
|
! RTEST(rb_class_inherited_p(klass, rb_cCAWrap)) ) {
|
|
1587
1606
|
rb_raise(rb_eTypeError,
|
|
1588
|
-
"from_memory_view builds a CArray; %
|
|
1589
|
-
|
|
1607
|
+
"from_memory_view builds a CArray; %"PRIsVALUE" cannot be returned from it",
|
|
1608
|
+
klass);
|
|
1590
1609
|
}
|
|
1591
1610
|
ca_mv_import_args_init(&a, obj, mask_obj);
|
|
1592
1611
|
a.explicit_data_type = explicit_data_type;
|
|
@@ -1642,12 +1661,12 @@ rb_ca_s_memory_view_reject_reason (VALUE klass, VALUE obj)
|
|
|
1642
1661
|
else if (rej.depth == 1) where = "parent";
|
|
1643
1662
|
else where = NULL; /* ancestor[N] */
|
|
1644
1663
|
if (where) {
|
|
1645
|
-
return rb_sprintf("%s is %
|
|
1646
|
-
where, rej.
|
|
1664
|
+
return rb_sprintf("%s is %"PRIsVALUE" (%s); zero-copy wrap not possible.%s",
|
|
1665
|
+
where, NIL_P(rej.klass) ? rb_str_new_cstr("(unknown)") : rej.klass, rej.reason,
|
|
1647
1666
|
rej.face ? "" : " Export arr.copy for a snapshot.");
|
|
1648
1667
|
} else {
|
|
1649
|
-
return rb_sprintf("ancestor[%d] is %
|
|
1650
|
-
rej.depth - 1, rej.
|
|
1668
|
+
return rb_sprintf("ancestor[%d] is %"PRIsVALUE" (%s); zero-copy wrap not possible.%s",
|
|
1669
|
+
rej.depth - 1, NIL_P(rej.klass) ? rb_str_new_cstr("(unknown)") : rej.klass, rej.reason,
|
|
1651
1670
|
rej.face ? "" : " Export arr.copy for a snapshot.");
|
|
1652
1671
|
}
|
|
1653
1672
|
}
|
data/ext/carray_operator.c
CHANGED
|
@@ -1272,7 +1272,7 @@ VALUE
|
|
|
1272
1272
|
rb_ca_call_binop (volatile VALUE self, volatile VALUE other,
|
|
1273
1273
|
ca_binop_func_t func[])
|
|
1274
1274
|
{
|
|
1275
|
-
volatile VALUE out;
|
|
1275
|
+
volatile VALUE out, receiver;
|
|
1276
1276
|
CArray *ca1, *ca2, *ca3; /* ca3 = ca1.op(ca2) */
|
|
1277
1277
|
int self_is_scalar, other_is_scalar;
|
|
1278
1278
|
ca_size_t n_kernel;
|
|
@@ -1282,12 +1282,43 @@ rb_ca_call_binop (volatile VALUE self, volatile VALUE other,
|
|
|
1282
1282
|
ca_binop_read_boolean_as_truth(func[CA_BOOLEAN] != ca_binop_not_implement,
|
|
1283
1283
|
&self, &other);
|
|
1284
1284
|
|
|
1285
|
+
receiver = rb_obj_is_carray(other) ? Qnil : self;
|
|
1286
|
+
|
|
1287
|
+
/* pmax and its kin pick by order, so a value the array can not hold is
|
|
1288
|
+
refused as an ordering refuses it. */
|
|
1289
|
+
if ( ! rb_obj_is_carray(other) && rb_obj_is_carray(self) &&
|
|
1290
|
+
ca_binop_picks_by_order(ca_binop_op_id_of_table(func)) ) {
|
|
1291
|
+
CArray *cs;
|
|
1292
|
+
GetCArray(self, cs);
|
|
1293
|
+
/* a boolean array picks as its 0 / 1 int64 numbers */
|
|
1294
|
+
if ( func[cs->data_type == CA_BOOLEAN ? CA_INT64 : cs->data_type]
|
|
1295
|
+
!= ca_binop_not_implement ) {
|
|
1296
|
+
ca_refuse_foreign_order(other, self);
|
|
1297
|
+
}
|
|
1298
|
+
else {
|
|
1299
|
+
/* an array the op is not defined for says so, whatever the operand */
|
|
1300
|
+
ca_op_refuse_unimplemented(self, cs->data_type, rb_eCADataTypeError);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1285
1304
|
/* do implicit casting */
|
|
1286
1305
|
rb_ca_cast_self_or_other(&self, &other);
|
|
1287
1306
|
|
|
1288
1307
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca1);
|
|
1289
1308
|
TypedData_Get_Struct(other, CArray, &carray_data_type, ca2);
|
|
1290
1309
|
|
|
1310
|
+
/* A Face whose cells are not Ruby values does not go down to an object
|
|
1311
|
+
array to meet a single Ruby object: an operator it does not define for
|
|
1312
|
+
an array of its own stays undefined. */
|
|
1313
|
+
if ( ca1->data_type == CA_OBJECT && rb_obj_is_carray(receiver) ) {
|
|
1314
|
+
CArray *ca0;
|
|
1315
|
+
TypedData_Get_Struct(receiver, CArray, &carray_data_type, ca0);
|
|
1316
|
+
if ( ca_is_face(ca0) && ca0->data_type == CA_FIXLEN ) {
|
|
1317
|
+
ca_op_refuse_unimplemented(receiver, ca0->data_type,
|
|
1318
|
+
rb_eCADataTypeError);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1291
1322
|
/* Boolean-as-numeric promotion: an arithmetic op (+ - * / % ** ...) has
|
|
1292
1323
|
no boolean kernel, so its func[CA_BOOLEAN] slot is ca_binop_not_implement.
|
|
1293
1324
|
When both operands promoted to CA_BOOLEAN (= bool op bool), coerce them
|
|
@@ -1853,16 +1884,8 @@ rb_ca_call_triop (VALUE self, VALUE other2, VALUE other3,
|
|
|
1853
1884
|
volatile VALUE out;
|
|
1854
1885
|
CArray *ca1, *ca2, *ca3, *cao;
|
|
1855
1886
|
|
|
1856
|
-
/*
|
|
1857
|
-
|
|
1858
|
-
two operands; for triop we apply it twice. After this, all three
|
|
1859
|
-
CArrays share the same data_type (and unbound-repeats are resolved). */
|
|
1860
|
-
rb_ca_cast_self_or_other(&self, &other2);
|
|
1861
|
-
rb_ca_cast_self_or_other(&self, &other3);
|
|
1862
|
-
rb_ca_cast_self_or_other(&other2, &other3);
|
|
1863
|
-
/* one more pass to re-normalise self vs other2 in case the
|
|
1864
|
-
other2/other3 cast widened other2 above self's data_type */
|
|
1865
|
-
rb_ca_cast_self_or_other(&self, &other2);
|
|
1887
|
+
/* After this, all three CArrays share the same data_type. */
|
|
1888
|
+
rb_ca_cast_three(&self, &other2, &other3);
|
|
1866
1889
|
|
|
1867
1890
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca1);
|
|
1868
1891
|
TypedData_Get_Struct(other2, CArray, &carray_data_type, ca2);
|
|
@@ -2426,6 +2449,23 @@ ca_bincmp_mixed_sign (VALUE self, VALUE other, ca_bincmp_func_t func[],
|
|
|
2426
2449
|
return out;
|
|
2427
2450
|
}
|
|
2428
2451
|
|
|
2452
|
+
/* The answer of eq (ne = 0) or ne (ne = 1) when no cell can match: false
|
|
2453
|
+
(true for ne) in every cell, masked where `self` is masked. */
|
|
2454
|
+
VALUE
|
|
2455
|
+
ca_bincmp_no_match (VALUE self, int ne)
|
|
2456
|
+
{
|
|
2457
|
+
volatile VALUE out;
|
|
2458
|
+
CArray *ca, *co;
|
|
2459
|
+
GetCArray(self, ca);
|
|
2460
|
+
out = RTEST(rb_obj_is_cscalar(self))
|
|
2461
|
+
? rb_cscalar_new(CA_BOOLEAN, 0, NULL)
|
|
2462
|
+
: rb_carray_new(CA_BOOLEAN, ca->ndim, ca->dim, 0, NULL);
|
|
2463
|
+
TypedData_Get_Struct(out, CArray, &carray_data_type, co);
|
|
2464
|
+
ca_mask_overlay_safe(co, 1, ca);
|
|
2465
|
+
memset(co->ptr, ne ? 1 : 0, co->elements * co->bytes);
|
|
2466
|
+
return out;
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2429
2469
|
VALUE
|
|
2430
2470
|
rb_ca_call_bincmp (volatile VALUE self, volatile VALUE other,
|
|
2431
2471
|
ca_bincmp_func_t func[],
|
|
@@ -2447,6 +2487,27 @@ rb_ca_call_bincmp (volatile VALUE self, volatile VALUE other,
|
|
|
2447
2487
|
}
|
|
2448
2488
|
}
|
|
2449
2489
|
|
|
2490
|
+
/* eq and ne with a value the array can not hold (nil, a String): no cell
|
|
2491
|
+
matches. */
|
|
2492
|
+
if ( (ca_bincmp_func_t) func == (ca_bincmp_func_t) ca_bincmp_eq
|
|
2493
|
+
|| (ca_bincmp_func_t) func == (ca_bincmp_func_t) ca_bincmp_ne ) {
|
|
2494
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca1);
|
|
2495
|
+
if ( ca_query_matches_nothing(ca1, other) ) {
|
|
2496
|
+
return ca_bincmp_no_match(self,
|
|
2497
|
+
(ca_bincmp_func_t) func == (ca_bincmp_func_t) ca_bincmp_ne);
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
/* An ordering with a value the array can not hold is refused as Float#<
|
|
2502
|
+
refuses it. An array that has no ordering at all (complex) keeps its
|
|
2503
|
+
own refusal below. */
|
|
2504
|
+
if ( ! rb_obj_is_carray(other) && ca_bincmp_op_id_of(func) <= CA_BINCMP_GE ) {
|
|
2505
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca1);
|
|
2506
|
+
if ( func[ca1->data_type] != ca_bincmp_not_implement ) {
|
|
2507
|
+
ca_refuse_foreign_order(other, self);
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2450
2511
|
/* Face gate: an ORDERABLE Face over numeric storage descends to storage
|
|
2451
2512
|
(fixing the surface-fixlen memcmp mis-order) and reconciles a Face RHS
|
|
2452
2513
|
via to_comparable (e.g. unit alignment). No-op for non-Face self and
|