carray 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +5 -25
  3. data/CHANGELOG.md +16 -0
  4. data/LICENSE +1 -1
  5. data/NEWS.md +3 -0
  6. data/README.md +128 -44
  7. data/carray.gemspec +22 -24
  8. data/ext/ca_array_pool.c +91 -0
  9. data/ext/ca_axis_descriptor.h +186 -0
  10. data/ext/ca_axis_dispatch.c +924 -0
  11. data/ext/ca_axis_group.c +1208 -0
  12. data/ext/ca_bincmp_dispatch.c +76 -0
  13. data/ext/ca_bincmp_dispatch.h +85 -0
  14. data/ext/ca_binop_dispatch.c +125 -0
  15. data/ext/ca_binop_dispatch.h +159 -0
  16. data/ext/ca_categorical_iterator.c +1375 -0
  17. data/ext/ca_compare.c +94 -0
  18. data/ext/ca_compare.h +26 -0
  19. data/ext/ca_composite_dispatch.c +414 -0
  20. data/ext/ca_composite_dispatch.h +116 -0
  21. data/ext/ca_for_buffer.h +96 -0
  22. data/ext/ca_for_each_element.h +241 -0
  23. data/ext/ca_group_iter.c +304 -0
  24. data/ext/ca_iter_substrate.h +325 -0
  25. data/ext/ca_kernel_iterator.c +4321 -0
  26. data/ext/ca_kernel_iterator.h +2603 -0
  27. data/ext/ca_moncmp_dispatch.c +37 -0
  28. data/ext/ca_moncmp_dispatch.h +62 -0
  29. data/ext/ca_monop_dispatch.c +200 -0
  30. data/ext/ca_monop_dispatch.h +235 -0
  31. data/ext/ca_obj_array.c +355 -359
  32. data/ext/ca_obj_bincmp.c +809 -0
  33. data/ext/ca_obj_binop.c +892 -0
  34. data/ext/ca_obj_bitarray.c +369 -164
  35. data/ext/ca_obj_bitfield.c +294 -234
  36. data/ext/ca_obj_block.c +189 -711
  37. data/ext/ca_obj_byte_swap.c +766 -0
  38. data/ext/ca_obj_const_string.c +965 -0
  39. data/ext/ca_obj_face.c +670 -0
  40. data/ext/ca_obj_face.h +247 -0
  41. data/ext/ca_obj_fake.c +228 -100
  42. data/ext/ca_obj_farray.c +54 -441
  43. data/ext/ca_obj_field.c +82 -529
  44. data/ext/ca_obj_fixlen_string.c +306 -0
  45. data/ext/ca_obj_grid.c +858 -440
  46. data/ext/ca_obj_meld.c +1034 -0
  47. data/ext/ca_obj_moncmp.c +569 -0
  48. data/ext/ca_obj_monop.c +1111 -0
  49. data/ext/ca_obj_object.c +774 -298
  50. data/ext/ca_obj_record.c +468 -0
  51. data/ext/ca_obj_reduce.c +97 -82
  52. data/ext/ca_obj_refer.c +569 -459
  53. data/ext/ca_obj_remap.c +475 -0
  54. data/ext/ca_obj_repeat.c +92 -477
  55. data/ext/ca_obj_roll.c +616 -0
  56. data/ext/ca_obj_select.c +344 -296
  57. data/ext/ca_obj_select_axis.c +1296 -0
  58. data/ext/ca_obj_shift.c +230 -792
  59. data/ext/ca_obj_source.c +78 -0
  60. data/ext/ca_obj_stack.c +1173 -0
  61. data/ext/ca_obj_stride.c +2501 -0
  62. data/ext/ca_obj_string.c +268 -0
  63. data/ext/ca_obj_tile.c +614 -0
  64. data/ext/ca_obj_time.c +546 -0
  65. data/ext/ca_obj_timedelta.c +435 -0
  66. data/ext/ca_obj_transpose.c +62 -516
  67. data/ext/ca_obj_triop.c +746 -0
  68. data/ext/ca_obj_unbound_repeat.c +208 -241
  69. data/ext/ca_obj_window.c +1131 -563
  70. data/ext/ca_op_byte_swap.c +175 -0
  71. data/ext/ca_op_ipower.c +319 -0
  72. data/ext/ca_op_powi.h +88 -0
  73. data/ext/ca_sort_kernels.h +132 -0
  74. data/ext/ca_sweep_engine.c +430 -0
  75. data/ext/ca_sweep_engine.h +157 -0
  76. data/ext/ca_transform_common.c +228 -0
  77. data/ext/ca_triop_dispatch.c +55 -0
  78. data/ext/ca_triop_dispatch.h +62 -0
  79. data/ext/carray.h +795 -402
  80. data/ext/carray_access.c +831 -711
  81. data/ext/carray_attribute.c +98 -330
  82. data/ext/carray_bincount.c +255 -0
  83. data/ext/carray_broadcast.c +283 -0
  84. data/ext/carray_call_cfunc.c +1360 -828
  85. data/ext/carray_call_cfunc.h +160 -0
  86. data/ext/carray_cast.c +1212 -301
  87. data/ext/carray_cast_func.rb +81 -40
  88. data/ext/carray_class.c +53 -63
  89. data/ext/carray_config.h +28 -0
  90. data/ext/carray_conversion.c +350 -346
  91. data/ext/carray_copy.c +156 -268
  92. data/ext/carray_core.c +1342 -199
  93. data/ext/carray_count.c +312 -0
  94. data/ext/carray_data_type.c +43 -19
  95. data/ext/carray_element.c +585 -213
  96. data/ext/carray_factorize.c +2542 -0
  97. data/ext/carray_generate.c +230 -559
  98. data/ext/carray_histogram.c +490 -0
  99. data/ext/carray_hold.c +228 -0
  100. data/ext/carray_index_classifier.c +1035 -0
  101. data/ext/carray_index_classifier.h +27 -0
  102. data/ext/carray_internal.h +120 -0
  103. data/ext/carray_kernels_bincmp.c +4445 -0
  104. data/ext/carray_kernels_binop.c +10979 -0
  105. data/ext/carray_kernels_init.c +36 -0
  106. data/ext/carray_kernels_map.c +3466 -0
  107. data/ext/carray_kernels_moncmp.c +2096 -0
  108. data/ext/carray_kernels_monop.c +18312 -0
  109. data/ext/carray_kernels_reduce_aggregate.c +25836 -0
  110. data/ext/carray_kernels_reduce_boolean.c +329 -0
  111. data/ext/carray_kernels_reduce_cumulative.c +14592 -0
  112. data/ext/carray_kernels_reduce_extreme.c +16947 -0
  113. data/ext/carray_kernels_reduce_variance.c +3909 -0
  114. data/ext/carray_kernels_scan.c +3692 -0
  115. data/ext/carray_kernels_search.c +32137 -0
  116. data/ext/carray_kernels_sort.c +10625 -0
  117. data/ext/carray_kernels_triop.c +1391 -0
  118. data/ext/carray_lazy.c +567 -0
  119. data/ext/carray_loop.c +88 -200
  120. data/ext/carray_mask.c +848 -154
  121. data/ext/carray_math_kernel.h +120 -0
  122. data/ext/carray_mathfunc.c +10 -241
  123. data/ext/carray_median_percentile.c +1257 -0
  124. data/ext/carray_memory_view.c +1625 -0
  125. data/ext/carray_operator.c +1526 -318
  126. data/ext/carray_order.c +664 -1394
  127. data/ext/carray_partition.c +416 -0
  128. data/ext/carray_random.c +518 -0
  129. data/ext/carray_scatter.c +357 -0
  130. data/ext/carray_slab.c +1219 -0
  131. data/ext/carray_slab.h +84 -0
  132. data/ext/carray_sort.c +829 -0
  133. data/ext/carray_sort_kernel.c +620 -0
  134. data/ext/carray_struct.c +695 -0
  135. data/ext/carray_test.c +343 -229
  136. data/ext/carray_undef.c +34 -17
  137. data/ext/carray_utils.c +175 -74
  138. data/ext/extconf.rb +216 -55
  139. data/ext/mk_call_cfunc.rb +480 -0
  140. data/ext/mkkernel.rb +8842 -0
  141. data/ext/ruby_carray.c +202 -101
  142. data/ext/version.h +4 -14
  143. data/ext/version.rb +5 -13
  144. data/lib/carray/arrow_tensor.rb +401 -0
  145. data/lib/carray/attribute.rb +166 -0
  146. data/lib/carray/autoload_carray.rb +220 -0
  147. data/lib/carray/autoload_method_extension.rb +44 -0
  148. data/lib/carray/axis_group.rb +711 -0
  149. data/lib/carray/basics.rb +481 -0
  150. data/lib/carray/bincount_nd.rb +358 -0
  151. data/lib/carray/block_iterator.rb +604 -0
  152. data/lib/carray/boolean_reduce.rb +109 -0
  153. data/lib/carray/categorical.rb +561 -0
  154. data/lib/carray/categorical_iterator.rb +1062 -0
  155. data/lib/carray/complex.rb +150 -0
  156. data/lib/carray/conditional.rb +216 -0
  157. data/lib/carray/const_string.rb +228 -0
  158. data/lib/carray/construct.rb +139 -328
  159. data/lib/carray/core_extensions.rb +240 -0
  160. data/lib/carray/data_type_extension.rb +233 -0
  161. data/lib/carray/fixlen_string.rb +95 -0
  162. data/lib/carray/frame/concat.rb +132 -0
  163. data/lib/carray/frame/convert.rb +95 -0
  164. data/lib/carray/frame/csv_parser.rb +211 -0
  165. data/lib/carray/frame/frame.rb +649 -0
  166. data/lib/carray/frame/group.rb +186 -0
  167. data/lib/carray/frame/io.rb +164 -0
  168. data/lib/carray/frame/join.rb +248 -0
  169. data/lib/carray/frame/records.rb +99 -0
  170. data/lib/carray/frame/sort.rb +113 -0
  171. data/lib/carray/frame/verbs.rb +299 -0
  172. data/lib/carray/frame.rb +16 -0
  173. data/lib/carray/histogram.rb +512 -0
  174. data/lib/carray/inspect.rb +37 -20
  175. data/lib/carray/iterator.rb +57 -349
  176. data/lib/carray/lazy.rb +889 -0
  177. data/lib/carray/mask_gap_fill.rb +200 -0
  178. data/lib/carray/math.rb +78 -342
  179. data/lib/carray/meld_reduce.rb +289 -0
  180. data/lib/carray/methods/align_addr.rb +116 -0
  181. data/lib/carray/methods/bin.rb +128 -0
  182. data/lib/carray/methods/bincount.rb +87 -0
  183. data/lib/carray/methods/bit_string.rb +92 -0
  184. data/lib/carray/methods/broadcast.rb +63 -0
  185. data/lib/carray/methods/choose.rb +39 -0
  186. data/lib/carray/methods/composition.rb +280 -0
  187. data/lib/carray/methods/gather_nd.rb +206 -0
  188. data/lib/carray/methods/index.rb +39 -0
  189. data/lib/carray/methods/insert_block.rb +99 -0
  190. data/lib/carray/methods/is_in.rb +141 -0
  191. data/lib/carray/methods/join.rb +90 -0
  192. data/lib/carray/methods/locate_addr.rb +47 -0
  193. data/lib/carray/methods/mask_duplicates.rb +41 -0
  194. data/lib/carray/methods/meshgrid.rb +91 -0
  195. data/lib/carray/methods/mode.rb +126 -0
  196. data/lib/carray/methods/nunique.rb +46 -0
  197. data/lib/carray/methods/resize.rb +56 -0
  198. data/lib/carray/methods/snap.rb +156 -0
  199. data/lib/carray/methods/string_format.rb +57 -0
  200. data/lib/carray/methods/unique.rb +47 -0
  201. data/lib/carray/methods/value_counts.rb +71 -0
  202. data/lib/carray/mkmf.rb +124 -101
  203. data/lib/carray/runtime.rb +108 -0
  204. data/lib/carray/serialize.rb +478 -167
  205. data/lib/carray/slab_iterator.rb +292 -0
  206. data/lib/carray/stack.rb +291 -0
  207. data/lib/carray/string.rb +56 -180
  208. data/lib/carray/string_operation_extension.rb +289 -0
  209. data/lib/carray/struct.rb +335 -323
  210. data/lib/carray/struct_builder.rb +697 -0
  211. data/lib/carray/table.rb +41 -2
  212. data/lib/carray/time.rb +2255 -38
  213. data/lib/carray/window_iterator.rb +655 -0
  214. data/lib/carray.rb +55 -57
  215. metadata +163 -130
  216. data/Rakefile +0 -51
  217. data/TODO.md +0 -18
  218. data/ext/ca_iter_block.c +0 -257
  219. data/ext/ca_iter_dimension.c +0 -299
  220. data/ext/ca_iter_window.c +0 -214
  221. data/ext/ca_obj_mapping.c +0 -644
  222. data/ext/carray_iterator.c +0 -641
  223. data/ext/carray_math.rb +0 -850
  224. data/ext/carray_numeric.c +0 -259
  225. data/ext/carray_sort_addr.c +0 -254
  226. data/ext/carray_stat.c +0 -2100
  227. data/ext/carray_stat_proc.rb +0 -1999
  228. data/ext/mkmath.rb +0 -741
  229. data/ext/ruby_ccomplex.c +0 -509
  230. data/ext/ruby_float_func.c +0 -86
  231. data/lib/carray/array.rb +0 -8
  232. data/lib/carray/autoload/autoload_base.rb +0 -19
  233. data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
  234. data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
  235. data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
  236. data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
  237. data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
  238. data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
  239. data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
  240. data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
  241. data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
  242. data/lib/carray/autoload/autoload_gem_random.rb +0 -8
  243. data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
  244. data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
  245. data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
  246. data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
  247. data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
  248. data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
  249. data/lib/carray/autoload/autoload_object_link.rb +0 -1
  250. data/lib/carray/autoload/autoload_object_pack.rb +0 -2
  251. data/lib/carray/autoload.rb +0 -141
  252. data/lib/carray/basic.rb +0 -191
  253. data/lib/carray/broadcast.rb +0 -101
  254. data/lib/carray/compose.rb +0 -315
  255. data/lib/carray/convert.rb +0 -115
  256. data/lib/carray/info.rb +0 -110
  257. data/lib/carray/io/imagemagick.rb +0 -235
  258. data/lib/carray/mask.rb +0 -102
  259. data/lib/carray/math/histogram.rb +0 -177
  260. data/lib/carray/math/recurrence.rb +0 -93
  261. data/lib/carray/object/ca_obj_iterator.rb +0 -50
  262. data/lib/carray/object/ca_obj_link.rb +0 -50
  263. data/lib/carray/object/ca_obj_pack.rb +0 -99
  264. data/lib/carray/obsolete.rb +0 -256
  265. data/lib/carray/ordering.rb +0 -181
  266. data/lib/carray/testing.rb +0 -51
  267. data/lib/carray/transform.rb +0 -109
  268. data/misc/Methods.ja.md +0 -182
  269. data/misc/NOTE +0 -51
  270. data/spec/Classes/CABitfield_spec.rb +0 -58
  271. data/spec/Classes/CABlockIterator_spec.rb +0 -114
  272. data/spec/Classes/CABlock_spec.rb +0 -205
  273. data/spec/Classes/CAField_spec.rb +0 -39
  274. data/spec/Classes/CAGrid_spec.rb +0 -75
  275. data/spec/Classes/CAMap_spec.rb +0 -0
  276. data/spec/Classes/CAMapping_spec.rb +0 -105
  277. data/spec/Classes/CAObject_attribute_spec.rb +0 -33
  278. data/spec/Classes/CAObject_spec.rb +0 -33
  279. data/spec/Classes/CARefer_spec.rb +0 -93
  280. data/spec/Classes/CARepeat_spec.rb +0 -65
  281. data/spec/Classes/CASelect_spec.rb +0 -22
  282. data/spec/Classes/CAShift_spec.rb +0 -16
  283. data/spec/Classes/CAStruct_spec.rb +0 -71
  284. data/spec/Classes/CATranspose_spec.rb +0 -60
  285. data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
  286. data/spec/Classes/CAWindow_spec.rb +0 -54
  287. data/spec/Classes/CAWrap_spec.rb +0 -8
  288. data/spec/Classes/CArray_spec.rb +0 -184
  289. data/spec/Classes/CScalar_spec.rb +0 -55
  290. data/spec/Classes/ex1.rb +0 -46
  291. data/spec/Features/feature_130_spec.rb +0 -19
  292. data/spec/Features/feature_attributes_spec.rb +0 -280
  293. data/spec/Features/feature_boolean_spec.rb +0 -98
  294. data/spec/Features/feature_broadcast.rb +0 -116
  295. data/spec/Features/feature_cast_function.rb +0 -19
  296. data/spec/Features/feature_cast_spec.rb +0 -33
  297. data/spec/Features/feature_class_spec.rb +0 -84
  298. data/spec/Features/feature_complex_spec.rb +0 -42
  299. data/spec/Features/feature_composite_spec.rb +0 -124
  300. data/spec/Features/feature_convert_spec.rb +0 -46
  301. data/spec/Features/feature_copy_spec.rb +0 -123
  302. data/spec/Features/feature_creation_spec.rb +0 -84
  303. data/spec/Features/feature_element_spec.rb +0 -144
  304. data/spec/Features/feature_extream_spec.rb +0 -54
  305. data/spec/Features/feature_generate_spec.rb +0 -74
  306. data/spec/Features/feature_index_spec.rb +0 -69
  307. data/spec/Features/feature_mask_spec.rb +0 -580
  308. data/spec/Features/feature_math_spec.rb +0 -97
  309. data/spec/Features/feature_order_spec.rb +0 -146
  310. data/spec/Features/feature_ref_store_spec.rb +0 -209
  311. data/spec/Features/feature_serialization_spec.rb +0 -125
  312. data/spec/Features/feature_stat_spec.rb +0 -397
  313. data/spec/Features/feature_virtual_spec.rb +0 -48
  314. data/spec/Features/method_eq_spec.rb +0 -81
  315. data/spec/Features/method_is_nan_spec.rb +0 -12
  316. data/spec/Features/method_map_spec.rb +0 -54
  317. data/spec/Features/method_max_with.rb +0 -20
  318. data/spec/Features/method_min_with.rb +0 -19
  319. data/spec/Features/method_ne_spec.rb +0 -18
  320. data/spec/Features/method_project_spec.rb +0 -188
  321. data/spec/Features/method_ref_spec.rb +0 -27
  322. data/spec/Features/method_round_spec.rb +0 -11
  323. data/spec/Features/method_s_linspace_spec.rb +0 -48
  324. data/spec/Features/method_s_span_spec.rb +0 -14
  325. data/spec/Features/method_seq_spec.rb +0 -47
  326. data/spec/Features/method_sort_with.rb +0 -43
  327. data/spec/Features/method_sorted_with.rb +0 -29
  328. data/spec/Features/method_span_spec.rb +0 -42
  329. data/spec/Features/method_wrap_readonly_spec.rb +0 -43
  330. data/spec/UnitTest/test_CAVirtual.rb +0 -214
  331. data/spec/spec_all.rb +0 -10
  332. data/utils/ca_ase.rb +0 -21
  333. data/utils/ca_methods.rb +0 -15
  334. data/utils/cast_checker.rb +0 -30
  335. data/utils/convert_test.rb +0 -73
  336. data/utils/extract_yard.rb +0 -22
  337. data/utils/guess_shape.rb +0 -76
  338. data/utils/monkey_patch_methods.rb +0 -62
  339. data/utils/remove_resource_fork.sh +0 -5
@@ -0,0 +1,480 @@
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
+ TYPED_PAIRS = [ # ca_call_cfunc_<m>_<n> (m outputs, n inputs)
36
+ [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6],
37
+ [2, 1], [2, 2], [2, 3], [2, 4],
38
+ [3, 1], [3, 2], [3, 3],
39
+ ]
40
+
41
+ # --- helpers ----------------------------------------------------------------
42
+
43
+ def void_p_list(n)
44
+ (0...n).map { |k| "void *p#{k}" }.join(", ")
45
+ end
46
+
47
+ # For _r variants: callback signature gains a trailing `void *userdata`.
48
+ def void_p_list_r(n)
49
+ void_p_list(n) + ", void *userdata"
50
+ end
51
+
52
+ def value_param_list(n, prefix: "rcx")
53
+ (0...n).map { |k| "VALUE #{prefix}#{k}" }.join(", ")
54
+ end
55
+
56
+ def args_p(n)
57
+ (0...n).map { |k| "p[#{k}]" }.join(", ")
58
+ end
59
+
60
+ # For _r variants: inner call gains a trailing `userdata` arg.
61
+ def args_p_r(n)
62
+ args_p(n) + ", userdata"
63
+ end
64
+
65
+ # --- signature builders -----------------------------------------------------
66
+ #
67
+ # Each builder returns the multi-line function prototype (without trailing
68
+ # `;` or `{`). Source emitters append the body; header emitters append `;`.
69
+ # Centralising signatures here prevents drift between `.c` and `.h`.
70
+
71
+ def sig_raw(n)
72
+ "VALUE\nca_call_cfunc_#{n} (void (*func)(#{void_p_list(n)}), const char *fsync,\n #{value_param_list(n)})"
73
+ end
74
+
75
+ def sig_raw_r(n)
76
+ "VALUE\nca_call_cfunc_#{n}_r (void (*func)(#{void_p_list_r(n)}), const char *fsync,\n #{value_param_list(n)},\n void *userdata)"
77
+ end
78
+
79
+ def typed_params(m, n, r: false)
80
+ dty = ->(k) { m == 1 ? "dty" : "dty#{k + 1}" }
81
+ out_data_type_params = (0...m).map { |k| "int8_t #{dty.(k)}" }
82
+ in_data_type_params = (0...n).map { |k| "int8_t dtx#{k + 1}" }
83
+ in_value_params = (0...n).map { |k| "volatile VALUE rx#{k + 1}" }
84
+ fp_args = ["void*"] * (m + n)
85
+ fp_args << "void *userdata" if r
86
+ func_sig = "void (*mathfunc)(#{fp_args.join(", ")})"
87
+ params = out_data_type_params + in_data_type_params + [func_sig] + in_value_params
88
+ params << "void *userdata" if r
89
+ params.join(", ")
90
+ end
91
+
92
+ def sig_typed(m, n)
93
+ "VALUE\nca_call_cfunc_#{m}_#{n} (#{typed_params(m, n)})"
94
+ end
95
+
96
+ def sig_typed_r(m, n)
97
+ "VALUE\nca_call_cfunc_#{m}_#{n}_r (#{typed_params(m, n, r: true)})"
98
+ end
99
+
100
+ # Re-indent each non-blank line of `s` with `prefix`. `<<~` strips the
101
+ # common leading whitespace from a heredoc, which would leave our body
102
+ # at column 0; we want a 2-space body indent inside the function brace.
103
+ def indent(s, prefix = " ")
104
+ s.each_line.map { |l| l.strip.empty? ? l : prefix + l }.join
105
+ end
106
+
107
+ # --- raw ca_call_cfunc_N ----------------------------------------------------
108
+
109
+ def emit_raw(n)
110
+ $src.puts sig_raw(n)
111
+ $src.puts "{"
112
+ $src.puts indent(<<~END_C)
113
+ CArray *cx[#{n}];
114
+ char *base[#{n}];
115
+ ca_size_t stride[#{n}];
116
+ char *owned_buf[#{n}];
117
+ int attached[#{n}];
118
+ ca_sweep_state_t state;
119
+ int k_op;
120
+
121
+ END_C
122
+ # extract CArray* from VALUE
123
+ (0...n).each do |k|
124
+ $src.puts " TypedData_Get_Struct(rcx#{k}, CArray, &carray_data_type, cx[#{k}]);"
125
+ end
126
+ $src.puts ""
127
+ $src.puts <<~END_C
128
+ /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
129
+ broadcast shape check, mask OR across INPUTs, mask propagate to
130
+ OUTPUTs. Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
131
+ state.n_ops = #{n};
132
+ state.fsync = fsync;
133
+ state.cx = cx;
134
+ state.base = base;
135
+ state.stride = stride;
136
+ state.owned_buf = owned_buf;
137
+ state.attached = attached;
138
+ state.no_mask = 0;
139
+ state.src_label = "ca_call_cfunc_#{n}";
140
+
141
+ ca_sweep_acquire(&state);
142
+
143
+ /* inner loop: advance per-cell ptrs and invoke user kernel func */
144
+ {
145
+ char *p[#{n}];
146
+ ca_size_t k;
147
+ if ( state.m0 ) {
148
+ for ( k = 0; k < state.n_kernel; k++ ) {
149
+ if ( ! state.m0[k] ) {
150
+ for ( k_op = 0; k_op < #{n}; k_op++ ) {
151
+ p[k_op] = base[k_op] + k * stride[k_op];
152
+ }
153
+ func(#{args_p(n)});
154
+ }
155
+ }
156
+ } else {
157
+ for ( k = 0; k < state.n_kernel; k++ ) {
158
+ for ( k_op = 0; k_op < #{n}; k_op++ ) {
159
+ p[k_op] = base[k_op] + k * stride[k_op];
160
+ }
161
+ func(#{args_p(n)});
162
+ }
163
+ }
164
+ }
165
+
166
+ ca_sweep_release(&state);
167
+
168
+ return rcx0;
169
+ }
170
+
171
+ END_C
172
+ end
173
+
174
+ # --- raw ca_call_cfunc_N_r (reentrant: + void *userdata at signature tail) --
175
+ #
176
+ # Variant of emit_raw with a trailing `void *userdata` parameter passed
177
+ # through to every per-cell `func(...)` invocation as its last argument.
178
+ # Naming follows POSIX convention (qsort_r / bsearch_r / strtok_r), where
179
+ # `_r` marks a reentrant form that takes a thunk so the callback no longer
180
+ # depends on file-static / global state. Use when the callback needs to
181
+ # share state with the caller (e.g. accumulators, configuration flags,
182
+ # library plan handles) without resorting to file-static plumbing.
183
+ def emit_raw_r(n)
184
+ $src.puts sig_raw_r(n)
185
+ $src.puts "{"
186
+ $src.puts indent(<<~END_C)
187
+ CArray *cx[#{n}];
188
+ char *base[#{n}];
189
+ ca_size_t stride[#{n}];
190
+ char *owned_buf[#{n}];
191
+ int attached[#{n}];
192
+ ca_sweep_state_t state;
193
+ int k_op;
194
+
195
+ END_C
196
+ (0...n).each do |k|
197
+ $src.puts " TypedData_Get_Struct(rcx#{k}, CArray, &carray_data_type, cx[#{k}]);"
198
+ end
199
+ $src.puts ""
200
+ $src.puts <<~END_C
201
+ /* sweep engine: same lifecycle as ca_call_cfunc_#{n}; the difference is
202
+ the per-cell `func(...)` call has `userdata` as its last argument. */
203
+ state.n_ops = #{n};
204
+ state.fsync = fsync;
205
+ state.cx = cx;
206
+ state.base = base;
207
+ state.stride = stride;
208
+ state.owned_buf = owned_buf;
209
+ state.attached = attached;
210
+ state.no_mask = 0;
211
+ state.src_label = "ca_call_cfunc_#{n}_r";
212
+
213
+ ca_sweep_acquire(&state);
214
+
215
+ {
216
+ char *p[#{n}];
217
+ ca_size_t k;
218
+ if ( state.m0 ) {
219
+ for ( k = 0; k < state.n_kernel; k++ ) {
220
+ if ( ! state.m0[k] ) {
221
+ for ( k_op = 0; k_op < #{n}; k_op++ ) {
222
+ p[k_op] = base[k_op] + k * stride[k_op];
223
+ }
224
+ func(#{args_p_r(n)});
225
+ }
226
+ }
227
+ } else {
228
+ for ( k = 0; k < state.n_kernel; k++ ) {
229
+ for ( k_op = 0; k_op < #{n}; k_op++ ) {
230
+ p[k_op] = base[k_op] + k * stride[k_op];
231
+ }
232
+ func(#{args_p_r(n)});
233
+ }
234
+ }
235
+ }
236
+
237
+ ca_sweep_release(&state);
238
+
239
+ return rcx0;
240
+ }
241
+
242
+ END_C
243
+ end
244
+
245
+ # --- typed ca_call_cfunc_M_N ------------------------------------------------
246
+
247
+ def emit_typed(m, n)
248
+ total = m + n
249
+ # Naming convention (matches legacy ext/carray_call_cfunc.c byte-for-byte):
250
+ # M==1 : output data_type = `dty`, output var = `ry`
251
+ # M >1 : output data_types = `dty1..dtyM`, output vars = `ry1..ryM`
252
+ dty = ->(k) { m == 1 ? "dty" : "dty#{k + 1}" }
253
+ ry = ->(k) { m == 1 ? "ry" : "ry#{k + 1}" }
254
+
255
+ fsync_str = "1" * m + "0" * n
256
+
257
+ $src.puts sig_typed(m, n)
258
+ $src.puts "{"
259
+
260
+ # output VALUE declarations
261
+ out_decl = (0...m).map { |k| "#{ry.(k)} = Qnil" }.join(", ")
262
+ $src.puts " volatile VALUE #{out_decl};"
263
+ $src.puts ""
264
+
265
+ # wrap inputs readonly to declared input data_types
266
+ (0...n).each do |k|
267
+ $src.puts " rx#{k + 1} = rb_ca_wrap_readonly(rx#{k + 1}, INT2NUM(dtx#{k + 1}));"
268
+ end
269
+ $src.puts ""
270
+
271
+ # build one output template per output data_type, widening inputs as needed
272
+ (0...m).each do |out_k|
273
+ cur_dty = dty.(out_k)
274
+ conds = (0...n).map { |in_k| "#{cur_dty} != dtx#{in_k + 1}" }
275
+ wrapped = (0...n).map { |in_k|
276
+ "rb_ca_wrap_readonly(rx#{in_k + 1}, INT2NUM(#{cur_dty}))"
277
+ }
278
+ plain = (0...n).map { |in_k| "rx#{in_k + 1}" }
279
+ $src.puts " if ( #{conds.join(" || ")} ) {"
280
+ $src.puts " #{ry.(out_k)} = rb_ca_template_n(#{n}, #{wrapped.join(", ")});"
281
+ $src.puts " } else {"
282
+ $src.puts " #{ry.(out_k)} = rb_ca_template_n(#{n}, #{plain.join(", ")});"
283
+ $src.puts " }"
284
+ end
285
+ $src.puts ""
286
+
287
+ # delegate to lower-level ca_call_cfunc_(m+n)
288
+ args = (0...m).map { |k| ry.(k) } + (0...n).map { |k| "rx#{k + 1}" }
289
+ $src.puts " ca_call_cfunc_#{total}(mathfunc, \"#{fsync_str}\", #{args.join(", ")});"
290
+ $src.puts ""
291
+
292
+ # return: scalar-fetch each output if rank-0, then assemble
293
+ (0...m).each do |k|
294
+ $src.puts " if ( rb_ca_is_scalar(#{ry.(k)}) ) {"
295
+ $src.puts " #{ry.(k)} = rb_ca_fetch_addr(#{ry.(k)}, 0);"
296
+ $src.puts " }"
297
+ end
298
+ if m == 1
299
+ $src.puts " return #{ry.(0)};"
300
+ else
301
+ list = (0...m).map { |k| ry.(k) }.join(", ")
302
+ $src.puts " return rb_ary_new3(#{m}, #{list});"
303
+ end
304
+ $src.puts "}"
305
+ $src.puts ""
306
+ end
307
+
308
+ # --- typed ca_call_cfunc_M_N_r (reentrant variant) -------------------------
309
+ #
310
+ # Same as emit_typed but the callback signature and outer function gain a
311
+ # trailing `void *userdata`; the inner delegate calls ca_call_cfunc_(M+N)_r
312
+ # and forwards `userdata` through.
313
+ def emit_typed_r(m, n)
314
+ total = m + n
315
+ dty = ->(k) { m == 1 ? "dty" : "dty#{k + 1}" }
316
+ ry = ->(k) { m == 1 ? "ry" : "ry#{k + 1}" }
317
+
318
+ fsync_str = "1" * m + "0" * n
319
+
320
+ $src.puts sig_typed_r(m, n)
321
+ $src.puts "{"
322
+
323
+ out_decl = (0...m).map { |k| "#{ry.(k)} = Qnil" }.join(", ")
324
+ $src.puts " volatile VALUE #{out_decl};"
325
+ $src.puts ""
326
+
327
+ (0...n).each do |k|
328
+ $src.puts " rx#{k + 1} = rb_ca_wrap_readonly(rx#{k + 1}, INT2NUM(dtx#{k + 1}));"
329
+ end
330
+ $src.puts ""
331
+
332
+ (0...m).each do |out_k|
333
+ cur_dty = dty.(out_k)
334
+ conds = (0...n).map { |in_k| "#{cur_dty} != dtx#{in_k + 1}" }
335
+ wrapped = (0...n).map { |in_k|
336
+ "rb_ca_wrap_readonly(rx#{in_k + 1}, INT2NUM(#{cur_dty}))"
337
+ }
338
+ plain = (0...n).map { |in_k| "rx#{in_k + 1}" }
339
+ $src.puts " if ( #{conds.join(" || ")} ) {"
340
+ $src.puts " #{ry.(out_k)} = rb_ca_template_n(#{n}, #{wrapped.join(", ")});"
341
+ $src.puts " } else {"
342
+ $src.puts " #{ry.(out_k)} = rb_ca_template_n(#{n}, #{plain.join(", ")});"
343
+ $src.puts " }"
344
+ end
345
+ $src.puts ""
346
+
347
+ args = (0...m).map { |k| ry.(k) } + (0...n).map { |k| "rx#{k + 1}" }
348
+ $src.puts " ca_call_cfunc_#{total}_r(mathfunc, \"#{fsync_str}\", #{args.join(", ")}, userdata);"
349
+ $src.puts ""
350
+
351
+ (0...m).each do |k|
352
+ $src.puts " if ( rb_ca_is_scalar(#{ry.(k)}) ) {"
353
+ $src.puts " #{ry.(k)} = rb_ca_fetch_addr(#{ry.(k)}, 0);"
354
+ $src.puts " }"
355
+ end
356
+ if m == 1
357
+ $src.puts " return #{ry.(0)};"
358
+ else
359
+ list = (0...m).map { |k| ry.(k) }.join(", ")
360
+ $src.puts " return rb_ary_new3(#{m}, #{list});"
361
+ end
362
+ $src.puts "}"
363
+ $src.puts ""
364
+ end
365
+
366
+ # --- header declaration emitters --------------------------------------------
367
+
368
+ def decl_raw(n) ; $hdr.puts sig_raw(n) + ";"; $hdr.puts ""; end
369
+ def decl_raw_r(n) ; $hdr.puts sig_raw_r(n) + ";"; $hdr.puts ""; end
370
+ def decl_typed(m, n) ; $hdr.puts sig_typed(m, n) + ";"; $hdr.puts ""; end
371
+ def decl_typed_r(m, n) ; $hdr.puts sig_typed_r(m, n) + ";"; $hdr.puts ""; end
372
+
373
+ # --- main -------------------------------------------------------------------
374
+
375
+ src_path = ARGV[0] || "carray_call_cfunc.c"
376
+ hdr_path = ARGV[1] || "carray_call_cfunc.h"
377
+
378
+ $src = File.open(src_path, "w")
379
+ $hdr = File.open(hdr_path, "w")
380
+
381
+ $src.puts <<~END_C
382
+ /* ---------------------------------------------------------------------------
383
+ *
384
+ * carray_call_cfunc.c -- ext-author math-call wrapper API
385
+ *
386
+ * GENERATED by ext/mk_call_cfunc.rb -- DO NOT EDIT
387
+ * To modify the template or add a new arity, edit mk_call_cfunc.rb
388
+ * and regenerate (= make / extconf re-runs the generator).
389
+ *
390
+ * Provides `ca_call_cfunc_N` (raw arity 1..7) and `ca_call_cfunc_M_N`
391
+ * (typed dispatcher) used by external CArray gems (carray-gsl, etc.)
392
+ * to wrap C math functions over CArray operations.
393
+ *
394
+ * Reentrant variants `ca_call_cfunc_N_r` and `ca_call_cfunc_M_N_r`
395
+ * (= POSIX `_r` convention, cf. qsort_r / bsearch_r / strtok_r) take
396
+ * a trailing `void *userdata` argument that is passed through to every
397
+ * per-cell callback invocation as its last argument. Use when the
398
+ * callback needs to share state with the caller (accumulators,
399
+ * configuration flags, library plan handles, ...) without resorting to
400
+ * file-static / global plumbing.
401
+ *
402
+ * Attach-safe: INPUT-only operands (= fsync[k] == '0') never call
403
+ * ca_attach on the operand or its mask (= alias check + ALLOCV +
404
+ * ca_xfer_all for non-alias). OUTPUT operands (= fsync[k] == '1')
405
+ * use ca_attach + ca_sync (= legitimate per the refined input-only-
406
+ * operand invariant established in PROPOSAL_EAGER_ELEMENTWISE_NO_ATTACH
407
+ * and extended in PROPOSAL_EAGER_SLOWPATH_CHUNKING_ARENA).
408
+ *
409
+ * L0.1 (PROPOSAL_L0_AUTHOR_SURFACE, 2026-06-11): the per-operand acquire
410
+ * + broadcast check + mask OR + release lifecycle is now factored out
411
+ * into ext/ca_sweep_engine.{c,h} (ca_sweep_acquire / ca_sweep_release). This
412
+ * file keeps the arity-dependent inner loop only. ABI unchanged.
413
+ *
414
+ * --------------------------------------------------------------------------- */
415
+
416
+ #include "carray.h"
417
+ #include "ca_sweep_engine.h"
418
+ #include <string.h>
419
+
420
+ END_C
421
+
422
+ $hdr.puts <<~END_H
423
+ /* ---------------------------------------------------------------------------
424
+ *
425
+ * carray_call_cfunc.h -- ext-author math-call wrapper API (declarations)
426
+ *
427
+ * GENERATED by ext/mk_call_cfunc.rb -- DO NOT EDIT
428
+ * Edit mk_call_cfunc.rb and rebuild to refresh both this header and
429
+ * the matching carray_call_cfunc.c.
430
+ *
431
+ * Included from carray.h so external gems pick up these prototypes
432
+ * transparently via `#include "carray.h"`. The generator co-emits
433
+ * source and header so the prototypes cannot drift from the function
434
+ * definitions. See carray_call_cfunc.c for the full design notes.
435
+ *
436
+ * --------------------------------------------------------------------------- */
437
+
438
+ #ifndef CARRAY_CALL_CFUNC_H
439
+ #define CARRAY_CALL_CFUNC_H
440
+
441
+ END_H
442
+
443
+ RAW_ARITIES.each do |n|
444
+ emit_raw(n)
445
+ decl_raw(n)
446
+ end
447
+
448
+ $src.puts "/* -------------------------------------------------------------------- */"
449
+ $src.puts "/* Typed dispatchers: M outputs, N inputs. Wrap each input readonly to */"
450
+ $src.puts "/* its declared data_type, allocate output template(s), delegate to raw. */"
451
+ $src.puts "/* -------------------------------------------------------------------- */"
452
+ $src.puts ""
453
+
454
+ TYPED_PAIRS.each do |m, n|
455
+ emit_typed(m, n)
456
+ decl_typed(m, n)
457
+ end
458
+
459
+ $src.puts "/* -------------------------------------------------------------------- */"
460
+ $src.puts "/* Reentrant variants (`_r` suffix, POSIX convention): same as the */"
461
+ $src.puts "/* corresponding non-`_r` variant but the callback takes a trailing */"
462
+ $src.puts "/* `void *userdata` argument and the outer function takes a trailing */"
463
+ $src.puts "/* `void *userdata` parameter forwarded to every per-cell invocation. */"
464
+ $src.puts "/* -------------------------------------------------------------------- */"
465
+ $src.puts ""
466
+
467
+ RAW_ARITIES.each do |n|
468
+ emit_raw_r(n)
469
+ decl_raw_r(n)
470
+ end
471
+
472
+ TYPED_PAIRS.each do |m, n|
473
+ emit_typed_r(m, n)
474
+ decl_typed_r(m, n)
475
+ end
476
+
477
+ $hdr.puts "#endif /* CARRAY_CALL_CFUNC_H */"
478
+
479
+ $src.close
480
+ $hdr.close