carray 3.0.1 → 3.0.3
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 +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -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/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_kernel_iterator.h
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
CA_SLAB_REDUCE_* / _MAP_* / _SCAN_* suites, CA_L2_FOR_EACH,
|
|
16
16
|
CA_*_UNMASKED helpers)
|
|
17
17
|
- the raw-API entry points the macros expand to: ca_iter_state_
|
|
18
|
-
init_l2 / next_slab_axes / sync_slab / finish
|
|
18
|
+
init_l2 / init_l2_paired / next_slab_axes / sync_slab / finish /
|
|
19
|
+
close, ca_iter_check_init, ca_iter_check_same_shape
|
|
19
20
|
- the enum/status tokens authors write literally: CA_SLAB_AXES,
|
|
20
21
|
CA_KERNEL_WRITE, CA_KERNEL_NO_MASK, CA_ITER_OK, CA_ITER_ERR_*
|
|
21
22
|
- the slab-delivery representation = the ca_iter_state fields a
|
|
@@ -41,21 +42,6 @@
|
|
|
41
42
|
devel/MEMO_KERNEL_ITERATOR_OOP_PATH.vev4.md for the planned engine
|
|
42
43
|
overhaul this contract insulates against.)
|
|
43
44
|
|
|
44
|
-
Step 1 scope (this commit):
|
|
45
|
-
- struct definition (subset used by step 1; chunk_pos / scratch /
|
|
46
|
-
descs / outer_idx fields are present but unused, reserved for
|
|
47
|
-
later steps per proposal §3.1)
|
|
48
|
-
- CA_SLAB_WHOLE policy only (single slab = whole array)
|
|
49
|
-
- alias path only: ca_attach_is_alias(src) must hold, else init
|
|
50
|
-
returns CA_ITER_ERR_NOT_CHEAP (renamed from ca_attach_is_cheap
|
|
51
|
-
in T1 step 9.4a)
|
|
52
|
-
- READ-only, no mask handling, no WRITE sync
|
|
53
|
-
|
|
54
|
-
Later steps will fill in scratch materialize (step 2), L2 strided
|
|
55
|
-
(step 3), WRITE + sync_slab (step 4), descriptor 6-view connection
|
|
56
|
-
via P3 ca_axis_dispatch_for_each_slab (step 5), mask + macros
|
|
57
|
-
(step 6), NO_MASK enforcement (step 7).
|
|
58
|
-
|
|
59
45
|
--------------------------------------------------------------------------- */
|
|
60
46
|
|
|
61
47
|
#ifndef CA_KERNEL_ITERATOR_H
|
|
@@ -66,9 +52,10 @@
|
|
|
66
52
|
|
|
67
53
|
/* ---- slab policy (proposal §2.2) ------------------------------------- */
|
|
68
54
|
typedef enum {
|
|
69
|
-
CA_SLAB_FREE = 0, /* engine-chosen chunk
|
|
70
|
-
|
|
71
|
-
|
|
55
|
+
CA_SLAB_FREE = 0, /* engine-chosen chunk. Not implemented:
|
|
56
|
+
init returns CA_ITER_ERR_POLICY. */
|
|
57
|
+
CA_SLAB_AXES = 1, /* user-pinned axes inside the slab (init_l2) */
|
|
58
|
+
CA_SLAB_WHOLE = 2 /* whole array in one slab */
|
|
72
59
|
} ca_slab_policy_t;
|
|
73
60
|
|
|
74
61
|
/* ---- kernel flags (proposal §2.2) ------------------------------------ */
|
|
@@ -93,9 +80,11 @@ typedef enum {
|
|
|
93
80
|
#define CA_ITER_ALIAS_NONE 0 /* scratch materialize. step 2+. */
|
|
94
81
|
#define CA_ITER_ALIAS_CONTIG 1 /* parent.ptr+offset direct slab. */
|
|
95
82
|
#define CA_ITER_ALIAS_STRIDED 2 /* L2 stride-aware. step 3+. */
|
|
96
|
-
#define CA_ITER_ALIAS_ATTACH 3 /*
|
|
97
|
-
|
|
98
|
-
|
|
83
|
+
#define CA_ITER_ALIAS_ATTACH 3 /* Not set by the engine. A
|
|
84
|
+
SRC_ATTACH walk runs with
|
|
85
|
+
CA_ITER_ALIAS_NONE over an
|
|
86
|
+
iterator-owned scratch filled and
|
|
87
|
+
written back with ca_xfer_all. */
|
|
99
88
|
#define CA_ITER_ALIAS_PER_SLAB 4 /* Phase C T3 fallback: per-slab
|
|
100
89
|
materialise via ca_axis_dispatch_gather
|
|
101
90
|
with subset descriptor (= caller-built
|
|
@@ -120,34 +109,28 @@ typedef enum {
|
|
|
120
109
|
mask in fiber_mask_scratch
|
|
121
110
|
(= rev2 §3.3, (data,mask)
|
|
122
111
|
pair). */
|
|
123
|
-
#define CA_ITER_ALIAS_STACK_OUTER_K 8 /*
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
entity case = eager-equivalent
|
|
140
|
-
memory bandwidth. Mask aliases
|
|
141
|
-
parent->mask similarly. Scoped
|
|
142
|
-
to slab_axes that exclude axis 0
|
|
143
|
-
(= axis 0 must be an outer iter
|
|
144
|
-
axis). */
|
|
112
|
+
#define CA_ITER_ALIAS_STACK_OUTER_K 8 /* CAStack source + CA_SLAB_AXES
|
|
113
|
+
whose slab leaves out the stack
|
|
114
|
+
axis (k_axis), which is then an
|
|
115
|
+
outer axis. Each slab lies inside
|
|
116
|
+
ONE parent, selected by
|
|
117
|
+
outer_idx[stack_k_outer_pos].
|
|
118
|
+
init_l2 attaches the K parents and
|
|
119
|
+
caches their ptrs and parent byte
|
|
120
|
+
strides; next_slab_axes reads
|
|
121
|
+
parents[k]->ptr + parent_off
|
|
122
|
+
directly. The parents' masks are
|
|
123
|
+
copied at init and the cursor
|
|
124
|
+
points into the copy. A fiber
|
|
125
|
+
that is not contiguous in its
|
|
126
|
+
parent is gathered (FIBER_CONTIG).
|
|
127
|
+
READ only. */
|
|
145
128
|
#define CA_ITER_ALIAS_STACK 7 /* PROPOSAL_CASTACK_LOOP_INTERCHANGE
|
|
146
129
|
Vector A rev2 (direct per-parent
|
|
147
130
|
ptr access): CAStack source +
|
|
148
131
|
CA_SLAB_AXES with slab_axes ==
|
|
149
|
-
[
|
|
150
|
-
view.mean(axis:
|
|
132
|
+
[k_axis] (= the stack axis alone,
|
|
133
|
+
e.g. view.mean(axis: k_axis)).
|
|
151
134
|
init_l2 attaches K parents up
|
|
152
135
|
front (= O(1) per entity parent),
|
|
153
136
|
caches parent->ptr aliases +
|
|
@@ -192,19 +175,30 @@ typedef enum {
|
|
|
192
175
|
|
|
193
176
|
/* ---- error codes ----------------------------------------------------- */
|
|
194
177
|
#define CA_ITER_OK 0
|
|
195
|
-
#define CA_ITER_ERR_NOT_CHEAP 1 /*
|
|
178
|
+
#define CA_ITER_ERR_NOT_CHEAP 1 /* the classifier does not recognise
|
|
179
|
+
the source (a view with no attach
|
|
180
|
+
slot; any other external obj_type
|
|
181
|
+
is delivered by attaching it) */
|
|
196
182
|
#define CA_ITER_ERR_POLICY 2 /* policy not implemented yet */
|
|
197
|
-
#define CA_ITER_ERR_FLAGS 3 /* flag combination unsupported
|
|
183
|
+
#define CA_ITER_ERR_FLAGS 3 /* flag combination unsupported;
|
|
184
|
+
also returned for a NULL state
|
|
185
|
+
or source */
|
|
198
186
|
#define CA_ITER_ERR_READONLY 4 /* WRITE on readonly view (CARepeat etc.) */
|
|
199
|
-
#define CA_ITER_ERR_MASK 5 /*
|
|
200
|
-
|
|
187
|
+
#define CA_ITER_ERR_MASK 5 /* reserved: no entry point returns
|
|
188
|
+
it (masked sources are accepted) */
|
|
189
|
+
#define CA_ITER_ERR_MASK_NOT_ALLOWED 6 /* NO_MASK flag set on a masked source */
|
|
201
190
|
/* ---- source kind (step 5+, internal routing) ------------------------- */
|
|
202
191
|
#define CA_ITER_SRC_NONE 0
|
|
203
192
|
#define CA_ITER_SRC_CASTRIDE 1 /* entity / CAStride family (step 1-4) */
|
|
204
|
-
#define CA_ITER_SRC_DESCRIPTOR 2 /*
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
193
|
+
#define CA_ITER_SRC_DESCRIPTOR 2 /* CASelectAxis / CAGrid / CASelect /
|
|
194
|
+
CAWindow / CAShift: per-axis
|
|
195
|
+
descriptors (describe_axes) */
|
|
196
|
+
#define CA_ITER_SRC_ATTACH 3 /* every other view the classifier
|
|
197
|
+
knows (conversion views, CATile,
|
|
198
|
+
CARoll, CAStack, CAMeld, CARemap,
|
|
199
|
+
CAObject, the lazy views) and any
|
|
200
|
+
registered external obj_type: the
|
|
201
|
+
view's own transfer gathers it */
|
|
208
202
|
#define CA_ITER_SRC_DESCRIPTOR_L2_ALIASABLE 4
|
|
209
203
|
/* F-2 (PROPOSAL_F2_KERNEL_ITERATOR_ALIAS
|
|
210
204
|
rev6): descriptor view whose innermost
|
|
@@ -220,13 +214,13 @@ typedef enum {
|
|
|
220
214
|
The classifier recognises the core's own view classes by comparing
|
|
221
215
|
their operation table against a list compiled into the engine. A view
|
|
222
216
|
class installed by a companion gem through ca_install_obj_type matches
|
|
223
|
-
nothing on that list
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
declares the routing here instead, once, in the class's Init:
|
|
217
|
+
nothing on that list; it is delivered as CA_ITER_SRC_ATTACH (the view's
|
|
218
|
+
own attach gathers it), and so is one that registers here, once, in the
|
|
219
|
+
class's Init:
|
|
227
220
|
|
|
228
221
|
ca_iter_register_source_kind(CA_OBJ_MY_VIEW, CA_ITER_SRC_ATTACH);
|
|
229
222
|
|
|
223
|
+
Registering states the routing rather than changing it.
|
|
230
224
|
CA_ITER_SRC_ATTACH is the only kind that may be registered. It is the
|
|
231
225
|
one whose contract an external class can meet on its own: func_attach
|
|
232
226
|
materialises (or aliases) src->ptr and func_sync scatters back — the
|
|
@@ -257,7 +251,10 @@ typedef struct {
|
|
|
257
251
|
ca_slab_policy_t policy;
|
|
258
252
|
int8_t ndim;
|
|
259
253
|
int8_t naxes; /* [step 5+] AXES policy axis count */
|
|
260
|
-
|
|
254
|
+
void *pair; /* the other state of a two-state
|
|
255
|
+
walk (ca_iter_state_init_l2_paired),
|
|
256
|
+
else NULL; finished with this one
|
|
257
|
+
when the walk raises */
|
|
261
258
|
uint32_t flags;
|
|
262
259
|
ca_size_t bytes; /* element size */
|
|
263
260
|
|
|
@@ -273,9 +270,9 @@ typedef struct {
|
|
|
273
270
|
ca_size_t composed_strides[CA_RANK_MAX]; /* byte units */
|
|
274
271
|
ca_size_t composed_base; /* byte offset from root->ptr */
|
|
275
272
|
|
|
276
|
-
/* --- descriptor framework cache (
|
|
277
|
-
For
|
|
278
|
-
|
|
273
|
+
/* --- descriptor framework cache (descriptor sources) ---
|
|
274
|
+
For CASelectAxis / CAGrid / CASelect / CAWindow / CAShift, init runs
|
|
275
|
+
the view's *_describe_axes once then
|
|
279
276
|
reuses the P3 substrate (ca_axis_dispatch_prepare / _layout /
|
|
280
277
|
_classify_prefix) to derive the slab layout. Cached inline so
|
|
281
278
|
next_slab walks the prefix axes without re-doing the analysis. */
|
|
@@ -315,8 +312,8 @@ typedef struct {
|
|
|
315
312
|
uint8_t write_dirty;
|
|
316
313
|
|
|
317
314
|
/* --- CA_SLAB_AXES policy fields (Phase A capstone, T1) ---
|
|
318
|
-
Populated when init_l2 is called with policy = CA_SLAB_AXES
|
|
319
|
-
|
|
315
|
+
Populated when init_l2 is called with policy = CA_SLAB_AXES, for
|
|
316
|
+
every kind of source. The kernel reads slab metadata directly
|
|
320
317
|
from these fields (= per-walk metadata, unchanged across slabs).
|
|
321
318
|
outer_axes / outer_dims / outer_strides drive the prefix walk;
|
|
322
319
|
slab_axes_buf / slab_dims / slab_strides describe the K-D slab
|
|
@@ -355,14 +352,14 @@ typedef struct {
|
|
|
355
352
|
gather and gathers each fiber here before yielding. Reused across
|
|
356
353
|
fibers; size grows to max slab_dims[0] * bytes.
|
|
357
354
|
|
|
358
|
-
last_data_off is
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
355
|
+
last_data_off is the byte offset of the current slab from alias_ptr,
|
|
356
|
+
set by next_slab_axes on its default path BEFORE the outer_idx
|
|
357
|
+
advance. sync_slab reads it for the fiber it scatters back and for
|
|
358
|
+
the cells of a whole-view scratch it compares; the slab iterator's
|
|
359
|
+
map_slab reads it to mark the output's mask.
|
|
362
360
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
touch these fields. */
|
|
361
|
+
The per-slab paths (CA_ITER_ALIAS_PER_SLAB / _HOIST) and the stack
|
|
362
|
+
paths do not set it. */
|
|
366
363
|
char *fiber_data_scratch;
|
|
367
364
|
ca_size_t fiber_data_scratch_cap;
|
|
368
365
|
ca_size_t last_data_off;
|
|
@@ -410,12 +407,10 @@ typedef struct {
|
|
|
410
407
|
here lets next_slab_axes compute mask_off without downcasting to
|
|
411
408
|
CAStack (= AC3 layering goal). */
|
|
412
409
|
ca_size_t stack_parent_mask_strides[CA_RANK_MAX];
|
|
413
|
-
/* --- PROPOSAL_CASTACK_XFER_OPT_LAYERING P.2 Case A (2026-06-18) --- */
|
|
414
410
|
/* When alias_mode == CA_ITER_ALIAS_STACK_OUTER_K and the CAStack
|
|
415
|
-
source carries a mask, init_l2
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
(xfree in finish). */
|
|
411
|
+
source carries a mask, init_l2 copies the K parent masks here, read
|
|
412
|
+
alongside parents[k]->ptr. NULL when the source has no mask. Owned
|
|
413
|
+
by the iterator (xfree in finish). */
|
|
419
414
|
boolean8_t **stack_parent_mask_ptrs; /* [n_parents] or NULL */
|
|
420
415
|
/* K axis position within the outer iter axis list. Set by init_l2
|
|
421
416
|
when alias_mode == CA_ITER_ALIAS_STACK_OUTER_K; next_slab_axes uses
|
|
@@ -461,10 +456,12 @@ typedef struct {
|
|
|
461
456
|
Not implemented in Phase 1 — falls back to L1 semantics so the predicate
|
|
462
457
|
stays well-defined for callers that probe ahead.
|
|
463
458
|
|
|
464
|
-
Descriptor
|
|
465
|
-
CAShift
|
|
466
|
-
CABitarray) return 0 at every level
|
|
467
|
-
|
|
459
|
+
Descriptor views (CASelectAxis / CAGrid / CASelect / CAWindow /
|
|
460
|
+
CAShift) and conversion views (CAFake / CAByteSwap / CABitfield /
|
|
461
|
+
CABitarray) return 0 at every level. init_l2 still reads a
|
|
462
|
+
descriptor view in place when its innermost axis is a stride
|
|
463
|
+
(CA_ITER_SRC_DESCRIPTOR_L2_ALIASABLE); this predicate does not
|
|
464
|
+
report that case.
|
|
468
465
|
|
|
469
466
|
ca_attach_is_alias is retained as the level=1 oracle for the Tier A
|
|
470
467
|
(PROPOSAL_DELEGATE_COPY_DATA) defer site; callers that already use
|
|
@@ -481,19 +478,21 @@ int ca_iter_can_alias (void *ap, int level);
|
|
|
481
478
|
src->ptr, stride implicit = bytes)
|
|
482
479
|
- CAStride family non-contig: scratch path (ca_copy_data
|
|
483
480
|
compose-fold gather into a malloc'd buffer)
|
|
484
|
-
-
|
|
481
|
+
- descriptor views (CAGrid / CASelect / CAMapping / CAWindow /
|
|
482
|
+
CAShift / CASelectAxis): gathered into a scratch buffer
|
|
483
|
+
- SRC_ATTACH views (overlays, lazy views, CAObject, CAStack, ...):
|
|
484
|
+
iterator-owned scratch filled through ca_xfer_all
|
|
485
|
+
- sources the classifier does not recognise: CA_ITER_ERR_NOT_CHEAP
|
|
485
486
|
|
|
486
|
-
policy: only
|
|
487
|
-
|
|
487
|
+
policy: CA_SLAB_WHOLE only (CA_SLAB_AXES and CA_SLAB_FREE return
|
|
488
|
+
CA_ITER_ERR_POLICY).
|
|
489
|
+
flags: any of CA_KERNEL_WRITE / CA_KERNEL_NO_MASK /
|
|
490
|
+
CA_KERNEL_FIBER_CONTIG; other bits return CA_ITER_ERR_FLAGS.
|
|
488
491
|
|
|
489
492
|
On success returns CA_ITER_OK; on error returns CA_ITER_ERR_*
|
|
490
493
|
without claiming resources (finish need not be called).
|
|
491
494
|
|
|
492
|
-
Pair with ca_iter_state_next_slab.
|
|
493
|
-
level-specific entry points so each setup path stays focused
|
|
494
|
-
(proposal §3.2 rev: original single-init was relaxed when L2 setup
|
|
495
|
-
diverged enough to warrant its own state initialiser; see
|
|
496
|
-
ROADMAP/CHANGELOG rev). */
|
|
495
|
+
Pair with ca_iter_state_next_slab. */
|
|
497
496
|
int ca_iter_state_init_l1 (ca_iter_state *st,
|
|
498
497
|
struct _CArray *src,
|
|
499
498
|
ca_slab_policy_t policy,
|
|
@@ -509,9 +508,23 @@ int ca_iter_state_init_l1 (ca_iter_state *st,
|
|
|
509
508
|
- CAStride non-contig: alias_mode = STRIDED, multi-slab walk over
|
|
510
509
|
prefix axes, each yield carries native inner stride_bytes. No
|
|
511
510
|
scratch.
|
|
512
|
-
-
|
|
513
|
-
|
|
514
|
-
|
|
511
|
+
- descriptor views: aliased when the innermost axis is a STRIDE
|
|
512
|
+
axis, otherwise gathered into scratch (per slab under
|
|
513
|
+
CA_SLAB_AXES when a slab axis is an INDEX or SHIFT axis)
|
|
514
|
+
- SRC_ATTACH views: iterator-owned scratch filled through
|
|
515
|
+
ca_xfer_all and written back the same way
|
|
516
|
+
- sources the classifier does not recognise: CA_ITER_ERR_NOT_CHEAP
|
|
517
|
+
|
|
518
|
+
policy: CA_SLAB_WHOLE or CA_SLAB_AXES (CA_SLAB_FREE returns
|
|
519
|
+
CA_ITER_ERR_POLICY, as do out-of-range or duplicate axes, and
|
|
520
|
+
CA_SLAB_AXES over a descriptor view whose descriptor rank
|
|
521
|
+
differs from the view's rank).
|
|
522
|
+
flags: as init_l1. CA_KERNEL_WRITE is refused with
|
|
523
|
+
CA_ITER_ERR_FLAGS when a CA_SLAB_AXES slab axis is an INDEX
|
|
524
|
+
or SHIFT axis of a descriptor view.
|
|
525
|
+
|
|
526
|
+
Pair with ca_iter_state_next_slab_strided (CA_SLAB_WHOLE) or
|
|
527
|
+
ca_iter_state_next_slab_axes (CA_SLAB_AXES). */
|
|
515
528
|
int ca_iter_state_init_l2 (ca_iter_state *st,
|
|
516
529
|
struct _CArray *src,
|
|
517
530
|
ca_slab_policy_t policy,
|
|
@@ -528,7 +541,24 @@ int ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
528
541
|
source carries a mask (= ca_has_mask(src)), or NULL otherwise.
|
|
529
542
|
The mask layout matches the value layout (= same iteration order
|
|
530
543
|
and same n). Step 6+: kernels use the CA_FOR_EACH_UNMASKED macro
|
|
531
|
-
family (carray.h) to skip masked cells.
|
|
544
|
+
family (carray.h) to skip masked cells.
|
|
545
|
+
|
|
546
|
+
The mask is an input. What it points at is a copy taken when the
|
|
547
|
+
walk began, so writing through it changes nothing -- not even under
|
|
548
|
+
CA_KERNEL_WRITE, where the value half of the same yield is often a
|
|
549
|
+
live alias. It also cannot express the thing an author would most
|
|
550
|
+
want it for: an unmasked source yields NULL, so there is nowhere to
|
|
551
|
+
record that a cell has become undefined. A kernel authors its
|
|
552
|
+
output mask on its own output array instead:
|
|
553
|
+
|
|
554
|
+
if ( op_mask == NULL ) {
|
|
555
|
+
ca_create_mask(co);
|
|
556
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
557
|
+
}
|
|
558
|
+
op_mask[out_i] = 1;
|
|
559
|
+
|
|
560
|
+
which is what every kernel in carray does (carray_hold.c, and the
|
|
561
|
+
reduction kernels mkkernel emits). */
|
|
532
562
|
int ca_iter_state_next_slab (ca_iter_state *st,
|
|
533
563
|
char **out_ptr,
|
|
534
564
|
boolean8_t **out_mask,
|
|
@@ -538,12 +568,9 @@ int ca_iter_state_next_slab (ca_iter_state *st,
|
|
|
538
568
|
*out_mask / *out_n / *out_stride_bytes when a slab is yielded;
|
|
539
569
|
returns 0 when the walk is complete. The kernel walks `*out_n`
|
|
540
570
|
elements by stepping `*out_stride_bytes` between consecutive
|
|
541
|
-
elements starting at `*out_ptr
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
since mask is boolean8_t == 1 byte, mask stride is 1 byte when the
|
|
545
|
-
value stride is bytes, and proportional otherwise). Only valid
|
|
546
|
-
when init_l2 was used. */
|
|
571
|
+
elements starting at `*out_ptr`. The mask, when non-NULL, is
|
|
572
|
+
contiguous whatever the value stride: mask[i] pairs with the value
|
|
573
|
+
at ptr + i * stride_bytes. Only valid when init_l2 was used. */
|
|
547
574
|
int ca_iter_state_next_slab_strided (ca_iter_state *st,
|
|
548
575
|
char **out_ptr,
|
|
549
576
|
boolean8_t **out_mask,
|
|
@@ -589,20 +616,85 @@ int ca_iter_state_next_slab_axes (ca_iter_state *st,
|
|
|
589
616
|
next_slab_strided + kernel invocation; the alias_mode branch lives
|
|
590
617
|
inside the state machine so the caller never has to inspect it.
|
|
591
618
|
|
|
592
|
-
Behaviour
|
|
619
|
+
Behaviour:
|
|
593
620
|
- !(flags & CA_KERNEL_WRITE): no-op (READ walk)
|
|
621
|
+
- per-fiber gather (CA_KERNEL_FIBER_CONTIG on a strided fiber):
|
|
622
|
+
the fiber is scattered back from its scratch first
|
|
594
623
|
- alias path (scratch_ptr == NULL): no-op — kernel wrote to
|
|
595
|
-
parent directly through alias_ptr
|
|
596
|
-
- scratch path
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
assert; step 5 re-evaluation noted in the proposal. */
|
|
624
|
+
parent directly through alias_ptr
|
|
625
|
+
- scratch path, at L1 or L2: written back through the source —
|
|
626
|
+
ca_xfer_all for SRC_ATTACH, ca_sync_data for CAStride, the
|
|
627
|
+
descriptor scatter for descriptor views */
|
|
600
628
|
void ca_iter_state_sync_slab (ca_iter_state *st);
|
|
601
629
|
|
|
602
|
-
/* Release any resources held by `st` and detach parent.
|
|
603
|
-
|
|
630
|
+
/* Release any resources held by `st` and detach parent. Idempotent:
|
|
631
|
+
a second call is a no-op. Also safe after a failed init, which holds
|
|
632
|
+
nothing to release (the call is then not required). */
|
|
604
633
|
void ca_iter_state_finish (ca_iter_state *st);
|
|
605
634
|
|
|
635
|
+
/* Open `st` as the second state of a walk whose first state is already
|
|
636
|
+
open -- an input and an output walked together. Takes what
|
|
637
|
+
ca_iter_state_init_l2 takes, plus `first`.
|
|
638
|
+
|
|
639
|
+
The two are then finished together when either walk raises (a gather
|
|
640
|
+
or a write-back through a source's slots): each is open in the
|
|
641
|
+
caller's frame, and the raise would jump over the other's finish. If
|
|
642
|
+
opening `st` raises, or is declined (the code is returned), `first` is
|
|
643
|
+
finished here, so the caller has nothing left to close.
|
|
644
|
+
|
|
645
|
+
When `st` writes (CA_KERNEL_WRITE), `first` reads, both walk by
|
|
646
|
+
CA_SLAB_AXES, and their arrays live in the same root, `first` is
|
|
647
|
+
reopened on a copy of its array taken before anything is written, so
|
|
648
|
+
the kernel reads the values the input held when the walk began. Two
|
|
649
|
+
walks opened separately with ca_iter_state_init_l2 know nothing of
|
|
650
|
+
each other: a read walk over memory a write walk writes into must be
|
|
651
|
+
given a copy by the caller. */
|
|
652
|
+
int ca_iter_state_init_l2_paired (ca_iter_state *st,
|
|
653
|
+
ca_iter_state *first,
|
|
654
|
+
struct _CArray *src,
|
|
655
|
+
ca_slab_policy_t policy,
|
|
656
|
+
int8_t *axes,
|
|
657
|
+
int8_t naxes,
|
|
658
|
+
uint32_t flags);
|
|
659
|
+
|
|
660
|
+
/* Finish a walk as the block macros leave it: when the body left a write
|
|
661
|
+
walk with `break`, the slab it was in is written back before the walk is
|
|
662
|
+
finished. ca_iter_state_finish itself abandons such a slab. */
|
|
663
|
+
void ca_iter_state_close (ca_iter_state *st);
|
|
664
|
+
|
|
665
|
+
/* Raise unless rc is CA_ITER_OK. The block macros call this on the value
|
|
666
|
+
ca_iter_state_init_l1 / _l2 returned, so an author who never looks at a
|
|
667
|
+
return code still hears about a request the iterator would not serve.
|
|
668
|
+
Returns rc when there is nothing to report, so it composes inside the
|
|
669
|
+
macros' comma expressions. */
|
|
670
|
+
int ca_iter_check_init (int rc);
|
|
671
|
+
|
|
672
|
+
/* Raise ArgumentError unless the two arrays have the same shape. The
|
|
673
|
+
INOUT and PAIR fiber macros call this before opening either walk. */
|
|
674
|
+
int ca_iter_check_same_shape (struct _CArray *a, struct _CArray *b);
|
|
675
|
+
|
|
676
|
+
/* Run body(arg) so that the walks in states[0..n) are finished however the
|
|
677
|
+
body leaves: by returning, by `break`, or by raising.
|
|
678
|
+
|
|
679
|
+
A walk releases what it holds in ca_iter_state_finish, and a body that
|
|
680
|
+
raises jumps over the finish -- the block macros put it in the `for`
|
|
681
|
+
increment, and a hand-written walk has it after the loop. A body that
|
|
682
|
+
calls back into Ruby (an object-lane kernel) can raise at any cell, so
|
|
683
|
+
it runs through this function.
|
|
684
|
+
|
|
685
|
+
The states belong to the caller's frame, not to the body's: after a
|
|
686
|
+
raise, the body's frame is gone, and the cleanup runs where it was.
|
|
687
|
+
Pass them to the body inside `arg` and open each one there, with
|
|
688
|
+
ca_iter_state_init_* or a block macro (`CA_FOR_EACH_SLAB(c->st, ...)`).
|
|
689
|
+
A state declared inside the body is not covered.
|
|
690
|
+
|
|
691
|
+
The states are marked unopened before the body runs, so one the body
|
|
692
|
+
never opens costs nothing, and the body may finish a walk itself:
|
|
693
|
+
finishing is idempotent. Returns what the body returns; a raise propagates
|
|
694
|
+
after the walks are finished. */
|
|
695
|
+
VALUE ca_iter_ensure (int32_t n, ca_iter_state *states,
|
|
696
|
+
VALUE (*body)(VALUE), VALUE arg);
|
|
697
|
+
|
|
606
698
|
/* ---- Phase C C.3: kernel author block macros ------------------------
|
|
607
699
|
(PROPOSAL_CAPSTONE_PHASE_C.md D3.1 (A) do/while/for + D3.2 (C) 2 kinds)
|
|
608
700
|
|
|
@@ -617,17 +709,27 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
617
709
|
surrounding scope.
|
|
618
710
|
- `flags` arg propagates to init_l2 (= CA_KERNEL_WRITE supported).
|
|
619
711
|
`sync_slab` is called automatically after each iteration; it's a
|
|
620
|
-
no-op when WRITE flag is absent.
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
712
|
+
no-op when WRITE flag is absent. The mask cursor is an input even
|
|
713
|
+
under WRITE -- see ca_iter_state_next_slab above for why, and for
|
|
714
|
+
where an output mask is written instead.
|
|
715
|
+
- Init failure (ca_iter_state_init_l2 returns CA_ITER_ERR_*) raises:
|
|
716
|
+
the macro passes the code to ca_iter_check_init, which reports what
|
|
717
|
+
the iterator declined to do. The body does not run and finish is
|
|
718
|
+
not reached, which is safe because a failed init allocates nothing.
|
|
719
|
+
Kernels that want to handle a refusal rather than propagate it
|
|
720
|
+
should drop down to the raw API and read the code themselves.
|
|
626
721
|
- `break;` from inside the body exits the loop AND triggers finish
|
|
627
722
|
correctly (= outer for's "increment" clause runs once on natural
|
|
628
|
-
exit; `break` from the inner while breaks both).
|
|
723
|
+
exit; `break` from the inner while breaks both). In a write walk
|
|
724
|
+
finish writes back the slab the body was in. `return` inside
|
|
629
725
|
the body LEAKS resources (scratch_ptr, parent attach) — drop to
|
|
630
|
-
raw API if early return is needed.
|
|
726
|
+
raw API if early return is needed. A body that raises leaks the
|
|
727
|
+
same way: the engine releases what it holds when the walk itself
|
|
728
|
+
raises (a gather or a write-back through the source's slots), but
|
|
729
|
+
the body runs in the caller's frame, where it has no hold on it.
|
|
730
|
+
A body that can raise -- one that calls back into Ruby, as an
|
|
731
|
+
object-lane kernel does -- runs through ca_iter_ensure, with the
|
|
732
|
+
state in the caller's frame.
|
|
631
733
|
- Macros are not statement-equivalent (= they expand to nested for
|
|
632
734
|
constructs). Don't follow them with `else` etc. */
|
|
633
735
|
|
|
@@ -760,11 +862,12 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
760
862
|
always-constant argument). CA_SLAB_AXES is still FROZEN, because
|
|
761
863
|
raw-API kernels pass it to ca_iter_state_init_l2 directly. */
|
|
762
864
|
#define CA_FOR_EACH_SLAB(st, ca, axes, naxes, flags, p, m) \
|
|
763
|
-
for ( int __caf_init = (
|
|
764
|
-
|
|
865
|
+
for ( int __caf_init = (ca_iter_check_init( \
|
|
866
|
+
ca_iter_state_init_l2(&(st), (ca), CA_SLAB_AXES, \
|
|
867
|
+
(axes), (naxes), (flags))), \
|
|
765
868
|
1); \
|
|
766
869
|
__caf_init; \
|
|
767
|
-
__caf_init = 0,
|
|
870
|
+
__caf_init = 0, ca_iter_state_close(&(st)) ) \
|
|
768
871
|
for ( ; ca_iter_state_next_slab_axes(&(st), &(p), &(m)); \
|
|
769
872
|
ca_iter_state_sync_slab(&(st)) )
|
|
770
873
|
|
|
@@ -777,21 +880,24 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
777
880
|
Shape mismatch between ca_in / ca_out is NOT validated by the macro
|
|
778
881
|
— caller responsibility (= typically output is `rb_ca_template_with_type`
|
|
779
882
|
of input, guaranteeing same shape). Init failure on either iter
|
|
780
|
-
|
|
883
|
+
raises — see CA_FOR_EACH_SLAB above. */
|
|
781
884
|
/* Policy fixed to CA_SLAB_AXES internally — see CA_FOR_EACH_SLAB above. */
|
|
782
885
|
#define CA_FOR_EACH_SLAB_INOUT(st_in, st_out, ca_in, ca_out, \
|
|
783
886
|
axes, naxes, \
|
|
784
887
|
p_in, p_out, m_in, m_out) \
|
|
785
888
|
for ( int __cafi_init = ( \
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
889
|
+
ca_iter_check_init( \
|
|
890
|
+
ca_iter_state_init_l2(&(st_in), (ca_in), CA_SLAB_AXES, \
|
|
891
|
+
(axes), (naxes), 0)), \
|
|
892
|
+
ca_iter_check_init( \
|
|
893
|
+
ca_iter_state_init_l2_paired(&(st_out), &(st_in), (ca_out), \
|
|
894
|
+
CA_SLAB_AXES, \
|
|
895
|
+
(axes), (naxes), CA_KERNEL_WRITE)), \
|
|
790
896
|
1); \
|
|
791
897
|
__cafi_init; \
|
|
792
898
|
__cafi_init = 0, \
|
|
793
|
-
|
|
794
|
-
|
|
899
|
+
ca_iter_state_close(&(st_in)), \
|
|
900
|
+
ca_iter_state_close(&(st_out)) ) \
|
|
795
901
|
for ( ; ca_iter_state_next_slab_axes(&(st_in), &(p_in), &(m_in)) && \
|
|
796
902
|
ca_iter_state_next_slab_axes(&(st_out), &(p_out), &(m_out)); \
|
|
797
903
|
ca_iter_state_sync_slab(&(st_out)) )
|
|
@@ -809,78 +915,75 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
809
915
|
The CA_KERNEL_FIBER_CONTIG flag is auto-set; engine gathers strided
|
|
810
916
|
fibers into per-state scratch when slab_strides[0] != bytes (= F.1a/b).
|
|
811
917
|
|
|
812
|
-
`axis`
|
|
813
|
-
|
|
814
|
-
|
|
918
|
+
`axis`, `ca`, `ca_in` and `ca_out` may be evaluated more than once:
|
|
919
|
+
pass variables, not expressions with side effects. `n` is set to the
|
|
920
|
+
fiber length (= slab_dims[0], constant per walk).
|
|
921
|
+
|
|
922
|
+
The forms without MASKED in the name hand out no mask cursor: a masked
|
|
923
|
+
source is walked with its masked cells read as values. Pass
|
|
924
|
+
CA_KERNEL_NO_MASK to have a masked source refused, or use a MASKED
|
|
925
|
+
form to see the mask.
|
|
815
926
|
|
|
816
927
|
Same constraints as CA_FOR_EACH_SLAB family:
|
|
817
|
-
- `break;` from body exits cleanly (finish runs
|
|
928
|
+
- `break;` from body exits cleanly (finish runs, and a write walk
|
|
929
|
+
writes back the fiber it was in).
|
|
818
930
|
- `return;` from body LEAKS scratch / parent attach -- use raw API.
|
|
819
931
|
- Macros are NOT statement-equivalent (nested for); no trailing else.
|
|
820
932
|
|
|
821
|
-
INOUT forms (form 2 / 4) require
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
macros runtime-assert shape equality and skip body on mismatch.
|
|
826
|
-
Authors that need broadcasting must drop to raw API. */
|
|
933
|
+
INOUT forms (form 2 / 4) require `ca_in` and `ca_out` to have the same
|
|
934
|
+
shape (ndim and every dim[k]), and raise ArgumentError before opening
|
|
935
|
+
either walk when they do not. Authors that need broadcasting must
|
|
936
|
+
drop to raw API. */
|
|
827
937
|
|
|
828
938
|
#define CA_FOR_EACH_FIBER(st, ca, axis, flags, p, n) \
|
|
829
939
|
for ( int __cff_init = ( \
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
940
|
+
ca_iter_check_init( \
|
|
941
|
+
ca_iter_state_init_l2(&(st), (ca), CA_SLAB_AXES, \
|
|
942
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
943
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
833
944
|
(n) = (st).slab_dims[0], \
|
|
834
945
|
1); \
|
|
835
946
|
__cff_init; \
|
|
836
|
-
__cff_init = 0,
|
|
947
|
+
__cff_init = 0, ca_iter_state_close(&(st)) ) \
|
|
837
948
|
for ( ; ca_iter_state_next_slab_axes(&(st), &(p), NULL); \
|
|
838
949
|
ca_iter_state_sync_slab(&(st)) )
|
|
839
950
|
|
|
840
951
|
#define CA_FOR_EACH_FIBER_MASKED(st, ca, axis, flags, p, n, m) \
|
|
841
952
|
for ( int __cffm_init = ( \
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
953
|
+
ca_iter_check_init( \
|
|
954
|
+
ca_iter_state_init_l2(&(st), (ca), CA_SLAB_AXES, \
|
|
955
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
956
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
845
957
|
(n) = (st).slab_dims[0], \
|
|
846
958
|
1); \
|
|
847
959
|
__cffm_init; \
|
|
848
|
-
__cffm_init = 0,
|
|
960
|
+
__cffm_init = 0, ca_iter_state_close(&(st)) ) \
|
|
849
961
|
for ( ; ca_iter_state_next_slab_axes(&(st), &(p), &(m)); \
|
|
850
962
|
ca_iter_state_sync_slab(&(st)) )
|
|
851
963
|
|
|
852
|
-
/* INOUT form 2
|
|
853
|
-
|
|
854
|
-
STRICT FULL SHAPE EQUALITY (rev4 §2.3): the inner for-condition
|
|
855
|
-
re-evaluates ca_in->ndim == ca_out->ndim and dim[axis] equality (=
|
|
856
|
-
minimal seam coverage given the macro can't loop over k). Full
|
|
857
|
-
per-axis equality lives one level up in the init-time short-circuit
|
|
858
|
-
below: we compare elements + ndim + axis dim, which catches the
|
|
859
|
-
common silent-corruption seam (= e.g. (3,5) vs (4,5) axis=1 with
|
|
860
|
-
matching fiber length but different fiber count). Comprehensive
|
|
861
|
-
per-dim check is the caller's responsibility for now (= simpler than
|
|
862
|
-
building a per-dim k loop into a macro; ext authors can drop to raw
|
|
863
|
-
API for arbitrary broadcasting designs). */
|
|
964
|
+
/* INOUT form 2. Output gets CA_KERNEL_WRITE auto-set. The shapes are
|
|
965
|
+
checked first (ca_iter_check_same_shape). */
|
|
864
966
|
#define CA_FOR_EACH_FIBER_INOUT(st_in, st_out, ca_in, ca_out, axis, \
|
|
865
967
|
flags, p_in, p_out, n) \
|
|
866
968
|
for ( int __cffi_init = ( \
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
969
|
+
ca_iter_check_same_shape((ca_in), (ca_out)), \
|
|
970
|
+
ca_iter_check_init( \
|
|
971
|
+
ca_iter_state_init_l2(&(st_in), (ca_in), CA_SLAB_AXES, \
|
|
972
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
973
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
974
|
+
ca_iter_check_init( \
|
|
975
|
+
ca_iter_state_init_l2_paired(&(st_out), &(st_in), (ca_out), \
|
|
976
|
+
CA_SLAB_AXES, \
|
|
977
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
978
|
+
((flags) | CA_KERNEL_FIBER_CONTIG \
|
|
979
|
+
| CA_KERNEL_WRITE))), \
|
|
874
980
|
(n) = (st_in).slab_dims[0], \
|
|
875
981
|
1); \
|
|
876
982
|
__cffi_init; \
|
|
877
983
|
__cffi_init = 0, \
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
for ( ; (st_in)
|
|
881
|
-
&& (st_in).src->elements == (st_out).src->elements \
|
|
882
|
-
&& (st_in).slab_dims[0] == (st_out).slab_dims[0] \
|
|
883
|
-
&& ca_iter_state_next_slab_axes(&(st_in), &(p_in), NULL) \
|
|
984
|
+
ca_iter_state_close(&(st_in)), \
|
|
985
|
+
ca_iter_state_close(&(st_out)) ) \
|
|
986
|
+
for ( ; ca_iter_state_next_slab_axes(&(st_in), &(p_in), NULL) \
|
|
884
987
|
&& ca_iter_state_next_slab_axes(&(st_out), &(p_out), NULL); \
|
|
885
988
|
ca_iter_state_sync_slab(&(st_in)), \
|
|
886
989
|
ca_iter_state_sync_slab(&(st_out)) )
|
|
@@ -888,27 +991,95 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
888
991
|
#define CA_FOR_EACH_FIBER_INOUT_MASKED(st_in, st_out, ca_in, ca_out, axis, \
|
|
889
992
|
flags, p_in, p_out, n, m) \
|
|
890
993
|
for ( int __cffim_init = ( \
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
994
|
+
ca_iter_check_same_shape((ca_in), (ca_out)), \
|
|
995
|
+
ca_iter_check_init( \
|
|
996
|
+
ca_iter_state_init_l2(&(st_in), (ca_in), CA_SLAB_AXES, \
|
|
997
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
998
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
999
|
+
ca_iter_check_init( \
|
|
1000
|
+
ca_iter_state_init_l2_paired(&(st_out), &(st_in), (ca_out), \
|
|
1001
|
+
CA_SLAB_AXES, \
|
|
1002
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
1003
|
+
((flags) | CA_KERNEL_FIBER_CONTIG \
|
|
1004
|
+
| CA_KERNEL_WRITE))), \
|
|
898
1005
|
(n) = (st_in).slab_dims[0], \
|
|
899
1006
|
1); \
|
|
900
1007
|
__cffim_init; \
|
|
901
1008
|
__cffim_init = 0, \
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
for ( ; (st_in)
|
|
905
|
-
&& (st_in).src->elements == (st_out).src->elements \
|
|
906
|
-
&& (st_in).slab_dims[0] == (st_out).slab_dims[0] \
|
|
907
|
-
&& ca_iter_state_next_slab_axes(&(st_in), &(p_in), &(m)) \
|
|
1009
|
+
ca_iter_state_close(&(st_in)), \
|
|
1010
|
+
ca_iter_state_close(&(st_out)) ) \
|
|
1011
|
+
for ( ; ca_iter_state_next_slab_axes(&(st_in), &(p_in), &(m)) \
|
|
908
1012
|
&& ca_iter_state_next_slab_axes(&(st_out), &(p_out), NULL); \
|
|
909
1013
|
ca_iter_state_sync_slab(&(st_in)), \
|
|
910
1014
|
ca_iter_state_sync_slab(&(st_out)) )
|
|
911
1015
|
|
|
1016
|
+
/* PAIR forms: two sources read together along the same axis.
|
|
1017
|
+
|
|
1018
|
+
The INOUT forms cover input + output. These cover input + input, which
|
|
1019
|
+
is what a routine taking two vectors of the same length wants -- a
|
|
1020
|
+
correlation, a dot product, a distance. Neither state gets
|
|
1021
|
+
CA_KERNEL_WRITE, and `flags` must not carry it: use the INOUT forms to
|
|
1022
|
+
write.
|
|
1023
|
+
|
|
1024
|
+
Both fibers are contig-delivered, so the pair may be handed straight to
|
|
1025
|
+
a C routine that walks it itself. The MASKED form yields BOTH mask
|
|
1026
|
+
cursors: which cells a pair of fibers may be used at is a question about
|
|
1027
|
+
both of them, and the INOUT forms answer only about the input.
|
|
1028
|
+
|
|
1029
|
+
The two sources must have the same shape, as for the INOUT forms:
|
|
1030
|
+
ca_iter_check_same_shape raises ArgumentError before either walk is
|
|
1031
|
+
opened. The two sources may be the same array. The second state is
|
|
1032
|
+
opened paired with the first, so a refusal or a raise on either side
|
|
1033
|
+
closes both. */
|
|
1034
|
+
|
|
1035
|
+
#define CA_FOR_EACH_FIBER_PAIR(st_a, st_b, ca_a, ca_b, axis, \
|
|
1036
|
+
flags, p_a, p_b, n) \
|
|
1037
|
+
for ( int __cffp_init = ( \
|
|
1038
|
+
ca_iter_check_same_shape((ca_a), (ca_b)), \
|
|
1039
|
+
ca_iter_check_init( \
|
|
1040
|
+
ca_iter_state_init_l2(&(st_a), (ca_a), CA_SLAB_AXES, \
|
|
1041
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
1042
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
1043
|
+
ca_iter_check_init( \
|
|
1044
|
+
ca_iter_state_init_l2_paired(&(st_b), &(st_a), (ca_b), \
|
|
1045
|
+
CA_SLAB_AXES, \
|
|
1046
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
1047
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
1048
|
+
(n) = (st_a).slab_dims[0], \
|
|
1049
|
+
1); \
|
|
1050
|
+
__cffp_init; \
|
|
1051
|
+
__cffp_init = 0, \
|
|
1052
|
+
ca_iter_state_close(&(st_a)), \
|
|
1053
|
+
ca_iter_state_close(&(st_b)) ) \
|
|
1054
|
+
for ( ; ca_iter_state_next_slab_axes(&(st_a), &(p_a), NULL) \
|
|
1055
|
+
&& ca_iter_state_next_slab_axes(&(st_b), &(p_b), NULL); \
|
|
1056
|
+
ca_iter_state_sync_slab(&(st_a)), \
|
|
1057
|
+
ca_iter_state_sync_slab(&(st_b)) )
|
|
1058
|
+
|
|
1059
|
+
#define CA_FOR_EACH_FIBER_PAIR_MASKED(st_a, st_b, ca_a, ca_b, axis, \
|
|
1060
|
+
flags, p_a, p_b, n, m_a, m_b) \
|
|
1061
|
+
for ( int __cffpm_init = ( \
|
|
1062
|
+
ca_iter_check_same_shape((ca_a), (ca_b)), \
|
|
1063
|
+
ca_iter_check_init( \
|
|
1064
|
+
ca_iter_state_init_l2(&(st_a), (ca_a), CA_SLAB_AXES, \
|
|
1065
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
1066
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
1067
|
+
ca_iter_check_init( \
|
|
1068
|
+
ca_iter_state_init_l2_paired(&(st_b), &(st_a), (ca_b), \
|
|
1069
|
+
CA_SLAB_AXES, \
|
|
1070
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
1071
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
1072
|
+
(n) = (st_a).slab_dims[0], \
|
|
1073
|
+
1); \
|
|
1074
|
+
__cffpm_init; \
|
|
1075
|
+
__cffpm_init = 0, \
|
|
1076
|
+
ca_iter_state_close(&(st_a)), \
|
|
1077
|
+
ca_iter_state_close(&(st_b)) ) \
|
|
1078
|
+
for ( ; ca_iter_state_next_slab_axes(&(st_a), &(p_a), &(m_a)) \
|
|
1079
|
+
&& ca_iter_state_next_slab_axes(&(st_b), &(p_b), &(m_b)); \
|
|
1080
|
+
ca_iter_state_sync_slab(&(st_a)), \
|
|
1081
|
+
ca_iter_state_sync_slab(&(st_b)) )
|
|
1082
|
+
|
|
912
1083
|
/* ---- Phase D: per-data_type reduction macro suite ----------------------- */
|
|
913
1084
|
|
|
914
1085
|
/* CA_SLAB_REDUCE_T(T, ...): generic per-data_type slab reduction. T is the
|
|
@@ -2244,7 +2415,7 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
2244
2415
|
Both states must share slab geometry (= same slab_ndim and slab_dims),
|
|
2245
2416
|
typically by initialising both with the same policy + axes on
|
|
2246
2417
|
shape-equal CArrays. Mask handling is **not** done by this macro —
|
|
2247
|
-
if your input is masked, see §
|
|
2418
|
+
if your input is masked, see §8 Mask handling in
|
|
2248
2419
|
docs/authoring/HOW_TO_WRITE_KERNEL.md. Caller is responsible for invoking
|
|
2249
2420
|
ca_iter_state_sync_slab on the output state after each slab.
|
|
2250
2421
|
|