carray 3.0.1 → 3.0.2
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 +520 -0
- data/README.md +2 -2
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +33 -4
- data/ext/ca_axis_group.c +202 -96
- data/ext/ca_categorical_iterator.c +108 -54
- data/ext/ca_kernel_iterator.c +317 -51
- data/ext/ca_kernel_iterator.h +142 -35
- data/ext/ca_obj_array.c +62 -20
- data/ext/ca_obj_block.c +4 -4
- data/ext/ca_obj_const_string.c +85 -26
- data/ext/ca_obj_face.c +24 -0
- data/ext/ca_obj_face.h +15 -0
- data/ext/ca_obj_fixlen_string.c +18 -5
- data/ext/ca_obj_meld.c +123 -25
- data/ext/ca_obj_object.c +8 -0
- data/ext/ca_obj_select.c +49 -34
- data/ext/ca_obj_stack.c +3 -8
- data/ext/ca_obj_stride.c +72 -1
- data/ext/ca_obj_string.c +8 -4
- data/ext/ca_obj_window.c +8 -2
- data/ext/ca_op_ipower.c +1 -2
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sweep_engine.c +307 -143
- data/ext/ca_sweep_engine.h +26 -5
- data/ext/carray.h +21 -2
- data/ext/carray_access.c +32 -20
- data/ext/carray_address_basis.c +590 -0
- data/ext/carray_broadcast.c +3 -3
- data/ext/carray_call_cfunc.c +667 -483
- data/ext/carray_cast.c +115 -41
- data/ext/carray_copy.c +55 -30
- data/ext/carray_core.c +83 -3
- data/ext/carray_count.c +9 -10
- data/ext/carray_factorize.c +46 -25
- data/ext/carray_internal.h +17 -0
- data/ext/carray_kernels_reduce_aggregate.c +168 -0
- data/ext/carray_kernels_reduce_cumulative.c +270 -1
- data/ext/carray_kernels_reduce_extreme.c +554 -8
- data/ext/carray_kernels_scan.c +4 -4
- data/ext/carray_kernels_search.c +94 -14
- data/ext/carray_loop.c +7 -1
- data/ext/carray_mask.c +23 -8
- data/ext/carray_median_percentile.c +55 -0
- data/ext/carray_operator.c +4 -4
- data/ext/carray_order.c +1 -1
- data/ext/carray_random.c +384 -40
- data/ext/carray_slab.c +13 -0
- data/ext/carray_sort.c +20 -22
- data/ext/mk_call_cfunc.rb +103 -116
- data/ext/mkkernel.rb +297 -29
- data/ext/ruby_carray.c +10 -1
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +5 -3
- data/lib/carray/autoload_method_extension.rb +12 -0
- data/lib/carray/axis_group.rb +77 -0
- data/lib/carray/basics.rb +4 -0
- data/lib/carray/block_iterator.rb +92 -16
- data/lib/carray/categorical.rb +150 -33
- data/lib/carray/categorical_iterator.rb +207 -80
- data/lib/carray/const_string.rb +131 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/csv_parser.rb +11 -4
- data/lib/carray/frame/frame.rb +81 -10
- data/lib/carray/frame/group.rb +36 -3
- data/lib/carray/frame/io.rb +67 -15
- data/lib/carray/frame/records.rb +18 -4
- data/lib/carray/frame/verbs.rb +14 -11
- data/lib/carray/inspect.rb +42 -9
- data/lib/carray/iterator.rb +143 -0
- data/lib/carray/lazy.rb +0 -37
- data/lib/carray/mask_gap_fill.rb +3 -1
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/is_in.rb +13 -2
- data/lib/carray/methods/locate_addr.rb +75 -2
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +110 -0
- data/lib/carray/methods/unique.rb +41 -1
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/slab_iterator.rb +58 -13
- data/lib/carray/string_operation_extension.rb +5 -1
- data/lib/carray/time.rb +18 -2
- data/lib/carray/window_iterator.rb +142 -20
- data/lib/carray.rb +2 -0
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_window.rb +10 -2
- data/yard-stubs/carray_access.rb +1 -1
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_core.rb +0 -80
- data/yard-stubs/carray_count.rb +7 -2
- data/yard-stubs/carray_lazy.rb +205 -0
- data/yard-stubs/carray_math.rb +1486 -3
- data/yard-stubs/carray_median_percentile.rb +16 -2
- data/yard-stubs/carray_order.rb +9 -69
- data/yard-stubs/carray_slab.rb +9 -7
- data/yard-stubs/carray_sort.rb +7 -5
- metadata +9 -1
data/ext/carray_cast.c
CHANGED
|
@@ -552,6 +552,77 @@ rb_ca_object_to_data_class (VALUE self, VALUE rtype, ca_size_t bytes)
|
|
|
552
552
|
return obj;
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
+
typedef struct {
|
|
556
|
+
CArray *ca;
|
|
557
|
+
CArray *cb;
|
|
558
|
+
boolean8_t *scratch;
|
|
559
|
+
} ca_to_type_ctx_t;
|
|
560
|
+
|
|
561
|
+
/* The cast proper, with `ca` attached. It can raise (a value the target
|
|
562
|
+
type cannot hold), so it runs under rb_ensure. */
|
|
563
|
+
static VALUE
|
|
564
|
+
ca_to_type_cast (VALUE arg)
|
|
565
|
+
{
|
|
566
|
+
ca_to_type_ctx_t *c = (ca_to_type_ctx_t *) arg;
|
|
567
|
+
CArray *ca = c->ca, *cb = c->cb;
|
|
568
|
+
|
|
569
|
+
if ( ca->data_type == CA_OBJECT
|
|
570
|
+
&& ( (cb->data_type >= CA_INT8 && cb->data_type <= CA_UINT64)
|
|
571
|
+
|| cb->data_type == CA_FLOAT32 || cb->data_type == CA_FLOAT64 ) ) {
|
|
572
|
+
/* object -> int/float: give the cast a mask buffer so an unparseable
|
|
573
|
+
cell becomes UNDEF (see ext/carray_cast_func.rb). Cast into a
|
|
574
|
+
scratch mask seeded from the source mask, then attach it to the
|
|
575
|
+
output only if some cell ended up masked -- an all-valid cast keeps
|
|
576
|
+
the mask-less result the legacy path produced. */
|
|
577
|
+
ca_size_t ne = cb->elements;
|
|
578
|
+
ca_size_t i;
|
|
579
|
+
boolean8_t any = 0;
|
|
580
|
+
boolean8_t *scratch;
|
|
581
|
+
c->scratch = scratch = ALLOC_N(boolean8_t, ne > 0 ? ne : 1);
|
|
582
|
+
if ( cb->mask ) {
|
|
583
|
+
memcpy(scratch, cb->mask->ptr, ne); /* copy of source mask */
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
memset(scratch, 0, ne);
|
|
587
|
+
}
|
|
588
|
+
ca_cast_block_with_mask(ne, ca, ca->ptr, cb, cb->ptr, scratch);
|
|
589
|
+
for (i=0; i<ne; i++) {
|
|
590
|
+
if ( scratch[i] ) {
|
|
591
|
+
any = 1;
|
|
592
|
+
break;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
if ( any ) {
|
|
596
|
+
if ( ! cb->mask ) {
|
|
597
|
+
ca_create_mask(cb);
|
|
598
|
+
}
|
|
599
|
+
memcpy(cb->mask->ptr, scratch, ne);
|
|
600
|
+
}
|
|
601
|
+
xfree(scratch);
|
|
602
|
+
c->scratch = NULL;
|
|
603
|
+
}
|
|
604
|
+
else if ( ca_has_mask(ca) ) {
|
|
605
|
+
ca_cast_block_with_mask(cb->elements, ca, ca->ptr, cb, cb->ptr,
|
|
606
|
+
(boolean8_t*)ca->mask->ptr);
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
ca_cast_block(cb->elements, ca, ca->ptr, cb, cb->ptr);
|
|
610
|
+
}
|
|
611
|
+
return Qnil;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
static VALUE
|
|
615
|
+
ca_to_type_release (VALUE arg)
|
|
616
|
+
{
|
|
617
|
+
ca_to_type_ctx_t *c = (ca_to_type_ctx_t *) arg;
|
|
618
|
+
if ( c->scratch ) {
|
|
619
|
+
xfree(c->scratch);
|
|
620
|
+
c->scratch = NULL;
|
|
621
|
+
}
|
|
622
|
+
ca_detach(c->ca);
|
|
623
|
+
return Qnil;
|
|
624
|
+
}
|
|
625
|
+
|
|
555
626
|
/* CArray#to_type(data_type, bytes:) -- eager copy of self converted to
|
|
556
627
|
data_type (a new entity owning its storage). User doc lives in
|
|
557
628
|
yard-stubs/carray_cast.rb. */
|
|
@@ -561,6 +632,7 @@ rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
|
|
|
561
632
|
{
|
|
562
633
|
volatile VALUE obj, rtype = Qnil, ropt, rbytes = Qnil;
|
|
563
634
|
CArray *ca, *cb;
|
|
635
|
+
ca_to_type_ctx_t ctx;
|
|
564
636
|
int8_t data_type;
|
|
565
637
|
ca_size_t bytes;
|
|
566
638
|
|
|
@@ -601,48 +673,11 @@ rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
|
|
|
601
673
|
|
|
602
674
|
TypedData_Get_Struct(obj, CArray, &carray_data_type, cb);
|
|
603
675
|
|
|
676
|
+
ctx.ca = ca;
|
|
677
|
+
ctx.cb = cb;
|
|
678
|
+
ctx.scratch = NULL;
|
|
604
679
|
ca_attach(ca);
|
|
605
|
-
|
|
606
|
-
&& ( (data_type >= CA_INT8 && data_type <= CA_UINT64)
|
|
607
|
-
|| data_type == CA_FLOAT32 || data_type == CA_FLOAT64 ) ) {
|
|
608
|
-
/* object -> int/float: give the cast a mask buffer so an unparseable
|
|
609
|
-
cell becomes UNDEF (see ext/carray_cast_func.rb). Cast into a
|
|
610
|
-
scratch mask seeded from the source mask, then attach it to the
|
|
611
|
-
output only if some cell ended up masked -- an all-valid cast keeps
|
|
612
|
-
the mask-less result the legacy path produced. */
|
|
613
|
-
ca_size_t ne = cb->elements;
|
|
614
|
-
ca_size_t i;
|
|
615
|
-
boolean8_t any = 0;
|
|
616
|
-
boolean8_t *scratch = ALLOC_N(boolean8_t, ne > 0 ? ne : 1);
|
|
617
|
-
if ( cb->mask ) {
|
|
618
|
-
memcpy(scratch, cb->mask->ptr, ne); /* copy of source mask */
|
|
619
|
-
}
|
|
620
|
-
else {
|
|
621
|
-
memset(scratch, 0, ne);
|
|
622
|
-
}
|
|
623
|
-
ca_cast_block_with_mask(ne, ca, ca->ptr, cb, cb->ptr, scratch);
|
|
624
|
-
for (i=0; i<ne; i++) {
|
|
625
|
-
if ( scratch[i] ) {
|
|
626
|
-
any = 1;
|
|
627
|
-
break;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
if ( any ) {
|
|
631
|
-
if ( ! cb->mask ) {
|
|
632
|
-
ca_create_mask(cb);
|
|
633
|
-
}
|
|
634
|
-
memcpy(cb->mask->ptr, scratch, ne);
|
|
635
|
-
}
|
|
636
|
-
xfree(scratch);
|
|
637
|
-
}
|
|
638
|
-
else if ( ca_has_mask(ca) ) {
|
|
639
|
-
ca_cast_block_with_mask(cb->elements, ca, ca->ptr, cb, cb->ptr,
|
|
640
|
-
(boolean8_t*)ca->mask->ptr);
|
|
641
|
-
}
|
|
642
|
-
else {
|
|
643
|
-
ca_cast_block(cb->elements, ca, ca->ptr, cb, cb->ptr);
|
|
644
|
-
}
|
|
645
|
-
ca_detach(ca);
|
|
680
|
+
rb_ensure(ca_to_type_cast, (VALUE) &ctx, ca_to_type_release, (VALUE) &ctx);
|
|
646
681
|
|
|
647
682
|
/* When rtype is a data_class (e.g. CAStruct subclass), wrap the
|
|
648
683
|
result in CARecord so the cast output carries data_class. */
|
|
@@ -1366,6 +1401,36 @@ rb_ca_cast (volatile VALUE self)
|
|
|
1366
1401
|
return obj;
|
|
1367
1402
|
}
|
|
1368
1403
|
|
|
1404
|
+
/* A String operand against a fixlen array is a value of that array's cell
|
|
1405
|
+
width. ca_value_to_data_type answers CA_OBJECT for a String, so without
|
|
1406
|
+
this the operand became an object scalar and the comparison ran down the
|
|
1407
|
+
object lane -- an rb_funcall of String#== per cell, against the cell's
|
|
1408
|
+
NUL-padded text. A fixlen array pads a short String on write
|
|
1409
|
+
(`a[i] = "be"` stores "be\0\0\0"), so that answered that an array does
|
|
1410
|
+
not equal the string it was written from, and did it 30x slower than the
|
|
1411
|
+
memcmp lane the fixlen comparison bodies are there to provide.
|
|
1412
|
+
|
|
1413
|
+
Two fixlen *arrays* of different widths keep the variable-width byte
|
|
1414
|
+
string semantics those bodies implement (min-width memcmp with a length
|
|
1415
|
+
tiebreak); this is only about a scalar standing in for a cell. */
|
|
1416
|
+
static int
|
|
1417
|
+
ca_fixlen_scalar_operand (volatile VALUE *scalar, VALUE reference)
|
|
1418
|
+
{
|
|
1419
|
+
CArray *cr;
|
|
1420
|
+
/* A String is the only operand that means a cell value here. A Regexp
|
|
1421
|
+
(match) or any other object keeps its own coercion: those are asking
|
|
1422
|
+
something about the bytes, not standing in for them. */
|
|
1423
|
+
if ( ! RB_TYPE_P(*scalar, T_STRING) || ! rb_obj_is_carray(reference) ) {
|
|
1424
|
+
return 0;
|
|
1425
|
+
}
|
|
1426
|
+
TypedData_Get_Struct(reference, CArray, &carray_data_type, cr);
|
|
1427
|
+
if ( cr->data_type != CA_FIXLEN ) {
|
|
1428
|
+
return 0;
|
|
1429
|
+
}
|
|
1430
|
+
*scalar = rb_cscalar_new_with_value(CA_FIXLEN, cr->bytes, *scalar);
|
|
1431
|
+
return 1;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1369
1434
|
/* CArray.cast(value) -- singleton entry delegating to rb_ca_cast, which
|
|
1370
1435
|
returns a CArray unchanged and coerces a Ruby value to a CScalar / CArray.
|
|
1371
1436
|
User doc lives in yard-stubs/carray_cast.rb. */
|
|
@@ -1409,6 +1474,9 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1409
1474
|
*self = rb_cscalar_new_with_value(CA_CMPLX128, 0, *self);
|
|
1410
1475
|
}
|
|
1411
1476
|
#endif
|
|
1477
|
+
else if ( ca_fixlen_scalar_operand(self, *other) ) {
|
|
1478
|
+
/* width taken from the fixlen reference; see the helper above */
|
|
1479
|
+
}
|
|
1412
1480
|
else if ( rb_ca_is_float_type(*other) ) {
|
|
1413
1481
|
*self = rb_cscalar_new_with_value(CA_FLOAT64, 0, *self);
|
|
1414
1482
|
}
|
|
@@ -1437,6 +1505,9 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1437
1505
|
*other = rb_cscalar_new_with_value(CA_CMPLX128, 0, *other);
|
|
1438
1506
|
}
|
|
1439
1507
|
#endif
|
|
1508
|
+
else if ( ca_fixlen_scalar_operand(other, *self) ) {
|
|
1509
|
+
/* width taken from the fixlen reference; see the helper above */
|
|
1510
|
+
}
|
|
1440
1511
|
else if ( rb_ca_is_float_type(*self) ) {
|
|
1441
1512
|
*other = rb_cscalar_new_with_value(CA_FLOAT64, 0, *other);
|
|
1442
1513
|
}
|
|
@@ -1824,6 +1895,9 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
|
|
|
1824
1895
|
if ( rb_ca_is_object_type(*self) ) {
|
|
1825
1896
|
*other = rb_cscalar_new_with_value(CA_OBJECT, 0, *other);
|
|
1826
1897
|
}
|
|
1898
|
+
else if ( ca_fixlen_scalar_operand(other, *self) ) {
|
|
1899
|
+
return; /* already the receiver's data_type and width */
|
|
1900
|
+
}
|
|
1827
1901
|
else if ( rb_ca_is_float_type(*self) ) {
|
|
1828
1902
|
*other = rb_cscalar_new_with_value(CA_FLOAT64, 0, *other);
|
|
1829
1903
|
}
|
data/ext/carray_copy.c
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include "carray.h"
|
|
12
12
|
#include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE */
|
|
13
13
|
#include "carray_internal.h" /* ca_gc_hold_push / ca_gc_hold_pop_to */
|
|
14
|
+
#include "ca_sweep_engine.h" /* ca_sweep_same_shape / ca_sweep_refuse_shapes */
|
|
14
15
|
#include <stdarg.h>
|
|
15
16
|
|
|
16
17
|
/* ------------------------------------------------------------------- */
|
|
@@ -19,22 +20,27 @@
|
|
|
19
20
|
* and bytes as `ca`, copies the element payload, and reproduces the
|
|
20
21
|
* mask state. Always copies even when `ca` is an entity; for view
|
|
21
22
|
* sources the data path goes through `ca_copy_data`, otherwise a flat
|
|
22
|
-
* memcpy of `ca_length(ca)` bytes.
|
|
23
|
+
* memcpy of `ca_length(ca)` bytes. If reading the source raises, the
|
|
24
|
+
* copy is freed before the raise propagates.
|
|
23
25
|
*
|
|
24
26
|
* Backs `CArray#copy` and is also reachable as a C-level utility from
|
|
25
27
|
* other ext files that need an owned snapshot. */
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
void
|
|
29
|
+
ca_fill_or_free (CArray *co, VALUE (*fill)(VALUE), VALUE arg)
|
|
28
30
|
{
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
co = carray_new(ca->data_type, ca->ndim, ca->dim, ca->bytes, 0);
|
|
31
|
+
int tag = 0;
|
|
32
|
+
rb_protect(fill, arg, &tag);
|
|
33
|
+
if ( tag ) {
|
|
34
|
+
ca_free(co);
|
|
35
|
+
rb_jump_tag(tag);
|
|
37
36
|
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static VALUE
|
|
40
|
+
ca_copy_fill (VALUE arg)
|
|
41
|
+
{
|
|
42
|
+
CArray **pair = (CArray **) arg;
|
|
43
|
+
CArray *ca = pair[0], *co = pair[1];
|
|
38
44
|
|
|
39
45
|
if ( ca_is_attached(ca) ) {
|
|
40
46
|
memcpy(co->ptr, ca->ptr, ca_length(ca));
|
|
@@ -47,6 +53,26 @@ ca_copy (void *ap)
|
|
|
47
53
|
if ( ca->mask ) {
|
|
48
54
|
ca_copy_mask(co, ca);
|
|
49
55
|
}
|
|
56
|
+
return Qnil;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
CArray *
|
|
60
|
+
ca_copy (void *ap)
|
|
61
|
+
{
|
|
62
|
+
CArray *ca = (CArray *) ap;
|
|
63
|
+
CArray *co;
|
|
64
|
+
CArray *pair[2];
|
|
65
|
+
|
|
66
|
+
if ( ca_is_scalar(ca) ) {
|
|
67
|
+
co = (CArray *) cscalar_new(ca->data_type, ca->bytes, 0);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
co = carray_new(ca->data_type, ca->ndim, ca->dim, ca->bytes, 0);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
pair[0] = ca;
|
|
74
|
+
pair[1] = co;
|
|
75
|
+
ca_fill_or_free(co, ca_copy_fill, (VALUE) pair);
|
|
50
76
|
|
|
51
77
|
return co;
|
|
52
78
|
}
|
|
@@ -272,16 +298,16 @@ rb_ca_template_with_type (VALUE self, VALUE rtype, VALUE rbytes)
|
|
|
272
298
|
return rb_ca_template_method(2, args, self);
|
|
273
299
|
}
|
|
274
300
|
|
|
275
|
-
/*
|
|
276
|
-
*
|
|
277
|
-
* size the output of vectorised scalar
|
|
278
|
-
*
|
|
301
|
+
/* Returns `template` of the first non-scalar among `n` variadic CArray
|
|
302
|
+
* arguments (of the first argument when all are scalars). Used by
|
|
303
|
+
* `carray_call_cfunc.c` to size the output of vectorised scalar
|
|
304
|
+
* C-function calls: a scalar pairs with any array, two arrays only when
|
|
305
|
+
* their shapes agree. */
|
|
279
306
|
VALUE
|
|
280
307
|
rb_ca_template_n (int n, ...)
|
|
281
308
|
{
|
|
282
|
-
volatile VALUE varg, obj;
|
|
283
|
-
CArray *ca;
|
|
284
|
-
ca_size_t elements = -1;
|
|
309
|
+
volatile VALUE varg, obj = Qnil;
|
|
310
|
+
CArray *ca, *donor = NULL;
|
|
285
311
|
va_list vargs;
|
|
286
312
|
int i;
|
|
287
313
|
|
|
@@ -289,24 +315,23 @@ rb_ca_template_n (int n, ...)
|
|
|
289
315
|
for (i=0; i<n; i++) {
|
|
290
316
|
varg = va_arg(vargs, VALUE);
|
|
291
317
|
if ( ! rb_obj_is_carray(varg) ) {
|
|
318
|
+
va_end(vargs);
|
|
292
319
|
rb_raise(rb_eRuntimeError, "[BUG] not-carray object given to rb_ca_template_n");
|
|
293
320
|
}
|
|
294
321
|
TypedData_Get_Struct(varg, CArray, &carray_data_type, ca);
|
|
295
322
|
if ( i == 0 ) {
|
|
296
323
|
obj = varg;
|
|
297
|
-
elements = ca->elements;
|
|
298
324
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
325
|
+
if ( ca_is_scalar(ca) ) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if ( ! donor ) {
|
|
329
|
+
donor = ca;
|
|
330
|
+
obj = varg;
|
|
331
|
+
}
|
|
332
|
+
else if ( ! ca_sweep_same_shape(donor, ca) ) {
|
|
333
|
+
va_end(vargs);
|
|
334
|
+
ca_sweep_refuse_shapes(donor, ca);
|
|
310
335
|
}
|
|
311
336
|
}
|
|
312
337
|
va_end(vargs);
|
data/ext/carray_core.c
CHANGED
|
@@ -1655,6 +1655,18 @@ ca_allocate (void *ap)
|
|
|
1655
1655
|
ca_allocate(ca->mask);
|
|
1656
1656
|
}
|
|
1657
1657
|
|
|
1658
|
+
/* The first attach of a view: materialise through the type's slot, then
|
|
1659
|
+
its mask. Run under rb_protect by ca_attach. */
|
|
1660
|
+
static VALUE
|
|
1661
|
+
ca_attach_view_first (VALUE arg)
|
|
1662
|
+
{
|
|
1663
|
+
CArray *ca = (CArray *) arg;
|
|
1664
|
+
ca_func[ca->obj_type].attach(ca);
|
|
1665
|
+
ca_update_mask(ca);
|
|
1666
|
+
ca_attach(ca->mask);
|
|
1667
|
+
return Qnil;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1658
1670
|
/* attach parent's data to ca->ptr */
|
|
1659
1671
|
|
|
1660
1672
|
void
|
|
@@ -1668,14 +1680,30 @@ ca_attach (void *ap)
|
|
|
1668
1680
|
|
|
1669
1681
|
if ( ca_is_view(ca) ) { /* view array */
|
|
1670
1682
|
|
|
1671
|
-
CAVIEW(ca)->attach
|
|
1672
|
-
if ( CAVIEW(ca)->attach > CA_ATTACH_MAX ) {
|
|
1683
|
+
if ( CAVIEW(ca)->attach >= CA_ATTACH_MAX ) {
|
|
1673
1684
|
rb_raise(rb_eRuntimeError,
|
|
1674
1685
|
"too large attach count of view array");
|
|
1675
1686
|
}
|
|
1687
|
+
CAVIEW(ca)->attach += 1; /* increments attach level */
|
|
1676
1688
|
|
|
1677
1689
|
if ( ! ca->ptr ) {
|
|
1678
|
-
|
|
1690
|
+
/* A slot can raise part way (a conversion meeting a value it cannot
|
|
1691
|
+
hold). Undo the attach then, or the next attach finds ca->ptr
|
|
1692
|
+
set, skips the slot and reads a half-filled buffer. A slot that
|
|
1693
|
+
got as far as publishing ca->ptr has also attached what its
|
|
1694
|
+
detach slot releases; one that raised earlier has published
|
|
1695
|
+
nothing and released its own parent attach on the way out. */
|
|
1696
|
+
int tag = 0;
|
|
1697
|
+
rb_protect(ca_attach_view_first, (VALUE) ca, &tag);
|
|
1698
|
+
if ( tag ) {
|
|
1699
|
+
if ( ca->ptr ) {
|
|
1700
|
+
ca_func[ca->obj_type].detach(ca);
|
|
1701
|
+
ca->ptr = NULL;
|
|
1702
|
+
}
|
|
1703
|
+
CAVIEW(ca)->attach -= 1;
|
|
1704
|
+
rb_jump_tag(tag);
|
|
1705
|
+
}
|
|
1706
|
+
return;
|
|
1679
1707
|
}
|
|
1680
1708
|
}
|
|
1681
1709
|
else { /* entity array */
|
|
@@ -1686,6 +1714,43 @@ ca_attach (void *ap)
|
|
|
1686
1714
|
ca_attach(ca->mask);
|
|
1687
1715
|
}
|
|
1688
1716
|
|
|
1717
|
+
/* Attach every array in list[0..n-1], or, if one of those attaches
|
|
1718
|
+
raises, none of them: the ones already attached are detached before the
|
|
1719
|
+
raise propagates. For views over several parents. */
|
|
1720
|
+
|
|
1721
|
+
typedef struct {
|
|
1722
|
+
CArray **list;
|
|
1723
|
+
int32_t n;
|
|
1724
|
+
int32_t done;
|
|
1725
|
+
} ca_attach_all_ctx_t;
|
|
1726
|
+
|
|
1727
|
+
static VALUE
|
|
1728
|
+
ca_attach_all_body (VALUE arg)
|
|
1729
|
+
{
|
|
1730
|
+
ca_attach_all_ctx_t *c = (ca_attach_all_ctx_t *) arg;
|
|
1731
|
+
for ( ; c->done < c->n; c->done++ ) {
|
|
1732
|
+
ca_attach(c->list[c->done]);
|
|
1733
|
+
}
|
|
1734
|
+
return Qnil;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
void
|
|
1738
|
+
ca_attach_all (CArray **list, int32_t n)
|
|
1739
|
+
{
|
|
1740
|
+
ca_attach_all_ctx_t c;
|
|
1741
|
+
int tag = 0;
|
|
1742
|
+
c.list = list;
|
|
1743
|
+
c.n = n;
|
|
1744
|
+
c.done = 0;
|
|
1745
|
+
rb_protect(ca_attach_all_body, (VALUE) &c, &tag);
|
|
1746
|
+
if ( tag ) {
|
|
1747
|
+
while ( c.done > 0 ) {
|
|
1748
|
+
ca_detach(list[--c.done]);
|
|
1749
|
+
}
|
|
1750
|
+
rb_jump_tag(tag);
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1689
1754
|
/* attach parent's data to ca->ptr */
|
|
1690
1755
|
|
|
1691
1756
|
void
|
|
@@ -2087,6 +2152,17 @@ ca_fill (void *ap, void *aptr)
|
|
|
2087
2152
|
|
|
2088
2153
|
/* ------------------------------------------------------------------- */
|
|
2089
2154
|
|
|
2155
|
+
#ifdef CARRAY_DEV_BUILD
|
|
2156
|
+
|
|
2157
|
+
/* The Ruby attach surface is built into development builds only. Ruby has no
|
|
2158
|
+
raw pointer, so the only thing a block can do inside an attach window is call
|
|
2159
|
+
back into the array API -- and which door that takes is invisible in the
|
|
2160
|
+
syntax: v[0] reads the attached buffer while v[] and v[0..1] compose past it
|
|
2161
|
+
to the root (R5, see the contract beside ca_attach in carray.h). Per-cell and
|
|
2162
|
+
whole-array writes reach the buffer and survive the sync; a write through a
|
|
2163
|
+
derived view is discarded. The in-tree tests drive the healthy spellings, so
|
|
2164
|
+
the surface stays reachable here and out of released builds. */
|
|
2165
|
+
|
|
2090
2166
|
/* subroutines for CArray.attach, CArray.attach!
|
|
2091
2167
|
CArray#attach, CArray#attach! */
|
|
2092
2168
|
|
|
@@ -2307,6 +2383,8 @@ rb_ca__detach__ (VALUE self)
|
|
|
2307
2383
|
return self;
|
|
2308
2384
|
}
|
|
2309
2385
|
|
|
2386
|
+
#endif /* CARRAY_DEV_BUILD */
|
|
2387
|
+
|
|
2310
2388
|
/* ------------------------------------------------------------------- */
|
|
2311
2389
|
|
|
2312
2390
|
static ID id_decode, id_encode;
|
|
@@ -2515,6 +2593,7 @@ Init_carray_core (void)
|
|
|
2515
2593
|
|
|
2516
2594
|
ca_init_obj_type();
|
|
2517
2595
|
|
|
2596
|
+
#ifdef CARRAY_DEV_BUILD
|
|
2518
2597
|
rb_define_singleton_method(rb_cCArray, "attach", rb_ca_s_attach, -1);
|
|
2519
2598
|
rb_define_singleton_method(rb_cCArray, "attach!", rb_ca_s_attach_bang, -1);
|
|
2520
2599
|
|
|
@@ -2524,6 +2603,7 @@ Init_carray_core (void)
|
|
|
2524
2603
|
rb_define_method(rb_cCArray, "__attach__", rb_ca__attach__, 0);
|
|
2525
2604
|
rb_define_method(rb_cCArray, "__sync__", rb_ca__sync__, 0);
|
|
2526
2605
|
rb_define_method(rb_cCArray, "__detach__", rb_ca__detach__, 0);
|
|
2606
|
+
#endif
|
|
2527
2607
|
|
|
2528
2608
|
rb_define_method(rb_cCArray, "members", rb_ca_members, 0);
|
|
2529
2609
|
|
data/ext/carray_count.c
CHANGED
|
@@ -39,11 +39,12 @@ VALUE rb_ca_count_not_masked (int argc, VALUE *argv, VALUE self);
|
|
|
39
39
|
- v is a CArray -> broadcast: count each v[k] and stack
|
|
40
40
|
(rejected for boolean self; see below)
|
|
41
41
|
- self is boolean, v scalar -> v must be true/false literal
|
|
42
|
-
- self is numeric, v scalar -> count_equal_ki (numeric
|
|
42
|
+
- self is numeric or object, v scalar -> count_equal_ki (numeric ==
|
|
43
|
+
for a number, Ruby == for an object)
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
- self is fixlen, v scalar -> count_equal_ki (memcmp over the whole
|
|
46
|
+
cell; a short String query is padded
|
|
47
|
+
out to the cell width) */
|
|
47
48
|
|
|
48
49
|
static VALUE
|
|
49
50
|
rb_ca_count (int argc, VALUE *argv, VALUE self)
|
|
@@ -95,11 +96,7 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
|
|
|
95
96
|
}
|
|
96
97
|
if ( ca_test_flag(src, CA_FLAG_FACE_COMPARABLE_STORAGE) ) {
|
|
97
98
|
if ( ! query_was_scalar ) {
|
|
98
|
-
|
|
99
|
-
GetCArray(rval, cv);
|
|
100
|
-
if ( ca_is_face(cv) ) {
|
|
101
|
-
rval = rb_ca_strip_face_value(rval);
|
|
102
|
-
}
|
|
99
|
+
rval = ca_face_operand_descend(rval, "count(v)");
|
|
103
100
|
}
|
|
104
101
|
}
|
|
105
102
|
else if ( rb_respond_to(self_ref, rb_intern("to_comparable")) ) {
|
|
@@ -290,7 +287,9 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
|
|
|
290
287
|
rb_obj_classname(rval));
|
|
291
288
|
}
|
|
292
289
|
} else {
|
|
293
|
-
|
|
290
|
+
/* true / false are the boolean array's own domain, not a number --
|
|
291
|
+
except in an object array, where they are ordinary stored values. */
|
|
292
|
+
if ( ( rval == Qtrue || rval == Qfalse ) && src->data_type != CA_OBJECT ) {
|
|
294
293
|
rb_raise(rb_eTypeError,
|
|
295
294
|
"count(v) on numeric array: v must be numeric, got %s",
|
|
296
295
|
rb_obj_classname(rval));
|
data/ext/carray_factorize.c
CHANGED
|
@@ -105,13 +105,27 @@
|
|
|
105
105
|
/* Descend `self` when it is an ORDERABLE Face; *pface keeps the pre-strip Face
|
|
106
106
|
for the re-lift (Qnil when there is nothing to put back). */
|
|
107
107
|
static VALUE
|
|
108
|
-
fz_face_descend (VALUE self, volatile VALUE *pface)
|
|
108
|
+
fz_face_descend (VALUE self, volatile VALUE *pface, const char *name)
|
|
109
109
|
{
|
|
110
110
|
CArray *ca;
|
|
111
111
|
GetCArray(self, ca);
|
|
112
|
-
if ( ca_is_face(ca)
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
if ( ca_is_face(ca) ) {
|
|
113
|
+
if ( ca_test_flag(ca, CA_FLAG_FACE_ORDERABLE_STORAGE) ) {
|
|
114
|
+
*pface = self;
|
|
115
|
+
return rb_ca_strip_face_value(self);
|
|
116
|
+
}
|
|
117
|
+
/* A Face that cannot be descended must not flow on undescended: whatever
|
|
118
|
+
reads it next reads its storage anyway, which is the encoding rather
|
|
119
|
+
than the values. A Face in this position normally never arrives --
|
|
120
|
+
CAConstString and CACategorical define their own members in Ruby -- but
|
|
121
|
+
the overrides only fire when the Face is the receiver, and this same
|
|
122
|
+
helper descends the *reference* for locate_addr, where it is the
|
|
123
|
+
argument. */
|
|
124
|
+
rb_raise(rb_eArgError,
|
|
125
|
+
"%s: %s is not orderable by storage (a cell encodes the value "
|
|
126
|
+
"rather than being it); convert it first -- #to_string for a "
|
|
127
|
+
"string Face -- or pass .parent to work in storage space",
|
|
128
|
+
name, rb_obj_classname(self));
|
|
115
129
|
}
|
|
116
130
|
*pface = Qnil;
|
|
117
131
|
return self;
|
|
@@ -140,15 +154,7 @@ fz_face_reconcile (VALUE reference, VALUE operand, const char *name)
|
|
|
140
154
|
rb_intern("to_comparable"),
|
|
141
155
|
1, operand));
|
|
142
156
|
}
|
|
143
|
-
|
|
144
|
-
CArray *op;
|
|
145
|
-
GetCArray(operand, op);
|
|
146
|
-
if ( ca_is_face(op) ) {
|
|
147
|
-
return rb_ca_strip_face_value(operand);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
(void) name;
|
|
151
|
-
return operand;
|
|
157
|
+
return ca_face_operand_descend(operand, name);
|
|
152
158
|
}
|
|
153
159
|
|
|
154
160
|
/* Put the Face back on a value-carrying output. */
|
|
@@ -495,7 +501,7 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
495
501
|
{
|
|
496
502
|
CArray *ca;
|
|
497
503
|
volatile VALUE face;
|
|
498
|
-
self = fz_face_descend(self, &face);
|
|
504
|
+
self = fz_face_descend(self, &face, "categorize");
|
|
499
505
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
500
506
|
|
|
501
507
|
int8_t dt = ca->data_type;
|
|
@@ -863,7 +869,7 @@ rb_ca_unique_flat (VALUE self)
|
|
|
863
869
|
{
|
|
864
870
|
CArray *ca;
|
|
865
871
|
volatile VALUE face;
|
|
866
|
-
self = fz_face_descend(self, &face);
|
|
872
|
+
self = fz_face_descend(self, &face, "unique");
|
|
867
873
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
868
874
|
|
|
869
875
|
int8_t dt = ca->data_type;
|
|
@@ -1113,7 +1119,7 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1113
1119
|
{
|
|
1114
1120
|
CArray *ca, *cv;
|
|
1115
1121
|
volatile VALUE face;
|
|
1116
|
-
self = fz_face_descend(self, &face);
|
|
1122
|
+
self = fz_face_descend(self, &face, "is_in");
|
|
1117
1123
|
rvalues = fz_face_reconcile(face, rvalues, "is_in");
|
|
1118
1124
|
GetCArray(self, ca);
|
|
1119
1125
|
|
|
@@ -1137,9 +1143,16 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1137
1143
|
rb_raise(rb_eArgError, "__is_in__: values must be a CArray");
|
|
1138
1144
|
}
|
|
1139
1145
|
GetCArray(rvalues, cv);
|
|
1140
|
-
if ( cv->data_type != dt
|
|
1146
|
+
if ( cv->data_type != dt ) {
|
|
1147
|
+
rb_raise(rb_eCADataTypeError,
|
|
1148
|
+
"__is_in__: values data type (%s) must match self (%s)",
|
|
1149
|
+
ca_type_name[cv->data_type], ca_type_name[dt]);
|
|
1150
|
+
}
|
|
1151
|
+
if ( dt == CA_FIXLEN && cv->bytes != ca->bytes ) {
|
|
1141
1152
|
rb_raise(rb_eCADataTypeError,
|
|
1142
|
-
"__is_in__:
|
|
1153
|
+
"__is_in__: a fixlen value is a cell-width blob, so the values "
|
|
1154
|
+
"must be %ld bytes wide like self, not %ld",
|
|
1155
|
+
(long) ca->bytes, (long) cv->bytes);
|
|
1143
1156
|
}
|
|
1144
1157
|
if ( cv->ndim < 1 ) {
|
|
1145
1158
|
rb_raise(rb_eRuntimeError, "__is_in__: values need ndim >= 1");
|
|
@@ -1271,7 +1284,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1271
1284
|
output is an address, so nothing is lifted back. */
|
|
1272
1285
|
{
|
|
1273
1286
|
volatile VALUE ref_face;
|
|
1274
|
-
rref = fz_face_descend(rref, &ref_face);
|
|
1287
|
+
rref = fz_face_descend(rref, &ref_face, "locate_addr");
|
|
1275
1288
|
self = fz_face_reconcile(ref_face, self, "locate_addr");
|
|
1276
1289
|
}
|
|
1277
1290
|
GetCArray(self, ca);
|
|
@@ -1531,7 +1544,7 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1531
1544
|
{
|
|
1532
1545
|
CArray *ca, *co;
|
|
1533
1546
|
volatile VALUE face;
|
|
1534
|
-
self = fz_face_descend(self, &face);
|
|
1547
|
+
self = fz_face_descend(self, &face, "set relation");
|
|
1535
1548
|
rother = fz_face_reconcile(face, rother, "set relation");
|
|
1536
1549
|
GetCArray(self, ca);
|
|
1537
1550
|
|
|
@@ -1554,8 +1567,16 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1554
1567
|
rb_raise(rb_eArgError, "set relation: other must be a CArray");
|
|
1555
1568
|
}
|
|
1556
1569
|
GetCArray(rother, co);
|
|
1557
|
-
if ( co->data_type != dt
|
|
1558
|
-
rb_raise(rb_eCADataTypeError,
|
|
1570
|
+
if ( co->data_type != dt ) {
|
|
1571
|
+
rb_raise(rb_eCADataTypeError,
|
|
1572
|
+
"set relation: other data type (%s) must match self (%s)",
|
|
1573
|
+
ca_type_name[co->data_type], ca_type_name[dt]);
|
|
1574
|
+
}
|
|
1575
|
+
if ( dt == CA_FIXLEN && co->bytes != ca->bytes ) {
|
|
1576
|
+
rb_raise(rb_eCADataTypeError,
|
|
1577
|
+
"set relation: a fixlen value is a cell-width blob, so other "
|
|
1578
|
+
"must be %ld bytes wide like self, not %ld",
|
|
1579
|
+
(long) ca->bytes, (long) co->bytes);
|
|
1559
1580
|
}
|
|
1560
1581
|
if ( co->ndim < 1 ) {
|
|
1561
1582
|
rb_raise(rb_eRuntimeError, "set relation: other need ndim >= 1");
|
|
@@ -1716,7 +1737,7 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1716
1737
|
{
|
|
1717
1738
|
CArray *ca, *co;
|
|
1718
1739
|
volatile VALUE face;
|
|
1719
|
-
self = fz_face_descend(self, &face);
|
|
1740
|
+
self = fz_face_descend(self, &face, "union");
|
|
1720
1741
|
rother = fz_face_reconcile(face, rother, "union");
|
|
1721
1742
|
GetCArray(self, ca);
|
|
1722
1743
|
|
|
@@ -1793,7 +1814,7 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1793
1814
|
{
|
|
1794
1815
|
CArray *ca;
|
|
1795
1816
|
volatile VALUE face;
|
|
1796
|
-
self = fz_face_descend(self, &face);
|
|
1817
|
+
self = fz_face_descend(self, &face, "value_counts");
|
|
1797
1818
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1798
1819
|
|
|
1799
1820
|
int8_t dt = ca->data_type;
|
|
@@ -2332,7 +2353,7 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2332
2353
|
{
|
|
2333
2354
|
CArray *ca;
|
|
2334
2355
|
volatile VALUE face;
|
|
2335
|
-
self = fz_face_descend(self, &face);
|
|
2356
|
+
self = fz_face_descend(self, &face, "mode");
|
|
2336
2357
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
2337
2358
|
|
|
2338
2359
|
int8_t dt = ca->data_type;
|