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,620 @@
1
+ /* ---------------------------------------------------------------------------
2
+
3
+ Portable textbook sort kernels: per-type quicksort + bottom-up
4
+ mergesort with inline comparison (no function-pointer indirection
5
+ like libc qsort / mergesort). All 10 numeric data types plus paired
6
+ forms for argsort.
7
+
8
+ Internal C API only (no Ruby surface, no Init function). Declared
9
+ in ca_sort_kernels.h. Callers: rb_ca_sort_copy (carray_sort.c),
10
+ rb_ca_partition_copy_c (carray_partition.c), and the mkkernel-
11
+ emitted sort_addr_ki kernels in carray_kernels.c.
12
+
13
+ Algorithms:
14
+
15
+ * quicksort (ca_sort_quick_<type>)
16
+ median-of-3 pivot, Hoare partition, strict `<`, insertion-sort
17
+ base (threshold 16), smaller-side recursion / larger-side
18
+ iterate (stack O(log n)). Depth-limit escape to mergesort for
19
+ worst-case O(n log n).
20
+
21
+ * mergesort (ca_sort_merge_<type>)
22
+ Bottom-up, ping-pong (cur / next) per pass with no inter-pass
23
+ memcpy. Strict `<` (stable: equal -> take-left). Insertion-
24
+ sort pre-pass that converts the input into R=16-wide sorted
25
+ blocks before the merge loop. Single-compare sorted-skip
26
+ (per-merge `!(cur[mid] < cur[mid-1])` test, true -> memcpy and
27
+ skip the merge loop; no run-state machine, distinct from
28
+ Timsort galloping).
29
+
30
+ * paired forms (ca_sort_quick_pair_<type> / ca_sort_merge_pair_<type>)
31
+ Same algorithms over (value, index) pairs for argsort
32
+ (sort_index / sort_addr). Stable tie-break by index is built
33
+ into the comparison, so quicksort is effectively stable for
34
+ argsort even though the algorithm itself is not.
35
+
36
+ * NaN partitioning (ca_partition_nan_<type> + _pair_<type>)
37
+ float32 / float64 only. One-pass Hoare-style partition that
38
+ separates `[finite | NaN]` regions so the downstream sort
39
+ kernel can operate on the finite slice with plain `<`.
40
+
41
+ * value-level quickselect (ca_partition_quick_<type>)
42
+ median-of-3 + Hoare + insertion base + one-sided recursion
43
+ into the side containing kth (quickselect property, expected
44
+ O(n)). Depth-limit escape to mergesort matches the sort
45
+ kernels.
46
+
47
+ ---------------------------------------------------------------------------*/
48
+
49
+ #include "carray.h"
50
+ #include "ca_sort_kernels.h"
51
+ #include <string.h>
52
+ #include <math.h>
53
+
54
+ #define CA_SORT_INSERTION_THRESHOLD 16
55
+
56
+ /* ---------------------------------------------------------------------------
57
+ DEFINE_SORT_MERGE(TYPE, SUFFIX)
58
+
59
+ Emits public `void ca_sort_merge_<SUFFIX>(TYPE *a, TYPE *aux,
60
+ ca_size_t n)`.
61
+ `aux` must be a caller-provided buffer of `n * sizeof(TYPE)` bytes.
62
+ --------------------------------------------------------------------------- */
63
+
64
+ #define DEFINE_SORT_MERGE(TYPE, SUFFIX) \
65
+ \
66
+ /* insertion-sort pre-pass on a[lo..hi-1] (half-open). R-wide blocks. \
67
+ Writes only into `a` (no buffer juggling). Body is intentionally \
68
+ identical to the quicksort insertion base. */ \
69
+ static void \
70
+ ca_sort_merge_##SUFFIX##_inspass (TYPE *a, ca_size_t n) \
71
+ { \
72
+ ca_size_t lo = 0; \
73
+ while ( lo < n ) { \
74
+ ca_size_t hi_excl = lo + CA_SORT_INSERTION_THRESHOLD; \
75
+ if ( hi_excl > n ) hi_excl = n; \
76
+ for ( ca_size_t k = lo + 1; k < hi_excl; k++ ) { \
77
+ TYPE v = a[k]; \
78
+ ca_size_t m = k; \
79
+ while ( m > lo && v < a[m - 1] ) { \
80
+ a[m] = a[m - 1]; \
81
+ m--; \
82
+ } \
83
+ a[m] = v; \
84
+ } \
85
+ lo = hi_excl; \
86
+ } \
87
+ } \
88
+ \
89
+ void \
90
+ ca_sort_merge_##SUFFIX (TYPE *a, TYPE *aux, ca_size_t n) \
91
+ { \
92
+ if ( n <= 1 ) return; \
93
+ \
94
+ /* Pre-pass: convert a[] into R=16-wide sorted blocks in place. */ \
95
+ ca_sort_merge_##SUFFIX##_inspass(a, n); \
96
+ \
97
+ TYPE *cur = a; \
98
+ TYPE *next = aux; \
99
+ \
100
+ /* Start width = R (= pre-pass output run width). */ \
101
+ for ( ca_size_t width = CA_SORT_INSERTION_THRESHOLD; \
102
+ width < n; \
103
+ width <<= 1 ) { \
104
+ for ( ca_size_t lo = 0; lo < n; lo += (width << 1) ) { \
105
+ ca_size_t mid = lo + width; \
106
+ ca_size_t hi = lo + (width << 1); \
107
+ /* CAREFUL: tail run clamp must run before the drain `while` \
108
+ loops below; without these the drains over-walk the buffer \
109
+ when n is not a power of 2 times width. */ \
110
+ if ( mid > n ) mid = n; \
111
+ if ( hi > n ) hi = n; \
112
+ \
113
+ /* Single-compare sorted-skip: if left tail <= right head, the merge \
114
+ is the identity in [lo, hi). Strict `<` here so equal heads also \
115
+ skip (stable: take-left). Cheap memcpy keeps invariant that \
116
+ `next[lo..hi)` is the merged output. */ \
117
+ if ( mid < hi && !(cur[mid] < cur[mid - 1]) ) { \
118
+ memcpy(next + lo, cur + lo, (size_t)(hi - lo) * sizeof(TYPE)); \
119
+ continue; \
120
+ } \
121
+ \
122
+ ca_size_t i = lo, j = mid, k = lo; \
123
+ /* strict `<` -> equal-key left-take -> stable. */ \
124
+ while ( i < mid && j < hi ) { \
125
+ if ( cur[j] < cur[i] ) next[k++] = cur[j++]; \
126
+ else next[k++] = cur[i++]; \
127
+ } \
128
+ /* Drain residual tail (paired with the clamp above). */ \
129
+ while ( i < mid ) next[k++] = cur[i++]; \
130
+ while ( j < hi ) next[k++] = cur[j++]; \
131
+ } \
132
+ /* ping-pong: swap roles for next pass. */ \
133
+ { TYPE *t = cur; cur = next; next = t; } \
134
+ } \
135
+ \
136
+ /* CAREFUL: parity check by POINTER IDENTITY, never by pass counter. \
137
+ The pre-pass + width loop may leave `cur` pointing at either `a` or \
138
+ `aux` depending on dataset size and the sorted-skip short-circuit; \
139
+ a pass-count parity check is unreliable. Single fix-up memcpy when \
140
+ the result landed in `aux`. */ \
141
+ if ( cur != a ) { \
142
+ memcpy(a, cur, (size_t) n * sizeof(TYPE)); \
143
+ } \
144
+ } \
145
+ struct ca_sort_merge_##SUFFIX##_eat_semicolon
146
+
147
+
148
+ /* ---------------------------------------------------------------------------
149
+ DEFINE_SORT_QUICK(TYPE, SUFFIX)
150
+
151
+ Emits public `void ca_sort_quick_<SUFFIX>(TYPE *a, ca_size_t n)`.
152
+ Algorithm: median-of-3 pivot + Hoare partition + insertion-sort
153
+ base (threshold 16) + smaller-side recursion / larger-side
154
+ iterate (stack O(log n)).
155
+
156
+ Worst-case guarantee: a recursion depth counter starts at
157
+ 2*floor(log2(n)) + 2. Once a branch exceeds that limit the
158
+ remaining subrange escapes to ca_sort_merge_<SUFFIX>, which is
159
+ O(n log n) regardless of input shape (= avoids heapsort by
160
+ reusing the existing merge path).
161
+ --------------------------------------------------------------------- */
162
+
163
+ #define DEFINE_SORT_QUICK(TYPE, SUFFIX) \
164
+ \
165
+ static void \
166
+ ca_sort_quick_##SUFFIX##_range (TYPE *a, ca_size_t lo, ca_size_t hi, \
167
+ int depth_limit) \
168
+ { \
169
+ while ( hi - lo > CA_SORT_INSERTION_THRESHOLD ) { \
170
+ if ( depth_limit <= 0 ) { \
171
+ /* Depth-limit escape: mergesort the remaining subrange. \
172
+ The surrounding quicksort loop has already partitioned the \
173
+ higher subranges, so only this [lo, hi] window needs the aux \
174
+ buffer (local malloc/free). */ \
175
+ ca_size_t n_remain = hi - lo + 1; \
176
+ TYPE *aux = (TYPE *) xmalloc((size_t) n_remain * sizeof(TYPE)); \
177
+ ca_sort_merge_##SUFFIX(a + lo, aux, n_remain); \
178
+ xfree(aux); \
179
+ return; \
180
+ } \
181
+ depth_limit--; \
182
+ ca_size_t mid = lo + (hi - lo) / 2; \
183
+ /* median-of-3: order a[lo] <= a[mid] <= a[hi] */ \
184
+ if ( a[mid] < a[lo] ) { TYPE t = a[lo]; a[lo] = a[mid]; a[mid] = t; } \
185
+ if ( a[hi] < a[lo] ) { TYPE t = a[lo]; a[lo] = a[hi]; a[hi] = t; } \
186
+ if ( a[hi] < a[mid] ) { TYPE t = a[mid]; a[mid] = a[hi]; a[hi] = t; } \
187
+ TYPE pivot = a[mid]; \
188
+ /* Hoare partition */ \
189
+ ca_size_t i = lo, j = hi; \
190
+ for (;;) { \
191
+ while ( a[i] < pivot ) i++; \
192
+ while ( pivot < a[j] ) j--; \
193
+ if ( i >= j ) break; \
194
+ { TYPE t = a[i]; a[i] = a[j]; a[j] = t; } \
195
+ i++; \
196
+ j--; \
197
+ } \
198
+ /* smaller side recurse, larger side iterate (stack O(log n)) */ \
199
+ if ( j - lo < hi - (j + 1) ) { \
200
+ ca_sort_quick_##SUFFIX##_range(a, lo, j, depth_limit); \
201
+ lo = j + 1; \
202
+ } else { \
203
+ ca_sort_quick_##SUFFIX##_range(a, j + 1, hi, depth_limit); \
204
+ hi = j; \
205
+ } \
206
+ } \
207
+ /* insertion-sort base case */ \
208
+ for ( ca_size_t k = lo + 1; k <= hi; k++ ) { \
209
+ TYPE v = a[k]; \
210
+ ca_size_t m = k; \
211
+ while ( m > lo && v < a[m - 1] ) { \
212
+ a[m] = a[m - 1]; \
213
+ m--; \
214
+ } \
215
+ a[m] = v; \
216
+ } \
217
+ } \
218
+ \
219
+ void \
220
+ ca_sort_quick_##SUFFIX (TYPE *a, ca_size_t n) \
221
+ { \
222
+ if ( n <= 1 ) return; \
223
+ /* depth_limit = 2 * floor(log2(n)) + 2, computed via integer \
224
+ bit-length (cheap and exact for ca_size_t). */ \
225
+ int depth_limit = 0; \
226
+ ca_size_t m = n; \
227
+ while ( m > 0 ) { depth_limit++; m >>= 1; } \
228
+ depth_limit *= 2; \
229
+ ca_sort_quick_##SUFFIX##_range(a, 0, n - 1, depth_limit); \
230
+ } \
231
+ struct ca_sort_quick_##SUFFIX##_eat_semicolon
232
+
233
+
234
+ /* ---------------------------------------------------------------------------
235
+ PAIR sort macros (argsort kernels).
236
+
237
+ The pair form sorts an array of (value, index) structs by value,
238
+ used by sort_index / sort_addr to obtain the permutation. Stable
239
+ tie-break is built into the comparison (equal values fall through
240
+ to compare indices), so quicksort is effectively stable for
241
+ argsort even though the algorithm itself is not.
242
+
243
+ Structurally identical to the scalar quick / merge macros above;
244
+ the only differences are (a) pair struct typedef, (b) inline cmp
245
+ that includes the index tie-break, (c) per-cell swap copies the
246
+ whole pair via TYPE temp.
247
+
248
+ Pair memory footprint: sizeof(TYPE) + sizeof(ca_size_t) (8 bytes
249
+ alignment-padded). Caller allocates N pairs once per fiber
250
+ (mkkernel emit_sort_native in carray_kernels.c).
251
+ --------------------------------------------------------------------- */
252
+
253
+ /* Pair struct typedefs live in carray.h so callers (mkkernel emit) can
254
+ allocate them by name. The macro below skips the typedef and only
255
+ defines the algorithm. */
256
+ #define DEFINE_SORT_PAIR(TYPE, SUFFIX) \
257
+ \
258
+ /* ---- pair mergesort (= stable; called by quick escape too) ---- */ \
259
+ \
260
+ static void \
261
+ ca_sort_merge_pair_##SUFFIX##_inspass (ca_pair_##SUFFIX *a, ca_size_t n) \
262
+ { \
263
+ ca_size_t lo = 0; \
264
+ while ( lo < n ) { \
265
+ ca_size_t hi_excl = lo + CA_SORT_INSERTION_THRESHOLD; \
266
+ if ( hi_excl > n ) hi_excl = n; \
267
+ for ( ca_size_t k = lo + 1; k < hi_excl; k++ ) { \
268
+ ca_pair_##SUFFIX v = a[k]; \
269
+ ca_size_t m = k; \
270
+ /* stable cmp: equal values keep ascending index (= left-take) */ \
271
+ while ( m > lo && \
272
+ ( v.v < a[m - 1].v || \
273
+ (!(a[m - 1].v < v.v) && v.i < a[m - 1].i) ) ) { \
274
+ a[m] = a[m - 1]; \
275
+ m--; \
276
+ } \
277
+ a[m] = v; \
278
+ } \
279
+ lo = hi_excl; \
280
+ } \
281
+ } \
282
+ \
283
+ void \
284
+ ca_sort_merge_pair_##SUFFIX (ca_pair_##SUFFIX *a, \
285
+ ca_pair_##SUFFIX *aux, \
286
+ ca_size_t n) \
287
+ { \
288
+ if ( n <= 1 ) return; \
289
+ ca_sort_merge_pair_##SUFFIX##_inspass(a, n); \
290
+ ca_pair_##SUFFIX *cur = a; \
291
+ ca_pair_##SUFFIX *next = aux; \
292
+ for ( ca_size_t width = CA_SORT_INSERTION_THRESHOLD; \
293
+ width < n; \
294
+ width <<= 1 ) { \
295
+ for ( ca_size_t lo = 0; lo < n; lo += (width << 1) ) { \
296
+ ca_size_t mid = lo + width; \
297
+ ca_size_t hi = lo + (width << 1); \
298
+ if ( mid > n ) mid = n; \
299
+ if ( hi > n ) hi = n; \
300
+ /* sorted-skip: left-tail <= right-head (stable cmp) */ \
301
+ if ( mid < hi ) { \
302
+ TYPE lt = cur[mid - 1].v; \
303
+ TYPE rh = cur[mid].v; \
304
+ ca_size_t li = cur[mid - 1].i; \
305
+ ca_size_t ri = cur[mid].i; \
306
+ int strict_left_smaller = (lt < rh) || \
307
+ (!(rh < lt) && li < ri); \
308
+ int equal = !(lt < rh) && !(rh < lt) && (li == ri); \
309
+ if ( strict_left_smaller || equal ) { \
310
+ memcpy(next + lo, cur + lo, \
311
+ (size_t)(hi - lo) * sizeof(ca_pair_##SUFFIX)); \
312
+ continue; \
313
+ } \
314
+ } \
315
+ ca_size_t i = lo, j = mid, k = lo; \
316
+ while ( i < mid && j < hi ) { \
317
+ /* stable: if cur[j] < cur[i] strictly, take j; else take i */ \
318
+ int take_j = (cur[j].v < cur[i].v) || \
319
+ (!(cur[i].v < cur[j].v) && cur[j].i < cur[i].i); \
320
+ if ( take_j ) next[k++] = cur[j++]; \
321
+ else next[k++] = cur[i++]; \
322
+ } \
323
+ while ( i < mid ) next[k++] = cur[i++]; \
324
+ while ( j < hi ) next[k++] = cur[j++]; \
325
+ } \
326
+ { ca_pair_##SUFFIX *t = cur; cur = next; next = t; } \
327
+ } \
328
+ if ( cur != a ) { \
329
+ memcpy(a, cur, (size_t) n * sizeof(ca_pair_##SUFFIX)); \
330
+ } \
331
+ } \
332
+ \
333
+ /* ---- pair quicksort (= stable via index tie-break + depth-limit escape) ----*/ \
334
+ \
335
+ static void \
336
+ ca_sort_quick_pair_##SUFFIX##_range (ca_pair_##SUFFIX *a, \
337
+ ca_size_t lo, ca_size_t hi, \
338
+ int depth_limit) \
339
+ { \
340
+ while ( hi - lo > CA_SORT_INSERTION_THRESHOLD ) { \
341
+ if ( depth_limit <= 0 ) { \
342
+ ca_size_t n_remain = hi - lo + 1; \
343
+ ca_pair_##SUFFIX *aux = \
344
+ (ca_pair_##SUFFIX *) xmalloc((size_t) n_remain * sizeof(ca_pair_##SUFFIX)); \
345
+ ca_sort_merge_pair_##SUFFIX(a + lo, aux, n_remain); \
346
+ xfree(aux); \
347
+ return; \
348
+ } \
349
+ depth_limit--; \
350
+ ca_size_t mid = lo + (hi - lo) / 2; \
351
+ /* median-of-3 by value (tie-break NOT applied here -- approximate \
352
+ median is fine; full stable cmp applies during partition). */ \
353
+ if ( a[mid].v < a[lo].v ) { ca_pair_##SUFFIX t = a[lo]; a[lo] = a[mid]; a[mid] = t; } \
354
+ if ( a[hi].v < a[lo].v ) { ca_pair_##SUFFIX t = a[lo]; a[lo] = a[hi]; a[hi] = t; } \
355
+ if ( a[hi].v < a[mid].v ) { ca_pair_##SUFFIX t = a[mid]; a[mid] = a[hi]; a[hi] = t; } \
356
+ TYPE pivot_v = a[mid].v; \
357
+ ca_size_t pivot_i = a[mid].i; \
358
+ /* Hoare partition with stable cmp (= compare by v, tie-break by i). */ \
359
+ ca_size_t i = lo, j = hi; \
360
+ for (;;) { \
361
+ while ( a[i].v < pivot_v || \
362
+ (!(pivot_v < a[i].v) && a[i].i < pivot_i) ) i++; \
363
+ while ( pivot_v < a[j].v || \
364
+ (!(a[j].v < pivot_v) && pivot_i < a[j].i) ) j--; \
365
+ if ( i >= j ) break; \
366
+ { ca_pair_##SUFFIX t = a[i]; a[i] = a[j]; a[j] = t; } \
367
+ i++; \
368
+ j--; \
369
+ } \
370
+ if ( j - lo < hi - (j + 1) ) { \
371
+ ca_sort_quick_pair_##SUFFIX##_range(a, lo, j, depth_limit); \
372
+ lo = j + 1; \
373
+ } else { \
374
+ ca_sort_quick_pair_##SUFFIX##_range(a, j + 1, hi, depth_limit); \
375
+ hi = j; \
376
+ } \
377
+ } \
378
+ /* insertion-sort base (stable cmp). */ \
379
+ for ( ca_size_t k = lo + 1; k <= hi; k++ ) { \
380
+ ca_pair_##SUFFIX v = a[k]; \
381
+ ca_size_t m = k; \
382
+ while ( m > lo && \
383
+ ( v.v < a[m - 1].v || \
384
+ (!(a[m - 1].v < v.v) && v.i < a[m - 1].i) ) ) { \
385
+ a[m] = a[m - 1]; \
386
+ m--; \
387
+ } \
388
+ a[m] = v; \
389
+ } \
390
+ } \
391
+ \
392
+ void \
393
+ ca_sort_quick_pair_##SUFFIX (ca_pair_##SUFFIX *a, ca_size_t n) \
394
+ { \
395
+ if ( n <= 1 ) return; \
396
+ int depth_limit = 0; \
397
+ ca_size_t m = n; \
398
+ while ( m > 0 ) { depth_limit++; m >>= 1; } \
399
+ depth_limit *= 2; \
400
+ ca_sort_quick_pair_##SUFFIX##_range(a, 0, n - 1, depth_limit); \
401
+ } \
402
+ struct ca_sort_pair_##SUFFIX##_eat_semicolon
403
+
404
+
405
+ /* ===== Per-type instantiations ===========================================
406
+ `<` is well-defined and IEEE-stable for all numeric C types used
407
+ here; NaN handling for f32 / f64 lives in the pre-partition pass
408
+ below. */
409
+
410
+ /* ---------------------------------------------------------------------------
411
+ NaN pre-partition (float data types only).
412
+
413
+ One-pass Hoare-style partition that separates `a[0..n)` into
414
+ `[finite | NaN]` regions in place, returning the finite count k
415
+ (the NaN region starts at a[k..n)). Unstable within the finite
416
+ region (original order of finite values not preserved) -- the
417
+ downstream sort kernel reorders them anyway.
418
+
419
+ Loop invariant:
420
+ - a[0 .. i) all finite
421
+ - a[j .. n) all NaN
422
+ - a[i .. j) unprocessed
423
+ Terminates when i == j.
424
+
425
+ `isnan(a[i])` is the only NaN-aware logic. The downstream sort
426
+ kernels treat the finite slice with plain `<`, which is well-
427
+ defined and IEEE-stable for finite operands.
428
+ --------------------------------------------------------------------------- */
429
+
430
+ #define DEFINE_PARTITION_NAN(TYPE, SUFFIX) \
431
+ ca_size_t \
432
+ ca_partition_nan_##SUFFIX (TYPE *a, ca_size_t n) \
433
+ { \
434
+ ca_size_t i = 0, j = n; \
435
+ while ( i < j ) { \
436
+ if ( isnan(a[i]) ) { \
437
+ j--; \
438
+ TYPE t = a[j]; a[j] = a[i]; a[i] = t; \
439
+ } else { \
440
+ i++; \
441
+ } \
442
+ } \
443
+ return i; \
444
+ } \
445
+ struct ca_partition_nan_##SUFFIX##_eat_semicolon
446
+
447
+ DEFINE_PARTITION_NAN(float32_t, f32);
448
+ DEFINE_PARTITION_NAN(double, f64);
449
+
450
+ /* Pair variant for argsort: separates ca_pair_<type> by
451
+ isnan(v.value). Returns the finite count.
452
+
453
+ Stable within both finite and NaN regions (original order
454
+ preserved), so argsort on NaN-containing input keeps NaN indices
455
+ in ascending order.
456
+
457
+ Implementation: 2-pass stable filter via xmalloc scratch (single
458
+ xmalloc + xfree per fiber; negligible overhead vs the sort
459
+ itself). */
460
+ #define DEFINE_PARTITION_NAN_PAIR(TYPE, SUFFIX) \
461
+ ca_size_t \
462
+ ca_partition_nan_pair_##SUFFIX (ca_pair_##SUFFIX *a, ca_size_t n) \
463
+ { \
464
+ if ( n == 0 ) return 0; \
465
+ ca_pair_##SUFFIX *scratch = \
466
+ (ca_pair_##SUFFIX *) xmalloc((size_t) n * sizeof(ca_pair_##SUFFIX)); \
467
+ ca_size_t fin = 0, nan_pos = 0; \
468
+ for ( ca_size_t k = 0; k < n; k++ ) { \
469
+ if ( !isnan(a[k].v) ) scratch[fin++] = a[k]; \
470
+ } \
471
+ ca_size_t finite_count = fin; \
472
+ for ( ca_size_t k = 0; k < n; k++ ) { \
473
+ if ( isnan(a[k].v) ) scratch[finite_count + nan_pos++] = a[k]; \
474
+ } \
475
+ memcpy(a, scratch, (size_t) n * sizeof(ca_pair_##SUFFIX)); \
476
+ xfree(scratch); \
477
+ return finite_count; \
478
+ } \
479
+ struct ca_partition_nan_pair_##SUFFIX##_eat_semicolon
480
+
481
+ DEFINE_PARTITION_NAN_PAIR(float32_t, f32);
482
+ DEFINE_PARTITION_NAN_PAIR(double, f64);
483
+
484
+
485
+ /* ---------------------------------------------------------------------------
486
+ DEFINE_PARTITION_QUICK(TYPE, SUFFIX) -- value-level quickselect.
487
+
488
+ Emits public `void ca_partition_quick_<SUFFIX>(TYPE *a,
489
+ ca_size_t n, ca_size_t kth)` that reorders `a[0..n)` so that:
490
+ - a[kth] is the kth-smallest element under `<`
491
+ - a[0..kth-1] all compare <= a[kth]
492
+ - a[kth+1..n-1] all compare >= a[kth]
493
+ Order within the two regions is unspecified.
494
+
495
+ Algorithm: median-of-3 pivot + Hoare partition + insertion-sort
496
+ base (threshold 16) + one-sided recursion into the side
497
+ containing kth (true quickselect: expected O(n), stack O(log n)).
498
+
499
+ Worst-case guarantee: depth_limit = 2*floor(log2(n)) + 2 (matches
500
+ the sort kernels). On escape, mergesort the residual window;
501
+ mergesort fully sorts the window, which is strictly stronger than
502
+ the partition contract, so kth ends up correct as a side-effect.
503
+ Cost on escape: O(n log n) on the residual window only.
504
+ --------------------------------------------------------------------- */
505
+
506
+ #define DEFINE_PARTITION_QUICK(TYPE, SUFFIX) \
507
+ \
508
+ static void \
509
+ ca_partition_quick_##SUFFIX##_range (TYPE *a, ca_size_t lo, ca_size_t hi, \
510
+ ca_size_t kth, int depth_limit) \
511
+ { \
512
+ while ( hi - lo > CA_SORT_INSERTION_THRESHOLD ) { \
513
+ if ( depth_limit <= 0 ) { \
514
+ /* Depth-limit escape: mergesort the residual window. A full \
515
+ sort is strictly stronger than the partition contract, so kth \
516
+ ends up correct as a side-effect. Cheaper than continuing to \
517
+ degrade on adversarial input. */ \
518
+ ca_size_t n_remain = hi - lo + 1; \
519
+ TYPE *aux = (TYPE *) xmalloc((size_t) n_remain * sizeof(TYPE)); \
520
+ ca_sort_merge_##SUFFIX(a + lo, aux, n_remain); \
521
+ xfree(aux); \
522
+ return; \
523
+ } \
524
+ depth_limit--; \
525
+ ca_size_t mid = lo + (hi - lo) / 2; \
526
+ /* median-of-3: order a[lo] <= a[mid] <= a[hi]. */ \
527
+ if ( a[mid] < a[lo] ) { TYPE t = a[lo]; a[lo] = a[mid]; a[mid] = t; } \
528
+ if ( a[hi] < a[lo] ) { TYPE t = a[lo]; a[lo] = a[hi]; a[hi] = t; } \
529
+ if ( a[hi] < a[mid] ) { TYPE t = a[mid]; a[mid] = a[hi]; a[hi] = t; } \
530
+ TYPE pivot = a[mid]; \
531
+ /* Hoare partition. */ \
532
+ ca_size_t i = lo, j = hi; \
533
+ for (;;) { \
534
+ while ( a[i] < pivot ) i++; \
535
+ while ( pivot < a[j] ) j--; \
536
+ if ( i >= j ) break; \
537
+ { TYPE t = a[i]; a[i] = a[j]; a[j] = t; } \
538
+ i++; \
539
+ j--; \
540
+ } \
541
+ /* After partition: \
542
+ a[lo..j] all compare <= pivot \
543
+ a[j+1..hi] all compare >= pivot \
544
+ Recurse only into the side containing kth. \
545
+ If kth <= j: kth is in the left half (which contains pivot \
546
+ boundary), so we tighten hi = j. \
547
+ Else: kth is in the right half, lo = j + 1. \
548
+ This is the quickselect property: expected O(n) work since each \
549
+ step halves the candidate window. */ \
550
+ if ( kth <= j ) { \
551
+ hi = j; \
552
+ } else { \
553
+ lo = j + 1; \
554
+ } \
555
+ } \
556
+ /* insertion-sort the residual base window so a[kth] is exact within \
557
+ [lo, hi]. Cheaper than another quickselect step and gives the \
558
+ partition contract for free across the small window. */ \
559
+ for ( ca_size_t k = lo + 1; k <= hi; k++ ) { \
560
+ TYPE v = a[k]; \
561
+ ca_size_t m = k; \
562
+ while ( m > lo && v < a[m - 1] ) { \
563
+ a[m] = a[m - 1]; \
564
+ m--; \
565
+ } \
566
+ a[m] = v; \
567
+ } \
568
+ } \
569
+ \
570
+ void \
571
+ ca_partition_quick_##SUFFIX (TYPE *a, ca_size_t n, ca_size_t kth) \
572
+ { \
573
+ if ( n <= 1 ) return; \
574
+ if ( kth >= n ) return; /* out-of-range kth = no-op, caller validates */ \
575
+ int depth_limit = 0; \
576
+ ca_size_t m = n; \
577
+ while ( m > 0 ) { depth_limit++; m >>= 1; } \
578
+ depth_limit *= 2; \
579
+ ca_partition_quick_##SUFFIX##_range(a, 0, n - 1, kth, depth_limit); \
580
+ } \
581
+ struct ca_partition_quick_##SUFFIX##_eat_semicolon
582
+
583
+
584
+ DEFINE_SORT_QUICK(int8_t, i8); DEFINE_SORT_MERGE(int8_t, i8);
585
+ DEFINE_SORT_QUICK(uint8_t, u8); DEFINE_SORT_MERGE(uint8_t, u8);
586
+ DEFINE_SORT_QUICK(int16_t, i16); DEFINE_SORT_MERGE(int16_t, i16);
587
+ DEFINE_SORT_QUICK(uint16_t, u16); DEFINE_SORT_MERGE(uint16_t, u16);
588
+ DEFINE_SORT_QUICK(int32_t, i32); DEFINE_SORT_MERGE(int32_t, i32);
589
+ DEFINE_SORT_QUICK(uint32_t, u32); DEFINE_SORT_MERGE(uint32_t, u32);
590
+ DEFINE_SORT_QUICK(int64_t, i64); DEFINE_SORT_MERGE(int64_t, i64);
591
+ DEFINE_SORT_QUICK(uint64_t, u64); DEFINE_SORT_MERGE(uint64_t, u64);
592
+ DEFINE_SORT_QUICK(float32_t, f32); DEFINE_SORT_MERGE(float32_t, f32);
593
+ DEFINE_SORT_QUICK(double, f64); DEFINE_SORT_MERGE(double, f64);
594
+
595
+ /* Pair sort instantiations for argsort (sort_index / sort_addr). */
596
+ DEFINE_SORT_PAIR(int8_t, i8);
597
+ DEFINE_SORT_PAIR(uint8_t, u8);
598
+ DEFINE_SORT_PAIR(int16_t, i16);
599
+ DEFINE_SORT_PAIR(uint16_t, u16);
600
+ DEFINE_SORT_PAIR(int32_t, i32);
601
+ DEFINE_SORT_PAIR(uint32_t, u32);
602
+ DEFINE_SORT_PAIR(int64_t, i64);
603
+ DEFINE_SORT_PAIR(uint64_t, u64);
604
+ DEFINE_SORT_PAIR(float32_t, f32);
605
+ DEFINE_SORT_PAIR(double, f64);
606
+
607
+ /* Value-level quickselect for partition_copy. */
608
+ DEFINE_PARTITION_QUICK(int8_t, i8);
609
+ DEFINE_PARTITION_QUICK(uint8_t, u8);
610
+ DEFINE_PARTITION_QUICK(int16_t, i16);
611
+ DEFINE_PARTITION_QUICK(uint16_t, u16);
612
+ DEFINE_PARTITION_QUICK(int32_t, i32);
613
+ DEFINE_PARTITION_QUICK(uint32_t, u32);
614
+ DEFINE_PARTITION_QUICK(int64_t, i64);
615
+ DEFINE_PARTITION_QUICK(uint64_t, u64);
616
+ DEFINE_PARTITION_QUICK(float32_t, f32);
617
+ DEFINE_PARTITION_QUICK(double, f64);
618
+
619
+ /* No Init function: this file exposes only C kernels (via ca_sort_kernels.h);
620
+ it registers no Ruby methods. */