carray 3.0.5 → 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 +233 -0
- data/README.md +1 -1
- data/carray.gemspec +3 -2
- data/ext/ca_axis_dispatch.c +6 -0
- data/ext/ca_axis_group.c +1 -1
- data/ext/ca_categorical_iterator.c +7 -7
- data/ext/ca_kernel_iterator.c +116 -231
- data/ext/ca_kernel_iterator.h +410 -254
- data/ext/ca_obj_bincmp.c +9 -1
- data/ext/ca_obj_binop.c +10 -1
- data/ext/ca_obj_bitfield.c +2 -0
- data/ext/ca_obj_byte_swap.c +2 -0
- data/ext/ca_obj_face.c +2 -0
- data/ext/ca_obj_fake.c +3 -1
- data/ext/ca_obj_grid.c +167 -12
- data/ext/ca_obj_meld.c +69 -113
- data/ext/ca_obj_moncmp.c +9 -1
- data/ext/ca_obj_monop.c +40 -2
- data/ext/ca_obj_object.c +54 -20
- data/ext/ca_obj_reduce.c +15 -1
- data/ext/ca_obj_refer.c +65 -20
- data/ext/ca_obj_remap.c +69 -10
- data/ext/ca_obj_roll.c +1 -0
- data/ext/ca_obj_select.c +4 -1
- data/ext/ca_obj_select_axis.c +1 -0
- data/ext/ca_obj_shift.c +1 -0
- data/ext/ca_obj_stack.c +310 -111
- data/ext/ca_obj_stride.c +131 -45
- data/ext/ca_obj_string.c +18 -2
- data/ext/ca_obj_tile.c +1 -0
- data/ext/ca_obj_triop.c +9 -1
- data/ext/ca_obj_window.c +1 -0
- data/ext/ca_op_ipower.c +8 -8
- data/ext/caframe_csv_reader.c +1 -1
- data/ext/carray.h +2 -1
- data/ext/carray_access.c +27 -64
- data/ext/carray_address_basis.c +134 -0
- data/ext/carray_attribute.c +8 -0
- data/ext/carray_broadcast.c +3 -4
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_cast.c +8 -11
- data/ext/carray_conversion.c +9 -5
- data/ext/carray_core.c +811 -72
- data/ext/carray_element.c +13 -9
- data/ext/carray_histogram.c +25 -3
- data/ext/carray_internal.h +147 -12
- data/ext/carray_kernels_bincmp.c +2007 -3
- data/ext/carray_kernels_binop.c +25365 -5199
- data/ext/carray_kernels_init.c +8 -8
- data/ext/carray_kernels_monop.c +10696 -3678
- data/ext/carray_kernels_reduce_aggregate.c +4429 -702
- data/ext/carray_kernels_reduce_boolean.c +1533 -15
- data/ext/carray_kernels_reduce_cumulative.c +1808 -248
- data/ext/carray_kernels_reduce_extreme.c +4508 -511
- data/ext/carray_kernels_reduce_variance.c +2284 -152
- data/ext/carray_kernels_scan.c +240 -240
- data/ext/carray_kernels_search.c +4211 -264
- data/ext/carray_kernels_sort.c +367 -450
- data/ext/carray_lazy.c +47 -0
- data/ext/carray_loop.c +1 -1
- data/ext/carray_mask.c +130 -139
- data/ext/carray_median_percentile.c +4 -4
- data/ext/carray_memory_view.c +13 -7
- data/ext/carray_operator.c +147 -44
- data/ext/carray_order.c +3 -2
- data/ext/carray_random.c +4 -1
- data/ext/carray_slab.c +97 -21
- data/ext/carray_sort.c +1 -1
- data/ext/carray_test.c +74 -19
- data/ext/carray_time_text.c +2 -2
- data/ext/extconf.rb +11 -0
- data/ext/mkkernel.rb +346 -94
- data/ext/ruby_carray.c +4 -1
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +25 -1
- 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 +1 -1
- data/lib/carray/block_iterator.rb +17 -3
- data/lib/carray/categorical.rb +6 -8
- data/lib/carray/categorical_iterator.rb +2 -2
- data/lib/carray/complex.rb +2 -2
- data/lib/carray/conditional.rb +3 -2
- data/lib/carray/frame/column_verbs.rb +45 -14
- 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 +399 -78
- data/lib/carray/frame/group.rb +679 -53
- data/lib/carray/frame/io.rb +209 -71
- 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/inspect.rb +7 -2
- data/lib/carray/iterator.rb +32 -0
- data/lib/carray/lazy.rb +17 -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/meshgrid.rb +3 -1
- data/lib/carray/runtime.rb +47 -8
- data/lib/carray/segment_iterator.rb +23 -8
- data/lib/carray/serialize.rb +34 -17
- data/lib/carray/stack.rb +18 -6
- data/lib/carray/time.rb +5 -0
- data/lib/carray/window_iterator.rb +16 -4
- data/yard-stubs/ca_obj_array.rb +26 -1
- data/yard-stubs/carray_cast.rb +8 -5
- data/yard-stubs/carray_conversion.rb +8 -2
- data/yard-stubs/carray_mask.rb +20 -1
- data/yard-stubs/carray_math.rb +31 -16
- data/yard-stubs/carray_memory_view.rb +7 -0
- data/yard-stubs/carray_test.rb +7 -4
- metadata +18 -4
data/ext/carray_operator.c
CHANGED
|
@@ -218,7 +218,7 @@ ca_chunked_run_acquire (ca_chunked_run_t *run, int k)
|
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
static VALUE
|
|
221
|
-
|
|
221
|
+
ca_chunked_run_loop (VALUE arg)
|
|
222
222
|
{
|
|
223
223
|
ca_chunked_run_t *run = (ca_chunked_run_t *) arg;
|
|
224
224
|
char *p[CA_CHUNKED_MAX_OPERANDS];
|
|
@@ -245,6 +245,15 @@ ca_chunked_run_body (VALUE arg)
|
|
|
245
245
|
return Qnil;
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
/* The object arrays among the operands are recorded as computed over
|
|
249
|
+
(ca_computing_run) while the run reads them. */
|
|
250
|
+
static VALUE
|
|
251
|
+
ca_chunked_run_body (VALUE arg)
|
|
252
|
+
{
|
|
253
|
+
ca_chunked_run_t *run = (ca_chunked_run_t *) arg;
|
|
254
|
+
return ca_computing_run(run->n_op, run->ca, ca_chunked_run_loop, arg);
|
|
255
|
+
}
|
|
256
|
+
|
|
248
257
|
static VALUE
|
|
249
258
|
ca_chunked_run_release (VALUE arg)
|
|
250
259
|
{
|
|
@@ -450,13 +459,21 @@ typedef struct {
|
|
|
450
459
|
int n;
|
|
451
460
|
CArray **held;
|
|
452
461
|
const char *mode; /* per held array: 'r' read, 'w' written in place */
|
|
462
|
+
CArray **ops; /* every operand, attached or gathered */
|
|
453
463
|
} ca_op_guard_t;
|
|
454
464
|
|
|
465
|
+
static VALUE
|
|
466
|
+
ca_op_guard_run (VALUE varg)
|
|
467
|
+
{
|
|
468
|
+
ca_op_guard_t *g = (ca_op_guard_t *) varg;
|
|
469
|
+
return g->run(g->arg);
|
|
470
|
+
}
|
|
471
|
+
|
|
455
472
|
static VALUE
|
|
456
473
|
ca_op_guard_body (VALUE varg)
|
|
457
474
|
{
|
|
458
475
|
ca_op_guard_t *g = (ca_op_guard_t *) varg;
|
|
459
|
-
g->
|
|
476
|
+
ca_computing_run(g->n, g->ops, ca_op_guard_run, varg);
|
|
460
477
|
g->done = 1;
|
|
461
478
|
return Qnil;
|
|
462
479
|
}
|
|
@@ -496,10 +513,13 @@ ca_op_guard_release (VALUE varg)
|
|
|
496
513
|
}
|
|
497
514
|
|
|
498
515
|
/* Runs the kernel packed in `call` with `held` attached; see above. NULL
|
|
499
|
-
entries in held are skipped.
|
|
516
|
+
entries in held are skipped. ops lists every operand the kernel reads
|
|
517
|
+
or writes, attached or gathered into a buffer, so that the object
|
|
518
|
+
arrays among them are recorded as computed over (ca_computing_run)
|
|
519
|
+
while the kernel runs; NULL means the operands are the held arrays. */
|
|
500
520
|
static void
|
|
501
521
|
ca_op_guarded (VALUE (*run)(VALUE), void *call,
|
|
502
|
-
int n, CArray **held, const char *mode)
|
|
522
|
+
int n, CArray **held, const char *mode, CArray **ops)
|
|
503
523
|
{
|
|
504
524
|
ca_op_guard_t g;
|
|
505
525
|
g.run = run;
|
|
@@ -508,6 +528,7 @@ ca_op_guarded (VALUE (*run)(VALUE), void *call,
|
|
|
508
528
|
g.n = n;
|
|
509
529
|
g.held = held;
|
|
510
530
|
g.mode = mode;
|
|
531
|
+
g.ops = ops ? ops : held;
|
|
511
532
|
rb_ensure(ca_op_guard_body, (VALUE) &g, ca_op_guard_release, (VALUE) &g);
|
|
512
533
|
}
|
|
513
534
|
|
|
@@ -556,6 +577,13 @@ ca_mask_overlay_or_body (VALUE arg)
|
|
|
556
577
|
Each operand other than a scalar has ca_out's number of elements
|
|
557
578
|
(ArgumentError otherwise); at most 8 operands.
|
|
558
579
|
|
|
580
|
+
A bang operation's ca_out can share its root with an operand, so its
|
|
581
|
+
mask buffer may be the root's mask that a later operand's mask reads
|
|
582
|
+
(`r.fma!(m, r.flip(0))`). When more than one operand is read and one
|
|
583
|
+
of them shares ca_out's root, the operands' masks are folded into a
|
|
584
|
+
scratch first and ORed into ca_out's mask at the end, so every operand
|
|
585
|
+
is read before ca_out's mask changes.
|
|
586
|
+
|
|
559
587
|
This gathers the full mask once; a per-chunk mask gather inside the
|
|
560
588
|
chunked branch is a possible future optimisation. */
|
|
561
589
|
void
|
|
@@ -563,7 +591,7 @@ ca_mask_overlay_safe (CArray *ca_out, int n, ...)
|
|
|
563
591
|
{
|
|
564
592
|
va_list ap;
|
|
565
593
|
CArray *slist[8];
|
|
566
|
-
int i, any_mask = 0;
|
|
594
|
+
int i, any_mask = 0, n_read = 0, shares = 0;
|
|
567
595
|
|
|
568
596
|
if ( n < 0 || n > 8 ) {
|
|
569
597
|
rb_raise(rb_eRuntimeError, "ca_mask_overlay_safe: n out of range");
|
|
@@ -589,23 +617,46 @@ ca_mask_overlay_safe (CArray *ca_out, int n, ...)
|
|
|
589
617
|
|
|
590
618
|
if ( ! any_mask ) return;
|
|
591
619
|
|
|
620
|
+
for ( i = 0; i < n; i++ ) {
|
|
621
|
+
CArray *cs = slist[i];
|
|
622
|
+
if ( ! cs || cs == ca_out ) {
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
n_read++;
|
|
626
|
+
if ( ca_shares_root(ca_out, cs) ) {
|
|
627
|
+
shares = 1;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
592
631
|
ca_update_mask(ca_out);
|
|
593
632
|
{
|
|
594
633
|
int created_new = 0;
|
|
634
|
+
volatile VALUE hacc = 0;
|
|
635
|
+
boolean8_t *mout, *ma;
|
|
636
|
+
ca_size_t elements = ca_out->elements;
|
|
637
|
+
|
|
595
638
|
if ( ! ca_out->mask ) {
|
|
596
639
|
ca_create_mask(ca_out);
|
|
597
640
|
created_new = 1;
|
|
598
641
|
}
|
|
599
642
|
|
|
600
|
-
|
|
601
|
-
|
|
643
|
+
mout = (boolean8_t *) ca_out->mask->ptr;
|
|
644
|
+
if ( n_read > 1 && shares ) {
|
|
645
|
+
ma = ALLOCV_N(boolean8_t, hacc, elements);
|
|
646
|
+
memset(ma, 0, elements);
|
|
647
|
+
}
|
|
648
|
+
else {
|
|
649
|
+
ma = mout;
|
|
650
|
+
}
|
|
602
651
|
|
|
603
652
|
/* Fresh mask → zero-init. Existing mask (= bang variant where
|
|
604
653
|
ca_out IS one of the operands) → preserve as initial accumulator
|
|
605
654
|
(= ca_out's own contribution is already in `ma`, OR in others).
|
|
606
655
|
This is structurally equivalent to ca_copy_mask_overlay_n's
|
|
607
656
|
behavior which OR'd into existing mask without clearing. */
|
|
608
|
-
if ( created_new )
|
|
657
|
+
if ( created_new ) {
|
|
658
|
+
memset(mout, 0, elements);
|
|
659
|
+
}
|
|
609
660
|
|
|
610
661
|
for ( i = 0; i < n; i++ ) {
|
|
611
662
|
CArray *cs = slist[i];
|
|
@@ -627,6 +678,14 @@ ca_mask_overlay_safe (CArray *ca_out, int n, ...)
|
|
|
627
678
|
ca_lazy_arena_release_held, (VALUE) &o);
|
|
628
679
|
}
|
|
629
680
|
}
|
|
681
|
+
|
|
682
|
+
if ( ma != mout ) {
|
|
683
|
+
ca_size_t j;
|
|
684
|
+
for (j=0; j<elements; j++) {
|
|
685
|
+
mout[j] |= ma[j];
|
|
686
|
+
}
|
|
687
|
+
ALLOCV_END(hacc);
|
|
688
|
+
}
|
|
630
689
|
}
|
|
631
690
|
}
|
|
632
691
|
|
|
@@ -707,7 +766,7 @@ rb_ca_call_monop (VALUE self, ca_monop_func_t func[])
|
|
|
707
766
|
ca_attach(ca1); /* window: the kernel runs through ca_op_guarded when it can raise */
|
|
708
767
|
k.p1 = ca1->ptr; k.i1 = 1;
|
|
709
768
|
if ( ca_monop_may_raise(func, ca1->data_type) ) {
|
|
710
|
-
ca_op_guarded(ca_monop_call, &k, 1, &ca1, "r");
|
|
769
|
+
ca_op_guarded(ca_monop_call, &k, 1, &ca1, "r", NULL);
|
|
711
770
|
}
|
|
712
771
|
else {
|
|
713
772
|
ca_monop_call((VALUE) &k);
|
|
@@ -724,7 +783,7 @@ rb_ca_call_monop (VALUE self, ca_monop_func_t func[])
|
|
|
724
783
|
int strided_path_done = 0;
|
|
725
784
|
{
|
|
726
785
|
extern ca_operation_function_t ca_stride_func;
|
|
727
|
-
if ( ca_func[ca1->obj_type].attach == ca_stride_func.attach ) {
|
|
786
|
+
if ( ca1->data_type != CA_OBJECT && ca_func[ca1->obj_type].attach == ca_stride_func.attach ) {
|
|
728
787
|
CAStride *cs1 = (CAStride *) ca1;
|
|
729
788
|
CArray *root1;
|
|
730
789
|
ca_size_t strides1[CA_RANK_MAX];
|
|
@@ -804,10 +863,21 @@ rb_ca_call_monop (VALUE self, ca_monop_func_t func[])
|
|
|
804
863
|
(void) h1;
|
|
805
864
|
p1 = ALLOCV_N(char, h1, ca1->elements * ca1->bytes);
|
|
806
865
|
ca_xfer_all(ca1, p1, CA_XFER_GET);
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
866
|
+
{
|
|
867
|
+
ca_monop_call_t k;
|
|
868
|
+
CArray *none[1] = { NULL };
|
|
869
|
+
k.f = func[ca1->data_type];
|
|
870
|
+
k.n = ca1->elements;
|
|
871
|
+
k.m = ( ca2->mask ) ? (boolean8_t *)ca2->mask->ptr : NULL;
|
|
872
|
+
k.p1 = p1; k.i1 = 1;
|
|
873
|
+
k.p2 = ca2->ptr; k.i2 = 1;
|
|
874
|
+
if ( ca_monop_may_raise(func, ca1->data_type) ) {
|
|
875
|
+
ca_op_guarded(ca_monop_call, &k, 1, none, "r", &ca1);
|
|
876
|
+
}
|
|
877
|
+
else {
|
|
878
|
+
ca_monop_call((VALUE) &k);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
811
881
|
ALLOCV_END(h1);
|
|
812
882
|
}
|
|
813
883
|
}
|
|
@@ -838,7 +908,7 @@ rb_ca_call_monop_bang (VALUE self, ca_monop_func_t func[])
|
|
|
838
908
|
k.p1 = ca1->ptr; k.i1 = 1;
|
|
839
909
|
k.p2 = ca1->ptr; k.i2 = 1;
|
|
840
910
|
if ( ca_monop_may_raise(func, ca1->data_type) ) {
|
|
841
|
-
ca_op_guarded(ca_monop_call, &k, 1, &ca1, "w");
|
|
911
|
+
ca_op_guarded(ca_monop_call, &k, 1, &ca1, "w", NULL);
|
|
842
912
|
}
|
|
843
913
|
else {
|
|
844
914
|
ca_monop_call((VALUE) &k);
|
|
@@ -889,7 +959,7 @@ rb_ca_call_monop_typed (VALUE self, ca_monop_func_t func[],
|
|
|
889
959
|
ca_attach(ca1); /* window: the kernel runs through ca_op_guarded when it can raise */
|
|
890
960
|
k.p1 = ca1->ptr; k.i1 = 1;
|
|
891
961
|
if ( ca_monop_may_raise(func, ca1->data_type) ) {
|
|
892
|
-
ca_op_guarded(ca_monop_call, &k, 1, &ca1, "r");
|
|
962
|
+
ca_op_guarded(ca_monop_call, &k, 1, &ca1, "r", NULL);
|
|
893
963
|
}
|
|
894
964
|
else {
|
|
895
965
|
ca_monop_call((VALUE) &k);
|
|
@@ -903,7 +973,7 @@ rb_ca_call_monop_typed (VALUE self, ca_monop_func_t func[],
|
|
|
903
973
|
int strided_path_done = 0;
|
|
904
974
|
{
|
|
905
975
|
extern ca_operation_function_t ca_stride_func;
|
|
906
|
-
if ( ca_func[ca1->obj_type].attach == ca_stride_func.attach ) {
|
|
976
|
+
if ( ca1->data_type != CA_OBJECT && ca_func[ca1->obj_type].attach == ca_stride_func.attach ) {
|
|
907
977
|
CAStride *cs1 = (CAStride *) ca1;
|
|
908
978
|
CArray *root1;
|
|
909
979
|
ca_size_t strides1[CA_RANK_MAX];
|
|
@@ -982,10 +1052,21 @@ rb_ca_call_monop_typed (VALUE self, ca_monop_func_t func[],
|
|
|
982
1052
|
(void) h1;
|
|
983
1053
|
p1 = ALLOCV_N(char, h1, ca1->elements * ca1->bytes);
|
|
984
1054
|
ca_xfer_all(ca1, p1, CA_XFER_GET);
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1055
|
+
{
|
|
1056
|
+
ca_monop_call_t k;
|
|
1057
|
+
CArray *none[1] = { NULL };
|
|
1058
|
+
k.f = func[ca1->data_type];
|
|
1059
|
+
k.n = ca1->elements;
|
|
1060
|
+
k.m = ( ca2->mask ) ? (boolean8_t *)ca2->mask->ptr : NULL;
|
|
1061
|
+
k.p1 = p1; k.i1 = 1;
|
|
1062
|
+
k.p2 = ca2->ptr; k.i2 = 1;
|
|
1063
|
+
if ( ca_monop_may_raise(func, ca1->data_type) ) {
|
|
1064
|
+
ca_op_guarded(ca_monop_call, &k, 1, none, "r", &ca1);
|
|
1065
|
+
}
|
|
1066
|
+
else {
|
|
1067
|
+
ca_monop_call((VALUE) &k);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
989
1070
|
ALLOCV_END(h1);
|
|
990
1071
|
}
|
|
991
1072
|
}
|
|
@@ -1286,7 +1367,7 @@ rb_ca_call_binop (volatile VALUE self, volatile VALUE other,
|
|
|
1286
1367
|
k.p2 = ca2->ptr; k.i2 = i2;
|
|
1287
1368
|
if ( ca_binop_may_raise(func, ca1->data_type) ) {
|
|
1288
1369
|
held[0] = ca1; held[1] = ca2;
|
|
1289
|
-
ca_op_guarded(ca_binop_call, &k, 2, held, "rr");
|
|
1370
|
+
ca_op_guarded(ca_binop_call, &k, 2, held, "rr", NULL);
|
|
1290
1371
|
}
|
|
1291
1372
|
else {
|
|
1292
1373
|
ca_binop_call((VALUE) &k);
|
|
@@ -1305,11 +1386,22 @@ rb_ca_call_binop (volatile VALUE self, volatile VALUE other,
|
|
|
1305
1386
|
|
|
1306
1387
|
p_shared = ALLOCV_N(char, h_shared, ca1->elements * ca1->bytes);
|
|
1307
1388
|
ca_xfer_all(ca1, p_shared, CA_XFER_GET);
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1389
|
+
{
|
|
1390
|
+
ca_binop_call_t k;
|
|
1391
|
+
CArray *none[2] = { NULL, NULL };
|
|
1392
|
+
k.f = func[ca1->data_type];
|
|
1393
|
+
k.n = n_kernel;
|
|
1394
|
+
k.m = ( ca3->mask ) ? (boolean8_t *) ca3->mask->ptr : NULL;
|
|
1395
|
+
k.p1 = p_shared; k.i1 = i1;
|
|
1396
|
+
k.p2 = p_shared; k.i2 = i2;
|
|
1397
|
+
k.p3 = ca3->ptr; k.i3 = i3;
|
|
1398
|
+
if ( ca_binop_may_raise(func, ca1->data_type) ) {
|
|
1399
|
+
ca_op_guarded(ca_binop_call, &k, 2, none, "rr", (CArray *[]){ ca1, ca2 });
|
|
1400
|
+
}
|
|
1401
|
+
else {
|
|
1402
|
+
ca_binop_call((VALUE) &k);
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1313
1405
|
ALLOCV_END(h_shared);
|
|
1314
1406
|
}
|
|
1315
1407
|
else {
|
|
@@ -1353,7 +1445,7 @@ rb_ca_call_binop (volatile VALUE self, volatile VALUE other,
|
|
|
1353
1445
|
fallback (dead on the success path) but fire for views outside the
|
|
1354
1446
|
CAStride+entity family (CASelect / CAGrid / CAReduce
|
|
1355
1447
|
etc.). */
|
|
1356
|
-
if ( i1 == 1 && i2 == 1 && nonalias_arrays >= 1 ) {
|
|
1448
|
+
if ( dt != CA_OBJECT && i1 == 1 && i2 == 1 && nonalias_arrays >= 1 ) {
|
|
1357
1449
|
extern ca_operation_function_t ca_stride_func;
|
|
1358
1450
|
CArray *root1 = NULL, *root2 = NULL;
|
|
1359
1451
|
ca_size_t strides1[CA_RANK_MAX], strides2[CA_RANK_MAX];
|
|
@@ -1505,7 +1597,7 @@ rb_ca_call_binop (volatile VALUE self, volatile VALUE other,
|
|
|
1505
1597
|
if ( ca_binop_may_raise(func, dt) ) {
|
|
1506
1598
|
held[0] = a1 ? ca1 : NULL;
|
|
1507
1599
|
held[1] = a2 ? ca2 : NULL;
|
|
1508
|
-
ca_op_guarded(ca_binop_call, &k, 2, held, "rr");
|
|
1600
|
+
ca_op_guarded(ca_binop_call, &k, 2, held, "rr", (CArray *[]){ ca1, ca2 });
|
|
1509
1601
|
}
|
|
1510
1602
|
else {
|
|
1511
1603
|
ca_binop_call((VALUE) &k);
|
|
@@ -1639,7 +1731,7 @@ rb_ca_call_binop_bang (VALUE self, VALUE other, ca_binop_func_t func[])
|
|
|
1639
1731
|
if ( ca_binop_may_raise(func, ca1->data_type) ) {
|
|
1640
1732
|
held[0] = ca1;
|
|
1641
1733
|
held[1] = a2 ? ca2 : NULL;
|
|
1642
|
-
ca_op_guarded(ca_binop_call, &k, 2, held, "wr");
|
|
1734
|
+
ca_op_guarded(ca_binop_call, &k, 2, held, "wr", (CArray *[]){ ca1, ca2 });
|
|
1643
1735
|
}
|
|
1644
1736
|
else {
|
|
1645
1737
|
ca_binop_call((VALUE) &k);
|
|
@@ -1866,7 +1958,7 @@ rb_ca_call_triop (VALUE self, VALUE other2, VALUE other3,
|
|
|
1866
1958
|
held[0] = attached1 ? ca1 : NULL;
|
|
1867
1959
|
held[1] = attached2 ? ca2 : NULL;
|
|
1868
1960
|
held[2] = attached3 ? ca3 : NULL;
|
|
1869
|
-
ca_op_guarded(ca_triop_call, &k, 3, held, "rrr");
|
|
1961
|
+
ca_op_guarded(ca_triop_call, &k, 3, held, "rrr", (CArray *[]){ ca1, ca2, ca3 });
|
|
1870
1962
|
}
|
|
1871
1963
|
else {
|
|
1872
1964
|
ca_triop_call((VALUE) &k);
|
|
@@ -2032,7 +2124,7 @@ rb_ca_call_triop_bang (VALUE self, VALUE other2, VALUE other3,
|
|
|
2032
2124
|
held[0] = ca1;
|
|
2033
2125
|
held[1] = attached2 ? ca2 : NULL;
|
|
2034
2126
|
held[2] = attached3 ? ca3 : NULL;
|
|
2035
|
-
ca_op_guarded(ca_triop_call, &k, 3, held, "wrr");
|
|
2127
|
+
ca_op_guarded(ca_triop_call, &k, 3, held, "wrr", (CArray *[]){ ca1, ca2, ca3 });
|
|
2036
2128
|
}
|
|
2037
2129
|
else {
|
|
2038
2130
|
ca_triop_call((VALUE) &k);
|
|
@@ -2077,7 +2169,7 @@ rb_ca_call_triop_bang (VALUE self, VALUE other2, VALUE other3,
|
|
|
2077
2169
|
ca_chunked_run_add(&run, ca3, s3);
|
|
2078
2170
|
run.kernel = ca_triop_chunk_kernel;
|
|
2079
2171
|
run.data = &d;
|
|
2080
|
-
ca_op_guarded(ca_triop_bang_chunked, &run, 1, &ca1, "w");
|
|
2172
|
+
ca_op_guarded(ca_triop_bang_chunked, &run, 1, &ca1, "w", NULL);
|
|
2081
2173
|
}
|
|
2082
2174
|
}
|
|
2083
2175
|
}
|
|
@@ -2141,8 +2233,9 @@ rb_ca_call_moncmp (VALUE self, ca_moncmp_func_t func[])
|
|
|
2141
2233
|
k.m = ( ca2->mask ) ? (boolean8_t *) ca2->mask->ptr : NULL;
|
|
2142
2234
|
k.p1 = p1; k.i1 = 1;
|
|
2143
2235
|
k.p2 = (boolean8_t *) ca2->ptr; k.i2 = 1;
|
|
2144
|
-
if (
|
|
2145
|
-
|
|
2236
|
+
if ( ca_moncmp_may_raise(func, ca1->data_type) ) {
|
|
2237
|
+
CArray *none[1] = { NULL };
|
|
2238
|
+
ca_op_guarded(ca_moncmp_call, &k, 1, attached1 ? &ca1 : none, "r", &ca1);
|
|
2146
2239
|
}
|
|
2147
2240
|
else {
|
|
2148
2241
|
ca_moncmp_call((VALUE) &k);
|
|
@@ -2431,12 +2524,23 @@ rb_ca_call_bincmp (volatile VALUE self, volatile VALUE other,
|
|
|
2431
2524
|
(void) h_shared;
|
|
2432
2525
|
p_shared = ALLOCV_N(char, h_shared, ca1->elements * ca1->bytes);
|
|
2433
2526
|
ca_xfer_all(ca1, p_shared, CA_XFER_GET);
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2527
|
+
{
|
|
2528
|
+
ca_bincmp_call_t k;
|
|
2529
|
+
CArray *none[2] = { NULL, NULL };
|
|
2530
|
+
k.f = func[ca1->data_type];
|
|
2531
|
+
k.n = n_kernel;
|
|
2532
|
+
k.m = ( ca3->mask ) ? (boolean8_t *) ca3->mask->ptr : NULL;
|
|
2533
|
+
k.p1 = p_shared; k.b1 = ca1->bytes; k.i1 = i1;
|
|
2534
|
+
k.p2 = p_shared; k.b2 = ca2->bytes; k.i2 = i2;
|
|
2535
|
+
k.p3 = ca3->ptr; k.b3 = ca3->bytes; k.i3 = i3;
|
|
2536
|
+
k.tol = tol;
|
|
2537
|
+
if ( ca_bincmp_may_raise(func, ca1->data_type) ) {
|
|
2538
|
+
ca_op_guarded(ca_bincmp_call, &k, 2, none, "rr", (CArray *[]){ ca1, ca2 });
|
|
2539
|
+
}
|
|
2540
|
+
else {
|
|
2541
|
+
ca_bincmp_call((VALUE) &k);
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2440
2544
|
ALLOCV_END(h_shared);
|
|
2441
2545
|
}
|
|
2442
2546
|
else {
|
|
@@ -2470,11 +2574,10 @@ rb_ca_call_bincmp (volatile VALUE self, volatile VALUE other,
|
|
|
2470
2574
|
k.p2 = p2; k.b2 = ca2->bytes; k.i2 = i2;
|
|
2471
2575
|
k.p3 = ca3->ptr; k.b3 = ca3->bytes; k.i3 = i3;
|
|
2472
2576
|
k.tol = tol;
|
|
2473
|
-
if ( (
|
|
2474
|
-
ca_bincmp_may_raise(func, ca1->data_type) ) {
|
|
2577
|
+
if ( ca_bincmp_may_raise(func, ca1->data_type) ) {
|
|
2475
2578
|
held[0] = attached1 ? ca1 : NULL;
|
|
2476
2579
|
held[1] = attached2 ? ca2 : NULL;
|
|
2477
|
-
ca_op_guarded(ca_bincmp_call, &k, 2, held, "rr");
|
|
2580
|
+
ca_op_guarded(ca_bincmp_call, &k, 2, held, "rr", (CArray *[]){ ca1, ca2 });
|
|
2478
2581
|
}
|
|
2479
2582
|
else {
|
|
2480
2583
|
ca_bincmp_call((VALUE) &k);
|
data/ext/carray_order.c
CHANGED
|
@@ -899,8 +899,9 @@ ca_topk_stable (VALUE self, VALUE picked, long axis, int desc)
|
|
|
899
899
|
for (k = 0; k < ndim; k++) inv[NUM2INT(perm[k])] = INT2FIX(k);
|
|
900
900
|
}
|
|
901
901
|
/* An entity whose fibers already lie along its last axis is read in
|
|
902
|
-
place; anything else is copied into that layout
|
|
903
|
-
|
|
902
|
+
place; anything else is copied into that layout, as is an entity
|
|
903
|
+
that leaves ptr NULL at rest (a CASource). */
|
|
904
|
+
if ( last && ca_is_entity(cv) && cv->ptr ) {
|
|
904
905
|
vals = key;
|
|
905
906
|
ca_update_mask(cv);
|
|
906
907
|
}
|
data/ext/carray_random.c
CHANGED
|
@@ -525,7 +525,10 @@ ca_randomn_bang_fill (VALUE arg)
|
|
|
525
525
|
CA_U(double) *p = (CA_U(double) *)ca->ptr;
|
|
526
526
|
ca_size_t pairs = n / 2;
|
|
527
527
|
for (i = 0; i < pairs; i++) {
|
|
528
|
-
|
|
528
|
+
double r1, r2;
|
|
529
|
+
box_muller_pair(&c->source, &r1, &r2);
|
|
530
|
+
p[2*i] = r1;
|
|
531
|
+
p[2*i+1] = r2;
|
|
529
532
|
}
|
|
530
533
|
if (n % 2 == 1) {
|
|
531
534
|
double r1, r2;
|
data/ext/carray_slab.c
CHANGED
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
Internals:
|
|
15
15
|
- ca_slab_iter_state_t (see carray_slab.h) is the per-call state struct.
|
|
16
|
-
- Each entry point
|
|
16
|
+
- Each entry point heap-allocates a zeroed state under a window guard
|
|
17
|
+
(slab_state_new), populates it via
|
|
17
18
|
slab_state_init (= nofail; only validation + scalar field fills),
|
|
18
19
|
then rb_ensure-runs slab_state_run_body (= acquires T1 substrate +
|
|
19
20
|
scratch + output, runs per-form loop) and slab_state_finish (= frees
|
|
@@ -21,9 +22,8 @@
|
|
|
21
22
|
- All heap acquisition lives in run_body so init-time rb_raise paths
|
|
22
23
|
cannot leak; rb_ensure guarantees finish on both normal and
|
|
23
24
|
exception exit.
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
not Ruby-wrapped.
|
|
25
|
+
- The guard marks the state's VALUE fields, and runs slab_state_finish
|
|
26
|
+
from a finalizer if the block's Fiber is abandoned mid-walk.
|
|
27
27
|
|
|
28
28
|
--------------------------------------------------------------------------- */
|
|
29
29
|
|
|
@@ -122,9 +122,9 @@ slab_state_init (ca_slab_iter_state_t *st, VALUE source, int8_t form,
|
|
|
122
122
|
{
|
|
123
123
|
CArray *src;
|
|
124
124
|
|
|
125
|
-
/*
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
/* The state arrives zeroed, which leaves VALUE fields Qfalse (= 0).
|
|
126
|
+
Body code uses `== Qnil` to distinguish unset slots from populated
|
|
127
|
+
CArray handles, so we must promote them to Qnil here. */
|
|
128
128
|
st->self = Qnil;
|
|
129
129
|
st->slab_view = Qnil;
|
|
130
130
|
st->carrier = Qnil;
|
|
@@ -526,8 +526,12 @@ ca_slab_advance_slab_view (ca_slab_iter_state_t *st,
|
|
|
526
526
|
if ( slab_cs->mask != NULL ) {
|
|
527
527
|
CAStride *mask_cs = (CAStride *) slab_cs->mask;
|
|
528
528
|
if ( m_in != NULL ) {
|
|
529
|
+
/* m_in points into the walk's copy of the source's mask, not into
|
|
530
|
+
the source's mask itself, so the offset is taken from the data
|
|
531
|
+
cell: it is what the slab reads once the copy is gone. */
|
|
529
532
|
mask_cs->ptr = (char *) m_in;
|
|
530
|
-
mask_cs->base_offset = (ca_size_t) ((
|
|
533
|
+
mask_cs->base_offset = (ca_size_t) ((p_in - src->ptr) / src->bytes)
|
|
534
|
+
* src->mask->bytes;
|
|
531
535
|
}
|
|
532
536
|
else {
|
|
533
537
|
/* The walk was opened on a source without a mask and the block
|
|
@@ -1202,7 +1206,9 @@ slab_state_run_body (VALUE arg)
|
|
|
1202
1206
|
held by the carrier, and the internal output view lets go of its
|
|
1203
1207
|
buffer. The copy is made into the array ca_slab_prepare_backing set
|
|
1204
1208
|
aside, so nothing here allocates. A slab that is a window onto the
|
|
1205
|
-
source
|
|
1209
|
+
source keeps reading the source's data, but its mask points into the
|
|
1210
|
+
walk's copy of the mask, which finish frees: it lets go of that copy
|
|
1211
|
+
and reads the source's mask from then on. */
|
|
1206
1212
|
static void
|
|
1207
1213
|
slab_state_release_views (ca_slab_iter_state_t *st)
|
|
1208
1214
|
{
|
|
@@ -1211,6 +1217,13 @@ slab_state_release_views (ca_slab_iter_state_t *st)
|
|
|
1211
1217
|
TypedData_Get_Struct(st->output_slab_view, CArray, &carray_data_type, ov);
|
|
1212
1218
|
ov->ptr = NULL;
|
|
1213
1219
|
}
|
|
1220
|
+
if ( st->carrier == Qnil && st->slab_view != Qnil ) {
|
|
1221
|
+
CArray *cs;
|
|
1222
|
+
TypedData_Get_Struct(st->slab_view, CArray, &carray_data_type, cs);
|
|
1223
|
+
if ( cs->mask ) {
|
|
1224
|
+
cs->mask->ptr = NULL;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1214
1227
|
if ( st->carrier != Qnil && st->slab_view != Qnil ) {
|
|
1215
1228
|
CArray *cw, *cs, *backing;
|
|
1216
1229
|
volatile VALUE bv;
|
|
@@ -1275,6 +1288,72 @@ slab_state_finish (VALUE arg)
|
|
|
1275
1288
|
/* Entry points: CArray#map_slab / #reduce_slab / #each_slab */
|
|
1276
1289
|
/* ------------------------------------------------------------------- */
|
|
1277
1290
|
|
|
1291
|
+
/* The walk yields to the block with its windows open. The state lives on
|
|
1292
|
+
the heap under a window guard, so that if the block's Fiber is abandoned
|
|
1293
|
+
(an Enumerator stopped with #next and dropped) the guard's finalizer
|
|
1294
|
+
still runs slab_state_finish and the source is let go. */
|
|
1295
|
+
|
|
1296
|
+
static void
|
|
1297
|
+
slab_state_mark (void *p)
|
|
1298
|
+
{
|
|
1299
|
+
ca_slab_iter_state_t *st = (ca_slab_iter_state_t *) p;
|
|
1300
|
+
rb_gc_mark(st->self);
|
|
1301
|
+
rb_gc_mark(st->slab_view);
|
|
1302
|
+
rb_gc_mark(st->carrier);
|
|
1303
|
+
rb_gc_mark(st->mask_carrier);
|
|
1304
|
+
rb_gc_mark(st->output);
|
|
1305
|
+
rb_gc_mark(st->output_slab_view);
|
|
1306
|
+
rb_gc_mark(st->init_val);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
static void
|
|
1310
|
+
slab_state_finish_abandoned (void *p)
|
|
1311
|
+
{
|
|
1312
|
+
slab_state_finish((VALUE)(uintptr_t) p);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
typedef struct {
|
|
1316
|
+
ca_slab_iter_state_t *st;
|
|
1317
|
+
VALUE guard;
|
|
1318
|
+
VALUE sentinel;
|
|
1319
|
+
} slab_run_t;
|
|
1320
|
+
|
|
1321
|
+
static VALUE
|
|
1322
|
+
slab_run_body (VALUE arg)
|
|
1323
|
+
{
|
|
1324
|
+
return slab_state_run_body((VALUE)(uintptr_t) ((slab_run_t *) arg)->st);
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
static VALUE
|
|
1328
|
+
slab_run_close (VALUE arg)
|
|
1329
|
+
{
|
|
1330
|
+
slab_run_t *r = (slab_run_t *) arg;
|
|
1331
|
+
ca_window_guard_disarm(r->guard, r->sentinel);
|
|
1332
|
+
return slab_state_finish((VALUE)(uintptr_t) r->st);
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
/* Allocates the state; slab_state_init fills it, then slab_run walks. */
|
|
1336
|
+
static ca_slab_iter_state_t *
|
|
1337
|
+
slab_state_new (slab_run_t *r)
|
|
1338
|
+
{
|
|
1339
|
+
ca_slab_iter_state_t *st = ZALLOC(ca_slab_iter_state_t);
|
|
1340
|
+
st->self = st->slab_view = st->carrier = st->mask_carrier = Qnil;
|
|
1341
|
+
st->output = st->output_slab_view = st->init_val = Qnil;
|
|
1342
|
+
r->st = st;
|
|
1343
|
+
r->guard = ca_window_guard_arm(slab_state_finish_abandoned, slab_state_mark,
|
|
1344
|
+
st, &r->sentinel);
|
|
1345
|
+
return st;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
static VALUE
|
|
1349
|
+
slab_run (slab_run_t *r)
|
|
1350
|
+
{
|
|
1351
|
+
VALUE result = rb_ensure(slab_run_body, (VALUE) r, slab_run_close, (VALUE) r);
|
|
1352
|
+
RB_GC_GUARD(r->guard);
|
|
1353
|
+
RB_GC_GUARD(r->sentinel);
|
|
1354
|
+
return result;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1278
1357
|
/* Shared kwarg parse: returns axis (required) + data_type / init via
|
|
1279
1358
|
out-params. init_out is set to Qundef if the `:init` key was absent
|
|
1280
1359
|
(= caller distinguishes per-slab vs per-element reduce forms). */
|
|
@@ -1322,7 +1401,7 @@ slab_extract_kwargs (int argc, VALUE *argv, const char *method_name)
|
|
|
1322
1401
|
static VALUE
|
|
1323
1402
|
rb_ca_map_slab (int argc, VALUE *argv, VALUE self)
|
|
1324
1403
|
{
|
|
1325
|
-
|
|
1404
|
+
slab_run_t r;
|
|
1326
1405
|
VALUE kw, axis, data_type, init_unused;
|
|
1327
1406
|
VALUE result;
|
|
1328
1407
|
|
|
@@ -1335,10 +1414,9 @@ rb_ca_map_slab (int argc, VALUE *argv, VALUE self)
|
|
|
1335
1414
|
rb_raise(rb_eLocalJumpError, "CArray#map_slab: block required");
|
|
1336
1415
|
}
|
|
1337
1416
|
|
|
1338
|
-
slab_state_init(&
|
|
1417
|
+
slab_state_init(slab_state_new(&r), self, CA_SLAB_FORM_MAP, axis, data_type, Qundef);
|
|
1339
1418
|
|
|
1340
|
-
result =
|
|
1341
|
-
slab_state_finish, (VALUE)(uintptr_t)&st);
|
|
1419
|
+
result = slab_run(&r);
|
|
1342
1420
|
RB_GC_GUARD(self);
|
|
1343
1421
|
return result;
|
|
1344
1422
|
}
|
|
@@ -1346,7 +1424,7 @@ rb_ca_map_slab (int argc, VALUE *argv, VALUE self)
|
|
|
1346
1424
|
static VALUE
|
|
1347
1425
|
rb_ca_reduce_slab (int argc, VALUE *argv, VALUE self)
|
|
1348
1426
|
{
|
|
1349
|
-
|
|
1427
|
+
slab_run_t r;
|
|
1350
1428
|
VALUE kw, axis, data_type, init_val;
|
|
1351
1429
|
VALUE result;
|
|
1352
1430
|
int8_t form;
|
|
@@ -1364,10 +1442,9 @@ rb_ca_reduce_slab (int argc, VALUE *argv, VALUE self)
|
|
|
1364
1442
|
form = (init_val == Qundef) ? CA_SLAB_FORM_REDUCE_SLAB
|
|
1365
1443
|
: CA_SLAB_FORM_REDUCE_FIBER;
|
|
1366
1444
|
|
|
1367
|
-
slab_state_init(&
|
|
1445
|
+
slab_state_init(slab_state_new(&r), self, form, axis, data_type, init_val);
|
|
1368
1446
|
|
|
1369
|
-
result =
|
|
1370
|
-
slab_state_finish, (VALUE)(uintptr_t)&st);
|
|
1447
|
+
result = slab_run(&r);
|
|
1371
1448
|
RB_GC_GUARD(self);
|
|
1372
1449
|
return result;
|
|
1373
1450
|
}
|
|
@@ -1375,7 +1452,7 @@ rb_ca_reduce_slab (int argc, VALUE *argv, VALUE self)
|
|
|
1375
1452
|
static VALUE
|
|
1376
1453
|
rb_ca_each_slab (int argc, VALUE *argv, VALUE self)
|
|
1377
1454
|
{
|
|
1378
|
-
|
|
1455
|
+
slab_run_t r;
|
|
1379
1456
|
VALUE kw, axis, data_type_unused, init_unused;
|
|
1380
1457
|
VALUE result;
|
|
1381
1458
|
|
|
@@ -1397,10 +1474,9 @@ rb_ca_each_slab (int argc, VALUE *argv, VALUE self)
|
|
|
1397
1474
|
2, args, RB_PASS_KEYWORDS);
|
|
1398
1475
|
}
|
|
1399
1476
|
|
|
1400
|
-
slab_state_init(&
|
|
1477
|
+
slab_state_init(slab_state_new(&r), self, CA_SLAB_FORM_EACH, axis, Qnil, Qundef);
|
|
1401
1478
|
|
|
1402
|
-
result =
|
|
1403
|
-
slab_state_finish, (VALUE)(uintptr_t)&st);
|
|
1479
|
+
result = slab_run(&r);
|
|
1404
1480
|
RB_GC_GUARD(self);
|
|
1405
1481
|
return result;
|
|
1406
1482
|
}
|
data/ext/carray_sort.c
CHANGED
|
@@ -156,7 +156,7 @@ static void \
|
|
|
156
156
|
msd_refine_##SUFFIX (CArray *key, ca_size_t *perm, void *vbuf, \
|
|
157
157
|
msd_runs_t *in, msd_runs_t *out, int masked_last) \
|
|
158
158
|
{ \
|
|
159
|
-
const TYPE *ptr = (const TYPE *) key->ptr;
|
|
159
|
+
const CA_U(TYPE) *ptr = (const CA_U(TYPE) *) key->ptr; \
|
|
160
160
|
const boolean8_t *m = ( key->mask ) ? (boolean8_t *) key->mask->ptr : NULL; \
|
|
161
161
|
ca_pair_##SUFFIX *buf = (ca_pair_##SUFFIX *) vbuf; \
|
|
162
162
|
ca_size_t r; \
|