carray 3.0.3 → 3.0.5

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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +469 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_descriptor.h +27 -24
  7. data/ext/ca_axis_dispatch.c +14 -26
  8. data/ext/ca_axis_group.c +27 -27
  9. data/ext/ca_binop_dispatch.c +1 -29
  10. data/ext/ca_binop_dispatch.h +0 -1
  11. data/ext/ca_categorical_iterator.c +231 -153
  12. data/ext/ca_compare.c +9 -20
  13. data/ext/ca_composite_dispatch.c +9 -9
  14. data/ext/ca_group_iter.c +16 -17
  15. data/ext/ca_kernel_iterator.c +1240 -2000
  16. data/ext/ca_kernel_iterator.h +502 -519
  17. data/ext/ca_monop_dispatch.c +82 -59
  18. data/ext/ca_monop_dispatch.h +1 -0
  19. data/ext/ca_obj_array.c +152 -45
  20. data/ext/ca_obj_bincmp.c +25 -21
  21. data/ext/ca_obj_binop.c +16 -26
  22. data/ext/ca_obj_bitarray.c +8 -3
  23. data/ext/ca_obj_bitfield.c +63 -49
  24. data/ext/ca_obj_block.c +18 -9
  25. data/ext/ca_obj_byte_swap.c +7 -7
  26. data/ext/ca_obj_const_string.c +188 -22
  27. data/ext/ca_obj_face.c +280 -58
  28. data/ext/ca_obj_face.h +19 -0
  29. data/ext/ca_obj_fake.c +15 -29
  30. data/ext/ca_obj_farray.c +6 -3
  31. data/ext/ca_obj_field.c +30 -8
  32. data/ext/ca_obj_fixlen_string.c +2 -3
  33. data/ext/ca_obj_grid.c +455 -134
  34. data/ext/ca_obj_meld.c +172 -34
  35. data/ext/ca_obj_moncmp.c +23 -8
  36. data/ext/ca_obj_monop.c +113 -67
  37. data/ext/ca_obj_object.c +210 -52
  38. data/ext/ca_obj_record.c +15 -7
  39. data/ext/ca_obj_reduce.c +17 -8
  40. data/ext/ca_obj_refer.c +42 -35
  41. data/ext/ca_obj_remap.c +30 -9
  42. data/ext/ca_obj_repeat.c +9 -10
  43. data/ext/ca_obj_roll.c +31 -10
  44. data/ext/ca_obj_select.c +48 -14
  45. data/ext/ca_obj_select_axis.c +15 -47
  46. data/ext/ca_obj_shift.c +41 -7
  47. data/ext/ca_obj_stack.c +180 -34
  48. data/ext/ca_obj_stride.c +190 -134
  49. data/ext/ca_obj_string.c +80 -4
  50. data/ext/ca_obj_tile.c +32 -11
  51. data/ext/ca_obj_time.c +22 -6
  52. data/ext/ca_obj_timedelta.c +22 -6
  53. data/ext/ca_obj_transpose.c +13 -7
  54. data/ext/ca_obj_triop.c +26 -32
  55. data/ext/ca_obj_window.c +267 -74
  56. data/ext/ca_op_ipower.c +4 -4
  57. data/ext/ca_sort_kernels.h +6 -3
  58. data/ext/ca_sweep_engine.c +2 -2
  59. data/ext/caframe_csv_reader.c +80 -1
  60. data/ext/carray.h +214 -75
  61. data/ext/carray_access.c +200 -99
  62. data/ext/carray_address_basis.c +343 -87
  63. data/ext/carray_attribute.c +113 -6
  64. data/ext/carray_bincount.c +10 -8
  65. data/ext/carray_broadcast.c +13 -8
  66. data/ext/carray_build_flags.h +3 -0
  67. data/ext/carray_call_cfunc.c +108 -0
  68. data/ext/carray_cast.c +375 -96
  69. data/ext/carray_cast_func.rb +90 -20
  70. data/ext/carray_class.c +4 -3
  71. data/ext/carray_config.h +28 -0
  72. data/ext/carray_conversion.c +18 -9
  73. data/ext/carray_copy.c +51 -14
  74. data/ext/carray_core.c +150 -55
  75. data/ext/carray_count.c +56 -20
  76. data/ext/carray_element.c +81 -33
  77. data/ext/carray_factorize.c +138 -84
  78. data/ext/carray_generate.c +199 -52
  79. data/ext/carray_histogram.c +63 -18
  80. data/ext/carray_hold.c +12 -15
  81. data/ext/carray_index_classifier.c +388 -176
  82. data/ext/carray_internal.h +348 -29
  83. data/ext/carray_kernels_bincmp.c +4453 -0
  84. data/ext/carray_kernels_binop.c +11368 -0
  85. data/ext/carray_kernels_init.c +1734 -0
  86. data/ext/carray_kernels_moncmp.c +2104 -0
  87. data/ext/carray_kernels_monop.c +18369 -0
  88. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  89. data/ext/carray_kernels_reduce_boolean.c +406 -0
  90. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  91. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  92. data/ext/carray_kernels_reduce_variance.c +3849 -0
  93. data/ext/carray_kernels_scan.c +4302 -0
  94. data/ext/carray_kernels_search.c +33829 -0
  95. data/ext/carray_kernels_sort.c +10897 -0
  96. data/ext/carray_kernels_triop.c +1864 -0
  97. data/ext/carray_key_windows.c +220 -0
  98. data/ext/carray_lazy.c +170 -111
  99. data/ext/carray_mask.c +337 -94
  100. data/ext/carray_median_percentile.c +82 -28
  101. data/ext/carray_memory_view.c +669 -561
  102. data/ext/carray_operator.c +129 -52
  103. data/ext/carray_order.c +604 -77
  104. data/ext/carray_partition.c +28 -27
  105. data/ext/carray_random.c +85 -31
  106. data/ext/carray_round.c +273 -0
  107. data/ext/carray_scatter.c +87 -45
  108. data/ext/carray_segment.c +3 -3
  109. data/ext/carray_slab.c +123 -37
  110. data/ext/carray_sort.c +259 -51
  111. data/ext/carray_sort_kernel.c +5 -7
  112. data/ext/carray_struct.c +54 -61
  113. data/ext/carray_test.c +26 -5
  114. data/ext/carray_time_text.c +4 -2
  115. data/ext/carray_undef.c +4 -0
  116. data/ext/carray_utils.c +309 -66
  117. data/ext/mk_call_cfunc.rb +19 -2
  118. data/ext/mkkernel.rb +403 -350
  119. data/ext/ruby_carray.c +10 -4
  120. data/ext/version.h +4 -4
  121. data/lib/carray/attribute.rb +139 -22
  122. data/lib/carray/autoload_carray.rb +8 -31
  123. data/lib/carray/autoload_method_extension.rb +14 -5
  124. data/lib/carray/axis_group.rb +255 -106
  125. data/lib/carray/basics.rb +105 -17
  126. data/lib/carray/bincount_nd.rb +12 -2
  127. data/lib/carray/block_iterator.rb +126 -23
  128. data/lib/carray/boolean_reduce.rb +17 -17
  129. data/lib/carray/categorical.rb +195 -59
  130. data/lib/carray/categorical_iterator.rb +132 -29
  131. data/lib/carray/complex.rb +5 -5
  132. data/lib/carray/conditional.rb +67 -18
  133. data/lib/carray/const_string.rb +24 -5
  134. data/lib/carray/construct.rb +15 -11
  135. data/lib/carray/data_type_extension.rb +9 -1
  136. data/lib/carray/distance_limit.rb +77 -0
  137. data/lib/carray/fixlen_string.rb +48 -3
  138. data/lib/carray/frame/column_verbs.rb +71 -0
  139. data/lib/carray/frame/concat.rb +17 -3
  140. data/lib/carray/frame/convert.rb +69 -0
  141. data/lib/carray/frame/csv_parser.rb +111 -17
  142. data/lib/carray/frame/describe.rb +3 -2
  143. data/lib/carray/frame/frame.rb +252 -28
  144. data/lib/carray/frame/group.rb +603 -101
  145. data/lib/carray/frame/io.rb +117 -28
  146. data/lib/carray/frame/join.rb +312 -51
  147. data/lib/carray/frame/records.rb +83 -7
  148. data/lib/carray/frame/reshape.rb +42 -35
  149. data/lib/carray/frame/sort.rb +7 -19
  150. data/lib/carray/frame/verbs.rb +188 -48
  151. data/lib/carray/frame/windows.rb +117 -0
  152. data/lib/carray/frame.rb +2 -0
  153. data/lib/carray/fuse_source.rb +42 -6
  154. data/lib/carray/fusion.rb +40 -16
  155. data/lib/carray/histogram.rb +6 -1
  156. data/lib/carray/inspect.rb +31 -8
  157. data/lib/carray/iterator.rb +85 -7
  158. data/lib/carray/key_windows.rb +620 -0
  159. data/lib/carray/lazy.rb +217 -183
  160. data/lib/carray/mask_gap_fill.rb +63 -57
  161. data/lib/carray/meld_reduce.rb +12 -14
  162. data/lib/carray/methods/bin.rb +26 -18
  163. data/lib/carray/methods/bincount.rb +16 -0
  164. data/lib/carray/methods/bit_string.rb +1 -1
  165. data/lib/carray/methods/choose.rb +16 -3
  166. data/lib/carray/methods/composition.rb +3 -1
  167. data/lib/carray/methods/gather_nd.rb +14 -5
  168. data/lib/carray/methods/insert_block.rb +2 -2
  169. data/lib/carray/methods/is_between.rb +59 -0
  170. data/lib/carray/methods/is_in.rb +61 -37
  171. data/lib/carray/methods/join.rb +1 -6
  172. data/lib/carray/methods/lag.rb +49 -0
  173. data/lib/carray/methods/locate_addr.rb +47 -51
  174. data/lib/carray/methods/mode.rb +1 -1
  175. data/lib/carray/methods/nunique.rb +11 -6
  176. data/lib/carray/methods/resize.rb +3 -3
  177. data/lib/carray/methods/value_counts.rb +4 -11
  178. data/lib/carray/record_order.rb +3 -3
  179. data/lib/carray/rng.rb +3 -0
  180. data/lib/carray/runtime.rb +53 -8
  181. data/lib/carray/segment_iterator.rb +323 -88
  182. data/lib/carray/serialize.rb +45 -14
  183. data/lib/carray/slab_iterator.rb +50 -0
  184. data/lib/carray/stack.rb +15 -12
  185. data/lib/carray/string.rb +113 -5
  186. data/lib/carray/string_operation_extension.rb +21 -6
  187. data/lib/carray/struct.rb +9 -21
  188. data/lib/carray/struct_builder.rb +24 -11
  189. data/lib/carray/time.rb +819 -158
  190. data/lib/carray/window_iterator.rb +122 -16
  191. data/lib/carray.rb +7 -0
  192. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  193. data/yard-stubs/ca_obj_field.rb +4 -0
  194. data/yard-stubs/ca_obj_grid.rb +21 -10
  195. data/yard-stubs/ca_obj_refer.rb +2 -1
  196. data/yard-stubs/ca_obj_roll.rb +2 -2
  197. data/yard-stubs/ca_obj_shift.rb +5 -1
  198. data/yard-stubs/ca_obj_tile.rb +1 -1
  199. data/yard-stubs/ca_obj_transpose.rb +5 -4
  200. data/yard-stubs/ca_obj_window.rb +8 -3
  201. data/yard-stubs/carray_access.rb +6 -1
  202. data/yard-stubs/carray_attribute.rb +3 -6
  203. data/yard-stubs/carray_cast.rb +12 -0
  204. data/yard-stubs/carray_conversion.rb +7 -2
  205. data/yard-stubs/carray_copy.rb +4 -2
  206. data/yard-stubs/carray_count.rb +4 -4
  207. data/yard-stubs/carray_element.rb +17 -10
  208. data/yard-stubs/carray_generate.rb +21 -1
  209. data/yard-stubs/carray_mask.rb +32 -3
  210. data/yard-stubs/carray_math.rb +41 -5
  211. data/yard-stubs/carray_median_percentile.rb +5 -2
  212. data/yard-stubs/carray_memory_view.rb +40 -23
  213. data/yard-stubs/carray_order.rb +129 -22
  214. data/yard-stubs/carray_random.rb +13 -4
  215. data/yard-stubs/carray_scatter.rb +17 -10
  216. data/yard-stubs/carray_slab.rb +9 -2
  217. data/yard-stubs/carray_sort.rb +6 -5
  218. data/yard-stubs/carray_test.rb +5 -3
  219. metadata +25 -3
  220. data/lib/carray/arrow_tensor.rb +0 -401
  221. data/lib/carray/table.rb +0 -108
data/ext/carray_utils.c CHANGED
@@ -17,6 +17,8 @@
17
17
 
18
18
  #include "ruby/st.h"
19
19
  #include "ruby/thread_native.h"
20
+ #include "ruby/ractor.h"
21
+ #include "ruby/debug.h" /* rb_profile_frames: the method the user called */
20
22
 
21
23
  static ID id_begin, id_end, id_excl_end;
22
24
  #define RANGE_BEG(r) (rb_funcall(r, id_begin, 0))
@@ -56,7 +58,8 @@ ca_set_iterator (int n, ...)
56
58
  max = ca->elements;
57
59
  }
58
60
  else if ( max != ca->elements ) {
59
- rb_raise(rb_eArgError, "data size mismatch in operation");
61
+ rb_raise(rb_eArgError, "%s: data size mismatch in operation",
62
+ ca_calling_method_name());
60
63
  }
61
64
  }
62
65
  }
@@ -158,7 +161,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
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,--]*/
@@ -172,6 +175,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
172
175
  if ( step == 0 ) {
173
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
  }
@@ -181,7 +185,6 @@ ca_parse_range (VALUE arg, ca_size_t size,
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
- 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;
@@ -211,8 +216,9 @@ ca_parse_range (VALUE arg, ca_size_t size,
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;
@@ -225,6 +231,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
225
231
  if ( step == 0 ) {
226
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
  }
@@ -234,7 +241,6 @@ ca_parse_range (VALUE arg, ca_size_t size,
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
- 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;
@@ -259,6 +267,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
259
267
  if ( step == 0 ) {
260
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
  }
@@ -268,7 +277,6 @@ ca_parse_range (VALUE arg, ca_size_t size,
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
- 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;
@@ -300,9 +312,11 @@ ca_parse_range (VALUE arg, ca_size_t size,
300
312
  if ( step == 0 ) {
301
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;
@@ -357,6 +371,10 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
357
371
  last = NUM2SIZE(x.end);
358
372
  excl = RTEST(x.exclude_end);
359
373
  step = NUM2SIZE(x.step);
374
+ if ( step == 0 ) {
375
+ rb_raise(rb_eArgError, "%s: step should not be 0",
376
+ ca_calling_method_name());
377
+ }
360
378
  if ( excl ) {
361
379
  last += ( (last>=start) ? -1 : 1 );
362
380
  }
@@ -377,6 +395,10 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
377
395
  if ( NIL_P(arg0) ) { /* [nil,k] */
378
396
  start = 0;
379
397
  step = NUM2SIZE(arg1);
398
+ if ( step == 0 ) {
399
+ rb_raise(rb_eArgError, "%s: step should not be 0",
400
+ ca_calling_method_name());
401
+ }
380
402
  count = (size-1)/llabs(step) + 1;
381
403
  *poffset = start;
382
404
  *pcount = count;
@@ -387,6 +409,10 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
387
409
  last = NUM2SIZE(RANGE_END(arg0));
388
410
  excl = RTEST(RANGE_EXCL(arg0));
389
411
  step = NUM2SIZE(arg1);
412
+ if ( step == 0 ) {
413
+ rb_raise(rb_eArgError, "%s: step should not be 0",
414
+ ca_calling_method_name());
415
+ }
390
416
  if ( excl ) {
391
417
  last += ( (last>=start) ? -1 : 1 );
392
418
  }
@@ -404,6 +430,10 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
404
430
  last = NUM2SIZE(x.end);
405
431
  excl = RTEST(x.exclude_end);
406
432
  step = NUM2SIZE(x.step);
433
+ if ( step == 0 ) {
434
+ rb_raise(rb_eArgError, "%s: step should not be 0",
435
+ ca_calling_method_name());
436
+ }
407
437
  if ( excl ) {
408
438
  last += ( (last>=start) ? -1 : 1 );
409
439
  }
@@ -535,27 +565,44 @@ ca_stable_id_name (ID id)
535
565
  /* The method a delegating method answers for. A method that does its work
536
566
  by calling others (median calls partition_index, mode calls sort) runs
537
567
  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;
568
+ the user called. The outermost one wins. The name is kept with the
569
+ Ruby thread (Thread#[], so per fiber): Ractors share native threads under
570
+ the M:N scheduler, and a native-thread-local variable leaks one Ractor's
571
+ name into another's message. */
572
+ static ID id_answering;
573
+
574
+ static const char *
575
+ ca_answering_name (void)
576
+ {
577
+ VALUE name = rb_thread_local_aref(rb_thread_current(), id_answering);
578
+ return NIL_P(name) ? NULL : ca_stable_id_name(SYM2ID(name));
579
+ }
580
+
581
+ static void
582
+ ca_set_answering_name (const char *name)
583
+ {
584
+ rb_thread_local_aset(rb_thread_current(), id_answering,
585
+ name ? ID2SYM(rb_intern(name)) : Qnil);
586
+ }
540
587
 
541
588
  static VALUE
542
589
  ca_answer_restore (VALUE unused)
543
590
  {
544
- ca_answering_name = NULL;
591
+ ca_set_answering_name(NULL);
545
592
  return Qnil;
546
593
  }
547
594
 
595
+ /* A C method that does its work by calling others runs them through here.
596
+ It used to fix the name at entry; the name is now found from the frames
597
+ when an error is raised (ca_user_called_method_id), which also reaches
598
+ the outer method, so nothing is fixed and nothing is paid on the way in. */
548
599
  VALUE
549
600
  ca_answer_as_caller (VALUE (*body)(VALUE), VALUE arg)
550
601
  {
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);
602
+ return body(arg);
556
603
  }
557
604
 
558
- /* CArray.__answer_as__(name) { ... }: the same for a method written in Ruby. */
605
+ /* CArray.__name_errors_after_method__(name) { ... }: the same for a method written in Ruby. */
559
606
  static VALUE
560
607
  rb_ca_s_answer_as_body (VALUE unused)
561
608
  {
@@ -565,23 +612,137 @@ rb_ca_s_answer_as_body (VALUE unused)
565
612
  static VALUE
566
613
  rb_ca_s_answer_as (VALUE klass, VALUE name)
567
614
  {
568
- if ( ca_answering_name ) {
615
+ if ( ca_answering_name() ) {
569
616
  return rb_yield(Qnil);
570
617
  }
571
- ca_answering_name = ca_stable_id_name(rb_to_id(name));
618
+ ca_set_answering_name(ca_stable_id_name(rb_to_id(name)));
572
619
  return rb_ensure(rb_ca_s_answer_as_body, Qnil, ca_answer_restore, Qnil);
573
620
  }
574
621
 
622
+ /* The directory the library's Ruby files are loaded from (lib/), set once
623
+ by lib/carray.rb as it loads, read only afterwards. */
624
+ static char *ca_library_root = NULL;
625
+ static long ca_library_root_len = 0;
626
+
627
+ /* CArray.library_root = dir (private): where the frames of the library's
628
+ own Ruby methods are. The first call wins. */
629
+ static VALUE
630
+ rb_ca_s_set_library_root (VALUE klass, VALUE dir)
631
+ {
632
+ if ( ca_library_root == NULL ) {
633
+ long len = RSTRING_LEN(StringValue(dir));
634
+ char *copy = ALLOC_N(char, len + 1);
635
+ memcpy(copy, RSTRING_PTR(dir), len);
636
+ copy[len] = '\0';
637
+ ca_library_root_len = len;
638
+ ca_library_root = copy;
639
+ }
640
+ return Qnil;
641
+ }
642
+
643
+ /* Whether a frame without a source file -- a C method -- is one of the
644
+ library's: a method of a CA* or CScalar class, or a CA_* conversion
645
+ function. A method of a core class (Array#map, Integer#times) is not. */
646
+ static int
647
+ ca_frame_is_library_cfunc (VALUE frame, VALUE name)
648
+ {
649
+ VALUE path = rb_profile_frame_classpath(frame);
650
+ if ( ! NIL_P(path) ) {
651
+ const char *p = RSTRING_PTR(path);
652
+ long n = RSTRING_LEN(path);
653
+ if ( ( n >= 2 && strncmp(p, "CA", 2) == 0 )
654
+ || ( n >= 7 && strncmp(p, "CScalar", 7) == 0 ) ) {
655
+ return 1;
656
+ }
657
+ }
658
+ return RSTRING_LEN(name) > 3 && strncmp(RSTRING_PTR(name), "CA_", 3) == 0;
659
+ }
660
+
661
+ /* The method the user called: going out from the innermost frame, the last
662
+ frame of the library -- a Ruby method under ca_library_root, or one of
663
+ its C methods -- before the user's own code (a block included) is
664
+ reached. A core C method the library calls on the way (Array#map) is
665
+ passed through. 0 when no frame of the library is found. */
666
+ #define CA_NAMING_FRAMES 64
667
+
668
+ static ID
669
+ ca_user_called_method_id (void)
670
+ {
671
+ ID id_initialize = rb_intern("initialize");
672
+ ID id_new = rb_intern("new");
673
+ VALUE frames[CA_NAMING_FRAMES];
674
+ int lines[CA_NAMING_FRAMES];
675
+ int n, i;
676
+ ID found = 0;
677
+ if ( ca_library_root == NULL ) {
678
+ return 0;
679
+ }
680
+ n = rb_profile_frames(0, CA_NAMING_FRAMES, frames, lines);
681
+ for (i = 0; i < n; i++) {
682
+ VALUE file = rb_profile_frame_absolute_path(frames[i]);
683
+ VALUE name, label;
684
+ if ( NIL_P(file) ) {
685
+ /* code evaluated with a file name (class_eval in the library) and the
686
+ core written in Ruby ("<internal:numeric>") have a path but no
687
+ absolute path; -e has a path outside the library */
688
+ file = rb_profile_frame_path(frames[i]);
689
+ }
690
+ if ( ! NIL_P(file) && strcmp(StringValueCStr(file), "<cfunc>") == 0 ) {
691
+ name = rb_profile_frame_method_name(frames[i]);
692
+ if ( NIL_P(name) ) {
693
+ continue;
694
+ }
695
+ if ( ca_frame_is_library_cfunc(frames[i], name) ) {
696
+ found = rb_to_id(name);
697
+ }
698
+ else if ( found == id_initialize && rb_to_id(name) == id_new ) {
699
+ found = id_new; /* Class#new around our initialize */
700
+ }
701
+ continue; /* a core C method passes */
702
+ }
703
+ if ( ! NIL_P(file) && strncmp(StringValueCStr(file), "<internal:", 10) == 0 ) {
704
+ continue; /* core written in Ruby (Integer#times) */
705
+ }
706
+ if ( NIL_P(file) /* eval without a file: the user's */
707
+ || RSTRING_LEN(file) <= ca_library_root_len
708
+ || strncmp(RSTRING_PTR(file), ca_library_root, ca_library_root_len) != 0
709
+ || RSTRING_PTR(file)[ca_library_root_len] != '/' ) {
710
+ break;
711
+ }
712
+ /* A block of the library (an each inside a method, the autoload stub)
713
+ names nothing: the method around it is further out. A block whose
714
+ method is a class body is a method made by define_method, and its
715
+ frame does not carry the method's name, so the walk gives up and the
716
+ innermost C method is named, as before the walk. */
717
+ label = rb_profile_frame_label(frames[i]);
718
+ if ( ! NIL_P(label) && strncmp(StringValueCStr(label), "block ", 6) == 0 ) {
719
+ VALUE base = rb_profile_frame_base_label(frames[i]);
720
+ if ( ! NIL_P(base) && RSTRING_LEN(base) > 0 && RSTRING_PTR(base)[0] == '<' ) {
721
+ return 0;
722
+ }
723
+ continue;
724
+ }
725
+ name = rb_profile_frame_method_name(frames[i]);
726
+ if ( ! NIL_P(name) ) {
727
+ found = rb_to_id(name);
728
+ }
729
+ }
730
+ return found;
731
+ }
732
+
575
733
  const char *
576
734
  ca_calling_method_name (void)
577
735
  {
578
736
  ID id;
579
737
  const char *s;
580
738
  size_t n;
581
- if ( ca_answering_name ) {
582
- return ca_answering_name;
739
+ if ( (s = ca_answering_name()) ) {
740
+ return s;
741
+ }
742
+ id = ca_user_called_method_id();
743
+ if ( ! id ) {
744
+ id = rb_frame_this_func();
583
745
  }
584
- id = rb_frame_this_func();
585
746
  if ( ! id ) {
586
747
  return "axis";
587
748
  }
@@ -624,15 +785,22 @@ ca_shape_elements (int8_t ndim, const ca_size_t *dim, ca_size_t bytes)
624
785
  return elements;
625
786
  }
626
787
 
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. */
788
+ /* An index array is read as ca_size_t. A float or complex one would be
789
+ cut to an integer on the way, so it is refused, as the indexer refuses
790
+ it. A uint64 one holding 2**63 or more would turn negative and count
791
+ from the end of the axis, so it is refused as the out-of-range index it
792
+ is. */
630
793
  void
631
794
  ca_check_index_array (VALUE v)
632
795
  {
633
796
  CArray *ca;
634
797
  if ( ! rb_obj_is_carray(v) ) return;
635
798
  GetCArray(v, ca);
799
+ if ( ca_is_float_type(ca) || ca_is_complex_type(ca) ) {
800
+ rb_raise(rb_eIndexError,
801
+ "data_type %s is invalid for an index (should be integer)",
802
+ ca_type_name[ca->data_type]);
803
+ }
636
804
  if ( ca->data_type != CA_UINT64 || ca->elements == 0 ) return;
637
805
  {
638
806
  VALUE max = rb_funcall(v, rb_intern("max"), 0);
@@ -698,7 +866,7 @@ ca_min_count_arg (VALUE v, const char *name)
698
866
  return n;
699
867
  }
700
868
 
701
- /* CArray.__min_count_need__(op, min_count, least): how many present cells a
869
+ /* CArray.__present_cells_needed_per_result_cell__(op, min_count, least): how many present cells a
702
870
  result cell of `op` needs (ca_too_few_present), for a reduction written
703
871
  in Ruby; it masks the cells whose count is below it. */
704
872
  static VALUE
@@ -719,11 +887,10 @@ int
719
887
  ca_symbol_choice (VALUE v, const char *arg, const char *c0, const char *c1,
720
888
  const char *name)
721
889
  {
722
- const char *nm = name ? name : ca_calling_method_name();
723
890
  ID id;
724
891
  if ( ! SYMBOL_P(v) ) {
725
892
  rb_raise(rb_eTypeError, "%s: %s must be a Symbol (got %"PRIsVALUE")",
726
- nm, arg, rb_obj_class(v));
893
+ name ? name : ca_calling_method_name(), arg, rb_obj_class(v));
727
894
  }
728
895
  id = SYM2ID(v);
729
896
  if ( id == rb_intern(c0) ) {
@@ -733,7 +900,7 @@ ca_symbol_choice (VALUE v, const char *arg, const char *c0, const char *c1,
733
900
  return 1;
734
901
  }
735
902
  rb_raise(rb_eArgError, "%s: unknown %s :%"PRIsVALUE" (expected :%s or :%s)",
736
- nm, arg, rb_id2str(id), c0, c1);
903
+ name ? name : ca_calling_method_name(), arg, rb_id2str(id), c0, c1);
737
904
  return 0;
738
905
  }
739
906
 
@@ -771,12 +938,21 @@ ca_reduce_fill (VALUE result, VALUE fill, int whole)
771
938
  if ( ca_has_mask(cr) ) {
772
939
  result = rb_ca_mask_fill_copy(result, fill);
773
940
  }
941
+ else if ( cr->elements > 0 ) {
942
+ /* No cell needed the fill, but a fill the result cannot hold is
943
+ refused all the same, not only when some cell happens to be
944
+ undefined: it goes into a one-cell array of the result's kind. */
945
+ volatile VALUE one = rb_funcall(rb_funcall(result, rb_intern("flatten"), 0),
946
+ rb_intern("[]"), 1,
947
+ rb_range_new(INT2FIX(0), INT2FIX(0), 0));
948
+ rb_ca_store_addr(rb_ca_template(one), 0, fill);
949
+ }
774
950
  return whole ? rb_ca_fetch_addr(result, 0) : result;
775
951
  }
776
952
  return ( result == CA_UNDEF ) ? fill : result;
777
953
  }
778
954
 
779
- /* CArray.__reduce_fill__(result, fill_value): ca_reduce_fill for a
955
+ /* CArray.__fill_undefined_result_cells__(result, fill_value): ca_reduce_fill for a
780
956
  reduction written in Ruby. A fill_value of nil or UNDEF leaves the
781
957
  undefined cells as they are. */
782
958
  static VALUE
@@ -817,6 +993,38 @@ rb_ca_normalize_axis_for_ndim (long raw, int ndim, const char *name)
817
993
  return (int) axis;
818
994
  }
819
995
 
996
+ /* An array has at most CA_RANK_MAX axes, and every dim[] and strides[]
997
+ array in the library is that long. A constructor or view whose result
998
+ would have more -- a shape given, a rank computed -- calls this before it
999
+ writes a single dim, and is refused with ArgumentError naming the method,
1000
+ the rank and the limit. `name` NULL names the method the user called. */
1001
+ void
1002
+ ca_check_rank_fits (long ndim, const char *name)
1003
+ {
1004
+ if ( ndim > CA_RANK_MAX ) {
1005
+ rb_raise(rb_eArgError, "%s: ndim %ld exceeds CA_RANK_MAX %d",
1006
+ name ? name : ca_calling_method_name(), ndim, CA_RANK_MAX);
1007
+ }
1008
+ }
1009
+
1010
+ /* The axis an `axis` argument names among `ndim` axes: the one rule every
1011
+ entry that takes an axis from Ruby keeps. An Integer, negative counting
1012
+ from the end; anything else raises TypeError, and an Integer outside
1013
+ [-ndim, ndim) raises ArgumentError naming the value given -- a Bignum
1014
+ too, since no ndim reaches it. `name` and the insertion-position use of
1015
+ `ndim` are as for rb_ca_normalize_axis_for_ndim. */
1016
+ int
1017
+ ca_normalize_axis_arg (VALUE raxis, int ndim, const char *name)
1018
+ {
1019
+ ca_check_rank_fits(ndim, name); /* no array has the axes to name */
1020
+ if ( RB_INTEGER_TYPE_P(raxis) && ! RB_FIXNUM_P(raxis) ) {
1021
+ rb_raise(rb_eArgError,
1022
+ "%s: axis %"PRIsVALUE" out of range for ndim %d",
1023
+ name ? name : ca_calling_method_name(), raxis, ndim);
1024
+ }
1025
+ return rb_ca_normalize_axis_for_ndim(ca_axis_integer(raxis, name), ndim, name);
1026
+ }
1027
+
820
1028
  /* Self-bound wrapper: delegate to the kernel using self.ndim. Kept
821
1029
  for backward compatibility with the existing instance method
822
1030
  `CArray#normalize_axis`. */
@@ -825,7 +1033,7 @@ rb_ca_normalize_axis_value (VALUE self, VALUE raxis, const char *name)
825
1033
  {
826
1034
  CArray *ca;
827
1035
  GetCArray(self, ca);
828
- return rb_ca_normalize_axis_for_ndim(ca_axis_integer(raxis, name), (int) ca->ndim, name);
1036
+ return ca_normalize_axis_arg(raxis, (int) ca->ndim, name);
829
1037
  }
830
1038
 
831
1039
  /* Ruby-facing `CArray#normalize_axis(axis, name=nil)` — returns the
@@ -860,7 +1068,7 @@ rb_ca_s_normalize_axis (int argc, VALUE *argv, VALUE klass)
860
1068
  int k;
861
1069
  rb_scan_args(argc, argv, "21", &raxis, &rndim, &rname);
862
1070
  name = NIL_P(rname) ? NULL : StringValueCStr(rname);
863
- k = rb_ca_normalize_axis_for_ndim(ca_axis_integer(raxis, name), NUM2INT(rndim), name);
1071
+ k = ca_normalize_axis_arg(raxis, NUM2INT(rndim), name);
864
1072
  return INT2NUM(k);
865
1073
  }
866
1074
 
@@ -880,7 +1088,7 @@ rb_ca_normalize_axes (int argc, VALUE *argv, VALUE self)
880
1088
  const char *name;
881
1089
 
882
1090
  rb_scan_args(argc, argv, "11", &raxes, &rname);
883
- name = NIL_P(rname) ? ca_calling_method_name() : StringValueCStr(rname);
1091
+ name = NIL_P(rname) ? NULL : StringValueCStr(rname); /* NULL: looked up on error */
884
1092
  GetCArray(self, ca);
885
1093
 
886
1094
  if ( NIL_P(raxes) ) {
@@ -941,7 +1149,8 @@ rb_ca_guess_type (VALUE obj)
941
1149
  /* Check before narrowing to int8_t, so the message names the id given. */
942
1150
  long id = FIX2LONG(obj);
943
1151
  if ( id <= CA_NONE || id >= CA_NTYPE ) {
944
- rb_raise(rb_eArgError, "invalid data_type id %ld", id);
1152
+ rb_raise(rb_eArgError, "%s: invalid data_type id %ld",
1153
+ ca_calling_method_name(), id);
945
1154
  }
946
1155
  return (int8_t) id;
947
1156
  }
@@ -968,7 +1177,8 @@ rb_ca_guess_type (VALUE obj)
968
1177
 
969
1178
  inspect = rb_inspect(obj);
970
1179
  rb_raise(rb_eArgError,
971
- "<%s> is unknown data_type representation", StringValuePtr(inspect));
1180
+ "%s: <%s> is unknown data_type representation",
1181
+ ca_calling_method_name(), StringValuePtr(inspect));
972
1182
  }
973
1183
 
974
1184
  void
@@ -991,7 +1201,7 @@ rb_ca_guess_type_and_bytes (VALUE rtype, VALUE rbytes,
991
1201
  }
992
1202
  }
993
1203
  else {
994
- CA_CHECK_DATA_TYPE(*data_type);
1204
+ CA_CHECK_DATA_TYPE_GIVEN(*data_type);
995
1205
  *bytes = ca_sizeof[*data_type];
996
1206
  }
997
1207
  }
@@ -1068,11 +1278,36 @@ rb_hash_has_key(VALUE hash, VALUE key)
1068
1278
  return Qfalse;
1069
1279
  }
1070
1280
 
1281
+ /* The next comma-separated key of a spec, its length in *len, or NULL
1282
+ past the last key. The spec is read in place: a copy to cut up would
1283
+ be a C allocation, and its failure has nowhere to go but to drop every
1284
+ keyword. */
1285
+ static const char *
1286
+ option_key (const char **sp, long *len)
1287
+ {
1288
+ const char *p = *sp, *end;
1289
+
1290
+ if ( p == NULL ) {
1291
+ return NULL;
1292
+ }
1293
+ end = strchr(p, ',');
1294
+ if ( end ) {
1295
+ *len = end - p;
1296
+ *sp = end + 1;
1297
+ }
1298
+ else {
1299
+ *len = (long) strlen(p);
1300
+ *sp = NULL;
1301
+ }
1302
+ return p;
1303
+ }
1304
+
1071
1305
  void
1072
1306
  rb_scan_options (VALUE ropt, const char *spec_in, ...)
1073
1307
  {
1074
1308
  VALUE *vp;
1075
- char *sp, *tok, *spec;
1309
+ const char *sp, *tok;
1310
+ long len;
1076
1311
  int has_option = 0;
1077
1312
  va_list vals;
1078
1313
 
@@ -1087,22 +1322,19 @@ rb_scan_options (VALUE ropt, const char *spec_in, ...)
1087
1322
  }
1088
1323
 
1089
1324
  va_start(vals, spec_in);
1090
- sp = spec = strdup(spec_in);
1091
- tok = strsep1(&sp, ',');
1092
- while ( tok != NULL ) {
1325
+ sp = spec_in;
1326
+ while ( ( tok = option_key(&sp, &len) ) != NULL ) {
1093
1327
  vp = va_arg(vals, VALUE*);
1094
1328
  if ( has_option ) {
1095
- VALUE key = ID2SYM(rb_intern(tok));
1329
+ VALUE key = ID2SYM(rb_intern2(tok, len));
1096
1330
  if ( rb_hash_has_key(ropt, key) ) {
1097
1331
  *vp = rb_hash_aref(ropt, key);
1098
1332
  }
1099
1333
  /* key absent: leave *vp unchanged (caller's pre-initialized default) */
1100
1334
  }
1101
1335
  /* opts == Qnil: leave all *vp unchanged */
1102
- tok = strsep1(&sp, ',');
1103
1336
  }
1104
1337
  va_end(vals);
1105
- free(spec);
1106
1338
 
1107
1339
  /* Strict: reject any key not named in spec, matching Ruby's native
1108
1340
  keyword-argument behaviour ("unknown keyword: :foo"). Every call
@@ -1115,15 +1347,12 @@ rb_scan_options (VALUE ropt, const char *spec_in, ...)
1115
1347
  VALUE key = rb_ary_entry(keys, i);
1116
1348
  VALUE kname = SYMBOL_P(key) ? rb_sym2str(key) : rb_obj_as_string(key);
1117
1349
  const char *kn = StringValueCStr(kname);
1118
- char *sp2, *tok2, *spec2;
1350
+ long kn_len = RSTRING_LEN(kname);
1119
1351
  int found = 0;
1120
- sp2 = spec2 = strdup(spec_in);
1121
- tok2 = strsep1(&sp2, ',');
1122
- while ( tok2 != NULL ) {
1123
- if ( strcmp(tok2, kn) == 0 ) { found = 1; break; }
1124
- tok2 = strsep1(&sp2, ',');
1352
+ sp = spec_in;
1353
+ while ( ( tok = option_key(&sp, &len) ) != NULL ) {
1354
+ if ( len == kn_len && memcmp(tok, kn, len) == 0 ) { found = 1; break; }
1125
1355
  }
1126
- free(spec2);
1127
1356
  if ( ! found ) {
1128
1357
  rb_raise(rb_eArgError, "unknown keyword: %"PRIsVALUE, rb_inspect(key));
1129
1358
  }
@@ -1156,7 +1385,8 @@ void
1156
1385
  rb_set_options (VALUE ropt, const char *spec_in, ...)
1157
1386
  {
1158
1387
  VALUE rval;
1159
- char *sp, *tok, *spec;
1388
+ const char *sp, *tok;
1389
+ long len;
1160
1390
  int has_option = 0;
1161
1391
  va_list vals;
1162
1392
 
@@ -1171,27 +1401,38 @@ rb_set_options (VALUE ropt, const char *spec_in, ...)
1171
1401
  }
1172
1402
 
1173
1403
  va_start(vals, spec_in);
1174
- sp = spec = strdup(spec_in);
1175
- tok = strsep1(&sp, ',');
1176
- while ( tok != NULL ) {
1404
+ sp = spec_in;
1405
+ while ( ( tok = option_key(&sp, &len) ) != NULL ) {
1177
1406
  rval = va_arg(vals, VALUE);
1178
1407
  if ( has_option ) {
1179
- rb_hash_aset(ropt, ID2SYM(rb_intern(tok)), rval);
1408
+ rb_hash_aset(ropt, ID2SYM(rb_intern2(tok, len)), rval);
1180
1409
  }
1181
- tok = strsep1(&sp, ',');
1182
1410
  }
1183
1411
  va_end(vals);
1184
- free(spec);
1185
1412
 
1186
1413
  return;
1187
1414
  }
1188
1415
 
1189
1416
 
1417
+ /* Whether this runs in the main Ractor: Init does, and leaves a value in
1418
+ its Ractor-local storage that no other Ractor has. */
1419
+ static rb_ractor_local_key_t ca_main_ractor_key;
1420
+
1421
+ int
1422
+ ca_in_main_ractor (void)
1423
+ {
1424
+ VALUE mark;
1425
+ return rb_ractor_local_storage_value_lookup(ca_main_ractor_key, &mark);
1426
+ }
1427
+
1190
1428
  void
1191
1429
  Init_carray_utils (void)
1192
1430
  {
1431
+ ca_main_ractor_key = rb_ractor_local_storage_value_newkey();
1432
+ rb_ractor_local_storage_value_set(ca_main_ractor_key, Qtrue);
1193
1433
  ca_id_names = st_init_numtable();
1194
1434
  rb_nativethread_lock_initialize(&ca_id_names_lock);
1435
+ id_answering = rb_intern("__carray_answering_method__");
1195
1436
  id_begin = rb_intern("begin");
1196
1437
  id_end = rb_intern("end");
1197
1438
  id_excl_end = rb_intern("exclude_end?");
@@ -1203,11 +1444,13 @@ Init_carray_utils (void)
1203
1444
  rb_define_method(rb_cCArray, "normalize_axes", rb_ca_normalize_axes, -1);
1204
1445
  rb_define_singleton_method(rb_cCArray, "normalize_axis",
1205
1446
  rb_ca_s_normalize_axis, -1);
1206
- rb_define_singleton_method(rb_cCArray, "__min_count_need__",
1447
+ rb_define_singleton_method(rb_cCArray, "__present_cells_needed_per_result_cell__",
1207
1448
  rb_ca_s_min_count_need, 3);
1208
- rb_define_singleton_method(rb_cCArray, "__reduce_fill__",
1449
+ rb_define_singleton_method(rb_cCArray, "__fill_undefined_result_cells__",
1209
1450
  rb_ca_s_reduce_fill, 2);
1210
- rb_define_singleton_method(rb_cCArray, "__answer_as__",
1451
+ rb_define_private_method(rb_singleton_class(rb_cCArray), "library_root=",
1452
+ rb_ca_s_set_library_root, 1);
1453
+ rb_define_singleton_method(rb_cCArray, "__name_errors_after_method__",
1211
1454
  rb_ca_s_answer_as, 1);
1212
1455
 
1213
1456
  }