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,671 @@
1
+ # ext/mk_call_cfunc.rb -- generator for ext/carray_call_cfunc.{c,h}
2
+ #
3
+ # Emits the ext-author-facing API `ca_call_cfunc_N` (= raw arity 1..7) and
4
+ # `ca_call_cfunc_M_N` (= typed dispatcher) used by external CArray gems
5
+ # (carray-gsl, etc.) to wrap C math functions over CArray operations.
6
+ #
7
+ # Generated 2026-06-10 as part of the PROPOSAL_EAGER_SLOWPATH_CHUNKING_ARENA
8
+ # attach-elimination flow extension (= D phase): the raw `ca_call_cfunc_N`
9
+ # template applies C.7-style alias / non-alias bifurcation for INPUT-only
10
+ # operands (= fsync[k] == '0') and ca_xfer_all-based safe mask gather (= no
11
+ # `ca_attach` on operand masks). OUTPUT operands (= fsync[k] == '1') still
12
+ # use ca_attach + ca_sync (= legitimate per the refined input-only-operand
13
+ # invariant).
14
+ #
15
+ # ABI 100% preserved: signatures, data_type semantics, fsync format, return
16
+ # behavior all unchanged. External gems link against the same symbols
17
+ # without source change.
18
+ #
19
+ # Why a generator? Each of the 7 raw + 13 typed variants is mechanically
20
+ # the same body with arity differences. Hand-keeping 1088 lines invites
21
+ # divergence (= the attach-safe rewrite would have to be repeated 20 times
22
+ # perfectly). The generator centralises the template so a single edit
23
+ # updates every variant. Add a new arity / typed pair by appending one
24
+ # line to the spec.
25
+ #
26
+ # Header (`carray_call_cfunc.h`) is emitted alongside the source so the
27
+ # extern declarations cannot drift from the function definitions. Both
28
+ # files are written in a single invocation; output paths default to
29
+ # `carray_call_cfunc.c` / `carray_call_cfunc.h` in the current directory
30
+ # and can be overridden as `ruby mk_call_cfunc.rb <src.c> <hdr.h>`.
31
+
32
+ # --- spec -------------------------------------------------------------------
33
+
34
+ RAW_ARITIES = (1..7).to_a # ca_call_cfunc_1 .. _7
35
+ SLAB_ARITIES = (1..7).to_a # ca_call_cslab_1 .. _7
36
+ TYPED_PAIRS = [ # ca_call_cfunc_<m>_<n> (m outputs, n inputs)
37
+ [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6],
38
+ [2, 1], [2, 2], [2, 3], [2, 4],
39
+ [3, 1], [3, 2], [3, 3],
40
+ ]
41
+
42
+ # --- helpers ----------------------------------------------------------------
43
+
44
+ def void_p_list(n)
45
+ (0...n).map { |k| "void *p#{k}" }.join(", ")
46
+ end
47
+
48
+ # For _r variants: callback signature gains a trailing `void *userdata`.
49
+ def void_p_list_r(n)
50
+ void_p_list(n) + ", void *userdata"
51
+ end
52
+
53
+ def value_param_list(n, prefix: "rcx")
54
+ (0...n).map { |k| "VALUE #{prefix}#{k}" }.join(", ")
55
+ end
56
+
57
+ def args_p(n)
58
+ (0...n).map { |k| "p[#{k}]" }.join(", ")
59
+ end
60
+
61
+ # For _r variants: inner call gains a trailing `userdata` arg.
62
+ def args_p_r(n)
63
+ args_p(n) + ", userdata"
64
+ end
65
+
66
+ # --- signature builders -----------------------------------------------------
67
+ #
68
+ # Each builder returns the multi-line function prototype (without trailing
69
+ # `;` or `{`). Source emitters append the body; header emitters append `;`.
70
+ # Centralising signatures here prevents drift between `.c` and `.h`.
71
+
72
+ def sig_raw(n)
73
+ "VALUE\nca_call_cfunc_#{n} (void (*func)(#{void_p_list(n)}), const char *fsync,\n #{value_param_list(n)})"
74
+ end
75
+
76
+ def sig_raw_r(n)
77
+ "VALUE\nca_call_cfunc_#{n}_r (void (*func)(#{void_p_list_r(n)}), const char *fsync,\n #{value_param_list(n)},\n void *userdata)"
78
+ end
79
+
80
+ def typed_params(m, n, r: false)
81
+ dty = ->(k) { m == 1 ? "dty" : "dty#{k + 1}" }
82
+ out_data_type_params = (0...m).map { |k| "int8_t #{dty.(k)}" }
83
+ in_data_type_params = (0...n).map { |k| "int8_t dtx#{k + 1}" }
84
+ in_value_params = (0...n).map { |k| "volatile VALUE rx#{k + 1}" }
85
+ fp_args = ["void*"] * (m + n)
86
+ fp_args << "void *userdata" if r
87
+ func_sig = "void (*mathfunc)(#{fp_args.join(", ")})"
88
+ params = out_data_type_params + in_data_type_params + [func_sig] + in_value_params
89
+ params << "void *userdata" if r
90
+ params.join(", ")
91
+ end
92
+
93
+ def sig_typed(m, n)
94
+ "VALUE\nca_call_cfunc_#{m}_#{n} (#{typed_params(m, n)})"
95
+ end
96
+
97
+ def sig_typed_r(m, n)
98
+ "VALUE\nca_call_cfunc_#{m}_#{n}_r (#{typed_params(m, n, r: true)})"
99
+ end
100
+
101
+ # The typed slab family declares its callback as ca_cslab_t rather than an
102
+ # arity-shaped function pointer: a slab callback takes its operands through
103
+ # `base`, so its signature does not grow with M + N.
104
+ def typed_slab_params(m, n, r: false)
105
+ dty = ->(k) { m == 1 ? "dty" : "dty#{k + 1}" }
106
+ out_data_type_params = (0...m).map { |k| "int8_t #{dty.(k)}" }
107
+ in_data_type_params = (0...n).map { |k| "int8_t dtx#{k + 1}" }
108
+ in_value_params = (0...n).map { |k| "volatile VALUE rx#{k + 1}" }
109
+ func_sig = r ? "ca_cslab_r_t slabfunc" : "ca_cslab_t slabfunc"
110
+ params = out_data_type_params + in_data_type_params + [func_sig] + in_value_params
111
+ params << "void *userdata" if r
112
+ params.join(", ")
113
+ end
114
+
115
+ def sig_typed_slab(m, n)
116
+ "VALUE\nca_call_cslab_#{m}_#{n} (#{typed_slab_params(m, n)})"
117
+ end
118
+
119
+ def sig_typed_slab_r(m, n)
120
+ "VALUE\nca_call_cslab_#{m}_#{n}_r (#{typed_slab_params(m, n, r: true)})"
121
+ end
122
+
123
+ # Re-indent each non-blank line of `s` with `prefix`. `<<~` strips the
124
+ # common leading whitespace from a heredoc, which would leave our body
125
+ # at column 0; we want a 2-space body indent inside the function brace.
126
+ def indent(s, prefix = " ")
127
+ s.each_line.map { |l| l.strip.empty? ? l : prefix + l }.join
128
+ end
129
+
130
+ # --- raw ca_call_cfunc_N ----------------------------------------------------
131
+
132
+ def emit_raw(n)
133
+ $src.puts sig_raw(n)
134
+ $src.puts "{"
135
+ $src.puts indent(<<~END_C)
136
+ CArray *cx[#{n}];
137
+ char *base[#{n}];
138
+ ca_size_t stride[#{n}];
139
+ char *owned_buf[#{n}];
140
+ int attached[#{n}];
141
+ ca_sweep_state_t state;
142
+ int k_op;
143
+
144
+ END_C
145
+ # extract CArray* from VALUE
146
+ (0...n).each do |k|
147
+ $src.puts " TypedData_Get_Struct(rcx#{k}, CArray, &carray_data_type, cx[#{k}]);"
148
+ end
149
+ $src.puts ""
150
+ $src.puts <<~END_C
151
+ /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
152
+ broadcast shape check, mask OR across INPUTs, mask propagate to
153
+ OUTPUTs. Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
154
+ state.n_ops = #{n};
155
+ state.fsync = fsync;
156
+ state.cx = cx;
157
+ state.base = base;
158
+ state.stride = stride;
159
+ state.owned_buf = owned_buf;
160
+ state.attached = attached;
161
+ state.no_mask = 0;
162
+ state.src_label = "ca_call_cfunc_#{n}";
163
+
164
+ ca_sweep_acquire(&state);
165
+
166
+ /* inner loop: advance per-cell ptrs and invoke user kernel func */
167
+ {
168
+ char *p[#{n}];
169
+ ca_size_t k;
170
+ if ( state.m0 ) {
171
+ for ( k = 0; k < state.n_kernel; k++ ) {
172
+ if ( ! state.m0[k] ) {
173
+ for ( k_op = 0; k_op < #{n}; k_op++ ) {
174
+ p[k_op] = base[k_op] + k * stride[k_op];
175
+ }
176
+ func(#{args_p(n)});
177
+ }
178
+ }
179
+ } else {
180
+ for ( k = 0; k < state.n_kernel; k++ ) {
181
+ for ( k_op = 0; k_op < #{n}; k_op++ ) {
182
+ p[k_op] = base[k_op] + k * stride[k_op];
183
+ }
184
+ func(#{args_p(n)});
185
+ }
186
+ }
187
+ }
188
+
189
+ ca_sweep_release(&state);
190
+
191
+ return rcx0;
192
+ }
193
+
194
+ END_C
195
+ end
196
+
197
+ # --- raw ca_call_cfunc_N_r (reentrant: + void *userdata at signature tail) --
198
+ #
199
+ # Variant of emit_raw with a trailing `void *userdata` parameter passed
200
+ # through to every per-cell `func(...)` invocation as its last argument.
201
+ # Naming follows POSIX convention (qsort_r / bsearch_r / strtok_r), where
202
+ # `_r` marks a reentrant form that takes a thunk so the callback no longer
203
+ # depends on file-static / global state. Use when the callback needs to
204
+ # share state with the caller (e.g. accumulators, configuration flags,
205
+ # library plan handles) without resorting to file-static plumbing.
206
+ def emit_raw_r(n)
207
+ $src.puts sig_raw_r(n)
208
+ $src.puts "{"
209
+ $src.puts indent(<<~END_C)
210
+ CArray *cx[#{n}];
211
+ char *base[#{n}];
212
+ ca_size_t stride[#{n}];
213
+ char *owned_buf[#{n}];
214
+ int attached[#{n}];
215
+ ca_sweep_state_t state;
216
+ int k_op;
217
+
218
+ END_C
219
+ (0...n).each do |k|
220
+ $src.puts " TypedData_Get_Struct(rcx#{k}, CArray, &carray_data_type, cx[#{k}]);"
221
+ end
222
+ $src.puts ""
223
+ $src.puts <<~END_C
224
+ /* sweep engine: same lifecycle as ca_call_cfunc_#{n}; the difference is
225
+ the per-cell `func(...)` call has `userdata` as its last argument. */
226
+ state.n_ops = #{n};
227
+ state.fsync = fsync;
228
+ state.cx = cx;
229
+ state.base = base;
230
+ state.stride = stride;
231
+ state.owned_buf = owned_buf;
232
+ state.attached = attached;
233
+ state.no_mask = 0;
234
+ state.src_label = "ca_call_cfunc_#{n}_r";
235
+
236
+ ca_sweep_acquire(&state);
237
+
238
+ {
239
+ char *p[#{n}];
240
+ ca_size_t k;
241
+ if ( state.m0 ) {
242
+ for ( k = 0; k < state.n_kernel; k++ ) {
243
+ if ( ! state.m0[k] ) {
244
+ for ( k_op = 0; k_op < #{n}; k_op++ ) {
245
+ p[k_op] = base[k_op] + k * stride[k_op];
246
+ }
247
+ func(#{args_p_r(n)});
248
+ }
249
+ }
250
+ } else {
251
+ for ( k = 0; k < state.n_kernel; k++ ) {
252
+ for ( k_op = 0; k_op < #{n}; k_op++ ) {
253
+ p[k_op] = base[k_op] + k * stride[k_op];
254
+ }
255
+ func(#{args_p_r(n)});
256
+ }
257
+ }
258
+ }
259
+
260
+ ca_sweep_release(&state);
261
+
262
+ return rcx0;
263
+ }
264
+
265
+ END_C
266
+ end
267
+
268
+ # --- typed dispatchers: M outputs, N inputs ---------------------------------
269
+ #
270
+ # The four typed emitters (cfunc / cfunc_r / cslab / cslab_r) differ in one
271
+ # line -- which lower-level family they delegate to -- and are identical in
272
+ # the wrapping, template allocation and return handling around it. That
273
+ # shared part lives in emit_typed_body so a change to the coercion rules is
274
+ # made once rather than four times, which is the same reason this file is a
275
+ # generator at all.
276
+ #
277
+ # Naming convention (matches legacy ext/carray_call_cfunc.c byte-for-byte):
278
+ # M==1 : output data_type = `dty`, output var = `ry`
279
+ # M >1 : output data_types = `dty1..dtyM`, output vars = `ry1..ryM`
280
+ def emit_typed_body(m, n)
281
+ dty = ->(k) { m == 1 ? "dty" : "dty#{k + 1}" }
282
+ ry = ->(k) { m == 1 ? "ry" : "ry#{k + 1}" }
283
+
284
+ # output VALUE declarations
285
+ out_decl = (0...m).map { |k| "#{ry.(k)} = Qnil" }.join(", ")
286
+ $src.puts " volatile VALUE #{out_decl};"
287
+ $src.puts ""
288
+
289
+ # wrap inputs readonly to declared input data_types
290
+ (0...n).each do |k|
291
+ $src.puts " rx#{k + 1} = rb_ca_wrap_readonly(rx#{k + 1}, INT2NUM(dtx#{k + 1}));"
292
+ end
293
+ $src.puts ""
294
+
295
+ # build one output template per output data_type, widening inputs as needed
296
+ (0...m).each do |out_k|
297
+ cur_dty = dty.(out_k)
298
+ conds = (0...n).map { |in_k| "#{cur_dty} != dtx#{in_k + 1}" }
299
+ wrapped = (0...n).map { |in_k|
300
+ "rb_ca_wrap_readonly(rx#{in_k + 1}, INT2NUM(#{cur_dty}))"
301
+ }
302
+ plain = (0...n).map { |in_k| "rx#{in_k + 1}" }
303
+ $src.puts " if ( #{conds.join(" || ")} ) {"
304
+ $src.puts " #{ry.(out_k)} = rb_ca_template_n(#{n}, #{wrapped.join(", ")});"
305
+ $src.puts " } else {"
306
+ $src.puts " #{ry.(out_k)} = rb_ca_template_n(#{n}, #{plain.join(", ")});"
307
+ $src.puts " }"
308
+ end
309
+ $src.puts ""
310
+
311
+ # delegate to the lower-level family
312
+ args = (0...m).map { |k| ry.(k) } + (0...n).map { |k| "rx#{k + 1}" }
313
+ yield args.join(", ")
314
+ $src.puts ""
315
+
316
+ # return: scalar-fetch each output if rank-0, then assemble
317
+ (0...m).each do |k|
318
+ $src.puts " if ( rb_ca_is_scalar(#{ry.(k)}) ) {"
319
+ $src.puts " #{ry.(k)} = rb_ca_fetch_addr(#{ry.(k)}, 0);"
320
+ $src.puts " }"
321
+ end
322
+ if m == 1
323
+ $src.puts " return #{ry.(0)};"
324
+ else
325
+ list = (0...m).map { |k| ry.(k) }.join(", ")
326
+ $src.puts " return rb_ary_new3(#{m}, #{list});"
327
+ end
328
+ $src.puts "}"
329
+ $src.puts ""
330
+ end
331
+
332
+ def fsync_literal(m, n)
333
+ "1" * m + "0" * n
334
+ end
335
+
336
+ def emit_typed(m, n)
337
+ $src.puts sig_typed(m, n)
338
+ $src.puts "{"
339
+ emit_typed_body(m, n) do |args|
340
+ $src.puts " ca_call_cfunc_#{m + n}(mathfunc, \"#{fsync_literal(m, n)}\", #{args});"
341
+ end
342
+ end
343
+
344
+ # --- typed ca_call_cfunc_M_N_r (reentrant variant) -------------------------
345
+ #
346
+ # Same as emit_typed but the callback signature and outer function gain a
347
+ # trailing `void *userdata`; the inner delegate calls ca_call_cfunc_(M+N)_r
348
+ # and forwards `userdata` through.
349
+ def emit_typed_r(m, n)
350
+ $src.puts sig_typed_r(m, n)
351
+ $src.puts "{"
352
+ emit_typed_body(m, n) do |args|
353
+ $src.puts " ca_call_cfunc_#{m + n}_r(mathfunc, \"#{fsync_literal(m, n)}\", #{args}, userdata);"
354
+ end
355
+ end
356
+
357
+ # --- typed ca_call_cslab_M_N (chunked variant) -----------------------------
358
+ #
359
+ # The same convenience over the slab family: the caller declares the data
360
+ # types its callback works in and gets back a freshly allocated output,
361
+ # rather than allocating one and matching dtypes by hand.
362
+ #
363
+ # This is where chunking pays most, and not by coincidence. Coercion is
364
+ # what this layer is for, and rb_ca_wrap_readonly implements it as a lazy
365
+ # readonly cast view -- which is never attach-alias, so it is exactly the
366
+ # operand kind the whole-buffer path materialises with
367
+ # xmalloc(elements * bytes). Declaring CA_DOUBLE over an int32 array
368
+ # therefore costs a full converted copy through ca_call_cfunc_M_N and one
369
+ # chunk of arena scratch through ca_call_cslab_M_N. The typical use of the
370
+ # typed layer is the case chunking was built for.
371
+ def emit_typed_slab(m, n)
372
+ $src.puts sig_typed_slab(m, n)
373
+ $src.puts "{"
374
+ emit_typed_body(m, n) do |args|
375
+ $src.puts " ca_call_cslab_#{m + n}(slabfunc, \"#{fsync_literal(m, n)}\", #{args});"
376
+ end
377
+ end
378
+
379
+ def emit_typed_slab_r(m, n)
380
+ $src.puts sig_typed_slab_r(m, n)
381
+ $src.puts "{"
382
+ emit_typed_body(m, n) do |args|
383
+ $src.puts " ca_call_cslab_#{m + n}_r(slabfunc, \"#{fsync_literal(m, n)}\", #{args}, userdata);"
384
+ end
385
+ end
386
+
387
+ # --- slab ca_call_cslab_N ---------------------------------------------------
388
+ #
389
+ # The chunked counterpart of ca_call_cfunc_N. Two things differ, and they
390
+ # are the same thing seen from two sides:
391
+ #
392
+ # memory -- ca_sweep_acquire_chunked holds one arena scratch of ~32KB per
393
+ # non-alias INPUT for the whole walk and re-gathers it per chunk, where
394
+ # ca_sweep_acquire materialises each such operand whole. Peak input
395
+ # memory stops scaling with the operand.
396
+ #
397
+ # speed -- the callback is handed a whole chunk rather than one cell, so
398
+ # the indirect call is paid once per few thousand cells instead of once
399
+ # per cell. Measured on `y = a + b*2.0` over 10M doubles: 1.48 ns per
400
+ # element through a per-cell callback against 0.34 ns for the same
401
+ # arithmetic in a loop the compiler can see. A slab callback keeps the
402
+ # loop, so it keeps the 0.34, and it is the shape a vectoriser can work
403
+ # with -- a per-cell callback defeats one by construction.
404
+ #
405
+ # The callback signature does not depend on the arity, because the operands
406
+ # reach it through `base` / `stride` rather than as separate parameters.
407
+ # One typedef therefore serves every ca_call_cslab_N.
408
+ #
409
+ # Masked cells are NOT skipped for the author, as the per-cell form skips
410
+ # them: a slab has no way to leave a hole. The chunk's slice of the mask
411
+ # arrives as `m0` instead -- one byte per cell, indexed 0..n-1 alongside the
412
+ # data, or NULL when no INPUT carried a mask.
413
+ def sig_slab(n)
414
+ "VALUE\nca_call_cslab_#{n} (ca_cslab_t func, const char *fsync,\n #{value_param_list(n)})"
415
+ end
416
+
417
+ def sig_slab_r(n)
418
+ "VALUE\nca_call_cslab_#{n}_r (ca_cslab_r_t func, const char *fsync,\n #{value_param_list(n)},\n void *userdata)"
419
+ end
420
+
421
+ def emit_slab_body(n, name, call)
422
+ $src.puts indent(<<~END_C)
423
+ CArray *cx[#{n}];
424
+ char *base[#{n}];
425
+ char *base_orig[#{n}];
426
+ ca_size_t stride[#{n}];
427
+ char *owned_buf[#{n}];
428
+ int attached[#{n}];
429
+ ca_sweep_state_t state;
430
+
431
+ END_C
432
+ (0...n).each do |k|
433
+ $src.puts " TypedData_Get_Struct(rcx#{k}, CArray, &carray_data_type, cx[#{k}]);"
434
+ end
435
+ $src.puts ""
436
+ $src.puts <<~END_C
437
+ /* sweep engine, chunked path: per-operand acquire (attach for OUTPUT
438
+ and alias INPUT, arena chunk scratch for non-alias INPUT), broadcast
439
+ shape check, mask OR across INPUTs, mask propagate to OUTPUTs at
440
+ release. Lifecycle template lives in ext/ca_sweep_engine.{c,h}.
441
+ base_orig is the field the whole-buffer path leaves zero; the
442
+ chunked path walks it, so it has to be given here. */
443
+ state.n_ops = #{n};
444
+ state.fsync = fsync;
445
+ state.cx = cx;
446
+ state.base = base;
447
+ state.base_orig = base_orig;
448
+ state.stride = stride;
449
+ state.owned_buf = owned_buf;
450
+ state.attached = attached;
451
+ state.no_mask = 0;
452
+ state.src_label = "#{name}";
453
+
454
+ ca_sweep_acquire_chunked(&state);
455
+
456
+ /* outer loop: hand the author one chunk at a time. base[] is rewritten
457
+ per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
458
+ at the arena scratch the chunk was just gathered into, which is
459
+ packed, so stride[] is the element size and the author's inner loop
460
+ sees contiguous data. */
461
+ while ( ca_sweep_next_chunk(&state) ) {
462
+ #{call};
463
+ }
464
+
465
+ ca_sweep_release_chunked(&state);
466
+
467
+ return rcx0;
468
+ }
469
+
470
+ END_C
471
+ end
472
+
473
+ def emit_slab(n)
474
+ $src.puts sig_slab(n)
475
+ $src.puts "{"
476
+ emit_slab_body(n, "ca_call_cslab_#{n}",
477
+ "func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state))")
478
+ end
479
+
480
+ # Variant of emit_slab with a trailing `void *userdata` parameter passed
481
+ # through to every chunk invocation as its last argument, following the same
482
+ # POSIX `_r` convention as ca_call_cfunc_N_r.
483
+ def emit_slab_r(n)
484
+ $src.puts sig_slab_r(n)
485
+ $src.puts "{"
486
+ emit_slab_body(n, "ca_call_cslab_#{n}_r",
487
+ "func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state), userdata)")
488
+ end
489
+
490
+ # --- header declaration emitters --------------------------------------------
491
+
492
+ def decl_raw(n) ; $hdr.puts sig_raw(n) + ";"; $hdr.puts ""; end
493
+ def decl_raw_r(n) ; $hdr.puts sig_raw_r(n) + ";"; $hdr.puts ""; end
494
+ def decl_typed(m, n) ; $hdr.puts sig_typed(m, n) + ";"; $hdr.puts ""; end
495
+ def decl_typed_r(m, n) ; $hdr.puts sig_typed_r(m, n) + ";"; $hdr.puts ""; end
496
+ def decl_typed_slab(m, n) ; $hdr.puts sig_typed_slab(m, n) + ";"; $hdr.puts ""; end
497
+ def decl_typed_slab_r(m, n) ; $hdr.puts sig_typed_slab_r(m, n) + ";"; $hdr.puts ""; end
498
+ def decl_slab(n) ; $hdr.puts sig_slab(n) + ";"; $hdr.puts ""; end
499
+ def decl_slab_r(n) ; $hdr.puts sig_slab_r(n) + ";"; $hdr.puts ""; end
500
+
501
+ # --- main -------------------------------------------------------------------
502
+
503
+ src_path = ARGV[0] || "carray_call_cfunc.c"
504
+ hdr_path = ARGV[1] || "carray_call_cfunc.h"
505
+
506
+ $src = File.open(src_path, "w")
507
+ $hdr = File.open(hdr_path, "w")
508
+
509
+ $src.puts <<~END_C
510
+ /* ---------------------------------------------------------------------------
511
+ *
512
+ * carray_call_cfunc.c -- ext-author math-call wrapper API
513
+ *
514
+ * GENERATED by ext/mk_call_cfunc.rb -- DO NOT EDIT
515
+ * To modify the template or add a new arity, edit mk_call_cfunc.rb
516
+ * and regenerate (= make / extconf re-runs the generator).
517
+ *
518
+ * Provides `ca_call_cfunc_N` (raw arity 1..7) and `ca_call_cfunc_M_N`
519
+ * (typed dispatcher) used by external CArray gems (carray-gsl, etc.)
520
+ * to wrap C math functions over CArray operations.
521
+ *
522
+ * Reentrant variants `ca_call_cfunc_N_r` and `ca_call_cfunc_M_N_r`
523
+ * (= POSIX `_r` convention, cf. qsort_r / bsearch_r / strtok_r) take
524
+ * a trailing `void *userdata` argument that is passed through to every
525
+ * per-cell callback invocation as its last argument. Use when the
526
+ * callback needs to share state with the caller (accumulators,
527
+ * configuration flags, library plan handles, ...) without resorting to
528
+ * file-static / global plumbing.
529
+ *
530
+ * Attach-safe: INPUT-only operands (= fsync[k] == '0') never call
531
+ * ca_attach on the operand or its mask (= alias check + ALLOCV +
532
+ * ca_xfer_all for non-alias). OUTPUT operands (= fsync[k] == '1')
533
+ * use ca_attach + ca_sync (= legitimate per the refined input-only-
534
+ * operand invariant established in PROPOSAL_EAGER_ELEMENTWISE_NO_ATTACH
535
+ * and extended in PROPOSAL_EAGER_SLOWPATH_CHUNKING_ARENA).
536
+ *
537
+ * Slab variants `ca_call_cslab_N` / `ca_call_cslab_N_r` take the chunked
538
+ * path instead (ca_sweep_acquire_chunked / ca_sweep_next_chunk /
539
+ * ca_sweep_release_chunked) and hand the callback a whole chunk -- base /
540
+ * stride per operand, a cell count, and the chunk's slice of the mask --
541
+ * rather than one cell. A non-alias INPUT is then re-gathered into a
542
+ * ~32KB arena scratch per chunk rather than materialised whole, so input
543
+ * memory peak stops scaling with the operand; and the indirect call is
544
+ * paid once per chunk, so the author's inner loop is one the compiler can
545
+ * vectorise. Use cfunc when the per-cell body is what you have (a math
546
+ * function to wrap); use cslab when the operand is large, virtual, or the
547
+ * body is worth vectorising.
548
+ *
549
+ * L0.1 (PROPOSAL_L0_AUTHOR_SURFACE, 2026-06-11): the per-operand acquire
550
+ * + broadcast check + mask OR + release lifecycle is now factored out
551
+ * into ext/ca_sweep_engine.{c,h} (ca_sweep_acquire / ca_sweep_release). This
552
+ * file keeps the arity-dependent inner loop only. ABI unchanged.
553
+ *
554
+ * --------------------------------------------------------------------------- */
555
+
556
+ #include "carray.h"
557
+ #include "ca_sweep_engine.h"
558
+ #include <string.h>
559
+
560
+ /* The chunk's iteration mask, or NULL when no INPUT operand carried one.
561
+ m0 is chunk-sized and re-gathered per chunk by ca_sweep_next_chunk, so
562
+ it is already the slice -- one byte per cell, indexed 0..chunk_n-1
563
+ alongside base[] and stride[]. */
564
+ static const boolean8_t *
565
+ ca_sweep_chunk_mask (ca_sweep_state_t *st)
566
+ {
567
+ return st->m0;
568
+ }
569
+
570
+ END_C
571
+
572
+ $hdr.puts <<~END_H
573
+ /* ---------------------------------------------------------------------------
574
+ *
575
+ * carray_call_cfunc.h -- ext-author math-call wrapper API (declarations)
576
+ *
577
+ * GENERATED by ext/mk_call_cfunc.rb -- DO NOT EDIT
578
+ * Edit mk_call_cfunc.rb and rebuild to refresh both this header and
579
+ * the matching carray_call_cfunc.c.
580
+ *
581
+ * Included from carray.h so external gems pick up these prototypes
582
+ * transparently via `#include "carray.h"`. The generator co-emits
583
+ * source and header so the prototypes cannot drift from the function
584
+ * definitions. See carray_call_cfunc.c for the full design notes.
585
+ *
586
+ * --------------------------------------------------------------------------- */
587
+
588
+ #ifndef CARRAY_CALL_CFUNC_H
589
+ #define CARRAY_CALL_CFUNC_H
590
+
591
+ /* Chunk callback for the ca_call_cslab_N family. `base` and `stride` are
592
+ one entry per operand, in the order the operands were passed; `n` is the
593
+ number of cells in this chunk; `m0` is the chunk's slice of the mask,
594
+ one byte per cell, or NULL when no INPUT carried a mask. The arity does
595
+ not appear in the signature -- the operands arrive through `base` -- so
596
+ one typedef serves every arity. */
597
+ typedef void (*ca_cslab_t) (char **base, ca_size_t *stride, ca_size_t n,
598
+ const boolean8_t *m0);
599
+
600
+ typedef void (*ca_cslab_r_t) (char **base, ca_size_t *stride, ca_size_t n,
601
+ const boolean8_t *m0, void *userdata);
602
+
603
+ END_H
604
+
605
+ RAW_ARITIES.each do |n|
606
+ emit_raw(n)
607
+ decl_raw(n)
608
+ end
609
+
610
+ $src.puts "/* -------------------------------------------------------------------- */"
611
+ $src.puts "/* Typed dispatchers: M outputs, N inputs. Wrap each input readonly to */"
612
+ $src.puts "/* its declared data_type, allocate output template(s), delegate to raw. */"
613
+ $src.puts "/* -------------------------------------------------------------------- */"
614
+ $src.puts ""
615
+
616
+ TYPED_PAIRS.each do |m, n|
617
+ emit_typed(m, n)
618
+ decl_typed(m, n)
619
+ end
620
+
621
+ $src.puts "/* -------------------------------------------------------------------- */"
622
+ $src.puts "/* Reentrant variants (`_r` suffix, POSIX convention): same as the */"
623
+ $src.puts "/* corresponding non-`_r` variant but the callback takes a trailing */"
624
+ $src.puts "/* `void *userdata` argument and the outer function takes a trailing */"
625
+ $src.puts "/* `void *userdata` parameter forwarded to every per-cell invocation. */"
626
+ $src.puts "/* -------------------------------------------------------------------- */"
627
+ $src.puts ""
628
+
629
+ RAW_ARITIES.each do |n|
630
+ emit_raw_r(n)
631
+ decl_raw_r(n)
632
+ end
633
+
634
+ TYPED_PAIRS.each do |m, n|
635
+ emit_typed_r(m, n)
636
+ decl_typed_r(m, n)
637
+ end
638
+
639
+ $src.puts "/* -------------------------------------------------------------------- */"
640
+ $src.puts "/* Slab variants: the chunked counterpart of ca_call_cfunc_N. The */"
641
+ $src.puts "/* callback is handed a whole chunk (base / stride / count / mask */"
642
+ $src.puts "/* slice) rather than one cell, and non-alias INPUTs are gathered */"
643
+ $src.puts "/* into a ~32KB arena scratch per chunk instead of materialised */"
644
+ $src.puts "/* whole, so input memory peak stops scaling with the operand. */"
645
+ $src.puts "/* -------------------------------------------------------------------- */"
646
+ $src.puts ""
647
+
648
+ SLAB_ARITIES.each do |n|
649
+ emit_slab(n)
650
+ decl_slab(n)
651
+ end
652
+
653
+ SLAB_ARITIES.each do |n|
654
+ emit_slab_r(n)
655
+ decl_slab_r(n)
656
+ end
657
+
658
+ TYPED_PAIRS.each do |m, n|
659
+ emit_typed_slab(m, n)
660
+ decl_typed_slab(m, n)
661
+ end
662
+
663
+ TYPED_PAIRS.each do |m, n|
664
+ emit_typed_slab_r(m, n)
665
+ decl_typed_slab_r(m, n)
666
+ end
667
+
668
+ $hdr.puts "#endif /* CARRAY_CALL_CFUNC_H */"
669
+
670
+ $src.close
671
+ $hdr.close