carray 2.0.1 → 3.0.0

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 (339) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +5 -25
  3. data/CHANGELOG.md +16 -0
  4. data/LICENSE +1 -1
  5. data/NEWS.md +3 -0
  6. data/README.md +128 -44
  7. data/carray.gemspec +22 -24
  8. data/ext/ca_array_pool.c +91 -0
  9. data/ext/ca_axis_descriptor.h +186 -0
  10. data/ext/ca_axis_dispatch.c +924 -0
  11. data/ext/ca_axis_group.c +1208 -0
  12. data/ext/ca_bincmp_dispatch.c +76 -0
  13. data/ext/ca_bincmp_dispatch.h +85 -0
  14. data/ext/ca_binop_dispatch.c +125 -0
  15. data/ext/ca_binop_dispatch.h +159 -0
  16. data/ext/ca_categorical_iterator.c +1375 -0
  17. data/ext/ca_compare.c +94 -0
  18. data/ext/ca_compare.h +26 -0
  19. data/ext/ca_composite_dispatch.c +414 -0
  20. data/ext/ca_composite_dispatch.h +116 -0
  21. data/ext/ca_for_buffer.h +96 -0
  22. data/ext/ca_for_each_element.h +241 -0
  23. data/ext/ca_group_iter.c +304 -0
  24. data/ext/ca_iter_substrate.h +325 -0
  25. data/ext/ca_kernel_iterator.c +4321 -0
  26. data/ext/ca_kernel_iterator.h +2603 -0
  27. data/ext/ca_moncmp_dispatch.c +37 -0
  28. data/ext/ca_moncmp_dispatch.h +62 -0
  29. data/ext/ca_monop_dispatch.c +200 -0
  30. data/ext/ca_monop_dispatch.h +235 -0
  31. data/ext/ca_obj_array.c +355 -359
  32. data/ext/ca_obj_bincmp.c +809 -0
  33. data/ext/ca_obj_binop.c +892 -0
  34. data/ext/ca_obj_bitarray.c +369 -164
  35. data/ext/ca_obj_bitfield.c +294 -234
  36. data/ext/ca_obj_block.c +189 -711
  37. data/ext/ca_obj_byte_swap.c +766 -0
  38. data/ext/ca_obj_const_string.c +965 -0
  39. data/ext/ca_obj_face.c +670 -0
  40. data/ext/ca_obj_face.h +247 -0
  41. data/ext/ca_obj_fake.c +228 -100
  42. data/ext/ca_obj_farray.c +54 -441
  43. data/ext/ca_obj_field.c +82 -529
  44. data/ext/ca_obj_fixlen_string.c +306 -0
  45. data/ext/ca_obj_grid.c +858 -440
  46. data/ext/ca_obj_meld.c +1034 -0
  47. data/ext/ca_obj_moncmp.c +569 -0
  48. data/ext/ca_obj_monop.c +1111 -0
  49. data/ext/ca_obj_object.c +772 -297
  50. data/ext/ca_obj_record.c +468 -0
  51. data/ext/ca_obj_reduce.c +97 -82
  52. data/ext/ca_obj_refer.c +569 -459
  53. data/ext/ca_obj_remap.c +475 -0
  54. data/ext/ca_obj_repeat.c +92 -477
  55. data/ext/ca_obj_roll.c +616 -0
  56. data/ext/ca_obj_select.c +344 -296
  57. data/ext/ca_obj_select_axis.c +1296 -0
  58. data/ext/ca_obj_shift.c +229 -791
  59. data/ext/ca_obj_source.c +78 -0
  60. data/ext/ca_obj_stack.c +1173 -0
  61. data/ext/ca_obj_stride.c +2501 -0
  62. data/ext/ca_obj_string.c +268 -0
  63. data/ext/ca_obj_tile.c +614 -0
  64. data/ext/ca_obj_time.c +546 -0
  65. data/ext/ca_obj_timedelta.c +435 -0
  66. data/ext/ca_obj_transpose.c +62 -516
  67. data/ext/ca_obj_triop.c +746 -0
  68. data/ext/ca_obj_unbound_repeat.c +207 -240
  69. data/ext/ca_obj_window.c +1131 -563
  70. data/ext/ca_op_byte_swap.c +175 -0
  71. data/ext/ca_op_ipower.c +319 -0
  72. data/ext/ca_op_powi.h +88 -0
  73. data/ext/ca_sort_kernels.h +132 -0
  74. data/ext/ca_sweep_engine.c +430 -0
  75. data/ext/ca_sweep_engine.h +157 -0
  76. data/ext/ca_transform_common.c +228 -0
  77. data/ext/ca_triop_dispatch.c +55 -0
  78. data/ext/ca_triop_dispatch.h +62 -0
  79. data/ext/carray.h +795 -402
  80. data/ext/carray_access.c +831 -711
  81. data/ext/carray_attribute.c +98 -329
  82. data/ext/carray_bincount.c +255 -0
  83. data/ext/carray_broadcast.c +283 -0
  84. data/ext/carray_call_cfunc.c +1360 -828
  85. data/ext/carray_call_cfunc.h +160 -0
  86. data/ext/carray_cast.c +1212 -301
  87. data/ext/carray_cast_func.rb +81 -40
  88. data/ext/carray_class.c +53 -63
  89. data/ext/carray_config.h +28 -0
  90. data/ext/carray_conversion.c +350 -346
  91. data/ext/carray_copy.c +156 -268
  92. data/ext/carray_core.c +1341 -198
  93. data/ext/carray_count.c +312 -0
  94. data/ext/carray_data_type.c +43 -19
  95. data/ext/carray_element.c +585 -213
  96. data/ext/carray_factorize.c +2542 -0
  97. data/ext/carray_generate.c +230 -559
  98. data/ext/carray_histogram.c +490 -0
  99. data/ext/carray_hold.c +228 -0
  100. data/ext/carray_index_classifier.c +1035 -0
  101. data/ext/carray_index_classifier.h +27 -0
  102. data/ext/carray_internal.h +120 -0
  103. data/ext/carray_kernels_bincmp.c +4445 -0
  104. data/ext/carray_kernels_binop.c +10979 -0
  105. data/ext/carray_kernels_init.c +36 -0
  106. data/ext/carray_kernels_map.c +3466 -0
  107. data/ext/carray_kernels_moncmp.c +2096 -0
  108. data/ext/carray_kernels_monop.c +18312 -0
  109. data/ext/carray_kernels_reduce_aggregate.c +25836 -0
  110. data/ext/carray_kernels_reduce_boolean.c +329 -0
  111. data/ext/carray_kernels_reduce_cumulative.c +14592 -0
  112. data/ext/carray_kernels_reduce_extreme.c +16947 -0
  113. data/ext/carray_kernels_reduce_variance.c +3909 -0
  114. data/ext/carray_kernels_scan.c +3692 -0
  115. data/ext/carray_kernels_search.c +32137 -0
  116. data/ext/carray_kernels_sort.c +10625 -0
  117. data/ext/carray_kernels_triop.c +1391 -0
  118. data/ext/carray_lazy.c +567 -0
  119. data/ext/carray_loop.c +88 -200
  120. data/ext/carray_mask.c +848 -154
  121. data/ext/carray_math_kernel.h +120 -0
  122. data/ext/carray_mathfunc.c +10 -241
  123. data/ext/carray_median_percentile.c +1257 -0
  124. data/ext/carray_memory_view.c +1625 -0
  125. data/ext/carray_operator.c +1526 -318
  126. data/ext/carray_order.c +664 -1394
  127. data/ext/carray_partition.c +416 -0
  128. data/ext/carray_random.c +518 -0
  129. data/ext/carray_scatter.c +357 -0
  130. data/ext/carray_slab.c +1219 -0
  131. data/ext/carray_slab.h +84 -0
  132. data/ext/carray_sort.c +829 -0
  133. data/ext/carray_sort_kernel.c +620 -0
  134. data/ext/carray_struct.c +695 -0
  135. data/ext/carray_test.c +343 -229
  136. data/ext/carray_undef.c +34 -17
  137. data/ext/carray_utils.c +175 -74
  138. data/ext/extconf.rb +216 -55
  139. data/ext/mk_call_cfunc.rb +480 -0
  140. data/ext/mkkernel.rb +8842 -0
  141. data/ext/ruby_carray.c +202 -101
  142. data/ext/version.h +5 -15
  143. data/ext/version.rb +5 -13
  144. data/lib/carray/arrow_tensor.rb +401 -0
  145. data/lib/carray/attribute.rb +166 -0
  146. data/lib/carray/autoload_carray.rb +220 -0
  147. data/lib/carray/autoload_method_extension.rb +44 -0
  148. data/lib/carray/axis_group.rb +711 -0
  149. data/lib/carray/basics.rb +481 -0
  150. data/lib/carray/bincount_nd.rb +358 -0
  151. data/lib/carray/block_iterator.rb +604 -0
  152. data/lib/carray/boolean_reduce.rb +109 -0
  153. data/lib/carray/categorical.rb +561 -0
  154. data/lib/carray/categorical_iterator.rb +1062 -0
  155. data/lib/carray/complex.rb +150 -0
  156. data/lib/carray/conditional.rb +216 -0
  157. data/lib/carray/const_string.rb +228 -0
  158. data/lib/carray/construct.rb +139 -328
  159. data/lib/carray/core_extensions.rb +240 -0
  160. data/lib/carray/data_type_extension.rb +233 -0
  161. data/lib/carray/fixlen_string.rb +95 -0
  162. data/lib/carray/frame/concat.rb +132 -0
  163. data/lib/carray/frame/convert.rb +95 -0
  164. data/lib/carray/frame/csv_parser.rb +211 -0
  165. data/lib/carray/frame/frame.rb +649 -0
  166. data/lib/carray/frame/group.rb +186 -0
  167. data/lib/carray/frame/io.rb +164 -0
  168. data/lib/carray/frame/join.rb +248 -0
  169. data/lib/carray/frame/records.rb +99 -0
  170. data/lib/carray/frame/sort.rb +113 -0
  171. data/lib/carray/frame/verbs.rb +299 -0
  172. data/lib/carray/frame.rb +16 -0
  173. data/lib/carray/histogram.rb +512 -0
  174. data/lib/carray/inspect.rb +37 -20
  175. data/lib/carray/iterator.rb +57 -349
  176. data/lib/carray/lazy.rb +889 -0
  177. data/lib/carray/mask_gap_fill.rb +200 -0
  178. data/lib/carray/math.rb +78 -342
  179. data/lib/carray/meld_reduce.rb +289 -0
  180. data/lib/carray/methods/align_addr.rb +116 -0
  181. data/lib/carray/methods/bin.rb +128 -0
  182. data/lib/carray/methods/bincount.rb +87 -0
  183. data/lib/carray/methods/bit_string.rb +92 -0
  184. data/lib/carray/methods/broadcast.rb +63 -0
  185. data/lib/carray/methods/choose.rb +39 -0
  186. data/lib/carray/methods/composition.rb +280 -0
  187. data/lib/carray/methods/gather_nd.rb +206 -0
  188. data/lib/carray/methods/index.rb +39 -0
  189. data/lib/carray/methods/insert_block.rb +99 -0
  190. data/lib/carray/methods/is_in.rb +141 -0
  191. data/lib/carray/methods/join.rb +90 -0
  192. data/lib/carray/methods/locate_addr.rb +47 -0
  193. data/lib/carray/methods/mask_duplicates.rb +41 -0
  194. data/lib/carray/methods/meshgrid.rb +91 -0
  195. data/lib/carray/methods/mode.rb +126 -0
  196. data/lib/carray/methods/nunique.rb +46 -0
  197. data/lib/carray/methods/resize.rb +56 -0
  198. data/lib/carray/methods/snap.rb +156 -0
  199. data/lib/carray/methods/string_format.rb +57 -0
  200. data/lib/carray/methods/unique.rb +47 -0
  201. data/lib/carray/methods/value_counts.rb +71 -0
  202. data/lib/carray/mkmf.rb +124 -101
  203. data/lib/carray/runtime.rb +108 -0
  204. data/lib/carray/serialize.rb +478 -167
  205. data/lib/carray/slab_iterator.rb +292 -0
  206. data/lib/carray/stack.rb +291 -0
  207. data/lib/carray/string.rb +56 -180
  208. data/lib/carray/string_operation_extension.rb +289 -0
  209. data/lib/carray/struct.rb +335 -323
  210. data/lib/carray/struct_builder.rb +697 -0
  211. data/lib/carray/table.rb +41 -2
  212. data/lib/carray/time.rb +2255 -38
  213. data/lib/carray/window_iterator.rb +655 -0
  214. data/lib/carray.rb +55 -57
  215. metadata +163 -130
  216. data/Rakefile +0 -51
  217. data/TODO.md +0 -18
  218. data/ext/ca_iter_block.c +0 -257
  219. data/ext/ca_iter_dimension.c +0 -299
  220. data/ext/ca_iter_window.c +0 -214
  221. data/ext/ca_obj_mapping.c +0 -644
  222. data/ext/carray_iterator.c +0 -641
  223. data/ext/carray_math.rb +0 -850
  224. data/ext/carray_numeric.c +0 -259
  225. data/ext/carray_sort_addr.c +0 -254
  226. data/ext/carray_stat.c +0 -2100
  227. data/ext/carray_stat_proc.rb +0 -1999
  228. data/ext/mkmath.rb +0 -741
  229. data/ext/ruby_ccomplex.c +0 -509
  230. data/ext/ruby_float_func.c +0 -86
  231. data/lib/carray/array.rb +0 -8
  232. data/lib/carray/autoload/autoload_base.rb +0 -19
  233. data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
  234. data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
  235. data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
  236. data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
  237. data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
  238. data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
  239. data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
  240. data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
  241. data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
  242. data/lib/carray/autoload/autoload_gem_random.rb +0 -8
  243. data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
  244. data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
  245. data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
  246. data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
  247. data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
  248. data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
  249. data/lib/carray/autoload/autoload_object_link.rb +0 -1
  250. data/lib/carray/autoload/autoload_object_pack.rb +0 -2
  251. data/lib/carray/autoload.rb +0 -141
  252. data/lib/carray/basic.rb +0 -191
  253. data/lib/carray/broadcast.rb +0 -101
  254. data/lib/carray/compose.rb +0 -315
  255. data/lib/carray/convert.rb +0 -115
  256. data/lib/carray/info.rb +0 -110
  257. data/lib/carray/io/imagemagick.rb +0 -235
  258. data/lib/carray/mask.rb +0 -102
  259. data/lib/carray/math/histogram.rb +0 -177
  260. data/lib/carray/math/recurrence.rb +0 -93
  261. data/lib/carray/object/ca_obj_iterator.rb +0 -50
  262. data/lib/carray/object/ca_obj_link.rb +0 -50
  263. data/lib/carray/object/ca_obj_pack.rb +0 -99
  264. data/lib/carray/obsolete.rb +0 -256
  265. data/lib/carray/ordering.rb +0 -181
  266. data/lib/carray/testing.rb +0 -51
  267. data/lib/carray/transform.rb +0 -109
  268. data/mailmap +0 -1
  269. data/misc/Methods.ja.md +0 -182
  270. data/misc/NOTE +0 -51
  271. data/spec/Classes/CABitfield_spec.rb +0 -58
  272. data/spec/Classes/CABlockIterator_spec.rb +0 -114
  273. data/spec/Classes/CABlock_spec.rb +0 -205
  274. data/spec/Classes/CAField_spec.rb +0 -39
  275. data/spec/Classes/CAGrid_spec.rb +0 -75
  276. data/spec/Classes/CAMap_spec.rb +0 -0
  277. data/spec/Classes/CAMapping_spec.rb +0 -105
  278. data/spec/Classes/CAObject_attribute_spec.rb +0 -33
  279. data/spec/Classes/CAObject_spec.rb +0 -33
  280. data/spec/Classes/CARefer_spec.rb +0 -93
  281. data/spec/Classes/CARepeat_spec.rb +0 -65
  282. data/spec/Classes/CASelect_spec.rb +0 -22
  283. data/spec/Classes/CAShift_spec.rb +0 -16
  284. data/spec/Classes/CAStruct_spec.rb +0 -71
  285. data/spec/Classes/CATranspose_spec.rb +0 -60
  286. data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
  287. data/spec/Classes/CAWindow_spec.rb +0 -54
  288. data/spec/Classes/CAWrap_spec.rb +0 -8
  289. data/spec/Classes/CArray_spec.rb +0 -184
  290. data/spec/Classes/CScalar_spec.rb +0 -55
  291. data/spec/Features/feature_130_spec.rb +0 -19
  292. data/spec/Features/feature_attributes_spec.rb +0 -280
  293. data/spec/Features/feature_boolean_spec.rb +0 -98
  294. data/spec/Features/feature_broadcast.rb +0 -116
  295. data/spec/Features/feature_cast_function.rb +0 -19
  296. data/spec/Features/feature_cast_spec.rb +0 -33
  297. data/spec/Features/feature_class_spec.rb +0 -84
  298. data/spec/Features/feature_complex_spec.rb +0 -42
  299. data/spec/Features/feature_composite_spec.rb +0 -124
  300. data/spec/Features/feature_convert_spec.rb +0 -46
  301. data/spec/Features/feature_copy_spec.rb +0 -123
  302. data/spec/Features/feature_creation_spec.rb +0 -84
  303. data/spec/Features/feature_element_spec.rb +0 -144
  304. data/spec/Features/feature_extream_spec.rb +0 -54
  305. data/spec/Features/feature_generate_spec.rb +0 -74
  306. data/spec/Features/feature_index_spec.rb +0 -69
  307. data/spec/Features/feature_mask_spec.rb +0 -580
  308. data/spec/Features/feature_math_spec.rb +0 -97
  309. data/spec/Features/feature_order_spec.rb +0 -146
  310. data/spec/Features/feature_ref_store_spec.rb +0 -209
  311. data/spec/Features/feature_serialization_spec.rb +0 -125
  312. data/spec/Features/feature_stat_spec.rb +0 -397
  313. data/spec/Features/feature_virtual_spec.rb +0 -48
  314. data/spec/Features/method_eq_spec.rb +0 -81
  315. data/spec/Features/method_is_nan_spec.rb +0 -12
  316. data/spec/Features/method_map_spec.rb +0 -54
  317. data/spec/Features/method_max_with.rb +0 -20
  318. data/spec/Features/method_min_with.rb +0 -19
  319. data/spec/Features/method_ne_spec.rb +0 -18
  320. data/spec/Features/method_project_spec.rb +0 -188
  321. data/spec/Features/method_ref_spec.rb +0 -27
  322. data/spec/Features/method_round_spec.rb +0 -11
  323. data/spec/Features/method_s_linspace_spec.rb +0 -48
  324. data/spec/Features/method_s_span_spec.rb +0 -14
  325. data/spec/Features/method_seq_spec.rb +0 -47
  326. data/spec/Features/method_sort_with.rb +0 -43
  327. data/spec/Features/method_sorted_with.rb +0 -29
  328. data/spec/Features/method_span_spec.rb +0 -42
  329. data/spec/Features/method_wrap_readonly_spec.rb +0 -43
  330. data/spec/UnitTest/test_CAVirtual.rb +0 -214
  331. data/spec/spec_all.rb +0 -10
  332. data/utils/ca_ase.rb +0 -21
  333. data/utils/ca_methods.rb +0 -15
  334. data/utils/cast_checker.rb +0 -30
  335. data/utils/convert_test.rb +0 -73
  336. data/utils/extract_yard.rb +0 -22
  337. data/utils/guess_shape.rb +0 -76
  338. data/utils/monkey_patch_methods.rb +0 -62
  339. data/utils/remove_resource_fork.sh +0 -5
data/ext/carray_undef.c CHANGED
@@ -1,10 +1,19 @@
1
1
  /* ---------------------------------------------------------------------------
2
2
 
3
- carray_undef.c
3
+ UNDEF sentinel value: the single instance of UndefClass exported as
4
+ the top-level constant `UNDEF`. Used by mask-bearing CArray APIs
5
+ to mean "masked / no value here" without choosing a numeric sentinel
6
+ (NaN / -1 / etc.) that might collide with valid data.
4
7
 
5
- This file is part of Ruby/CArray extension library.
8
+ Identity semantics: every reference to UNDEF is the same Ruby object;
9
+ C code compares with raw pointer equality (`rval == CA_UNDEF`). The
10
+ GC pin in Init_carray_undef guarantees the pointer stays valid even
11
+ under Ruby 3+ compacting GC.
6
12
 
7
- Copyright (C) 2005-2025 Hiroki Motoyoshi
13
+ Coercion asymmetry: to_s / inspect return the literal string "UNDEF"
14
+ (display works), but to_f / to_i / to_int raise TypeError (numeric
15
+ coercion is rejected so accidental arithmetic on UNDEF surfaces as
16
+ an error rather than silently producing 0 / NaN).
8
17
 
9
18
  ---------------------------------------------------------------------------- */
10
19
 
@@ -14,46 +23,54 @@ static VALUE rb_cUNDEF;
14
23
 
15
24
  VALUE CA_UNDEF;
16
25
 
17
- static VALUE rb_ud_inspect (VALUE self)
26
+ static VALUE rb_ud_inspect (VALUE self)
18
27
  {
19
28
  return rb_str_new2("UNDEF");
20
29
  }
21
30
 
22
- static VALUE rb_ud_to_s (VALUE self)
31
+ static VALUE rb_ud_to_s (VALUE self)
23
32
  {
24
- /* rb_raise(rb_eTypeError, "can't coerce UNDEF into String"); */
25
33
  return rb_str_new2("UNDEF");
26
34
  }
27
35
 
28
- static VALUE rb_ud_to_f (VALUE self)
36
+ static VALUE rb_ud_to_f (VALUE self)
29
37
  {
30
38
  rb_raise(rb_eTypeError, "can't coerce UNDEF into Float");
31
- /* return rb_float_new(0.0/0.0); */
32
39
  }
33
40
 
34
- static VALUE rb_ud_to_i (VALUE self)
41
+ static VALUE rb_ud_to_i (VALUE self)
35
42
  {
36
43
  rb_raise(rb_eTypeError, "can't coerce UNDEF into Integer");
37
44
  }
38
45
 
39
- static VALUE rb_ud_equal (VALUE self, VALUE other)
46
+ static VALUE rb_ud_equal (VALUE self, VALUE other)
40
47
  {
41
48
  return ( self == other ) ? Qtrue : Qfalse;
42
49
  }
43
50
 
44
51
  void
45
- Init_carray_undef ()
52
+ Init_carray_undef (void)
46
53
  {
47
54
  rb_cUNDEF = rb_define_class("UndefClass", rb_cObject);
48
55
  rb_define_method(rb_cUNDEF, "inspect", rb_ud_inspect, 0);
49
- rb_define_method(rb_cUNDEF, "to_s", rb_ud_to_s, 0);
50
- rb_define_method(rb_cUNDEF, "to_f", rb_ud_to_f, 0);
51
- rb_define_method(rb_cUNDEF, "to_i", rb_ud_to_i, 0);
52
- rb_define_method(rb_cUNDEF, "to_int", rb_ud_to_i, 0);
53
- rb_define_method(rb_cUNDEF, "==", rb_ud_equal, 1);
56
+ rb_define_method(rb_cUNDEF, "to_s", rb_ud_to_s, 0);
57
+ rb_define_method(rb_cUNDEF, "to_f", rb_ud_to_f, 0);
58
+ rb_define_method(rb_cUNDEF, "to_i", rb_ud_to_i, 0);
59
+ rb_define_method(rb_cUNDEF, "to_int", rb_ud_to_i, 0);
60
+ rb_define_method(rb_cUNDEF, "==", rb_ud_equal, 1);
54
61
 
55
- CA_UNDEF = rb_funcall(rb_cUNDEF, rb_intern("new"), 0);
62
+ /* Singleton: instantiate once, then undef `new` so no second instance
63
+ can be created. The identity invariant relies on this. */
64
+ CA_UNDEF = rb_funcall(rb_cUNDEF, rb_intern("new"), 0);
56
65
  rb_undef_method(CLASS_OF(rb_cUNDEF), "new");
57
66
  rb_const_set(rb_cObject, rb_intern("UNDEF"), CA_UNDEF);
67
+
68
+ /* CAREFUL: CA_UNDEF is dereferenced via raw pointer compare
69
+ (`rval == CA_UNDEF`) throughout the C code, so the underlying
70
+ object must not be relocated. Constant registration above
71
+ keeps the object reachable but does not prevent compacting GC
72
+ (Ruby 2.7+) from moving it to a new address; the pin here
73
+ disables compaction for this single sentinel. */
74
+ rb_gc_register_mark_object(CA_UNDEF);
58
75
  }
59
76
 
data/ext/carray_utils.c CHANGED
@@ -1,10 +1,13 @@
1
1
  /* ---------------------------------------------------------------------------
2
2
 
3
- carray_utils.c
3
+ Utility helpers shared across the `ext/` C files: iterator setup / loop count
4
+ variadic helpers, Range parsing (`ca_parse_range` family), axis
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.
4
8
 
5
- This file is part of Ruby/CArray extension library.
6
-
7
- Copyright (C) 2005-2025 Hiroki Motoyoshi
9
+ YARD signatures live in yard-stubs/carray_utils.rb; this file
10
+ carries implementation-only prose.
8
11
 
9
12
  ---------------------------------------------------------------------------- */
10
13
 
@@ -12,11 +15,7 @@
12
15
  #include "ruby.h"
13
16
  #include "carray.h"
14
17
 
15
- #if RUBY_VERSION_CODE >= 190
16
18
  #include "ruby/st.h"
17
- #else
18
- #include "st.h"
19
- #endif
20
19
 
21
20
  static ID id_begin, id_end, id_excl_end;
22
21
  #define RANGE_BEG(r) (rb_funcall(r, id_begin, 0))
@@ -25,21 +24,8 @@ static ID id_begin, id_end, id_excl_end;
25
24
 
26
25
  /* ------------------------------------------------------------------- */
27
26
 
28
- void *
29
- malloc_with_check (size_t size)
30
- {
31
- void *ptr;
32
- ptr = xmalloc(size);
33
- if ( !ptr ) {
34
- rb_memerror();
35
- }
36
- return ptr;
37
- }
38
-
39
- /* ------------------------------------------------------------------- */
40
-
41
27
  void
42
- ca_debug () {}
28
+ ca_debug (void) {}
43
29
 
44
30
  /* ------------------------------------------------------------------- */
45
31
 
@@ -334,7 +320,7 @@ void
334
320
  ca_parse_range_without_check (VALUE arg, ca_size_t size,
335
321
  ca_size_t *poffset, ca_size_t *pcount, ca_size_t *pstep)
336
322
  {
337
- ca_size_t start, last, count, step, bound, excl;
323
+ ca_size_t start, last, count, step, excl;
338
324
 
339
325
  retry:
340
326
 
@@ -375,7 +361,6 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
375
361
  last += ( (last>=start) ? -1 : 1 );
376
362
  }
377
363
  count = (last - start)/llabs(step) + 1;
378
- bound = start + (count - 1)*step;
379
364
  *poffset = start;
380
365
  *pcount = count;
381
366
  *pstep = step;
@@ -393,7 +378,6 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
393
378
  start = 0;
394
379
  step = NUM2SIZE(arg1);
395
380
  count = (size-1)/llabs(step) + 1;
396
- bound = start + (count - 1)*step;
397
381
  *poffset = start;
398
382
  *pcount = count;
399
383
  *pstep = step;
@@ -407,7 +391,6 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
407
391
  last += ( (last>=start) ? -1 : 1 );
408
392
  }
409
393
  count = (last - start)/llabs(step) + 1;
410
- bound = start + (count - 1)*step;
411
394
  *poffset = start;
412
395
  *pcount = count;
413
396
  *pstep = step;
@@ -425,7 +408,6 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
425
408
  last += ( (last>=start) ? -1 : 1 );
426
409
  }
427
410
  count = (last - start)/llabs(step) + 1;
428
- bound = start + (count - 1)*step;
429
411
  *poffset = start;
430
412
  *pcount = count;
431
413
  *pstep = step;
@@ -434,7 +416,6 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
434
416
  else { /* [i,n] */
435
417
  start = NUM2SIZE(arg0);
436
418
  count = NUM2SIZE(arg1);
437
- bound = start + (count - 1);
438
419
  *poffset = start;
439
420
  *pcount = count;
440
421
  *pstep = 1;
@@ -444,7 +425,6 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
444
425
  start = NUM2SIZE(rb_ary_entry(arg, 0));
445
426
  count = NUM2SIZE(rb_ary_entry(arg, 1));
446
427
  step = NUM2SIZE(rb_ary_entry(arg, 2));
447
- bound = start + (count - 1)*step;
448
428
  *poffset = start;
449
429
  *pcount = count;
450
430
  *pstep = step;
@@ -502,10 +482,113 @@ ca_bounds_normalize_index (int8_t bounds, ca_size_t size0, ca_size_t k)
502
482
  }
503
483
  }
504
484
 
505
- /* @private
506
- @overload scan_float (str, fill_value=nil)
485
+ /* Self-independent kernel: normalize `raw` against `ndim`, returning a
486
+ canonical non-negative axis in [0, ndim) as int. Accepts negative
487
+ values (Python/Ruby convention: -1 => ndim-1). Raises ArgumentError
488
+ if out of range. `name` is used in the error message (e.g.
489
+ "mask_duplicates", "sum", "merge"); pass NULL to default to "axis".
490
+
491
+ For an insertion position (= valid range [0, old_ndim] inclusive),
492
+ pass `old_ndim + 1` as `ndim` so the half-open [0, ndim) check
493
+ matches the inclusive [0, old_ndim] semantics. */
494
+ int
495
+ rb_ca_normalize_axis_for_ndim (long raw, int ndim, const char *name)
496
+ {
497
+ long axis = (raw < 0) ? raw + ndim : raw;
498
+ if ( axis < 0 || axis >= ndim ) {
499
+ rb_raise(rb_eArgError,
500
+ "%s: axis %ld out of range for ndim %d",
501
+ name ? name : "axis", raw, ndim);
502
+ }
503
+ return (int) axis;
504
+ }
507
505
 
508
- */
506
+ /* Self-bound wrapper: delegate to the kernel using self.ndim. Kept
507
+ for backward compatibility with the existing instance method
508
+ `CArray#normalize_axis`. */
509
+ int
510
+ rb_ca_normalize_axis_value (VALUE self, VALUE raxis, const char *name)
511
+ {
512
+ CArray *ca;
513
+ GetCArray(self, ca);
514
+ return rb_ca_normalize_axis_for_ndim(NUM2LONG(raxis), (int) ca->ndim, name);
515
+ }
516
+
517
+ /* Ruby-facing `CArray#normalize_axis(axis, name=nil)` — returns the
518
+ * canonical non-negative axis index in [0, ndim) for `self`. Accepts
519
+ * negative `axis` interpreted as (ndim + axis). Raises ArgumentError
520
+ * on out-of-range input; `name` (if given) is embedded in the
521
+ * message. */
522
+ static VALUE
523
+ rb_ca_normalize_axis (int argc, VALUE *argv, VALUE self)
524
+ {
525
+ VALUE raxis, rname;
526
+ const char *name;
527
+ int k;
528
+ rb_scan_args(argc, argv, "11", &raxis, &rname);
529
+ name = NIL_P(rname) ? NULL : StringValueCStr(rname);
530
+ k = rb_ca_normalize_axis_value(self, raxis, name);
531
+ return INT2NUM(k);
532
+ }
533
+
534
+ /* Class-method form `CArray.normalize_axis(axis, ndim, name=nil)` —
535
+ * normalizes `axis` against an explicit `ndim` (range [0, ndim))
536
+ * without needing a CArray instance. For an insertion position
537
+ * (valid range [0, old_ndim] inclusive), pass `old_ndim + 1` as
538
+ * `ndim`. Called from class-method contexts (e.g. `CArray.stack`
539
+ * normalizing before `list[0]` is available) and from
540
+ * lib/carray/compose.rb merge / composite paths. */
541
+ static VALUE
542
+ rb_ca_s_normalize_axis (int argc, VALUE *argv, VALUE klass)
543
+ {
544
+ VALUE raxis, rndim, rname;
545
+ const char *name;
546
+ int k;
547
+ rb_scan_args(argc, argv, "21", &raxis, &rndim, &rname);
548
+ name = NIL_P(rname) ? NULL : StringValueCStr(rname);
549
+ k = rb_ca_normalize_axis_for_ndim(NUM2LONG(raxis), NUM2INT(rndim), name);
550
+ return INT2NUM(k);
551
+ }
552
+
553
+ /* Ruby-facing `CArray#normalize_axes(axes, name=nil)` — normalizes a
554
+ * multi-axis specifier to an Array<Integer> of canonical axes in
555
+ * [0, ndim), preserving input order. Accepts nil (returns the full
556
+ * axis list [0..ndim-1]), a single Integer (returns [k] after
557
+ * normalization), or an Array<Integer> (each element normalized).
558
+ * Raises on out-of-range or duplicate axes. */
559
+ static VALUE
560
+ rb_ca_normalize_axes (int argc, VALUE *argv, VALUE self)
561
+ {
562
+ VALUE raxes, rname, out;
563
+ CArray *ca;
564
+ int8_t axes_buf[CA_RANK_MAX];
565
+ int8_t naxes, i;
566
+ const char *name;
567
+
568
+ rb_scan_args(argc, argv, "11", &raxes, &rname);
569
+ name = NIL_P(rname) ? "axes" : StringValueCStr(rname);
570
+ GetCArray(self, ca);
571
+
572
+ if ( NIL_P(raxes) ) {
573
+ out = rb_ary_new_capa(ca->ndim);
574
+ for ( i = 0; i < ca->ndim; i++ ) {
575
+ rb_ary_push(out, INT2NUM(i));
576
+ }
577
+ return out;
578
+ }
579
+
580
+ naxes = rb_ca_parse_reduce_axes_kw_ctx(raxes, ca, axes_buf, name);
581
+ out = rb_ary_new_capa(naxes);
582
+ for ( i = 0; i < naxes; i++ ) {
583
+ rb_ary_push(out, INT2NUM(axes_buf[i]));
584
+ }
585
+ return out;
586
+ }
587
+
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. */
509
592
 
510
593
  static VALUE
511
594
  rb_ca_s_scan_float (int argc, VALUE *argv, VALUE self)
@@ -532,10 +615,11 @@ rb_ca_s_scan_float (int argc, VALUE *argv, VALUE self)
532
615
  }
533
616
  }
534
617
 
535
- /* @private
536
- @overload scan_int (str, fill_value=nil)
537
-
538
- */
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. */
539
623
 
540
624
  static VALUE
541
625
  rb_ca_s_scan_int (int argc, VALUE *argv, VALUE self)
@@ -578,10 +662,10 @@ static const struct {
578
662
  { "uint64", CA_UINT64 },
579
663
  { "float32", CA_FLOAT32 },
580
664
  { "float64", CA_FLOAT64 },
581
- { "float128", CA_FLOAT128 },
665
+ { "float128", CA_FLOAT128 }, /* reserved (retired in 3.0); ca_valid[12]=0 */
582
666
  { "cmplx64", CA_CMPLX64 },
583
667
  { "cmplx128", CA_CMPLX128 },
584
- { "cmplx256", CA_CMPLX256 },
668
+ { "cmplx256", CA_CMPLX256 }, /* reserved (retired in 3.0); ca_valid[15]=0 */
585
669
  { "object", CA_OBJECT },
586
670
  { "byte", CA_UINT8 },
587
671
  { "short", CA_INT16 },
@@ -710,7 +794,6 @@ strsep1(char **sp, const char sep)
710
794
  return p0;
711
795
  }
712
796
 
713
- #if RUBY_VERSION_CODE >= 220
714
797
  static VALUE
715
798
  rb_hash_has_key(VALUE hash, VALUE key)
716
799
  {
@@ -722,30 +805,6 @@ rb_hash_has_key(VALUE hash, VALUE key)
722
805
  }
723
806
  return Qfalse;
724
807
  }
725
- #else
726
- #if RUBY_VERSION_CODE >= 190
727
- static VALUE
728
- rb_hash_has_key(VALUE hash, VALUE key)
729
- {
730
- if (!RHASH(hash)->ntbl) {
731
- return Qfalse;
732
- }
733
- if (st_lookup(RHASH(hash)->ntbl, key, 0)) {
734
- return Qtrue;
735
- }
736
- return Qfalse;
737
- }
738
- #else
739
- static VALUE
740
- rb_hash_has_key (VALUE hash, VALUE key)
741
- {
742
- if (st_lookup(RHASH(hash)->tbl, key, 0) ) {
743
- return Qtrue;
744
- }
745
- return Qfalse;
746
- }
747
- #endif
748
- #endif
749
808
 
750
809
  void
751
810
  rb_scan_options (VALUE ropt, const char *spec_in, ...)
@@ -775,25 +834,62 @@ rb_scan_options (VALUE ropt, const char *spec_in, ...)
775
834
  if ( rb_hash_has_key(ropt, key) ) {
776
835
  *vp = rb_hash_aref(ropt, key);
777
836
  }
778
- else {
779
- if ( *vp != CA_NIL ) {
780
- *vp = Qnil;
781
- }
782
- }
783
- }
784
- else {
785
- if ( *vp != CA_NIL ) {
786
- *vp = Qnil;
787
- }
837
+ /* key absent: leave *vp unchanged (caller's pre-initialized default) */
788
838
  }
839
+ /* opts == Qnil: leave all *vp unchanged */
789
840
  tok = strsep1(&sp, ',');
790
841
  }
791
842
  va_end(vals);
792
843
  free(spec);
793
844
 
845
+ /* Strict: reject any key not named in spec, matching Ruby's native
846
+ keyword-argument behaviour ("unknown keyword: :foo"). Every call
847
+ site scans all of a method's accepted keys in a single call, so a
848
+ leftover key is genuinely unrecognised. */
849
+ if ( has_option && ! RHASH_EMPTY_P(ropt) ) {
850
+ VALUE keys = rb_funcall(ropt, rb_intern("keys"), 0);
851
+ long i, n = RARRAY_LEN(keys);
852
+ for ( i = 0; i < n; i++ ) {
853
+ VALUE key = rb_ary_entry(keys, i);
854
+ VALUE kname = SYMBOL_P(key) ? rb_sym2str(key) : rb_obj_as_string(key);
855
+ const char *kn = StringValueCStr(kname);
856
+ char *sp2, *tok2, *spec2;
857
+ int found = 0;
858
+ sp2 = spec2 = strdup(spec_in);
859
+ tok2 = strsep1(&sp2, ',');
860
+ while ( tok2 != NULL ) {
861
+ if ( strcmp(tok2, kn) == 0 ) { found = 1; break; }
862
+ tok2 = strsep1(&sp2, ',');
863
+ }
864
+ free(spec2);
865
+ if ( ! found ) {
866
+ rb_raise(rb_eArgError, "unknown keyword: %"PRIsVALUE, rb_inspect(key));
867
+ }
868
+ }
869
+ }
870
+
794
871
  return;
795
872
  }
796
873
 
874
+ /* For methods that take no keyword arguments at all. ropt is the trailing
875
+ Hash from rb_pop_options / rb_scan_args "*:", or Qnil when there is none.
876
+ Raises the same message Ruby raises for an unrecognised keyword
877
+ ("unknown keyword: :axis"), so a keyword passed to a positional-only
878
+ method does not surface as a TypeError from NUM2SIZE or as an
879
+ argument-count mismatch. */
880
+ void
881
+ rb_reject_options (VALUE ropt)
882
+ {
883
+ /* Table of accepted keys, empty. rb_get_kwargs declares it non-null and
884
+ reads required + optional (= 0) entries, so a one-slot dummy is enough. */
885
+ static const ID accepts_none[1] = { 0 };
886
+
887
+ if ( NIL_P(ropt) ) {
888
+ return;
889
+ }
890
+ rb_get_kwargs(ropt, accepts_none, 0, 0, NULL);
891
+ }
892
+
797
893
  void
798
894
  rb_set_options (VALUE ropt, const char *spec_in, ...)
799
895
  {
@@ -830,7 +926,7 @@ rb_set_options (VALUE ropt, const char *spec_in, ...)
830
926
 
831
927
 
832
928
  void
833
- Init_carray_utils ()
929
+ Init_carray_utils (void)
834
930
  {
835
931
  id_begin = rb_intern("begin");
836
932
  id_end = rb_intern("end");
@@ -844,5 +940,10 @@ Init_carray_utils ()
844
940
  rb_define_singleton_method(rb_cCArray, "guess_type_and_bytes",
845
941
  rb_ca_s_guess_type_and_bytes, -1);
846
942
 
943
+ rb_define_method(rb_cCArray, "normalize_axis", rb_ca_normalize_axis, -1);
944
+ rb_define_method(rb_cCArray, "normalize_axes", rb_ca_normalize_axes, -1);
945
+ rb_define_singleton_method(rb_cCArray, "normalize_axis",
946
+ rb_ca_s_normalize_axis, -1);
947
+
847
948
  }
848
949