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_utils.c
CHANGED
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
Utility helpers shared across the `ext/` C files: iterator setup / loop count
|
|
4
4
|
variadic helpers, Range parsing (`ca_parse_range` family), axis
|
|
5
5
|
normalization primitives (`ca_normalize_axis*` + Ruby-facing
|
|
6
|
-
`normalize_axis` / `normalize_axes`)
|
|
7
|
-
(`_scan_float` / `_scan_int`) for the text I/O layer.
|
|
6
|
+
`normalize_axis` / `normalize_axes`).
|
|
8
7
|
|
|
9
8
|
YARD signatures live in yard-stubs/carray_utils.rb; this file
|
|
10
9
|
carries implementation-only prose.
|
|
@@ -14,8 +13,12 @@
|
|
|
14
13
|
#include <stdarg.h>
|
|
15
14
|
#include "ruby.h"
|
|
16
15
|
#include "carray.h"
|
|
16
|
+
#include "carray_internal.h" /* ca_calling_method_name */
|
|
17
17
|
|
|
18
18
|
#include "ruby/st.h"
|
|
19
|
+
#include "ruby/thread_native.h"
|
|
20
|
+
#include "ruby/ractor.h"
|
|
21
|
+
#include "ruby/debug.h" /* rb_profile_frames: the method the user called */
|
|
19
22
|
|
|
20
23
|
static ID id_begin, id_end, id_excl_end;
|
|
21
24
|
#define RANGE_BEG(r) (rb_funcall(r, id_begin, 0))
|
|
@@ -55,7 +58,8 @@ ca_set_iterator (int n, ...)
|
|
|
55
58
|
max = ca->elements;
|
|
56
59
|
}
|
|
57
60
|
else if ( max != ca->elements ) {
|
|
58
|
-
rb_raise(
|
|
61
|
+
rb_raise(rb_eArgError, "%s: data size mismatch in operation",
|
|
62
|
+
ca_calling_method_name());
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
65
|
}
|
|
@@ -94,7 +98,7 @@ ca_get_loop_count (int n, ...)
|
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
if ( elements == -1 ) {
|
|
97
|
-
rb_raise(
|
|
101
|
+
rb_raise(rb_eArgError, "no data to process");
|
|
98
102
|
}
|
|
99
103
|
return elements;
|
|
100
104
|
}
|
|
@@ -153,12 +157,11 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
153
157
|
last += ( (last>=start) ? -1 : 1 );
|
|
154
158
|
}
|
|
155
159
|
if ( last < 0 || last >= size ) {
|
|
156
|
-
|
|
157
|
-
"invalid index range");
|
|
160
|
+
ca_index_out_of_range(last, size, "index");
|
|
158
161
|
}
|
|
159
162
|
*poffset = start;
|
|
160
163
|
*pcount = llabs(last - start) + 1;
|
|
161
|
-
*pstep = 1;
|
|
164
|
+
*pstep = ( last >= start ) ? 1 : -1;
|
|
162
165
|
}
|
|
163
166
|
#ifdef HAVE_RB_ARITHMETIC_SEQUENCE_EXTRACT
|
|
164
167
|
else if ( rb_obj_is_kind_of(arg, rb_cArithSeq) ) { /* ca[--,ArithSeq,--]*/
|
|
@@ -170,8 +173,9 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
170
173
|
excl = RTEST(x.exclude_end);
|
|
171
174
|
step = NUM2SIZE(x.step);
|
|
172
175
|
if ( step == 0 ) {
|
|
173
|
-
rb_raise(
|
|
176
|
+
rb_raise(rb_eArgError, "step should not be 0");
|
|
174
177
|
}
|
|
178
|
+
CA_CHECK_INDEX(start, size);
|
|
175
179
|
if ( last < 0 ) {
|
|
176
180
|
last += size;
|
|
177
181
|
}
|
|
@@ -179,9 +183,8 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
179
183
|
last += ( (last>=start) ? -1 : 1 );
|
|
180
184
|
}
|
|
181
185
|
if ( last < 0 || last >= size ) {
|
|
182
|
-
|
|
186
|
+
ca_index_out_of_range(last, size, "index");
|
|
183
187
|
}
|
|
184
|
-
CA_CHECK_INDEX(start, size);
|
|
185
188
|
if ( (last - start) * step < 0 ) {
|
|
186
189
|
count = 1;
|
|
187
190
|
}
|
|
@@ -189,7 +192,9 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
189
192
|
count = llabs(last - start)/llabs(step) + 1;
|
|
190
193
|
}
|
|
191
194
|
bound = start + (count - 1)*step;
|
|
192
|
-
|
|
195
|
+
if ( count > 0 && ( bound < 0 || bound >= size ) ) {
|
|
196
|
+
ca_index_out_of_range(bound, size, "index");
|
|
197
|
+
}
|
|
193
198
|
*poffset = start;
|
|
194
199
|
*pcount = count;
|
|
195
200
|
*pstep = step;
|
|
@@ -206,13 +211,14 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
206
211
|
if ( NIL_P(arg0) ) { /* [nil,k] */
|
|
207
212
|
step = NUM2SIZE(arg1);
|
|
208
213
|
if ( step == 0 ) {
|
|
209
|
-
rb_raise(
|
|
214
|
+
rb_raise(rb_eArgError, "step should not be 0");
|
|
210
215
|
}
|
|
211
216
|
start = 0;
|
|
212
217
|
count = (size-1)/llabs(step) + 1;
|
|
213
218
|
bound = start + (count - 1)*step;
|
|
214
|
-
|
|
215
|
-
|
|
219
|
+
if ( count > 0 && ( bound < 0 || bound >= size ) ) {
|
|
220
|
+
ca_index_out_of_range(bound, size, "index");
|
|
221
|
+
}
|
|
216
222
|
*poffset = start;
|
|
217
223
|
*pcount = count;
|
|
218
224
|
*pstep = step;
|
|
@@ -223,8 +229,9 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
223
229
|
excl = RTEST(RANGE_EXCL(arg0));
|
|
224
230
|
step = NUM2SIZE(arg1);
|
|
225
231
|
if ( step == 0 ) {
|
|
226
|
-
rb_raise(
|
|
232
|
+
rb_raise(rb_eArgError, "step should not be 0");
|
|
227
233
|
}
|
|
234
|
+
CA_CHECK_INDEX(start, size);
|
|
228
235
|
if ( last < 0 ) {
|
|
229
236
|
last += size;
|
|
230
237
|
}
|
|
@@ -232,9 +239,8 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
232
239
|
last += ( (last>=start) ? -1 : 1 );
|
|
233
240
|
}
|
|
234
241
|
if ( last < 0 || last >= size ) {
|
|
235
|
-
|
|
242
|
+
ca_index_out_of_range(last, size, "index");
|
|
236
243
|
}
|
|
237
|
-
CA_CHECK_INDEX(start, size);
|
|
238
244
|
if ( (last - start) * step < 0 ) {
|
|
239
245
|
count = 1;
|
|
240
246
|
}
|
|
@@ -242,7 +248,9 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
242
248
|
count = llabs(last - start)/llabs(step) + 1;
|
|
243
249
|
}
|
|
244
250
|
bound = start + (count - 1)*step;
|
|
245
|
-
|
|
251
|
+
if ( count > 0 && ( bound < 0 || bound >= size ) ) {
|
|
252
|
+
ca_index_out_of_range(bound, size, "index");
|
|
253
|
+
}
|
|
246
254
|
*poffset = start;
|
|
247
255
|
*pcount = count;
|
|
248
256
|
*pstep = step;
|
|
@@ -257,8 +265,9 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
257
265
|
excl = RTEST(x.exclude_end);
|
|
258
266
|
step = NUM2SIZE(x.step);
|
|
259
267
|
if ( step == 0 ) {
|
|
260
|
-
rb_raise(
|
|
268
|
+
rb_raise(rb_eArgError, "step should not be 0");
|
|
261
269
|
}
|
|
270
|
+
CA_CHECK_INDEX(start, size);
|
|
262
271
|
if ( last < 0 ) {
|
|
263
272
|
last += size;
|
|
264
273
|
}
|
|
@@ -266,9 +275,8 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
266
275
|
last += ( (last>=start) ? -1 : 1 );
|
|
267
276
|
}
|
|
268
277
|
if ( last < 0 || last >= size ) {
|
|
269
|
-
|
|
278
|
+
ca_index_out_of_range(last, size, "index");
|
|
270
279
|
}
|
|
271
|
-
CA_CHECK_INDEX(start, size);
|
|
272
280
|
if ( (last - start) * step < 0 ) {
|
|
273
281
|
count = 1;
|
|
274
282
|
}
|
|
@@ -276,7 +284,9 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
276
284
|
count = llabs(last - start)/llabs(step) + 1;
|
|
277
285
|
}
|
|
278
286
|
bound = start + (count - 1)*step;
|
|
279
|
-
|
|
287
|
+
if ( count > 0 && ( bound < 0 || bound >= size ) ) {
|
|
288
|
+
ca_index_out_of_range(bound, size, "index");
|
|
289
|
+
}
|
|
280
290
|
*poffset = start;
|
|
281
291
|
*pcount = count;
|
|
282
292
|
*pstep = step;
|
|
@@ -285,9 +295,11 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
285
295
|
else { /* [i,n] */
|
|
286
296
|
start = NUM2SIZE(arg0);
|
|
287
297
|
count = NUM2SIZE(arg1);
|
|
288
|
-
bound = start + (count - 1);
|
|
289
298
|
CA_CHECK_INDEX(start, size);
|
|
290
|
-
|
|
299
|
+
bound = start + (count - 1);
|
|
300
|
+
if ( count > 0 && ( bound < 0 || bound >= size ) ) {
|
|
301
|
+
ca_index_out_of_range(bound, size, "index");
|
|
302
|
+
}
|
|
291
303
|
*poffset = start;
|
|
292
304
|
*pcount = count;
|
|
293
305
|
*pstep = 1;
|
|
@@ -298,21 +310,23 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
298
310
|
count = NUM2SIZE(rb_ary_entry(arg, 1));
|
|
299
311
|
step = NUM2SIZE(rb_ary_entry(arg, 2));
|
|
300
312
|
if ( step == 0 ) {
|
|
301
|
-
rb_raise(
|
|
313
|
+
rb_raise(rb_eArgError, "step should not be 0");
|
|
302
314
|
}
|
|
303
|
-
bound = start + (count - 1)*step;
|
|
304
315
|
CA_CHECK_INDEX(start, size);
|
|
305
|
-
|
|
316
|
+
bound = start + (count - 1)*step;
|
|
317
|
+
if ( count > 0 && ( bound < 0 || bound >= size ) ) {
|
|
318
|
+
ca_index_out_of_range(bound, size, "index");
|
|
319
|
+
}
|
|
306
320
|
*poffset = start;
|
|
307
321
|
*pcount = count;
|
|
308
322
|
*pstep = step;
|
|
309
323
|
}
|
|
310
324
|
else {
|
|
311
|
-
rb_raise(
|
|
325
|
+
rb_raise(rb_eArgError, "unknown range specification");
|
|
312
326
|
}
|
|
313
327
|
}
|
|
314
328
|
else {
|
|
315
|
-
rb_raise(
|
|
329
|
+
rb_raise(rb_eArgError, "unknown range specification");
|
|
316
330
|
}
|
|
317
331
|
}
|
|
318
332
|
|
|
@@ -430,11 +444,11 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
|
|
|
430
444
|
*pstep = step;
|
|
431
445
|
}
|
|
432
446
|
else {
|
|
433
|
-
rb_raise(
|
|
447
|
+
rb_raise(rb_eArgError, "unknown range specification");
|
|
434
448
|
}
|
|
435
449
|
}
|
|
436
450
|
else {
|
|
437
|
-
rb_raise(
|
|
451
|
+
rb_raise(rb_eArgError, "unknown range specification");
|
|
438
452
|
}
|
|
439
453
|
}
|
|
440
454
|
|
|
@@ -458,14 +472,12 @@ ca_bounds_normalize_index (int8_t bounds, ca_size_t size0, ca_size_t k)
|
|
|
458
472
|
k += size0;
|
|
459
473
|
}
|
|
460
474
|
if ( k < 0 || k >= size0 ) {
|
|
461
|
-
|
|
462
|
-
"window index out of range");
|
|
475
|
+
ca_index_out_of_range(k, size0, "index");
|
|
463
476
|
}
|
|
464
477
|
return k;
|
|
465
478
|
case CA_BOUNDS_STRICT:
|
|
466
479
|
if ( k < 0 || k >= size0 ) {
|
|
467
|
-
|
|
468
|
-
"window index out of range");
|
|
480
|
+
ca_index_out_of_range(k, size0, "index");
|
|
469
481
|
}
|
|
470
482
|
return k;
|
|
471
483
|
case CA_BOUNDS_NEAREST:
|
|
@@ -477,16 +489,469 @@ ca_bounds_normalize_index (int8_t bounds, ca_size_t size0, ca_size_t k)
|
|
|
477
489
|
k = k % (2*size0);
|
|
478
490
|
return ( k < size0 ) ? k : 2*size0-1-k;
|
|
479
491
|
default:
|
|
480
|
-
rb_raise(
|
|
492
|
+
rb_raise(rb_eArgError,
|
|
481
493
|
"unknown window boundary specified (%i)", bounds);
|
|
482
494
|
}
|
|
483
495
|
}
|
|
484
496
|
|
|
497
|
+
/* The name of the method the user called, for error messages. A C
|
|
498
|
+
entry reached directly from C (no rb_funcall) reports the method that
|
|
499
|
+
was entered from Ruby, which is the one the user wrote. The internal
|
|
500
|
+
`_ki` twin of a public method is reported under the public name.
|
|
501
|
+
Falls back to "axis" when there is no method frame. */
|
|
502
|
+
/* A C copy of an ID's name that stays put. rb_id2name points into the
|
|
503
|
+
name's String, which compaction can move while a caller is still
|
|
504
|
+
formatting a message with it; the copy is made once per ID while the
|
|
505
|
+
String is held on the stack (and so pinned), and kept for the life of
|
|
506
|
+
the process. The table is shared by every Ractor, hence the lock. */
|
|
507
|
+
static st_table *ca_id_names = NULL;
|
|
508
|
+
static rb_nativethread_lock_t ca_id_names_lock;
|
|
509
|
+
|
|
510
|
+
static const char *
|
|
511
|
+
ca_stable_id_name (ID id)
|
|
512
|
+
{
|
|
513
|
+
st_data_t found;
|
|
514
|
+
const char *name = NULL;
|
|
515
|
+
rb_nativethread_lock_lock(&ca_id_names_lock);
|
|
516
|
+
if ( st_lookup(ca_id_names, (st_data_t) id, &found) ) {
|
|
517
|
+
name = (const char *) found;
|
|
518
|
+
}
|
|
519
|
+
rb_nativethread_lock_unlock(&ca_id_names_lock);
|
|
520
|
+
if ( name ) {
|
|
521
|
+
return name;
|
|
522
|
+
}
|
|
523
|
+
{
|
|
524
|
+
VALUE str = rb_id2str(id);
|
|
525
|
+
long len;
|
|
526
|
+
char *copy;
|
|
527
|
+
if ( NIL_P(str) ) {
|
|
528
|
+
return NULL;
|
|
529
|
+
}
|
|
530
|
+
len = RSTRING_LEN(str);
|
|
531
|
+
copy = ALLOC_N(char, len + 1);
|
|
532
|
+
memcpy(copy, RSTRING_PTR(str), len);
|
|
533
|
+
copy[len] = '\0';
|
|
534
|
+
RB_GC_GUARD(str);
|
|
535
|
+
rb_nativethread_lock_lock(&ca_id_names_lock);
|
|
536
|
+
if ( st_lookup(ca_id_names, (st_data_t) id, &found) ) {
|
|
537
|
+
xfree(copy);
|
|
538
|
+
name = (const char *) found;
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
st_insert(ca_id_names, (st_data_t) id, (st_data_t) copy);
|
|
542
|
+
name = copy;
|
|
543
|
+
}
|
|
544
|
+
rb_nativethread_lock_unlock(&ca_id_names_lock);
|
|
545
|
+
return name;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/* The method a delegating method answers for. A method that does its work
|
|
550
|
+
by calling others (median calls partition_index, mode calls sort) runs
|
|
551
|
+
them under ca_answer_as_caller, so an error they raise names the method
|
|
552
|
+
the user called. The outermost one wins. The name is kept with the
|
|
553
|
+
Ruby thread (Thread#[], so per fiber): Ractors share native threads under
|
|
554
|
+
the M:N scheduler, and a native-thread-local variable leaks one Ractor's
|
|
555
|
+
name into another's message. */
|
|
556
|
+
static ID id_answering;
|
|
557
|
+
|
|
558
|
+
static const char *
|
|
559
|
+
ca_answering_name (void)
|
|
560
|
+
{
|
|
561
|
+
VALUE name = rb_thread_local_aref(rb_thread_current(), id_answering);
|
|
562
|
+
return NIL_P(name) ? NULL : ca_stable_id_name(SYM2ID(name));
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
static void
|
|
566
|
+
ca_set_answering_name (const char *name)
|
|
567
|
+
{
|
|
568
|
+
rb_thread_local_aset(rb_thread_current(), id_answering,
|
|
569
|
+
name ? ID2SYM(rb_intern(name)) : Qnil);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
static VALUE
|
|
573
|
+
ca_answer_restore (VALUE unused)
|
|
574
|
+
{
|
|
575
|
+
ca_set_answering_name(NULL);
|
|
576
|
+
return Qnil;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/* A C method that does its work by calling others runs them through here.
|
|
580
|
+
It used to fix the name at entry; the name is now found from the frames
|
|
581
|
+
when an error is raised (ca_user_called_method_id), which also reaches
|
|
582
|
+
the outer method, so nothing is fixed and nothing is paid on the way in. */
|
|
583
|
+
VALUE
|
|
584
|
+
ca_answer_as_caller (VALUE (*body)(VALUE), VALUE arg)
|
|
585
|
+
{
|
|
586
|
+
return body(arg);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/* CArray.__name_errors_after_method__(name) { ... }: the same for a method written in Ruby. */
|
|
590
|
+
static VALUE
|
|
591
|
+
rb_ca_s_answer_as_body (VALUE unused)
|
|
592
|
+
{
|
|
593
|
+
return rb_yield(Qnil);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
static VALUE
|
|
597
|
+
rb_ca_s_answer_as (VALUE klass, VALUE name)
|
|
598
|
+
{
|
|
599
|
+
if ( ca_answering_name() ) {
|
|
600
|
+
return rb_yield(Qnil);
|
|
601
|
+
}
|
|
602
|
+
ca_set_answering_name(ca_stable_id_name(rb_to_id(name)));
|
|
603
|
+
return rb_ensure(rb_ca_s_answer_as_body, Qnil, ca_answer_restore, Qnil);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/* The directory the library's Ruby files are loaded from (lib/), set once
|
|
607
|
+
by lib/carray.rb as it loads, read only afterwards. */
|
|
608
|
+
static char *ca_library_root = NULL;
|
|
609
|
+
static long ca_library_root_len = 0;
|
|
610
|
+
|
|
611
|
+
/* CArray.library_root = dir (private): where the frames of the library's
|
|
612
|
+
own Ruby methods are. The first call wins. */
|
|
613
|
+
static VALUE
|
|
614
|
+
rb_ca_s_set_library_root (VALUE klass, VALUE dir)
|
|
615
|
+
{
|
|
616
|
+
if ( ca_library_root == NULL ) {
|
|
617
|
+
long len = RSTRING_LEN(StringValue(dir));
|
|
618
|
+
char *copy = ALLOC_N(char, len + 1);
|
|
619
|
+
memcpy(copy, RSTRING_PTR(dir), len);
|
|
620
|
+
copy[len] = '\0';
|
|
621
|
+
ca_library_root_len = len;
|
|
622
|
+
ca_library_root = copy;
|
|
623
|
+
}
|
|
624
|
+
return Qnil;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/* Whether a frame without a source file -- a C method -- is one of the
|
|
628
|
+
library's: a method of a CA* or CScalar class, or a CA_* conversion
|
|
629
|
+
function. A method of a core class (Array#map, Integer#times) is not. */
|
|
630
|
+
static int
|
|
631
|
+
ca_frame_is_library_cfunc (VALUE frame, VALUE name)
|
|
632
|
+
{
|
|
633
|
+
VALUE path = rb_profile_frame_classpath(frame);
|
|
634
|
+
if ( ! NIL_P(path) ) {
|
|
635
|
+
const char *p = RSTRING_PTR(path);
|
|
636
|
+
long n = RSTRING_LEN(path);
|
|
637
|
+
if ( ( n >= 2 && strncmp(p, "CA", 2) == 0 )
|
|
638
|
+
|| ( n >= 7 && strncmp(p, "CScalar", 7) == 0 ) ) {
|
|
639
|
+
return 1;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
return RSTRING_LEN(name) > 3 && strncmp(RSTRING_PTR(name), "CA_", 3) == 0;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/* The method the user called: going out from the innermost frame, the last
|
|
646
|
+
frame of the library -- a Ruby method under ca_library_root, or one of
|
|
647
|
+
its C methods -- before the user's own code (a block included) is
|
|
648
|
+
reached. A core C method the library calls on the way (Array#map) is
|
|
649
|
+
passed through. 0 when no frame of the library is found. */
|
|
650
|
+
#define CA_NAMING_FRAMES 64
|
|
651
|
+
|
|
652
|
+
static ID
|
|
653
|
+
ca_user_called_method_id (void)
|
|
654
|
+
{
|
|
655
|
+
ID id_initialize = rb_intern("initialize");
|
|
656
|
+
ID id_new = rb_intern("new");
|
|
657
|
+
VALUE frames[CA_NAMING_FRAMES];
|
|
658
|
+
int lines[CA_NAMING_FRAMES];
|
|
659
|
+
int n, i;
|
|
660
|
+
ID found = 0;
|
|
661
|
+
if ( ca_library_root == NULL ) {
|
|
662
|
+
return 0;
|
|
663
|
+
}
|
|
664
|
+
n = rb_profile_frames(0, CA_NAMING_FRAMES, frames, lines);
|
|
665
|
+
for (i = 0; i < n; i++) {
|
|
666
|
+
VALUE file = rb_profile_frame_absolute_path(frames[i]);
|
|
667
|
+
VALUE name, label;
|
|
668
|
+
if ( NIL_P(file) ) {
|
|
669
|
+
/* code evaluated with a file name (class_eval in the library) and the
|
|
670
|
+
core written in Ruby ("<internal:numeric>") have a path but no
|
|
671
|
+
absolute path; -e has a path outside the library */
|
|
672
|
+
file = rb_profile_frame_path(frames[i]);
|
|
673
|
+
}
|
|
674
|
+
if ( ! NIL_P(file) && strcmp(StringValueCStr(file), "<cfunc>") == 0 ) {
|
|
675
|
+
name = rb_profile_frame_method_name(frames[i]);
|
|
676
|
+
if ( NIL_P(name) ) {
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
if ( ca_frame_is_library_cfunc(frames[i], name) ) {
|
|
680
|
+
found = rb_to_id(name);
|
|
681
|
+
}
|
|
682
|
+
else if ( found == id_initialize && rb_to_id(name) == id_new ) {
|
|
683
|
+
found = id_new; /* Class#new around our initialize */
|
|
684
|
+
}
|
|
685
|
+
continue; /* a core C method passes */
|
|
686
|
+
}
|
|
687
|
+
if ( ! NIL_P(file) && strncmp(StringValueCStr(file), "<internal:", 10) == 0 ) {
|
|
688
|
+
continue; /* core written in Ruby (Integer#times) */
|
|
689
|
+
}
|
|
690
|
+
if ( NIL_P(file) /* eval without a file: the user's */
|
|
691
|
+
|| RSTRING_LEN(file) <= ca_library_root_len
|
|
692
|
+
|| strncmp(RSTRING_PTR(file), ca_library_root, ca_library_root_len) != 0
|
|
693
|
+
|| RSTRING_PTR(file)[ca_library_root_len] != '/' ) {
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
/* A block of the library (an each inside a method, the autoload stub)
|
|
697
|
+
names nothing: the method around it is further out. A block whose
|
|
698
|
+
method is a class body is a method made by define_method, and its
|
|
699
|
+
frame does not carry the method's name, so the walk gives up and the
|
|
700
|
+
innermost C method is named, as before the walk. */
|
|
701
|
+
label = rb_profile_frame_label(frames[i]);
|
|
702
|
+
if ( ! NIL_P(label) && strncmp(StringValueCStr(label), "block ", 6) == 0 ) {
|
|
703
|
+
VALUE base = rb_profile_frame_base_label(frames[i]);
|
|
704
|
+
if ( ! NIL_P(base) && RSTRING_LEN(base) > 0 && RSTRING_PTR(base)[0] == '<' ) {
|
|
705
|
+
return 0;
|
|
706
|
+
}
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
name = rb_profile_frame_method_name(frames[i]);
|
|
710
|
+
if ( ! NIL_P(name) ) {
|
|
711
|
+
found = rb_to_id(name);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return found;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
const char *
|
|
718
|
+
ca_calling_method_name (void)
|
|
719
|
+
{
|
|
720
|
+
ID id;
|
|
721
|
+
const char *s;
|
|
722
|
+
size_t n;
|
|
723
|
+
if ( (s = ca_answering_name()) ) {
|
|
724
|
+
return s;
|
|
725
|
+
}
|
|
726
|
+
id = ca_user_called_method_id();
|
|
727
|
+
if ( ! id ) {
|
|
728
|
+
id = rb_frame_this_func();
|
|
729
|
+
}
|
|
730
|
+
if ( ! id ) {
|
|
731
|
+
return "axis";
|
|
732
|
+
}
|
|
733
|
+
s = ca_stable_id_name(id);
|
|
734
|
+
if ( ! s ) {
|
|
735
|
+
return "axis";
|
|
736
|
+
}
|
|
737
|
+
n = strlen(s);
|
|
738
|
+
if ( n > 3 && strcmp(s + n - 3, "_ki") == 0 ) {
|
|
739
|
+
return ca_stable_id_name(rb_intern2(s, (long) (n - 3)));
|
|
740
|
+
}
|
|
741
|
+
return s;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/* The Integer value of an integer argument (`axis`, `kth`, `min_count`,
|
|
745
|
+
...). Anything else -- a Float included, which NUM2LONG would truncate
|
|
746
|
+
-- is a TypeError. `arg` is the argument's name; `name` names the method
|
|
747
|
+
in the message, NULL for the method the user called. */
|
|
748
|
+
/* The number of cells in a shape. A shape whose cell count, or whose size
|
|
749
|
+
at `bytes` a cell, does not fit ca_size_t is refused: wrapped, the count
|
|
750
|
+
would describe a smaller array than the view addresses, and every read
|
|
751
|
+
and write past it would leave the buffer. Negative extents are the
|
|
752
|
+
caller's to refuse, with its own message. */
|
|
753
|
+
ca_size_t
|
|
754
|
+
ca_shape_elements (int8_t ndim, const ca_size_t *dim, ca_size_t bytes)
|
|
755
|
+
{
|
|
756
|
+
ca_size_t elements = 1, total;
|
|
757
|
+
int8_t i;
|
|
758
|
+
for ( i = 0; i < ndim; i++ ) {
|
|
759
|
+
if ( dim[i] == 0 ) return 0; /* empty, whatever the other extents */
|
|
760
|
+
}
|
|
761
|
+
for ( i = 0; i < ndim; i++ ) {
|
|
762
|
+
if ( __builtin_mul_overflow(elements, dim[i], &elements) ) {
|
|
763
|
+
rb_raise(rb_eArgError, "too large byte length");
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
if ( __builtin_mul_overflow(elements, (bytes > 0 ? bytes : 1), &total) ) {
|
|
767
|
+
rb_raise(rb_eArgError, "too large byte length");
|
|
768
|
+
}
|
|
769
|
+
return elements;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/* An index array is read as ca_size_t. A float or complex one would be
|
|
773
|
+
cut to an integer on the way, so it is refused, as the indexer refuses
|
|
774
|
+
it. A uint64 one holding 2**63 or more would turn negative and count
|
|
775
|
+
from the end of the axis, so it is refused as the out-of-range index it
|
|
776
|
+
is. */
|
|
777
|
+
void
|
|
778
|
+
ca_check_index_array (VALUE v)
|
|
779
|
+
{
|
|
780
|
+
CArray *ca;
|
|
781
|
+
if ( ! rb_obj_is_carray(v) ) return;
|
|
782
|
+
GetCArray(v, ca);
|
|
783
|
+
if ( ca_is_float_type(ca) || ca_is_complex_type(ca) ) {
|
|
784
|
+
rb_raise(rb_eIndexError,
|
|
785
|
+
"data_type %s is invalid for an index (should be integer)",
|
|
786
|
+
ca_type_name[ca->data_type]);
|
|
787
|
+
}
|
|
788
|
+
if ( ca->data_type != CA_UINT64 || ca->elements == 0 ) return;
|
|
789
|
+
{
|
|
790
|
+
VALUE max = rb_funcall(v, rb_intern("max"), 0);
|
|
791
|
+
if ( rb_obj_is_kind_of(max, rb_cInteger) &&
|
|
792
|
+
RTEST(rb_funcall(max, rb_intern(">"), 1, LL2NUM(CA_LENGTH_MAX))) ) {
|
|
793
|
+
rb_raise(rb_eIndexError, "index %"PRIsVALUE" is out of range", max);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
long
|
|
799
|
+
ca_integer_arg (VALUE v, const char *arg, const char *name)
|
|
800
|
+
{
|
|
801
|
+
if ( ! RB_INTEGER_TYPE_P(v) ) {
|
|
802
|
+
rb_raise(rb_eTypeError, "%s: %s must be an Integer (got %"PRIsVALUE")",
|
|
803
|
+
name ? name : ca_calling_method_name(), arg, rb_obj_class(v));
|
|
804
|
+
}
|
|
805
|
+
return NUM2LONG(v);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
void
|
|
809
|
+
ca_index_out_of_range_at (ca_size_t idx, ca_size_t n, int axis)
|
|
810
|
+
{
|
|
811
|
+
rb_raise(rb_eIndexError,
|
|
812
|
+
"%s: index %lld is out of range for length %lld on axis %d",
|
|
813
|
+
ca_calling_method_name(), (long long) idx, (long long) n, axis);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
void
|
|
817
|
+
ca_obj_compare_refused (VALUE a, VALUE b)
|
|
818
|
+
{
|
|
819
|
+
/* The right-hand value is written as Ruby's own comparison error writes
|
|
820
|
+
it: inspected when it is nil, true, false or a number, its class
|
|
821
|
+
otherwise. */
|
|
822
|
+
volatile VALUE rhs = ( RB_SPECIAL_CONST_P(b) || RB_FLOAT_TYPE_P(b) )
|
|
823
|
+
? rb_inspect(b) : rb_class_name(rb_obj_class(b));
|
|
824
|
+
rb_raise(rb_eArgError, "%s: comparison of %"PRIsVALUE" with %"PRIsVALUE" failed",
|
|
825
|
+
ca_calling_method_name(), rb_class_name(rb_obj_class(a)), rhs);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
void
|
|
829
|
+
ca_index_out_of_range (ca_size_t idx, ca_size_t n, const char *what)
|
|
830
|
+
{
|
|
831
|
+
rb_raise(rb_eIndexError, "%s: %s %lld is out of range for length %lld",
|
|
832
|
+
ca_calling_method_name(), what, (long long) idx, (long long) n);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/* The min_count: keyword of a reduction: nil (not given) is -1, any other
|
|
836
|
+
value an Integer of at least 0. An error names `name`, or the method the
|
|
837
|
+
user called when NULL. See ca_too_few_present. */
|
|
838
|
+
long
|
|
839
|
+
ca_min_count_arg (VALUE v, const char *name)
|
|
840
|
+
{
|
|
841
|
+
long n;
|
|
842
|
+
if ( NIL_P(v) ) {
|
|
843
|
+
return -1;
|
|
844
|
+
}
|
|
845
|
+
n = ca_integer_arg(v, "min_count", name);
|
|
846
|
+
if ( n < 0 ) {
|
|
847
|
+
rb_raise(rb_eArgError, "%s: min_count must be non-negative (got %ld)",
|
|
848
|
+
name ? name : ca_calling_method_name(), n);
|
|
849
|
+
}
|
|
850
|
+
return n;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
/* CArray.__present_cells_needed_per_result_cell__(op, min_count, least): how many present cells a
|
|
854
|
+
result cell of `op` needs (ca_too_few_present), for a reduction written
|
|
855
|
+
in Ruby; it masks the cells whose count is below it. */
|
|
856
|
+
static VALUE
|
|
857
|
+
rb_ca_s_min_count_need (VALUE klass, VALUE vop, VALUE vmc, VALUE vleast)
|
|
858
|
+
{
|
|
859
|
+
volatile VALUE name = rb_String(vop);
|
|
860
|
+
long need = NUM2LONG(vleast);
|
|
861
|
+
long mc = ca_min_count_arg(vmc, StringValueCStr(name));
|
|
862
|
+
return LONG2NUM(mc > need ? mc : need);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
/* A keyword that names one of two Symbols (`masked_position: :first /
|
|
866
|
+
:last`, `kind: :quick / :stable`, `method: :ordinal / :dense`):
|
|
867
|
+
returns 0 for c0 and 1 for c1. Anything but a Symbol is a TypeError,
|
|
868
|
+
another Symbol an ArgumentError, both naming the method (`name`, or the
|
|
869
|
+
method the user called when NULL). */
|
|
870
|
+
int
|
|
871
|
+
ca_symbol_choice (VALUE v, const char *arg, const char *c0, const char *c1,
|
|
872
|
+
const char *name)
|
|
873
|
+
{
|
|
874
|
+
ID id;
|
|
875
|
+
if ( ! SYMBOL_P(v) ) {
|
|
876
|
+
rb_raise(rb_eTypeError, "%s: %s must be a Symbol (got %"PRIsVALUE")",
|
|
877
|
+
name ? name : ca_calling_method_name(), arg, rb_obj_class(v));
|
|
878
|
+
}
|
|
879
|
+
id = SYM2ID(v);
|
|
880
|
+
if ( id == rb_intern(c0) ) {
|
|
881
|
+
return 0;
|
|
882
|
+
}
|
|
883
|
+
if ( id == rb_intern(c1) ) {
|
|
884
|
+
return 1;
|
|
885
|
+
}
|
|
886
|
+
rb_raise(rb_eArgError, "%s: unknown %s :%"PRIsVALUE" (expected :%s or :%s)",
|
|
887
|
+
name ? name : ca_calling_method_name(), arg, rb_id2str(id), c0, c1);
|
|
888
|
+
return 0;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/* `fill` as a cell of `data_type` holds it: the value a store of `fill`
|
|
892
|
+
into such an array would leave. */
|
|
893
|
+
VALUE
|
|
894
|
+
ca_fill_as (VALUE fill, int8_t data_type)
|
|
895
|
+
{
|
|
896
|
+
ca_size_t dim[1] = { 1 };
|
|
897
|
+
VALUE cell = rb_carray_new(data_type, 1, dim, 0, NULL);
|
|
898
|
+
rb_ca_store_all(cell, fill);
|
|
899
|
+
return rb_ca_fetch_addr(cell, 0);
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/* The `fill_value:` of a reduction, applied to its result: the masked
|
|
903
|
+
cells of a CArray result are filled as a store would fill them, each
|
|
904
|
+
member of a two-array result (minmax) alike. `whole` says the result
|
|
905
|
+
was computed with every axis kept for a full reduction; its one cell
|
|
906
|
+
is then returned as the scalar the caller asked for. A caller passes
|
|
907
|
+
no fill for `fill_value: UNDEF`, which leaves the cells undefined. */
|
|
908
|
+
VALUE
|
|
909
|
+
ca_reduce_fill (VALUE result, VALUE fill, int whole)
|
|
910
|
+
{
|
|
911
|
+
if ( RB_TYPE_P(result, T_ARRAY) ) {
|
|
912
|
+
long i, n = RARRAY_LEN(result);
|
|
913
|
+
VALUE out = rb_ary_new_capa(n);
|
|
914
|
+
for ( i = 0; i < n; i++ ) {
|
|
915
|
+
rb_ary_push(out, ca_reduce_fill(RARRAY_AREF(result, i), fill, whole));
|
|
916
|
+
}
|
|
917
|
+
return out;
|
|
918
|
+
}
|
|
919
|
+
if ( rb_obj_is_kind_of(result, rb_cCArray) ) {
|
|
920
|
+
CArray *cr;
|
|
921
|
+
GetCArray(result, cr);
|
|
922
|
+
if ( ca_has_mask(cr) ) {
|
|
923
|
+
result = rb_ca_mask_fill_copy(result, fill);
|
|
924
|
+
}
|
|
925
|
+
return whole ? rb_ca_fetch_addr(result, 0) : result;
|
|
926
|
+
}
|
|
927
|
+
return ( result == CA_UNDEF ) ? fill : result;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/* CArray.__fill_undefined_result_cells__(result, fill_value): ca_reduce_fill for a
|
|
931
|
+
reduction written in Ruby. A fill_value of nil or UNDEF leaves the
|
|
932
|
+
undefined cells as they are. */
|
|
933
|
+
static VALUE
|
|
934
|
+
rb_ca_s_reduce_fill (VALUE klass, VALUE result, VALUE fill)
|
|
935
|
+
{
|
|
936
|
+
if ( NIL_P(fill) || fill == CA_UNDEF ) {
|
|
937
|
+
return result;
|
|
938
|
+
}
|
|
939
|
+
return ca_reduce_fill(result, fill, 0);
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
/* ca_integer_arg for an `axis` argument. */
|
|
943
|
+
long
|
|
944
|
+
ca_axis_integer (VALUE raxis, const char *name)
|
|
945
|
+
{
|
|
946
|
+
return ca_integer_arg(raxis, "axis", name);
|
|
947
|
+
}
|
|
948
|
+
|
|
485
949
|
/* Self-independent kernel: normalize `raw` against `ndim`, returning a
|
|
486
950
|
canonical non-negative axis in [0, ndim) as int. Accepts negative
|
|
487
951
|
values (Python/Ruby convention: -1 => ndim-1). Raises ArgumentError
|
|
488
952
|
if out of range. `name` is used in the error message (e.g.
|
|
489
|
-
"mask_duplicates", "sum", "merge"); pass NULL to
|
|
953
|
+
"mask_duplicates", "sum", "merge"); pass NULL to use the name of the
|
|
954
|
+
method the user called.
|
|
490
955
|
|
|
491
956
|
For an insertion position (= valid range [0, old_ndim] inclusive),
|
|
492
957
|
pass `old_ndim + 1` as `ndim` so the half-open [0, ndim) check
|
|
@@ -498,11 +963,43 @@ rb_ca_normalize_axis_for_ndim (long raw, int ndim, const char *name)
|
|
|
498
963
|
if ( axis < 0 || axis >= ndim ) {
|
|
499
964
|
rb_raise(rb_eArgError,
|
|
500
965
|
"%s: axis %ld out of range for ndim %d",
|
|
501
|
-
name ? name :
|
|
966
|
+
name ? name : ca_calling_method_name(), raw, ndim);
|
|
502
967
|
}
|
|
503
968
|
return (int) axis;
|
|
504
969
|
}
|
|
505
970
|
|
|
971
|
+
/* An array has at most CA_RANK_MAX axes, and every dim[] and strides[]
|
|
972
|
+
array in the library is that long. A constructor or view whose result
|
|
973
|
+
would have more -- a shape given, a rank computed -- calls this before it
|
|
974
|
+
writes a single dim, and is refused with ArgumentError naming the method,
|
|
975
|
+
the rank and the limit. `name` NULL names the method the user called. */
|
|
976
|
+
void
|
|
977
|
+
ca_check_rank_fits (long ndim, const char *name)
|
|
978
|
+
{
|
|
979
|
+
if ( ndim > CA_RANK_MAX ) {
|
|
980
|
+
rb_raise(rb_eArgError, "%s: ndim %ld exceeds CA_RANK_MAX %d",
|
|
981
|
+
name ? name : ca_calling_method_name(), ndim, CA_RANK_MAX);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/* The axis an `axis` argument names among `ndim` axes: the one rule every
|
|
986
|
+
entry that takes an axis from Ruby keeps. An Integer, negative counting
|
|
987
|
+
from the end; anything else raises TypeError, and an Integer outside
|
|
988
|
+
[-ndim, ndim) raises ArgumentError naming the value given -- a Bignum
|
|
989
|
+
too, since no ndim reaches it. `name` and the insertion-position use of
|
|
990
|
+
`ndim` are as for rb_ca_normalize_axis_for_ndim. */
|
|
991
|
+
int
|
|
992
|
+
ca_normalize_axis_arg (VALUE raxis, int ndim, const char *name)
|
|
993
|
+
{
|
|
994
|
+
ca_check_rank_fits(ndim, name); /* no array has the axes to name */
|
|
995
|
+
if ( RB_INTEGER_TYPE_P(raxis) && ! RB_FIXNUM_P(raxis) ) {
|
|
996
|
+
rb_raise(rb_eArgError,
|
|
997
|
+
"%s: axis %"PRIsVALUE" out of range for ndim %d",
|
|
998
|
+
name ? name : ca_calling_method_name(), raxis, ndim);
|
|
999
|
+
}
|
|
1000
|
+
return rb_ca_normalize_axis_for_ndim(ca_axis_integer(raxis, name), ndim, name);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
506
1003
|
/* Self-bound wrapper: delegate to the kernel using self.ndim. Kept
|
|
507
1004
|
for backward compatibility with the existing instance method
|
|
508
1005
|
`CArray#normalize_axis`. */
|
|
@@ -511,7 +1008,7 @@ rb_ca_normalize_axis_value (VALUE self, VALUE raxis, const char *name)
|
|
|
511
1008
|
{
|
|
512
1009
|
CArray *ca;
|
|
513
1010
|
GetCArray(self, ca);
|
|
514
|
-
return
|
|
1011
|
+
return ca_normalize_axis_arg(raxis, (int) ca->ndim, name);
|
|
515
1012
|
}
|
|
516
1013
|
|
|
517
1014
|
/* Ruby-facing `CArray#normalize_axis(axis, name=nil)` — returns the
|
|
@@ -546,7 +1043,7 @@ rb_ca_s_normalize_axis (int argc, VALUE *argv, VALUE klass)
|
|
|
546
1043
|
int k;
|
|
547
1044
|
rb_scan_args(argc, argv, "21", &raxis, &rndim, &rname);
|
|
548
1045
|
name = NIL_P(rname) ? NULL : StringValueCStr(rname);
|
|
549
|
-
k =
|
|
1046
|
+
k = ca_normalize_axis_arg(raxis, NUM2INT(rndim), name);
|
|
550
1047
|
return INT2NUM(k);
|
|
551
1048
|
}
|
|
552
1049
|
|
|
@@ -566,7 +1063,7 @@ rb_ca_normalize_axes (int argc, VALUE *argv, VALUE self)
|
|
|
566
1063
|
const char *name;
|
|
567
1064
|
|
|
568
1065
|
rb_scan_args(argc, argv, "11", &raxes, &rname);
|
|
569
|
-
name = NIL_P(rname) ?
|
|
1066
|
+
name = NIL_P(rname) ? NULL : StringValueCStr(rname); /* NULL: looked up on error */
|
|
570
1067
|
GetCArray(self, ca);
|
|
571
1068
|
|
|
572
1069
|
if ( NIL_P(raxes) ) {
|
|
@@ -585,67 +1082,6 @@ rb_ca_normalize_axes (int argc, VALUE *argv, VALUE self)
|
|
|
585
1082
|
return out;
|
|
586
1083
|
}
|
|
587
1084
|
|
|
588
|
-
/* `CArray._scan_float(str, fill_value=nil)` — parses `str` as a
|
|
589
|
-
* single double via `sscanf("%lf")`. Returns `fill_value` (or NaN
|
|
590
|
-
* when `fill_value` is nil) if `str` is nil or unparseable. Internal
|
|
591
|
-
* helper for text-format I/O readers. */
|
|
592
|
-
|
|
593
|
-
static VALUE
|
|
594
|
-
rb_ca_s_scan_float (int argc, VALUE *argv, VALUE self)
|
|
595
|
-
{
|
|
596
|
-
volatile VALUE rstr, rfval;
|
|
597
|
-
double value;
|
|
598
|
-
int count;
|
|
599
|
-
|
|
600
|
-
rb_scan_args(argc, argv, "11", (VALUE *)&rstr, (VALUE *)&rfval);
|
|
601
|
-
|
|
602
|
-
if ( NIL_P(rstr) ) {
|
|
603
|
-
return ( NIL_P(rfval) ) ? rb_float_new(0.0/0.0) : rfval;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
Check_Type(rstr, T_STRING);
|
|
607
|
-
|
|
608
|
-
count = sscanf(StringValuePtr(rstr), "%lf", &value);
|
|
609
|
-
|
|
610
|
-
if ( count == 1 ) {
|
|
611
|
-
return rb_float_new(value);
|
|
612
|
-
}
|
|
613
|
-
else {
|
|
614
|
-
return ( NIL_P(rfval) ) ? rb_float_new(0.0/0.0) : rfval;
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
/* `CArray._scan_int(str, fill_value=nil)` — parses `str` as a single
|
|
619
|
-
* integer via `sscanf("%li")` (accepts `0x`, `0`, and decimal
|
|
620
|
-
* prefixes). Returns `fill_value` (or 0 when `fill_value` is nil) if
|
|
621
|
-
* `str` is nil or unparseable. Internal helper for text-format I/O
|
|
622
|
-
* readers. */
|
|
623
|
-
|
|
624
|
-
static VALUE
|
|
625
|
-
rb_ca_s_scan_int (int argc, VALUE *argv, VALUE self)
|
|
626
|
-
{
|
|
627
|
-
volatile VALUE rstr, rfval;
|
|
628
|
-
long value;
|
|
629
|
-
int count;
|
|
630
|
-
|
|
631
|
-
rb_scan_args(argc, argv, "11", (VALUE *) &rstr, (VALUE *) &rfval);
|
|
632
|
-
|
|
633
|
-
if ( NIL_P(rstr) ) {
|
|
634
|
-
return ( NIL_P(rfval) ) ? INT2NUM(0) : rfval;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
Check_Type(rstr, T_STRING);
|
|
638
|
-
|
|
639
|
-
count = sscanf(StringValuePtr(rstr), "%li", &value);
|
|
640
|
-
|
|
641
|
-
if ( count == 1 ) {
|
|
642
|
-
return SIZE2NUM(value);
|
|
643
|
-
}
|
|
644
|
-
else {
|
|
645
|
-
return ( NIL_P(rfval) ) ? INT2NUM(0) : rfval;
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
|
|
649
1085
|
static const struct {
|
|
650
1086
|
const char *name;
|
|
651
1087
|
int data_type;
|
|
@@ -685,7 +1121,13 @@ rb_ca_guess_type (VALUE obj)
|
|
|
685
1121
|
VALUE inspect;
|
|
686
1122
|
|
|
687
1123
|
if ( TYPE(obj) == T_FIXNUM ) {
|
|
688
|
-
|
|
1124
|
+
/* Check before narrowing to int8_t, so the message names the id given. */
|
|
1125
|
+
long id = FIX2LONG(obj);
|
|
1126
|
+
if ( id <= CA_NONE || id >= CA_NTYPE ) {
|
|
1127
|
+
rb_raise(rb_eArgError, "%s: invalid data_type id %ld",
|
|
1128
|
+
ca_calling_method_name(), id);
|
|
1129
|
+
}
|
|
1130
|
+
return (int8_t) id;
|
|
689
1131
|
}
|
|
690
1132
|
else if ( TYPE(obj) == T_STRING ) {
|
|
691
1133
|
const char *name0;
|
|
@@ -701,7 +1143,7 @@ rb_ca_guess_type (VALUE obj)
|
|
|
701
1143
|
}
|
|
702
1144
|
}
|
|
703
1145
|
else if ( TYPE(obj) == T_SYMBOL ) {
|
|
704
|
-
return rb_ca_guess_type(
|
|
1146
|
+
return rb_ca_guess_type(rb_str_dup(rb_sym2str(obj)));
|
|
705
1147
|
}
|
|
706
1148
|
else if ( TYPE(obj) == T_CLASS ) {
|
|
707
1149
|
ca_check_data_class(obj);
|
|
@@ -709,8 +1151,9 @@ rb_ca_guess_type (VALUE obj)
|
|
|
709
1151
|
}
|
|
710
1152
|
|
|
711
1153
|
inspect = rb_inspect(obj);
|
|
712
|
-
rb_raise(
|
|
713
|
-
"<%s> is unknown data_type representation",
|
|
1154
|
+
rb_raise(rb_eArgError,
|
|
1155
|
+
"%s: <%s> is unknown data_type representation",
|
|
1156
|
+
ca_calling_method_name(), StringValuePtr(inspect));
|
|
714
1157
|
}
|
|
715
1158
|
|
|
716
1159
|
void
|
|
@@ -733,7 +1176,7 @@ rb_ca_guess_type_and_bytes (VALUE rtype, VALUE rbytes,
|
|
|
733
1176
|
}
|
|
734
1177
|
}
|
|
735
1178
|
else {
|
|
736
|
-
|
|
1179
|
+
CA_CHECK_DATA_TYPE_GIVEN(*data_type);
|
|
737
1180
|
*bytes = ca_sizeof[*data_type];
|
|
738
1181
|
}
|
|
739
1182
|
}
|
|
@@ -754,11 +1197,15 @@ rb_ca_s_guess_type_and_bytes (int argc, VALUE *argv, VALUE klass)
|
|
|
754
1197
|
return rb_assoc_new(INT2NUM(data_type), SIZE2NUM(bytes));
|
|
755
1198
|
}
|
|
756
1199
|
|
|
1200
|
+
/* Takes the trailing keyword Hash off argv when the caller passed keywords.
|
|
1201
|
+
A Hash passed as a positional argument (`f({axis: 0})`) stays an argument,
|
|
1202
|
+
as in Ruby 3: it may be a value, such as a cell of an object array. */
|
|
757
1203
|
VALUE
|
|
758
1204
|
rb_pop_options (int *argc, VALUE **argv)
|
|
759
1205
|
{
|
|
760
1206
|
VALUE ropt;
|
|
761
|
-
if ( ( *argc > 0 ) && (
|
|
1207
|
+
if ( ( *argc > 0 ) && rb_keyword_given_p() &&
|
|
1208
|
+
( TYPE( (*argv)[*argc-1] ) == T_HASH ) ) {
|
|
762
1209
|
ropt = (*argv)[*argc-1];
|
|
763
1210
|
(*argc) -= 1;
|
|
764
1211
|
}
|
|
@@ -925,18 +1372,29 @@ rb_set_options (VALUE ropt, const char *spec_in, ...)
|
|
|
925
1372
|
}
|
|
926
1373
|
|
|
927
1374
|
|
|
1375
|
+
/* Whether this runs in the main Ractor: Init does, and leaves a value in
|
|
1376
|
+
its Ractor-local storage that no other Ractor has. */
|
|
1377
|
+
static rb_ractor_local_key_t ca_main_ractor_key;
|
|
1378
|
+
|
|
1379
|
+
int
|
|
1380
|
+
ca_in_main_ractor (void)
|
|
1381
|
+
{
|
|
1382
|
+
VALUE mark;
|
|
1383
|
+
return rb_ractor_local_storage_value_lookup(ca_main_ractor_key, &mark);
|
|
1384
|
+
}
|
|
1385
|
+
|
|
928
1386
|
void
|
|
929
1387
|
Init_carray_utils (void)
|
|
930
1388
|
{
|
|
1389
|
+
ca_main_ractor_key = rb_ractor_local_storage_value_newkey();
|
|
1390
|
+
rb_ractor_local_storage_value_set(ca_main_ractor_key, Qtrue);
|
|
1391
|
+
ca_id_names = st_init_numtable();
|
|
1392
|
+
rb_nativethread_lock_initialize(&ca_id_names_lock);
|
|
1393
|
+
id_answering = rb_intern("__carray_answering_method__");
|
|
931
1394
|
id_begin = rb_intern("begin");
|
|
932
1395
|
id_end = rb_intern("end");
|
|
933
1396
|
id_excl_end = rb_intern("exclude_end?");
|
|
934
1397
|
|
|
935
|
-
rb_define_singleton_method(rb_cCArray, "_scan_float",
|
|
936
|
-
rb_ca_s_scan_float, -1);
|
|
937
|
-
rb_define_singleton_method(rb_cCArray, "_scan_int",
|
|
938
|
-
rb_ca_s_scan_int, -1);
|
|
939
|
-
|
|
940
1398
|
rb_define_singleton_method(rb_cCArray, "guess_type_and_bytes",
|
|
941
1399
|
rb_ca_s_guess_type_and_bytes, -1);
|
|
942
1400
|
|
|
@@ -944,6 +1402,14 @@ Init_carray_utils (void)
|
|
|
944
1402
|
rb_define_method(rb_cCArray, "normalize_axes", rb_ca_normalize_axes, -1);
|
|
945
1403
|
rb_define_singleton_method(rb_cCArray, "normalize_axis",
|
|
946
1404
|
rb_ca_s_normalize_axis, -1);
|
|
1405
|
+
rb_define_singleton_method(rb_cCArray, "__present_cells_needed_per_result_cell__",
|
|
1406
|
+
rb_ca_s_min_count_need, 3);
|
|
1407
|
+
rb_define_singleton_method(rb_cCArray, "__fill_undefined_result_cells__",
|
|
1408
|
+
rb_ca_s_reduce_fill, 2);
|
|
1409
|
+
rb_define_private_method(rb_singleton_class(rb_cCArray), "library_root=",
|
|
1410
|
+
rb_ca_s_set_library_root, 1);
|
|
1411
|
+
rb_define_singleton_method(rb_cCArray, "__name_errors_after_method__",
|
|
1412
|
+
rb_ca_s_answer_as, 1);
|
|
947
1413
|
|
|
948
1414
|
}
|
|
949
1415
|
|