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/ca_kernel_iterator.c
CHANGED
|
@@ -554,13 +554,54 @@ ca_iter_strip_storage_wrapper (CArray *src)
|
|
|
554
554
|
}
|
|
555
555
|
|
|
556
556
|
int
|
|
557
|
-
|
|
557
|
+
ca_iter_check_init (int rc)
|
|
558
|
+
{
|
|
559
|
+
const char *why;
|
|
560
|
+
|
|
561
|
+
if ( rc == CA_ITER_OK ) return rc;
|
|
562
|
+
|
|
563
|
+
switch ( rc ) {
|
|
564
|
+
case CA_ITER_ERR_NOT_CHEAP:
|
|
565
|
+
why = "the source cannot be read without materialising it";
|
|
566
|
+
break;
|
|
567
|
+
case CA_ITER_ERR_POLICY:
|
|
568
|
+
why = "the slab policy or the axes given do not apply to this source";
|
|
569
|
+
break;
|
|
570
|
+
case CA_ITER_ERR_FLAGS:
|
|
571
|
+
why = "this flag combination is not supported for this source";
|
|
572
|
+
break;
|
|
573
|
+
case CA_ITER_ERR_READONLY:
|
|
574
|
+
why = "the array is read-only and the kernel asked to write";
|
|
575
|
+
break;
|
|
576
|
+
case CA_ITER_ERR_MASK:
|
|
577
|
+
why = "the source carries a mask";
|
|
578
|
+
break;
|
|
579
|
+
case CA_ITER_ERR_MASK_NOT_ALLOWED:
|
|
580
|
+
why = "the kernel declared CA_KERNEL_NO_MASK and the source carries a mask";
|
|
581
|
+
break;
|
|
582
|
+
default:
|
|
583
|
+
why = "the request was refused";
|
|
584
|
+
break;
|
|
585
|
+
}
|
|
586
|
+
rb_raise(rb_eRuntimeError, "kernel iterator: %s (rc=%d)", why, rc);
|
|
587
|
+
return rc; /* not reached */
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
static int
|
|
591
|
+
ca_iter_state_init_l1_unprotected (ca_iter_state *st,
|
|
558
592
|
struct _CArray *src,
|
|
559
593
|
ca_slab_policy_t policy,
|
|
560
594
|
int8_t *axes,
|
|
561
595
|
int8_t naxes,
|
|
562
596
|
uint32_t flags)
|
|
563
597
|
{
|
|
598
|
+
/* Leave the state defined before anything can return. Every error
|
|
599
|
+
return below hands control back to a caller that may not look at the
|
|
600
|
+
code, so what it is left holding has to be a state that iterates zero
|
|
601
|
+
times rather than whatever its stack frame happened to contain. */
|
|
602
|
+
if ( st == NULL ) return CA_ITER_ERR_FLAGS;
|
|
603
|
+
memset(st, 0, sizeof(*st));
|
|
604
|
+
|
|
564
605
|
/* PROPOSAL_CAFACE_PHASE_2 F.2.6 + PROPOSAL_LAZY_MARKER_LIFT Phase 0:
|
|
565
606
|
storage-identical wrapper strip at entry (= same rationale as init_l2
|
|
566
607
|
below). Strip before validate_inputs.
|
|
@@ -586,7 +627,6 @@ ca_iter_state_init_l1 (ca_iter_state *st,
|
|
|
586
627
|
|
|
587
628
|
uint8_t src_kind = ca_iter_classify_source(src);
|
|
588
629
|
|
|
589
|
-
memset(st, 0, sizeof(*st));
|
|
590
630
|
st->src = src;
|
|
591
631
|
st->src_kind = src_kind;
|
|
592
632
|
st->level = 1;
|
|
@@ -740,14 +780,21 @@ ca_iter_state_init_l1 (ca_iter_state *st,
|
|
|
740
780
|
return CA_ITER_OK;
|
|
741
781
|
}
|
|
742
782
|
|
|
743
|
-
int
|
|
744
|
-
|
|
783
|
+
static int
|
|
784
|
+
ca_iter_state_init_l2_unprotected (ca_iter_state *st,
|
|
745
785
|
struct _CArray *src,
|
|
746
786
|
ca_slab_policy_t policy,
|
|
747
787
|
int8_t *axes,
|
|
748
788
|
int8_t naxes,
|
|
749
789
|
uint32_t flags)
|
|
750
790
|
{
|
|
791
|
+
/* Leave the state defined before anything can return. Every error
|
|
792
|
+
return below hands control back to a caller that may not look at the
|
|
793
|
+
code, so what it is left holding has to be a state that iterates zero
|
|
794
|
+
times rather than whatever its stack frame happened to contain. */
|
|
795
|
+
if ( st == NULL ) return CA_ITER_ERR_FLAGS;
|
|
796
|
+
memset(st, 0, sizeof(*st));
|
|
797
|
+
|
|
751
798
|
/* PROPOSAL_CAFACE_PHASE_2 F.2.6 (= MEMO §3.5 kernel_iterator entry strip)
|
|
752
799
|
+ PROPOSAL_LAZY_MARKER_LIFT Phase 0.
|
|
753
800
|
|
|
@@ -828,7 +875,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
828
875
|
if ( ca_iter_should_per_fiber_fused(src, src_kind, fiber_ax,
|
|
829
876
|
row_byte_strides[fiber_ax],
|
|
830
877
|
flags) ) {
|
|
831
|
-
memset(st, 0, sizeof(*st));
|
|
832
878
|
st->src = src;
|
|
833
879
|
st->src_kind = src_kind;
|
|
834
880
|
st->level = 2;
|
|
@@ -922,7 +968,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
922
968
|
return CA_ITER_ERR_FLAGS;
|
|
923
969
|
}
|
|
924
970
|
|
|
925
|
-
memset(st, 0, sizeof(*st));
|
|
926
971
|
st->src = src;
|
|
927
972
|
st->src_kind = CA_ITER_SRC_DESCRIPTOR;
|
|
928
973
|
st->level = 2;
|
|
@@ -1091,7 +1136,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1091
1136
|
}
|
|
1092
1137
|
|
|
1093
1138
|
if ( outer_has_shift ) {
|
|
1094
|
-
memset(st, 0, sizeof(*st));
|
|
1095
1139
|
st->src = src;
|
|
1096
1140
|
st->src_kind = CA_ITER_SRC_DESCRIPTOR;
|
|
1097
1141
|
st->level = 2;
|
|
@@ -1185,7 +1229,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1185
1229
|
return CA_ITER_OK;
|
|
1186
1230
|
}
|
|
1187
1231
|
|
|
1188
|
-
memset(st, 0, sizeof(*st));
|
|
1189
1232
|
st->src = src;
|
|
1190
1233
|
st->src_kind = CA_ITER_SRC_DESCRIPTOR; /* Phase B alias path */
|
|
1191
1234
|
st->level = 2;
|
|
@@ -1333,7 +1376,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1333
1376
|
in_slab[ax] = 1;
|
|
1334
1377
|
}
|
|
1335
1378
|
|
|
1336
|
-
memset(st, 0, sizeof(*st));
|
|
1337
1379
|
st->src = src;
|
|
1338
1380
|
st->src_kind = CA_ITER_SRC_ATTACH;
|
|
1339
1381
|
st->level = 2;
|
|
@@ -1386,6 +1428,7 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1386
1428
|
k_axis..N-2]; either way outer_idx[m] = parent axis m). */
|
|
1387
1429
|
if ( ca_func[src->obj_type].attach == ca_stack_func.attach
|
|
1388
1430
|
&& !ca_has_mask(src)
|
|
1431
|
+
&& !(flags & CA_KERNEL_WRITE)
|
|
1389
1432
|
&& naxes == 1 && axes[0] == ((CAStack *) src)->k_axis ) {
|
|
1390
1433
|
CAStack *stack = (CAStack *) src;
|
|
1391
1434
|
int8_t parent_ndim = src->ndim - 1;
|
|
@@ -1501,6 +1544,7 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1501
1544
|
s - 1); only the K stack axis (s == k_axis) has no parent
|
|
1502
1545
|
counterpart. */
|
|
1503
1546
|
if ( ca_func[src->obj_type].attach == ca_stack_func.attach
|
|
1547
|
+
&& !(flags & CA_KERNEL_WRITE)
|
|
1504
1548
|
&& naxes >= 1 && !in_slab[((CAStack *) src)->k_axis] ) {
|
|
1505
1549
|
CAStack *stack = (CAStack *) src;
|
|
1506
1550
|
int8_t k_axis = stack->k_axis;
|
|
@@ -1721,7 +1765,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1721
1765
|
/ CATile / CARoll). Same shape as L1 SRC_ATTACH: iterator-owns
|
|
1722
1766
|
scratch + xfer_all GET/PUT. Yield as one 1-D strided slab. */
|
|
1723
1767
|
if ( src_kind == CA_ITER_SRC_ATTACH ) {
|
|
1724
|
-
memset(st, 0, sizeof(*st));
|
|
1725
1768
|
st->src = src;
|
|
1726
1769
|
st->src_kind = CA_ITER_SRC_ATTACH;
|
|
1727
1770
|
st->level = 2;
|
|
@@ -1773,7 +1816,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1773
1816
|
int8_t nd = raw_ndim;
|
|
1774
1817
|
int8_t k;
|
|
1775
1818
|
|
|
1776
|
-
memset(st, 0, sizeof(*st));
|
|
1777
1819
|
st->src = src;
|
|
1778
1820
|
st->src_kind = CA_ITER_SRC_DESCRIPTOR_L2_ALIASABLE;
|
|
1779
1821
|
st->level = 2;
|
|
@@ -1864,7 +1906,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1864
1906
|
/* raw_descs / raw_pdims / raw_ndim were populated by route_source
|
|
1865
1907
|
above so we skip the local describe_axes call. Kept locals
|
|
1866
1908
|
named raw_* to match the original code. */
|
|
1867
|
-
memset(st, 0, sizeof(*st));
|
|
1868
1909
|
st->src = src;
|
|
1869
1910
|
st->src_kind = CA_ITER_SRC_DESCRIPTOR;
|
|
1870
1911
|
st->level = 2;
|
|
@@ -1938,7 +1979,6 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
1938
1979
|
}
|
|
1939
1980
|
|
|
1940
1981
|
/* === CAStride / entity L2 path === */
|
|
1941
|
-
memset(st, 0, sizeof(*st));
|
|
1942
1982
|
st->src = src;
|
|
1943
1983
|
st->src_kind = CA_ITER_SRC_CASTRIDE;
|
|
1944
1984
|
st->level = 2;
|
|
@@ -2139,8 +2179,8 @@ ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
2139
2179
|
return CA_ITER_OK;
|
|
2140
2180
|
}
|
|
2141
2181
|
|
|
2142
|
-
int
|
|
2143
|
-
|
|
2182
|
+
static int
|
|
2183
|
+
ca_iter_state_next_slab_unprotected (ca_iter_state *st,
|
|
2144
2184
|
char **out_ptr,
|
|
2145
2185
|
boolean8_t **out_mask,
|
|
2146
2186
|
ca_size_t *out_n)
|
|
@@ -2162,8 +2202,8 @@ ca_iter_state_next_slab (ca_iter_state *st,
|
|
|
2162
2202
|
return 1;
|
|
2163
2203
|
}
|
|
2164
2204
|
|
|
2165
|
-
int
|
|
2166
|
-
|
|
2205
|
+
static int
|
|
2206
|
+
ca_iter_state_next_slab_strided_unprotected (ca_iter_state *st,
|
|
2167
2207
|
char **out_ptr,
|
|
2168
2208
|
boolean8_t **out_mask,
|
|
2169
2209
|
ca_size_t *out_n,
|
|
@@ -2231,8 +2271,8 @@ ca_iter_state_next_slab_strided (ca_iter_state *st,
|
|
|
2231
2271
|
return 1;
|
|
2232
2272
|
}
|
|
2233
2273
|
|
|
2234
|
-
int
|
|
2235
|
-
|
|
2274
|
+
static int
|
|
2275
|
+
ca_iter_state_next_slab_axes_unprotected (ca_iter_state *st,
|
|
2236
2276
|
char **out_ptr,
|
|
2237
2277
|
boolean8_t **out_mask)
|
|
2238
2278
|
{
|
|
@@ -2742,38 +2782,22 @@ ca_iter_state_next_slab_axes (ca_iter_state *st,
|
|
|
2742
2782
|
return 1;
|
|
2743
2783
|
}
|
|
2744
2784
|
|
|
2745
|
-
void
|
|
2746
|
-
|
|
2785
|
+
static void
|
|
2786
|
+
ca_iter_state_sync_slab_unprotected (ca_iter_state *st)
|
|
2747
2787
|
{
|
|
2748
2788
|
/* READ walk: nothing to sync. */
|
|
2749
2789
|
if ( st == NULL || !(st->flags & CA_KERNEL_WRITE) ) return;
|
|
2750
2790
|
|
|
2751
|
-
/*
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2791
|
+
/* Neither stack mode can be reached with WRITE set: both are declined
|
|
2792
|
+
at init, which sends a write destination down the generic SRC_ATTACH
|
|
2793
|
+
path instead. They cannot serve a write themselves -- ALIAS_STACK
|
|
2794
|
+
hands out a tile cache that finish frees, and STACK_OUTER_K aliases
|
|
2795
|
+
parents[k]->ptr, which is the attach buffer rather than the parent's
|
|
2796
|
+
own memory whenever the parent is a view. Scattering per parent
|
|
2797
|
+
would let the fast paths carry writes too; until then this branch is
|
|
2798
|
+
just the assertion that they are not asked to. */
|
|
2757
2799
|
if ( st->alias_mode == CA_ITER_ALIAS_STACK
|
|
2758
2800
|
|| st->alias_mode == CA_ITER_ALIAS_STACK_OUTER_K ) {
|
|
2759
|
-
/* STACK_OUTER_K (P.2 Case A) is READ-only scope: slabs are direct
|
|
2760
|
-
aliases into parents[k]->ptr, kernel WRITE would scatter into
|
|
2761
|
-
parent memory which is out of scope (see proposal R1). Skip
|
|
2762
|
-
sync. */
|
|
2763
|
-
st->write_dirty = 0;
|
|
2764
|
-
return;
|
|
2765
|
-
}
|
|
2766
|
-
|
|
2767
|
-
/* SRC_ATTACH path (step 9 + 2026-05-31 refactor): kernel wrote into
|
|
2768
|
-
iterator-owned scratch (= scratch_ptr). Push back via xfer_all PUT
|
|
2769
|
-
which routes through the view's xfer_all slot -- handles CAFake
|
|
2770
|
-
(cast back), CAByteSwap (swap back), CABitfield/CABitarray (bit
|
|
2771
|
-
pack back), CAReduce (broadcast across reduce window). Inherits
|
|
2772
|
-
transform-fused / partial materialise / etc. automatically. */
|
|
2773
|
-
if ( st->src_kind == CA_ITER_SRC_ATTACH ) {
|
|
2774
|
-
if ( st->src->elements > 0 ) {
|
|
2775
|
-
ca_xfer_all(st->src, st->scratch_ptr, CA_XFER_PUT);
|
|
2776
|
-
}
|
|
2777
2801
|
st->write_dirty = 0;
|
|
2778
2802
|
return;
|
|
2779
2803
|
}
|
|
@@ -2852,12 +2876,32 @@ ca_iter_state_sync_slab (ca_iter_state *st)
|
|
|
2852
2876
|
ca_stride_scatter_run(dst, st->fiber_data_scratch,
|
|
2853
2877
|
bytes, n, data_step);
|
|
2854
2878
|
}
|
|
2855
|
-
/* Fall through
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2879
|
+
/* Fall through. The gather above is not specific to a src_kind --
|
|
2880
|
+
it fires for any source whose fiber is not innermost-contig -- so
|
|
2881
|
+
for SRC_ATTACH this has just written the fiber back into the
|
|
2882
|
+
whole-view scratch, and the push-back below carries it to the
|
|
2883
|
+
source. For the alias paths scratch_ptr is NULL and the switch
|
|
2884
|
+
below early-returns. */
|
|
2885
|
+
}
|
|
2886
|
+
|
|
2887
|
+
/* SRC_ATTACH path (step 9 + 2026-05-31 refactor): kernel wrote into
|
|
2888
|
+
iterator-owned scratch (= scratch_ptr). Push back via xfer_all PUT
|
|
2889
|
+
which routes through the view's xfer_all slot -- handles CAFake
|
|
2890
|
+
(cast back), CAByteSwap (swap back), CABitfield/CABitarray (bit
|
|
2891
|
+
pack back), CAReduce (broadcast across reduce window). Inherits
|
|
2892
|
+
transform-fused / partial materialise / etc. automatically.
|
|
2893
|
+
|
|
2894
|
+
This has to stay below the two per-fiber blocks: consulting
|
|
2895
|
+
src_kind first would push back the whole-view buffer while the
|
|
2896
|
+
fiber the author actually wrote sat unscattered in
|
|
2897
|
+
fiber_data_scratch, and would push back a NULL one for
|
|
2898
|
+
PER_FIBER_FUSED, which owns no whole-view buffer at all. */
|
|
2899
|
+
if ( st->src_kind == CA_ITER_SRC_ATTACH ) {
|
|
2900
|
+
if ( st->src->elements > 0 ) {
|
|
2901
|
+
ca_xfer_all(st->src, st->scratch_ptr, CA_XFER_PUT);
|
|
2902
|
+
}
|
|
2903
|
+
st->write_dirty = 0;
|
|
2904
|
+
return;
|
|
2861
2905
|
}
|
|
2862
2906
|
|
|
2863
2907
|
/* alias path: kernel wrote through alias_ptr into parent directly
|
|
@@ -2996,6 +3040,228 @@ ca_iter_state_finish (ca_iter_state *st)
|
|
|
2996
3040
|
st->alias_ptr = NULL;
|
|
2997
3041
|
}
|
|
2998
3042
|
|
|
3043
|
+
/* ---- Raise-safe entry points ----------------------------------------
|
|
3044
|
+
*
|
|
3045
|
+
* A walk reads its source, and a source that converts as it is read (a
|
|
3046
|
+
* lazy view over an object array, say) raises when it meets a cell it
|
|
3047
|
+
* cannot convert. The caller's loop then never reaches
|
|
3048
|
+
* ca_iter_state_finish -- the block macros put it in the `for`
|
|
3049
|
+
* increment, which a raise jumps over, and it is past the raise in
|
|
3050
|
+
* hand-written walks too. So the walk finishes itself on the way out.
|
|
3051
|
+
*
|
|
3052
|
+
* Every entry point that can raise is called through rb_protect here,
|
|
3053
|
+
* and ca_iter_state_finish is idempotent (it clears st->src), so the
|
|
3054
|
+
* caller's own finish after an ordinary walk stays correct.
|
|
3055
|
+
*
|
|
3056
|
+
* Not covered: a kernel body that raises. It runs in the caller's
|
|
3057
|
+
* frame, between two calls of these functions, where the engine has no
|
|
3058
|
+
* hold on it. An object-lane kernel calling back into Ruby is the case
|
|
3059
|
+
* to watch.
|
|
3060
|
+
*
|
|
3061
|
+
* init runs protected always -- once per walk, next to a materialise.
|
|
3062
|
+
* next_slab / sync_slab are called once per slab, in walks whose whole
|
|
3063
|
+
* per-fiber cost can be a few nanoseconds, so they are protected only
|
|
3064
|
+
* when this walk can raise at all: when it gathers each fiber through
|
|
3065
|
+
* the source's own transfer slots, or when it writes scratch back
|
|
3066
|
+
* through them. Every other shape hands out pointers into memory that
|
|
3067
|
+
* init already materialised, and moves it with memcpy. */
|
|
3068
|
+
|
|
3069
|
+
/* Private flags bit, kept in ca_iter_state.flags rather than a field of
|
|
3070
|
+
its own: the state is stack-allocated by ext authors through the block
|
|
3071
|
+
macros, so growing it would overrun states built against an older
|
|
3072
|
+
header. */
|
|
3073
|
+
#define CA_ITER_FLAG_WALK_MAY_RAISE 0x80000000u
|
|
3074
|
+
|
|
3075
|
+
typedef struct {
|
|
3076
|
+
ca_iter_state *st;
|
|
3077
|
+
CArray *src;
|
|
3078
|
+
ca_slab_policy_t policy;
|
|
3079
|
+
int8_t *axes;
|
|
3080
|
+
int8_t naxes;
|
|
3081
|
+
uint32_t flags;
|
|
3082
|
+
char **out_ptr;
|
|
3083
|
+
boolean8_t **out_mask;
|
|
3084
|
+
ca_size_t *out_n;
|
|
3085
|
+
ca_size_t *out_stride_bytes;
|
|
3086
|
+
int rc;
|
|
3087
|
+
} ca_iter_call_t;
|
|
3088
|
+
|
|
3089
|
+
/* Whether next_slab / sync_slab on this walk need the protection. */
|
|
3090
|
+
static void
|
|
3091
|
+
ca_iter_mark_walk_may_raise (ca_iter_state *st)
|
|
3092
|
+
{
|
|
3093
|
+
if ( st == NULL ) return;
|
|
3094
|
+
if ( st->alias_mode == CA_ITER_ALIAS_PER_FIBER_FUSED ) {
|
|
3095
|
+
/* gathers each fiber through the source's xfer_stride slot */
|
|
3096
|
+
st->flags |= CA_ITER_FLAG_WALK_MAY_RAISE;
|
|
3097
|
+
}
|
|
3098
|
+
else if ( (st->flags & CA_KERNEL_WRITE)
|
|
3099
|
+
&& (st->scratch_ptr != NULL
|
|
3100
|
+
|| st->src_kind == CA_ITER_SRC_ATTACH) ) {
|
|
3101
|
+
/* writes back out of iterator-owned scratch, through the source's
|
|
3102
|
+
xfer_all / sync_data slot. A write into aliased memory needs no
|
|
3103
|
+
push-back at all: sync_slab returns at once. */
|
|
3104
|
+
st->flags |= CA_ITER_FLAG_WALK_MAY_RAISE;
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
|
|
3108
|
+
static void
|
|
3109
|
+
ca_iter_protect (ca_iter_state *st, VALUE (*body)(VALUE), VALUE arg)
|
|
3110
|
+
{
|
|
3111
|
+
int tag = 0;
|
|
3112
|
+
rb_protect(body, arg, &tag);
|
|
3113
|
+
if ( tag ) {
|
|
3114
|
+
ca_iter_state_finish(st);
|
|
3115
|
+
rb_jump_tag(tag);
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
|
|
3119
|
+
static VALUE
|
|
3120
|
+
ca_iter_call_init_l1 (VALUE arg)
|
|
3121
|
+
{
|
|
3122
|
+
ca_iter_call_t *c = (ca_iter_call_t *) arg;
|
|
3123
|
+
c->rc = ca_iter_state_init_l1_unprotected(c->st, c->src, c->policy,
|
|
3124
|
+
c->axes, c->naxes, c->flags);
|
|
3125
|
+
return Qnil;
|
|
3126
|
+
}
|
|
3127
|
+
|
|
3128
|
+
static VALUE
|
|
3129
|
+
ca_iter_call_init_l2 (VALUE arg)
|
|
3130
|
+
{
|
|
3131
|
+
ca_iter_call_t *c = (ca_iter_call_t *) arg;
|
|
3132
|
+
c->rc = ca_iter_state_init_l2_unprotected(c->st, c->src, c->policy,
|
|
3133
|
+
c->axes, c->naxes, c->flags);
|
|
3134
|
+
return Qnil;
|
|
3135
|
+
}
|
|
3136
|
+
|
|
3137
|
+
static VALUE
|
|
3138
|
+
ca_iter_call_next_slab (VALUE arg)
|
|
3139
|
+
{
|
|
3140
|
+
ca_iter_call_t *c = (ca_iter_call_t *) arg;
|
|
3141
|
+
c->rc = ca_iter_state_next_slab_unprotected(c->st, c->out_ptr,
|
|
3142
|
+
c->out_mask, c->out_n);
|
|
3143
|
+
return Qnil;
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3146
|
+
static VALUE
|
|
3147
|
+
ca_iter_call_next_slab_strided (VALUE arg)
|
|
3148
|
+
{
|
|
3149
|
+
ca_iter_call_t *c = (ca_iter_call_t *) arg;
|
|
3150
|
+
c->rc = ca_iter_state_next_slab_strided_unprotected(c->st, c->out_ptr,
|
|
3151
|
+
c->out_mask, c->out_n,
|
|
3152
|
+
c->out_stride_bytes);
|
|
3153
|
+
return Qnil;
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
static VALUE
|
|
3157
|
+
ca_iter_call_next_slab_axes (VALUE arg)
|
|
3158
|
+
{
|
|
3159
|
+
ca_iter_call_t *c = (ca_iter_call_t *) arg;
|
|
3160
|
+
c->rc = ca_iter_state_next_slab_axes_unprotected(c->st, c->out_ptr,
|
|
3161
|
+
c->out_mask);
|
|
3162
|
+
return Qnil;
|
|
3163
|
+
}
|
|
3164
|
+
|
|
3165
|
+
static VALUE
|
|
3166
|
+
ca_iter_call_sync_slab (VALUE arg)
|
|
3167
|
+
{
|
|
3168
|
+
ca_iter_call_t *c = (ca_iter_call_t *) arg;
|
|
3169
|
+
ca_iter_state_sync_slab_unprotected(c->st);
|
|
3170
|
+
return Qnil;
|
|
3171
|
+
}
|
|
3172
|
+
|
|
3173
|
+
int
|
|
3174
|
+
ca_iter_state_init_l1 (ca_iter_state *st,
|
|
3175
|
+
struct _CArray *src,
|
|
3176
|
+
ca_slab_policy_t policy,
|
|
3177
|
+
int8_t *axes,
|
|
3178
|
+
int8_t naxes,
|
|
3179
|
+
uint32_t flags)
|
|
3180
|
+
{
|
|
3181
|
+
ca_iter_call_t c;
|
|
3182
|
+
c.st = st; c.src = src; c.policy = policy;
|
|
3183
|
+
c.axes = axes; c.naxes = naxes; c.flags = flags; c.rc = CA_ITER_OK;
|
|
3184
|
+
ca_iter_protect(st, ca_iter_call_init_l1, (VALUE) &c);
|
|
3185
|
+
if ( c.rc == CA_ITER_OK ) ca_iter_mark_walk_may_raise(st);
|
|
3186
|
+
return c.rc;
|
|
3187
|
+
}
|
|
3188
|
+
|
|
3189
|
+
int
|
|
3190
|
+
ca_iter_state_init_l2 (ca_iter_state *st,
|
|
3191
|
+
struct _CArray *src,
|
|
3192
|
+
ca_slab_policy_t policy,
|
|
3193
|
+
int8_t *axes,
|
|
3194
|
+
int8_t naxes,
|
|
3195
|
+
uint32_t flags)
|
|
3196
|
+
{
|
|
3197
|
+
ca_iter_call_t c;
|
|
3198
|
+
c.st = st; c.src = src; c.policy = policy;
|
|
3199
|
+
c.axes = axes; c.naxes = naxes; c.flags = flags; c.rc = CA_ITER_OK;
|
|
3200
|
+
ca_iter_protect(st, ca_iter_call_init_l2, (VALUE) &c);
|
|
3201
|
+
if ( c.rc == CA_ITER_OK ) ca_iter_mark_walk_may_raise(st);
|
|
3202
|
+
return c.rc;
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3205
|
+
int
|
|
3206
|
+
ca_iter_state_next_slab (ca_iter_state *st,
|
|
3207
|
+
char **out_ptr,
|
|
3208
|
+
boolean8_t **out_mask,
|
|
3209
|
+
ca_size_t *out_n)
|
|
3210
|
+
{
|
|
3211
|
+
ca_iter_call_t c;
|
|
3212
|
+
if ( st == NULL || !(st->flags & CA_ITER_FLAG_WALK_MAY_RAISE) ) {
|
|
3213
|
+
return ca_iter_state_next_slab_unprotected(st, out_ptr, out_mask, out_n);
|
|
3214
|
+
}
|
|
3215
|
+
c.st = st; c.out_ptr = out_ptr; c.out_mask = out_mask; c.out_n = out_n;
|
|
3216
|
+
c.rc = 0;
|
|
3217
|
+
ca_iter_protect(st, ca_iter_call_next_slab, (VALUE) &c);
|
|
3218
|
+
return c.rc;
|
|
3219
|
+
}
|
|
3220
|
+
|
|
3221
|
+
int
|
|
3222
|
+
ca_iter_state_next_slab_strided (ca_iter_state *st,
|
|
3223
|
+
char **out_ptr,
|
|
3224
|
+
boolean8_t **out_mask,
|
|
3225
|
+
ca_size_t *out_n,
|
|
3226
|
+
ca_size_t *out_stride_bytes)
|
|
3227
|
+
{
|
|
3228
|
+
ca_iter_call_t c;
|
|
3229
|
+
if ( st == NULL || !(st->flags & CA_ITER_FLAG_WALK_MAY_RAISE) ) {
|
|
3230
|
+
return ca_iter_state_next_slab_strided_unprotected(st, out_ptr, out_mask,
|
|
3231
|
+
out_n, out_stride_bytes);
|
|
3232
|
+
}
|
|
3233
|
+
c.st = st; c.out_ptr = out_ptr; c.out_mask = out_mask; c.out_n = out_n;
|
|
3234
|
+
c.out_stride_bytes = out_stride_bytes; c.rc = 0;
|
|
3235
|
+
ca_iter_protect(st, ca_iter_call_next_slab_strided, (VALUE) &c);
|
|
3236
|
+
return c.rc;
|
|
3237
|
+
}
|
|
3238
|
+
|
|
3239
|
+
int
|
|
3240
|
+
ca_iter_state_next_slab_axes (ca_iter_state *st,
|
|
3241
|
+
char **out_ptr,
|
|
3242
|
+
boolean8_t **out_mask)
|
|
3243
|
+
{
|
|
3244
|
+
ca_iter_call_t c;
|
|
3245
|
+
if ( st == NULL || !(st->flags & CA_ITER_FLAG_WALK_MAY_RAISE) ) {
|
|
3246
|
+
return ca_iter_state_next_slab_axes_unprotected(st, out_ptr, out_mask);
|
|
3247
|
+
}
|
|
3248
|
+
c.st = st; c.out_ptr = out_ptr; c.out_mask = out_mask; c.rc = 0;
|
|
3249
|
+
ca_iter_protect(st, ca_iter_call_next_slab_axes, (VALUE) &c);
|
|
3250
|
+
return c.rc;
|
|
3251
|
+
}
|
|
3252
|
+
|
|
3253
|
+
void
|
|
3254
|
+
ca_iter_state_sync_slab (ca_iter_state *st)
|
|
3255
|
+
{
|
|
3256
|
+
ca_iter_call_t c;
|
|
3257
|
+
if ( st == NULL || !(st->flags & CA_ITER_FLAG_WALK_MAY_RAISE) ) {
|
|
3258
|
+
ca_iter_state_sync_slab_unprotected(st);
|
|
3259
|
+
return;
|
|
3260
|
+
}
|
|
3261
|
+
c.st = st;
|
|
3262
|
+
ca_iter_protect(st, ca_iter_call_sync_slab, (VALUE) &c);
|
|
3263
|
+
}
|
|
3264
|
+
|
|
2999
3265
|
#ifdef CARRAY_DEV_BUILD
|
|
3000
3266
|
/* ============================================================
|
|
3001
3267
|
* smoke surface (dev-only, stripped in release)
|