carray 3.0.2 → 3.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +568 -0
- data/README.md +6 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +220 -0
- data/ext/ca_axis_group.c +201 -123
- data/ext/ca_binop_dispatch.c +46 -52
- data/ext/ca_binop_dispatch.h +1 -1
- data/ext/ca_categorical_iterator.c +249 -183
- data/ext/ca_compare.c +7 -12
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +38 -23
- data/ext/ca_kernel_iterator.c +1765 -2076
- data/ext/ca_kernel_iterator.h +584 -566
- data/ext/ca_monop_dispatch.c +86 -63
- data/ext/ca_monop_dispatch.h +5 -0
- data/ext/ca_obj_array.c +223 -56
- data/ext/ca_obj_bincmp.c +172 -138
- data/ext/ca_obj_binop.c +116 -230
- data/ext/ca_obj_bitarray.c +40 -26
- data/ext/ca_obj_bitfield.c +100 -68
- data/ext/ca_obj_block.c +19 -9
- data/ext/ca_obj_byte_swap.c +45 -46
- data/ext/ca_obj_const_string.c +269 -44
- data/ext/ca_obj_face.c +612 -89
- data/ext/ca_obj_face.h +111 -47
- data/ext/ca_obj_fake.c +36 -79
- data/ext/ca_obj_farray.c +7 -3
- data/ext/ca_obj_field.c +33 -8
- data/ext/ca_obj_fixlen_string.c +23 -24
- data/ext/ca_obj_grid.c +541 -210
- data/ext/ca_obj_meld.c +331 -111
- data/ext/ca_obj_moncmp.c +80 -65
- data/ext/ca_obj_monop.c +177 -149
- data/ext/ca_obj_object.c +664 -248
- data/ext/ca_obj_record.c +63 -23
- data/ext/ca_obj_reduce.c +18 -16
- data/ext/ca_obj_refer.c +140 -58
- data/ext/ca_obj_remap.c +85 -24
- data/ext/ca_obj_repeat.c +24 -9
- data/ext/ca_obj_roll.c +121 -16
- data/ext/ca_obj_select.c +61 -58
- data/ext/ca_obj_select_axis.c +73 -107
- data/ext/ca_obj_shift.c +32 -102
- data/ext/ca_obj_stack.c +372 -122
- data/ext/ca_obj_stride.c +348 -140
- data/ext/ca_obj_string.c +88 -22
- data/ext/ca_obj_tile.c +38 -21
- data/ext/ca_obj_time.c +45 -31
- data/ext/ca_obj_timedelta.c +43 -29
- data/ext/ca_obj_transpose.c +17 -6
- data/ext/ca_obj_triop.c +125 -141
- data/ext/ca_obj_window.c +330 -44
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +104 -81
- data/ext/ca_sweep_engine.h +7 -20
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +542 -0
- data/ext/carray.h +241 -92
- data/ext/carray_access.c +608 -276
- data/ext/carray_address_basis.c +494 -97
- data/ext/carray_attribute.c +129 -4
- data/ext/carray_bincount.c +39 -7
- data/ext/carray_broadcast.c +56 -19
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_call_cfunc.c +108 -28
- data/ext/carray_cast.c +1576 -223
- data/ext/carray_cast_func.rb +77 -24
- data/ext/carray_class.c +4 -3
- data/ext/carray_conversion.c +208 -75
- data/ext/carray_copy.c +82 -24
- data/ext/carray_core.c +646 -162
- data/ext/carray_count.c +171 -88
- data/ext/carray_element.c +94 -60
- data/ext/carray_factorize.c +670 -324
- data/ext/carray_generate.c +260 -83
- data/ext/carray_histogram.c +209 -106
- data/ext/carray_hold.c +14 -16
- data/ext/carray_index_classifier.c +422 -243
- data/ext/carray_internal.h +692 -3
- data/ext/carray_kernels_bincmp.c +7 -0
- data/ext/carray_kernels_binop.c +487 -120
- data/ext/carray_kernels_init.c +653 -50
- data/ext/carray_kernels_moncmp.c +15 -8
- data/ext/carray_kernels_monop.c +99 -43
- data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
- data/ext/carray_kernels_reduce_boolean.c +112 -36
- data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
- data/ext/carray_kernels_reduce_extreme.c +3032 -2892
- data/ext/carray_kernels_reduce_variance.c +439 -500
- data/ext/carray_kernels_scan.c +1097 -488
- data/ext/carray_kernels_search.c +3787 -2176
- data/ext/carray_kernels_sort.c +1200 -920
- data/ext/carray_kernels_triop.c +479 -7
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +967 -153
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +910 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +299 -100
- data/ext/carray_memory_view.c +872 -758
- data/ext/carray_operator.c +1171 -364
- data/ext/carray_order.c +505 -133
- data/ext/carray_partition.c +112 -65
- data/ext/carray_random.c +327 -239
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +346 -78
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +249 -86
- data/ext/carray_sort.c +224 -227
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +118 -39
- data/ext/carray_test.c +193 -69
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +579 -113
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +19 -4
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1202 -1014
- data/ext/ruby_carray.c +17 -5
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +160 -17
- data/lib/carray/autoload_carray.rb +23 -27
- data/lib/carray/autoload_method_extension.rb +20 -5
- data/lib/carray/axis_group.rb +360 -63
- data/lib/carray/basics.rb +162 -28
- data/lib/carray/bincount_nd.rb +18 -2
- data/lib/carray/block_iterator.rb +231 -58
- data/lib/carray/boolean_reduce.rb +34 -42
- data/lib/carray/categorical.rb +242 -52
- data/lib/carray/categorical_iterator.rb +437 -827
- data/lib/carray/complex.rb +41 -34
- data/lib/carray/conditional.rb +150 -14
- data/lib/carray/const_string.rb +59 -4
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +7 -1
- data/lib/carray/frame/column_verbs.rb +70 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +82 -7
- data/lib/carray/frame/csv_parser.rb +688 -87
- data/lib/carray/frame/describe.rb +80 -0
- data/lib/carray/frame/frame.rb +369 -45
- data/lib/carray/frame/group.rb +631 -90
- data/lib/carray/frame/io.rb +506 -79
- data/lib/carray/frame/join.rb +411 -62
- data/lib/carray/frame/records.rb +116 -19
- data/lib/carray/frame/reshape.rb +455 -0
- data/lib/carray/frame/sort.rb +30 -18
- data/lib/carray/frame/verbs.rb +868 -61
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +4 -0
- data/lib/carray/fuse_source.rb +118 -2
- data/lib/carray/fusion.rb +257 -42
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +54 -13
- data/lib/carray/iterator.rb +99 -9
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +216 -193
- data/lib/carray/mask_gap_fill.rb +112 -92
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +52 -21
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +18 -2
- data/lib/carray/methods/bit_string.rb +15 -4
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +18 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +25 -5
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +140 -10
- data/lib/carray/methods/join.rb +2 -7
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +182 -45
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +65 -17
- data/lib/carray/segment_iterator.rb +1221 -0
- data/lib/carray/serialize.rb +214 -30
- data/lib/carray/slab_iterator.rb +101 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +12 -4
- data/lib/carray/struct.rb +137 -58
- data/lib/carray/struct_builder.rb +124 -17
- data/lib/carray/time.rb +1222 -186
- data/lib/carray/window_iterator.rb +242 -81
- data/lib/carray.rb +9 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +5 -1
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +5 -4
- data/yard-stubs/ca_obj_roll.rb +2 -3
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +9 -5
- data/yard-stubs/carray_access.rb +11 -5
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +88 -43
- data/yard-stubs/carray_conversion.rb +15 -2
- data/yard-stubs/carray_copy.rb +12 -5
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +60 -12
- data/yard-stubs/carray_math.rb +52 -14
- data/yard-stubs/carray_median_percentile.rb +15 -8
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +61 -29
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +21 -9
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +10 -2
- data/yard-stubs/carray_sort.rb +49 -8
- data/yard-stubs/carray_test.rb +15 -3
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -5
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_kernels_map.c +0 -3467
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_scatter.c
CHANGED
|
@@ -9,14 +9,19 @@
|
|
|
9
9
|
duplicates unbuffered (sequential) — collisions accumulate
|
|
10
10
|
mask pair skipped when any of addrs[i] / vals[i] / self[addrs[i]] is masked
|
|
11
11
|
cast vals silently cast to self.data_type
|
|
12
|
-
data type
|
|
12
|
+
data type add / sub / mul: numeric, complex included
|
|
13
|
+
min / max: real numeric only (complex has no order)
|
|
13
14
|
(boolean / object / fixlen → CADataTypeError; the bang
|
|
14
15
|
cannot widen self, same rationale as fma! / fms!)
|
|
15
16
|
replace: numeric or boolean (assignment, no widening)
|
|
17
|
+
scalar any Numeric, true / false, or UNDEF; converted to self's
|
|
18
|
+
type as the indexer's store converts it (a value that does
|
|
19
|
+
not fit raises, as `self[i] = v` does)
|
|
16
20
|
|
|
17
21
|
--------------------------------------------------------------------------- */
|
|
18
22
|
|
|
19
23
|
#include "carray.h"
|
|
24
|
+
#include "carray_internal.h" /* ca_attach_window */
|
|
20
25
|
|
|
21
26
|
/* ---------- common kernel macros ----------
|
|
22
27
|
|
|
@@ -26,8 +31,8 @@
|
|
|
26
31
|
APPLY(qp, v) := one of:
|
|
27
32
|
OP_ADD *(qp) += (v)
|
|
28
33
|
OP_SUB *(qp) -= (v)
|
|
29
|
-
OP_MIN_FLT
|
|
30
|
-
OP_MAX_FLT
|
|
34
|
+
OP_MIN_FLT a NaN loses (CA_EXTREMUM_REPLACES, carray_internal.h)
|
|
35
|
+
OP_MAX_FLT likewise
|
|
31
36
|
OP_MIN_INT if ((v) < *(qp)) *(qp) = (v)
|
|
32
37
|
OP_MAX_INT if ((v) > *(qp)) *(qp) = (v)
|
|
33
38
|
*/
|
|
@@ -36,14 +41,30 @@
|
|
|
36
41
|
#define OP_SUB(qp, v) (*(qp) -= (v))
|
|
37
42
|
#define OP_MUL(qp, v) (*(qp) *= (v))
|
|
38
43
|
#define OP_REPLACE(qp, v) (*(qp) = (v))
|
|
39
|
-
#define OP_MIN_FLT(qp, v) do { if ((v)
|
|
40
|
-
#define OP_MAX_FLT(qp, v) do { if ((v)
|
|
44
|
+
#define OP_MIN_FLT(qp, v) do { if ( CA_EXTREMUM_REPLACES((v), *(qp), <) ) *(qp) = (v); } while (0)
|
|
45
|
+
#define OP_MAX_FLT(qp, v) do { if ( CA_EXTREMUM_REPLACES((v), *(qp), >) ) *(qp) = (v); } while (0)
|
|
41
46
|
#define OP_MIN_INT(qp, v) do { if ((v) < *(qp)) *(qp) = (v); } while (0)
|
|
42
47
|
#define OP_MAX_INT(qp, v) do { if ((v) > *(qp)) *(qp) = (v); } while (0)
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
/* The scalar operand, already converted to self's type by rb_ca_obj2ptr
|
|
50
|
+
(the indexer's store conversion) and held as one cell in vcell. */
|
|
51
|
+
typedef union {
|
|
52
|
+
char bytes[16];
|
|
53
|
+
double d;
|
|
54
|
+
int64_t l;
|
|
55
|
+
#ifdef HAVE_COMPLEX_H
|
|
56
|
+
cmplx128_t z;
|
|
57
|
+
#endif
|
|
58
|
+
} ca_scatter_cell_t;
|
|
59
|
+
|
|
60
|
+
#define SCALAR_REAL(T) (*(const T *) vcell.bytes)
|
|
61
|
+
#define SCALAR_CMPLX(T) (*(const T *) vcell.bytes)
|
|
62
|
+
|
|
63
|
+
#define LOOP_SCALAR(T, APPLY) LOOP_SCALAR_V(T, APPLY, SCALAR_REAL(T))
|
|
64
|
+
|
|
65
|
+
#define LOOP_SCALAR_V(T, APPLY, VS) do { \
|
|
66
|
+
T *q = (T *) qbase; \
|
|
67
|
+
T vs = VS; \
|
|
47
68
|
if ( mself ) { \
|
|
48
69
|
for (i = 0; i < n; i++) { \
|
|
49
70
|
if ( maddrs && maddrs[i] ) continue; \
|
|
@@ -64,7 +85,7 @@
|
|
|
64
85
|
} while (0)
|
|
65
86
|
|
|
66
87
|
#define LOOP_VEC(T, APPLY) do { \
|
|
67
|
-
T *q = (T *)
|
|
88
|
+
T *q = (T *) qbase; \
|
|
68
89
|
T *r = (T *) cv->ptr; \
|
|
69
90
|
if ( mself ) { \
|
|
70
91
|
for (i = 0; i < n; i++) { \
|
|
@@ -93,23 +114,29 @@
|
|
|
93
114
|
both value and mask (indexer contract, `self[addrs] = vals`).
|
|
94
115
|
- masked vals[i] flips target to masked (writes UNDEF); valid
|
|
95
116
|
vals[i] writes value and clears the target's mask bit.
|
|
96
|
-
|
|
97
|
-
writes and clears target mask. */
|
|
117
|
+
A scalar UNDEF masks every target (self's mask exists by then); any
|
|
118
|
+
other scalar writes and clears the target's mask. */
|
|
98
119
|
|
|
99
|
-
#define LOOP_SCALAR_REPLACE(T)
|
|
100
|
-
|
|
101
|
-
|
|
120
|
+
#define LOOP_SCALAR_REPLACE(T) LOOP_SCALAR_REPLACE_V(T, SCALAR_REAL(T))
|
|
121
|
+
|
|
122
|
+
#define LOOP_SCALAR_REPLACE_V(T, VS) do { \
|
|
123
|
+
T *q = (T *) qbase; \
|
|
124
|
+
T vs = VS; \
|
|
102
125
|
for (i = 0; i < n; i++) { \
|
|
103
126
|
if ( maddrs && maddrs[i] ) continue; \
|
|
104
127
|
addr = p[i]; \
|
|
105
128
|
CA_CHECK_INDEX(addr, elements); \
|
|
129
|
+
if ( vals_undef ) { \
|
|
130
|
+
mself[addr] = 1; \
|
|
131
|
+
continue; \
|
|
132
|
+
} \
|
|
106
133
|
q[addr] = vs; \
|
|
107
134
|
if ( mself ) mself[addr] = 0; \
|
|
108
135
|
} \
|
|
109
136
|
} while (0)
|
|
110
137
|
|
|
111
138
|
#define LOOP_VEC_REPLACE(T) do { \
|
|
112
|
-
T *q = (T *)
|
|
139
|
+
T *q = (T *) qbase; \
|
|
113
140
|
T *r = (T *) cv->ptr; \
|
|
114
141
|
for (i = 0; i < n; i++) { \
|
|
115
142
|
if ( maddrs && maddrs[i] ) continue; \
|
|
@@ -137,13 +164,13 @@
|
|
|
137
164
|
case CA_UINT32: if (vals_scalar) LOOP_SCALAR_REPLACE(uint32_t); else LOOP_VEC_REPLACE(uint32_t); break; \
|
|
138
165
|
case CA_UINT16: if (vals_scalar) LOOP_SCALAR_REPLACE(uint16_t); else LOOP_VEC_REPLACE(uint16_t); break; \
|
|
139
166
|
case CA_UINT8: if (vals_scalar) LOOP_SCALAR_REPLACE(uint8_t); else LOOP_VEC_REPLACE(uint8_t); break; \
|
|
167
|
+
CASES_CMPLX_REPLACE \
|
|
140
168
|
default: \
|
|
141
169
|
rb_bug("carray_scatter: unsupported data_type %d after numeric check", ca->data_type); \
|
|
142
170
|
} \
|
|
143
171
|
} while (0)
|
|
144
172
|
|
|
145
|
-
#define
|
|
146
|
-
switch ( ca->data_type ) { \
|
|
173
|
+
#define CASES_REAL(APPLY_INT, APPLY_FLT) \
|
|
147
174
|
case CA_FLOAT64: if (vals_scalar) LOOP_SCALAR(double, APPLY_FLT); else LOOP_VEC(double, APPLY_FLT); break; \
|
|
148
175
|
case CA_FLOAT32: if (vals_scalar) LOOP_SCALAR(float, APPLY_FLT); else LOOP_VEC(float, APPLY_FLT); break; \
|
|
149
176
|
case CA_INT64: if (vals_scalar) LOOP_SCALAR(int64_t, APPLY_INT); else LOOP_VEC(int64_t, APPLY_INT); break; \
|
|
@@ -153,121 +180,361 @@
|
|
|
153
180
|
case CA_UINT64: if (vals_scalar) LOOP_SCALAR(uint64_t, APPLY_INT); else LOOP_VEC(uint64_t, APPLY_INT); break; \
|
|
154
181
|
case CA_UINT32: if (vals_scalar) LOOP_SCALAR(uint32_t, APPLY_INT); else LOOP_VEC(uint32_t, APPLY_INT); break; \
|
|
155
182
|
case CA_UINT16: if (vals_scalar) LOOP_SCALAR(uint16_t, APPLY_INT); else LOOP_VEC(uint16_t, APPLY_INT); break; \
|
|
156
|
-
case CA_UINT8: if (vals_scalar) LOOP_SCALAR(uint8_t, APPLY_INT); else LOOP_VEC(uint8_t, APPLY_INT); break;
|
|
183
|
+
case CA_UINT8: if (vals_scalar) LOOP_SCALAR(uint8_t, APPLY_INT); else LOOP_VEC(uint8_t, APPLY_INT); break;
|
|
184
|
+
|
|
185
|
+
#ifdef HAVE_COMPLEX_H
|
|
186
|
+
#define CASES_CMPLX(APPLY) \
|
|
187
|
+
case CA_CMPLX64: if (vals_scalar) LOOP_SCALAR_V(cmplx64_t, APPLY, SCALAR_CMPLX(cmplx64_t)); \
|
|
188
|
+
else LOOP_VEC(cmplx64_t, APPLY); break; \
|
|
189
|
+
case CA_CMPLX128: if (vals_scalar) LOOP_SCALAR_V(cmplx128_t, APPLY, SCALAR_CMPLX(cmplx128_t)); \
|
|
190
|
+
else LOOP_VEC(cmplx128_t, APPLY); break;
|
|
191
|
+
#define CASES_CMPLX_REPLACE \
|
|
192
|
+
case CA_CMPLX64: if (vals_scalar) LOOP_SCALAR_REPLACE_V(cmplx64_t, SCALAR_CMPLX(cmplx64_t)); \
|
|
193
|
+
else LOOP_VEC_REPLACE(cmplx64_t); break; \
|
|
194
|
+
case CA_CMPLX128: if (vals_scalar) LOOP_SCALAR_REPLACE_V(cmplx128_t, SCALAR_CMPLX(cmplx128_t)); \
|
|
195
|
+
else LOOP_VEC_REPLACE(cmplx128_t); break;
|
|
196
|
+
#else
|
|
197
|
+
#define CASES_CMPLX(APPLY)
|
|
198
|
+
#define CASES_CMPLX_REPLACE
|
|
199
|
+
#endif
|
|
200
|
+
|
|
201
|
+
/* add / sub / mul: every numeric type, complex included. */
|
|
202
|
+
#define DISPATCH_ARITH(APPLY) do { \
|
|
203
|
+
switch ( ca->data_type ) { \
|
|
204
|
+
CASES_REAL(APPLY, APPLY) \
|
|
205
|
+
CASES_CMPLX(APPLY) \
|
|
206
|
+
default: \
|
|
207
|
+
rb_bug("carray_scatter: unsupported data_type %d after numeric check", ca->data_type); \
|
|
208
|
+
} \
|
|
209
|
+
} while (0)
|
|
210
|
+
|
|
211
|
+
/* min / max: real types only; the setup has already refused complex. */
|
|
212
|
+
#define DISPATCH_ORDERED(APPLY_INT, APPLY_FLT) do { \
|
|
213
|
+
switch ( ca->data_type ) { \
|
|
214
|
+
CASES_REAL(APPLY_INT, APPLY_FLT) \
|
|
157
215
|
default: \
|
|
158
|
-
/* numeric check passed before dispatch; complex types fall through to bug */ \
|
|
159
216
|
rb_bug("carray_scatter: unsupported data_type %d after numeric check", ca->data_type); \
|
|
160
217
|
} \
|
|
161
218
|
} while (0)
|
|
162
219
|
|
|
163
|
-
/*
|
|
220
|
+
/* A value that is one cell for every address: a Numeric, true / false,
|
|
221
|
+
or UNDEF. Anything else (a CArray, an Array, ...) is coerced to an
|
|
222
|
+
array of values. */
|
|
223
|
+
static int
|
|
224
|
+
ca_scatter_is_scalar (VALUE v)
|
|
225
|
+
{
|
|
226
|
+
return v == CA_UNDEF || v == Qtrue || v == Qfalse
|
|
227
|
+
|| rb_obj_is_kind_of(v, rb_cNumeric);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* Setup boilerplate: parse args and wrap addrs/vals.
|
|
164
231
|
|
|
165
232
|
Outputs into caller's locals:
|
|
166
|
-
ca, ci, cv (CArray*), n
|
|
167
|
-
|
|
168
|
-
|
|
233
|
+
ca, ci, cv (CArray*), n (ca_size_t),
|
|
234
|
+
vals_scalar, vals_undef (int), vcell (the scalar as one cell).
|
|
235
|
+
|
|
236
|
+
The kernel then runs through AT_RUN, and an address out of range
|
|
237
|
+
raising part way still leaves the cells already written.
|
|
169
238
|
|
|
170
|
-
|
|
239
|
+
An address or value array that shares self's root is copied first:
|
|
240
|
+
read in place, it would show the kernel cells it has already written.
|
|
171
241
|
*/
|
|
172
242
|
/* Body shared by arithmetic and replace setups. Caller precondition:
|
|
173
243
|
the data_type gate has already run (arithmetic = numeric only, replace
|
|
174
|
-
= numeric or boolean).
|
|
175
|
-
|
|
176
|
-
|
|
244
|
+
= numeric or boolean). A scalar is converted the way `self[i] = v`
|
|
245
|
+
converts it, so true / false reach only a boolean self and a value that
|
|
246
|
+
does not fit raises. A scalar UNDEF is a masked value: the arithmetic
|
|
247
|
+
family skips every pair, replace masks every target. */
|
|
248
|
+
#define AT_SETUP_BODY(name) \
|
|
249
|
+
ca_check_index_array(raddrs); \
|
|
177
250
|
raddrs = rb_ca_wrap_readonly(raddrs, INT2NUM(CA_SIZE)); \
|
|
178
251
|
TypedData_Get_Struct(raddrs, CArray, &carray_data_type, ci); \
|
|
252
|
+
if ( ca_shares_root(ci, ca) ) { \
|
|
253
|
+
raddrs = rb_ca_copy(raddrs); \
|
|
254
|
+
TypedData_Get_Struct(raddrs, CArray, &carray_data_type, ci); \
|
|
255
|
+
} \
|
|
179
256
|
n = ci->elements; \
|
|
180
257
|
if ( n == 0 ) return self; \
|
|
181
|
-
vals_scalar = (
|
|
182
|
-
|| ((allow_bool_scalar) && (rvals == Qtrue || rvals == Qfalse))); \
|
|
258
|
+
vals_scalar = ca_scatter_is_scalar(rvals); \
|
|
183
259
|
if ( vals_scalar ) { \
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
|
|
260
|
+
if ( rvals == CA_UNDEF ) { \
|
|
261
|
+
vals_undef = 1; \
|
|
262
|
+
} \
|
|
263
|
+
else { \
|
|
264
|
+
rb_ca_obj2ptr(self, rvals, vcell.bytes); \
|
|
265
|
+
} \
|
|
187
266
|
} \
|
|
188
267
|
else { \
|
|
268
|
+
/* coerce: a store into the receiver */ \
|
|
189
269
|
rvals = rb_ca_wrap_readonly(rvals, INT2NUM(ca->data_type)); \
|
|
190
270
|
TypedData_Get_Struct(rvals, CArray, &carray_data_type, cv); \
|
|
271
|
+
if ( ca_shares_root(cv, ca) ) { \
|
|
272
|
+
rvals = rb_ca_copy(rvals); \
|
|
273
|
+
TypedData_Get_Struct(rvals, CArray, &carray_data_type, cv); \
|
|
274
|
+
} \
|
|
191
275
|
if ( cv->elements != n ) { \
|
|
192
276
|
rb_raise(rb_eArgError, \
|
|
193
277
|
name ": vals length (%lld) doesn't match addrs length (%lld)", \
|
|
194
278
|
(long long)cv->elements, (long long)n); \
|
|
195
279
|
} \
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
p = (ca_size_t *) ci->ptr; \
|
|
200
|
-
maddrs = ci->mask ? (boolean8_t *) ci->mask->ptr : NULL; \
|
|
201
|
-
mvals = (cv && cv->mask) ? (boolean8_t *) cv->mask->ptr : NULL; \
|
|
202
|
-
mself = ca->mask ? (boolean8_t *) ca->mask->ptr : NULL; \
|
|
203
|
-
elements = ca->elements;
|
|
204
|
-
|
|
205
|
-
#define AT_SETUP_OR_RETURN(name) \
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
#define AT_SETUP_LOCALS \
|
|
206
283
|
CArray *ca, *ci, *cv = NULL; \
|
|
207
|
-
ca_size_t
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
284
|
+
ca_size_t n; \
|
|
285
|
+
int vals_scalar, vals_undef = 0; \
|
|
286
|
+
ca_scatter_cell_t vcell = {{0}};
|
|
287
|
+
|
|
288
|
+
#define AT_SETUP_OR_RETURN(name, ordered) \
|
|
289
|
+
AT_SETUP_LOCALS \
|
|
212
290
|
rb_ca_modify(self); \
|
|
213
291
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca); \
|
|
214
292
|
if ( ! ca_is_numeric_type(ca) ) { \
|
|
215
293
|
rb_raise(rb_eCADataTypeError, name " requires a numeric array"); \
|
|
216
294
|
} \
|
|
217
|
-
|
|
295
|
+
if ( (ordered) && ca_is_complex_type(ca) ) { \
|
|
296
|
+
rb_raise(rb_eCADataTypeError, \
|
|
297
|
+
name " requires a real array (complex values have no order)"); \
|
|
298
|
+
} \
|
|
299
|
+
AT_SETUP_BODY(name) \
|
|
300
|
+
if ( vals_undef ) return self;
|
|
218
301
|
|
|
219
302
|
/* replace variant: accepts boolean self (assignment, no widening) and
|
|
220
303
|
Ruby true / false as scalar vals. */
|
|
221
304
|
#define AT_SETUP_OR_RETURN_REPLACE(name) \
|
|
222
|
-
|
|
223
|
-
ca_size_t i, n, addr, elements; \
|
|
224
|
-
ca_size_t *p; \
|
|
225
|
-
boolean8_t *maddrs, *mvals = NULL, *mself; \
|
|
226
|
-
int vals_scalar, v_is_float = 0; \
|
|
227
|
-
double vd = 0.0; long vl = 0; \
|
|
305
|
+
AT_SETUP_LOCALS \
|
|
228
306
|
rb_ca_modify(self); \
|
|
229
307
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca); \
|
|
230
308
|
if ( ! ca_is_numeric_type(ca) && ca->data_type != CA_BOOLEAN ) { \
|
|
231
309
|
rb_raise(rb_eCADataTypeError, \
|
|
232
310
|
name " requires a numeric or boolean array"); \
|
|
233
311
|
} \
|
|
234
|
-
AT_SETUP_BODY(name
|
|
312
|
+
AT_SETUP_BODY(name) \
|
|
313
|
+
if ( vals_undef ) ca_create_mask(ca);
|
|
314
|
+
|
|
315
|
+
/* The kernel works either on self's own memory or on a compact region:
|
|
316
|
+
the distinct cells the addresses touch, read out of self and written
|
|
317
|
+
back to the same cells. In the region form `region` is set, the
|
|
318
|
+
addresses are replaced by slots into it, and skip marks the pairs the
|
|
319
|
+
kernel must pass over (a masked address, or any pair at or after the
|
|
320
|
+
first address out of range). */
|
|
321
|
+
typedef struct {
|
|
322
|
+
char *data;
|
|
323
|
+
boolean8_t *mask;
|
|
324
|
+
ca_size_t m;
|
|
325
|
+
ca_size_t *slots;
|
|
326
|
+
boolean8_t *skip;
|
|
327
|
+
ca_size_t n;
|
|
328
|
+
} ca_scatter_region_t;
|
|
329
|
+
|
|
330
|
+
typedef struct {
|
|
331
|
+
CArray *ca, *ci, *cv;
|
|
332
|
+
ca_size_t n;
|
|
333
|
+
int vals_scalar, vals_undef;
|
|
334
|
+
ca_scatter_cell_t vcell;
|
|
335
|
+
ca_scatter_region_t *region;
|
|
336
|
+
} ca_scatter_ctx_t;
|
|
337
|
+
|
|
338
|
+
/* Defines fname, the kernel body running DISPATCH with the names the
|
|
339
|
+
loop macros expect. */
|
|
340
|
+
#define AT_BODY(fname, DISPATCH) \
|
|
341
|
+
static VALUE \
|
|
342
|
+
fname (VALUE arg) \
|
|
343
|
+
{ \
|
|
344
|
+
ca_scatter_ctx_t *c_ = (ca_scatter_ctx_t *) arg; \
|
|
345
|
+
ca_scatter_region_t *rg_ = c_->region; \
|
|
346
|
+
CArray *ca = c_->ca, *ci = c_->ci, *cv = c_->cv; \
|
|
347
|
+
ca_size_t i, addr; \
|
|
348
|
+
ca_size_t n = rg_ ? rg_->n : c_->n; \
|
|
349
|
+
ca_size_t elements = rg_ ? rg_->m : ca->elements; \
|
|
350
|
+
char *qbase = rg_ ? rg_->data : ca->ptr; \
|
|
351
|
+
ca_size_t *p = rg_ ? rg_->slots : (ca_size_t *) ci->ptr; \
|
|
352
|
+
boolean8_t *maddrs = rg_ ? rg_->skip \
|
|
353
|
+
: (ci->mask ? (boolean8_t *) ci->mask->ptr : NULL); \
|
|
354
|
+
boolean8_t *mvals = (cv && cv->mask) ? (boolean8_t *) cv->mask->ptr : NULL; \
|
|
355
|
+
boolean8_t *mself = rg_ ? rg_->mask \
|
|
356
|
+
: (ca->mask ? (boolean8_t *) ca->mask->ptr : NULL); \
|
|
357
|
+
int vals_scalar = c_->vals_scalar, vals_undef = c_->vals_undef; \
|
|
358
|
+
ca_scatter_cell_t vcell = c_->vcell; \
|
|
359
|
+
(void) cv; (void) mvals; (void) vals_undef; (void) vcell; \
|
|
360
|
+
DISPATCH; \
|
|
361
|
+
return Qnil; \
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
static int
|
|
365
|
+
ca_scatter_cmp_addr (const void *a, const void *b)
|
|
366
|
+
{
|
|
367
|
+
ca_size_t x = *(const ca_size_t *) a, y = *(const ca_size_t *) b;
|
|
368
|
+
return (x > y) - (x < y);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
typedef struct {
|
|
372
|
+
ca_scatter_ctx_t *ctx;
|
|
373
|
+
VALUE (*kernel)(VALUE);
|
|
374
|
+
} ca_scatter_region_arg_t;
|
|
375
|
+
|
|
376
|
+
/* Window body for a self that does not lend its memory (a selection, a
|
|
377
|
+
converting view, ...). Attaching such a self would materialise every
|
|
378
|
+
cell and push every cell back, so cells the addresses never name would
|
|
379
|
+
make a round trip through the view -- and come back changed when the
|
|
380
|
+
view converts lossily. Only the cells named are read and written.
|
|
235
381
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
382
|
+
The pairs before the first address out of range are applied, then the
|
|
383
|
+
range error is raised, as in the direct form. */
|
|
384
|
+
static VALUE
|
|
385
|
+
ca_scatter_region_body (VALUE varg)
|
|
386
|
+
{
|
|
387
|
+
ca_scatter_region_arg_t *a = (ca_scatter_region_arg_t *) varg;
|
|
388
|
+
ca_scatter_ctx_t *c = a->ctx;
|
|
389
|
+
CArray *ca = c->ca, *ci = c->ci;
|
|
390
|
+
ca_size_t n = c->n, elements = ca->elements;
|
|
391
|
+
ca_size_t *p = (ca_size_t *) ci->ptr;
|
|
392
|
+
boolean8_t *maddrs = ci->mask ? (boolean8_t *) ci->mask->ptr : NULL;
|
|
393
|
+
ca_scatter_region_t rg;
|
|
394
|
+
ca_size_t *addrs, *uniq, i, nv, m, bad = 0;
|
|
395
|
+
boolean8_t *skip;
|
|
396
|
+
int self_masked = ca_has_mask(ca);
|
|
397
|
+
volatile VALUE h1 = 0, h2 = 0, h3 = 0, h4 = 0, h5 = 0;
|
|
398
|
+
|
|
399
|
+
addrs = ALLOCV_N(ca_size_t, h1, n);
|
|
400
|
+
skip = ALLOCV_N(boolean8_t, h2, n);
|
|
401
|
+
uniq = ALLOCV_N(ca_size_t, h3, n);
|
|
402
|
+
|
|
403
|
+
/* Normalise the addresses up to the first one out of range. */
|
|
404
|
+
m = 0;
|
|
405
|
+
for (nv = 0; nv < n; nv++) {
|
|
406
|
+
ca_size_t addr = p[nv];
|
|
407
|
+
if ( maddrs && maddrs[nv] ) {
|
|
408
|
+
skip[nv] = 1;
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
if ( addr < 0 ) {
|
|
412
|
+
addr += elements;
|
|
413
|
+
}
|
|
414
|
+
if ( addr < 0 || addr >= elements ) {
|
|
415
|
+
bad = p[nv];
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
skip[nv] = 0;
|
|
419
|
+
addrs[nv] = addr;
|
|
420
|
+
uniq[m++] = addr;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
qsort(uniq, (size_t) m, sizeof(ca_size_t), ca_scatter_cmp_addr);
|
|
424
|
+
if ( m > 0 ) {
|
|
425
|
+
ca_size_t k = 1;
|
|
426
|
+
for (i = 1; i < m; i++) {
|
|
427
|
+
if ( uniq[i] != uniq[k-1] ) {
|
|
428
|
+
uniq[k++] = uniq[i];
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
m = k;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/* Each address becomes its slot in uniq. */
|
|
435
|
+
for (i = 0; i < nv; i++) {
|
|
436
|
+
if ( ! skip[i] ) {
|
|
437
|
+
ca_size_t *hit = bsearch(&addrs[i], uniq, (size_t) m, sizeof(ca_size_t),
|
|
438
|
+
ca_scatter_cmp_addr);
|
|
439
|
+
addrs[i] = hit - uniq;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
rg.m = m;
|
|
444
|
+
rg.slots = addrs;
|
|
445
|
+
rg.skip = skip;
|
|
446
|
+
rg.n = nv;
|
|
447
|
+
rg.data = ALLOCV(h4, (size_t) (m > 0 ? m : 1) * ca->bytes);
|
|
448
|
+
rg.mask = NULL;
|
|
449
|
+
|
|
450
|
+
if ( m > 0 ) {
|
|
451
|
+
ca_xfer_addrs(ca, m, uniq, rg.data, CA_XFER_GET);
|
|
452
|
+
if ( self_masked ) {
|
|
453
|
+
ca_update_mask(ca);
|
|
454
|
+
rg.mask = ALLOCV_N(boolean8_t, h5, m);
|
|
455
|
+
ca_xfer_addrs(ca->mask, m, uniq, rg.mask, CA_XFER_GET);
|
|
456
|
+
}
|
|
457
|
+
c->region = &rg;
|
|
458
|
+
a->kernel((VALUE) c);
|
|
459
|
+
c->region = NULL;
|
|
460
|
+
ca_xfer_addrs(ca, m, uniq, rg.data, CA_XFER_PUT);
|
|
461
|
+
if ( rg.mask ) {
|
|
462
|
+
ca_xfer_addrs(ca->mask, m, uniq, rg.mask, CA_XFER_PUT);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if ( nv < n ) {
|
|
467
|
+
CA_CHECK_INDEX(bad, elements); /* raises */
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if ( h5 ) { ALLOCV_END(h5); }
|
|
471
|
+
ALLOCV_END(h4);
|
|
472
|
+
ALLOCV_END(h3);
|
|
473
|
+
ALLOCV_END(h2);
|
|
474
|
+
ALLOCV_END(h1);
|
|
475
|
+
return Qnil;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/* Self is written ('w'); the addresses and the values are read ('r').
|
|
479
|
+
A self that lends its memory is written in place; any other self goes
|
|
480
|
+
through the region form above, with only the addresses and the values
|
|
481
|
+
opened. */
|
|
482
|
+
#define AT_RUN(body) do { \
|
|
483
|
+
ca_scatter_ctx_t c_; \
|
|
484
|
+
CArray *list_[3]; \
|
|
485
|
+
c_.ca = ca; c_.ci = ci; c_.cv = cv; c_.n = n; \
|
|
486
|
+
c_.vals_scalar = vals_scalar; c_.vals_undef = vals_undef; \
|
|
487
|
+
c_.vcell = vcell; \
|
|
488
|
+
c_.region = NULL; \
|
|
489
|
+
if ( ca_attach_is_alias(ca) ) { \
|
|
490
|
+
list_[0] = ca; list_[1] = ci; list_[2] = cv; \
|
|
491
|
+
ca_attach_window(vals_scalar ? 2 : 3, list_, "wrr", body, (VALUE) &c_); \
|
|
492
|
+
} \
|
|
493
|
+
else { \
|
|
494
|
+
ca_scatter_region_arg_t ra_; \
|
|
495
|
+
ra_.ctx = &c_; ra_.kernel = body; \
|
|
496
|
+
list_[0] = ci; list_[1] = cv; \
|
|
497
|
+
ca_attach_window(vals_scalar ? 1 : 2, list_, "rr", \
|
|
498
|
+
ca_scatter_region_body, (VALUE) &ra_); \
|
|
499
|
+
} \
|
|
500
|
+
/* the views AT_SETUP_BODY made are reached only through ci and cv */ \
|
|
501
|
+
RB_GC_GUARD(raddrs); \
|
|
502
|
+
RB_GC_GUARD(rvals); \
|
|
240
503
|
} while (0)
|
|
241
504
|
|
|
242
505
|
/* --------------------------------------------------------------- */
|
|
243
506
|
|
|
507
|
+
AT_BODY(ca_scatter_add_body, DISPATCH_ARITH(OP_ADD))
|
|
508
|
+
|
|
244
509
|
/* CArray#scatter_add!(addrs, vals) — for each i, self[addrs[i]] +=
|
|
245
510
|
* vals[i] (or += vals when scalar). Duplicate addrs accumulate
|
|
246
511
|
* (unbuffered), unlike self[addrs] += vals which is last-wins. */
|
|
247
512
|
static VALUE
|
|
248
513
|
rb_ca_scatter_add_bang (VALUE self, VALUE raddrs, VALUE rvals)
|
|
249
514
|
{
|
|
250
|
-
AT_SETUP_OR_RETURN("scatter_add!");
|
|
251
|
-
|
|
252
|
-
AT_TEARDOWN();
|
|
515
|
+
AT_SETUP_OR_RETURN("scatter_add!", 0);
|
|
516
|
+
AT_RUN(ca_scatter_add_body);
|
|
253
517
|
return self;
|
|
254
518
|
}
|
|
255
519
|
|
|
256
520
|
/* --------------------------------------------------------------- */
|
|
257
521
|
|
|
522
|
+
AT_BODY(ca_scatter_sub_body, DISPATCH_ARITH(OP_SUB))
|
|
523
|
+
|
|
258
524
|
/* CArray#scatter_sub!(addrs, vals) — for each i, self[addrs[i]] -=
|
|
259
525
|
* vals[i]. Same mask/cast/bounds policy as scatter_add!. */
|
|
260
526
|
static VALUE
|
|
261
527
|
rb_ca_scatter_sub_bang (VALUE self, VALUE raddrs, VALUE rvals)
|
|
262
528
|
{
|
|
263
|
-
AT_SETUP_OR_RETURN("scatter_sub!");
|
|
264
|
-
|
|
265
|
-
AT_TEARDOWN();
|
|
529
|
+
AT_SETUP_OR_RETURN("scatter_sub!", 0);
|
|
530
|
+
AT_RUN(ca_scatter_sub_body);
|
|
266
531
|
return self;
|
|
267
532
|
}
|
|
268
533
|
|
|
269
534
|
/* --------------------------------------------------------------- */
|
|
270
535
|
|
|
536
|
+
AT_BODY(ca_scatter_mul_body, DISPATCH_ARITH(OP_MUL))
|
|
537
|
+
|
|
271
538
|
/* CArray#scatter_mul!(addrs, vals) — for each i, self[addrs[i]] *=
|
|
272
539
|
* vals[i]. NaN/inf follow standard C arithmetic (no fmin-style
|
|
273
540
|
* missing-value rule); integer overflow wraps. Otherwise identical
|
|
@@ -275,14 +542,15 @@ rb_ca_scatter_sub_bang (VALUE self, VALUE raddrs, VALUE rvals)
|
|
|
275
542
|
static VALUE
|
|
276
543
|
rb_ca_scatter_mul_bang (VALUE self, VALUE raddrs, VALUE rvals)
|
|
277
544
|
{
|
|
278
|
-
AT_SETUP_OR_RETURN("scatter_mul!");
|
|
279
|
-
|
|
280
|
-
AT_TEARDOWN();
|
|
545
|
+
AT_SETUP_OR_RETURN("scatter_mul!", 0);
|
|
546
|
+
AT_RUN(ca_scatter_mul_body);
|
|
281
547
|
return self;
|
|
282
548
|
}
|
|
283
549
|
|
|
284
550
|
/* --------------------------------------------------------------- */
|
|
285
551
|
|
|
552
|
+
AT_BODY(ca_scatter_min_body, DISPATCH_ORDERED(OP_MIN_INT, OP_MIN_FLT))
|
|
553
|
+
|
|
286
554
|
/* CArray#scatter_min!(addrs, vals) — for each i, self[addrs[i]] =
|
|
287
555
|
* min(self[addrs[i]], vals[i]). Float types follow the fmin rule
|
|
288
556
|
* (NaN is treated as missing). Same mask/cast/bounds policy as
|
|
@@ -290,28 +558,30 @@ rb_ca_scatter_mul_bang (VALUE self, VALUE raddrs, VALUE rvals)
|
|
|
290
558
|
static VALUE
|
|
291
559
|
rb_ca_scatter_min_bang (VALUE self, VALUE raddrs, VALUE rvals)
|
|
292
560
|
{
|
|
293
|
-
AT_SETUP_OR_RETURN("scatter_min!");
|
|
294
|
-
|
|
295
|
-
AT_TEARDOWN();
|
|
561
|
+
AT_SETUP_OR_RETURN("scatter_min!", 1);
|
|
562
|
+
AT_RUN(ca_scatter_min_body);
|
|
296
563
|
return self;
|
|
297
564
|
}
|
|
298
565
|
|
|
299
566
|
/* --------------------------------------------------------------- */
|
|
300
567
|
|
|
568
|
+
AT_BODY(ca_scatter_max_body, DISPATCH_ORDERED(OP_MAX_INT, OP_MAX_FLT))
|
|
569
|
+
|
|
301
570
|
/* CArray#scatter_max!(addrs, vals) — for each i, self[addrs[i]] =
|
|
302
571
|
* max(self[addrs[i]], vals[i]). Float types follow the fmax rule.
|
|
303
572
|
* Otherwise identical to scatter_add!. */
|
|
304
573
|
static VALUE
|
|
305
574
|
rb_ca_scatter_max_bang (VALUE self, VALUE raddrs, VALUE rvals)
|
|
306
575
|
{
|
|
307
|
-
AT_SETUP_OR_RETURN("scatter_max!");
|
|
308
|
-
|
|
309
|
-
AT_TEARDOWN();
|
|
576
|
+
AT_SETUP_OR_RETURN("scatter_max!", 1);
|
|
577
|
+
AT_RUN(ca_scatter_max_body);
|
|
310
578
|
return self;
|
|
311
579
|
}
|
|
312
580
|
|
|
313
581
|
/* --------------------------------------------------------------- */
|
|
314
582
|
|
|
583
|
+
AT_BODY(ca_scatter_replace_body, DISPATCH_NUMERIC_REPLACE())
|
|
584
|
+
|
|
315
585
|
/* CArray#scatter_replace!(addrs, vals) — for each i, self[addrs[i]] =
|
|
316
586
|
* vals[i] (or = vals when scalar). Semantically equivalent to
|
|
317
587
|
* self[addrs] = vals (last-write-wins on duplicate addrs) but bypasses
|
|
@@ -325,8 +595,7 @@ rb_ca_scatter_replace_bang (VALUE self, VALUE raddrs, VALUE rvals)
|
|
|
325
595
|
/* Pre-scan: if vals is a masked CArray and self isn't yet masked,
|
|
326
596
|
promote self so the kernel can flip target cells to masked (indexer
|
|
327
597
|
`self[addrs] = vals` establishes self.mask lazily the same way). */
|
|
328
|
-
if (
|
|
329
|
-
&& rb_obj_is_carray(rvals) ) {
|
|
598
|
+
if ( rb_obj_is_carray(rvals) ) {
|
|
330
599
|
CArray *cv_pre;
|
|
331
600
|
TypedData_Get_Struct(rvals, CArray, &carray_data_type, cv_pre);
|
|
332
601
|
if ( ca_has_mask(cv_pre) ) {
|
|
@@ -338,8 +607,7 @@ rb_ca_scatter_replace_bang (VALUE self, VALUE raddrs, VALUE rvals)
|
|
|
338
607
|
}
|
|
339
608
|
}
|
|
340
609
|
AT_SETUP_OR_RETURN_REPLACE("scatter_replace!");
|
|
341
|
-
|
|
342
|
-
AT_TEARDOWN();
|
|
610
|
+
AT_RUN(ca_scatter_replace_body);
|
|
343
611
|
return self;
|
|
344
612
|
}
|
|
345
613
|
|