carray 2.0.1 → 3.0.1

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 (386) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +6 -25
  3. data/CHANGELOG.md +338 -0
  4. data/{NEWS.md → CHANGELOG.v1.md} +3 -0
  5. data/LICENSE +1 -1
  6. data/README.md +120 -36
  7. data/carray.gemspec +32 -30
  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 +1244 -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 +124 -0
  15. data/ext/ca_binop_dispatch.h +152 -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 +239 -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 +4367 -0
  26. data/ext/ca_kernel_iterator.h +2596 -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 +839 -0
  33. data/ext/ca_obj_binop.c +948 -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 +967 -0
  39. data/ext/ca_obj_face.c +750 -0
  40. data/ext/ca_obj_face.h +279 -0
  41. data/ext/ca_obj_fake.c +239 -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 +308 -0
  45. data/ext/ca_obj_grid.c +866 -440
  46. data/ext/ca_obj_meld.c +1039 -0
  47. data/ext/ca_obj_moncmp.c +588 -0
  48. data/ext/ca_obj_monop.c +1123 -0
  49. data/ext/ca_obj_object.c +866 -296
  50. data/ext/ca_obj_record.c +470 -0
  51. data/ext/ca_obj_reduce.c +97 -82
  52. data/ext/ca_obj_refer.c +593 -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 +624 -0
  56. data/ext/ca_obj_select.c +344 -296
  57. data/ext/ca_obj_select_axis.c +1306 -0
  58. data/ext/ca_obj_shift.c +231 -793
  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 +2584 -0
  62. data/ext/ca_obj_string.c +270 -0
  63. data/ext/ca_obj_tile.c +622 -0
  64. data/ext/ca_obj_time.c +548 -0
  65. data/ext/ca_obj_timedelta.c +437 -0
  66. data/ext/ca_obj_transpose.c +62 -516
  67. data/ext/ca_obj_triop.c +785 -0
  68. data/ext/ca_obj_window.c +1202 -565
  69. data/ext/ca_op_byte_swap.c +175 -0
  70. data/ext/ca_op_cmplx64.h +123 -0
  71. data/ext/ca_op_ipower.c +316 -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 +473 -0
  75. data/ext/ca_sweep_engine.h +166 -0
  76. data/ext/ca_transform_common.c +235 -0
  77. data/ext/ca_triop_dispatch.c +55 -0
  78. data/ext/ca_triop_dispatch.h +62 -0
  79. data/ext/carray.h +810 -420
  80. data/ext/carray_access.c +873 -731
  81. data/ext/carray_attribute.c +98 -329
  82. data/ext/carray_bincount.c +255 -0
  83. data/ext/carray_broadcast.c +376 -0
  84. data/ext/carray_build_flags.h +3 -0
  85. data/ext/carray_call_cfunc.c +2897 -874
  86. data/ext/carray_call_cfunc.h +313 -0
  87. data/ext/carray_cast.c +1264 -315
  88. data/ext/carray_cast_func.rb +81 -40
  89. data/ext/carray_class.c +53 -63
  90. data/ext/carray_config.h +28 -0
  91. data/ext/carray_conversion.c +350 -346
  92. data/ext/carray_copy.c +168 -270
  93. data/ext/carray_core.c +1396 -206
  94. data/ext/carray_count.c +312 -0
  95. data/ext/carray_data_type.c +43 -19
  96. data/ext/carray_element.c +585 -213
  97. data/ext/carray_factorize.c +2542 -0
  98. data/ext/carray_generate.c +230 -559
  99. data/ext/carray_histogram.c +490 -0
  100. data/ext/carray_hold.c +228 -0
  101. data/ext/carray_index_classifier.c +1021 -0
  102. data/ext/carray_index_classifier.h +27 -0
  103. data/ext/carray_internal.h +136 -0
  104. data/ext/carray_kernels_bincmp.c +4446 -0
  105. data/ext/carray_kernels_binop.c +11001 -0
  106. data/ext/carray_kernels_init.c +1131 -0
  107. data/ext/carray_kernels_map.c +3467 -0
  108. data/ext/carray_kernels_moncmp.c +2097 -0
  109. data/ext/carray_kernels_monop.c +18313 -0
  110. data/ext/carray_kernels_reduce_aggregate.c +25837 -0
  111. data/ext/carray_kernels_reduce_boolean.c +330 -0
  112. data/ext/carray_kernels_reduce_cumulative.c +14593 -0
  113. data/ext/carray_kernels_reduce_extreme.c +16948 -0
  114. data/ext/carray_kernels_reduce_variance.c +3910 -0
  115. data/ext/carray_kernels_scan.c +3693 -0
  116. data/ext/carray_kernels_search.c +32138 -0
  117. data/ext/carray_kernels_sort.c +10626 -0
  118. data/ext/carray_kernels_triop.c +1392 -0
  119. data/ext/carray_lazy.c +737 -0
  120. data/ext/carray_loop.c +88 -200
  121. data/ext/carray_mask.c +853 -158
  122. data/ext/carray_math_kernel.h +120 -0
  123. data/ext/carray_mathfunc.c +10 -241
  124. data/ext/carray_median_percentile.c +1257 -0
  125. data/ext/carray_memory_view.c +1650 -0
  126. data/ext/carray_operator.c +1525 -320
  127. data/ext/carray_order.c +664 -1394
  128. data/ext/carray_partition.c +416 -0
  129. data/ext/carray_random.c +518 -0
  130. data/ext/carray_scatter.c +357 -0
  131. data/ext/carray_slab.c +1219 -0
  132. data/ext/carray_slab.h +84 -0
  133. data/ext/carray_sort.c +829 -0
  134. data/ext/carray_sort_kernel.c +620 -0
  135. data/ext/carray_struct.c +695 -0
  136. data/ext/carray_test.c +343 -229
  137. data/ext/carray_undef.c +34 -17
  138. data/ext/carray_utils.c +175 -74
  139. data/ext/extconf.rb +234 -55
  140. data/ext/mk_call_cfunc.rb +671 -0
  141. data/ext/mkkernel.rb +9096 -0
  142. data/ext/ruby_carray.c +211 -108
  143. data/ext/version.h +4 -14
  144. data/ext/version.rb +5 -13
  145. data/lib/carray/arrow_tensor.rb +401 -0
  146. data/lib/carray/attribute.rb +166 -0
  147. data/lib/carray/autoload_carray.rb +239 -0
  148. data/lib/carray/autoload_method_extension.rb +45 -0
  149. data/lib/carray/axis_group.rb +711 -0
  150. data/lib/carray/basics.rb +481 -0
  151. data/lib/carray/bincount_nd.rb +358 -0
  152. data/lib/carray/block_iterator.rb +614 -0
  153. data/lib/carray/boolean_reduce.rb +109 -0
  154. data/lib/carray/categorical.rb +561 -0
  155. data/lib/carray/categorical_iterator.rb +1084 -0
  156. data/lib/carray/complex.rb +150 -0
  157. data/lib/carray/conditional.rb +216 -0
  158. data/lib/carray/const_string.rb +228 -0
  159. data/lib/carray/construct.rb +160 -328
  160. data/lib/carray/core_extensions.rb +297 -0
  161. data/lib/carray/data_type_extension.rb +250 -0
  162. data/lib/carray/fixlen_string.rb +95 -0
  163. data/lib/carray/frame/concat.rb +132 -0
  164. data/lib/carray/frame/convert.rb +95 -0
  165. data/lib/carray/frame/csv_parser.rb +211 -0
  166. data/lib/carray/frame/frame.rb +642 -0
  167. data/lib/carray/frame/group.rb +186 -0
  168. data/lib/carray/frame/io.rb +321 -0
  169. data/lib/carray/frame/join.rb +248 -0
  170. data/lib/carray/frame/records.rb +99 -0
  171. data/lib/carray/frame/sort.rb +113 -0
  172. data/lib/carray/frame/verbs.rb +316 -0
  173. data/lib/carray/frame.rb +16 -0
  174. data/lib/carray/fuse_source.rb +123 -0
  175. data/lib/carray/fusion.rb +218 -0
  176. data/lib/carray/histogram.rb +512 -0
  177. data/lib/carray/inspect.rb +37 -26
  178. data/lib/carray/iterator.rb +58 -349
  179. data/lib/carray/lazy.rb +941 -0
  180. data/lib/carray/mask_gap_fill.rb +200 -0
  181. data/lib/carray/math.rb +78 -342
  182. data/lib/carray/meld_reduce.rb +289 -0
  183. data/lib/carray/methods/align_addr.rb +116 -0
  184. data/lib/carray/methods/bin.rb +128 -0
  185. data/lib/carray/methods/bincount.rb +87 -0
  186. data/lib/carray/methods/bit_string.rb +92 -0
  187. data/lib/carray/methods/broadcast.rb +63 -0
  188. data/lib/carray/methods/choose.rb +39 -0
  189. data/lib/carray/methods/composition.rb +280 -0
  190. data/lib/carray/methods/gather_nd.rb +206 -0
  191. data/lib/carray/methods/index.rb +39 -0
  192. data/lib/carray/methods/insert_block.rb +99 -0
  193. data/lib/carray/methods/is_in.rb +141 -0
  194. data/lib/carray/methods/join.rb +90 -0
  195. data/lib/carray/methods/locate_addr.rb +52 -0
  196. data/lib/carray/methods/mask_duplicates.rb +41 -0
  197. data/lib/carray/methods/meshgrid.rb +90 -0
  198. data/lib/carray/methods/mode.rb +126 -0
  199. data/lib/carray/methods/nunique.rb +46 -0
  200. data/lib/carray/methods/resize.rb +56 -0
  201. data/lib/carray/methods/snap.rb +161 -0
  202. data/lib/carray/methods/string_format.rb +57 -0
  203. data/lib/carray/methods/unique.rb +47 -0
  204. data/lib/carray/methods/value_counts.rb +71 -0
  205. data/lib/carray/mkmf.rb +124 -101
  206. data/lib/carray/runtime.rb +89 -0
  207. data/lib/carray/serialize.rb +478 -167
  208. data/lib/carray/slab_iterator.rb +305 -0
  209. data/lib/carray/stack.rb +291 -0
  210. data/lib/carray/string.rb +56 -180
  211. data/lib/carray/string_operation_extension.rb +289 -0
  212. data/lib/carray/struct.rb +335 -323
  213. data/lib/carray/struct_builder.rb +697 -0
  214. data/lib/carray/table.rb +41 -2
  215. data/lib/carray/time.rb +2654 -38
  216. data/lib/carray/window_iterator.rb +927 -0
  217. data/lib/carray.rb +55 -57
  218. data/yard-stubs/ca_obj_array.rb +385 -0
  219. data/yard-stubs/ca_obj_bitarray.rb +38 -0
  220. data/yard-stubs/ca_obj_bitfield.rb +43 -0
  221. data/yard-stubs/ca_obj_block.rb +73 -0
  222. data/yard-stubs/ca_obj_byte_swap.rb +56 -0
  223. data/yard-stubs/ca_obj_fake.rb +31 -0
  224. data/yard-stubs/ca_obj_farray.rb +32 -0
  225. data/yard-stubs/ca_obj_field.rb +45 -0
  226. data/yard-stubs/ca_obj_grid.rb +35 -0
  227. data/yard-stubs/ca_obj_refer.rb +72 -0
  228. data/yard-stubs/ca_obj_roll.rb +45 -0
  229. data/yard-stubs/ca_obj_shift.rb +43 -0
  230. data/yard-stubs/ca_obj_stride.rb +181 -0
  231. data/yard-stubs/ca_obj_tile.rb +29 -0
  232. data/yard-stubs/ca_obj_transpose.rb +40 -0
  233. data/yard-stubs/ca_obj_window.rb +49 -0
  234. data/yard-stubs/carray_access.rb +131 -0
  235. data/yard-stubs/carray_attribute.rb +246 -0
  236. data/yard-stubs/carray_broadcast.rb +37 -0
  237. data/yard-stubs/carray_cast.rb +489 -0
  238. data/yard-stubs/carray_class.rb +65 -0
  239. data/yard-stubs/carray_conversion.rb +76 -0
  240. data/yard-stubs/carray_copy.rb +79 -0
  241. data/yard-stubs/carray_core.rb +114 -0
  242. data/yard-stubs/carray_count.rb +79 -0
  243. data/yard-stubs/carray_element.rb +108 -0
  244. data/yard-stubs/carray_generate.rb +66 -0
  245. data/yard-stubs/carray_lazy.rb +23 -0
  246. data/yard-stubs/carray_loop.rb +140 -0
  247. data/yard-stubs/carray_mask.rb +259 -0
  248. data/yard-stubs/carray_math.rb +132 -0
  249. data/yard-stubs/carray_mathfunc.rb +45 -0
  250. data/yard-stubs/carray_median_percentile.rb +89 -0
  251. data/yard-stubs/carray_memory_view.rb +163 -0
  252. data/yard-stubs/carray_order.rb +312 -0
  253. data/yard-stubs/carray_random.rb +89 -0
  254. data/yard-stubs/carray_scatter.rb +106 -0
  255. data/yard-stubs/carray_slab.rb +57 -0
  256. data/yard-stubs/carray_sort.rb +163 -0
  257. data/yard-stubs/carray_test.rb +85 -0
  258. data/yard-stubs/carray_undef.rb +64 -0
  259. data/yard-stubs/carray_utils.rb +97 -0
  260. data/yard-stubs/ruby_carray.rb +193 -0
  261. metadata +220 -138
  262. data/Rakefile +0 -51
  263. data/TODO.md +0 -18
  264. data/ext/ca_iter_block.c +0 -257
  265. data/ext/ca_iter_dimension.c +0 -299
  266. data/ext/ca_iter_window.c +0 -214
  267. data/ext/ca_obj_mapping.c +0 -644
  268. data/ext/ca_obj_unbound_repeat.c +0 -529
  269. data/ext/carray_iterator.c +0 -641
  270. data/ext/carray_math.rb +0 -850
  271. data/ext/carray_numeric.c +0 -259
  272. data/ext/carray_sort_addr.c +0 -254
  273. data/ext/carray_stat.c +0 -2100
  274. data/ext/carray_stat_proc.rb +0 -1999
  275. data/ext/mkmath.rb +0 -741
  276. data/ext/ruby_ccomplex.c +0 -509
  277. data/ext/ruby_float_func.c +0 -86
  278. data/lib/carray/array.rb +0 -8
  279. data/lib/carray/autoload/autoload_base.rb +0 -19
  280. data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
  281. data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
  282. data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
  283. data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
  284. data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
  285. data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
  286. data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
  287. data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
  288. data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
  289. data/lib/carray/autoload/autoload_gem_random.rb +0 -8
  290. data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
  291. data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
  292. data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
  293. data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
  294. data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
  295. data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
  296. data/lib/carray/autoload/autoload_object_link.rb +0 -1
  297. data/lib/carray/autoload/autoload_object_pack.rb +0 -2
  298. data/lib/carray/autoload.rb +0 -141
  299. data/lib/carray/basic.rb +0 -191
  300. data/lib/carray/broadcast.rb +0 -101
  301. data/lib/carray/compose.rb +0 -315
  302. data/lib/carray/convert.rb +0 -115
  303. data/lib/carray/info.rb +0 -110
  304. data/lib/carray/io/imagemagick.rb +0 -235
  305. data/lib/carray/mask.rb +0 -102
  306. data/lib/carray/math/histogram.rb +0 -177
  307. data/lib/carray/math/recurrence.rb +0 -93
  308. data/lib/carray/object/ca_obj_iterator.rb +0 -50
  309. data/lib/carray/object/ca_obj_link.rb +0 -50
  310. data/lib/carray/object/ca_obj_pack.rb +0 -99
  311. data/lib/carray/obsolete.rb +0 -256
  312. data/lib/carray/ordering.rb +0 -181
  313. data/lib/carray/testing.rb +0 -51
  314. data/lib/carray/transform.rb +0 -109
  315. data/mailmap +0 -1
  316. data/misc/Methods.ja.md +0 -182
  317. data/misc/NOTE +0 -51
  318. data/spec/Classes/CABitfield_spec.rb +0 -58
  319. data/spec/Classes/CABlockIterator_spec.rb +0 -114
  320. data/spec/Classes/CABlock_spec.rb +0 -205
  321. data/spec/Classes/CAField_spec.rb +0 -39
  322. data/spec/Classes/CAGrid_spec.rb +0 -75
  323. data/spec/Classes/CAMap_spec.rb +0 -0
  324. data/spec/Classes/CAMapping_spec.rb +0 -105
  325. data/spec/Classes/CAObject_attribute_spec.rb +0 -33
  326. data/spec/Classes/CAObject_spec.rb +0 -33
  327. data/spec/Classes/CARefer_spec.rb +0 -93
  328. data/spec/Classes/CARepeat_spec.rb +0 -65
  329. data/spec/Classes/CASelect_spec.rb +0 -22
  330. data/spec/Classes/CAShift_spec.rb +0 -16
  331. data/spec/Classes/CAStruct_spec.rb +0 -71
  332. data/spec/Classes/CATranspose_spec.rb +0 -60
  333. data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
  334. data/spec/Classes/CAWindow_spec.rb +0 -54
  335. data/spec/Classes/CAWrap_spec.rb +0 -8
  336. data/spec/Classes/CArray_spec.rb +0 -184
  337. data/spec/Classes/CScalar_spec.rb +0 -55
  338. data/spec/Features/feature_130_spec.rb +0 -19
  339. data/spec/Features/feature_attributes_spec.rb +0 -280
  340. data/spec/Features/feature_boolean_spec.rb +0 -98
  341. data/spec/Features/feature_broadcast.rb +0 -116
  342. data/spec/Features/feature_cast_function.rb +0 -19
  343. data/spec/Features/feature_cast_spec.rb +0 -33
  344. data/spec/Features/feature_class_spec.rb +0 -84
  345. data/spec/Features/feature_complex_spec.rb +0 -42
  346. data/spec/Features/feature_composite_spec.rb +0 -124
  347. data/spec/Features/feature_convert_spec.rb +0 -46
  348. data/spec/Features/feature_copy_spec.rb +0 -123
  349. data/spec/Features/feature_creation_spec.rb +0 -84
  350. data/spec/Features/feature_element_spec.rb +0 -144
  351. data/spec/Features/feature_extream_spec.rb +0 -54
  352. data/spec/Features/feature_generate_spec.rb +0 -74
  353. data/spec/Features/feature_index_spec.rb +0 -69
  354. data/spec/Features/feature_mask_spec.rb +0 -580
  355. data/spec/Features/feature_math_spec.rb +0 -97
  356. data/spec/Features/feature_order_spec.rb +0 -146
  357. data/spec/Features/feature_ref_store_spec.rb +0 -209
  358. data/spec/Features/feature_serialization_spec.rb +0 -125
  359. data/spec/Features/feature_stat_spec.rb +0 -397
  360. data/spec/Features/feature_virtual_spec.rb +0 -48
  361. data/spec/Features/method_eq_spec.rb +0 -81
  362. data/spec/Features/method_is_nan_spec.rb +0 -12
  363. data/spec/Features/method_map_spec.rb +0 -54
  364. data/spec/Features/method_max_with.rb +0 -20
  365. data/spec/Features/method_min_with.rb +0 -19
  366. data/spec/Features/method_ne_spec.rb +0 -18
  367. data/spec/Features/method_project_spec.rb +0 -188
  368. data/spec/Features/method_ref_spec.rb +0 -27
  369. data/spec/Features/method_round_spec.rb +0 -11
  370. data/spec/Features/method_s_linspace_spec.rb +0 -48
  371. data/spec/Features/method_s_span_spec.rb +0 -14
  372. data/spec/Features/method_seq_spec.rb +0 -47
  373. data/spec/Features/method_sort_with.rb +0 -43
  374. data/spec/Features/method_sorted_with.rb +0 -29
  375. data/spec/Features/method_span_spec.rb +0 -42
  376. data/spec/Features/method_wrap_readonly_spec.rb +0 -43
  377. data/spec/UnitTest/test_CAVirtual.rb +0 -214
  378. data/spec/spec_all.rb +0 -10
  379. data/utils/ca_ase.rb +0 -21
  380. data/utils/ca_methods.rb +0 -15
  381. data/utils/cast_checker.rb +0 -30
  382. data/utils/convert_test.rb +0 -73
  383. data/utils/extract_yard.rb +0 -22
  384. data/utils/guess_shape.rb +0 -76
  385. data/utils/monkey_patch_methods.rb +0 -62
  386. data/utils/remove_resource_fork.sh +0 -5
@@ -0,0 +1,1021 @@
1
+ /* ---------------------------------------------------------------------------
2
+
3
+ Index classifier for `[]` / `[]=` — turns the argv passed to
4
+ CArray subscription into a CAIndexInfo describing the region
5
+ (POINT / BLOCK / ITERATOR / ADDRESS / GRID / SELECT / …). The
6
+ public entry `rb_ca_scan_index` in ca_obj_access.c forwards to
7
+ `rb_ca_scan_index_v2` here.
8
+
9
+ See docs/topics/Indexer_decision_tree.md for the wire-format spec.
10
+
11
+ Design shape:
12
+ - one REG per handler function (grep-friendly)
13
+ - rubber-dim pre-pass with a stack-allocated argv_expanded slot
14
+ - a single negative-index normaliser used by all handlers
15
+ - fast paths (POINT / ADDRESS, ndim == argc, all-FIXNUM) at
16
+ the top of the entry point
17
+ - single-character alphabetic Symbols (:a-:z / :A-:Z) reserved
18
+ for future contraction notation; the classifier raises
19
+ NotImplementedError when they appear.
20
+
21
+ --------------------------------------------------------------------------- */
22
+
23
+ #include "carray.h"
24
+ #include "carray_index_classifier.h"
25
+
26
+ /* Range accessor macros — carray_access.c keeps a private cache
27
+ with the same shape; the duplication here keeps this file
28
+ self-contained without cross-file symbol exposure. */
29
+ static ID ca_classifier_id_begin = 0;
30
+ static ID ca_classifier_id_end = 0;
31
+ static ID ca_classifier_id_excl_end = 0;
32
+ #define CA_CLASSIFIER_RANGE_BEG(r) (rb_funcall((r), ca_classifier_id_begin, 0))
33
+ #define CA_CLASSIFIER_RANGE_END(r) (rb_funcall((r), ca_classifier_id_end, 0))
34
+ #define CA_CLASSIFIER_RANGE_EXCL(r) (rb_funcall((r), ca_classifier_id_excl_end, 0))
35
+
36
+ /* -------------------------------------------------------------------- */
37
+ /* Symbol cache — see the range-macro comment above for why this
38
+ file keeps its own copy independent of carray_access.c. */
39
+
40
+ static VALUE ca_classifier_sym_perc = Qundef;
41
+ static VALUE ca_classifier_sym_under = Qundef;
42
+ static VALUE ca_classifier_sym_gt = Qundef; /* :> slab-iterator marker */
43
+ static VALUE ca_classifier_sym_tilde = Qundef; /* :~ rubber-dim alias for `false` */
44
+
45
+ static inline void
46
+ ca_classifier_sym_cache_init (void)
47
+ {
48
+ if ( ca_classifier_sym_perc == Qundef ) {
49
+ ca_classifier_sym_perc = ID2SYM(rb_intern("%"));
50
+ ca_classifier_sym_under = ID2SYM(rb_intern("_"));
51
+ ca_classifier_sym_gt = ID2SYM(rb_intern(">"));
52
+ ca_classifier_sym_tilde = ID2SYM(rb_intern("~"));
53
+ ca_classifier_id_begin = rb_intern("begin");
54
+ ca_classifier_id_end = rb_intern("end");
55
+ ca_classifier_id_excl_end = rb_intern("exclude_end?");
56
+ }
57
+ }
58
+
59
+ /* -------------------------------------------------------------------- */
60
+ /* Classifier context — every handler reads / writes through this
61
+ struct. Lives on rb_ca_scan_index_v2's stack; not exposed. */
62
+
63
+ typedef struct {
64
+ /* inputs (read-only after init) */
65
+ int ca_ndim;
66
+ ca_size_t *ca_dim;
67
+ ca_size_t ca_elements;
68
+ long argc; /* may be adjusted by rubber-dim expansion */
69
+ VALUE *argv; /* points at argv_expanded after pre-pass */
70
+
71
+ /* output (target of handlers) */
72
+ CAIndexInfo *info;
73
+
74
+ /* working storage for rubber-dim expansion */
75
+ VALUE argv_expanded[CA_RANK_MAX];
76
+ } ca_classifier_ctx_t;
77
+
78
+ /* -------------------------------------------------------------------- */
79
+ /* helpers */
80
+
81
+ /* Negative-index normalisation gathered in one place, replacing
82
+ the CA_CHECK_INDEX_AT macro that used to be expanded at every
83
+ call site. Error-message format is byte-identical with the
84
+ legacy path so downstream error-message assertions still match. */
85
+ static inline ca_size_t
86
+ ca_classifier_normalize_axis_index (ca_size_t k, ca_size_t dim, int axis, int range_check)
87
+ {
88
+ if ( k < 0 ) {
89
+ k += dim;
90
+ }
91
+ if ( range_check && ( k < 0 || k >= dim ) ) {
92
+ rb_raise(rb_eIndexError,
93
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
94
+ axis, (ca_size_t) k, (ca_size_t) (dim - 1));
95
+ }
96
+ return k;
97
+ }
98
+
99
+ /* Flat-address normalisation for the `argc == 1, ndim > 1,
100
+ Integer` path. CA_CHECK_INDEX does not carry axis info in its
101
+ message, which is the intended behaviour on the flat path. */
102
+ static inline ca_size_t
103
+ ca_classifier_normalize_flat_address (ca_size_t addr, ca_size_t elements, int range_check)
104
+ {
105
+ if ( range_check ) {
106
+ CA_CHECK_INDEX(addr, elements);
107
+ }
108
+ return addr;
109
+ }
110
+
111
+ /* -------------------------------------------------------------------- */
112
+ /* Fast paths. */
113
+
114
+ /* Fast path 1: ca[i, j, k] all-FIXNUM, argc == ndim → POINT.
115
+ Returns 1 if classified, 0 if the caller should continue. */
116
+ static inline int
117
+ ca_classifier_try_point_fast_path (ca_classifier_ctx_t *ctx)
118
+ {
119
+ long i;
120
+ if ( ctx->argc < 1 || ctx->argc != ctx->ca_ndim ) {
121
+ return 0;
122
+ }
123
+ for (i = 0; i < ctx->argc; i++) {
124
+ if ( ! FIXNUM_P(ctx->argv[i]) ) {
125
+ return 0;
126
+ }
127
+ }
128
+
129
+ ctx->info->type = CA_REG_POINT;
130
+ ctx->info->ndim = (int16_t) ctx->argc;
131
+ for (i = 0; i < ctx->argc; i++) {
132
+ ca_size_t k = FIX2LONG(ctx->argv[i]);
133
+ if ( ctx->info->range_check ) {
134
+ /* Bignum is rejected by FIXNUM_P above; the slow path's
135
+ rb_obj_is_kind_of(arg, rb_cInteger) picks it up so the
136
+ Integer semantics are preserved end-to-end. */
137
+ k = ca_classifier_normalize_axis_index(k, ctx->ca_dim[i], (int) i,
138
+ ctx->info->range_check);
139
+ }
140
+ ctx->info->index_type[i] = CA_IDX_SCALAR;
141
+ ctx->info->index[i].scalar = k;
142
+ }
143
+ return 1;
144
+ }
145
+
146
+ /* Fast path 2: ca[flat_addr] single FIXNUM, ndim > 1 → ADDRESS. */
147
+ static inline int
148
+ ca_classifier_try_address_fast_path (ca_classifier_ctx_t *ctx)
149
+ {
150
+ ca_size_t addr;
151
+ if ( ctx->argc != 1 || ctx->ca_ndim <= 1 || ! FIXNUM_P(ctx->argv[0]) ) {
152
+ return 0;
153
+ }
154
+ addr = FIX2LONG(ctx->argv[0]);
155
+ addr = ca_classifier_normalize_flat_address(addr, ctx->ca_elements,
156
+ ctx->info->range_check);
157
+ ctx->info->type = CA_REG_ADDRESS;
158
+ ctx->info->ndim = 1;
159
+ ctx->info->index[0].scalar = addr;
160
+ return 1;
161
+ }
162
+
163
+ /* -------------------------------------------------------------------- */
164
+ /* Single-character alphabetic Symbols (`:a`-`:z` / `:A`-`:Z`) are
165
+ reserved for future contraction notation. Raises
166
+ NotImplementedError rather than the generic IndexError. The
167
+ caller passes any Symbol that is not `:_` / `:%`; a
168
+ non-reserved Symbol returns without action. */
169
+ static inline void
170
+ ca_classifier_check_reserved_contraction_symbol (VALUE sym)
171
+ {
172
+ const char *name;
173
+ if ( ! SYMBOL_P(sym) ) return;
174
+ name = rb_id2name(SYM2ID(sym));
175
+ if ( name != NULL
176
+ && name[0] != '\0' && name[1] == '\0'
177
+ && ( ( name[0] >= 'a' && name[0] <= 'z' )
178
+ || ( name[0] >= 'A' && name[0] <= 'Z' ) )
179
+ && name[0] != '_' /* :_ is iterator marker, handled separately */ ) {
180
+ rb_raise(rb_eNotImpError,
181
+ "symbol :%s is reserved for future contraction notation "
182
+ "(not yet implemented)",
183
+ name);
184
+ }
185
+ }
186
+
187
+ /* -------------------------------------------------------------------- */
188
+ /* Per-axis BLOCK builders.
189
+ *
190
+ * Each helper takes the user-supplied arg + axis index + dim and
191
+ * populates info->index[axis].block plus
192
+ * info->index_type[axis] = BLOCK. Error messages are byte-
193
+ * identical with the legacy path so downstream regexes still
194
+ * match. */
195
+
196
+ /* Range → BLOCK */
197
+ static void
198
+ ca_classifier_axis_from_range (ca_classifier_ctx_t *ctx, int axis, VALUE arg)
199
+ {
200
+ ca_size_t start, last, count, step;
201
+ int excl;
202
+ volatile VALUE iv_beg, iv_end, iv_excl;
203
+ CAIndexInfo *info = ctx->info;
204
+ ca_size_t dim = ctx->ca_dim[axis];
205
+
206
+ iv_beg = CA_CLASSIFIER_RANGE_BEG(arg);
207
+ iv_end = CA_CLASSIFIER_RANGE_END(arg);
208
+ iv_excl = CA_CLASSIFIER_RANGE_EXCL(arg);
209
+
210
+ start = NIL_P(iv_beg) ? 0 : NUM2SIZE(iv_beg);
211
+ last = NIL_P(iv_end) ? -1 : NUM2SIZE(iv_end);
212
+ excl = RTEST(iv_excl);
213
+
214
+ info->index_type[axis] = CA_IDX_BLOCK;
215
+
216
+ if ( info->range_check ) {
217
+ /* Inlined CA_CHECK_INDEX_AT so the format string stays
218
+ byte-identical with the surrounding helpers. */
219
+ if ( start < 0 ) start += dim;
220
+ if ( start < 0 || start >= dim ) {
221
+ rb_raise(rb_eIndexError,
222
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
223
+ axis, (ca_size_t) start, (ca_size_t) (dim - 1));
224
+ }
225
+ }
226
+
227
+ if ( last < 0 ) {
228
+ last += dim; /* don't use CA_CHECK_INDEX for excl */
229
+ }
230
+ if ( excl && start == last ) {
231
+ info->index[axis].block.start = start;
232
+ info->index[axis].block.count = 0;
233
+ info->index[axis].block.step = 1;
234
+ return;
235
+ }
236
+ if ( excl ) {
237
+ last += ( last >= start ) ? -1 : 1;
238
+ }
239
+ if ( info->range_check ) {
240
+ if ( last < 0 || last >= dim ) {
241
+ rb_raise(rb_eIndexError,
242
+ "index %" PRId64 " is out of range (0..%" PRId64 ") at %i-dim",
243
+ (ca_size_t) last, (ca_size_t) (dim - 1), axis);
244
+ }
245
+ }
246
+ count = llabs(last - start) + 1;
247
+ step = ( last >= start ) ? 1 : -1;
248
+ info->index[axis].block.start = start;
249
+ info->index[axis].block.count = count;
250
+ info->index[axis].block.step = step;
251
+ }
252
+
253
+ #ifdef HAVE_RB_ARITHMETIC_SEQUENCE_EXTRACT
254
+ /* ArithSeq → BLOCK */
255
+ static void
256
+ ca_classifier_axis_from_arithseq (ca_classifier_ctx_t *ctx, int axis, VALUE arg)
257
+ {
258
+ ca_size_t start, last, count, step, bound;
259
+ int excl;
260
+ volatile VALUE iv_beg, iv_end, iv_excl;
261
+ rb_arithmetic_sequence_components_t x;
262
+ CAIndexInfo *info = ctx->info;
263
+ ca_size_t dim = ctx->ca_dim[axis];
264
+
265
+ rb_arithmetic_sequence_extract(arg, &x);
266
+ iv_beg = x.begin;
267
+ iv_end = x.end;
268
+ iv_excl = x.exclude_end;
269
+ step = NUM2SIZE(x.step);
270
+
271
+ start = NIL_P(iv_beg) ? 0 : NUM2SIZE(iv_beg);
272
+ last = NIL_P(iv_end) ? -1 : NUM2SIZE(iv_end);
273
+ excl = RTEST(iv_excl);
274
+
275
+ if ( step == 0 ) {
276
+ rb_raise(rb_eRuntimeError,
277
+ "step in index equals to 0 in block reference");
278
+ }
279
+
280
+ info->index_type[axis] = CA_IDX_BLOCK;
281
+
282
+ /* CAREFUL: always range-check start on the ArithSeq path,
283
+ ignoring info->range_check. An ArithSeq with a negative or
284
+ out-of-range start silently produces an empty region if this
285
+ check is deferred, which upstream callers do not expect. */
286
+ if ( start < 0 ) start += dim;
287
+ if ( start < 0 || start >= dim ) {
288
+ rb_raise(rb_eIndexError,
289
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
290
+ axis, (ca_size_t) start, (ca_size_t) (dim - 1));
291
+ }
292
+
293
+ if ( last < 0 ) {
294
+ last += dim;
295
+ }
296
+ if ( excl && start == last ) {
297
+ info->index[axis].block.start = start;
298
+ info->index[axis].block.count = 0;
299
+ info->index[axis].block.step = 1;
300
+ return;
301
+ }
302
+ if ( excl ) {
303
+ last += ( last >= start ) ? -1 : 1;
304
+ }
305
+ if ( last < 0 || last >= dim ) {
306
+ rb_raise(rb_eIndexError,
307
+ "index %" PRId64 " is out of range (0..%" PRId64 ") at %i-dim",
308
+ (ca_size_t) last, (ca_size_t) (dim - 1), axis);
309
+ }
310
+ if ( (last - start) * (long long) step < 0 ) {
311
+ count = 1;
312
+ }
313
+ else {
314
+ count = llabs(last - start) / llabs((long long) step) + 1;
315
+ }
316
+ bound = start + (count - 1) * step;
317
+ if ( bound < 0 ) bound += dim; /* CA_CHECK_INDEX_AT signature */
318
+ if ( bound < 0 || bound >= dim ) {
319
+ rb_raise(rb_eIndexError,
320
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
321
+ axis, (ca_size_t) bound, (ca_size_t) (dim - 1));
322
+ }
323
+ info->index[axis].block.start = start;
324
+ info->index[axis].block.count = count;
325
+ info->index[axis].block.step = step;
326
+ }
327
+ #endif
328
+
329
+ /* T_ARRAY → BLOCK. Accepts [nil] / [Range] / [Integer] (len 1),
330
+ [nil, step] / [Range, step] / [start, count] (len 2), or
331
+ [start, count, step] (len 3). */
332
+ static void
333
+ ca_classifier_axis_from_array (ca_classifier_ctx_t *ctx, int axis, VALUE arg)
334
+ {
335
+ CAIndexInfo *info = ctx->info;
336
+ ca_size_t dim = ctx->ca_dim[axis];
337
+ long len = RARRAY_LEN(arg);
338
+
339
+ info->index_type[axis] = CA_IDX_BLOCK;
340
+
341
+ if ( len == 1 ) {
342
+ VALUE a0 = rb_ary_entry(arg, 0);
343
+ if ( NIL_P(a0) ) { /* [nil] → ALL */
344
+ info->index_type[axis] = CA_IDX_ALL;
345
+ return;
346
+ }
347
+ if ( rb_obj_is_kind_of(a0, rb_cRange) ) { /* [Range] → recurse */
348
+ ca_classifier_axis_from_range(ctx, axis, a0);
349
+ return;
350
+ }
351
+ /* [Integer] */
352
+ {
353
+ ca_size_t start = NUM2SIZE(a0);
354
+ if ( start < 0 ) start += dim;
355
+ if ( start < 0 || start >= dim ) {
356
+ rb_raise(rb_eIndexError,
357
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
358
+ axis, (ca_size_t) start, (ca_size_t) (dim - 1));
359
+ }
360
+ info->index[axis].block.start = start;
361
+ info->index[axis].block.count = 1;
362
+ info->index[axis].block.step = 1;
363
+ return;
364
+ }
365
+ }
366
+
367
+ if ( len == 2 ) {
368
+ VALUE a0 = rb_ary_entry(arg, 0);
369
+ VALUE a1 = rb_ary_entry(arg, 1);
370
+
371
+ if ( NIL_P(a0) ) { /* [nil, step] */
372
+ ca_size_t start = 0, last, count, step, bound;
373
+ step = NUM2SIZE(a1);
374
+ if ( step == 0 ) {
375
+ rb_raise(rb_eRuntimeError,
376
+ "step in index equals to 0 in block reference");
377
+ }
378
+ last = dim - 1;
379
+ count = ( step < 0 ) ? 1 : (last / step + 1);
380
+ bound = start + (count - 1) * step;
381
+ if ( bound < 0 ) bound += dim;
382
+ if ( bound < 0 || bound >= dim ) {
383
+ rb_raise(rb_eIndexError,
384
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
385
+ axis, (ca_size_t) bound, (ca_size_t) (dim - 1));
386
+ }
387
+ info->index[axis].block.start = start;
388
+ info->index[axis].block.count = count;
389
+ info->index[axis].block.step = step;
390
+ return;
391
+ }
392
+
393
+ if ( rb_obj_is_kind_of(a0, rb_cRange) ) { /* [Range, step] */
394
+ ca_size_t start, last, count, step, bound;
395
+ int excl;
396
+ volatile VALUE iv_beg, iv_end, iv_excl;
397
+ iv_beg = CA_CLASSIFIER_RANGE_BEG(a0);
398
+ iv_end = CA_CLASSIFIER_RANGE_END(a0);
399
+ iv_excl = CA_CLASSIFIER_RANGE_EXCL(a0);
400
+ start = NIL_P(iv_beg) ? 0 : NUM2SIZE(iv_beg);
401
+ last = NIL_P(iv_end) ? -1 : NUM2SIZE(iv_end);
402
+ excl = RTEST(iv_excl);
403
+ step = NUM2SIZE(a1);
404
+ if ( step == 0 ) {
405
+ rb_raise(rb_eRuntimeError,
406
+ "step in index equals to 0 in block reference");
407
+ }
408
+ if ( start < 0 ) start += dim;
409
+ if ( start < 0 || start >= dim ) {
410
+ rb_raise(rb_eIndexError,
411
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
412
+ axis, (ca_size_t) start, (ca_size_t) (dim - 1));
413
+ }
414
+ if ( last < 0 ) last += dim;
415
+ if ( excl && start == last ) {
416
+ info->index[axis].block.start = start;
417
+ info->index[axis].block.count = 0;
418
+ info->index[axis].block.step = 1;
419
+ return;
420
+ }
421
+ if ( excl ) {
422
+ last += ( last >= start ) ? -1 : 1;
423
+ }
424
+ if ( last < 0 || last >= dim ) {
425
+ rb_raise(rb_eIndexError,
426
+ "index %" PRId64 " is out of range (0..%" PRId64 ") at %i-dim",
427
+ (ca_size_t) last, (ca_size_t) (dim - 1), axis);
428
+ }
429
+ if ( (last - start) * (long long) step < 0 ) {
430
+ count = 1;
431
+ }
432
+ else {
433
+ count = llabs(last - start) / llabs((long long) step) + 1;
434
+ }
435
+ bound = start + (count - 1) * step;
436
+ if ( bound < 0 ) bound += dim;
437
+ if ( bound < 0 || bound >= dim ) {
438
+ rb_raise(rb_eIndexError,
439
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
440
+ axis, (ca_size_t) bound, (ca_size_t) (dim - 1));
441
+ }
442
+ info->index[axis].block.start = start;
443
+ info->index[axis].block.count = count;
444
+ info->index[axis].block.step = step;
445
+ return;
446
+ }
447
+
448
+ /* [start, count] */
449
+ {
450
+ ca_size_t start, count, bound;
451
+ start = NUM2SIZE(a0);
452
+ count = NUM2SIZE(a1);
453
+ bound = start + (count - 1);
454
+ if ( start < 0 ) start += dim;
455
+ if ( start < 0 || start >= dim ) {
456
+ rb_raise(rb_eIndexError,
457
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
458
+ axis, (ca_size_t) start, (ca_size_t) (dim - 1));
459
+ }
460
+ if ( bound < 0 ) bound += dim;
461
+ if ( bound < 0 || bound >= dim ) {
462
+ rb_raise(rb_eIndexError,
463
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
464
+ axis, (ca_size_t) bound, (ca_size_t) (dim - 1));
465
+ }
466
+ info->index[axis].block.start = start;
467
+ info->index[axis].block.count = count;
468
+ info->index[axis].block.step = 1;
469
+ return;
470
+ }
471
+ }
472
+
473
+ if ( len == 3 ) { /* [start, count, step] */
474
+ ca_size_t start, count, step, bound;
475
+ start = NUM2SIZE(rb_ary_entry(arg, 0));
476
+ count = NUM2SIZE(rb_ary_entry(arg, 1));
477
+ step = NUM2SIZE(rb_ary_entry(arg, 2));
478
+ if ( step == 0 ) {
479
+ rb_raise(rb_eRuntimeError,
480
+ "step in index equals to 0 in block reference");
481
+ }
482
+ bound = start + (count - 1) * step;
483
+ if ( start < 0 ) start += dim;
484
+ if ( start < 0 || start >= dim ) {
485
+ rb_raise(rb_eIndexError,
486
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
487
+ axis, (ca_size_t) start, (ca_size_t) (dim - 1));
488
+ }
489
+ if ( bound < 0 ) bound += dim;
490
+ if ( bound < 0 || bound >= dim ) {
491
+ rb_raise(rb_eIndexError,
492
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
493
+ axis, (ca_size_t) bound, (ca_size_t) (dim - 1));
494
+ }
495
+ info->index[axis].block.start = start;
496
+ info->index[axis].block.count = count;
497
+ info->index[axis].block.step = step;
498
+ return;
499
+ }
500
+
501
+ rb_raise(rb_eIndexError,
502
+ "invalid form of index range at %i-dim "
503
+ "(should be [start[,count[,step]]], [range, step])",
504
+ axis);
505
+ }
506
+
507
+ /* -------------------------------------------------------------------- */
508
+ /* Per-axis dispatcher — main-loop body.
509
+ *
510
+ * Returns 1 to signal the main loop to STOP (a CArray at an axis
511
+ * position triggers a REG = GRID short-circuit that skips
512
+ * remaining axes and the post-loop ndim check). Otherwise
513
+ * returns 0. Sets *out_is_grid when the GRID short-circuit
514
+ * fires; out_is_grid must not be NULL. */
515
+ static int
516
+ ca_classifier_dispatch_axis_arg (ca_classifier_ctx_t *ctx, int axis, VALUE arg,
517
+ int *out_is_grid)
518
+ {
519
+ CAIndexInfo *info = ctx->info;
520
+ ca_size_t dim = ctx->ca_dim[axis];
521
+
522
+ if ( rb_obj_is_kind_of(arg, rb_cInteger) ) {
523
+ ca_size_t k = NUM2SIZE(arg);
524
+ info->index_type[axis] = CA_IDX_SCALAR;
525
+ if ( info->range_check ) {
526
+ k = ca_classifier_normalize_axis_index(k, dim, axis, info->range_check);
527
+ }
528
+ info->index[axis].scalar = k;
529
+ return 0;
530
+ }
531
+ if ( NIL_P(arg) ) {
532
+ info->index_type[axis] = CA_IDX_ALL;
533
+ return 0;
534
+ }
535
+ if ( rb_obj_is_kind_of(arg, rb_cRange) ) {
536
+ ca_classifier_axis_from_range(ctx, axis, arg);
537
+ return 0;
538
+ }
539
+ #ifdef HAVE_RB_ARITHMETIC_SEQUENCE_EXTRACT
540
+ if ( rb_obj_is_kind_of(arg, rb_cArithSeq) ) {
541
+ ca_classifier_axis_from_arithseq(ctx, axis, arg);
542
+ return 0;
543
+ }
544
+ #endif
545
+ if ( TYPE(arg) == T_ARRAY ) {
546
+ ca_classifier_axis_from_array(ctx, axis, arg);
547
+ return 0;
548
+ }
549
+ if ( SYMBOL_P(arg) ) {
550
+ /* :> is the slab-iterator marker. :_ is newaxis, intercepted
551
+ at the [] / []= entry before scan_index sees it — if it
552
+ reaches this branch it slipped past the newaxis hook. */
553
+ if ( arg == ca_classifier_sym_gt ) {
554
+ info->index_type[axis] = CA_IDX_SYMBOL;
555
+ info->index[axis].symbol.id = SYM2ID(arg);
556
+ info->index[axis].symbol.spec = Qnil;
557
+ return 0;
558
+ }
559
+ if ( arg == ca_classifier_sym_under ) {
560
+ /* :_ reached here because it slipped past the [] / []=
561
+ newaxis hook (typically CArray.scan_index called directly). */
562
+ rb_raise(rb_eIndexError,
563
+ "symbol :_ (newaxis) is handled at the [] / []= level, "
564
+ "not valid in scan_index");
565
+ }
566
+ ca_classifier_check_reserved_contraction_symbol(arg); /* raises if reserved */
567
+ rb_raise(rb_eIndexError,
568
+ "symbol :%s is invalid as the index for slab iterator "
569
+ "(use :> instead)",
570
+ rb_id2name(SYM2ID(arg)));
571
+ }
572
+ if ( rb_obj_is_carray(arg) ) {
573
+ /* CArray (boolean / integer) at an axis position → GRID.
574
+ Signal the caller to stop populating later axes; the
575
+ main-loop caller breaks out after this axis. */
576
+ CArray *ci;
577
+ TypedData_Get_Struct(arg, CArray, &carray_data_type, ci);
578
+ if ( ca_is_boolean_type(ci) || ca_is_integer_type(ci) ) {
579
+ if ( out_is_grid ) *out_is_grid = 1;
580
+ return 1; /* signal caller: stop main loop, REG = GRID */
581
+ }
582
+ rb_raise(rb_eIndexError,
583
+ "data_type %s is invalid for reference by gridding at %i-dim "
584
+ "(should be boolean or integer)",
585
+ ca_type_name[ci->data_type], axis);
586
+ }
587
+ {
588
+ VALUE inspect = rb_inspect(arg);
589
+ rb_raise(rb_eIndexError,
590
+ "object '%s' is invalid for the index for reference at %i-dim",
591
+ StringValuePtr(inspect), axis);
592
+ }
593
+ }
594
+
595
+ /* -------------------------------------------------------------------- */
596
+ /* Rubber-dim pre-pass. Walks ctx->argv detecting Qfalse (or its
597
+ `:~` alias), expands the rubber slot into `Qnil` fills in
598
+ ctx->argv_expanded, and re-points ctx->argv at it. At most one
599
+ rubber marker is honoured; a second one falls through to the
600
+ per-axis dispatcher and raises. */
601
+
602
+ static void
603
+ ca_classifier_expand_rubber_dim (ca_classifier_ctx_t *ctx)
604
+ {
605
+ long i, j;
606
+ long argc = ctx->argc;
607
+ VALUE *argv = ctx->argv;
608
+ int rubber_pos = -1;
609
+ long expanded_argc;
610
+ int rndim;
611
+
612
+ for (i = 0; i < argc; i++) {
613
+ if ( argv[i] == Qfalse || argv[i] == ca_classifier_sym_tilde ) {
614
+ rubber_pos = (int) i; /* :~ is an alias for the `false` rubber marker */
615
+ /* Only the first rubber marker is honoured; later occurrences fall
616
+ through to the per-axis dispatcher and raise. */
617
+ break;
618
+ }
619
+ }
620
+
621
+ if ( rubber_pos < 0 ) {
622
+ /* No rubber dim — validate argc == ndim and pass through. */
623
+ if ( argc != ctx->ca_ndim ) {
624
+ rb_raise(rb_eIndexError,
625
+ "number of indices exceeds the ndim of carray (%i > %i)",
626
+ (int) argc, ctx->ca_ndim);
627
+ }
628
+ return;
629
+ }
630
+
631
+ if ( argc > ctx->ca_ndim + 1 ) {
632
+ rb_raise(rb_eIndexError,
633
+ "index specification exceeds the ndim of carray (%i)",
634
+ ctx->ca_ndim);
635
+ }
636
+
637
+ /* rndim = number of nils the rubber expands to.
638
+ *
639
+ * CAREFUL: rndim == 0 is a valid outcome — the rubber consumes
640
+ * nothing when argc == ndim + 1 (e.g. `[false, 0, 1]` on
641
+ * ndim = 2 collapses to `[0, 1]`). Clamping only at the
642
+ * negative side preserves that path. */
643
+ rndim = ctx->ca_ndim - (int)argc + 1;
644
+ if ( rndim < 0 ) rndim = 0;
645
+ expanded_argc = argc - 1 + rndim;
646
+
647
+ j = 0;
648
+ for (i = 0; i < argc; i++) {
649
+ if ( i == rubber_pos ) {
650
+ int k;
651
+ for (k = 0; k < rndim; k++) {
652
+ ctx->argv_expanded[j++] = Qnil;
653
+ }
654
+ } else {
655
+ ctx->argv_expanded[j++] = argv[i];
656
+ }
657
+ }
658
+ ctx->argc = expanded_argc;
659
+ ctx->argv = ctx->argv_expanded;
660
+ }
661
+
662
+ /* -------------------------------------------------------------------- */
663
+ /* Final REG decision — walks info->index_type[] and decides
664
+ POINT / BLOCK / ITERATOR / GRID. */
665
+
666
+ static void
667
+ ca_classifier_finalize_reg (ca_classifier_ctx_t *ctx, int is_grid)
668
+ {
669
+ int i, is_point = 1, is_iterator = 0;
670
+ CAIndexInfo *info = ctx->info;
671
+
672
+ for (i = 0; i < info->ndim; i++) {
673
+ switch ( info->index_type[i] ) {
674
+ case CA_IDX_SCALAR: break;
675
+ case CA_IDX_ALL: is_point = 0; break;
676
+ case CA_IDX_SYMBOL: is_iterator = 1; break;
677
+ default: is_point = 0; break;
678
+ }
679
+ }
680
+
681
+ if ( is_grid ) info->type = CA_REG_GRID;
682
+ else if ( is_iterator ) info->type = CA_REG_ITERATOR;
683
+ else if ( is_point ) info->type = CA_REG_POINT;
684
+ else info->type = CA_REG_BLOCK;
685
+
686
+ /* CAREFUL: when REG == ITERATOR, every CA_IDX_SCALAR axis must
687
+ be rewritten into a BLOCK with {start, count = 1, step = 1}.
688
+ Downstream iterator machinery treats SCALAR and BLOCK
689
+ differently, and skipping this rewrite silently changes the
690
+ iteration shape. */
691
+ if ( info->type == CA_REG_ITERATOR ) {
692
+ for (i = 0; i < info->ndim; i++) {
693
+ if ( info->index_type[i] == CA_IDX_SCALAR ) {
694
+ ca_size_t start = info->index[i].scalar;
695
+ info->index_type[i] = CA_IDX_BLOCK;
696
+ info->index[i].block.start = start;
697
+ info->index[i].block.step = 1;
698
+ info->index[i].block.count = 1;
699
+ }
700
+ }
701
+ }
702
+ }
703
+
704
+ /* -------------------------------------------------------------------- */
705
+ /* argc == 1 special dispatch. Returns 1 if the region was
706
+ classified here, 0 to continue to the main loop. */
707
+
708
+ static int
709
+ ca_classifier_try_argc1_special (ca_classifier_ctx_t *ctx)
710
+ {
711
+ VALUE arg = ctx->argv[0];
712
+ CAIndexInfo *info = ctx->info;
713
+
714
+ /* A single Qfalse / :~ means ALL, so `ca[:~]` and `ca[false]`
715
+ both collapse to `ca[]`. */
716
+ if ( arg == Qfalse || arg == ca_classifier_sym_tilde ) {
717
+ info->type = CA_REG_ALL;
718
+ return 1;
719
+ }
720
+
721
+ /* T_STRING: "@name" → ATTRIBUTE, "field" → MEMBER. */
722
+ if ( TYPE(arg) == T_STRING ) {
723
+ const char *s = StringValuePtr(arg);
724
+ if ( s[0] == '@' ) {
725
+ info->type = CA_REG_ATTRIBUTE;
726
+ info->symbol = rb_str_new2(s + 1);
727
+ } else {
728
+ info->type = CA_REG_MEMBER;
729
+ info->symbol = ID2SYM(rb_intern(s));
730
+ }
731
+ return 1;
732
+ }
733
+
734
+ /* argc == 1 CArray → GRID / MAPPING / SELECT. */
735
+ if ( rb_obj_is_carray(arg) ) {
736
+ CArray *cs;
737
+ TypedData_Get_Struct(arg, CArray, &carray_data_type, cs);
738
+ if ( ca_is_integer_type(cs) ) {
739
+ if ( ctx->ca_ndim == 1 && cs->ndim == 1 ) {
740
+ info->type = CA_REG_GRID;
741
+ } else {
742
+ info->type = CA_REG_MAPPING;
743
+ }
744
+ return 1;
745
+ }
746
+ if ( ca_is_boolean_type(cs) ) {
747
+ if ( ctx->ca_elements != cs->elements ) {
748
+ rb_raise(rb_eRuntimeError,
749
+ "mismatch of # of elements ( %" PRId64 " <=> %" PRId64 " ) "
750
+ "in reference by selection",
751
+ (ca_size_t) cs->elements,
752
+ (ca_size_t) ctx->ca_elements);
753
+ }
754
+ info->type = CA_REG_SELECT;
755
+ info->select = cs;
756
+ return 1;
757
+ }
758
+ rb_raise(rb_eIndexError,
759
+ "data_type %s is invalid for reference by selection/mapping"
760
+ "(should be boolean or integer)",
761
+ ca_type_name[cs->data_type]);
762
+ }
763
+
764
+ /* ndim > 1 with Integer → ADDRESS. Fixnum was caught by the
765
+ fast path; this branch handles Bignum. */
766
+ if ( ctx->ca_ndim > 1 && rb_obj_is_kind_of(arg, rb_cInteger) ) {
767
+ ca_size_t addr = NUM2SIZE(arg);
768
+ info->type = CA_REG_ADDRESS;
769
+ info->ndim = 1;
770
+ if ( info->range_check ) {
771
+ CA_CHECK_INDEX(addr, ctx->ca_elements);
772
+ }
773
+ info->index[0].scalar = addr;
774
+ return 1;
775
+ }
776
+
777
+ /* ndim > 1 with nil → FLATTEN. */
778
+ if ( ctx->ca_ndim > 1 && NIL_P(arg) ) {
779
+ info->type = CA_REG_FLATTEN;
780
+ return 1;
781
+ }
782
+
783
+ /* ndim > 1 with Range / ArithSeq / T_ARRAY → ADDRESS_COMPLEX.
784
+ The classifier only sets info->type here; the actual
785
+ [start, count, step] triple is built by re-scanning argv
786
+ against a flat dim = [elements] at the Ruby surface
787
+ (rb_ca_s_scan_index_v2 below). */
788
+ if ( ctx->ca_ndim > 1 ) {
789
+ info->type = CA_REG_ADDRESS_COMPLEX;
790
+ return 1;
791
+ }
792
+
793
+ /* argc == 1 && ndim == 1: fall through to the main loop
794
+ (which classifies this as POINT 1-D). */
795
+ return 0;
796
+ }
797
+
798
+ /* -------------------------------------------------------------------- */
799
+ /* Entry point. */
800
+
801
+ void
802
+ rb_ca_scan_index_v2 (int ca_ndim, ca_size_t *ca_dim, ca_size_t ca_elements,
803
+ long argc, VALUE *argv, CAIndexInfo *info)
804
+ {
805
+ ca_classifier_ctx_t ctx;
806
+ long i;
807
+
808
+ ca_classifier_sym_cache_init();
809
+
810
+ ctx.ca_ndim = ca_ndim;
811
+ ctx.ca_dim = ca_dim;
812
+ ctx.ca_elements = ca_elements;
813
+ ctx.argc = argc;
814
+ ctx.argv = argv;
815
+ ctx.info = info;
816
+
817
+ info->ndim = 0;
818
+ info->select = NULL;
819
+
820
+ /* argc == 0 → ALL */
821
+ if ( argc == 0 ) {
822
+ info->type = CA_REG_ALL;
823
+ return;
824
+ }
825
+
826
+ /* argv[0] = multi-char Symbol → METHOD_CALL. Single-char
827
+ specials (:_ / :%) fall through the strlen check and are
828
+ handled downstream (argc == 1 special / fast paths / main
829
+ loop). Single-char alphabetic reserved-contraction Symbols
830
+ also fall through here and are raised later by the per-axis
831
+ dispatcher's SYMBOL_P branch. */
832
+ if ( SYMBOL_P(argv[0]) ) {
833
+ const char *name = rb_id2name(SYM2ID(argv[0]));
834
+ if ( name != NULL && strlen(name) > 1 ) {
835
+ info->type = CA_REG_METHOD_CALL;
836
+ info->symbol = argv[0];
837
+ return;
838
+ }
839
+ }
840
+
841
+ /* Fast paths. */
842
+ if ( ca_classifier_try_point_fast_path(&ctx) ) return;
843
+ if ( ca_classifier_try_address_fast_path(&ctx) ) return;
844
+
845
+ /* argc == 1 special cases. */
846
+ if ( argc == 1 ) {
847
+ if ( ca_classifier_try_argc1_special(&ctx) ) return;
848
+ }
849
+
850
+ /* Main loop entered when argc >= 1 was not handled above, or
851
+ when argc == 1 && ndim == 1 falls through to the POINT 1-D
852
+ classification below. */
853
+
854
+ /* CAREFUL: pre-scan for :%. The Symbol at any position pins the
855
+ final REG and short-circuits both the main loop and the argc /
856
+ ndim validation below — skipping the pre-scan lets the ndim
857
+ mismatch check fire before the Symbol is recognised. */
858
+ for (i = 0; i < ctx.argc; i++) {
859
+ if ( ctx.argv[i] == ca_classifier_sym_perc ) {
860
+ info->type = CA_REG_REPEAT;
861
+ return;
862
+ }
863
+ }
864
+
865
+ ca_classifier_expand_rubber_dim(&ctx);
866
+
867
+ info->ndim = (int16_t) ctx.argc;
868
+ {
869
+ int is_grid = 0;
870
+ int stop = 0;
871
+ for (i = 0; i < ctx.argc && ! stop; i++) {
872
+ stop = ca_classifier_dispatch_axis_arg(&ctx, (int) i, ctx.argv[i], &is_grid);
873
+ }
874
+
875
+ /* CAREFUL: the GRID short-circuit skips the post-loop ndim
876
+ validation. A CArray at an axis position may reduce the
877
+ effective info->ndim below ctx.ca_ndim, and re-checking
878
+ here would raise on legitimate grid regions. */
879
+ if ( ! is_grid && ctx.ca_ndim != info->ndim ) {
880
+ rb_raise(rb_eIndexError,
881
+ "number of indices does not equal to the ndim (%i != %i)",
882
+ info->ndim, ctx.ca_ndim);
883
+ }
884
+
885
+ ca_classifier_finalize_reg(&ctx, is_grid);
886
+ }
887
+ }
888
+
889
+ /* -------------------------------------------------------------------- */
890
+ /* Debug / test surface: CArray._scan_index_v2(dim_array, idx_array)
891
+ returns a plain [type_int, index_array] pair rather than the
892
+ full CAIndexInfo struct. Kept for spec regression checks and
893
+ downstream introspection. */
894
+
895
+ static VALUE
896
+ rb_ca_s_scan_index_v2 (VALUE self, VALUE rdim, VALUE ridx)
897
+ {
898
+ CAIndexInfo info;
899
+ ca_size_t dim[CA_RANK_MAX];
900
+ ca_size_t elements;
901
+ int ndim, i;
902
+ VALUE rindex;
903
+
904
+ Check_Type(rdim, T_ARRAY);
905
+ Check_Type(ridx, T_ARRAY);
906
+
907
+ ndim = (int) RARRAY_LEN(rdim);
908
+ elements = 1;
909
+ for (i = 0; i < ndim; i++) {
910
+ dim[i] = NUM2SIZE(rb_ary_entry(rdim, i));
911
+ elements *= dim[i];
912
+ }
913
+
914
+ CA_CHECK_RANK(ndim);
915
+ CA_CHECK_DIM(ndim, dim);
916
+
917
+ info.range_check = 1;
918
+ rb_ca_scan_index_v2(ndim, dim, elements,
919
+ RARRAY_LEN(ridx),
920
+ (VALUE *) RARRAY_CONST_PTR(ridx), &info);
921
+
922
+ rindex = rb_ary_new();
923
+ switch ( info.type ) {
924
+ case CA_REG_ALL:
925
+ case CA_REG_FLATTEN:
926
+ case CA_REG_SELECT:
927
+ case CA_REG_REPEAT:
928
+ case CA_REG_GRID:
929
+ case CA_REG_MAPPING:
930
+ case CA_REG_METHOD_CALL:
931
+ case CA_REG_MEMBER:
932
+ case CA_REG_ATTRIBUTE:
933
+ break;
934
+ case CA_REG_ADDRESS:
935
+ rb_ary_push(rindex, SIZE2NUM(info.index[0].scalar));
936
+ break;
937
+ case CA_REG_ADDRESS_COMPLEX: {
938
+ /* Recursive flat re-scan: build a 1-D dim = [elements] and
939
+ re-classify; the resulting BLOCK / SCALAR / ALL is wrapped
940
+ in a single-element array so the caller can consume it
941
+ uniformly with the other cases. */
942
+ CAIndexInfo flat_info;
943
+ ca_size_t flat_dim[1];
944
+ VALUE inner;
945
+ flat_dim[0] = elements;
946
+ flat_info.range_check = 1;
947
+ rb_ca_scan_index_v2(1, flat_dim, elements,
948
+ RARRAY_LEN(ridx),
949
+ (VALUE *) RARRAY_CONST_PTR(ridx), &flat_info);
950
+ /* Wrap index[0] as [start, count, step] / scalar / [0, elements, 1]
951
+ depending on which per-axis kind the flat re-scan produced. */
952
+ switch ( flat_info.index_type[0] ) {
953
+ case CA_IDX_BLOCK:
954
+ inner = rb_ary_new3(3,
955
+ SIZE2NUM(flat_info.index[0].block.start),
956
+ SIZE2NUM(flat_info.index[0].block.count),
957
+ SIZE2NUM(flat_info.index[0].block.step));
958
+ rb_ary_push(rindex, inner);
959
+ break;
960
+ case CA_IDX_SCALAR:
961
+ rb_ary_push(rindex, SIZE2NUM(flat_info.index[0].scalar));
962
+ break;
963
+ case CA_IDX_ALL:
964
+ rb_ary_push(rindex,
965
+ rb_ary_new3(3, INT2NUM(0), SIZE2NUM(elements),
966
+ INT2NUM(1)));
967
+ break;
968
+ default: break;
969
+ }
970
+ break;
971
+ }
972
+ case CA_REG_POINT:
973
+ for (i = 0; i < ndim; i++) {
974
+ rb_ary_push(rindex, SIZE2NUM(info.index[i].scalar));
975
+ }
976
+ break;
977
+ case CA_REG_BLOCK:
978
+ case CA_REG_ITERATOR:
979
+ for (i = 0; i < ndim; i++) {
980
+ switch ( info.index_type[i] ) {
981
+ case CA_IDX_SCALAR:
982
+ rb_ary_push(rindex, SIZE2NUM(info.index[i].scalar));
983
+ break;
984
+ case CA_IDX_ALL:
985
+ rb_ary_push(rindex,
986
+ rb_ary_new3(3, INT2NUM(0),
987
+ rb_ary_entry(rdim, i),
988
+ INT2NUM(1)));
989
+ break;
990
+ case CA_IDX_BLOCK:
991
+ rb_ary_push(rindex,
992
+ rb_ary_new3(3,
993
+ SIZE2NUM(info.index[i].block.start),
994
+ SIZE2NUM(info.index[i].block.count),
995
+ SIZE2NUM(info.index[i].block.step)));
996
+ break;
997
+ case CA_IDX_SYMBOL:
998
+ rb_ary_push(rindex,
999
+ rb_ary_new3(2,
1000
+ ID2SYM(info.index[i].symbol.id),
1001
+ info.index[i].symbol.spec));
1002
+ break;
1003
+ default:
1004
+ rb_raise(rb_eRuntimeError, "unknown index spec");
1005
+ }
1006
+ }
1007
+ break;
1008
+ default:
1009
+ rb_raise(rb_eArgError, "unknown index specification");
1010
+ }
1011
+
1012
+ return rb_ary_new3(2, INT2NUM(info.type), rindex);
1013
+ }
1014
+
1015
+ void
1016
+ Init_carray_index_classifier (void)
1017
+ {
1018
+ ca_classifier_sym_cache_init();
1019
+ rb_define_singleton_method(rb_cCArray, "_scan_index_v2",
1020
+ rb_ca_s_scan_index_v2, 2);
1021
+ }