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