carray 3.0.2 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +304 -0
  3. data/README.md +3 -4
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +225 -0
  6. data/ext/ca_axis_group.c +177 -99
  7. data/ext/ca_binop_dispatch.c +54 -32
  8. data/ext/ca_binop_dispatch.h +1 -0
  9. data/ext/ca_categorical_iterator.c +66 -71
  10. data/ext/ca_compare.c +8 -2
  11. data/ext/ca_for_buffer.h +21 -68
  12. data/ext/ca_group_iter.c +27 -11
  13. data/ext/ca_kernel_iterator.c +663 -214
  14. data/ext/ca_kernel_iterator.h +231 -167
  15. data/ext/ca_monop_dispatch.c +4 -4
  16. data/ext/ca_monop_dispatch.h +4 -0
  17. data/ext/ca_obj_array.c +132 -22
  18. data/ext/ca_obj_bincmp.c +152 -121
  19. data/ext/ca_obj_binop.c +107 -210
  20. data/ext/ca_obj_bitarray.c +37 -24
  21. data/ext/ca_obj_bitfield.c +95 -62
  22. data/ext/ca_obj_block.c +1 -0
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +96 -25
  25. data/ext/ca_obj_face.c +406 -64
  26. data/ext/ca_obj_face.h +92 -47
  27. data/ext/ca_obj_fake.c +21 -50
  28. data/ext/ca_obj_farray.c +1 -0
  29. data/ext/ca_obj_field.c +16 -3
  30. data/ext/ca_obj_fixlen_string.c +21 -21
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +189 -107
  33. data/ext/ca_obj_moncmp.c +61 -61
  34. data/ext/ca_obj_monop.c +125 -107
  35. data/ext/ca_obj_object.c +543 -233
  36. data/ext/ca_obj_record.c +51 -16
  37. data/ext/ca_obj_reduce.c +5 -8
  38. data/ext/ca_obj_refer.c +117 -33
  39. data/ext/ca_obj_remap.c +57 -17
  40. data/ext/ca_obj_repeat.c +21 -5
  41. data/ext/ca_obj_roll.c +115 -11
  42. data/ext/ca_obj_select.c +47 -49
  43. data/ext/ca_obj_select_axis.c +58 -60
  44. data/ext/ca_obj_shift.c +22 -102
  45. data/ext/ca_obj_stack.c +223 -118
  46. data/ext/ca_obj_stride.c +195 -34
  47. data/ext/ca_obj_string.c +17 -18
  48. data/ext/ca_obj_tile.c +32 -16
  49. data/ext/ca_obj_time.c +23 -25
  50. data/ext/ca_obj_timedelta.c +21 -23
  51. data/ext/ca_obj_transpose.c +12 -3
  52. data/ext/ca_obj_triop.c +110 -117
  53. data/ext/ca_obj_window.c +149 -27
  54. data/ext/ca_op_ipower.c +24 -11
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_sort_kernels.h +70 -0
  58. data/ext/ca_sweep_engine.c +102 -79
  59. data/ext/ca_sweep_engine.h +7 -20
  60. data/ext/ca_triop_dispatch.c +4 -1
  61. data/ext/ca_triop_dispatch.h +5 -2
  62. data/ext/caframe_csv_reader.c +463 -0
  63. data/ext/carray.h +70 -27
  64. data/ext/carray_access.c +455 -211
  65. data/ext/carray_address_basis.c +177 -36
  66. data/ext/carray_attribute.c +45 -3
  67. data/ext/carray_bincount.c +32 -2
  68. data/ext/carray_broadcast.c +46 -14
  69. data/ext/carray_call_cfunc.c +0 -28
  70. data/ext/carray_cast.c +1444 -209
  71. data/ext/carray_cast_func.rb +34 -21
  72. data/ext/carray_conversion.c +197 -73
  73. data/ext/carray_copy.c +32 -11
  74. data/ext/carray_core.c +514 -122
  75. data/ext/carray_count.c +140 -87
  76. data/ext/carray_element.c +18 -27
  77. data/ext/carray_factorize.c +569 -277
  78. data/ext/carray_generate.c +76 -40
  79. data/ext/carray_histogram.c +152 -94
  80. data/ext/carray_hold.c +2 -1
  81. data/ext/carray_index_classifier.c +63 -96
  82. data/ext/carray_internal.h +385 -3
  83. data/ext/carray_lazy.c +834 -79
  84. data/ext/carray_loop.c +81 -65
  85. data/ext/carray_mask.c +682 -316
  86. data/ext/carray_math_kernel.h +1 -0
  87. data/ext/carray_median_percentile.c +221 -76
  88. data/ext/carray_memory_view.c +254 -248
  89. data/ext/carray_operator.c +1089 -359
  90. data/ext/carray_order.c +133 -69
  91. data/ext/carray_partition.c +102 -56
  92. data/ext/carray_random.c +273 -239
  93. data/ext/carray_scatter.c +308 -65
  94. data/ext/carray_segment.c +257 -0
  95. data/ext/carray_slab.c +170 -70
  96. data/ext/carray_sort.c +215 -218
  97. data/ext/carray_sort_kernel.c +8 -1
  98. data/ext/carray_struct.c +99 -21
  99. data/ext/carray_test.c +167 -64
  100. data/ext/carray_time_text.c +1182 -0
  101. data/ext/carray_utils.c +363 -98
  102. data/ext/extconf.rb +27 -2
  103. data/ext/mk_call_cfunc.rb +0 -2
  104. data/ext/mk_pow5_table.rb +35 -0
  105. data/ext/mkkernel.rb +1076 -846
  106. data/ext/ruby_carray.c +7 -1
  107. data/ext/version.h +4 -4
  108. data/ext/version.rb +4 -2
  109. data/lib/carray/attribute.rb +39 -0
  110. data/lib/carray/autoload_carray.rb +19 -0
  111. data/lib/carray/autoload_method_extension.rb +6 -0
  112. data/lib/carray/axis_group.rb +174 -26
  113. data/lib/carray/basics.rb +91 -25
  114. data/lib/carray/bincount_nd.rb +6 -0
  115. data/lib/carray/block_iterator.rb +118 -48
  116. data/lib/carray/boolean_reduce.rb +21 -29
  117. data/lib/carray/categorical.rb +94 -26
  118. data/lib/carray/categorical_iterator.rb +333 -826
  119. data/lib/carray/complex.rb +36 -29
  120. data/lib/carray/conditional.rb +94 -7
  121. data/lib/carray/const_string.rb +46 -0
  122. data/lib/carray/frame/concat.rb +157 -6
  123. data/lib/carray/frame/convert.rb +13 -7
  124. data/lib/carray/frame/csv_parser.rb +589 -82
  125. data/lib/carray/frame/describe.rb +79 -0
  126. data/lib/carray/frame/frame.rb +124 -25
  127. data/lib/carray/frame/group.rb +189 -63
  128. data/lib/carray/frame/io.rb +412 -72
  129. data/lib/carray/frame/join.rb +134 -46
  130. data/lib/carray/frame/records.rb +37 -16
  131. data/lib/carray/frame/reshape.rb +448 -0
  132. data/lib/carray/frame/sort.rb +26 -2
  133. data/lib/carray/frame/verbs.rb +715 -48
  134. data/lib/carray/frame.rb +2 -0
  135. data/lib/carray/fuse_source.rb +111 -2
  136. data/lib/carray/fusion.rb +229 -38
  137. data/lib/carray/inspect.rb +29 -11
  138. data/lib/carray/iterator.rb +14 -2
  139. data/lib/carray/lazy.rb +54 -30
  140. data/lib/carray/mask_gap_fill.rb +66 -52
  141. data/lib/carray/math.rb +32 -19
  142. data/lib/carray/meld_reduce.rb +40 -7
  143. data/lib/carray/methods/align_addr.rb +8 -4
  144. data/lib/carray/methods/bincount.rb +2 -2
  145. data/lib/carray/methods/bit_string.rb +14 -3
  146. data/lib/carray/methods/composition.rb +16 -10
  147. data/lib/carray/methods/factorize.rb +2 -2
  148. data/lib/carray/methods/gather_nd.rb +13 -2
  149. data/lib/carray/methods/insert_block.rb +9 -14
  150. data/lib/carray/methods/is_in.rb +117 -4
  151. data/lib/carray/methods/join.rb +1 -1
  152. data/lib/carray/methods/locate_addr.rb +177 -36
  153. data/lib/carray/methods/mode.rb +18 -1
  154. data/lib/carray/methods/repeat.rb +1 -20
  155. data/lib/carray/methods/resize.rb +21 -23
  156. data/lib/carray/methods/snap.rb +34 -12
  157. data/lib/carray/methods/unique.rb +11 -2
  158. data/lib/carray/record_order.rb +208 -0
  159. data/lib/carray/runtime.rb +14 -11
  160. data/lib/carray/segment_iterator.rb +990 -0
  161. data/lib/carray/serialize.rb +197 -27
  162. data/lib/carray/slab_iterator.rb +51 -27
  163. data/lib/carray/stack.rb +10 -4
  164. data/lib/carray/string_operation_extension.rb +4 -3
  165. data/lib/carray/struct.rb +142 -51
  166. data/lib/carray/struct_builder.rb +110 -14
  167. data/lib/carray/table.rb +2 -2
  168. data/lib/carray/time.rb +517 -103
  169. data/lib/carray/window_iterator.rb +127 -72
  170. data/lib/carray.rb +2 -2
  171. data/yard-stubs/ca_obj_array.rb +4 -4
  172. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  173. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  174. data/yard-stubs/ca_obj_fake.rb +1 -1
  175. data/yard-stubs/ca_obj_field.rb +1 -1
  176. data/yard-stubs/ca_obj_refer.rb +3 -3
  177. data/yard-stubs/ca_obj_roll.rb +0 -1
  178. data/yard-stubs/ca_obj_stride.rb +10 -7
  179. data/yard-stubs/ca_obj_transpose.rb +1 -1
  180. data/yard-stubs/ca_obj_window.rb +1 -2
  181. data/yard-stubs/carray_access.rb +5 -4
  182. data/yard-stubs/carray_broadcast.rb +1 -1
  183. data/yard-stubs/carray_cast.rb +78 -43
  184. data/yard-stubs/carray_conversion.rb +13 -1
  185. data/yard-stubs/carray_copy.rb +8 -3
  186. data/yard-stubs/carray_core.rb +3 -3
  187. data/yard-stubs/carray_count.rb +9 -0
  188. data/yard-stubs/carray_lazy.rb +5 -1
  189. data/yard-stubs/carray_loop.rb +4 -1
  190. data/yard-stubs/carray_mask.rb +34 -10
  191. data/yard-stubs/carray_math.rb +25 -13
  192. data/yard-stubs/carray_median_percentile.rb +10 -6
  193. data/yard-stubs/carray_order.rb +34 -13
  194. data/yard-stubs/carray_scatter.rb +10 -3
  195. data/yard-stubs/carray_segment.rb +72 -0
  196. data/yard-stubs/carray_slab.rb +2 -1
  197. data/yard-stubs/carray_sort.rb +43 -3
  198. data/yard-stubs/carray_test.rb +10 -0
  199. data/yard-stubs/carray_utils.rb +0 -26
  200. metadata +11 -19
  201. data/ext/ca_for_each_element.h +0 -239
  202. data/ext/carray_build_flags.h +0 -3
  203. data/ext/carray_config.h +0 -28
  204. data/ext/carray_kernels_bincmp.c +0 -4446
  205. data/ext/carray_kernels_binop.c +0 -11001
  206. data/ext/carray_kernels_init.c +0 -1131
  207. data/ext/carray_kernels_map.c +0 -3467
  208. data/ext/carray_kernels_moncmp.c +0 -2097
  209. data/ext/carray_kernels_monop.c +0 -18313
  210. data/ext/carray_kernels_reduce_aggregate.c +0 -26005
  211. data/ext/carray_kernels_reduce_boolean.c +0 -330
  212. data/ext/carray_kernels_reduce_cumulative.c +0 -14862
  213. data/ext/carray_kernels_reduce_extreme.c +0 -17494
  214. data/ext/carray_kernels_reduce_variance.c +0 -3910
  215. data/ext/carray_kernels_scan.c +0 -3693
  216. data/ext/carray_kernels_search.c +0 -32218
  217. data/ext/carray_kernels_sort.c +0 -10626
  218. data/ext/carray_kernels_triop.c +0 -1392
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,10 @@
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"
19
20
 
20
21
  static ID id_begin, id_end, id_excl_end;
21
22
  #define RANGE_BEG(r) (rb_funcall(r, id_begin, 0))
@@ -55,7 +56,7 @@ ca_set_iterator (int n, ...)
55
56
  max = ca->elements;
56
57
  }
57
58
  else if ( max != ca->elements ) {
58
- rb_raise(rb_eRuntimeError, "data size mismatch in operation");
59
+ rb_raise(rb_eArgError, "data size mismatch in operation");
59
60
  }
60
61
  }
61
62
  }
@@ -94,7 +95,7 @@ ca_get_loop_count (int n, ...)
94
95
  }
95
96
 
96
97
  if ( elements == -1 ) {
97
- rb_raise(rb_eRuntimeError, "no data to process");
98
+ rb_raise(rb_eArgError, "no data to process");
98
99
  }
99
100
  return elements;
100
101
  }
@@ -153,8 +154,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
153
154
  last += ( (last>=start) ? -1 : 1 );
154
155
  }
155
156
  if ( last < 0 || last >= size ) {
156
- rb_raise(rb_eIndexError,
157
- "invalid index range");
157
+ ca_index_out_of_range(last, size, "index");
158
158
  }
159
159
  *poffset = start;
160
160
  *pcount = llabs(last - start) + 1;
@@ -170,7 +170,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
170
170
  excl = RTEST(x.exclude_end);
171
171
  step = NUM2SIZE(x.step);
172
172
  if ( step == 0 ) {
173
- rb_raise(rb_eRuntimeError, "step should not be 0");
173
+ rb_raise(rb_eArgError, "step should not be 0");
174
174
  }
175
175
  if ( last < 0 ) {
176
176
  last += size;
@@ -179,7 +179,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
179
179
  last += ( (last>=start) ? -1 : 1 );
180
180
  }
181
181
  if ( last < 0 || last >= size ) {
182
- rb_raise(rb_eIndexError, "index out of range");
182
+ ca_index_out_of_range(last, size, "index");
183
183
  }
184
184
  CA_CHECK_INDEX(start, size);
185
185
  if ( (last - start) * step < 0 ) {
@@ -206,7 +206,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
206
206
  if ( NIL_P(arg0) ) { /* [nil,k] */
207
207
  step = NUM2SIZE(arg1);
208
208
  if ( step == 0 ) {
209
- rb_raise(rb_eRuntimeError, "step should not be 0");
209
+ rb_raise(rb_eArgError, "step should not be 0");
210
210
  }
211
211
  start = 0;
212
212
  count = (size-1)/llabs(step) + 1;
@@ -223,7 +223,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
223
223
  excl = RTEST(RANGE_EXCL(arg0));
224
224
  step = NUM2SIZE(arg1);
225
225
  if ( step == 0 ) {
226
- rb_raise(rb_eRuntimeError, "step should not be 0");
226
+ rb_raise(rb_eArgError, "step should not be 0");
227
227
  }
228
228
  if ( last < 0 ) {
229
229
  last += size;
@@ -232,7 +232,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
232
232
  last += ( (last>=start) ? -1 : 1 );
233
233
  }
234
234
  if ( last < 0 || last >= size ) {
235
- rb_raise(rb_eIndexError, "index out of range");
235
+ ca_index_out_of_range(last, size, "index");
236
236
  }
237
237
  CA_CHECK_INDEX(start, size);
238
238
  if ( (last - start) * step < 0 ) {
@@ -257,7 +257,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
257
257
  excl = RTEST(x.exclude_end);
258
258
  step = NUM2SIZE(x.step);
259
259
  if ( step == 0 ) {
260
- rb_raise(rb_eRuntimeError, "step should not be 0");
260
+ rb_raise(rb_eArgError, "step should not be 0");
261
261
  }
262
262
  if ( last < 0 ) {
263
263
  last += size;
@@ -266,7 +266,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
266
266
  last += ( (last>=start) ? -1 : 1 );
267
267
  }
268
268
  if ( last < 0 || last >= size ) {
269
- rb_raise(rb_eIndexError, "index out of range");
269
+ ca_index_out_of_range(last, size, "index");
270
270
  }
271
271
  CA_CHECK_INDEX(start, size);
272
272
  if ( (last - start) * step < 0 ) {
@@ -298,7 +298,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
298
298
  count = NUM2SIZE(rb_ary_entry(arg, 1));
299
299
  step = NUM2SIZE(rb_ary_entry(arg, 2));
300
300
  if ( step == 0 ) {
301
- rb_raise(rb_eRuntimeError, "step should not be 0");
301
+ rb_raise(rb_eArgError, "step should not be 0");
302
302
  }
303
303
  bound = start + (count - 1)*step;
304
304
  CA_CHECK_INDEX(start, size);
@@ -308,11 +308,11 @@ ca_parse_range (VALUE arg, ca_size_t size,
308
308
  *pstep = step;
309
309
  }
310
310
  else {
311
- rb_raise(rb_eRuntimeError, "unknown range specification");
311
+ rb_raise(rb_eArgError, "unknown range specification");
312
312
  }
313
313
  }
314
314
  else {
315
- rb_raise(rb_eRuntimeError, "unknown range specification");
315
+ rb_raise(rb_eArgError, "unknown range specification");
316
316
  }
317
317
  }
318
318
 
@@ -430,11 +430,11 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
430
430
  *pstep = step;
431
431
  }
432
432
  else {
433
- rb_raise(rb_eRuntimeError, "unknown range specification");
433
+ rb_raise(rb_eArgError, "unknown range specification");
434
434
  }
435
435
  }
436
436
  else {
437
- rb_raise(rb_eRuntimeError, "unknown range specification");
437
+ rb_raise(rb_eArgError, "unknown range specification");
438
438
  }
439
439
  }
440
440
 
@@ -458,14 +458,12 @@ ca_bounds_normalize_index (int8_t bounds, ca_size_t size0, ca_size_t k)
458
458
  k += size0;
459
459
  }
460
460
  if ( k < 0 || k >= size0 ) {
461
- rb_raise(rb_eRuntimeError,
462
- "window index out of range");
461
+ ca_index_out_of_range(k, size0, "index");
463
462
  }
464
463
  return k;
465
464
  case CA_BOUNDS_STRICT:
466
465
  if ( k < 0 || k >= size0 ) {
467
- rb_raise(rb_eRuntimeError,
468
- "window index out of range");
466
+ ca_index_out_of_range(k, size0, "index");
469
467
  }
470
468
  return k;
471
469
  case CA_BOUNDS_NEAREST:
@@ -477,16 +475,332 @@ ca_bounds_normalize_index (int8_t bounds, ca_size_t size0, ca_size_t k)
477
475
  k = k % (2*size0);
478
476
  return ( k < size0 ) ? k : 2*size0-1-k;
479
477
  default:
480
- rb_raise(rb_eRuntimeError,
478
+ rb_raise(rb_eArgError,
481
479
  "unknown window boundary specified (%i)", bounds);
482
480
  }
483
481
  }
484
482
 
483
+ /* The name of the method the user called, for error messages. A C
484
+ entry reached directly from C (no rb_funcall) reports the method that
485
+ was entered from Ruby, which is the one the user wrote. The internal
486
+ `_ki` twin of a public method is reported under the public name.
487
+ Falls back to "axis" when there is no method frame. */
488
+ /* A C copy of an ID's name that stays put. rb_id2name points into the
489
+ name's String, which compaction can move while a caller is still
490
+ formatting a message with it; the copy is made once per ID while the
491
+ String is held on the stack (and so pinned), and kept for the life of
492
+ the process. The table is shared by every Ractor, hence the lock. */
493
+ static st_table *ca_id_names = NULL;
494
+ static rb_nativethread_lock_t ca_id_names_lock;
495
+
496
+ static const char *
497
+ ca_stable_id_name (ID id)
498
+ {
499
+ st_data_t found;
500
+ const char *name = NULL;
501
+ rb_nativethread_lock_lock(&ca_id_names_lock);
502
+ if ( st_lookup(ca_id_names, (st_data_t) id, &found) ) {
503
+ name = (const char *) found;
504
+ }
505
+ rb_nativethread_lock_unlock(&ca_id_names_lock);
506
+ if ( name ) {
507
+ return name;
508
+ }
509
+ {
510
+ VALUE str = rb_id2str(id);
511
+ long len;
512
+ char *copy;
513
+ if ( NIL_P(str) ) {
514
+ return NULL;
515
+ }
516
+ len = RSTRING_LEN(str);
517
+ copy = ALLOC_N(char, len + 1);
518
+ memcpy(copy, RSTRING_PTR(str), len);
519
+ copy[len] = '\0';
520
+ RB_GC_GUARD(str);
521
+ rb_nativethread_lock_lock(&ca_id_names_lock);
522
+ if ( st_lookup(ca_id_names, (st_data_t) id, &found) ) {
523
+ xfree(copy);
524
+ name = (const char *) found;
525
+ }
526
+ else {
527
+ st_insert(ca_id_names, (st_data_t) id, (st_data_t) copy);
528
+ name = copy;
529
+ }
530
+ rb_nativethread_lock_unlock(&ca_id_names_lock);
531
+ return name;
532
+ }
533
+ }
534
+
535
+ /* The method a delegating method answers for. A method that does its work
536
+ by calling others (median calls partition_index, mode calls sort) runs
537
+ them under ca_answer_as_caller, so an error they raise names the method
538
+ the user called. The outermost one wins. */
539
+ static _Thread_local const char *ca_answering_name = NULL;
540
+
541
+ static VALUE
542
+ ca_answer_restore (VALUE unused)
543
+ {
544
+ ca_answering_name = NULL;
545
+ return Qnil;
546
+ }
547
+
548
+ VALUE
549
+ ca_answer_as_caller (VALUE (*body)(VALUE), VALUE arg)
550
+ {
551
+ if ( ca_answering_name ) {
552
+ return body(arg);
553
+ }
554
+ ca_answering_name = ca_calling_method_name();
555
+ return rb_ensure(body, arg, ca_answer_restore, Qnil);
556
+ }
557
+
558
+ /* CArray.__answer_as__(name) { ... }: the same for a method written in Ruby. */
559
+ static VALUE
560
+ rb_ca_s_answer_as_body (VALUE unused)
561
+ {
562
+ return rb_yield(Qnil);
563
+ }
564
+
565
+ static VALUE
566
+ rb_ca_s_answer_as (VALUE klass, VALUE name)
567
+ {
568
+ if ( ca_answering_name ) {
569
+ return rb_yield(Qnil);
570
+ }
571
+ ca_answering_name = ca_stable_id_name(rb_to_id(name));
572
+ return rb_ensure(rb_ca_s_answer_as_body, Qnil, ca_answer_restore, Qnil);
573
+ }
574
+
575
+ const char *
576
+ ca_calling_method_name (void)
577
+ {
578
+ ID id;
579
+ const char *s;
580
+ size_t n;
581
+ if ( ca_answering_name ) {
582
+ return ca_answering_name;
583
+ }
584
+ id = rb_frame_this_func();
585
+ if ( ! id ) {
586
+ return "axis";
587
+ }
588
+ s = ca_stable_id_name(id);
589
+ if ( ! s ) {
590
+ return "axis";
591
+ }
592
+ n = strlen(s);
593
+ if ( n > 3 && strcmp(s + n - 3, "_ki") == 0 ) {
594
+ return ca_stable_id_name(rb_intern2(s, (long) (n - 3)));
595
+ }
596
+ return s;
597
+ }
598
+
599
+ /* The Integer value of an integer argument (`axis`, `kth`, `min_count`,
600
+ ...). Anything else -- a Float included, which NUM2LONG would truncate
601
+ -- is a TypeError. `arg` is the argument's name; `name` names the method
602
+ in the message, NULL for the method the user called. */
603
+ /* The number of cells in a shape. A shape whose cell count, or whose size
604
+ at `bytes` a cell, does not fit ca_size_t is refused: wrapped, the count
605
+ would describe a smaller array than the view addresses, and every read
606
+ and write past it would leave the buffer. Negative extents are the
607
+ caller's to refuse, with its own message. */
608
+ ca_size_t
609
+ ca_shape_elements (int8_t ndim, const ca_size_t *dim, ca_size_t bytes)
610
+ {
611
+ ca_size_t elements = 1, total;
612
+ int8_t i;
613
+ for ( i = 0; i < ndim; i++ ) {
614
+ if ( dim[i] == 0 ) return 0; /* empty, whatever the other extents */
615
+ }
616
+ for ( i = 0; i < ndim; i++ ) {
617
+ if ( __builtin_mul_overflow(elements, dim[i], &elements) ) {
618
+ rb_raise(rb_eArgError, "too large byte length");
619
+ }
620
+ }
621
+ if ( __builtin_mul_overflow(elements, (bytes > 0 ? bytes : 1), &total) ) {
622
+ rb_raise(rb_eArgError, "too large byte length");
623
+ }
624
+ return elements;
625
+ }
626
+
627
+ /* An index array is read as ca_size_t. A uint64 one holding 2**63 or more
628
+ would turn negative on the way and count from the end of the axis, so it
629
+ is refused here as the out-of-range index it is. */
630
+ void
631
+ ca_check_index_array (VALUE v)
632
+ {
633
+ CArray *ca;
634
+ if ( ! rb_obj_is_carray(v) ) return;
635
+ GetCArray(v, ca);
636
+ if ( ca->data_type != CA_UINT64 || ca->elements == 0 ) return;
637
+ {
638
+ VALUE max = rb_funcall(v, rb_intern("max"), 0);
639
+ if ( rb_obj_is_kind_of(max, rb_cInteger) &&
640
+ RTEST(rb_funcall(max, rb_intern(">"), 1, LL2NUM(CA_LENGTH_MAX))) ) {
641
+ rb_raise(rb_eIndexError, "index %"PRIsVALUE" is out of range", max);
642
+ }
643
+ }
644
+ }
645
+
646
+ long
647
+ ca_integer_arg (VALUE v, const char *arg, const char *name)
648
+ {
649
+ if ( ! RB_INTEGER_TYPE_P(v) ) {
650
+ rb_raise(rb_eTypeError, "%s: %s must be an Integer (got %"PRIsVALUE")",
651
+ name ? name : ca_calling_method_name(), arg, rb_obj_class(v));
652
+ }
653
+ return NUM2LONG(v);
654
+ }
655
+
656
+ void
657
+ ca_index_out_of_range_at (ca_size_t idx, ca_size_t n, int axis)
658
+ {
659
+ rb_raise(rb_eIndexError,
660
+ "%s: index %lld is out of range for length %lld on axis %d",
661
+ ca_calling_method_name(), (long long) idx, (long long) n, axis);
662
+ }
663
+
664
+ void
665
+ ca_obj_compare_refused (VALUE a, VALUE b)
666
+ {
667
+ /* The right-hand value is written as Ruby's own comparison error writes
668
+ it: inspected when it is nil, true, false or a number, its class
669
+ otherwise. */
670
+ volatile VALUE rhs = ( RB_SPECIAL_CONST_P(b) || RB_FLOAT_TYPE_P(b) )
671
+ ? rb_inspect(b) : rb_class_name(rb_obj_class(b));
672
+ rb_raise(rb_eArgError, "%s: comparison of %"PRIsVALUE" with %"PRIsVALUE" failed",
673
+ ca_calling_method_name(), rb_class_name(rb_obj_class(a)), rhs);
674
+ }
675
+
676
+ void
677
+ ca_index_out_of_range (ca_size_t idx, ca_size_t n, const char *what)
678
+ {
679
+ rb_raise(rb_eIndexError, "%s: %s %lld is out of range for length %lld",
680
+ ca_calling_method_name(), what, (long long) idx, (long long) n);
681
+ }
682
+
683
+ /* The min_count: keyword of a reduction: nil (not given) is -1, any other
684
+ value an Integer of at least 0. An error names `name`, or the method the
685
+ user called when NULL. See ca_too_few_present. */
686
+ long
687
+ ca_min_count_arg (VALUE v, const char *name)
688
+ {
689
+ long n;
690
+ if ( NIL_P(v) ) {
691
+ return -1;
692
+ }
693
+ n = ca_integer_arg(v, "min_count", name);
694
+ if ( n < 0 ) {
695
+ rb_raise(rb_eArgError, "%s: min_count must be non-negative (got %ld)",
696
+ name ? name : ca_calling_method_name(), n);
697
+ }
698
+ return n;
699
+ }
700
+
701
+ /* CArray.__min_count_need__(op, min_count, least): how many present cells a
702
+ result cell of `op` needs (ca_too_few_present), for a reduction written
703
+ in Ruby; it masks the cells whose count is below it. */
704
+ static VALUE
705
+ rb_ca_s_min_count_need (VALUE klass, VALUE vop, VALUE vmc, VALUE vleast)
706
+ {
707
+ volatile VALUE name = rb_String(vop);
708
+ long need = NUM2LONG(vleast);
709
+ long mc = ca_min_count_arg(vmc, StringValueCStr(name));
710
+ return LONG2NUM(mc > need ? mc : need);
711
+ }
712
+
713
+ /* A keyword that names one of two Symbols (`masked_position: :first /
714
+ :last`, `kind: :quick / :stable`, `method: :ordinal / :dense`):
715
+ returns 0 for c0 and 1 for c1. Anything but a Symbol is a TypeError,
716
+ another Symbol an ArgumentError, both naming the method (`name`, or the
717
+ method the user called when NULL). */
718
+ int
719
+ ca_symbol_choice (VALUE v, const char *arg, const char *c0, const char *c1,
720
+ const char *name)
721
+ {
722
+ const char *nm = name ? name : ca_calling_method_name();
723
+ ID id;
724
+ if ( ! SYMBOL_P(v) ) {
725
+ rb_raise(rb_eTypeError, "%s: %s must be a Symbol (got %"PRIsVALUE")",
726
+ nm, arg, rb_obj_class(v));
727
+ }
728
+ id = SYM2ID(v);
729
+ if ( id == rb_intern(c0) ) {
730
+ return 0;
731
+ }
732
+ if ( id == rb_intern(c1) ) {
733
+ return 1;
734
+ }
735
+ rb_raise(rb_eArgError, "%s: unknown %s :%"PRIsVALUE" (expected :%s or :%s)",
736
+ nm, arg, rb_id2str(id), c0, c1);
737
+ return 0;
738
+ }
739
+
740
+ /* `fill` as a cell of `data_type` holds it: the value a store of `fill`
741
+ into such an array would leave. */
742
+ VALUE
743
+ ca_fill_as (VALUE fill, int8_t data_type)
744
+ {
745
+ ca_size_t dim[1] = { 1 };
746
+ VALUE cell = rb_carray_new(data_type, 1, dim, 0, NULL);
747
+ rb_ca_store_all(cell, fill);
748
+ return rb_ca_fetch_addr(cell, 0);
749
+ }
750
+
751
+ /* The `fill_value:` of a reduction, applied to its result: the masked
752
+ cells of a CArray result are filled as a store would fill them, each
753
+ member of a two-array result (minmax) alike. `whole` says the result
754
+ was computed with every axis kept for a full reduction; its one cell
755
+ is then returned as the scalar the caller asked for. A caller passes
756
+ no fill for `fill_value: UNDEF`, which leaves the cells undefined. */
757
+ VALUE
758
+ ca_reduce_fill (VALUE result, VALUE fill, int whole)
759
+ {
760
+ if ( RB_TYPE_P(result, T_ARRAY) ) {
761
+ long i, n = RARRAY_LEN(result);
762
+ VALUE out = rb_ary_new_capa(n);
763
+ for ( i = 0; i < n; i++ ) {
764
+ rb_ary_push(out, ca_reduce_fill(RARRAY_AREF(result, i), fill, whole));
765
+ }
766
+ return out;
767
+ }
768
+ if ( rb_obj_is_kind_of(result, rb_cCArray) ) {
769
+ CArray *cr;
770
+ GetCArray(result, cr);
771
+ if ( ca_has_mask(cr) ) {
772
+ result = rb_ca_mask_fill_copy(result, fill);
773
+ }
774
+ return whole ? rb_ca_fetch_addr(result, 0) : result;
775
+ }
776
+ return ( result == CA_UNDEF ) ? fill : result;
777
+ }
778
+
779
+ /* CArray.__reduce_fill__(result, fill_value): ca_reduce_fill for a
780
+ reduction written in Ruby. A fill_value of nil or UNDEF leaves the
781
+ undefined cells as they are. */
782
+ static VALUE
783
+ rb_ca_s_reduce_fill (VALUE klass, VALUE result, VALUE fill)
784
+ {
785
+ if ( NIL_P(fill) || fill == CA_UNDEF ) {
786
+ return result;
787
+ }
788
+ return ca_reduce_fill(result, fill, 0);
789
+ }
790
+
791
+ /* ca_integer_arg for an `axis` argument. */
792
+ long
793
+ ca_axis_integer (VALUE raxis, const char *name)
794
+ {
795
+ return ca_integer_arg(raxis, "axis", name);
796
+ }
797
+
485
798
  /* Self-independent kernel: normalize `raw` against `ndim`, returning a
486
799
  canonical non-negative axis in [0, ndim) as int. Accepts negative
487
800
  values (Python/Ruby convention: -1 => ndim-1). Raises ArgumentError
488
801
  if out of range. `name` is used in the error message (e.g.
489
- "mask_duplicates", "sum", "merge"); pass NULL to default to "axis".
802
+ "mask_duplicates", "sum", "merge"); pass NULL to use the name of the
803
+ method the user called.
490
804
 
491
805
  For an insertion position (= valid range [0, old_ndim] inclusive),
492
806
  pass `old_ndim + 1` as `ndim` so the half-open [0, ndim) check
@@ -498,7 +812,7 @@ rb_ca_normalize_axis_for_ndim (long raw, int ndim, const char *name)
498
812
  if ( axis < 0 || axis >= ndim ) {
499
813
  rb_raise(rb_eArgError,
500
814
  "%s: axis %ld out of range for ndim %d",
501
- name ? name : "axis", raw, ndim);
815
+ name ? name : ca_calling_method_name(), raw, ndim);
502
816
  }
503
817
  return (int) axis;
504
818
  }
@@ -511,7 +825,7 @@ rb_ca_normalize_axis_value (VALUE self, VALUE raxis, const char *name)
511
825
  {
512
826
  CArray *ca;
513
827
  GetCArray(self, ca);
514
- return rb_ca_normalize_axis_for_ndim(NUM2LONG(raxis), (int) ca->ndim, name);
828
+ return rb_ca_normalize_axis_for_ndim(ca_axis_integer(raxis, name), (int) ca->ndim, name);
515
829
  }
516
830
 
517
831
  /* Ruby-facing `CArray#normalize_axis(axis, name=nil)` — returns the
@@ -546,7 +860,7 @@ rb_ca_s_normalize_axis (int argc, VALUE *argv, VALUE klass)
546
860
  int k;
547
861
  rb_scan_args(argc, argv, "21", &raxis, &rndim, &rname);
548
862
  name = NIL_P(rname) ? NULL : StringValueCStr(rname);
549
- k = rb_ca_normalize_axis_for_ndim(NUM2LONG(raxis), NUM2INT(rndim), name);
863
+ k = rb_ca_normalize_axis_for_ndim(ca_axis_integer(raxis, name), NUM2INT(rndim), name);
550
864
  return INT2NUM(k);
551
865
  }
552
866
 
@@ -566,7 +880,7 @@ rb_ca_normalize_axes (int argc, VALUE *argv, VALUE self)
566
880
  const char *name;
567
881
 
568
882
  rb_scan_args(argc, argv, "11", &raxes, &rname);
569
- name = NIL_P(rname) ? "axes" : StringValueCStr(rname);
883
+ name = NIL_P(rname) ? ca_calling_method_name() : StringValueCStr(rname);
570
884
  GetCArray(self, ca);
571
885
 
572
886
  if ( NIL_P(raxes) ) {
@@ -585,67 +899,6 @@ rb_ca_normalize_axes (int argc, VALUE *argv, VALUE self)
585
899
  return out;
586
900
  }
587
901
 
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
902
  static const struct {
650
903
  const char *name;
651
904
  int data_type;
@@ -685,7 +938,12 @@ rb_ca_guess_type (VALUE obj)
685
938
  VALUE inspect;
686
939
 
687
940
  if ( TYPE(obj) == T_FIXNUM ) {
688
- return NUM2SIZE(obj);
941
+ /* Check before narrowing to int8_t, so the message names the id given. */
942
+ long id = FIX2LONG(obj);
943
+ if ( id <= CA_NONE || id >= CA_NTYPE ) {
944
+ rb_raise(rb_eArgError, "invalid data_type id %ld", id);
945
+ }
946
+ return (int8_t) id;
689
947
  }
690
948
  else if ( TYPE(obj) == T_STRING ) {
691
949
  const char *name0;
@@ -701,7 +959,7 @@ rb_ca_guess_type (VALUE obj)
701
959
  }
702
960
  }
703
961
  else if ( TYPE(obj) == T_SYMBOL ) {
704
- return rb_ca_guess_type(rb_str_new2(rb_id2name(SYM2ID(obj))));
962
+ return rb_ca_guess_type(rb_str_dup(rb_sym2str(obj)));
705
963
  }
706
964
  else if ( TYPE(obj) == T_CLASS ) {
707
965
  ca_check_data_class(obj);
@@ -709,7 +967,7 @@ rb_ca_guess_type (VALUE obj)
709
967
  }
710
968
 
711
969
  inspect = rb_inspect(obj);
712
- rb_raise(rb_eRuntimeError,
970
+ rb_raise(rb_eArgError,
713
971
  "<%s> is unknown data_type representation", StringValuePtr(inspect));
714
972
  }
715
973
 
@@ -754,11 +1012,15 @@ rb_ca_s_guess_type_and_bytes (int argc, VALUE *argv, VALUE klass)
754
1012
  return rb_assoc_new(INT2NUM(data_type), SIZE2NUM(bytes));
755
1013
  }
756
1014
 
1015
+ /* Takes the trailing keyword Hash off argv when the caller passed keywords.
1016
+ A Hash passed as a positional argument (`f({axis: 0})`) stays an argument,
1017
+ as in Ruby 3: it may be a value, such as a cell of an object array. */
757
1018
  VALUE
758
1019
  rb_pop_options (int *argc, VALUE **argv)
759
1020
  {
760
1021
  VALUE ropt;
761
- if ( ( *argc > 0 ) && ( TYPE( (*argv)[*argc-1] ) == T_HASH ) ) {
1022
+ if ( ( *argc > 0 ) && rb_keyword_given_p() &&
1023
+ ( TYPE( (*argv)[*argc-1] ) == T_HASH ) ) {
762
1024
  ropt = (*argv)[*argc-1];
763
1025
  (*argc) -= 1;
764
1026
  }
@@ -928,15 +1190,12 @@ rb_set_options (VALUE ropt, const char *spec_in, ...)
928
1190
  void
929
1191
  Init_carray_utils (void)
930
1192
  {
1193
+ ca_id_names = st_init_numtable();
1194
+ rb_nativethread_lock_initialize(&ca_id_names_lock);
931
1195
  id_begin = rb_intern("begin");
932
1196
  id_end = rb_intern("end");
933
1197
  id_excl_end = rb_intern("exclude_end?");
934
1198
 
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
1199
  rb_define_singleton_method(rb_cCArray, "guess_type_and_bytes",
941
1200
  rb_ca_s_guess_type_and_bytes, -1);
942
1201
 
@@ -944,6 +1203,12 @@ Init_carray_utils (void)
944
1203
  rb_define_method(rb_cCArray, "normalize_axes", rb_ca_normalize_axes, -1);
945
1204
  rb_define_singleton_method(rb_cCArray, "normalize_axis",
946
1205
  rb_ca_s_normalize_axis, -1);
1206
+ rb_define_singleton_method(rb_cCArray, "__min_count_need__",
1207
+ rb_ca_s_min_count_need, 3);
1208
+ rb_define_singleton_method(rb_cCArray, "__reduce_fill__",
1209
+ rb_ca_s_reduce_fill, 2);
1210
+ rb_define_singleton_method(rb_cCArray, "__answer_as__",
1211
+ rb_ca_s_answer_as, 1);
947
1212
 
948
1213
  }
949
1214