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.
Files changed (247) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +568 -0
  3. data/README.md +6 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +220 -0
  7. data/ext/ca_axis_group.c +201 -123
  8. data/ext/ca_binop_dispatch.c +46 -52
  9. data/ext/ca_binop_dispatch.h +1 -1
  10. data/ext/ca_categorical_iterator.c +249 -183
  11. data/ext/ca_compare.c +7 -12
  12. data/ext/ca_for_buffer.h +21 -68
  13. data/ext/ca_group_iter.c +38 -23
  14. data/ext/ca_kernel_iterator.c +1765 -2076
  15. data/ext/ca_kernel_iterator.h +584 -566
  16. data/ext/ca_monop_dispatch.c +86 -63
  17. data/ext/ca_monop_dispatch.h +5 -0
  18. data/ext/ca_obj_array.c +223 -56
  19. data/ext/ca_obj_bincmp.c +172 -138
  20. data/ext/ca_obj_binop.c +116 -230
  21. data/ext/ca_obj_bitarray.c +40 -26
  22. data/ext/ca_obj_bitfield.c +100 -68
  23. data/ext/ca_obj_block.c +19 -9
  24. data/ext/ca_obj_byte_swap.c +45 -46
  25. data/ext/ca_obj_const_string.c +269 -44
  26. data/ext/ca_obj_face.c +612 -89
  27. data/ext/ca_obj_face.h +111 -47
  28. data/ext/ca_obj_fake.c +36 -79
  29. data/ext/ca_obj_farray.c +7 -3
  30. data/ext/ca_obj_field.c +33 -8
  31. data/ext/ca_obj_fixlen_string.c +23 -24
  32. data/ext/ca_obj_grid.c +541 -210
  33. data/ext/ca_obj_meld.c +331 -111
  34. data/ext/ca_obj_moncmp.c +80 -65
  35. data/ext/ca_obj_monop.c +177 -149
  36. data/ext/ca_obj_object.c +664 -248
  37. data/ext/ca_obj_record.c +63 -23
  38. data/ext/ca_obj_reduce.c +18 -16
  39. data/ext/ca_obj_refer.c +140 -58
  40. data/ext/ca_obj_remap.c +85 -24
  41. data/ext/ca_obj_repeat.c +24 -9
  42. data/ext/ca_obj_roll.c +121 -16
  43. data/ext/ca_obj_select.c +61 -58
  44. data/ext/ca_obj_select_axis.c +73 -107
  45. data/ext/ca_obj_shift.c +32 -102
  46. data/ext/ca_obj_stack.c +372 -122
  47. data/ext/ca_obj_stride.c +348 -140
  48. data/ext/ca_obj_string.c +88 -22
  49. data/ext/ca_obj_tile.c +38 -21
  50. data/ext/ca_obj_time.c +45 -31
  51. data/ext/ca_obj_timedelta.c +43 -29
  52. data/ext/ca_obj_transpose.c +17 -6
  53. data/ext/ca_obj_triop.c +125 -141
  54. data/ext/ca_obj_window.c +330 -44
  55. data/ext/ca_op_ipower.c +24 -11
  56. data/ext/ca_op_powi.h +57 -30
  57. data/ext/ca_pow5_table.h +656 -0
  58. data/ext/ca_sort_kernels.h +70 -0
  59. data/ext/ca_sweep_engine.c +104 -81
  60. data/ext/ca_sweep_engine.h +7 -20
  61. data/ext/ca_triop_dispatch.c +4 -1
  62. data/ext/ca_triop_dispatch.h +5 -2
  63. data/ext/caframe_csv_reader.c +542 -0
  64. data/ext/carray.h +241 -92
  65. data/ext/carray_access.c +608 -276
  66. data/ext/carray_address_basis.c +494 -97
  67. data/ext/carray_attribute.c +129 -4
  68. data/ext/carray_bincount.c +39 -7
  69. data/ext/carray_broadcast.c +56 -19
  70. data/ext/carray_build_flags.h +1 -1
  71. data/ext/carray_call_cfunc.c +108 -28
  72. data/ext/carray_cast.c +1576 -223
  73. data/ext/carray_cast_func.rb +77 -24
  74. data/ext/carray_class.c +4 -3
  75. data/ext/carray_conversion.c +208 -75
  76. data/ext/carray_copy.c +82 -24
  77. data/ext/carray_core.c +646 -162
  78. data/ext/carray_count.c +171 -88
  79. data/ext/carray_element.c +94 -60
  80. data/ext/carray_factorize.c +670 -324
  81. data/ext/carray_generate.c +260 -83
  82. data/ext/carray_histogram.c +209 -106
  83. data/ext/carray_hold.c +14 -16
  84. data/ext/carray_index_classifier.c +422 -243
  85. data/ext/carray_internal.h +692 -3
  86. data/ext/carray_kernels_bincmp.c +7 -0
  87. data/ext/carray_kernels_binop.c +487 -120
  88. data/ext/carray_kernels_init.c +653 -50
  89. data/ext/carray_kernels_moncmp.c +15 -8
  90. data/ext/carray_kernels_monop.c +99 -43
  91. data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
  92. data/ext/carray_kernels_reduce_boolean.c +112 -36
  93. data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
  94. data/ext/carray_kernels_reduce_extreme.c +3032 -2892
  95. data/ext/carray_kernels_reduce_variance.c +439 -500
  96. data/ext/carray_kernels_scan.c +1097 -488
  97. data/ext/carray_kernels_search.c +3787 -2176
  98. data/ext/carray_kernels_sort.c +1200 -920
  99. data/ext/carray_kernels_triop.c +479 -7
  100. data/ext/carray_key_windows.c +216 -0
  101. data/ext/carray_lazy.c +967 -153
  102. data/ext/carray_loop.c +81 -65
  103. data/ext/carray_mask.c +910 -324
  104. data/ext/carray_math_kernel.h +1 -0
  105. data/ext/carray_median_percentile.c +299 -100
  106. data/ext/carray_memory_view.c +872 -758
  107. data/ext/carray_operator.c +1171 -364
  108. data/ext/carray_order.c +505 -133
  109. data/ext/carray_partition.c +112 -65
  110. data/ext/carray_random.c +327 -239
  111. data/ext/carray_round.c +273 -0
  112. data/ext/carray_scatter.c +346 -78
  113. data/ext/carray_segment.c +257 -0
  114. data/ext/carray_slab.c +249 -86
  115. data/ext/carray_sort.c +224 -227
  116. data/ext/carray_sort_kernel.c +8 -1
  117. data/ext/carray_struct.c +118 -39
  118. data/ext/carray_test.c +193 -69
  119. data/ext/carray_time_text.c +1182 -0
  120. data/ext/carray_undef.c +4 -0
  121. data/ext/carray_utils.c +579 -113
  122. data/ext/extconf.rb +27 -2
  123. data/ext/mk_call_cfunc.rb +19 -4
  124. data/ext/mk_pow5_table.rb +35 -0
  125. data/ext/mkkernel.rb +1202 -1014
  126. data/ext/ruby_carray.c +17 -5
  127. data/ext/version.h +4 -4
  128. data/ext/version.rb +4 -2
  129. data/lib/carray/attribute.rb +160 -17
  130. data/lib/carray/autoload_carray.rb +23 -27
  131. data/lib/carray/autoload_method_extension.rb +20 -5
  132. data/lib/carray/axis_group.rb +360 -63
  133. data/lib/carray/basics.rb +162 -28
  134. data/lib/carray/bincount_nd.rb +18 -2
  135. data/lib/carray/block_iterator.rb +231 -58
  136. data/lib/carray/boolean_reduce.rb +34 -42
  137. data/lib/carray/categorical.rb +242 -52
  138. data/lib/carray/categorical_iterator.rb +437 -827
  139. data/lib/carray/complex.rb +41 -34
  140. data/lib/carray/conditional.rb +150 -14
  141. data/lib/carray/const_string.rb +59 -4
  142. data/lib/carray/construct.rb +15 -11
  143. data/lib/carray/data_type_extension.rb +1 -0
  144. data/lib/carray/distance_limit.rb +77 -0
  145. data/lib/carray/fixlen_string.rb +7 -1
  146. data/lib/carray/frame/column_verbs.rb +70 -0
  147. data/lib/carray/frame/concat.rb +157 -6
  148. data/lib/carray/frame/convert.rb +82 -7
  149. data/lib/carray/frame/csv_parser.rb +688 -87
  150. data/lib/carray/frame/describe.rb +80 -0
  151. data/lib/carray/frame/frame.rb +369 -45
  152. data/lib/carray/frame/group.rb +631 -90
  153. data/lib/carray/frame/io.rb +506 -79
  154. data/lib/carray/frame/join.rb +411 -62
  155. data/lib/carray/frame/records.rb +116 -19
  156. data/lib/carray/frame/reshape.rb +455 -0
  157. data/lib/carray/frame/sort.rb +30 -18
  158. data/lib/carray/frame/verbs.rb +868 -61
  159. data/lib/carray/frame/windows.rb +117 -0
  160. data/lib/carray/frame.rb +4 -0
  161. data/lib/carray/fuse_source.rb +118 -2
  162. data/lib/carray/fusion.rb +257 -42
  163. data/lib/carray/histogram.rb +6 -1
  164. data/lib/carray/inspect.rb +54 -13
  165. data/lib/carray/iterator.rb +99 -9
  166. data/lib/carray/key_windows.rb +620 -0
  167. data/lib/carray/lazy.rb +216 -193
  168. data/lib/carray/mask_gap_fill.rb +112 -92
  169. data/lib/carray/math.rb +32 -19
  170. data/lib/carray/meld_reduce.rb +52 -21
  171. data/lib/carray/methods/align_addr.rb +8 -4
  172. data/lib/carray/methods/bin.rb +26 -18
  173. data/lib/carray/methods/bincount.rb +18 -2
  174. data/lib/carray/methods/bit_string.rb +15 -4
  175. data/lib/carray/methods/choose.rb +16 -3
  176. data/lib/carray/methods/composition.rb +18 -10
  177. data/lib/carray/methods/factorize.rb +2 -2
  178. data/lib/carray/methods/gather_nd.rb +25 -5
  179. data/lib/carray/methods/insert_block.rb +9 -14
  180. data/lib/carray/methods/is_between.rb +59 -0
  181. data/lib/carray/methods/is_in.rb +140 -10
  182. data/lib/carray/methods/join.rb +2 -7
  183. data/lib/carray/methods/lag.rb +49 -0
  184. data/lib/carray/methods/locate_addr.rb +182 -45
  185. data/lib/carray/methods/mode.rb +18 -1
  186. data/lib/carray/methods/nunique.rb +11 -6
  187. data/lib/carray/methods/repeat.rb +1 -20
  188. data/lib/carray/methods/resize.rb +21 -23
  189. data/lib/carray/methods/snap.rb +34 -12
  190. data/lib/carray/methods/unique.rb +11 -2
  191. data/lib/carray/methods/value_counts.rb +4 -11
  192. data/lib/carray/record_order.rb +208 -0
  193. data/lib/carray/rng.rb +3 -0
  194. data/lib/carray/runtime.rb +65 -17
  195. data/lib/carray/segment_iterator.rb +1221 -0
  196. data/lib/carray/serialize.rb +214 -30
  197. data/lib/carray/slab_iterator.rb +101 -27
  198. data/lib/carray/stack.rb +10 -4
  199. data/lib/carray/string.rb +105 -5
  200. data/lib/carray/string_operation_extension.rb +12 -4
  201. data/lib/carray/struct.rb +137 -58
  202. data/lib/carray/struct_builder.rb +124 -17
  203. data/lib/carray/time.rb +1222 -186
  204. data/lib/carray/window_iterator.rb +242 -81
  205. data/lib/carray.rb +9 -2
  206. data/yard-stubs/ca_obj_array.rb +4 -4
  207. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  208. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  209. data/yard-stubs/ca_obj_fake.rb +1 -1
  210. data/yard-stubs/ca_obj_field.rb +5 -1
  211. data/yard-stubs/ca_obj_grid.rb +21 -10
  212. data/yard-stubs/ca_obj_refer.rb +5 -4
  213. data/yard-stubs/ca_obj_roll.rb +2 -3
  214. data/yard-stubs/ca_obj_shift.rb +5 -1
  215. data/yard-stubs/ca_obj_stride.rb +10 -7
  216. data/yard-stubs/ca_obj_tile.rb +1 -1
  217. data/yard-stubs/ca_obj_transpose.rb +1 -1
  218. data/yard-stubs/ca_obj_window.rb +9 -5
  219. data/yard-stubs/carray_access.rb +11 -5
  220. data/yard-stubs/carray_attribute.rb +0 -5
  221. data/yard-stubs/carray_broadcast.rb +1 -1
  222. data/yard-stubs/carray_cast.rb +88 -43
  223. data/yard-stubs/carray_conversion.rb +15 -2
  224. data/yard-stubs/carray_copy.rb +12 -5
  225. data/yard-stubs/carray_core.rb +3 -3
  226. data/yard-stubs/carray_count.rb +9 -0
  227. data/yard-stubs/carray_element.rb +10 -4
  228. data/yard-stubs/carray_generate.rb +21 -1
  229. data/yard-stubs/carray_lazy.rb +5 -1
  230. data/yard-stubs/carray_loop.rb +4 -1
  231. data/yard-stubs/carray_mask.rb +60 -12
  232. data/yard-stubs/carray_math.rb +52 -14
  233. data/yard-stubs/carray_median_percentile.rb +15 -8
  234. data/yard-stubs/carray_memory_view.rb +40 -23
  235. data/yard-stubs/carray_order.rb +61 -29
  236. data/yard-stubs/carray_random.rb +13 -4
  237. data/yard-stubs/carray_scatter.rb +21 -9
  238. data/yard-stubs/carray_segment.rb +72 -0
  239. data/yard-stubs/carray_slab.rb +10 -2
  240. data/yard-stubs/carray_sort.rb +49 -8
  241. data/yard-stubs/carray_test.rb +15 -3
  242. data/yard-stubs/carray_utils.rb +0 -26
  243. metadata +19 -5
  244. data/ext/ca_for_each_element.h +0 -239
  245. data/ext/carray_kernels_map.c +0 -3467
  246. data/lib/carray/arrow_tensor.rb +0 -401
  247. 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`), and text-scan helpers
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(rb_eRuntimeError, "data size mismatch in operation");
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(rb_eRuntimeError, "no data to process");
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
- rb_raise(rb_eIndexError,
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(rb_eRuntimeError, "step should not be 0");
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
- rb_raise(rb_eIndexError, "index out of range");
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
- CA_CHECK_INDEX(bound, size);
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(rb_eRuntimeError, "step should not be 0");
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
- CA_CHECK_INDEX(start, size);
215
- CA_CHECK_INDEX(bound, size);
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(rb_eRuntimeError, "step should not be 0");
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
- rb_raise(rb_eIndexError, "index out of range");
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
- CA_CHECK_INDEX(bound, size);
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(rb_eRuntimeError, "step should not be 0");
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
- rb_raise(rb_eIndexError, "index out of range");
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
- CA_CHECK_INDEX(bound, size);
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
- CA_CHECK_INDEX(bound, size);
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(rb_eRuntimeError, "step should not be 0");
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
- CA_CHECK_INDEX(bound, size);
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(rb_eRuntimeError, "unknown range specification");
325
+ rb_raise(rb_eArgError, "unknown range specification");
312
326
  }
313
327
  }
314
328
  else {
315
- rb_raise(rb_eRuntimeError, "unknown range specification");
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(rb_eRuntimeError, "unknown range specification");
447
+ rb_raise(rb_eArgError, "unknown range specification");
434
448
  }
435
449
  }
436
450
  else {
437
- rb_raise(rb_eRuntimeError, "unknown range specification");
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
- rb_raise(rb_eRuntimeError,
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
- rb_raise(rb_eRuntimeError,
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(rb_eRuntimeError,
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 default to "axis".
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 : "axis", raw, ndim);
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 rb_ca_normalize_axis_for_ndim(NUM2LONG(raxis), (int) ca->ndim, name);
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 = rb_ca_normalize_axis_for_ndim(NUM2LONG(raxis), NUM2INT(rndim), name);
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) ? "axes" : StringValueCStr(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
- return NUM2SIZE(obj);
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(rb_str_new2(rb_id2name(SYM2ID(obj))));
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(rb_eRuntimeError,
713
- "<%s> is unknown data_type representation", StringValuePtr(inspect));
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
- CA_CHECK_DATA_TYPE(*data_type);
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 ) && ( TYPE( (*argv)[*argc-1] ) == T_HASH ) ) {
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