carray 2.0.1 → 3.0.0
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/.yardopts +5 -25
- data/CHANGELOG.md +16 -0
- data/LICENSE +1 -1
- data/NEWS.md +3 -0
- data/README.md +128 -44
- data/carray.gemspec +22 -24
- data/ext/ca_array_pool.c +91 -0
- data/ext/ca_axis_descriptor.h +186 -0
- data/ext/ca_axis_dispatch.c +924 -0
- data/ext/ca_axis_group.c +1208 -0
- data/ext/ca_bincmp_dispatch.c +76 -0
- data/ext/ca_bincmp_dispatch.h +85 -0
- data/ext/ca_binop_dispatch.c +125 -0
- data/ext/ca_binop_dispatch.h +159 -0
- data/ext/ca_categorical_iterator.c +1375 -0
- data/ext/ca_compare.c +94 -0
- data/ext/ca_compare.h +26 -0
- data/ext/ca_composite_dispatch.c +414 -0
- data/ext/ca_composite_dispatch.h +116 -0
- data/ext/ca_for_buffer.h +96 -0
- data/ext/ca_for_each_element.h +241 -0
- data/ext/ca_group_iter.c +304 -0
- data/ext/ca_iter_substrate.h +325 -0
- data/ext/ca_kernel_iterator.c +4321 -0
- data/ext/ca_kernel_iterator.h +2603 -0
- data/ext/ca_moncmp_dispatch.c +37 -0
- data/ext/ca_moncmp_dispatch.h +62 -0
- data/ext/ca_monop_dispatch.c +200 -0
- data/ext/ca_monop_dispatch.h +235 -0
- data/ext/ca_obj_array.c +355 -359
- data/ext/ca_obj_bincmp.c +809 -0
- data/ext/ca_obj_binop.c +892 -0
- data/ext/ca_obj_bitarray.c +369 -164
- data/ext/ca_obj_bitfield.c +294 -234
- data/ext/ca_obj_block.c +189 -711
- data/ext/ca_obj_byte_swap.c +766 -0
- data/ext/ca_obj_const_string.c +965 -0
- data/ext/ca_obj_face.c +670 -0
- data/ext/ca_obj_face.h +247 -0
- data/ext/ca_obj_fake.c +228 -100
- data/ext/ca_obj_farray.c +54 -441
- data/ext/ca_obj_field.c +82 -529
- data/ext/ca_obj_fixlen_string.c +306 -0
- data/ext/ca_obj_grid.c +858 -440
- data/ext/ca_obj_meld.c +1034 -0
- data/ext/ca_obj_moncmp.c +569 -0
- data/ext/ca_obj_monop.c +1111 -0
- data/ext/ca_obj_object.c +772 -297
- data/ext/ca_obj_record.c +468 -0
- data/ext/ca_obj_reduce.c +97 -82
- data/ext/ca_obj_refer.c +569 -459
- data/ext/ca_obj_remap.c +475 -0
- data/ext/ca_obj_repeat.c +92 -477
- data/ext/ca_obj_roll.c +616 -0
- data/ext/ca_obj_select.c +344 -296
- data/ext/ca_obj_select_axis.c +1296 -0
- data/ext/ca_obj_shift.c +229 -791
- data/ext/ca_obj_source.c +78 -0
- data/ext/ca_obj_stack.c +1173 -0
- data/ext/ca_obj_stride.c +2501 -0
- data/ext/ca_obj_string.c +268 -0
- data/ext/ca_obj_tile.c +614 -0
- data/ext/ca_obj_time.c +546 -0
- data/ext/ca_obj_timedelta.c +435 -0
- data/ext/ca_obj_transpose.c +62 -516
- data/ext/ca_obj_triop.c +746 -0
- data/ext/ca_obj_unbound_repeat.c +207 -240
- data/ext/ca_obj_window.c +1131 -563
- data/ext/ca_op_byte_swap.c +175 -0
- data/ext/ca_op_ipower.c +319 -0
- data/ext/ca_op_powi.h +88 -0
- data/ext/ca_sort_kernels.h +132 -0
- data/ext/ca_sweep_engine.c +430 -0
- data/ext/ca_sweep_engine.h +157 -0
- data/ext/ca_transform_common.c +228 -0
- data/ext/ca_triop_dispatch.c +55 -0
- data/ext/ca_triop_dispatch.h +62 -0
- data/ext/carray.h +795 -402
- data/ext/carray_access.c +831 -711
- data/ext/carray_attribute.c +98 -329
- data/ext/carray_bincount.c +255 -0
- data/ext/carray_broadcast.c +283 -0
- data/ext/carray_call_cfunc.c +1360 -828
- data/ext/carray_call_cfunc.h +160 -0
- data/ext/carray_cast.c +1212 -301
- data/ext/carray_cast_func.rb +81 -40
- data/ext/carray_class.c +53 -63
- data/ext/carray_config.h +28 -0
- data/ext/carray_conversion.c +350 -346
- data/ext/carray_copy.c +156 -268
- data/ext/carray_core.c +1341 -198
- data/ext/carray_count.c +312 -0
- data/ext/carray_data_type.c +43 -19
- data/ext/carray_element.c +585 -213
- data/ext/carray_factorize.c +2542 -0
- data/ext/carray_generate.c +230 -559
- data/ext/carray_histogram.c +490 -0
- data/ext/carray_hold.c +228 -0
- data/ext/carray_index_classifier.c +1035 -0
- data/ext/carray_index_classifier.h +27 -0
- data/ext/carray_internal.h +120 -0
- data/ext/carray_kernels_bincmp.c +4445 -0
- data/ext/carray_kernels_binop.c +10979 -0
- data/ext/carray_kernels_init.c +36 -0
- data/ext/carray_kernels_map.c +3466 -0
- data/ext/carray_kernels_moncmp.c +2096 -0
- data/ext/carray_kernels_monop.c +18312 -0
- data/ext/carray_kernels_reduce_aggregate.c +25836 -0
- data/ext/carray_kernels_reduce_boolean.c +329 -0
- data/ext/carray_kernels_reduce_cumulative.c +14592 -0
- data/ext/carray_kernels_reduce_extreme.c +16947 -0
- data/ext/carray_kernels_reduce_variance.c +3909 -0
- data/ext/carray_kernels_scan.c +3692 -0
- data/ext/carray_kernels_search.c +32137 -0
- data/ext/carray_kernels_sort.c +10625 -0
- data/ext/carray_kernels_triop.c +1391 -0
- data/ext/carray_lazy.c +567 -0
- data/ext/carray_loop.c +88 -200
- data/ext/carray_mask.c +848 -154
- data/ext/carray_math_kernel.h +120 -0
- data/ext/carray_mathfunc.c +10 -241
- data/ext/carray_median_percentile.c +1257 -0
- data/ext/carray_memory_view.c +1625 -0
- data/ext/carray_operator.c +1526 -318
- data/ext/carray_order.c +664 -1394
- data/ext/carray_partition.c +416 -0
- data/ext/carray_random.c +518 -0
- data/ext/carray_scatter.c +357 -0
- data/ext/carray_slab.c +1219 -0
- data/ext/carray_slab.h +84 -0
- data/ext/carray_sort.c +829 -0
- data/ext/carray_sort_kernel.c +620 -0
- data/ext/carray_struct.c +695 -0
- data/ext/carray_test.c +343 -229
- data/ext/carray_undef.c +34 -17
- data/ext/carray_utils.c +175 -74
- data/ext/extconf.rb +216 -55
- data/ext/mk_call_cfunc.rb +480 -0
- data/ext/mkkernel.rb +8842 -0
- data/ext/ruby_carray.c +202 -101
- data/ext/version.h +5 -15
- data/ext/version.rb +5 -13
- data/lib/carray/arrow_tensor.rb +401 -0
- data/lib/carray/attribute.rb +166 -0
- data/lib/carray/autoload_carray.rb +220 -0
- data/lib/carray/autoload_method_extension.rb +44 -0
- data/lib/carray/axis_group.rb +711 -0
- data/lib/carray/basics.rb +481 -0
- data/lib/carray/bincount_nd.rb +358 -0
- data/lib/carray/block_iterator.rb +604 -0
- data/lib/carray/boolean_reduce.rb +109 -0
- data/lib/carray/categorical.rb +561 -0
- data/lib/carray/categorical_iterator.rb +1062 -0
- data/lib/carray/complex.rb +150 -0
- data/lib/carray/conditional.rb +216 -0
- data/lib/carray/const_string.rb +228 -0
- data/lib/carray/construct.rb +139 -328
- data/lib/carray/core_extensions.rb +240 -0
- data/lib/carray/data_type_extension.rb +233 -0
- data/lib/carray/fixlen_string.rb +95 -0
- data/lib/carray/frame/concat.rb +132 -0
- data/lib/carray/frame/convert.rb +95 -0
- data/lib/carray/frame/csv_parser.rb +211 -0
- data/lib/carray/frame/frame.rb +649 -0
- data/lib/carray/frame/group.rb +186 -0
- data/lib/carray/frame/io.rb +164 -0
- data/lib/carray/frame/join.rb +248 -0
- data/lib/carray/frame/records.rb +99 -0
- data/lib/carray/frame/sort.rb +113 -0
- data/lib/carray/frame/verbs.rb +299 -0
- data/lib/carray/frame.rb +16 -0
- data/lib/carray/histogram.rb +512 -0
- data/lib/carray/inspect.rb +37 -20
- data/lib/carray/iterator.rb +57 -349
- data/lib/carray/lazy.rb +889 -0
- data/lib/carray/mask_gap_fill.rb +200 -0
- data/lib/carray/math.rb +78 -342
- data/lib/carray/meld_reduce.rb +289 -0
- data/lib/carray/methods/align_addr.rb +116 -0
- data/lib/carray/methods/bin.rb +128 -0
- data/lib/carray/methods/bincount.rb +87 -0
- data/lib/carray/methods/bit_string.rb +92 -0
- data/lib/carray/methods/broadcast.rb +63 -0
- data/lib/carray/methods/choose.rb +39 -0
- data/lib/carray/methods/composition.rb +280 -0
- data/lib/carray/methods/gather_nd.rb +206 -0
- data/lib/carray/methods/index.rb +39 -0
- data/lib/carray/methods/insert_block.rb +99 -0
- data/lib/carray/methods/is_in.rb +141 -0
- data/lib/carray/methods/join.rb +90 -0
- data/lib/carray/methods/locate_addr.rb +47 -0
- data/lib/carray/methods/mask_duplicates.rb +41 -0
- data/lib/carray/methods/meshgrid.rb +91 -0
- data/lib/carray/methods/mode.rb +126 -0
- data/lib/carray/methods/nunique.rb +46 -0
- data/lib/carray/methods/resize.rb +56 -0
- data/lib/carray/methods/snap.rb +156 -0
- data/lib/carray/methods/string_format.rb +57 -0
- data/lib/carray/methods/unique.rb +47 -0
- data/lib/carray/methods/value_counts.rb +71 -0
- data/lib/carray/mkmf.rb +124 -101
- data/lib/carray/runtime.rb +108 -0
- data/lib/carray/serialize.rb +478 -167
- data/lib/carray/slab_iterator.rb +292 -0
- data/lib/carray/stack.rb +291 -0
- data/lib/carray/string.rb +56 -180
- data/lib/carray/string_operation_extension.rb +289 -0
- data/lib/carray/struct.rb +335 -323
- data/lib/carray/struct_builder.rb +697 -0
- data/lib/carray/table.rb +41 -2
- data/lib/carray/time.rb +2255 -38
- data/lib/carray/window_iterator.rb +655 -0
- data/lib/carray.rb +55 -57
- metadata +163 -130
- data/Rakefile +0 -51
- data/TODO.md +0 -18
- data/ext/ca_iter_block.c +0 -257
- data/ext/ca_iter_dimension.c +0 -299
- data/ext/ca_iter_window.c +0 -214
- data/ext/ca_obj_mapping.c +0 -644
- data/ext/carray_iterator.c +0 -641
- data/ext/carray_math.rb +0 -850
- data/ext/carray_numeric.c +0 -259
- data/ext/carray_sort_addr.c +0 -254
- data/ext/carray_stat.c +0 -2100
- data/ext/carray_stat_proc.rb +0 -1999
- data/ext/mkmath.rb +0 -741
- data/ext/ruby_ccomplex.c +0 -509
- data/ext/ruby_float_func.c +0 -86
- data/lib/carray/array.rb +0 -8
- data/lib/carray/autoload/autoload_base.rb +0 -19
- data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
- data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
- data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
- data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
- data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
- data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
- data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
- data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
- data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
- data/lib/carray/autoload/autoload_gem_random.rb +0 -8
- data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
- data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
- data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
- data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
- data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
- data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
- data/lib/carray/autoload/autoload_object_link.rb +0 -1
- data/lib/carray/autoload/autoload_object_pack.rb +0 -2
- data/lib/carray/autoload.rb +0 -141
- data/lib/carray/basic.rb +0 -191
- data/lib/carray/broadcast.rb +0 -101
- data/lib/carray/compose.rb +0 -315
- data/lib/carray/convert.rb +0 -115
- data/lib/carray/info.rb +0 -110
- data/lib/carray/io/imagemagick.rb +0 -235
- data/lib/carray/mask.rb +0 -102
- data/lib/carray/math/histogram.rb +0 -177
- data/lib/carray/math/recurrence.rb +0 -93
- data/lib/carray/object/ca_obj_iterator.rb +0 -50
- data/lib/carray/object/ca_obj_link.rb +0 -50
- data/lib/carray/object/ca_obj_pack.rb +0 -99
- data/lib/carray/obsolete.rb +0 -256
- data/lib/carray/ordering.rb +0 -181
- data/lib/carray/testing.rb +0 -51
- data/lib/carray/transform.rb +0 -109
- data/mailmap +0 -1
- data/misc/Methods.ja.md +0 -182
- data/misc/NOTE +0 -51
- data/spec/Classes/CABitfield_spec.rb +0 -58
- data/spec/Classes/CABlockIterator_spec.rb +0 -114
- data/spec/Classes/CABlock_spec.rb +0 -205
- data/spec/Classes/CAField_spec.rb +0 -39
- data/spec/Classes/CAGrid_spec.rb +0 -75
- data/spec/Classes/CAMap_spec.rb +0 -0
- data/spec/Classes/CAMapping_spec.rb +0 -105
- data/spec/Classes/CAObject_attribute_spec.rb +0 -33
- data/spec/Classes/CAObject_spec.rb +0 -33
- data/spec/Classes/CARefer_spec.rb +0 -93
- data/spec/Classes/CARepeat_spec.rb +0 -65
- data/spec/Classes/CASelect_spec.rb +0 -22
- data/spec/Classes/CAShift_spec.rb +0 -16
- data/spec/Classes/CAStruct_spec.rb +0 -71
- data/spec/Classes/CATranspose_spec.rb +0 -60
- data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
- data/spec/Classes/CAWindow_spec.rb +0 -54
- data/spec/Classes/CAWrap_spec.rb +0 -8
- data/spec/Classes/CArray_spec.rb +0 -184
- data/spec/Classes/CScalar_spec.rb +0 -55
- data/spec/Features/feature_130_spec.rb +0 -19
- data/spec/Features/feature_attributes_spec.rb +0 -280
- data/spec/Features/feature_boolean_spec.rb +0 -98
- data/spec/Features/feature_broadcast.rb +0 -116
- data/spec/Features/feature_cast_function.rb +0 -19
- data/spec/Features/feature_cast_spec.rb +0 -33
- data/spec/Features/feature_class_spec.rb +0 -84
- data/spec/Features/feature_complex_spec.rb +0 -42
- data/spec/Features/feature_composite_spec.rb +0 -124
- data/spec/Features/feature_convert_spec.rb +0 -46
- data/spec/Features/feature_copy_spec.rb +0 -123
- data/spec/Features/feature_creation_spec.rb +0 -84
- data/spec/Features/feature_element_spec.rb +0 -144
- data/spec/Features/feature_extream_spec.rb +0 -54
- data/spec/Features/feature_generate_spec.rb +0 -74
- data/spec/Features/feature_index_spec.rb +0 -69
- data/spec/Features/feature_mask_spec.rb +0 -580
- data/spec/Features/feature_math_spec.rb +0 -97
- data/spec/Features/feature_order_spec.rb +0 -146
- data/spec/Features/feature_ref_store_spec.rb +0 -209
- data/spec/Features/feature_serialization_spec.rb +0 -125
- data/spec/Features/feature_stat_spec.rb +0 -397
- data/spec/Features/feature_virtual_spec.rb +0 -48
- data/spec/Features/method_eq_spec.rb +0 -81
- data/spec/Features/method_is_nan_spec.rb +0 -12
- data/spec/Features/method_map_spec.rb +0 -54
- data/spec/Features/method_max_with.rb +0 -20
- data/spec/Features/method_min_with.rb +0 -19
- data/spec/Features/method_ne_spec.rb +0 -18
- data/spec/Features/method_project_spec.rb +0 -188
- data/spec/Features/method_ref_spec.rb +0 -27
- data/spec/Features/method_round_spec.rb +0 -11
- data/spec/Features/method_s_linspace_spec.rb +0 -48
- data/spec/Features/method_s_span_spec.rb +0 -14
- data/spec/Features/method_seq_spec.rb +0 -47
- data/spec/Features/method_sort_with.rb +0 -43
- data/spec/Features/method_sorted_with.rb +0 -29
- data/spec/Features/method_span_spec.rb +0 -42
- data/spec/Features/method_wrap_readonly_spec.rb +0 -43
- data/spec/UnitTest/test_CAVirtual.rb +0 -214
- data/spec/spec_all.rb +0 -10
- data/utils/ca_ase.rb +0 -21
- data/utils/ca_methods.rb +0 -15
- data/utils/cast_checker.rb +0 -30
- data/utils/convert_test.rb +0 -73
- data/utils/extract_yard.rb +0 -22
- data/utils/guess_shape.rb +0 -76
- data/utils/monkey_patch_methods.rb +0 -62
- data/utils/remove_resource_fork.sh +0 -5
|
@@ -0,0 +1,1296 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
CASelectAxis: per-axis boolean selection view (sister of CAGrid for integer
|
|
4
|
+
index). Mixes AP-axes (nil/Integer/Range) with one boolean-INDIRECT axis,
|
|
5
|
+
and gathers each per-INDIRECT slab using row-major byte strides.
|
|
6
|
+
|
|
7
|
+
Sibling of ca_obj_grid.c (CAGrid, the integer-index counterpart); both
|
|
8
|
+
emit a per-axis descriptor consumed by the shared engine in
|
|
9
|
+
ca_axis_dispatch.c.
|
|
10
|
+
|
|
11
|
+
Scope:
|
|
12
|
+
- single INDIRECT axis (boolean), other axes AP (nil/Integer/Range)
|
|
13
|
+
- parent must be an entity CArray (no CAStride parent)
|
|
14
|
+
- selector copied at construction (fully static, fragility-free)
|
|
15
|
+
- selector must not have a mask (hard reject)
|
|
16
|
+
- slab copy uses straightforward nested-loop memcpy (no SIMD fast paths)
|
|
17
|
+
|
|
18
|
+
---------------------------------------------------------------------------- */
|
|
19
|
+
|
|
20
|
+
#include "carray.h"
|
|
21
|
+
|
|
22
|
+
typedef struct {
|
|
23
|
+
/* CAView prefix (mirrors carray.h ca_virtual layout) */
|
|
24
|
+
int16_t obj_type;
|
|
25
|
+
int8_t data_type;
|
|
26
|
+
int8_t ndim;
|
|
27
|
+
int32_t flags;
|
|
28
|
+
ca_size_t bytes;
|
|
29
|
+
ca_size_t elements;
|
|
30
|
+
ca_size_t *dim;
|
|
31
|
+
char *ptr;
|
|
32
|
+
CArray *mask;
|
|
33
|
+
char *_pool; /* framework-managed pool buffer (NULL = legacy ALLOC_N path). */
|
|
34
|
+
CArray *parent;
|
|
35
|
+
uint32_t attach;
|
|
36
|
+
uint8_t nosync;
|
|
37
|
+
/* --- CASelectAxis tail ---
|
|
38
|
+
Single INDIRECT axis (boolean); the other axes are AP. */
|
|
39
|
+
int8_t indirect_axis; /* axis index of the boolean-selected axis */
|
|
40
|
+
CArray *selector; /* owned copy of boolean CArray (no mask) */
|
|
41
|
+
ca_size_t *ap_start; /* per axis (size ndim); unused for indirect axis */
|
|
42
|
+
ca_size_t *ap_count; /* per axis (size ndim); = dim[k] for AP axes */
|
|
43
|
+
ca_size_t *ap_step; /* per axis (size ndim); unused for indirect axis */
|
|
44
|
+
/* Derived at attach time; freed at detach. */
|
|
45
|
+
ca_size_t *indices; /* resolved indices for indirect axis (length = dim[indirect_axis]) */
|
|
46
|
+
/* Constant-step detection on indices. When indices form a constant-step
|
|
47
|
+
sequence (= consecutive TRUE block, full-TRUE mask, equally-spaced
|
|
48
|
+
mask), describe_axes emits STRIDE kind instead of INDEX, letting the
|
|
49
|
+
engine's STRIDE fast path (contiguous memcpy when step==1) replace
|
|
50
|
+
per-cell INDEX lookups. */
|
|
51
|
+
uint8_t stride_kind; /* 1 if indices form constant-step run */
|
|
52
|
+
ca_size_t stride_start;
|
|
53
|
+
ca_size_t stride_step;
|
|
54
|
+
} CASelectAxis;
|
|
55
|
+
|
|
56
|
+
static size_t
|
|
57
|
+
ca_select_axis_dsize (const void *ap)
|
|
58
|
+
{
|
|
59
|
+
const CASelectAxis *ca = (const CASelectAxis *) ap;
|
|
60
|
+
return sizeof(CASelectAxis)
|
|
61
|
+
+ ca->ndim * sizeof(ca_size_t) /* dim */
|
|
62
|
+
+ 3 * ca->ndim * sizeof(ca_size_t); /* ap_start, ap_count, ap_step */
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Pool framework hooks: the four ndim-sized arrays (dim, ap_start,
|
|
66
|
+
ap_count, ap_step) move into one _pool buffer. The variable-size
|
|
67
|
+
`indices` (count_true) and the `selector` CArray copy stay separate. */
|
|
68
|
+
static size_t
|
|
69
|
+
ca_select_axis_pool_bytes (int8_t ndim)
|
|
70
|
+
{
|
|
71
|
+
ca_size_t n = (ndim > 0) ? ndim : 1;
|
|
72
|
+
return 4 * (size_t) n * sizeof(ca_size_t);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static void
|
|
76
|
+
ca_select_axis_pool_init (void *ap, int8_t ndim)
|
|
77
|
+
{
|
|
78
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
79
|
+
ca_size_t n = (ndim > 0) ? ndim : 1;
|
|
80
|
+
ca_size_t *base = (ca_size_t *) ca->_pool;
|
|
81
|
+
ca->dim = base + 0 * n;
|
|
82
|
+
ca->ap_start = base + 1 * n;
|
|
83
|
+
ca->ap_count = base + 2 * n;
|
|
84
|
+
ca->ap_step = base + 3 * n;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const rb_data_type_t caselectaxis_data_type = {
|
|
88
|
+
.parent = &caview_data_type,
|
|
89
|
+
.wrap_struct_name = "CASelectAxis",
|
|
90
|
+
.function = {
|
|
91
|
+
.dmark = ca_mark,
|
|
92
|
+
.dfree = ca_free,
|
|
93
|
+
.dsize = ca_select_axis_dsize,
|
|
94
|
+
.dcompact = NULL
|
|
95
|
+
},
|
|
96
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const rb_data_type_t caselectaxis_mask_data_type = {
|
|
100
|
+
.parent = &caselectaxis_data_type,
|
|
101
|
+
.wrap_struct_name = "CASelectAxisMask",
|
|
102
|
+
.function = {
|
|
103
|
+
.dmark = NULL,
|
|
104
|
+
.dfree = ca_free_nop,
|
|
105
|
+
.dsize = ca_select_axis_dsize,
|
|
106
|
+
.dcompact = NULL
|
|
107
|
+
},
|
|
108
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
static int8_t CA_OBJ_SELECT_AXIS;
|
|
112
|
+
|
|
113
|
+
/* Benchmark-only bypass flag: when non-zero, rb_ca_grid skips the
|
|
114
|
+
CASelectAxis dispatch hook and falls through to the pre-CSA CAGrid path.
|
|
115
|
+
Exposed to Ruby as CArray._csa_bypass=. Production code never touches it. */
|
|
116
|
+
int ca_csa_dispatch_bypass = 0;
|
|
117
|
+
|
|
118
|
+
static VALUE
|
|
119
|
+
rb_ca_s_csa_bypass_eq (VALUE klass, VALUE val)
|
|
120
|
+
{
|
|
121
|
+
(void) klass;
|
|
122
|
+
ca_csa_dispatch_bypass = RTEST(val) ? 1 : 0;
|
|
123
|
+
return val;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static VALUE
|
|
127
|
+
rb_ca_s_csa_bypass_p (VALUE klass)
|
|
128
|
+
{
|
|
129
|
+
(void) klass;
|
|
130
|
+
return ca_csa_dispatch_bypass ? Qtrue : Qfalse;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
static VALUE rb_cCASelectAxis;
|
|
134
|
+
static VALUE rb_cCASelectAxisMask;
|
|
135
|
+
|
|
136
|
+
/* Forward declarations of internal helpers */
|
|
137
|
+
static CArray *ca_select_axis_new (CArray *parent, int8_t indirect_axis,
|
|
138
|
+
CArray *selector,
|
|
139
|
+
ca_size_t *ap_start,
|
|
140
|
+
ca_size_t *ap_count,
|
|
141
|
+
ca_size_t *ap_step);
|
|
142
|
+
|
|
143
|
+
/* ------------------------------------------------------------------- */
|
|
144
|
+
/* Setup / constructor / destructor */
|
|
145
|
+
/* ------------------------------------------------------------------- */
|
|
146
|
+
|
|
147
|
+
static int
|
|
148
|
+
ca_select_axis_setup (CASelectAxis *ca, CArray *parent, int8_t indirect_axis,
|
|
149
|
+
CArray *selector,
|
|
150
|
+
ca_size_t *ap_start, ca_size_t *ap_count, ca_size_t *ap_step)
|
|
151
|
+
{
|
|
152
|
+
int8_t k;
|
|
153
|
+
int8_t ndim = parent->ndim;
|
|
154
|
+
|
|
155
|
+
/* Validate indirect axis range */
|
|
156
|
+
if ( indirect_axis < 0 || indirect_axis >= ndim ) {
|
|
157
|
+
rb_raise(rb_eArgError,
|
|
158
|
+
"CASelectAxis: indirect_axis %d out of range [0, %d)",
|
|
159
|
+
indirect_axis, ndim);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Validate selector */
|
|
163
|
+
if ( ! ca_is_boolean_type(selector) ) {
|
|
164
|
+
rb_raise(rb_eArgError,
|
|
165
|
+
"CASelectAxis: selector must be a boolean CArray");
|
|
166
|
+
}
|
|
167
|
+
if ( selector->ndim != 1 ) {
|
|
168
|
+
rb_raise(rb_eArgError,
|
|
169
|
+
"CASelectAxis: selector must be 1-D");
|
|
170
|
+
}
|
|
171
|
+
if ( selector->dim[0] != parent->dim[indirect_axis] ) {
|
|
172
|
+
rb_raise(rb_eArgError,
|
|
173
|
+
"CASelectAxis: selector length (%lld) != parent dim[%d] (%lld)",
|
|
174
|
+
(long long) selector->dim[0],
|
|
175
|
+
(int) indirect_axis,
|
|
176
|
+
(long long) parent->dim[indirect_axis]);
|
|
177
|
+
}
|
|
178
|
+
if ( ca_has_mask(selector) ) {
|
|
179
|
+
rb_raise(rb_eArgError,
|
|
180
|
+
"CASelectAxis: selector boolean array must not have a mask. "
|
|
181
|
+
"Use `selector.strip_mask(false)` etc. to flatten first.");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* Validate AP axes */
|
|
185
|
+
for ( k = 0; k < ndim; k++ ) {
|
|
186
|
+
if ( k == indirect_axis ) continue;
|
|
187
|
+
if ( ap_step[k] == 0 ) {
|
|
188
|
+
rb_raise(rb_eArgError, "CASelectAxis: ap_step[%d] is 0", (int) k);
|
|
189
|
+
}
|
|
190
|
+
if ( ap_count[k] <= 0 ) {
|
|
191
|
+
rb_raise(rb_eArgError, "CASelectAxis: ap_count[%d] must be positive", (int) k);
|
|
192
|
+
}
|
|
193
|
+
{
|
|
194
|
+
ca_size_t start_v = ap_start[k];
|
|
195
|
+
ca_size_t last_v = ap_start[k] + (ap_count[k] - 1) * ap_step[k];
|
|
196
|
+
if ( start_v < 0 || start_v >= parent->dim[k] ) {
|
|
197
|
+
rb_raise(rb_eIndexError,
|
|
198
|
+
"CASelectAxis: ap_start[%d]=%lld out of range [0, %lld)",
|
|
199
|
+
(int) k, (long long) start_v, (long long) parent->dim[k]);
|
|
200
|
+
}
|
|
201
|
+
if ( last_v < 0 || last_v >= parent->dim[k] ) {
|
|
202
|
+
rb_raise(rb_eIndexError,
|
|
203
|
+
"CASelectAxis: ap last index at axis %d (%lld) out of range [0, %lld)",
|
|
204
|
+
(int) k, (long long) last_v, (long long) parent->dim[k]);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* Initialise struct */
|
|
210
|
+
ca->obj_type = CA_OBJ_SELECT_AXIS;
|
|
211
|
+
ca->data_type = parent->data_type;
|
|
212
|
+
ca->flags = 0;
|
|
213
|
+
ca->ndim = ndim;
|
|
214
|
+
ca->bytes = parent->bytes;
|
|
215
|
+
ca->ptr = NULL;
|
|
216
|
+
ca->mask = NULL;
|
|
217
|
+
ca->parent = parent;
|
|
218
|
+
ca->attach = 0;
|
|
219
|
+
ca->nosync = 0;
|
|
220
|
+
ca->indirect_axis = indirect_axis;
|
|
221
|
+
ca->indices = NULL;
|
|
222
|
+
|
|
223
|
+
/* Copy selector (view owns its own copy; immune to external mutation).
|
|
224
|
+
The selector is small (1 axis length), so the copy cost is acceptable,
|
|
225
|
+
and it avoids the fragility CASelect has from live references. */
|
|
226
|
+
ca->selector = ca_copy(selector);
|
|
227
|
+
|
|
228
|
+
/* Allocate dim and AP arrays (pool path: already wired by pool_init). */
|
|
229
|
+
if ( ! ca->_pool ) {
|
|
230
|
+
ca->dim = ALLOC_N(ca_size_t, ndim);
|
|
231
|
+
ca->ap_start = ALLOC_N(ca_size_t, ndim);
|
|
232
|
+
ca->ap_count = ALLOC_N(ca_size_t, ndim);
|
|
233
|
+
ca->ap_step = ALLOC_N(ca_size_t, ndim);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* Walk selector twice: first to count (auto-vectorisable), then to
|
|
237
|
+
snapshot TRUE positions into exactly-sized indices[]. Allocating to
|
|
238
|
+
the exact count avoids large over-allocations for sparse selectors.
|
|
239
|
+
This is the SOLE selector-walk phase in the view's lifecycle. */
|
|
240
|
+
ca_size_t count_true = 0;
|
|
241
|
+
ca_size_t n_input = ca->selector->elements;
|
|
242
|
+
{
|
|
243
|
+
boolean8_t *s = (boolean8_t *) ca->selector->ptr;
|
|
244
|
+
ca_size_t i;
|
|
245
|
+
for ( i = 0; i < n_input; i++ ) {
|
|
246
|
+
count_true += s[i]; /* boolean stored as 0/1, no branch */
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
ca->indices = ALLOC_N(ca_size_t, count_true > 0 ? count_true : 1);
|
|
250
|
+
{
|
|
251
|
+
boolean8_t *s = (boolean8_t *) ca->selector->ptr;
|
|
252
|
+
ca_size_t i, j = 0;
|
|
253
|
+
for ( i = 0; i < n_input; i++ ) {
|
|
254
|
+
if ( s[i] ) ca->indices[j++] = i;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* Constant-step detection: do indices[] form a constant-step sequence?
|
|
259
|
+
When YES, describe_axes emits STRIDE kind (start/step/count) instead of INDEX,
|
|
260
|
+
unlocking the engine's contig-memcpy fast path for common patterns
|
|
261
|
+
(all-TRUE mask, contiguous TRUE block, equally-spaced mask). */
|
|
262
|
+
ca->stride_kind = 0;
|
|
263
|
+
ca->stride_start = 0;
|
|
264
|
+
ca->stride_step = 1;
|
|
265
|
+
if ( count_true >= 2 ) {
|
|
266
|
+
ca_size_t step = ca->indices[1] - ca->indices[0];
|
|
267
|
+
ca_size_t i;
|
|
268
|
+
int is_const = 1;
|
|
269
|
+
for ( i = 2; i < count_true; i++ ) {
|
|
270
|
+
if ( ca->indices[i] - ca->indices[i-1] != step ) { is_const = 0; break; }
|
|
271
|
+
}
|
|
272
|
+
if ( is_const ) {
|
|
273
|
+
ca->stride_kind = 1;
|
|
274
|
+
ca->stride_start = ca->indices[0];
|
|
275
|
+
ca->stride_step = step;
|
|
276
|
+
}
|
|
277
|
+
} else if ( count_true == 1 ) {
|
|
278
|
+
/* single TRUE: degenerate STRIDE (count=1, step irrelevant) */
|
|
279
|
+
ca->stride_kind = 1;
|
|
280
|
+
ca->stride_start = ca->indices[0];
|
|
281
|
+
ca->stride_step = 1;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* Populate dim and AP arrays */
|
|
285
|
+
for ( k = 0; k < ndim; k++ ) {
|
|
286
|
+
if ( k == indirect_axis ) {
|
|
287
|
+
ca->dim[k] = count_true;
|
|
288
|
+
ca->ap_start[k] = 0;
|
|
289
|
+
ca->ap_count[k] = count_true;
|
|
290
|
+
ca->ap_step[k] = 1;
|
|
291
|
+
} else {
|
|
292
|
+
ca->dim[k] = ap_count[k];
|
|
293
|
+
ca->ap_start[k] = ap_start[k];
|
|
294
|
+
ca->ap_count[k] = ap_count[k];
|
|
295
|
+
ca->ap_step[k] = ap_step[k];
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/* Compute total elements */
|
|
300
|
+
ca->elements = 1;
|
|
301
|
+
for ( k = 0; k < ndim; k++ ) {
|
|
302
|
+
ca->elements *= ca->dim[k];
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return 0;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
static CArray *
|
|
309
|
+
ca_select_axis_new (CArray *parent, int8_t indirect_axis,
|
|
310
|
+
CArray *selector,
|
|
311
|
+
ca_size_t *ap_start, ca_size_t *ap_count, ca_size_t *ap_step)
|
|
312
|
+
{
|
|
313
|
+
CASelectAxis *ca = (CASelectAxis *) ca_array_alloc(CA_OBJ_SELECT_AXIS, parent->ndim);
|
|
314
|
+
ca_select_axis_setup(ca, parent, indirect_axis, selector,
|
|
315
|
+
ap_start, ap_count, ap_step);
|
|
316
|
+
return (CArray *) ca;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
static void
|
|
320
|
+
free_ca_select_axis (void *ap)
|
|
321
|
+
{
|
|
322
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
323
|
+
if ( ca != NULL ) {
|
|
324
|
+
ca_free(ca->mask);
|
|
325
|
+
if ( ca->selector ) ca_free(ca->selector);
|
|
326
|
+
if ( ca->indices ) xfree(ca->indices); /* variable-size, separate */
|
|
327
|
+
if ( ca->_pool ) {
|
|
328
|
+
/* dim/ap_start/ap_count/ap_step all live in _pool. */
|
|
329
|
+
ca_array_free(ca);
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
if ( ca->ap_start ) xfree(ca->ap_start);
|
|
333
|
+
if ( ca->ap_count ) xfree(ca->ap_count);
|
|
334
|
+
if ( ca->ap_step ) xfree(ca->ap_step);
|
|
335
|
+
if ( ca->dim ) xfree(ca->dim);
|
|
336
|
+
xfree(ca);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* ------------------------------------------------------------------- */
|
|
342
|
+
/* Operation functions */
|
|
343
|
+
/* */
|
|
344
|
+
/* All gather / scatter / fill paths delegate to the common descriptor */
|
|
345
|
+
/* engine in ext/ca_axis_dispatch.c. This file holds only view-specific */
|
|
346
|
+
/* concerns: setup, describe_axes, mask, lifecycle. */
|
|
347
|
+
/* ------------------------------------------------------------------- */
|
|
348
|
+
|
|
349
|
+
static void *
|
|
350
|
+
ca_select_axis_func_clone (void *ap)
|
|
351
|
+
{
|
|
352
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
353
|
+
return ca_select_axis_new(ca->parent, ca->indirect_axis, ca->selector,
|
|
354
|
+
ca->ap_start, ca->ap_count, ca->ap_step);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/* Compute parent index for a single output index, without requiring attach.
|
|
358
|
+
Uses the pre-computed ca->indices[] snapshot (built once at setup) for the
|
|
359
|
+
indirect axis -- O(1) indirect load. */
|
|
360
|
+
static void
|
|
361
|
+
ca_select_axis_output_to_parent_idx (CASelectAxis *ca, ca_size_t *out_idx,
|
|
362
|
+
ca_size_t *parent_idx)
|
|
363
|
+
{
|
|
364
|
+
int8_t k;
|
|
365
|
+
int8_t iax = ca->indirect_axis;
|
|
366
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
367
|
+
if ( k == iax ) {
|
|
368
|
+
parent_idx[k] = ca->indices[out_idx[k]];
|
|
369
|
+
} else {
|
|
370
|
+
parent_idx[k] = ca->ap_start[k] + out_idx[k] * ca->ap_step[k];
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/* per-cell logic lives in ca_select_axis_func_xfer_index; forward-declared
|
|
376
|
+
for the region-delivery paths below. */
|
|
377
|
+
static void ca_select_axis_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir);
|
|
378
|
+
|
|
379
|
+
/* dir-unified per-cell. Direct addressing when attached; otherwise
|
|
380
|
+
translate the output index to
|
|
381
|
+
parent's index and delegate to ca_xfer_index (which handles boundary-view
|
|
382
|
+
parents safely -- replaces the old ptr_at_index-based path). */
|
|
383
|
+
static void
|
|
384
|
+
ca_select_axis_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
385
|
+
{
|
|
386
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
387
|
+
if ( ca->ptr ) {
|
|
388
|
+
ca_size_t addr = ca_index2addr((CArray *) ca, idx);
|
|
389
|
+
char *p = ca->ptr + ca->bytes * addr;
|
|
390
|
+
if (dir == CA_XFER_GET) memcpy(data, p, ca->bytes);
|
|
391
|
+
else memcpy(p, data, ca->bytes);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
/* Not attached: compute parent's index, delegate. */
|
|
395
|
+
ca_size_t pidx[CA_RANK_MAX];
|
|
396
|
+
ca_select_axis_output_to_parent_idx(ca, idx, pidx);
|
|
397
|
+
ca_xfer_index(ca->parent, pidx, data, dir);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* Batched address gather/scatter. Per-axis output->parent index remap,
|
|
401
|
+
always in-bounds. ONE parent ca_xfer_addrs call -- no whole-view attach.
|
|
402
|
+
|
|
403
|
+
Fast path: when the addrs are a whole-view sequential run
|
|
404
|
+
[0..elements-1] and parent.ptr is present, bypass the ALLOCV per-cell
|
|
405
|
+
remap loop and dispatch directly to ca_axis_dispatch_gather/_scatter
|
|
406
|
+
(same engine xfer_all uses). This fires for the hot pattern
|
|
407
|
+
ca[:is_not_masked] / ca[mostly_true_mask], which degenerates to
|
|
408
|
+
whole-view sequential addrs through this slot. Sub-region sequential
|
|
409
|
+
addrs are not lifted (would require row-major rectangular
|
|
410
|
+
reconstruction); the per-cell path handles them. No ca_attach added;
|
|
411
|
+
parent.ptr is opportunistic. */
|
|
412
|
+
static void
|
|
413
|
+
ca_select_axis_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
414
|
+
void *data, int dir)
|
|
415
|
+
{
|
|
416
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
417
|
+
CArray *parent = ca->parent;
|
|
418
|
+
ca_size_t *paddrs;
|
|
419
|
+
ca_size_t i, base;
|
|
420
|
+
volatile VALUE holder;
|
|
421
|
+
|
|
422
|
+
/* Opportunistic fast path. ca_resolve_attached_root_via_identity lifts
|
|
423
|
+
parent->ptr through an identity CAStride compose-fold (= a CARefer
|
|
424
|
+
reshape view over an entity, etc.). */
|
|
425
|
+
if ( n == ca->elements
|
|
426
|
+
&& ca_xfer_addrs_is_sequential_run(n, addrs, &base) && base == 0 ) {
|
|
427
|
+
CArray *eff_parent = ca_resolve_attached_root_via_identity(parent);
|
|
428
|
+
if ( eff_parent->ptr ) {
|
|
429
|
+
ca_axis_desc_t sub_axes[CA_RANK_MAX];
|
|
430
|
+
ca_size_t parent_axis_dims[CA_RANK_MAX];
|
|
431
|
+
int8_t k, iax = ca->indirect_axis;
|
|
432
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
433
|
+
parent_axis_dims[k] = parent->dim[k];
|
|
434
|
+
if ( k == iax ) {
|
|
435
|
+
sub_axes[k].kind = CA_AXIS_KIND_INDEX;
|
|
436
|
+
sub_axes[k].count = ca->dim[k];
|
|
437
|
+
sub_axes[k].start = 0;
|
|
438
|
+
sub_axes[k].step = 0;
|
|
439
|
+
sub_axes[k].indices = ca->indices; /* pre-computed TRUE positions */
|
|
440
|
+
} else {
|
|
441
|
+
sub_axes[k].kind = CA_AXIS_KIND_STRIDE;
|
|
442
|
+
sub_axes[k].count = ca->dim[k];
|
|
443
|
+
sub_axes[k].start = ca->ap_start[k];
|
|
444
|
+
sub_axes[k].step = ca->ap_step[k];
|
|
445
|
+
sub_axes[k].indices = NULL;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if ( dir == CA_XFER_GET ) {
|
|
449
|
+
ca_axis_dispatch_gather(eff_parent, parent_axis_dims, sub_axes, ca->ndim,
|
|
450
|
+
ca->bytes, ca->elements, NULL, (char *) data);
|
|
451
|
+
} else {
|
|
452
|
+
ca_axis_dispatch_scatter(eff_parent, parent_axis_dims, sub_axes, ca->ndim,
|
|
453
|
+
ca->bytes, ca->elements, (char *) data);
|
|
454
|
+
}
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* Per-cell remap fallback (arbitrary addrs, view parent, partial). */
|
|
460
|
+
paddrs = ALLOCV_N(ca_size_t, holder, n);
|
|
461
|
+
for (i = 0; i < n; i++) {
|
|
462
|
+
ca_size_t vidx[CA_RANK_MAX], pidx[CA_RANK_MAX];
|
|
463
|
+
ca_addr2index((CArray *) ca, addrs[i], vidx);
|
|
464
|
+
ca_select_axis_output_to_parent_idx(ca, vidx, pidx);
|
|
465
|
+
paddrs[i] = ca_index2addr(ca->parent, pidx);
|
|
466
|
+
}
|
|
467
|
+
ca_xfer_addrs(ca->parent, n, paddrs, data, dir);
|
|
468
|
+
ALLOCV_END(holder);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/* fold_stride: a CSA folds when every axis is stride-expressible. AP
|
|
472
|
+
(non-indirect) axes always are
|
|
473
|
+
(start_k + i*step_k). The boolean-selected (indirect) axis folds only when
|
|
474
|
+
it selects exactly one element (dim == 1): the single TRUE position bakes
|
|
475
|
+
into the base. A multi-element selection is a true gather -> decline.
|
|
476
|
+
Synthesises a CAStride over parent and composes f through it. */
|
|
477
|
+
static int
|
|
478
|
+
ca_select_axis_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
|
|
479
|
+
{
|
|
480
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
481
|
+
CArray *parent = ca->parent;
|
|
482
|
+
int8_t iax = ca->indirect_axis;
|
|
483
|
+
ca_size_t pstride[CA_RANK_MAX];
|
|
484
|
+
ca_size_t synth_strides[CA_RANK_MAX];
|
|
485
|
+
ca_size_t synth_base = 0;
|
|
486
|
+
ca_size_t next_strides[CA_RANK_MAX];
|
|
487
|
+
ca_size_t next_base;
|
|
488
|
+
ca_size_t s;
|
|
489
|
+
CAStride tmp, synth;
|
|
490
|
+
int8_t k;
|
|
491
|
+
|
|
492
|
+
if ( ca->dim[iax] != 1 ) {
|
|
493
|
+
return 0; /* multi-element boolean selection -> true gather, decline */
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/* parent row-major byte strides (ca->bytes == parent->bytes) */
|
|
497
|
+
s = ca->bytes;
|
|
498
|
+
for (k = ca->ndim - 1; k >= 0; k--) {
|
|
499
|
+
pstride[k] = s;
|
|
500
|
+
s *= parent->dim[k];
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
for (k = 0; k < ca->ndim; k++) {
|
|
504
|
+
if ( k == iax ) {
|
|
505
|
+
/* single TRUE position (dim==1 case) -> baked into base (count 1).
|
|
506
|
+
Pre-computed in ca->indices[0] at setup; no re-scan of selector. */
|
|
507
|
+
synth_strides[k] = 0;
|
|
508
|
+
synth_base += ca->indices[0] * pstride[k];
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
synth_strides[k] = ca->ap_step[k] * pstride[k];
|
|
512
|
+
synth_base += ca->ap_start[k] * pstride[k];
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
tmp.ndim = f->ndim;
|
|
517
|
+
tmp.bytes = ca->bytes;
|
|
518
|
+
tmp.dim = f->counts;
|
|
519
|
+
tmp.strides = f->strides;
|
|
520
|
+
tmp.base_offset = f->base;
|
|
521
|
+
|
|
522
|
+
synth.ndim = ca->ndim;
|
|
523
|
+
synth.bytes = ca->bytes;
|
|
524
|
+
synth.dim = ca->dim;
|
|
525
|
+
synth.strides = synth_strides;
|
|
526
|
+
synth.base_offset = synth_base;
|
|
527
|
+
|
|
528
|
+
if (!ca_stride_compose_through(&tmp, &synth, next_strides, &next_base)) {
|
|
529
|
+
return 0;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
for (k = 0; k < f->ndim; k++) f->strides[k] = next_strides[k];
|
|
533
|
+
f->base = next_base;
|
|
534
|
+
*next_parent = parent;
|
|
535
|
+
return 1;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/* xfer_stride: structural region delivery when a multi-select CSA is the
|
|
539
|
+
(declining) fold boundary. Mirrors CAGrid:
|
|
540
|
+
the indirect (boolean-selected) axis behaves like INDEX, the AP axes like
|
|
541
|
+
STRIDE. Iterate the outer axes; deliver the innermost axis as one run --
|
|
542
|
+
parent.xfer_stride for an AP inner axis, parent.xfer_addrs for the indirect
|
|
543
|
+
inner axis. data is contiguous (semantics b, no whole-view attach).
|
|
544
|
+
The indirect axis's TRUE positions are resolved once from the selector
|
|
545
|
+
(snapshot, no attach). Non-axis-aligned / unexpected requests fall back to
|
|
546
|
+
per-cell delivery (the wiring guards ndim == parent ndim). */
|
|
547
|
+
static void
|
|
548
|
+
ca_select_axis_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
549
|
+
ca_size_t *strides, void *data, int dir)
|
|
550
|
+
{
|
|
551
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
552
|
+
CArray *parent = ca->parent;
|
|
553
|
+
int8_t ndim = ca->ndim;
|
|
554
|
+
int8_t inner = ndim - 1;
|
|
555
|
+
int8_t iax = ca->indirect_axis;
|
|
556
|
+
ca_size_t pnative[CA_RANK_MAX]; /* parent row-major byte strides */
|
|
557
|
+
ca_size_t cnative[CA_RANK_MAX]; /* CSA row-major byte strides */
|
|
558
|
+
ca_size_t dstride[CA_RANK_MAX]; /* data row-major byte strides over counts */
|
|
559
|
+
ca_size_t src_step[CA_RANK_MAX];
|
|
560
|
+
ca_size_t o[CA_RANK_MAX];
|
|
561
|
+
const ca_size_t *tpos; /* TRUE positions of indirect axis (= ca->indices) */
|
|
562
|
+
ca_size_t s;
|
|
563
|
+
int8_t k;
|
|
564
|
+
int aligned = 1;
|
|
565
|
+
char *d = (char *) data;
|
|
566
|
+
|
|
567
|
+
s = parent->bytes;
|
|
568
|
+
for (k = ndim - 1; k >= 0; k--) { pnative[k] = s; s *= parent->dim[k]; }
|
|
569
|
+
s = ca->bytes;
|
|
570
|
+
for (k = ndim - 1; k >= 0; k--) { cnative[k] = s; s *= ca->dim[k]; }
|
|
571
|
+
s = ca->bytes;
|
|
572
|
+
for (k = ndim - 1; k >= 0; k--) { dstride[k] = s; s *= counts[k]; }
|
|
573
|
+
|
|
574
|
+
for (k = 0; k < ndim; k++) {
|
|
575
|
+
if (strides[k] % cnative[k] != 0) { aligned = 0; break; }
|
|
576
|
+
src_step[k] = strides[k] / cnative[k];
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (!aligned) {
|
|
580
|
+
ca_size_t idx[CA_RANK_MAX], doff = 0, base = 0;
|
|
581
|
+
for (k = 0; k < ndim; k++) base += starts[k] * cnative[k];
|
|
582
|
+
for (k = 0; k < ndim; k++) idx[k] = 0;
|
|
583
|
+
while (1) {
|
|
584
|
+
ca_size_t coff = base, cidx[CA_RANK_MAX];
|
|
585
|
+
for (k = 0; k < ndim; k++) coff += idx[k] * strides[k];
|
|
586
|
+
ca_addr2index((CArray *) ca, coff / ca->bytes, cidx);
|
|
587
|
+
ca_select_axis_func_xfer_index(ca, cidx, d + doff, dir);
|
|
588
|
+
doff += ca->bytes;
|
|
589
|
+
k = ndim - 1;
|
|
590
|
+
while (k >= 0) { if (++idx[k] < counts[k]) break; idx[k] = 0; k--; }
|
|
591
|
+
if (k < 0) break;
|
|
592
|
+
}
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/* TRUE positions of the indirect axis are pre-computed in ca->indices[]
|
|
597
|
+
at setup (length = ca->dim[iax] = count_true). */
|
|
598
|
+
tpos = ca->indices;
|
|
599
|
+
|
|
600
|
+
/* Fast path: when parent is attached (ptr != NULL), translate the
|
|
601
|
+
sub-region request (starts/counts/src_step) into a transient
|
|
602
|
+
ca_axis_desc_t[] sub-descriptor and call
|
|
603
|
+
ca_axis_dispatch_gather/_scatter directly. Same engine entry
|
|
604
|
+
ca_select_axis_func_xfer_all uses (minus the ca_attach(parent) call,
|
|
605
|
+
which per-region functions must not do). Collapses count_true
|
|
606
|
+
outer-dispatch calls into 1 batched engine call. Mirrors the CAGrid
|
|
607
|
+
xfer_stride fast path, with indirect_axis playing the role of an INDEX
|
|
608
|
+
axis.
|
|
609
|
+
|
|
610
|
+
Parent unattached (= view parent) falls through to the per-row loop
|
|
611
|
+
below. */
|
|
612
|
+
if ( parent->ptr ) {
|
|
613
|
+
ca_axis_desc_t sub_axes[CA_RANK_MAX];
|
|
614
|
+
ca_size_t parent_axis_dims[CA_RANK_MAX];
|
|
615
|
+
ca_size_t *index_buf = NULL;
|
|
616
|
+
volatile VALUE index_holder = Qnil;
|
|
617
|
+
ca_size_t total_elements = 1;
|
|
618
|
+
ca_size_t j;
|
|
619
|
+
|
|
620
|
+
for ( k = 0; k < ndim; k++ ) {
|
|
621
|
+
parent_axis_dims[k] = parent->dim[k];
|
|
622
|
+
total_elements *= counts[k];
|
|
623
|
+
if ( k == iax ) {
|
|
624
|
+
/* INDIRECT axis */
|
|
625
|
+
sub_axes[k].kind = CA_AXIS_KIND_INDEX;
|
|
626
|
+
sub_axes[k].count = counts[k];
|
|
627
|
+
sub_axes[k].start = 0;
|
|
628
|
+
sub_axes[k].step = 0;
|
|
629
|
+
if ( src_step[k] == 1 ) {
|
|
630
|
+
/* zero-copy pointer offset */
|
|
631
|
+
sub_axes[k].indices = (ca_size_t *)(tpos + starts[k]);
|
|
632
|
+
} else {
|
|
633
|
+
/* sub-sampled or reversed: materialise sub-indices */
|
|
634
|
+
index_buf = ALLOCV_N(ca_size_t, index_holder, counts[k]);
|
|
635
|
+
for ( j = 0; j < counts[k]; j++ ) {
|
|
636
|
+
index_buf[j] = tpos[starts[k] + j * src_step[k]];
|
|
637
|
+
}
|
|
638
|
+
sub_axes[k].indices = index_buf;
|
|
639
|
+
}
|
|
640
|
+
} else {
|
|
641
|
+
/* AP / STRIDE axis */
|
|
642
|
+
sub_axes[k].kind = CA_AXIS_KIND_STRIDE;
|
|
643
|
+
sub_axes[k].count = counts[k];
|
|
644
|
+
sub_axes[k].start = ca->ap_start[k] + starts[k] * ca->ap_step[k];
|
|
645
|
+
sub_axes[k].step = ca->ap_step[k] * src_step[k];
|
|
646
|
+
sub_axes[k].indices = NULL;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
if ( dir == CA_XFER_GET ) {
|
|
651
|
+
ca_axis_dispatch_gather(parent, parent_axis_dims, sub_axes, ndim,
|
|
652
|
+
ca->bytes, total_elements, NULL, d);
|
|
653
|
+
} else {
|
|
654
|
+
ca_axis_dispatch_scatter(parent, parent_axis_dims, sub_axes, ndim,
|
|
655
|
+
ca->bytes, total_elements, d);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
if ( index_buf != NULL ) ALLOCV_END(index_holder);
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/* Fallback (parent unattached): per-row outer loop + per-row
|
|
663
|
+
ca_xfer_stride/ca_xfer_addrs. */
|
|
664
|
+
for (k = 0; k < ndim; k++) o[k] = 0;
|
|
665
|
+
|
|
666
|
+
while (1) {
|
|
667
|
+
ca_size_t pbase = 0, doff = 0;
|
|
668
|
+
for (k = 0; k < inner; k++) {
|
|
669
|
+
ca_size_t gpos = starts[k] + o[k] * src_step[k];
|
|
670
|
+
ca_size_t ppos = (k == iax) ? tpos[gpos]
|
|
671
|
+
: (ca->ap_start[k] + gpos * ca->ap_step[k]);
|
|
672
|
+
pbase += ppos * pnative[k];
|
|
673
|
+
doff += o[k] * dstride[k];
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
if (inner != iax) { /* AP inner axis -> STRIDE run */
|
|
677
|
+
ca_size_t pstarts[CA_RANK_MAX], pcounts[CA_RANK_MAX], pstrides[CA_RANK_MAX];
|
|
678
|
+
ca_size_t inner_pbase =
|
|
679
|
+
(ca->ap_start[inner] + starts[inner] * ca->ap_step[inner]) * pnative[inner];
|
|
680
|
+
ca_addr2index((CArray *) parent, (pbase + inner_pbase) / parent->bytes, pstarts);
|
|
681
|
+
for (k = 0; k < ndim; k++) { pcounts[k] = 1; pstrides[k] = 0; }
|
|
682
|
+
pcounts[inner] = counts[inner];
|
|
683
|
+
pstrides[inner] = src_step[inner] * ca->ap_step[inner] * pnative[inner];
|
|
684
|
+
ca_xfer_stride(parent, pstarts, pcounts, pstrides, d + doff, dir);
|
|
685
|
+
}
|
|
686
|
+
else { /* indirect inner axis -> gather */
|
|
687
|
+
ca_size_t *addrs;
|
|
688
|
+
ca_size_t j, n = counts[inner];
|
|
689
|
+
volatile VALUE holder;
|
|
690
|
+
addrs = ALLOCV_N(ca_size_t, holder, n);
|
|
691
|
+
for (j = 0; j < n; j++) {
|
|
692
|
+
ca_size_t gpos = starts[inner] + j * src_step[inner];
|
|
693
|
+
addrs[j] = (pbase + tpos[gpos] * pnative[inner]) / parent->bytes;
|
|
694
|
+
}
|
|
695
|
+
ca_xfer_addrs(parent, n, addrs, d + doff, dir);
|
|
696
|
+
ALLOCV_END(holder);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
k = inner - 1;
|
|
700
|
+
while (k >= 0) { if (++o[k] < counts[k]) break; o[k] = 0; k--; }
|
|
701
|
+
if (k < 0) break;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
static void
|
|
706
|
+
ca_select_axis_func_allocate (void *ap)
|
|
707
|
+
{
|
|
708
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
709
|
+
ca_attach(ca->parent);
|
|
710
|
+
ca->ptr = xmalloc(ca_length(ca));
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/* attach / sync / copy_data / sync_data / fill_data all go through the
|
|
714
|
+
common descriptor engine. This file holds only describe_axes for
|
|
715
|
+
translating CSA state into the shared descriptor; the engine in
|
|
716
|
+
ext/ca_axis_dispatch.c does the rest. */
|
|
717
|
+
|
|
718
|
+
static void
|
|
719
|
+
ca_select_axis_func_attach (void *ap)
|
|
720
|
+
{
|
|
721
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
722
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
723
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
724
|
+
ca_attach(ca->parent);
|
|
725
|
+
ca_select_axis_describe_axes(ca, desc, pdims);
|
|
726
|
+
ca->ptr = ca_axis_dispatch_attach(ca->parent, pdims, desc, ca->ndim,
|
|
727
|
+
ca->bytes, ca->elements, NULL);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
static void
|
|
731
|
+
ca_select_axis_func_sync (void *ap)
|
|
732
|
+
{
|
|
733
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
734
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
735
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
736
|
+
ca_select_axis_describe_axes(ca, desc, pdims);
|
|
737
|
+
ca_axis_dispatch_scatter(ca->parent, pdims, desc, ca->ndim, ca->bytes,
|
|
738
|
+
ca->elements, ca->ptr);
|
|
739
|
+
ca_sync(ca->parent);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
static void
|
|
743
|
+
ca_select_axis_func_detach (void *ap)
|
|
744
|
+
{
|
|
745
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
746
|
+
if ( ca->ptr ) {
|
|
747
|
+
xfree(ca->ptr);
|
|
748
|
+
ca->ptr = NULL;
|
|
749
|
+
}
|
|
750
|
+
/* indices[] lives for the view's lifetime; freed in free_ca_select_axis. */
|
|
751
|
+
ca_detach(ca->parent);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/* xfer_all: fast path on parent->ptr, with no silent transitive attach
|
|
755
|
+
of the parent. A cold parent uses a proper 2-pass (materialise the
|
|
756
|
+
parent into scratch, expose it as parent->ptr, run the fast path, then
|
|
757
|
+
write scratch back for PUT). */
|
|
758
|
+
static void
|
|
759
|
+
ca_select_axis_func_run_fast_path (CASelectAxis *ca, char *data, int dir)
|
|
760
|
+
{
|
|
761
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
762
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
763
|
+
ca_select_axis_describe_axes(ca, desc, pdims);
|
|
764
|
+
if ( dir == CA_XFER_GET ) {
|
|
765
|
+
ca_axis_dispatch_gather(ca->parent, pdims, desc, ca->ndim, ca->bytes,
|
|
766
|
+
ca->elements, NULL, data);
|
|
767
|
+
} else {
|
|
768
|
+
ca_axis_dispatch_scatter(ca->parent, pdims, desc, ca->ndim, ca->bytes,
|
|
769
|
+
ca->elements, data);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
static void
|
|
774
|
+
ca_select_axis_func_xfer_all (void *ap, void *data, int dir)
|
|
775
|
+
{
|
|
776
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
777
|
+
if ( ca->parent->ptr ) {
|
|
778
|
+
ca_select_axis_func_run_fast_path(ca, (char *) data, dir);
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
/* Proper 2-pass cold fallback. */
|
|
782
|
+
{
|
|
783
|
+
volatile VALUE holder;
|
|
784
|
+
CArray *parent = ca->parent;
|
|
785
|
+
ca_size_t plen = parent->elements * parent->bytes;
|
|
786
|
+
char *parent_scratch = ALLOCV_N(char, holder, plen);
|
|
787
|
+
char *parent_ptr_saved = parent->ptr;
|
|
788
|
+
ca_xfer_all(parent, parent_scratch, CA_XFER_GET);
|
|
789
|
+
parent->ptr = parent_scratch;
|
|
790
|
+
ca_select_axis_func_run_fast_path(ca, (char *) data, dir);
|
|
791
|
+
if ( dir == CA_XFER_PUT ) {
|
|
792
|
+
ca_xfer_all(parent, parent_scratch, CA_XFER_PUT);
|
|
793
|
+
}
|
|
794
|
+
parent->ptr = parent_ptr_saved;
|
|
795
|
+
ALLOCV_END(holder);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
static void
|
|
800
|
+
ca_select_axis_func_fill_data (void *ap, void *val)
|
|
801
|
+
{
|
|
802
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
803
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
804
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
805
|
+
|
|
806
|
+
ca_select_axis_describe_axes(ca, desc, pdims);
|
|
807
|
+
|
|
808
|
+
/* Writing the selected cells used to go through a whole-parent attach and
|
|
809
|
+
sync. Where that attach is a gather rather than an alias, the cells this
|
|
810
|
+
view did not select make the round trip for nothing -- and through a
|
|
811
|
+
lossy layer they do not come back the same. Hand each slab to the parent
|
|
812
|
+
as a region instead. (PROPOSAL_PARTIAL_FILL_WHOLE_ROOT_WRITEBACK.md) */
|
|
813
|
+
if ( !ca_is_attached(ca->parent) && !ca_attach_is_alias(ca->parent) ) {
|
|
814
|
+
ca_axis_dispatch_fill_value_via_parent(ca->parent, pdims, desc, ca->ndim,
|
|
815
|
+
ca->bytes, ca->elements, val);
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
ca_attach(ca->parent);
|
|
820
|
+
ca_axis_dispatch_fill_value(ca->parent, pdims, desc, ca->ndim, ca->bytes,
|
|
821
|
+
ca->elements, val);
|
|
822
|
+
ca_sync(ca->parent);
|
|
823
|
+
ca_detach(ca->parent);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
static void
|
|
827
|
+
ca_select_axis_func_create_mask (void *ap)
|
|
828
|
+
{
|
|
829
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
830
|
+
ca_update_mask(ca->parent);
|
|
831
|
+
if ( ! ca->parent->mask ) {
|
|
832
|
+
ca_create_mask(ca->parent);
|
|
833
|
+
}
|
|
834
|
+
ca->mask = ca_select_axis_new(ca->parent->mask, ca->indirect_axis,
|
|
835
|
+
ca->selector,
|
|
836
|
+
ca->ap_start, ca->ap_count, ca->ap_step);
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
ca_operation_function_t ca_select_axis_func = {
|
|
840
|
+
-1, /* CA_OBJ_SELECT_AXIS, populated at install time */
|
|
841
|
+
CA_VIEW_ARRAY,
|
|
842
|
+
free_ca_select_axis,
|
|
843
|
+
ca_select_axis_func_clone,
|
|
844
|
+
ca_select_axis_func_allocate,
|
|
845
|
+
ca_select_axis_func_attach,
|
|
846
|
+
ca_select_axis_func_sync,
|
|
847
|
+
ca_select_axis_func_detach,
|
|
848
|
+
ca_select_axis_func_fill_data,
|
|
849
|
+
ca_select_axis_func_create_mask,
|
|
850
|
+
ca_select_axis_func_xfer_index,
|
|
851
|
+
ca_select_axis_func_xfer_addrs,
|
|
852
|
+
ca_select_axis_func_fold_stride,
|
|
853
|
+
ca_select_axis_func_xfer_stride,
|
|
854
|
+
ca_select_axis_func_xfer_all,
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
/* ------------------------------------------------------------------- */
|
|
858
|
+
/* Ruby surface (debug constructor + indexer dispatch) */
|
|
859
|
+
/* ------------------------------------------------------------------- */
|
|
860
|
+
|
|
861
|
+
static VALUE
|
|
862
|
+
rb_ca_select_axis_s_allocate (VALUE klass)
|
|
863
|
+
{
|
|
864
|
+
CASelectAxis *ca;
|
|
865
|
+
return TypedData_Make_Struct(klass, CASelectAxis, &caselectaxis_data_type, ca);
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
static VALUE
|
|
869
|
+
rb_ca_select_axis_initialize_copy (VALUE self, VALUE other)
|
|
870
|
+
{
|
|
871
|
+
CASelectAxis *ca, *cs;
|
|
872
|
+
TypedData_Get_Struct(self, CASelectAxis, &caselectaxis_data_type, ca);
|
|
873
|
+
TypedData_Get_Struct(other, CASelectAxis, &caselectaxis_data_type, cs);
|
|
874
|
+
if ( ca_func[CA_OBJ_SELECT_AXIS].pool_init ) {
|
|
875
|
+
ca_array_pool_alloc(ca, CA_OBJ_SELECT_AXIS, cs->parent->ndim);
|
|
876
|
+
}
|
|
877
|
+
ca_select_axis_setup(ca, cs->parent, cs->indirect_axis, cs->selector,
|
|
878
|
+
cs->ap_start, cs->ap_count, cs->ap_step);
|
|
879
|
+
return self;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/* Debug-only Ruby ctor:
|
|
883
|
+
CASelectAxis._new_debug(parent, indirect_axis, selector,
|
|
884
|
+
ap_start_arr, ap_count_arr, ap_step_arr)
|
|
885
|
+
|
|
886
|
+
ap_*_arr are Arrays of size parent.ndim. Entries for the indirect axis
|
|
887
|
+
are ignored. Intended for testing only; production dispatch runs
|
|
888
|
+
through rb_ca_select_axis (from the `[]` indexer in carray_access.c). */
|
|
889
|
+
static VALUE
|
|
890
|
+
rb_ca_select_axis_s_new_debug (VALUE klass, VALUE rparent, VALUE rindirect,
|
|
891
|
+
VALUE rselector, VALUE rap_start,
|
|
892
|
+
VALUE rap_count, VALUE rap_step)
|
|
893
|
+
{
|
|
894
|
+
CArray *parent, *selector;
|
|
895
|
+
int8_t indirect_axis = (int8_t) NUM2INT(rindirect);
|
|
896
|
+
int8_t ndim;
|
|
897
|
+
int8_t k;
|
|
898
|
+
VALUE obj;
|
|
899
|
+
CASelectAxis *ca;
|
|
900
|
+
|
|
901
|
+
Check_Type(rap_start, T_ARRAY);
|
|
902
|
+
Check_Type(rap_count, T_ARRAY);
|
|
903
|
+
Check_Type(rap_step, T_ARRAY);
|
|
904
|
+
|
|
905
|
+
TypedData_Get_Struct(rparent, CArray, &carray_data_type, parent);
|
|
906
|
+
TypedData_Get_Struct(rselector, CArray, &carray_data_type, selector);
|
|
907
|
+
|
|
908
|
+
ndim = parent->ndim;
|
|
909
|
+
if ( RARRAY_LEN(rap_start) != ndim ||
|
|
910
|
+
RARRAY_LEN(rap_count) != ndim ||
|
|
911
|
+
RARRAY_LEN(rap_step) != ndim ) {
|
|
912
|
+
rb_raise(rb_eArgError,
|
|
913
|
+
"CASelectAxis._new_debug: ap_* arrays must have length %d", ndim);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
ca_size_t ap_start_buf[CA_RANK_MAX];
|
|
917
|
+
ca_size_t ap_count_buf[CA_RANK_MAX];
|
|
918
|
+
ca_size_t ap_step_buf[CA_RANK_MAX];
|
|
919
|
+
for ( k = 0; k < ndim; k++ ) {
|
|
920
|
+
ap_start_buf[k] = (ca_size_t) NUM2LL(rb_ary_entry(rap_start, k));
|
|
921
|
+
ap_count_buf[k] = (ca_size_t) NUM2LL(rb_ary_entry(rap_count, k));
|
|
922
|
+
ap_step_buf[k] = (ca_size_t) NUM2LL(rb_ary_entry(rap_step, k));
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
obj = TypedData_Make_Struct(klass, CASelectAxis, &caselectaxis_data_type, ca);
|
|
926
|
+
ca_select_axis_setup(ca, parent, indirect_axis, selector,
|
|
927
|
+
ap_start_buf, ap_count_buf, ap_step_buf);
|
|
928
|
+
rb_ivar_set(obj, rb_intern("_parent"), rparent);
|
|
929
|
+
rb_ivar_set(obj, rb_intern("_selector"), rselector);
|
|
930
|
+
return obj;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/* ------------------------------------------------------------------- */
|
|
934
|
+
/* Indexer dispatch hook: called from rb_ca_grid */
|
|
935
|
+
/* ------------------------------------------------------------------- */
|
|
936
|
+
|
|
937
|
+
/* Eligibility check: route ca[*spec] to CASelectAxis only when CSA's
|
|
938
|
+
slab fast path applies AND CSA is expected to outperform CAGrid:
|
|
939
|
+
- argc == ca->ndim
|
|
940
|
+
- exactly one boolean CArray argument; rest are nil / Integer / Range
|
|
941
|
+
- the boolean is on axis 0 (outermost) — slab fast path criterion
|
|
942
|
+
|
|
943
|
+
Pattern A (mask outer + AP inner) is the only configuration where CSA's
|
|
944
|
+
single-walk slab xfer beats CAGrid's recursive innermost-contig attach.
|
|
945
|
+
Other configurations (interleaved AP+INDIRECT, indirect inner, AP with
|
|
946
|
+
step != 1) are routed to CAGrid to avoid regressions. */
|
|
947
|
+
int
|
|
948
|
+
rb_ca_select_axis_eligible_p (int argc, VALUE *argv, VALUE self)
|
|
949
|
+
{
|
|
950
|
+
CArray *ca;
|
|
951
|
+
int i;
|
|
952
|
+
|
|
953
|
+
/* Cheapest rejection first: argv[0] must be T_DATA (CArray-shaped).
|
|
954
|
+
Everything else (nil, Fixnum, Range, ...) fails TYPE check in O(1). */
|
|
955
|
+
if ( argc < 1 ) return 0;
|
|
956
|
+
if ( TYPE(argv[0]) != T_DATA ) return 0;
|
|
957
|
+
|
|
958
|
+
/* Now the slower checks: is it a CArray, is it boolean. */
|
|
959
|
+
if ( ! rb_obj_is_carray(argv[0]) ) return 0;
|
|
960
|
+
if ( ! rb_ca_is_boolean_type(argv[0]) ) return 0;
|
|
961
|
+
|
|
962
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
963
|
+
if ( argc != ca->ndim ) return 0;
|
|
964
|
+
|
|
965
|
+
/* axis 0 is the boolean (indirect). Walk rest; require nil/Integer/Range. */
|
|
966
|
+
for ( i = 1; i < argc; i++ ) {
|
|
967
|
+
VALUE arg = argv[i];
|
|
968
|
+
if ( NIL_P(arg) ) continue;
|
|
969
|
+
if ( FIXNUM_P(arg) ) continue;
|
|
970
|
+
if ( TYPE(arg) == T_DATA ) return 0; /* CArray at axis > 0 → bail */
|
|
971
|
+
if ( rb_obj_is_kind_of(arg, rb_cRange) ) continue;
|
|
972
|
+
if ( rb_obj_is_kind_of(arg, rb_cInteger) ) continue;
|
|
973
|
+
return 0;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
return 1;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
/* Construct a CASelectAxis from the indexer's argc/argv. Assumes
|
|
980
|
+
rb_ca_select_axis_eligible_p has already returned 1. */
|
|
981
|
+
VALUE
|
|
982
|
+
rb_ca_select_axis (int argc, VALUE *argv, VALUE self)
|
|
983
|
+
{
|
|
984
|
+
CArray *parent;
|
|
985
|
+
CArray *selector = NULL;
|
|
986
|
+
ca_size_t ap_start[CA_RANK_MAX];
|
|
987
|
+
ca_size_t ap_count[CA_RANK_MAX];
|
|
988
|
+
ca_size_t ap_step[CA_RANK_MAX];
|
|
989
|
+
int8_t indirect_axis = -1;
|
|
990
|
+
VALUE rselector_keep = Qnil;
|
|
991
|
+
VALUE obj;
|
|
992
|
+
CASelectAxis *ca;
|
|
993
|
+
int i;
|
|
994
|
+
|
|
995
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, parent);
|
|
996
|
+
|
|
997
|
+
if ( argc != parent->ndim ) {
|
|
998
|
+
rb_raise(rb_eArgError,
|
|
999
|
+
"CASelectAxis dispatch: argc (%d) != ndim (%d)", argc, parent->ndim);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
for ( i = 0; i < argc; i++ ) {
|
|
1003
|
+
VALUE arg = argv[i];
|
|
1004
|
+
|
|
1005
|
+
if ( NIL_P(arg) ) {
|
|
1006
|
+
ap_start[i] = 0;
|
|
1007
|
+
ap_count[i] = parent->dim[i];
|
|
1008
|
+
ap_step[i] = 1;
|
|
1009
|
+
}
|
|
1010
|
+
else if ( FIXNUM_P(arg) || rb_obj_is_kind_of(arg, rb_cInteger) ) {
|
|
1011
|
+
ca_size_t n = NUM2LL(arg);
|
|
1012
|
+
if ( n < 0 ) n += parent->dim[i];
|
|
1013
|
+
if ( n < 0 || n >= parent->dim[i] ) {
|
|
1014
|
+
rb_raise(rb_eIndexError,
|
|
1015
|
+
"CASelectAxis: index %lld out of range at axis %d",
|
|
1016
|
+
(long long) n, i);
|
|
1017
|
+
}
|
|
1018
|
+
ap_start[i] = n;
|
|
1019
|
+
ap_count[i] = 1;
|
|
1020
|
+
ap_step[i] = 1;
|
|
1021
|
+
}
|
|
1022
|
+
else if ( rb_obj_is_kind_of(arg, rb_cRange) ) {
|
|
1023
|
+
VALUE rfirst = rb_funcall(arg, rb_intern("first"), 0);
|
|
1024
|
+
VALUE rlast = rb_funcall(arg, rb_intern("last"), 0);
|
|
1025
|
+
int exclusive = RTEST(rb_funcall(arg, rb_intern("exclude_end?"), 0));
|
|
1026
|
+
ca_size_t a = NUM2LL(rfirst);
|
|
1027
|
+
ca_size_t b = NUM2LL(rlast);
|
|
1028
|
+
if ( a < 0 ) a += parent->dim[i];
|
|
1029
|
+
if ( b < 0 ) b += parent->dim[i];
|
|
1030
|
+
ca_size_t cnt = exclusive ? (b - a) : (b - a + 1);
|
|
1031
|
+
if ( cnt <= 0 ) {
|
|
1032
|
+
rb_raise(rb_eIndexError,
|
|
1033
|
+
"CASelectAxis: empty range at axis %d", i);
|
|
1034
|
+
}
|
|
1035
|
+
if ( a < 0 || a >= parent->dim[i] ||
|
|
1036
|
+
(a + cnt - 1) < 0 || (a + cnt - 1) >= parent->dim[i] ) {
|
|
1037
|
+
rb_raise(rb_eIndexError,
|
|
1038
|
+
"CASelectAxis: range [%lld..%lld] out of bounds at axis %d",
|
|
1039
|
+
(long long) a, (long long) (a + cnt - 1), i);
|
|
1040
|
+
}
|
|
1041
|
+
ap_start[i] = a;
|
|
1042
|
+
ap_count[i] = cnt;
|
|
1043
|
+
ap_step[i] = 1;
|
|
1044
|
+
}
|
|
1045
|
+
else if ( rb_obj_is_carray(arg) && rb_ca_is_boolean_type(arg) ) {
|
|
1046
|
+
TypedData_Get_Struct(arg, CArray, &carray_data_type, selector);
|
|
1047
|
+
indirect_axis = (int8_t) i;
|
|
1048
|
+
rselector_keep = arg;
|
|
1049
|
+
ap_start[i] = 0;
|
|
1050
|
+
ap_count[i] = 0; /* unused for indirect axis */
|
|
1051
|
+
ap_step[i] = 1;
|
|
1052
|
+
}
|
|
1053
|
+
else {
|
|
1054
|
+
rb_raise(rb_eArgError,
|
|
1055
|
+
"CASelectAxis: unsupported index type at axis %d", i);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
if ( indirect_axis < 0 ) {
|
|
1060
|
+
rb_raise(rb_eRuntimeError,
|
|
1061
|
+
"CASelectAxis dispatch: no boolean axis found (eligibility bug)");
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
obj = TypedData_Make_Struct(rb_cCASelectAxis, CASelectAxis,
|
|
1065
|
+
&caselectaxis_data_type, ca);
|
|
1066
|
+
ca_select_axis_setup(ca, parent, indirect_axis, selector,
|
|
1067
|
+
ap_start, ap_count, ap_step);
|
|
1068
|
+
|
|
1069
|
+
/* Keep Ruby objects alive (parent and selector references). */
|
|
1070
|
+
rb_ivar_set(obj, rb_intern("_parent"), self);
|
|
1071
|
+
rb_ivar_set(obj, rb_intern("_selector"), rselector_keep);
|
|
1072
|
+
return obj;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
/* ------------------------------------------------------------------- */
|
|
1076
|
+
/* Producer interface: emit the per-axis descriptor array.
|
|
1077
|
+
Writes ca->ndim entries into `out` (caller-allocated) and the
|
|
1078
|
+
matching effective parent dim into `out_parent_dims` (caller-
|
|
1079
|
+
allocated, sized CA_RANK_MAX). CSA is a per-axis view (descriptor.
|
|
1080
|
+
ndim == parent.ndim), so out_parent_dims is just parent->dim
|
|
1081
|
+
copied through. */
|
|
1082
|
+
|
|
1083
|
+
void
|
|
1084
|
+
ca_select_axis_describe_axes (void *ap, ca_axis_desc_t *out,
|
|
1085
|
+
ca_size_t *out_parent_dims)
|
|
1086
|
+
{
|
|
1087
|
+
CASelectAxis *ca = (CASelectAxis *) ap;
|
|
1088
|
+
int8_t k;
|
|
1089
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
1090
|
+
out_parent_dims[k] = ca->parent->dim[k];
|
|
1091
|
+
if ( k == ca->indirect_axis ) {
|
|
1092
|
+
if ( ca->stride_kind ) {
|
|
1093
|
+
/* constant-step run -> STRIDE kind. */
|
|
1094
|
+
out[k].kind = CA_AXIS_KIND_STRIDE;
|
|
1095
|
+
out[k].count = ca->dim[k];
|
|
1096
|
+
out[k].start = ca->stride_start;
|
|
1097
|
+
out[k].step = ca->stride_step;
|
|
1098
|
+
out[k].indices = NULL;
|
|
1099
|
+
} else {
|
|
1100
|
+
out[k].kind = CA_AXIS_KIND_INDEX;
|
|
1101
|
+
out[k].count = ca->dim[k];
|
|
1102
|
+
out[k].start = 0;
|
|
1103
|
+
out[k].step = 0;
|
|
1104
|
+
out[k].indices = ca->indices;
|
|
1105
|
+
}
|
|
1106
|
+
} else {
|
|
1107
|
+
out[k].kind = CA_AXIS_KIND_STRIDE;
|
|
1108
|
+
out[k].count = ca->ap_count[k];
|
|
1109
|
+
out[k].start = ca->ap_start[k];
|
|
1110
|
+
out[k].step = ca->ap_step[k];
|
|
1111
|
+
out[k].indices = NULL;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
#ifdef CARRAY_DEV_BUILD
|
|
1117
|
+
/* ============================================================
|
|
1118
|
+
* Debug accessors (dev-only, stripped in release)
|
|
1119
|
+
*
|
|
1120
|
+
* Gated by CARRAY_DEV_BUILD (enabled via `extconf.rb --enable-dev-build`
|
|
1121
|
+
* or `CARRAY_DEV=1 rake build_ext`). They expose the per-axis descriptor
|
|
1122
|
+
* and the engine's raw output to Ruby so spec_ai can pin them; nothing in
|
|
1123
|
+
* lib/ or the rest of ext/ consumes them. CAGrid carries the same four
|
|
1124
|
+
* under the same fence.
|
|
1125
|
+
* ============================================================ */
|
|
1126
|
+
|
|
1127
|
+
/* Returns an Array of per-axis Arrays:
|
|
1128
|
+
STRIDE axis -> [:stride, count, start, step]
|
|
1129
|
+
INDEX axis -> [:index, count, [indices...]] */
|
|
1130
|
+
static VALUE
|
|
1131
|
+
rb_ca_select_axis_describe_axes (VALUE self)
|
|
1132
|
+
{
|
|
1133
|
+
CASelectAxis *ca;
|
|
1134
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
1135
|
+
VALUE arr, entry, idx_ary;
|
|
1136
|
+
int8_t k;
|
|
1137
|
+
ca_size_t i;
|
|
1138
|
+
|
|
1139
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
1140
|
+
TypedData_Get_Struct(self, CASelectAxis, &caselectaxis_data_type, ca);
|
|
1141
|
+
ca_select_axis_describe_axes(ca, desc, pdims);
|
|
1142
|
+
|
|
1143
|
+
arr = rb_ary_new_capa(ca->ndim);
|
|
1144
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
1145
|
+
if ( desc[k].kind == CA_AXIS_KIND_STRIDE ) {
|
|
1146
|
+
entry = rb_ary_new_capa(4);
|
|
1147
|
+
rb_ary_push(entry, ID2SYM(rb_intern("stride")));
|
|
1148
|
+
rb_ary_push(entry, SIZE2NUM(desc[k].count));
|
|
1149
|
+
rb_ary_push(entry, SIZE2NUM(desc[k].start));
|
|
1150
|
+
rb_ary_push(entry, SIZE2NUM(desc[k].step));
|
|
1151
|
+
} else {
|
|
1152
|
+
entry = rb_ary_new_capa(3);
|
|
1153
|
+
rb_ary_push(entry, ID2SYM(rb_intern("index")));
|
|
1154
|
+
rb_ary_push(entry, SIZE2NUM(desc[k].count));
|
|
1155
|
+
idx_ary = rb_ary_new_capa(desc[k].count);
|
|
1156
|
+
for ( i = 0; i < desc[k].count; i++ ) {
|
|
1157
|
+
rb_ary_push(idx_ary, SIZE2NUM(desc[k].indices[i]));
|
|
1158
|
+
}
|
|
1159
|
+
rb_ary_push(entry, idx_ary);
|
|
1160
|
+
}
|
|
1161
|
+
rb_ary_push(arr, entry);
|
|
1162
|
+
}
|
|
1163
|
+
return arr;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
/* Returns the raw bytes produced by ca_axis_dispatch_attach as a String.
|
|
1167
|
+
Compared against `view.to_ca.dump_binary` in tests to verify binary
|
|
1168
|
+
equality with the existing attach path. */
|
|
1169
|
+
static VALUE
|
|
1170
|
+
rb_ca_select_axis_dispatch_attach_debug (VALUE self)
|
|
1171
|
+
{
|
|
1172
|
+
CASelectAxis *ca;
|
|
1173
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
1174
|
+
char *buf;
|
|
1175
|
+
VALUE str;
|
|
1176
|
+
|
|
1177
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
1178
|
+
TypedData_Get_Struct(self, CASelectAxis, &caselectaxis_data_type, ca);
|
|
1179
|
+
ca_select_axis_describe_axes(ca, desc, pdims);
|
|
1180
|
+
|
|
1181
|
+
ca_attach(ca->parent);
|
|
1182
|
+
buf = ca_axis_dispatch_attach(ca->parent, pdims, desc, ca->ndim, ca->bytes,
|
|
1183
|
+
ca->elements, NULL);
|
|
1184
|
+
ca_detach(ca->parent);
|
|
1185
|
+
|
|
1186
|
+
str = rb_str_new(buf, ca->elements * ca->bytes);
|
|
1187
|
+
xfree(buf);
|
|
1188
|
+
return str;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
/* Feeds a String of bytes (length == elements * bytes) through
|
|
1192
|
+
ca_axis_dispatch_scatter and returns nil. Mutates the parent; tests
|
|
1193
|
+
compare the resulting parent state against the same scatter performed
|
|
1194
|
+
through the view's sync path. */
|
|
1195
|
+
static VALUE
|
|
1196
|
+
rb_ca_select_axis_dispatch_scatter_debug (VALUE self, VALUE in_str)
|
|
1197
|
+
{
|
|
1198
|
+
CASelectAxis *ca;
|
|
1199
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
1200
|
+
ca_size_t expected;
|
|
1201
|
+
|
|
1202
|
+
Check_Type(in_str, T_STRING);
|
|
1203
|
+
TypedData_Get_Struct(self, CASelectAxis, &caselectaxis_data_type, ca);
|
|
1204
|
+
|
|
1205
|
+
expected = ca->elements * ca->bytes;
|
|
1206
|
+
if ( (ca_size_t) RSTRING_LEN(in_str) != expected ) {
|
|
1207
|
+
rb_raise(rb_eArgError,
|
|
1208
|
+
"CASelectAxis#_dispatch_scatter_debug: input string length %lld "
|
|
1209
|
+
"!= expected %lld",
|
|
1210
|
+
(long long) RSTRING_LEN(in_str), (long long) expected);
|
|
1211
|
+
}
|
|
1212
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
1213
|
+
ca_select_axis_describe_axes(ca, desc, pdims);
|
|
1214
|
+
|
|
1215
|
+
ca_attach(ca->parent);
|
|
1216
|
+
ca_axis_dispatch_scatter(ca->parent, pdims, desc, ca->ndim, ca->bytes,
|
|
1217
|
+
ca->elements, RSTRING_PTR(in_str));
|
|
1218
|
+
ca_sync(ca->parent);
|
|
1219
|
+
ca_detach(ca->parent);
|
|
1220
|
+
return Qnil;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
/* Broadcasts a String of length == bytes (one value) into every selected
|
|
1224
|
+
parent cell through ca_axis_dispatch_fill_value. */
|
|
1225
|
+
static VALUE
|
|
1226
|
+
rb_ca_select_axis_dispatch_fill_value_debug (VALUE self, VALUE val_str)
|
|
1227
|
+
{
|
|
1228
|
+
CASelectAxis *ca;
|
|
1229
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
1230
|
+
|
|
1231
|
+
Check_Type(val_str, T_STRING);
|
|
1232
|
+
TypedData_Get_Struct(self, CASelectAxis, &caselectaxis_data_type, ca);
|
|
1233
|
+
|
|
1234
|
+
if ( (ca_size_t) RSTRING_LEN(val_str) != ca->bytes ) {
|
|
1235
|
+
rb_raise(rb_eArgError,
|
|
1236
|
+
"CASelectAxis#_dispatch_fill_value_debug: value string length %lld "
|
|
1237
|
+
"!= bytes %lld",
|
|
1238
|
+
(long long) RSTRING_LEN(val_str), (long long) ca->bytes);
|
|
1239
|
+
}
|
|
1240
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
1241
|
+
ca_select_axis_describe_axes(ca, desc, pdims);
|
|
1242
|
+
|
|
1243
|
+
ca_attach(ca->parent);
|
|
1244
|
+
ca_axis_dispatch_fill_value(ca->parent, pdims, desc, ca->ndim, ca->bytes,
|
|
1245
|
+
ca->elements, RSTRING_PTR(val_str));
|
|
1246
|
+
ca_sync(ca->parent);
|
|
1247
|
+
ca_detach(ca->parent);
|
|
1248
|
+
return Qnil;
|
|
1249
|
+
}
|
|
1250
|
+
#endif /* CARRAY_DEV_BUILD */
|
|
1251
|
+
|
|
1252
|
+
/* ------------------------------------------------------------------- */
|
|
1253
|
+
|
|
1254
|
+
void
|
|
1255
|
+
Init_ca_obj_select_axis (void)
|
|
1256
|
+
{
|
|
1257
|
+
rb_cCASelectAxis = rb_define_class("CASelectAxis", rb_cCAView);
|
|
1258
|
+
rb_cCASelectAxisMask = rb_define_class("CASelectAxisMask", rb_cCASelectAxis);
|
|
1259
|
+
|
|
1260
|
+
ca_select_axis_func.struct_size = sizeof(CASelectAxis);
|
|
1261
|
+
ca_select_axis_func.pool_bytes = ca_select_axis_pool_bytes;
|
|
1262
|
+
ca_select_axis_func.pool_init = ca_select_axis_pool_init;
|
|
1263
|
+
|
|
1264
|
+
CA_OBJ_SELECT_AXIS = ca_install_obj_type(rb_cCASelectAxis,
|
|
1265
|
+
&caselectaxis_data_type,
|
|
1266
|
+
rb_cCASelectAxisMask,
|
|
1267
|
+
&caselectaxis_mask_data_type,
|
|
1268
|
+
&ca_select_axis_func, sizeof(ca_select_axis_func));
|
|
1269
|
+
rb_define_const(rb_cObject, "CA_OBJ_SELECT_AXIS", INT2NUM(CA_OBJ_SELECT_AXIS));
|
|
1270
|
+
|
|
1271
|
+
rb_define_alloc_func(rb_cCASelectAxis, rb_ca_select_axis_s_allocate);
|
|
1272
|
+
rb_define_method(rb_cCASelectAxis, "initialize_copy",
|
|
1273
|
+
rb_ca_select_axis_initialize_copy, 1);
|
|
1274
|
+
/* Debug-only ctor for testing; not part of the public API. */
|
|
1275
|
+
rb_define_singleton_method(rb_cCASelectAxis, "_new_debug",
|
|
1276
|
+
rb_ca_select_axis_s_new_debug, 6);
|
|
1277
|
+
|
|
1278
|
+
#ifdef CARRAY_DEV_BUILD
|
|
1279
|
+
/* debug accessors (dev-only, stripped in release).
|
|
1280
|
+
_dispatch_attach_debug returns the raw ca_axis_dispatch_attach bytes
|
|
1281
|
+
as a Ruby String so tests can assert binary equality with the
|
|
1282
|
+
existing attach output. */
|
|
1283
|
+
rb_define_method(rb_cCASelectAxis, "_describe_axes",
|
|
1284
|
+
rb_ca_select_axis_describe_axes, 0);
|
|
1285
|
+
rb_define_method(rb_cCASelectAxis, "_dispatch_attach_debug",
|
|
1286
|
+
rb_ca_select_axis_dispatch_attach_debug, 0);
|
|
1287
|
+
rb_define_method(rb_cCASelectAxis, "_dispatch_scatter_debug",
|
|
1288
|
+
rb_ca_select_axis_dispatch_scatter_debug, 1);
|
|
1289
|
+
rb_define_method(rb_cCASelectAxis, "_dispatch_fill_value_debug",
|
|
1290
|
+
rb_ca_select_axis_dispatch_fill_value_debug, 1);
|
|
1291
|
+
#endif
|
|
1292
|
+
|
|
1293
|
+
/* Benchmark-only bypass setter on CArray class. */
|
|
1294
|
+
rb_define_singleton_method(rb_cCArray, "_csa_bypass=", rb_ca_s_csa_bypass_eq, 1);
|
|
1295
|
+
rb_define_singleton_method(rb_cCArray, "_csa_bypass?", rb_ca_s_csa_bypass_p, 0);
|
|
1296
|
+
}
|