carray 2.0.0 → 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 +774 -298
- 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 +230 -792
- 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 +208 -241
- 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 -330
- 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 +1342 -199
- 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 +4 -14
- 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/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/Classes/ex1.rb +0 -46
- 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
data/ext/ca_obj_binop.c
ADDED
|
@@ -0,0 +1,892 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
Lazy binadic element-wise arithmetic view: holds (left, right,
|
|
4
|
+
op_id) and materialises the promoted result on attach. Carries
|
|
5
|
+
CA_FLAG_READ_ONLY; there is no bang path and `[]=` raises.
|
|
6
|
+
|
|
7
|
+
Sibling of ca_obj_monop.c (unary arithmetic) and ca_obj_bincmp.c
|
|
8
|
+
(comparison → boolean); dispatched by ca_binop_kernel_lookup_vv
|
|
9
|
+
from ca_binop_dispatch.h. Casts to the common data_type are
|
|
10
|
+
inserted as CAMonOp nodes by the public builder before the
|
|
11
|
+
CABinOp is constructed.
|
|
12
|
+
|
|
13
|
+
xfer_stride model:
|
|
14
|
+
1. Pull left into `data` (the output buffer). Left and output
|
|
15
|
+
share data_type (cast-before invariant), so this is safe as
|
|
16
|
+
an in-place gather.
|
|
17
|
+
2. Pull right into an arena scratch (per-node).
|
|
18
|
+
3. Call the eager 1-D kernel with src1 == dst == data (in-place
|
|
19
|
+
left) and src2 == scratch.
|
|
20
|
+
|
|
21
|
+
Mask handling: non-trapping ops always pass m=NULL (SIMD fast
|
|
22
|
+
path). Trapping ops (integer DIV / MOD / QUO) build a per-slab
|
|
23
|
+
mask from `left->mask | right->mask` when either operand has a
|
|
24
|
+
mask, using the operand-side masks directly to avoid a
|
|
25
|
+
create_mask ordering dependency on the output view.
|
|
26
|
+
|
|
27
|
+
Cross-ndim promotion: intentional design rejection, not a
|
|
28
|
+
deferred feature. Implicit trailing-align (`(M, N) + (N,)` etc.)
|
|
29
|
+
is permanently excluded; callers must reshape.
|
|
30
|
+
|
|
31
|
+
---------------------------------------------------------------------------- */
|
|
32
|
+
|
|
33
|
+
#include "carray.h"
|
|
34
|
+
#include "carray_internal.h" /* ca_lazy_arena_* */
|
|
35
|
+
#include "ca_binop_dispatch.h"
|
|
36
|
+
#include "ca_monop_dispatch.h" /* CA_MONOP_CAST_BASE */
|
|
37
|
+
|
|
38
|
+
/* carray_broadcast.c */
|
|
39
|
+
extern VALUE ca_broadcast_view (VALUE src, int8_t ndim,
|
|
40
|
+
ca_size_t *target_dim);
|
|
41
|
+
|
|
42
|
+
int8_t CA_OBJ_BINOP;
|
|
43
|
+
VALUE rb_cCABinOp;
|
|
44
|
+
|
|
45
|
+
/* CALazyMarker obj_type — collapse-on-consume marker checked by
|
|
46
|
+
the public builder below. */
|
|
47
|
+
extern int8_t CA_OBJ_LAZY_MARKER;
|
|
48
|
+
|
|
49
|
+
/* Defined in carray_lazy.c: wrap a non-CArray Ruby value as a
|
|
50
|
+
CScalar carrying the other operand's natural data_type. */
|
|
51
|
+
extern VALUE ca_lazy_wrap_scalar (VALUE other, CArray *self_ca);
|
|
52
|
+
|
|
53
|
+
/* ------------------------------------------------------------------- */
|
|
54
|
+
/* CABinOp struct */
|
|
55
|
+
/* ------------------------------------------------------------------- */
|
|
56
|
+
|
|
57
|
+
typedef struct CABinOp {
|
|
58
|
+
int16_t obj_type;
|
|
59
|
+
int8_t data_type;
|
|
60
|
+
int8_t ndim;
|
|
61
|
+
int32_t flags;
|
|
62
|
+
ca_size_t bytes;
|
|
63
|
+
ca_size_t elements;
|
|
64
|
+
ca_size_t *dim;
|
|
65
|
+
char *ptr;
|
|
66
|
+
CArray *mask;
|
|
67
|
+
char *_pool; /* framework-managed pool buffer (NULL = legacy ALLOC_N path). */
|
|
68
|
+
CArray *parent; /* = left (so generic walk machinery treats
|
|
69
|
+
left as the primary parent for marker
|
|
70
|
+
collapse and attach lifecycle traversal) */
|
|
71
|
+
uint32_t attach;
|
|
72
|
+
uint8_t nosync;
|
|
73
|
+
/* CABinOp-specific tail */
|
|
74
|
+
CArray *right;
|
|
75
|
+
uint16_t op_id;
|
|
76
|
+
uint8_t right_is_scalar; /* 1 ⇒ right has elements == 1, walk
|
|
77
|
+
with element-stride 0 (= broadcast) */
|
|
78
|
+
} CABinOp;
|
|
79
|
+
|
|
80
|
+
static size_t
|
|
81
|
+
ca_binop_dsize (const void *ap)
|
|
82
|
+
{
|
|
83
|
+
const CABinOp *ca = (const CABinOp *) ap;
|
|
84
|
+
return sizeof(CABinOp) + ca->ndim * sizeof(ca_size_t);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Pool framework hooks: single ndim-sized tail (dim) in the _pool
|
|
88
|
+
buffer. See ca_array_pool.c for the shared alloc/free discipline. */
|
|
89
|
+
static size_t
|
|
90
|
+
ca_binop_pool_bytes (int8_t ndim)
|
|
91
|
+
{
|
|
92
|
+
ca_size_t n = (ndim > 0) ? ndim : 1;
|
|
93
|
+
return (size_t) n * sizeof(ca_size_t);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
static void
|
|
97
|
+
ca_binop_pool_init (void *ap, int8_t ndim)
|
|
98
|
+
{
|
|
99
|
+
CABinOp *ca = (CABinOp *) ap;
|
|
100
|
+
ca->dim = (ca_size_t *) ca->_pool;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const rb_data_type_t cabinop_data_type = {
|
|
104
|
+
.parent = &caview_data_type,
|
|
105
|
+
.wrap_struct_name = "CABinOp",
|
|
106
|
+
.function = {
|
|
107
|
+
.dmark = ca_mark,
|
|
108
|
+
.dfree = ca_free,
|
|
109
|
+
.dsize = ca_binop_dsize,
|
|
110
|
+
.dcompact = NULL
|
|
111
|
+
},
|
|
112
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/* ------------------------------------------------------------------- */
|
|
116
|
+
/* setup / new / free */
|
|
117
|
+
/* ------------------------------------------------------------------- */
|
|
118
|
+
|
|
119
|
+
static int
|
|
120
|
+
ca_binop_setup (CABinOp *ca, CArray *left, CArray *right, uint16_t op_id)
|
|
121
|
+
{
|
|
122
|
+
int8_t out_dt = ca_lazy_promote_binop(op_id, left->data_type,
|
|
123
|
+
right->data_type);
|
|
124
|
+
ca_size_t out_bytes = ca_sizeof[out_dt];
|
|
125
|
+
|
|
126
|
+
ca->obj_type = CA_OBJ_BINOP;
|
|
127
|
+
ca->data_type = out_dt;
|
|
128
|
+
ca->flags = CA_FLAG_READ_ONLY;
|
|
129
|
+
ca->ndim = left->ndim;
|
|
130
|
+
ca->bytes = out_bytes;
|
|
131
|
+
ca->elements = left->elements;
|
|
132
|
+
ca->ptr = NULL;
|
|
133
|
+
ca->mask = NULL;
|
|
134
|
+
if ( ! ca->_pool ) {
|
|
135
|
+
ca->dim = ALLOC_N(ca_size_t, left->ndim);
|
|
136
|
+
}
|
|
137
|
+
ca->parent = left;
|
|
138
|
+
ca->attach = 0;
|
|
139
|
+
ca->nosync = 0;
|
|
140
|
+
ca->right = right;
|
|
141
|
+
ca->op_id = op_id;
|
|
142
|
+
/* right_is_scalar fast path: when right holds a single element,
|
|
143
|
+
xfer_stride pulls only that cell into scratch and walks the
|
|
144
|
+
kernel with element-stride 0 (broadcast). The symmetric
|
|
145
|
+
left_is_scalar case is currently handled by wrapping left in
|
|
146
|
+
a broadcast view of right's shape (correct but slower). */
|
|
147
|
+
ca->right_is_scalar = ( right->elements == 1 && left->elements > 1 ) ? 1 : 0;
|
|
148
|
+
|
|
149
|
+
memcpy(ca->dim, left->dim, left->ndim * sizeof(ca_size_t));
|
|
150
|
+
|
|
151
|
+
if ( ca_has_mask(left) || ca_has_mask(right) ) {
|
|
152
|
+
ca_create_mask(ca);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if ( ca_is_scalar(left) && ca_is_scalar(right) ) {
|
|
156
|
+
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
CABinOp *
|
|
163
|
+
ca_binop_new (CArray *left, CArray *right, uint16_t op_id)
|
|
164
|
+
{
|
|
165
|
+
CABinOp *ca = (CABinOp *) ca_array_alloc(CA_OBJ_BINOP, left->ndim);
|
|
166
|
+
ca_binop_setup(ca, left, right, op_id);
|
|
167
|
+
return ca;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
static void
|
|
171
|
+
free_ca_binop (void *ap)
|
|
172
|
+
{
|
|
173
|
+
CABinOp *ca = (CABinOp *) ap;
|
|
174
|
+
if ( ca != NULL ) {
|
|
175
|
+
ca_free(ca->mask);
|
|
176
|
+
if ( ca->_pool ) {
|
|
177
|
+
ca_array_free(ca); /* dim lives in _pool */
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
xfree(ca->dim);
|
|
181
|
+
xfree(ca);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* ------------------------------------------------------------------- */
|
|
187
|
+
/* operation function table */
|
|
188
|
+
/* ------------------------------------------------------------------- */
|
|
189
|
+
|
|
190
|
+
static void ca_binop_func_xfer_stride (void *ap, ca_size_t *starts,
|
|
191
|
+
ca_size_t *counts, ca_size_t *strides,
|
|
192
|
+
void *data, int dir);
|
|
193
|
+
|
|
194
|
+
static void *
|
|
195
|
+
ca_binop_func_clone (void *ap)
|
|
196
|
+
{
|
|
197
|
+
CABinOp *ca = (CABinOp *) ap;
|
|
198
|
+
return ca_binop_new(ca->parent, ca->right, ca->op_id);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* Per-cell get: dispatched through the same xfer_stride machinery
|
|
202
|
+
with counts == 1 on every axis. Not the hot path — a hot loop
|
|
203
|
+
should call `.to_ca` and read the entity directly. */
|
|
204
|
+
static void
|
|
205
|
+
ca_binop_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
206
|
+
{
|
|
207
|
+
CABinOp *ca = (CABinOp *) ap;
|
|
208
|
+
ca_size_t starts[CA_RANK_MAX];
|
|
209
|
+
ca_size_t counts[CA_RANK_MAX];
|
|
210
|
+
ca_size_t strides[CA_RANK_MAX];
|
|
211
|
+
int8_t k;
|
|
212
|
+
ca_size_t s;
|
|
213
|
+
|
|
214
|
+
if ( dir != CA_XFER_GET ) {
|
|
215
|
+
rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_index PUT)");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
s = ca->bytes;
|
|
219
|
+
for ( k = ca->ndim - 1; k >= 0; k-- ) {
|
|
220
|
+
starts[k] = idx[k];
|
|
221
|
+
counts[k] = 1;
|
|
222
|
+
strides[k] = s;
|
|
223
|
+
}
|
|
224
|
+
ca_binop_func_xfer_stride(ca, starts, counts, strides, data, CA_XFER_GET);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
static void
|
|
228
|
+
ca_binop_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
229
|
+
void *data, int dir)
|
|
230
|
+
{
|
|
231
|
+
CABinOp *ca = (CABinOp *) ap;
|
|
232
|
+
ca_size_t i;
|
|
233
|
+
char *out = (char *) data;
|
|
234
|
+
|
|
235
|
+
if ( dir != CA_XFER_GET ) {
|
|
236
|
+
rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_addrs PUT)");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
for ( i = 0; i < n; i++ ) {
|
|
240
|
+
ca_size_t idx[CA_RANK_MAX];
|
|
241
|
+
ca_addr2index((CArray *)ca, addrs[i], idx);
|
|
242
|
+
ca_binop_func_xfer_index(ca, idx, out + i * ca->bytes, CA_XFER_GET);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/* Test / observability counters bumped from the xfer_stride hot
|
|
247
|
+
path so specs can assert scratch acquisition (one per node,
|
|
248
|
+
independent of left-chain depth) and materialise vs
|
|
249
|
+
non-materialise behaviour without attaching the view. */
|
|
250
|
+
ca_size_t ca_binop_scratch_acquire_count = 0;
|
|
251
|
+
ca_size_t ca_binop_materialise_call_count = 0;
|
|
252
|
+
|
|
253
|
+
static void
|
|
254
|
+
ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
255
|
+
ca_size_t *strides, void *data, int dir)
|
|
256
|
+
{
|
|
257
|
+
CABinOp *bo = (CABinOp *) ap;
|
|
258
|
+
ca_size_t slab_n;
|
|
259
|
+
int8_t k;
|
|
260
|
+
void *scratch;
|
|
261
|
+
volatile VALUE holder;
|
|
262
|
+
ca_size_t right_bytes;
|
|
263
|
+
ca_size_t right_step; /* element-stride for the kernel walk */
|
|
264
|
+
|
|
265
|
+
if ( dir != CA_XFER_GET ) {
|
|
266
|
+
rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_stride PUT)");
|
|
267
|
+
}
|
|
268
|
+
ca_binop_materialise_call_count++;
|
|
269
|
+
|
|
270
|
+
slab_n = 1;
|
|
271
|
+
for ( k = 0; k < bo->ndim; k++ ) slab_n *= counts[k];
|
|
272
|
+
|
|
273
|
+
/* === 1. Pull left into the output buffer ===
|
|
274
|
+
CAREFUL: left.data_type == output.data_type by the cast-before
|
|
275
|
+
invariant, so the caller's `strides` (output byte layout) is
|
|
276
|
+
also valid for left. A mismatch would silently write past the
|
|
277
|
+
output row. */
|
|
278
|
+
ca_xfer_stride(bo->parent, starts, counts, strides, data, CA_XFER_GET);
|
|
279
|
+
|
|
280
|
+
/* === 2. Pull right into an arena scratch === */
|
|
281
|
+
right_bytes = bo->right->bytes;
|
|
282
|
+
(void) holder; /* Kept for stack-shape compatibility with the
|
|
283
|
+
surrounding code; arena replaces the ALLOCV. */
|
|
284
|
+
if ( bo->right_is_scalar ) {
|
|
285
|
+
/* CScalar-shaped right: pull exactly 1 element and walk it in
|
|
286
|
+
the kernel with element-stride 0. */
|
|
287
|
+
ca_size_t one_starts[CA_RANK_MAX] = {0};
|
|
288
|
+
ca_size_t one_counts[CA_RANK_MAX];
|
|
289
|
+
ca_size_t one_strides[CA_RANK_MAX];
|
|
290
|
+
for ( k = 0; k < bo->right->ndim; k++ ) {
|
|
291
|
+
one_counts[k] = 1;
|
|
292
|
+
one_strides[k] = right_bytes;
|
|
293
|
+
}
|
|
294
|
+
scratch = ca_lazy_arena_acquire(right_bytes);
|
|
295
|
+
ca_binop_scratch_acquire_count++;
|
|
296
|
+
ca_xfer_stride(bo->right, one_starts, one_counts, one_strides,
|
|
297
|
+
scratch, CA_XFER_GET);
|
|
298
|
+
right_step = 0;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
/* Same-shape right. Pull with the same byte layout the caller
|
|
302
|
+
requested for the output; right.bytes matches output.bytes
|
|
303
|
+
because right.data_type == out.data_type by cast-before. */
|
|
304
|
+
ca_size_t right_strides[CA_RANK_MAX];
|
|
305
|
+
ca_size_t s = right_bytes;
|
|
306
|
+
for ( k = bo->ndim - 1; k >= 0; k-- ) {
|
|
307
|
+
right_strides[k] = s;
|
|
308
|
+
s *= counts[k];
|
|
309
|
+
}
|
|
310
|
+
scratch = ca_lazy_arena_acquire(slab_n * right_bytes);
|
|
311
|
+
ca_binop_scratch_acquire_count++;
|
|
312
|
+
ca_xfer_stride(bo->right, starts, counts, right_strides, scratch,
|
|
313
|
+
CA_XFER_GET);
|
|
314
|
+
right_step = 1;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/* === 3. Apply the kernel: data (src1 == dst) op scratch (src2) → data ===
|
|
318
|
+
*
|
|
319
|
+
* Kernel signature (ext/carray.h):
|
|
320
|
+
* fn(n, m, ptr1=src1, i1, ptr2=src2, i2, ptr3=dst, i3)
|
|
321
|
+
*
|
|
322
|
+
* Mask handling:
|
|
323
|
+
* - non-trapping op → m = NULL (SIMD fast path; garbage compute
|
|
324
|
+
* on masked cells is allowed).
|
|
325
|
+
* - trapping op with any operand mask → build a per-slab OR
|
|
326
|
+
* mask from the operand-side masks.
|
|
327
|
+
*
|
|
328
|
+
* CAREFUL: the trapping-op mask is built from left.mask and
|
|
329
|
+
* right.mask directly, NOT from out->mask. The output's mask
|
|
330
|
+
* comes from create_mask (called separately on view
|
|
331
|
+
* construction), and reading it here would introduce an
|
|
332
|
+
* ordering dependency that reversed the invariant "the mask is
|
|
333
|
+
* always available before kernels run".
|
|
334
|
+
*
|
|
335
|
+
* CAREFUL: ptr1 == ptr3 == data (in-place left) is safe because
|
|
336
|
+
* each cell reads src1, reads src2, and writes dst atomically
|
|
337
|
+
* before the loop advances. */
|
|
338
|
+
{
|
|
339
|
+
boolean8_t *slab_mask = NULL;
|
|
340
|
+
void *mscratch = NULL;
|
|
341
|
+
volatile VALUE mholder = Qnil;
|
|
342
|
+
int is_trapping = ca_binop_is_trapping(bo->op_id, bo->data_type);
|
|
343
|
+
|
|
344
|
+
if ( is_trapping && ( ca_has_mask(bo->parent) ||
|
|
345
|
+
ca_has_mask(bo->right) ) ) {
|
|
346
|
+
/* Build a slab-shaped mask = left.slab_mask | right.slab_mask.
|
|
347
|
+
Pull each operand's mask (or fill with 0 if absent) into the
|
|
348
|
+
output-shaped layout, then OR them in place. */
|
|
349
|
+
ca_size_t k_;
|
|
350
|
+
ca_size_t right_mask_strides[CA_RANK_MAX];
|
|
351
|
+
(void) mholder; /* Kept for stack-shape compatibility; arena
|
|
352
|
+
replaces the ALLOCV path here. */
|
|
353
|
+
|
|
354
|
+
mscratch = ca_lazy_arena_acquire(slab_n);
|
|
355
|
+
slab_mask = (boolean8_t *) mscratch;
|
|
356
|
+
|
|
357
|
+
if ( ca_has_mask(bo->parent) ) {
|
|
358
|
+
ca_size_t mstrides[CA_RANK_MAX];
|
|
359
|
+
ca_size_t s = 1;
|
|
360
|
+
for ( k_ = bo->ndim - 1; k_ >= 0; k_-- ) {
|
|
361
|
+
mstrides[k_] = s; s *= counts[k_];
|
|
362
|
+
}
|
|
363
|
+
ca_xfer_stride(bo->parent->mask, starts, counts, mstrides,
|
|
364
|
+
slab_mask, CA_XFER_GET);
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
memset(slab_mask, 0, slab_n);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if ( ca_has_mask(bo->right) ) {
|
|
371
|
+
boolean8_t *rm = NULL;
|
|
372
|
+
ca_size_t i_;
|
|
373
|
+
if ( bo->right_is_scalar ) {
|
|
374
|
+
/* CScalar right: pull the single mask bit and broadcast OR. */
|
|
375
|
+
ca_size_t one_starts[CA_RANK_MAX] = {0};
|
|
376
|
+
ca_size_t one_counts[CA_RANK_MAX];
|
|
377
|
+
ca_size_t one_strides[CA_RANK_MAX];
|
|
378
|
+
boolean8_t one_bit = 0;
|
|
379
|
+
for ( k_ = 0; k_ < bo->right->ndim; k_++ ) {
|
|
380
|
+
one_counts[k_] = 1;
|
|
381
|
+
one_strides[k_] = 1;
|
|
382
|
+
}
|
|
383
|
+
ca_xfer_stride(bo->right->mask, one_starts, one_counts,
|
|
384
|
+
one_strides, &one_bit, CA_XFER_GET);
|
|
385
|
+
if ( one_bit ) {
|
|
386
|
+
for ( i_ = 0; i_ < slab_n; i_++ ) slab_mask[i_] = 1;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
ca_size_t s = 1;
|
|
391
|
+
for ( k_ = bo->ndim - 1; k_ >= 0; k_-- ) {
|
|
392
|
+
right_mask_strides[k_] = s; s *= counts[k_];
|
|
393
|
+
}
|
|
394
|
+
/* Small mask-scratch for right; OR into slab_mask in
|
|
395
|
+
place to avoid a persistent second buffer. */
|
|
396
|
+
rm = (boolean8_t *) ALLOCA_N(boolean8_t, slab_n);
|
|
397
|
+
ca_xfer_stride(bo->right->mask, starts, counts,
|
|
398
|
+
right_mask_strides, rm, CA_XFER_GET);
|
|
399
|
+
for ( i_ = 0; i_ < slab_n; i_++ ) slab_mask[i_] |= rm[i_];
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
ca_binop_func_t fn = ca_binop_kernel_lookup_vv(bo->op_id, bo->data_type);
|
|
405
|
+
if ( fn == NULL ) {
|
|
406
|
+
if ( mscratch ) ca_lazy_arena_release(mscratch);
|
|
407
|
+
ca_lazy_arena_release(scratch);
|
|
408
|
+
rb_raise(rb_eNotImpError,
|
|
409
|
+
"CABinOp: kernel not implemented (op_id=%u data_type=%d)",
|
|
410
|
+
(unsigned) bo->op_id, (int) bo->data_type);
|
|
411
|
+
}
|
|
412
|
+
fn(slab_n, slab_mask,
|
|
413
|
+
(char *)data, 1, /* src1 == dst (left, in-place) */
|
|
414
|
+
(char *)scratch, right_step, /* src2 (right) */
|
|
415
|
+
(char *)data, 1); /* dst */
|
|
416
|
+
|
|
417
|
+
if ( mscratch ) ca_lazy_arena_release(mscratch);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
ca_lazy_arena_release(scratch);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
static void
|
|
424
|
+
ca_binop_func_xfer_all (void *ap, void *data, int dir)
|
|
425
|
+
{
|
|
426
|
+
CABinOp *ca = (CABinOp *) ap;
|
|
427
|
+
ca_size_t starts[CA_RANK_MAX];
|
|
428
|
+
ca_size_t native[CA_RANK_MAX];
|
|
429
|
+
int8_t k;
|
|
430
|
+
ca_size_t s = ca->bytes;
|
|
431
|
+
for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
|
|
432
|
+
for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
|
|
433
|
+
ca_xfer_stride(ca, starts, ca->dim, native, data, dir);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
static void
|
|
437
|
+
ca_binop_func_allocate (void *ap)
|
|
438
|
+
{
|
|
439
|
+
CABinOp *ca = (CABinOp *) ap;
|
|
440
|
+
ca->ptr = xmalloc(ca_length(ca));
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
static void
|
|
444
|
+
ca_binop_func_attach (void *ap)
|
|
445
|
+
{
|
|
446
|
+
/* CAREFUL: call the view-specific xfer_stride directly here,
|
|
447
|
+
not the public ca_xfer_stride dispatcher. The dispatcher's
|
|
448
|
+
self-memcpy fast path detects data == ca->ptr and returns
|
|
449
|
+
without materialising, so the freshly-allocated buffer would
|
|
450
|
+
still hold garbage. */
|
|
451
|
+
CABinOp *ca = (CABinOp *) ap;
|
|
452
|
+
ca_size_t starts[CA_RANK_MAX];
|
|
453
|
+
ca_size_t native[CA_RANK_MAX];
|
|
454
|
+
int8_t k;
|
|
455
|
+
ca_size_t s;
|
|
456
|
+
|
|
457
|
+
ca->ptr = xmalloc(ca_length(ca));
|
|
458
|
+
|
|
459
|
+
s = ca->bytes;
|
|
460
|
+
for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
|
|
461
|
+
for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
|
|
462
|
+
ca_binop_func_xfer_stride(ca, starts, ca->dim, native, ca->ptr, CA_XFER_GET);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
static void
|
|
466
|
+
ca_binop_func_sync (void *ap)
|
|
467
|
+
{
|
|
468
|
+
/* read-only */
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
static void
|
|
472
|
+
ca_binop_func_detach (void *ap)
|
|
473
|
+
{
|
|
474
|
+
CABinOp *ca = (CABinOp *) ap;
|
|
475
|
+
xfree(ca->ptr);
|
|
476
|
+
ca->ptr = NULL;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
NORETURN(static void ca_binop_func_fill_data (void *ap, void *ptr));
|
|
480
|
+
static void
|
|
481
|
+
ca_binop_func_fill_data (void *ap, void *ptr)
|
|
482
|
+
{
|
|
483
|
+
rb_raise(rb_eRuntimeError, "CABinOp is read-only (fill_data)");
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/* Build out.mask. When either parent has a mask, materialise a
|
|
487
|
+
freshly-allocated boolean8_t buffer. For most ops this is the blind
|
|
488
|
+
OR `left.mask | right.mask`.
|
|
489
|
+
|
|
490
|
+
Boolean AND / OR are three-valued (Kleene): a masked cell is resolved by
|
|
491
|
+
the *known* side (`unknown | true = true`, `unknown & false = false`), so
|
|
492
|
+
it is NOT masked in the result. This needs operand VALUES, not just
|
|
493
|
+
masks, so both operands are attached; the blind value the value kernel
|
|
494
|
+
later writes is already correct on a resolved cell because the absorbing
|
|
495
|
+
element (true for OR, false for AND) dominates whatever garbage sits on
|
|
496
|
+
the masked side. Nested trees compose: an inner boolean `&`/`|` node's
|
|
497
|
+
mask is already Kleene-resolved by the time an outer node reads it.
|
|
498
|
+
|
|
499
|
+
Not memory-optimal (a CARepeat-like view would share pages), but correct
|
|
500
|
+
and decoupled from xfer_stride ordering. */
|
|
501
|
+
static void
|
|
502
|
+
ca_binop_func_create_mask (void *ap)
|
|
503
|
+
{
|
|
504
|
+
CABinOp *bo = (CABinOp *) ap;
|
|
505
|
+
CArray *l = bo->parent;
|
|
506
|
+
CArray *r = bo->right;
|
|
507
|
+
boolean8_t *dst;
|
|
508
|
+
ca_size_t i, n;
|
|
509
|
+
int has_l, has_r, kleene, need_l, need_r, is_or;
|
|
510
|
+
boolean8_t *lm, *rm, *lv, *rv;
|
|
511
|
+
|
|
512
|
+
has_l = ca_has_mask(l);
|
|
513
|
+
has_r = ca_has_mask(r);
|
|
514
|
+
if ( ! has_l && ! has_r ) return;
|
|
515
|
+
|
|
516
|
+
kleene = ( bo->data_type == CA_BOOLEAN &&
|
|
517
|
+
( bo->op_id == CA_BINOP_BIT_AND || bo->op_id == CA_BINOP_BIT_OR ) );
|
|
518
|
+
is_or = ( bo->op_id == CA_BINOP_BIT_OR );
|
|
519
|
+
|
|
520
|
+
bo->mask = (CArray *) carray_new(CA_BOOLEAN, bo->ndim, bo->dim, 0, NULL);
|
|
521
|
+
dst = (boolean8_t *) bo->mask->ptr;
|
|
522
|
+
n = bo->elements;
|
|
523
|
+
|
|
524
|
+
/* Kleene needs operand values even where an operand is unmasked. */
|
|
525
|
+
need_l = has_l || kleene;
|
|
526
|
+
need_r = has_r || kleene;
|
|
527
|
+
if ( need_l ) ca_attach(l);
|
|
528
|
+
if ( need_r ) ca_attach(r);
|
|
529
|
+
|
|
530
|
+
lm = has_l ? (boolean8_t *) l->mask->ptr : NULL;
|
|
531
|
+
rm = has_r ? (boolean8_t *) r->mask->ptr : NULL;
|
|
532
|
+
lv = kleene ? (boolean8_t *) l->ptr : NULL;
|
|
533
|
+
rv = kleene ? (boolean8_t *) r->ptr : NULL;
|
|
534
|
+
|
|
535
|
+
for ( i = 0; i < n; i++ ) {
|
|
536
|
+
/* right broadcast: repeat element 0 when right was a scalar. */
|
|
537
|
+
ca_size_t ri = bo->right_is_scalar ? 0 : i;
|
|
538
|
+
boolean8_t am = lm ? lm[i] : 0;
|
|
539
|
+
boolean8_t bm = rm ? rm[ri] : 0;
|
|
540
|
+
boolean8_t m = (boolean8_t)( am | bm );
|
|
541
|
+
if ( kleene && m ) {
|
|
542
|
+
boolean8_t av = lv[i], bv = rv[ri];
|
|
543
|
+
if ( is_or ) {
|
|
544
|
+
if ( ( ! am && av ) || ( ! bm && bv ) ) m = 0; /* known TRUE */
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
if ( ( ! am && ! av ) || ( ! bm && ! bv ) ) m = 0; /* known FALSE */
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
dst[i] = m;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if ( need_l ) ca_detach(l);
|
|
554
|
+
if ( need_r ) ca_detach(r);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
ca_operation_function_t ca_binop_func = {
|
|
558
|
+
-1, /* CA_OBJ_BINOP, set at install time */
|
|
559
|
+
CA_VIEW_ARRAY,
|
|
560
|
+
free_ca_binop,
|
|
561
|
+
ca_binop_func_clone,
|
|
562
|
+
ca_binop_func_allocate,
|
|
563
|
+
ca_binop_func_attach,
|
|
564
|
+
ca_binop_func_sync,
|
|
565
|
+
ca_binop_func_detach,
|
|
566
|
+
ca_binop_func_fill_data,
|
|
567
|
+
ca_binop_func_create_mask,
|
|
568
|
+
ca_binop_func_xfer_index,
|
|
569
|
+
ca_binop_func_xfer_addrs,
|
|
570
|
+
NULL, /* fold_stride: never fold — op boundary */
|
|
571
|
+
ca_binop_func_xfer_stride,
|
|
572
|
+
ca_binop_func_xfer_all,
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
/* ------------------------------------------------------------------- */
|
|
576
|
+
/* Public builder (= lib/carray/lazy.rb dispatch entry) */
|
|
577
|
+
/* ------------------------------------------------------------------- */
|
|
578
|
+
|
|
579
|
+
/* Marker collapse helper: if cary wraps a CALazyMarker, replace with
|
|
580
|
+
the marker's stored Ruby parent so the marker does not appear in
|
|
581
|
+
the constructed CABinOp tree. */
|
|
582
|
+
static VALUE
|
|
583
|
+
collapse_marker (VALUE cary)
|
|
584
|
+
{
|
|
585
|
+
CArray *ca;
|
|
586
|
+
if ( ! rb_obj_is_carray(cary) ) return cary;
|
|
587
|
+
TypedData_Get_Struct(cary, CArray, &carray_data_type, ca);
|
|
588
|
+
if ( ca->obj_type == CA_OBJ_LAZY_MARKER ) {
|
|
589
|
+
return rb_ca_parent(cary);
|
|
590
|
+
}
|
|
591
|
+
return cary;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/* Low-level constructor: wraps l_cary (left) and r_cary (right)
|
|
595
|
+
into a CABinOp. Does NOT insert cast nodes; the caller must
|
|
596
|
+
have promoted both operands to the common data_type. */
|
|
597
|
+
static VALUE
|
|
598
|
+
rb_ca_binop_new (VALUE l_cary, VALUE r_cary, uint16_t op_id)
|
|
599
|
+
{
|
|
600
|
+
volatile VALUE obj;
|
|
601
|
+
CArray *l, *r;
|
|
602
|
+
CABinOp *ca;
|
|
603
|
+
rb_check_carray_object(l_cary);
|
|
604
|
+
rb_check_carray_object(r_cary);
|
|
605
|
+
TypedData_Get_Struct(l_cary, CArray, &carray_data_type, l);
|
|
606
|
+
TypedData_Get_Struct(r_cary, CArray, &carray_data_type, r);
|
|
607
|
+
ca = ca_binop_new(l, r, op_id);
|
|
608
|
+
obj = ca_wrap_struct(ca);
|
|
609
|
+
rb_ca_set_parent(obj, l_cary);
|
|
610
|
+
/* Pin right via an ivar so GC keeps it alive. parent slot already
|
|
611
|
+
pins left. */
|
|
612
|
+
rb_ivar_set(obj, rb_intern("__binop_right__"), r_cary);
|
|
613
|
+
return obj;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/* Public builder: build a CABinOp tree node for op_id over
|
|
617
|
+
(l_cary, r_cary). Inserts cast nodes when either operand's
|
|
618
|
+
data_type differs from the common data_type, then resolves
|
|
619
|
+
same-ndim size-1 broadcast via ca_broadcast_pair. The cast
|
|
620
|
+
nodes are inserted BEFORE broadcast so the cast acts on the
|
|
621
|
+
smallest possible element count.
|
|
622
|
+
|
|
623
|
+
Broadcast scope (bound-dimension only):
|
|
624
|
+
same shape → no-op
|
|
625
|
+
same ndim + size-1 → ca_broadcast_pair wraps the size-1 axis
|
|
626
|
+
operand in a stride-0 CAStride
|
|
627
|
+
CScalar vs array → xfer_stride walks with element_step = 0
|
|
628
|
+
different ndim → ArgumentError
|
|
629
|
+
|
|
630
|
+
CAREFUL: the different-ndim raise is an intentional design
|
|
631
|
+
rejection, not a deferred feature. Implicit cross-ndim
|
|
632
|
+
promotion (`(M, N) + (N,)` etc.) is permanently excluded from
|
|
633
|
+
CArray; callers must reshape explicitly. The eager CArray path
|
|
634
|
+
enforces the same rule, and re-introducing a silent
|
|
635
|
+
trailing-align here would diverge the lazy path from it. */
|
|
636
|
+
VALUE
|
|
637
|
+
rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
|
|
638
|
+
{
|
|
639
|
+
CArray *l, *r;
|
|
640
|
+
int8_t l_in_dt, r_in_dt;
|
|
641
|
+
volatile VALUE l_resolved, r_resolved;
|
|
642
|
+
|
|
643
|
+
/* Collapse markers on both sides. */
|
|
644
|
+
l_resolved = collapse_marker(l_cary);
|
|
645
|
+
r_resolved = collapse_marker(r_cary);
|
|
646
|
+
|
|
647
|
+
/* Promote a non-CArray Ruby value to a CScalar carrying the
|
|
648
|
+
other side's natural data_type. */
|
|
649
|
+
if ( ! rb_obj_is_carray(l_resolved) ) {
|
|
650
|
+
rb_check_carray_object(r_resolved);
|
|
651
|
+
TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
|
|
652
|
+
l_resolved = ca_lazy_wrap_scalar(l_resolved, r);
|
|
653
|
+
}
|
|
654
|
+
if ( ! rb_obj_is_carray(r_resolved) ) {
|
|
655
|
+
rb_check_carray_object(l_resolved);
|
|
656
|
+
TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
|
|
657
|
+
r_resolved = ca_lazy_wrap_scalar(r_resolved, l);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
|
|
661
|
+
TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
|
|
662
|
+
|
|
663
|
+
/* === Step 1: insert cast nodes. Applied to each operand before
|
|
664
|
+
broadcast so the cast acts on the smallest element count. */
|
|
665
|
+
ca_binop_kernel_input_data_types(op_id, l->data_type, r->data_type,
|
|
666
|
+
&l_in_dt, &r_in_dt);
|
|
667
|
+
|
|
668
|
+
if ( l_in_dt != l->data_type ) {
|
|
669
|
+
VALUE cast_op = INT2NUM(CA_MONOP_CAST_BASE + l_in_dt);
|
|
670
|
+
l_resolved = rb_funcall(rb_const_get(rb_cObject, rb_intern("CAMonOp")),
|
|
671
|
+
rb_intern("__build__"), 2,
|
|
672
|
+
l_resolved, cast_op);
|
|
673
|
+
TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
|
|
674
|
+
}
|
|
675
|
+
if ( r_in_dt != r->data_type ) {
|
|
676
|
+
VALUE cast_op = INT2NUM(CA_MONOP_CAST_BASE + r_in_dt);
|
|
677
|
+
r_resolved = rb_funcall(rb_const_get(rb_cObject, rb_intern("CAMonOp")),
|
|
678
|
+
rb_intern("__build__"), 2,
|
|
679
|
+
r_resolved, cast_op);
|
|
680
|
+
TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/* === Step 2: broadcast via ca_broadcast_pair (same-ndim size-1
|
|
684
|
+
expansion). No-op when shapes already match or either operand
|
|
685
|
+
is scalar; also a no-op for incompatible shapes, which the
|
|
686
|
+
final elements-mismatch check below catches. */
|
|
687
|
+
ca_broadcast_pair(&l_resolved, &r_resolved);
|
|
688
|
+
TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
|
|
689
|
+
TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
|
|
690
|
+
|
|
691
|
+
/* === Step 3: shape sanity. After broadcast_pair, accept:
|
|
692
|
+
(a) equal elements (matched shape, common case),
|
|
693
|
+
(b) right is a 1-element CScalar (xfer_stride uses
|
|
694
|
+
element_step = 0),
|
|
695
|
+
(c) left is a 1-element CScalar — swap operands when the
|
|
696
|
+
op commutes (ADD / MUL / BIT_*). Non-commutative +
|
|
697
|
+
left scalar wraps left in a broadcast view of right's
|
|
698
|
+
shape so the kernel sees matched shapes; cost is N
|
|
699
|
+
reads of the scalar cell with stride 0. */
|
|
700
|
+
if ( l->elements != r->elements ) {
|
|
701
|
+
if ( r->elements == 1 && l->elements > 1 ) {
|
|
702
|
+
/* CScalar-vs-array, right. xfer_stride handles this with
|
|
703
|
+
right_step = 0. */
|
|
704
|
+
}
|
|
705
|
+
else if ( l->elements == 1 && r->elements > 1 ) {
|
|
706
|
+
int commutes = ( op_id == CA_BINOP_ADD ||
|
|
707
|
+
op_id == CA_BINOP_MUL ||
|
|
708
|
+
op_id == CA_BINOP_BIT_AND ||
|
|
709
|
+
op_id == CA_BINOP_BIT_OR ||
|
|
710
|
+
op_id == CA_BINOP_BIT_XOR );
|
|
711
|
+
if ( commutes ) {
|
|
712
|
+
VALUE tmp = l_resolved; l_resolved = r_resolved; r_resolved = tmp;
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
/* Non-commutative + left scalar: broadcast the left operand
|
|
716
|
+
(CScalar with ndim=1 dim=[1]) up to right's shape.
|
|
717
|
+
ca_repeat_setup signature:
|
|
718
|
+
count[i] > 0 → repeat (stride-0) axis of size count[i]
|
|
719
|
+
count[i] == 0 → data axis (inherits from parent)
|
|
720
|
+
Total data axes must equal parent->ndim.
|
|
721
|
+
For lifting a CScalar (parent.ndim=1, dim=[1]) to right's
|
|
722
|
+
ndim N: count = {1, 1, ..., 1, 0} (N-1 leading dummy 1s,
|
|
723
|
+
1 trailing data axis), then broadcast that (1,1,...,1)
|
|
724
|
+
shape to right's dim via ca_broadcast_view. */
|
|
725
|
+
ca_size_t count[CA_RANK_MAX];
|
|
726
|
+
int8_t k;
|
|
727
|
+
if ( r->ndim > l->ndim ) {
|
|
728
|
+
for ( k = 0; k < r->ndim - 1; k++ ) count[k] = 1; /* dummy */
|
|
729
|
+
count[r->ndim - 1] = 0; /* data */
|
|
730
|
+
l_resolved = rb_ca_repeat_new(l_resolved, r->ndim, count);
|
|
731
|
+
TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
|
|
732
|
+
}
|
|
733
|
+
l_resolved = ca_broadcast_view(l_resolved, r->ndim, r->dim);
|
|
734
|
+
TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
else {
|
|
738
|
+
/* Cross-ndim or otherwise incompatible shapes; see the
|
|
739
|
+
builder header comment for why CArray rejects implicit
|
|
740
|
+
cross-ndim promotion. */
|
|
741
|
+
rb_raise(rb_eArgError,
|
|
742
|
+
"CABinOp: shape mismatch (%lld vs %lld) — only same-"
|
|
743
|
+
"ndim size-1 broadcast is supported; cross-ndim "
|
|
744
|
+
"promotion is not adopted in CArray "
|
|
745
|
+
"(reshape explicitly)",
|
|
746
|
+
(long long) l->elements, (long long) r->elements);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
return rb_ca_binop_new(l_resolved, r_resolved, op_id);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
static VALUE
|
|
754
|
+
rb_ca_binop_s_build (VALUE klass, VALUE l_cary, VALUE r_cary, VALUE op_id_val)
|
|
755
|
+
{
|
|
756
|
+
uint16_t op_id = (uint16_t) NUM2UINT(op_id_val);
|
|
757
|
+
(void) klass;
|
|
758
|
+
return rb_ca_binop_build(l_cary, r_cary, op_id);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/* op_id accessor for inspect / dump_tree consumers in Ruby. */
|
|
762
|
+
static VALUE
|
|
763
|
+
rb_ca_binop_op_id (VALUE self)
|
|
764
|
+
{
|
|
765
|
+
CABinOp *bo;
|
|
766
|
+
TypedData_Get_Struct(self, CABinOp, &cabinop_data_type, bo);
|
|
767
|
+
return UINT2NUM(bo->op_id);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/* Right-operand accessor — needed by inspect / dump_tree because
|
|
771
|
+
the right reference lives off the prefix and is not reachable
|
|
772
|
+
via .parent. */
|
|
773
|
+
static VALUE
|
|
774
|
+
rb_ca_binop_right (VALUE self)
|
|
775
|
+
{
|
|
776
|
+
return rb_ivar_get(self, rb_intern("__binop_right__"));
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/* Test instrumentation (mirrors CAMonOp counters). */
|
|
780
|
+
static VALUE
|
|
781
|
+
rb_ca_binop_s_reset_scratch_counter (VALUE klass)
|
|
782
|
+
{
|
|
783
|
+
ca_binop_scratch_acquire_count = 0;
|
|
784
|
+
return Qnil;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
static VALUE
|
|
788
|
+
rb_ca_binop_s_scratch_count (VALUE klass)
|
|
789
|
+
{
|
|
790
|
+
return SIZE2NUM(ca_binop_scratch_acquire_count);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
static VALUE
|
|
794
|
+
rb_ca_binop_s_reset_materialise_counter (VALUE klass)
|
|
795
|
+
{
|
|
796
|
+
ca_binop_materialise_call_count = 0;
|
|
797
|
+
return Qnil;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
static VALUE
|
|
801
|
+
rb_ca_binop_s_materialise_count (VALUE klass)
|
|
802
|
+
{
|
|
803
|
+
return SIZE2NUM(ca_binop_materialise_call_count);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
static VALUE
|
|
807
|
+
rb_ca_binop_s_allocate (VALUE klass)
|
|
808
|
+
{
|
|
809
|
+
CABinOp *ca;
|
|
810
|
+
return TypedData_Make_Struct(klass, CABinOp, &cabinop_data_type, ca);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
static VALUE
|
|
814
|
+
rb_ca_binop_initialize_copy (VALUE self, VALUE other)
|
|
815
|
+
{
|
|
816
|
+
CABinOp *ca, *cs;
|
|
817
|
+
TypedData_Get_Struct(self, CABinOp, &cabinop_data_type, ca);
|
|
818
|
+
TypedData_Get_Struct(other, CABinOp, &cabinop_data_type, cs);
|
|
819
|
+
if ( ca_func[CA_OBJ_BINOP].pool_init ) {
|
|
820
|
+
ca_array_pool_alloc(ca, CA_OBJ_BINOP, cs->parent->ndim);
|
|
821
|
+
}
|
|
822
|
+
ca_binop_setup(ca, cs->parent, cs->right, cs->op_id);
|
|
823
|
+
return self;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
void
|
|
827
|
+
Init_ca_obj_binop (void)
|
|
828
|
+
{
|
|
829
|
+
rb_cCABinOp = rb_define_class("CABinOp", rb_cCAView);
|
|
830
|
+
|
|
831
|
+
ca_binop_func.struct_size = sizeof(CABinOp);
|
|
832
|
+
ca_binop_func.pool_bytes = ca_binop_pool_bytes;
|
|
833
|
+
ca_binop_func.pool_init = ca_binop_pool_init;
|
|
834
|
+
|
|
835
|
+
CA_OBJ_BINOP = ca_install_obj_type(rb_cCABinOp,
|
|
836
|
+
&cabinop_data_type,
|
|
837
|
+
rb_cCArrayMask,
|
|
838
|
+
&carray_mask_data_type, &ca_binop_func, sizeof(ca_binop_func));
|
|
839
|
+
rb_define_const(rb_cObject, "CA_OBJ_BINOP", INT2NUM(CA_OBJ_BINOP));
|
|
840
|
+
|
|
841
|
+
/* op_id constants shared with lib/carray/lazy.rb. */
|
|
842
|
+
rb_define_const(rb_cCABinOp, "OP_ADD", INT2NUM(CA_BINOP_ADD));
|
|
843
|
+
rb_define_const(rb_cCABinOp, "OP_SUB", INT2NUM(CA_BINOP_SUB));
|
|
844
|
+
rb_define_const(rb_cCABinOp, "OP_MUL", INT2NUM(CA_BINOP_MUL));
|
|
845
|
+
rb_define_const(rb_cCABinOp, "OP_DIV", INT2NUM(CA_BINOP_DIV));
|
|
846
|
+
rb_define_const(rb_cCABinOp, "OP_POW", INT2NUM(CA_BINOP_POW));
|
|
847
|
+
rb_define_const(rb_cCABinOp, "OP_BIT_AND", INT2NUM(CA_BINOP_BIT_AND));
|
|
848
|
+
rb_define_const(rb_cCABinOp, "OP_BIT_OR", INT2NUM(CA_BINOP_BIT_OR));
|
|
849
|
+
rb_define_const(rb_cCABinOp, "OP_BIT_XOR", INT2NUM(CA_BINOP_BIT_XOR));
|
|
850
|
+
rb_define_const(rb_cCABinOp, "OP_BIT_LSHIFT", INT2NUM(CA_BINOP_BIT_LSHIFT));
|
|
851
|
+
rb_define_const(rb_cCABinOp, "OP_BIT_RSHIFT", INT2NUM(CA_BINOP_BIT_RSHIFT));
|
|
852
|
+
rb_define_const(rb_cCABinOp, "OP_MOD", INT2NUM(CA_BINOP_MOD));
|
|
853
|
+
rb_define_const(rb_cCABinOp, "OP_QUO", INT2NUM(CA_BINOP_QUO));
|
|
854
|
+
rb_define_const(rb_cCABinOp, "OP_RCP_MUL", INT2NUM(CA_BINOP_RCP_MUL));
|
|
855
|
+
rb_define_const(rb_cCABinOp, "OP_IPOWER", INT2NUM(CA_BINOP_IPOWER));
|
|
856
|
+
rb_define_const(rb_cCABinOp, "OP_COPYSIGN", INT2NUM(CA_BINOP_COPYSIGN));
|
|
857
|
+
rb_define_const(rb_cCABinOp, "OP_LOGADDEXP", INT2NUM(CA_BINOP_LOGADDEXP));
|
|
858
|
+
rb_define_const(rb_cCABinOp, "OP_NEXTAFTER", INT2NUM(CA_BINOP_NEXTAFTER));
|
|
859
|
+
rb_define_const(rb_cCABinOp, "OP_FMOD", INT2NUM(CA_BINOP_FMOD));
|
|
860
|
+
rb_define_const(rb_cCABinOp, "OP_ATAN2", INT2NUM(CA_BINOP_ATAN2));
|
|
861
|
+
rb_define_const(rb_cCABinOp, "OP_HYPOT", INT2NUM(CA_BINOP_HYPOT));
|
|
862
|
+
rb_define_const(rb_cCABinOp, "OP_PMAX", INT2NUM(CA_BINOP_PMAX));
|
|
863
|
+
rb_define_const(rb_cCABinOp, "OP_PMIN", INT2NUM(CA_BINOP_PMIN));
|
|
864
|
+
rb_define_const(rb_cCABinOp, "OP_MAXIMUM", INT2NUM(CA_BINOP_MAXIMUM));
|
|
865
|
+
rb_define_const(rb_cCABinOp, "OP_MINIMUM", INT2NUM(CA_BINOP_MINIMUM));
|
|
866
|
+
rb_define_const(rb_cCABinOp, "OP_AND", INT2NUM(CA_BINOP_AND));
|
|
867
|
+
rb_define_const(rb_cCABinOp, "OP_OR", INT2NUM(CA_BINOP_OR));
|
|
868
|
+
rb_define_const(rb_cCABinOp, "OP_XOR", INT2NUM(CA_BINOP_XOR));
|
|
869
|
+
rb_define_const(rb_cCABinOp, "OP_REMINDER", INT2NUM(CA_BINOP_REMINDER));
|
|
870
|
+
|
|
871
|
+
rb_define_alloc_func(rb_cCABinOp, rb_ca_binop_s_allocate);
|
|
872
|
+
rb_define_method(rb_cCABinOp, "initialize_copy",
|
|
873
|
+
rb_ca_binop_initialize_copy, 1);
|
|
874
|
+
|
|
875
|
+
rb_define_singleton_method(rb_cCABinOp, "__build__",
|
|
876
|
+
rb_ca_binop_s_build, 3);
|
|
877
|
+
|
|
878
|
+
rb_define_method(rb_cCABinOp, "__op_id__",
|
|
879
|
+
rb_ca_binop_op_id, 0);
|
|
880
|
+
rb_define_method(rb_cCABinOp, "__binop_right__",
|
|
881
|
+
rb_ca_binop_right, 0);
|
|
882
|
+
|
|
883
|
+
/* Test instrumentation, not user-facing. */
|
|
884
|
+
rb_define_singleton_method(rb_cCABinOp, "__reset_scratch_counter__",
|
|
885
|
+
rb_ca_binop_s_reset_scratch_counter, 0);
|
|
886
|
+
rb_define_singleton_method(rb_cCABinOp, "__scratch_count__",
|
|
887
|
+
rb_ca_binop_s_scratch_count, 0);
|
|
888
|
+
rb_define_singleton_method(rb_cCABinOp, "__reset_materialise_counter__",
|
|
889
|
+
rb_ca_binop_s_reset_materialise_counter, 0);
|
|
890
|
+
rb_define_singleton_method(rb_cCABinOp, "__materialise_count__",
|
|
891
|
+
rb_ca_binop_s_materialise_count, 0);
|
|
892
|
+
}
|