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,132 @@
1
+ /* ---------------------------------------------------------------------------
2
+
3
+ ca_sort_kernels.h
4
+
5
+ Portable textbook sort kernels (PROPOSAL_PORTABLE_TEXTBOOK_SORT).
6
+
7
+ P.1 / P.2 : quicksort + mergesort over the 10 numeric dtypes
8
+ (i8 / u8 / i16 / u16 / i32 / u32 / i64 / u64 / f32 / f64)
9
+ P.3 : NaN pre-partition for f32 / f64
10
+ P.4 : pair (value + index) variants for argsort kernels —
11
+ sort_index / sort_addr / partition_index family
12
+ P.9 : value-level quickselect for partition_copy
13
+
14
+ Status: ext-internal. Signatures may change across 3.x while the
15
+ textbook sort family evolves. Included from carray.h so internal
16
+ consumers (carray_sort_kernel.c, carray_order.c, carray_kernels.c,
17
+ mkkernel emit) reach it transparently via `#include "carray.h"`.
18
+
19
+ Depends on int8_t .. uint64_t / float32_t / double / ca_size_t
20
+ typedefs from carray.h — when this header is included from carray.h
21
+ mid-file, those typedefs are already in scope by the time we reach
22
+ the include site.
23
+
24
+ --------------------------------------------------------------------------- */
25
+
26
+ #ifndef CA_SORT_KERNELS_H
27
+ #define CA_SORT_KERNELS_H 1
28
+
29
+ /* Needs int8_t .. uint64_t / float32_t / double / ca_size_t. No longer
30
+ pulled mid-carray.h (PROPOSAL_CARRAY_H_REORG H.4.1), so include carray.h
31
+ directly to be self-sufficient when a consumer includes this header.
32
+ Guard-protected, so the re-entry is a no-op when carray.h is already in
33
+ flight. */
34
+ #include "carray.h"
35
+
36
+ /* P.1 / P.2: quicksort over 10 numeric dtypes. */
37
+ void ca_sort_quick_i8 (int8_t *a, ca_size_t n);
38
+ void ca_sort_quick_u8 (uint8_t *a, ca_size_t n);
39
+ void ca_sort_quick_i16 (int16_t *a, ca_size_t n);
40
+ void ca_sort_quick_u16 (uint16_t *a, ca_size_t n);
41
+ void ca_sort_quick_i32 (int32_t *a, ca_size_t n);
42
+ void ca_sort_quick_u32 (uint32_t *a, ca_size_t n);
43
+ void ca_sort_quick_i64 (int64_t *a, ca_size_t n);
44
+ void ca_sort_quick_u64 (uint64_t *a, ca_size_t n);
45
+ void ca_sort_quick_f32 (float32_t *a, ca_size_t n);
46
+ void ca_sort_quick_f64 (double *a, ca_size_t n);
47
+
48
+ /* P.1 / P.2: mergesort over 10 numeric dtypes (`aux` is caller-supplied
49
+ scratch buffer of the same length / dtype as `a`). */
50
+ void ca_sort_merge_i8 (int8_t *a, int8_t *aux, ca_size_t n);
51
+ void ca_sort_merge_u8 (uint8_t *a, uint8_t *aux, ca_size_t n);
52
+ void ca_sort_merge_i16 (int16_t *a, int16_t *aux, ca_size_t n);
53
+ void ca_sort_merge_u16 (uint16_t *a, uint16_t *aux, ca_size_t n);
54
+ void ca_sort_merge_i32 (int32_t *a, int32_t *aux, ca_size_t n);
55
+ void ca_sort_merge_u32 (uint32_t *a, uint32_t *aux, ca_size_t n);
56
+ void ca_sort_merge_i64 (int64_t *a, int64_t *aux, ca_size_t n);
57
+ void ca_sort_merge_u64 (uint64_t *a, uint64_t *aux, ca_size_t n);
58
+ void ca_sort_merge_f32 (float32_t *a, float32_t *aux, ca_size_t n);
59
+ void ca_sort_merge_f64 (double *a, double *aux, ca_size_t n);
60
+
61
+ /* P.3: NaN pre-partition for float dtypes (Hoare 1-pass, returns finite count). */
62
+ ca_size_t ca_partition_nan_f32 (float32_t *a, ca_size_t n);
63
+ ca_size_t ca_partition_nan_f64 (double *a, ca_size_t n);
64
+
65
+ /* P.4: pair variant of NaN pre-partition for float argsort kernels. */
66
+ struct ca_pair_f32;
67
+ struct ca_pair_f64;
68
+ ca_size_t ca_partition_nan_pair_f32 (struct ca_pair_f32 *a, ca_size_t n);
69
+ ca_size_t ca_partition_nan_pair_f64 (struct ca_pair_f64 *a, ca_size_t n);
70
+
71
+ /* P.9: value-level quickselect for partition_copy.
72
+ Reorders a[0..n) so that a[kth] is exact + left/right regions
73
+ satisfy <= / >= contracts. Order within each region unspecified. */
74
+ void ca_partition_quick_i8 (int8_t *a, ca_size_t n, ca_size_t kth);
75
+ void ca_partition_quick_u8 (uint8_t *a, ca_size_t n, ca_size_t kth);
76
+ void ca_partition_quick_i16 (int16_t *a, ca_size_t n, ca_size_t kth);
77
+ void ca_partition_quick_u16 (uint16_t *a, ca_size_t n, ca_size_t kth);
78
+ void ca_partition_quick_i32 (int32_t *a, ca_size_t n, ca_size_t kth);
79
+ void ca_partition_quick_u32 (uint32_t *a, ca_size_t n, ca_size_t kth);
80
+ void ca_partition_quick_i64 (int64_t *a, ca_size_t n, ca_size_t kth);
81
+ void ca_partition_quick_u64 (uint64_t *a, ca_size_t n, ca_size_t kth);
82
+ void ca_partition_quick_f32 (float32_t *a, ca_size_t n, ca_size_t kth);
83
+ void ca_partition_quick_f64 (double *a, ca_size_t n, ca_size_t kth);
84
+
85
+ /* P.4: pair sort kernels (= argsort: sort_index / sort_addr). The pair
86
+ struct is opaque to mkkernel-emitted callers via void*; each kernel
87
+ has its own well-defined layout: { TYPE v; ca_size_t i; } with natural
88
+ alignment padding. */
89
+ struct ca_pair_i8 { int8_t v; ca_size_t i; };
90
+ struct ca_pair_u8 { uint8_t v; ca_size_t i; };
91
+ struct ca_pair_i16 { int16_t v; ca_size_t i; };
92
+ struct ca_pair_u16 { uint16_t v; ca_size_t i; };
93
+ struct ca_pair_i32 { int32_t v; ca_size_t i; };
94
+ struct ca_pair_u32 { uint32_t v; ca_size_t i; };
95
+ struct ca_pair_i64 { int64_t v; ca_size_t i; };
96
+ struct ca_pair_u64 { uint64_t v; ca_size_t i; };
97
+ struct ca_pair_f32 { float32_t v; ca_size_t i; };
98
+ struct ca_pair_f64 { double v; ca_size_t i; };
99
+ typedef struct ca_pair_i8 ca_pair_i8;
100
+ typedef struct ca_pair_u8 ca_pair_u8;
101
+ typedef struct ca_pair_i16 ca_pair_i16;
102
+ typedef struct ca_pair_u16 ca_pair_u16;
103
+ typedef struct ca_pair_i32 ca_pair_i32;
104
+ typedef struct ca_pair_u32 ca_pair_u32;
105
+ typedef struct ca_pair_i64 ca_pair_i64;
106
+ typedef struct ca_pair_u64 ca_pair_u64;
107
+ typedef struct ca_pair_f32 ca_pair_f32;
108
+ typedef struct ca_pair_f64 ca_pair_f64;
109
+
110
+ void ca_sort_quick_pair_i8 (ca_pair_i8 *a, ca_size_t n);
111
+ void ca_sort_quick_pair_u8 (ca_pair_u8 *a, ca_size_t n);
112
+ void ca_sort_quick_pair_i16 (ca_pair_i16 *a, ca_size_t n);
113
+ void ca_sort_quick_pair_u16 (ca_pair_u16 *a, ca_size_t n);
114
+ void ca_sort_quick_pair_i32 (ca_pair_i32 *a, ca_size_t n);
115
+ void ca_sort_quick_pair_u32 (ca_pair_u32 *a, ca_size_t n);
116
+ void ca_sort_quick_pair_i64 (ca_pair_i64 *a, ca_size_t n);
117
+ void ca_sort_quick_pair_u64 (ca_pair_u64 *a, ca_size_t n);
118
+ void ca_sort_quick_pair_f32 (ca_pair_f32 *a, ca_size_t n);
119
+ void ca_sort_quick_pair_f64 (ca_pair_f64 *a, ca_size_t n);
120
+
121
+ void ca_sort_merge_pair_i8 (ca_pair_i8 *a, ca_pair_i8 *aux, ca_size_t n);
122
+ void ca_sort_merge_pair_u8 (ca_pair_u8 *a, ca_pair_u8 *aux, ca_size_t n);
123
+ void ca_sort_merge_pair_i16 (ca_pair_i16 *a, ca_pair_i16 *aux, ca_size_t n);
124
+ void ca_sort_merge_pair_u16 (ca_pair_u16 *a, ca_pair_u16 *aux, ca_size_t n);
125
+ void ca_sort_merge_pair_i32 (ca_pair_i32 *a, ca_pair_i32 *aux, ca_size_t n);
126
+ void ca_sort_merge_pair_u32 (ca_pair_u32 *a, ca_pair_u32 *aux, ca_size_t n);
127
+ void ca_sort_merge_pair_i64 (ca_pair_i64 *a, ca_pair_i64 *aux, ca_size_t n);
128
+ void ca_sort_merge_pair_u64 (ca_pair_u64 *a, ca_pair_u64 *aux, ca_size_t n);
129
+ void ca_sort_merge_pair_f32 (ca_pair_f32 *a, ca_pair_f32 *aux, ca_size_t n);
130
+ void ca_sort_merge_pair_f64 (ca_pair_f64 *a, ca_pair_f64 *aux, ca_size_t n);
131
+
132
+ #endif /* CA_SORT_KERNELS_H */
@@ -0,0 +1,430 @@
1
+ /* ---------------------------------------------------------------------------
2
+
3
+ Sweep (xfer_all) author-surface engine: shared acquire / release
4
+ bodies for the ca_call_cfunc trampolines generated by
5
+ mk_call_cfunc.rb. See ca_sweep_engine.h for the full lifecycle
6
+ template.
7
+
8
+ Two paths:
9
+ whole-buffer ca_sweep_acquire / _release — xmalloc scratch
10
+ chunked ca_sweep_acquire_chunked / _next_chunk / _release_chunked
11
+ — arena scratch
12
+
13
+ Both propagate INPUT masks to OUTPUT masks and honor the NO_MASK
14
+ form guard (masked INPUT + NO_MASK = raise, since a NO_MASK kernel
15
+ cannot observe masked cells).
16
+
17
+ ---------------------------------------------------------------------------- */
18
+
19
+ #include "carray.h"
20
+ #include "carray_internal.h" /* ca_lazy_arena_* */
21
+ #include "ca_sweep_engine.h"
22
+ #include "ca_for_buffer.h"
23
+ #include <string.h>
24
+
25
+ void
26
+ ca_sweep_acquire (ca_sweep_state_t *st)
27
+ {
28
+ int k_op;
29
+ int any_input_mask = 0;
30
+
31
+ if ((int) strlen(st->fsync) != st->n_ops) {
32
+ rb_raise(rb_eRuntimeError,
33
+ "[BUG] invalid length of fsync arg in %s (expected %d)",
34
+ st->src_label ? st->src_label : "ca_sweep_acquire",
35
+ st->n_ops);
36
+ }
37
+
38
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
39
+ st->base[k_op] = NULL;
40
+ st->owned_buf[k_op] = NULL;
41
+ st->attached[k_op] = 0;
42
+ }
43
+ st->m0 = NULL;
44
+ st->n_kernel = 1;
45
+ /* CAREFUL: do not reset st->no_mask here — caller sets it before
46
+ * acquire and the NO_MASK guard below consumes it. */
47
+
48
+ /* Per-operand acquire:
49
+ * OUTPUT (fsync == '1') -> ca_attach + base = ca->ptr
50
+ * INPUT alias -> ca_attach + base = ca->ptr
51
+ * INPUT non-alias non-scalar -> xmalloc scratch + ca_xfer_all
52
+ * INPUT non-alias never attaches the operand itself; the scratch
53
+ * copy carries the values into the kernel. */
54
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
55
+ CArray *ca = st->cx[k_op];
56
+ if (st->fsync[k_op] == '1') {
57
+ ca_attach(ca);
58
+ st->base[k_op] = (char *) ca->ptr;
59
+ st->attached[k_op] = 1;
60
+ } else if (ca_attach_is_alias(ca)) {
61
+ ca_attach(ca);
62
+ st->base[k_op] = (char *) ca->ptr;
63
+ st->attached[k_op] = 1;
64
+ } else {
65
+ ca_size_t bytes_total = ca->elements * ca->bytes;
66
+ st->owned_buf[k_op] = xmalloc(bytes_total);
67
+ st->base[k_op] = st->owned_buf[k_op];
68
+ ca_xfer_all(ca, st->base[k_op], CA_XFER_GET);
69
+ }
70
+ }
71
+
72
+ /* compute n_kernel (= broadcast shape) and per-cell strides */
73
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
74
+ CArray *ca = st->cx[k_op];
75
+ if (ca_is_scalar(ca)) {
76
+ st->stride[k_op] = 0;
77
+ } else {
78
+ st->stride[k_op] = ca->bytes;
79
+ if (st->n_kernel == 1) {
80
+ st->n_kernel = ca->elements;
81
+ } else if (ca->elements != st->n_kernel) {
82
+ rb_raise(rb_eRuntimeError, "data size mismatch in operation");
83
+ }
84
+ }
85
+ }
86
+
87
+ /* iter mask m0 = OR of INPUT operand masks, gathered via ca_xfer_all
88
+ so no operand mask attach happens. Stays NULL if no INPUT masks. */
89
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
90
+ if (st->fsync[k_op] == '0' && ca_has_mask(st->cx[k_op])) {
91
+ any_input_mask = 1;
92
+ break;
93
+ }
94
+ }
95
+ if (any_input_mask && st->no_mask) {
96
+ rb_raise(rb_eRuntimeError,
97
+ "%s: masked INPUT not allowed in NO_MASK form "
98
+ "(use the *_MASKED form to handle masked cells explicitly)",
99
+ st->src_label ? st->src_label : "ca_sweep_acquire");
100
+ }
101
+ if (any_input_mask) {
102
+ st->m0 = xmalloc(st->n_kernel);
103
+ memset(st->m0, 0, st->n_kernel);
104
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
105
+ CArray *ca = st->cx[k_op];
106
+ if (st->fsync[k_op] != '0') continue;
107
+ ca_update_mask(ca);
108
+ if (!ca->mask) continue;
109
+ if (ca_is_scalar(ca)) {
110
+ boolean8_t bit = 0;
111
+ ca_xfer_all(ca->mask, &bit, CA_XFER_GET);
112
+ if (bit) memset(st->m0, 1, st->n_kernel);
113
+ } else {
114
+ boolean8_t *ms = xmalloc(st->n_kernel);
115
+ ca_size_t j;
116
+ ca_xfer_all(ca->mask, ms, CA_XFER_GET);
117
+ for (j = 0; j < st->n_kernel; j++) st->m0[j] |= ms[j];
118
+ xfree(ms);
119
+ }
120
+ }
121
+ }
122
+
123
+ /* Overwrite each OUTPUT mask with the iter mask (creating the
124
+ OUTPUT mask if it did not exist). No-op when m0 is NULL. */
125
+ if (st->m0) {
126
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
127
+ CArray *ca = st->cx[k_op];
128
+ if (st->fsync[k_op] != '1') continue;
129
+ ca_update_mask(ca);
130
+ if (!ca->mask) ca_create_mask(ca);
131
+ memcpy(ca->mask->ptr, st->m0, st->n_kernel);
132
+ }
133
+ }
134
+ }
135
+
136
+ void
137
+ ca_sweep_release (ca_sweep_state_t *st)
138
+ {
139
+ int k_op;
140
+ /* sync OUTPUTs (reverse order) */
141
+ for (k_op = st->n_ops - 1; k_op >= 0; k_op--) {
142
+ if (st->fsync[k_op] == '1') ca_sync(st->cx[k_op]);
143
+ }
144
+ /* detach attached / xfree owned buffers (reverse order) */
145
+ for (k_op = st->n_ops - 1; k_op >= 0; k_op--) {
146
+ if (st->attached[k_op]) {
147
+ ca_detach(st->cx[k_op]);
148
+ } else if (st->owned_buf[k_op]) {
149
+ xfree(st->owned_buf[k_op]);
150
+ st->owned_buf[k_op] = NULL;
151
+ }
152
+ }
153
+ if (st->m0) {
154
+ xfree(st->m0);
155
+ st->m0 = NULL;
156
+ }
157
+ }
158
+
159
+ /* ===== Chunked path implementation ===== */
160
+
161
+ void
162
+ ca_sweep_acquire_chunked (ca_sweep_state_t *st)
163
+ {
164
+ int k_op;
165
+ int any_input_mask = 0;
166
+ CArray *shape_donor = NULL;
167
+
168
+ if ((int) strlen(st->fsync) != st->n_ops) {
169
+ rb_raise(rb_eRuntimeError,
170
+ "[BUG] invalid length of fsync arg in %s (expected %d)",
171
+ st->src_label ? st->src_label : "ca_sweep_acquire_chunked",
172
+ st->n_ops);
173
+ }
174
+
175
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
176
+ st->base[k_op] = NULL;
177
+ st->base_orig[k_op] = NULL;
178
+ st->owned_buf[k_op] = NULL;
179
+ st->attached[k_op] = 0;
180
+ }
181
+ st->m0 = NULL;
182
+ st->n_kernel = 1;
183
+ st->chunk_off = 0;
184
+ st->chunk_n = 0;
185
+ st->chunk_n_max = 0;
186
+ st->inner = 1;
187
+ st->chunked_state = 0;
188
+
189
+ /* compute broadcast shape (n_kernel + strides) from operand shapes.
190
+ * scalar operands collapse to stride 0; non-scalar operands must agree
191
+ * on element count. shape_donor is the first non-scalar operand and
192
+ * defines the chunking inner-axis size. */
193
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
194
+ CArray *ca = st->cx[k_op];
195
+ if (ca_is_scalar(ca)) {
196
+ st->stride[k_op] = 0;
197
+ } else {
198
+ st->stride[k_op] = ca->bytes;
199
+ if (st->n_kernel == 1) {
200
+ st->n_kernel = ca->elements;
201
+ shape_donor = ca;
202
+ } else if (ca->elements != st->n_kernel) {
203
+ rb_raise(rb_eRuntimeError, "data size mismatch in operation");
204
+ }
205
+ }
206
+ }
207
+
208
+ /* chunk-size policy: inner = donor's product of dims[1..]; chunk_n_max
209
+ * = compute_n on donor->bytes (= dtype-dependent 32KB target). */
210
+ if (shape_donor) {
211
+ st->inner = ca_chunk_inner_size(shape_donor);
212
+ st->chunk_n_max = ca_chunk_compute_n(st->n_kernel, st->inner,
213
+ shape_donor->bytes);
214
+ } else {
215
+ /* all-scalar: single 1-cell chunk */
216
+ st->inner = 1;
217
+ st->chunk_n_max = 1;
218
+ }
219
+
220
+ /* per-operand acquire:
221
+ * OUTPUT (fsync == '1') : ca_attach + base_orig = ca->ptr (legitimate)
222
+ * INPUT alias : ca_attach + base_orig = ca->ptr (zero-copy)
223
+ * INPUT non-alias non-scalar : arena chunk scratch of chunk_n_max bytes
224
+ * INPUT scalar : ca_attach + base_orig = ca->ptr (1 cell)
225
+ */
226
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
227
+ CArray *ca = st->cx[k_op];
228
+ if (st->fsync[k_op] == '1') {
229
+ ca_attach(ca);
230
+ st->base_orig[k_op] = (char *) ca->ptr;
231
+ st->attached[k_op] = 1;
232
+ } else if (ca_is_scalar(ca) || ca_attach_is_alias(ca)) {
233
+ ca_attach(ca);
234
+ st->base_orig[k_op] = (char *) ca->ptr;
235
+ st->attached[k_op] = 1;
236
+ } else {
237
+ /* non-alias non-scalar INPUT: arena scratch sized for chunk_n_max */
238
+ ca_size_t scratch_bytes = st->chunk_n_max * ca->bytes;
239
+ st->owned_buf[k_op] = (char *) ca_lazy_arena_acquire(scratch_bytes);
240
+ /* base_orig stays NULL -- per-chunk gather lands the data in
241
+ * owned_buf[k_op]; base[k_op] will be set to owned_buf[k_op] at
242
+ * each chunk boundary. */
243
+ }
244
+ }
245
+
246
+ /* iter mask = OR of INPUT operand masks (full size, n_kernel bytes).
247
+ * Per-chunk mask gather is a future optim; this MVP gathers once. */
248
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
249
+ if (st->fsync[k_op] == '0' && ca_has_mask(st->cx[k_op])) {
250
+ any_input_mask = 1;
251
+ break;
252
+ }
253
+ }
254
+ if (any_input_mask && st->no_mask) {
255
+ rb_raise(rb_eRuntimeError,
256
+ "%s: masked INPUT not allowed in NO_MASK form "
257
+ "(use the *_MASKED form to handle masked cells explicitly)",
258
+ st->src_label ? st->src_label : "ca_sweep_acquire_chunked");
259
+ }
260
+ if (any_input_mask) {
261
+ st->m0 = (boolean8_t *) ca_lazy_arena_acquire(st->n_kernel);
262
+ memset(st->m0, 0, st->n_kernel);
263
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
264
+ CArray *ca = st->cx[k_op];
265
+ if (st->fsync[k_op] != '0') continue;
266
+ ca_update_mask(ca);
267
+ if (!ca->mask) continue;
268
+ if (ca_is_scalar(ca)) {
269
+ boolean8_t bit = 0;
270
+ ca_xfer_all(ca->mask, &bit, CA_XFER_GET);
271
+ if (bit) memset(st->m0, 1, st->n_kernel);
272
+ } else {
273
+ boolean8_t *ms = (boolean8_t *) ca_lazy_arena_acquire(st->n_kernel);
274
+ ca_size_t j;
275
+ ca_xfer_all(ca->mask, ms, CA_XFER_GET);
276
+ for (j = 0; j < st->n_kernel; j++) st->m0[j] |= ms[j];
277
+ ca_lazy_arena_release(ms);
278
+ }
279
+ }
280
+ }
281
+
282
+ /* CAREFUL: m0 -> OUTPUT mask propagation is deferred to release
283
+ * time so that author per-cell m_out writes during the chunk loop
284
+ * are captured in the final OUTPUT mask. Do not fold this into
285
+ * acquire; doing so would clobber the author's writes. */
286
+ }
287
+
288
+ int
289
+ ca_sweep_next_chunk (ca_sweep_state_t *st)
290
+ {
291
+ int k_op;
292
+ ca_size_t off, n;
293
+
294
+ if (st->chunked_state == 0) {
295
+ /* first chunk */
296
+ st->chunk_off = 0;
297
+ st->chunked_state = 1;
298
+ } else {
299
+ /* advance */
300
+ st->chunk_off += st->chunk_n;
301
+ }
302
+
303
+ if (st->chunk_off >= st->n_kernel) {
304
+ st->chunked_state = 2;
305
+ return 0;
306
+ }
307
+
308
+ off = st->chunk_off;
309
+ n = st->chunk_n_max;
310
+ if (off + n > st->n_kernel) n = st->n_kernel - off;
311
+ st->chunk_n = n;
312
+
313
+ /* set up base[] for the upcoming chunk */
314
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
315
+ CArray *ca = st->cx[k_op];
316
+ if (st->stride[k_op] == 0) {
317
+ /* scalar: stride 0, base is the single-cell ptr (base_orig) */
318
+ st->base[k_op] = st->base_orig[k_op];
319
+ } else if (st->base_orig[k_op]) {
320
+ /* alias INPUT or OUTPUT: walk through ca->ptr by chunk_off */
321
+ st->base[k_op] = st->base_orig[k_op] + off * st->stride[k_op];
322
+ } else {
323
+ /* non-alias INPUT: per-chunk gather into owned_buf (arena) */
324
+ ca_chunked_gather(ca, off, n, st->owned_buf[k_op]);
325
+ st->base[k_op] = st->owned_buf[k_op];
326
+ }
327
+ }
328
+
329
+ return 1;
330
+ }
331
+
332
+ void
333
+ ca_sweep_release_chunked (ca_sweep_state_t *st)
334
+ {
335
+ int k_op;
336
+ /* Propagate (possibly author-mutated) m0 to OUTPUT mask before
337
+ * sync. For INOUT_MASKED forms this captures the author's per-cell
338
+ * m_out writes; other forms behave the same as the whole-buffer
339
+ * acquire-time propagation. */
340
+ if (st->m0) {
341
+ for (k_op = 0; k_op < st->n_ops; k_op++) {
342
+ CArray *ca = st->cx[k_op];
343
+ if (st->fsync[k_op] != '1') continue;
344
+ ca_update_mask(ca);
345
+ if (!ca->mask) ca_create_mask(ca);
346
+ memcpy(ca->mask->ptr, st->m0, st->n_kernel);
347
+ }
348
+ }
349
+ /* sync OUTPUTs (reverse order, regardless of whether chunk loop ran) */
350
+ for (k_op = st->n_ops - 1; k_op >= 0; k_op--) {
351
+ if (st->fsync[k_op] == '1') ca_sync(st->cx[k_op]);
352
+ }
353
+ /* detach attached / release arena scratch buffers (reverse order) */
354
+ for (k_op = st->n_ops - 1; k_op >= 0; k_op--) {
355
+ if (st->attached[k_op]) {
356
+ ca_detach(st->cx[k_op]);
357
+ } else if (st->owned_buf[k_op]) {
358
+ ca_lazy_arena_release(st->owned_buf[k_op]);
359
+ st->owned_buf[k_op] = NULL;
360
+ }
361
+ }
362
+ if (st->m0) {
363
+ ca_lazy_arena_release(st->m0);
364
+ st->m0 = NULL;
365
+ }
366
+ }
367
+
368
+ /* ===== WHOLE_BUFFER function form (rb_ensure-protected) ===== */
369
+
370
+ typedef struct {
371
+ CArray *ca;
372
+ int writable;
373
+ ca_with_buffer_body_fn body_fn;
374
+ void *user_data;
375
+ } ca_with_buffer_ctx_t;
376
+
377
+ static VALUE
378
+ ca_with_buffer_body_trampoline (VALUE ctx_val)
379
+ {
380
+ ca_with_buffer_ctx_t *ctx = (ca_with_buffer_ctx_t *) ctx_val;
381
+ ctx->body_fn(ctx->user_data, ctx->ca->ptr, ctx->ca->elements);
382
+ return Qnil;
383
+ }
384
+
385
+ static VALUE
386
+ ca_with_buffer_ensure_trampoline (VALUE ctx_val)
387
+ {
388
+ ca_with_buffer_ctx_t *ctx = (ca_with_buffer_ctx_t *) ctx_val;
389
+ if (ctx->writable) ca_sync(ctx->ca);
390
+ ca_detach(ctx->ca);
391
+ return Qnil;
392
+ }
393
+
394
+ void
395
+ rb_ca_call_with_buffer (VALUE r_ca, int writable,
396
+ ca_with_buffer_body_fn body, void *user_data)
397
+ {
398
+ ca_with_buffer_ctx_t ctx;
399
+ TypedData_Get_Struct(r_ca, CArray, &carray_data_type, ctx.ca);
400
+ /* CAREFUL: attach outside rb_ensure. If attach raises, we are not
401
+ * yet inside the ensure scope, so the ensure trampoline will not
402
+ * fire on a not-attached ca (which would try to detach and crash). */
403
+ ca_attach(ctx.ca);
404
+ ctx.writable = writable;
405
+ ctx.body_fn = body;
406
+ ctx.user_data = user_data;
407
+ rb_ensure(ca_with_buffer_body_trampoline, (VALUE) &ctx,
408
+ ca_with_buffer_ensure_trampoline, (VALUE) &ctx);
409
+ }
410
+
411
+ void
412
+ ca_sweep_check_same_shape (CArray *ca_in, CArray *ca_out, const char *src_label)
413
+ {
414
+ int k;
415
+ const char *lbl = src_label ? src_label : "ca_sweep_check_same_shape";
416
+ if (ca_in->ndim != ca_out->ndim) {
417
+ rb_raise(rb_eRuntimeError,
418
+ "%s: shape mismatch (ndim %d vs %d)",
419
+ lbl, ca_in->ndim, ca_out->ndim);
420
+ }
421
+ for (k = 0; k < ca_in->ndim; k++) {
422
+ if (ca_in->dim[k] != ca_out->dim[k]) {
423
+ rb_raise(rb_eRuntimeError,
424
+ "%s: shape mismatch at dim[%d] (%lld vs %lld)",
425
+ lbl, k,
426
+ (long long) ca_in->dim[k],
427
+ (long long) ca_out->dim[k]);
428
+ }
429
+ }
430
+ }