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,766 @@
1
+ /* ---------------------------------------------------------------------------
2
+
3
+ CAByteSwap view: element-wise byte-order reversal of the parent.
4
+ Same shape and byte width as the parent; materialises on attach
5
+ with the byte swap applied. Sibling of CAFake (both are
6
+ value-conversion views under CAView).
7
+
8
+ Numeric primitive parents route through CAMonOp(byte_swap) by
9
+ `rb_ca_swap_bytes` — this file's CAByteSwap handles the residual
10
+ cases (CA_FIXLEN with data_class field-recursive swap, bare
11
+ fixlen buffers) that the monop kernel table does not cover.
12
+
13
+ ---------------------------------------------------------------------------- */
14
+
15
+ #include "carray.h"
16
+ #include "ca_iter_substrate.h" /* ca_xfer_stride_transform_fused */
17
+ #include "ca_monop_dispatch.h" /* CA_MONOP_BYTE_SWAP dispatch id */
18
+ #include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE for CARecord parent */
19
+
20
+ /* CAStride family identification (used for fast-path eligibility). */
21
+ extern ca_operation_function_t ca_stride_func;
22
+
23
+ /* Reverse the byte order of each `bytes`-wide element in place.
24
+ Element-local (no cross-element dependency), so the same routine
25
+ serves both the internal recursion helper rb_ca_swap_bytes_bang
26
+ and CAByteSwap's materialise — the caller just points it at the
27
+ target buffer (self->ptr or a scratch). */
28
+ void
29
+ ca_swap_bytes (char *ptr, ca_size_t bytes, ca_size_t elements)
30
+ {
31
+ char *p;
32
+ char val;
33
+ ca_size_t i;
34
+
35
+ #define SWAP_BYTE(a, b) (val = (a), (a) = (b), (b) = val)
36
+
37
+ switch ( bytes ) {
38
+ case 1:
39
+ break;
40
+ case 2:
41
+ for (i=0; i<elements; i++) {
42
+ p = ptr + 2*i;
43
+ SWAP_BYTE(p[0], p[1]);
44
+ }
45
+ break;
46
+ case 4:
47
+ for (i=0; i<elements; i++) {
48
+ p = ptr + 4*i;
49
+ SWAP_BYTE(p[0], p[3]);
50
+ SWAP_BYTE(p[1], p[2]);
51
+ }
52
+ break;
53
+ case 8:
54
+ for (i=0; i<elements; i++) {
55
+ p = ptr + 8*i;
56
+ SWAP_BYTE(p[0], p[7]);
57
+ SWAP_BYTE(p[1], p[6]);
58
+ SWAP_BYTE(p[2], p[5]);
59
+ SWAP_BYTE(p[3], p[4]);
60
+ }
61
+ break;
62
+ case 16:
63
+ for (i=0; i<elements; i++) {
64
+ p = ptr + 16*i;
65
+ SWAP_BYTE(p[0], p[15]);
66
+ SWAP_BYTE(p[1], p[14]);
67
+ SWAP_BYTE(p[2], p[13]);
68
+ SWAP_BYTE(p[3], p[12]);
69
+ SWAP_BYTE(p[4], p[11]);
70
+ SWAP_BYTE(p[5], p[10]);
71
+ SWAP_BYTE(p[6], p[9]);
72
+ SWAP_BYTE(p[7], p[8]);
73
+ }
74
+ break;
75
+ default: {
76
+ char *p1, *p2;
77
+ for (i=0; i<elements; i++) {
78
+ p = ptr + i*bytes;
79
+ p1 = p;
80
+ p2 = p+bytes-1;
81
+ while (p1<p2) {
82
+ SWAP_BYTE(*p1, *p2);
83
+ p1++; p2--;
84
+ }
85
+ }
86
+ break;
87
+ }
88
+ }
89
+
90
+ #undef SWAP_BYTE
91
+
92
+ }
93
+
94
+ /* Dispatch a byte-order swap of a buffer by data_type. Complex
95
+ types swap their two halves independently; everything else swaps
96
+ `bytes`-wide elements directly.
97
+ *
98
+ * CAREFUL: CA_FIXLEN structs with a data_class are NOT handled
99
+ * here — the caller must decompose them into their primitive
100
+ * fields (see ca_byte_swap_apply / _one).
101
+ *
102
+ * extern-visible so CAMonOp(byte_swap) in ca_obj_monop.c can share
103
+ * the same primitive for its writable lifecycle. */
104
+ void
105
+ ca_byte_swap_buffer (int8_t data_type, ca_size_t bytes, ca_size_t elements,
106
+ char *buf)
107
+ {
108
+ switch ( data_type ) {
109
+ case CA_CMPLX64:
110
+ ca_swap_bytes(buf, 4, 2 * elements);
111
+ break;
112
+ case CA_CMPLX128:
113
+ ca_swap_bytes(buf, 8, 2 * elements);
114
+ break;
115
+ default:
116
+ ca_swap_bytes(buf, bytes, elements);
117
+ }
118
+ }
119
+
120
+ typedef struct {
121
+ int16_t obj_type;
122
+ int8_t data_type;
123
+ int8_t ndim;
124
+ int32_t flags;
125
+ ca_size_t bytes;
126
+ ca_size_t elements;
127
+ ca_size_t *dim;
128
+ char *ptr;
129
+ CArray *mask;
130
+ char *_pool; /* framework-managed pool buffer (NULL = legacy ALLOC_N path). */
131
+ CArray *parent;
132
+ uint32_t attach;
133
+ uint8_t nosync;
134
+ /* ----- tail (must be marked by dmark) ----- */
135
+ VALUE data_class; /* parent's data_class, or Qnil if none. Snapshot
136
+ at setup time so attach can do field-recursive
137
+ swap on CA_FIXLEN structs without access to a
138
+ Ruby self VALUE. */
139
+ } CAByteSwap;
140
+
141
+ static size_t
142
+ ca_byte_swap_dsize (const void *ap)
143
+ {
144
+ const CAByteSwap *ca = (const CAByteSwap *) ap;
145
+ return sizeof(CAByteSwap) + ca->ndim * sizeof(ca_size_t);
146
+ }
147
+
148
+ /* Pool framework hooks: single ndim-sized tail (dim) in the _pool
149
+ buffer. See ca_array_pool.c for the shared alloc/free discipline. */
150
+ static size_t
151
+ ca_byte_swap_pool_bytes (int8_t ndim)
152
+ {
153
+ ca_size_t n = (ndim > 0) ? ndim : 1;
154
+ return (size_t) n * sizeof(ca_size_t);
155
+ }
156
+
157
+ static void
158
+ ca_byte_swap_pool_init (void *ap, int8_t ndim)
159
+ {
160
+ CAByteSwap *ca = (CAByteSwap *) ap;
161
+ ca->dim = (ca_size_t *) ca->_pool;
162
+ }
163
+
164
+ /* Custom dmark: ca_mark walks the standard prefix; the data_class
165
+ tail is a VALUE snapshot that must also be marked so the Class
166
+ stays alive across GC while the view holds it. */
167
+ static void
168
+ ca_byte_swap_mark (void *ap)
169
+ {
170
+ CAByteSwap *ca = (CAByteSwap *) ap;
171
+ ca_mark(ca);
172
+ rb_gc_mark(ca->data_class);
173
+ }
174
+
175
+ const rb_data_type_t cabyteswap_data_type = {
176
+ .parent = &caview_data_type,
177
+ .wrap_struct_name = "CAByteSwap",
178
+ .function = {
179
+ .dmark = ca_byte_swap_mark,
180
+ .dfree = ca_free,
181
+ .dsize = ca_byte_swap_dsize,
182
+ .dcompact = NULL
183
+ },
184
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
185
+ };
186
+
187
+ static int8_t CA_OBJ_BYTE_SWAP;
188
+ VALUE rb_cCAByteSwap;
189
+
190
+ /* ------------------------------------------------------------------- */
191
+
192
+ int
193
+ ca_byte_swap_setup (CAByteSwap *ca, CArray *parent, VALUE data_class)
194
+ {
195
+ CA_CHECK_DATA_TYPE(parent->data_type);
196
+
197
+ if ( parent->data_type == CA_OBJECT ) {
198
+ rb_raise(rb_eCADataTypeError, "object array can't be byte-swapped");
199
+ }
200
+
201
+ ca->obj_type = CA_OBJ_BYTE_SWAP;
202
+ ca->data_type = parent->data_type;
203
+ ca->flags = 0;
204
+ ca->ndim = parent->ndim;
205
+ ca->bytes = parent->bytes;
206
+ ca->elements = parent->elements;
207
+ ca->ptr = NULL;
208
+ ca->mask = NULL;
209
+ if ( ! ca->_pool ) {
210
+ ca->dim = ALLOC_N(ca_size_t, ca->ndim);
211
+ }
212
+ memcpy(ca->dim, parent->dim, ca->ndim * sizeof(ca_size_t));
213
+
214
+ ca->parent = parent;
215
+ ca->attach = 0;
216
+ ca->nosync = 0;
217
+ ca->data_class = data_class; /* Qnil if parent has no data_class */
218
+
219
+ if ( ca_has_mask(parent) ) {
220
+ ca_create_mask(ca);
221
+ }
222
+ if ( ca_is_scalar(parent) ) {
223
+ ca_set_flag(ca, CA_FLAG_SCALAR);
224
+ }
225
+
226
+ return 0;
227
+ }
228
+
229
+ CAByteSwap *
230
+ ca_byte_swap_new (CArray *parent, VALUE data_class)
231
+ {
232
+ CAByteSwap *ca = (CAByteSwap *) ca_array_alloc(CA_OBJ_BYTE_SWAP, parent->ndim);
233
+ ca_byte_swap_setup(ca, parent, data_class);
234
+ return ca;
235
+ }
236
+
237
+ static void
238
+ free_ca_byte_swap (void *ap)
239
+ {
240
+ CAByteSwap *ca = (CAByteSwap *) ap;
241
+ if ( ca != NULL ) {
242
+ ca_free(ca->mask);
243
+ if ( ca->_pool ) {
244
+ ca_array_free(ca); /* dim lives in _pool */
245
+ }
246
+ else {
247
+ xfree(ca->dim);
248
+ xfree(ca);
249
+ }
250
+ }
251
+ }
252
+
253
+ /* ------------------------------------------------------------------- */
254
+
255
+ /* Apply the byte-swap transformation to a buffer in place.
256
+ Three cases:
257
+ - CA_FIXLEN + data_class: walk each record's fields recursively
258
+ via a temporary CAWrap + rb_ca_swap_bytes_bang.
259
+ - CA_CMPLX64 / CA_CMPLX128: swap each 4 / 8-byte half independently
260
+ so the real / imaginary components are individually correct.
261
+ - other primitives / bare fixlen: ca_swap_bytes(buf, bytes, elements). */
262
+ static void
263
+ ca_byte_swap_apply (CAByteSwap *ca, char *buf)
264
+ {
265
+ if ( ca->data_type == CA_FIXLEN && RTEST(ca->data_class) ) {
266
+ volatile VALUE wrap = rb_ca_wrap_new(CA_FIXLEN, ca->ndim, ca->dim,
267
+ ca->bytes, NULL, buf);
268
+ /* data_class travels on CARecord (Face), so wrap the transient
269
+ into CARecord to let rb_ca_swap_bytes_bang see the fields. */
270
+ wrap = rb_funcall(rb_const_get(rb_cObject, rb_intern("CARecord")),
271
+ rb_intern("wrap"), 2, wrap, ca->data_class);
272
+ rb_ca_swap_bytes_bang(wrap);
273
+ return;
274
+ }
275
+ ca_byte_swap_buffer(ca->data_type, ca->bytes, ca->elements, buf);
276
+ }
277
+
278
+ /* Swap a single element worth of bytes in place (for fetch / store /
279
+ fill paths). Always succeeds: CA_FIXLEN + data_class recurses via
280
+ a transient CAWrap of width 1 (per-field swap, mirrors bulk path);
281
+ bare FIXLEN does flat byte swap of one cell; primitives use their
282
+ widths. Per-cell paths never call ca_attach. */
283
+ static int
284
+ ca_byte_swap_apply_one (CAByteSwap *ca, char *buf)
285
+ {
286
+ if ( ca->data_type == CA_FIXLEN && RTEST(ca->data_class) ) {
287
+ ca_size_t one = 1;
288
+ volatile VALUE wrap = rb_ca_wrap_new(CA_FIXLEN, 1, &one,
289
+ ca->bytes, NULL, buf);
290
+ /* Same CARecord-wrap trick as ca_byte_swap_apply, but for a
291
+ single cell. */
292
+ wrap = rb_funcall(rb_const_get(rb_cObject, rb_intern("CARecord")),
293
+ rb_intern("wrap"), 2, wrap, ca->data_class);
294
+ rb_ca_swap_bytes_bang(wrap);
295
+ return 1;
296
+ }
297
+ ca_byte_swap_buffer(ca->data_type, ca->bytes, 1, buf);
298
+ return 1;
299
+ }
300
+
301
+ /* ------------------------------------------------------------------- */
302
+
303
+ static void *
304
+ ca_byte_swap_func_clone (void *ap)
305
+ {
306
+ CAByteSwap *ca = (CAByteSwap *) ap;
307
+ return ca_byte_swap_new(ca->parent, ca->data_class);
308
+ }
309
+
310
+ /* Per-cell get / put: fetch parent cell + swap into caller buffer
311
+ (GET), or swap a caller copy + store it back (PUT). Never calls
312
+ ca_attach — the swap primitive works on any stack scratch. */
313
+ static void
314
+ ca_byte_swap_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
315
+ {
316
+ CAByteSwap *ca = (CAByteSwap *) ap;
317
+ if ( dir == CA_XFER_GET ) {
318
+ ca_fetch_index(ca->parent, idx, data);
319
+ ca_byte_swap_apply_one(ca, (char *) data);
320
+ }
321
+ else {
322
+ char v[32];
323
+ char *buf = (ca->bytes <= 32) ? v : xmalloc(ca->bytes);
324
+ memcpy(buf, data, ca->bytes);
325
+ ca_byte_swap_apply_one(ca, buf);
326
+ ca_store_index(ca->parent, idx, buf);
327
+ if ( buf != v ) xfree(buf);
328
+ }
329
+ }
330
+
331
+ /* Batched gather / scatter. CAByteSwap is 1:1 same-size with its
332
+ parent, so the incoming address list is delivered as-is to the
333
+ parent in one call; the byte swap is applied to the delivered
334
+ buffer in place. CA_FIXLEN + data_class cases swap field-
335
+ recursively per cell; everything else uses the bulk primitive. */
336
+ static void
337
+ ca_byte_swap_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
338
+ void *data, int dir)
339
+ {
340
+ CAByteSwap *ca = (CAByteSwap *) ap;
341
+ char *d = (char *) data;
342
+ int is_struct = ( ca->data_type == CA_FIXLEN && RTEST(ca->data_class) );
343
+ ca_size_t i;
344
+
345
+ if ( dir == CA_XFER_GET ) {
346
+ ca_xfer_addrs(ca->parent, n, addrs, data, CA_XFER_GET);
347
+ if ( is_struct ) {
348
+ for (i = 0; i < n; i++) ca_byte_swap_apply_one(ca, d + i * ca->bytes);
349
+ }
350
+ else {
351
+ ca_byte_swap_buffer(ca->data_type, ca->bytes, n, d);
352
+ }
353
+ }
354
+ else {
355
+ char *v;
356
+ volatile VALUE holder;
357
+ v = ALLOCV_N(char, holder, n * ca->bytes);
358
+ memcpy(v, data, n * ca->bytes);
359
+ if ( is_struct ) {
360
+ for (i = 0; i < n; i++) ca_byte_swap_apply_one(ca, v + i * ca->bytes);
361
+ }
362
+ else {
363
+ ca_byte_swap_buffer(ca->data_type, ca->bytes, n, v);
364
+ }
365
+ ca_xfer_addrs(ca->parent, n, addrs, v, CA_XFER_PUT);
366
+ ALLOCV_END(holder);
367
+ }
368
+ }
369
+
370
+ /* CAByteSwap is a never-fold transform boundary that is size-
371
+ preserving (parent.bytes == view.bytes), so the incoming region
372
+ recurses through parent.xfer_stride and the swap is applied to
373
+ the contiguous delivered buffer. Parent's own stride chain
374
+ folds to entity inside the recursive call, so this file does not
375
+ attach the parent directly. */
376
+
377
+ /* Per-row byte-swap transform callbacks for the shared fused
378
+ xfer_stride helper. src and dst share the same bytes (view is
379
+ size-preserving), so a plain memcpy + ca_byte_swap_buffer in
380
+ place is enough. */
381
+ static void
382
+ ca_byte_swap_xform_get (ca_size_t n, CArray *src_arr, char *src_row,
383
+ CArray *dst_arr, char *dst_row)
384
+ {
385
+ CAByteSwap *cb = (CAByteSwap *) dst_arr;
386
+ memcpy(dst_row, src_row, n * cb->bytes);
387
+ ca_byte_swap_buffer(cb->data_type, cb->bytes, n, dst_row);
388
+ }
389
+
390
+ static void
391
+ ca_byte_swap_xform_put (ca_size_t n, CArray *src_arr, char *src_row,
392
+ CArray *dst_arr, char *dst_row)
393
+ {
394
+ CAByteSwap *cb = (CAByteSwap *) src_arr;
395
+ memcpy(dst_row, src_row, n * cb->bytes);
396
+ ca_byte_swap_buffer(cb->data_type, cb->bytes, n, dst_row);
397
+ }
398
+
399
+ /* Fast path (non-struct): compose-fold walk with per-row byte
400
+ swap, no scratch for the whole region. CA_FIXLEN + data_class
401
+ cases fall back to the scratch-and-swap 2-pass because they need
402
+ per-cell field-recursive swap that the fused helper cannot
403
+ express. */
404
+ static void
405
+ ca_byte_swap_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
406
+ ca_size_t *strides, void *data, int dir)
407
+ {
408
+ CAByteSwap *ca = (CAByteSwap *) ap;
409
+ char *d = (char *) data;
410
+ int is_struct = ( ca->data_type == CA_FIXLEN && RTEST(ca->data_class) );
411
+ ca_size_t n = 1, i;
412
+ int8_t k;
413
+
414
+ if ( !is_struct ) {
415
+ if ( ca_xfer_stride_transform_fused((CArray *)ca, ca->parent,
416
+ starts, counts, strides,
417
+ d, dir,
418
+ ca_byte_swap_xform_get,
419
+ ca_byte_swap_xform_put) ) {
420
+ return;
421
+ }
422
+ }
423
+
424
+ /* Fallback scratch-and-swap 2-pass (handles struct case + cold
425
+ boundary parents). */
426
+ for ( k = 0; k < ca->ndim; k++ ) n *= counts[k];
427
+ if ( dir == CA_XFER_GET ) {
428
+ ca_xfer_stride(ca->parent, starts, counts, strides, data, CA_XFER_GET);
429
+ if ( is_struct ) {
430
+ for (i = 0; i < n; i++) ca_byte_swap_apply_one(ca, d + i * ca->bytes);
431
+ }
432
+ else {
433
+ ca_byte_swap_buffer(ca->data_type, ca->bytes, n, d);
434
+ }
435
+ }
436
+ else {
437
+ char *v;
438
+ volatile VALUE holder;
439
+ v = ALLOCV_N(char, holder, n * ca->bytes);
440
+ memcpy(v, data, n * ca->bytes);
441
+ if ( is_struct ) {
442
+ for (i = 0; i < n; i++) ca_byte_swap_apply_one(ca, v + i * ca->bytes);
443
+ }
444
+ else {
445
+ ca_byte_swap_buffer(ca->data_type, ca->bytes, n, v);
446
+ }
447
+ ca_xfer_stride(ca->parent, starts, counts, strides, v, CA_XFER_PUT);
448
+ ALLOCV_END(holder);
449
+ }
450
+ }
451
+
452
+ static void
453
+ ca_byte_swap_func_allocate (void *ap)
454
+ {
455
+ CAByteSwap *ca = (CAByteSwap *) ap;
456
+ ca_attach(ca->parent);
457
+ ca->ptr = xmalloc(ca_length(ca));
458
+ }
459
+
460
+ static void
461
+ ca_byte_swap_func_attach (void *ap)
462
+ {
463
+ CAByteSwap *ca = (CAByteSwap *) ap;
464
+ ca_attach(ca->parent);
465
+ ca->ptr = xmalloc(ca_length(ca));
466
+ memcpy(ca->ptr, ca->parent->ptr, ca_length(ca));
467
+ ca_byte_swap_apply(ca, ca->ptr);
468
+ }
469
+
470
+ static void
471
+ ca_byte_swap_func_sync (void *ap)
472
+ {
473
+ CAByteSwap *ca = (CAByteSwap *) ap;
474
+ /* Swap is involutive, so applying it once to the view buffer
475
+ restores the parent byte order before the copy-back. */
476
+ ca_byte_swap_apply(ca, ca->ptr);
477
+ memcpy(ca->parent->ptr, ca->ptr, ca_length(ca));
478
+ ca_sync(ca->parent);
479
+ }
480
+
481
+ static void
482
+ ca_byte_swap_func_detach (void *ap)
483
+ {
484
+ CAByteSwap *ca = (CAByteSwap *) ap;
485
+ xfree(ca->ptr);
486
+ ca->ptr = NULL;
487
+ ca_detach(ca->parent);
488
+ }
489
+
490
+ /* Whole-view transfer as a thin wrapper around xfer_stride.
491
+ Deliberately does not call ca_attach(parent) — the underlying
492
+ xfer_stride reaches the parent through the fused helper (or,
493
+ for cold non-CAStride parents, its own scratch-and-swap 2-pass)
494
+ without needing a whole-view attach here. */
495
+ static void
496
+ ca_byte_swap_func_xfer_all (void *ap, void *data, int dir)
497
+ {
498
+ CAByteSwap *ca = (CAByteSwap *) ap;
499
+ ca_size_t starts[CA_RANK_MAX];
500
+ ca_size_t native[CA_RANK_MAX];
501
+ int8_t k;
502
+ ca_size_t s = ca->bytes;
503
+ for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
504
+ for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
505
+ ca_xfer_stride(ca, starts, ca->dim, native, data, dir);
506
+ }
507
+
508
+ static void
509
+ ca_byte_swap_func_fill_data (void *ap, void *ptr)
510
+ {
511
+ CAByteSwap *ca = (CAByteSwap *) ap;
512
+ char v[32];
513
+ char *buf = (ca->bytes <= 32) ? v : xmalloc(ca->bytes);
514
+ memcpy(buf, ptr, ca->bytes);
515
+ if ( !ca_byte_swap_apply_one(ca, buf) ) {
516
+ /* Bare CA_FIXLEN fill: broadcast the raw bytes into the view
517
+ buffer through attach/sync so the parent sees the correct
518
+ byte order after mapping back. */
519
+ ca_attach(ca);
520
+ {
521
+ ca_size_t i;
522
+ for (i = 0; i < ca->elements; i++) {
523
+ memcpy(ca->ptr + i * ca->bytes, ptr, ca->bytes);
524
+ }
525
+ }
526
+ ca_sync(ca);
527
+ ca_detach(ca);
528
+ if ( buf != v ) xfree(buf);
529
+ return;
530
+ }
531
+ ca_fill(ca->parent, buf);
532
+ if ( buf != v ) xfree(buf);
533
+ }
534
+
535
+ /* fill_data with a region. Swapping is per value, not per cell, so the one
536
+ value is swapped once and the region passes to the parent as it stands --
537
+ a swap view reorders bytes within a cell, never cells within the array, so
538
+ its addresses are the parent's. A bare CA_FIXLEN has no swap to apply and
539
+ falls to the per-cell walk, which at least stays inside the region. */
540
+
541
+ static void
542
+ ca_byte_swap_func_fill_stride (void *ap, ca_size_t base, int8_t ndim,
543
+ ca_size_t *counts, ca_size_t *steps, void *ptr)
544
+ {
545
+ CAByteSwap *ca = (CAByteSwap *) ap;
546
+ char v[32];
547
+ char *buf = (ca->bytes <= 32) ? v : xmalloc(ca->bytes);
548
+ memcpy(buf, ptr, ca->bytes);
549
+ if ( ca_byte_swap_apply_one(ca, buf) ) {
550
+ ca_fill_stride(ca->parent, base, ndim, counts, steps, buf);
551
+ }
552
+ else {
553
+ ca_fill_stride_default(ca, base, ndim, counts, steps, ptr);
554
+ }
555
+ if ( buf != v ) xfree(buf);
556
+ }
557
+
558
+ static void
559
+ ca_byte_swap_func_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
560
+ void *ptr)
561
+ {
562
+ CAByteSwap *ca = (CAByteSwap *) ap;
563
+ char v[32];
564
+ char *buf = (ca->bytes <= 32) ? v : xmalloc(ca->bytes);
565
+ memcpy(buf, ptr, ca->bytes);
566
+ if ( ca_byte_swap_apply_one(ca, buf) ) {
567
+ ca_fill_addrs(ca->parent, n, addrs, buf);
568
+ }
569
+ else {
570
+ ca_fill_addrs_default(ca, n, addrs, ptr);
571
+ }
572
+ if ( buf != v ) xfree(buf);
573
+ }
574
+
575
+ static void
576
+ ca_byte_swap_func_create_mask (void *ap)
577
+ {
578
+ CAByteSwap *ca = (CAByteSwap *) ap;
579
+ ca_update_mask(ca->parent);
580
+ if ( ! ca->parent->mask ) {
581
+ ca_create_mask(ca->parent);
582
+ }
583
+ /* Mask is byte-wide (boolean), so the swap is a no-op for the
584
+ mask itself. Share the parent's mask via a CARefer to keep the
585
+ two in lockstep. */
586
+ ca->mask =
587
+ (CArray *) ca_refer_new(ca->parent->mask,
588
+ CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
589
+ }
590
+
591
+ ca_operation_function_t ca_byte_swap_func = {
592
+ -1, /* CA_OBJ_BYTE_SWAP */
593
+ CA_VIEW_ARRAY,
594
+ free_ca_byte_swap,
595
+ ca_byte_swap_func_clone,
596
+ ca_byte_swap_func_allocate,
597
+ ca_byte_swap_func_attach,
598
+ ca_byte_swap_func_sync,
599
+ ca_byte_swap_func_detach,
600
+ ca_byte_swap_func_fill_data,
601
+ ca_byte_swap_func_create_mask,
602
+ ca_byte_swap_func_xfer_index,
603
+ ca_byte_swap_func_xfer_addrs,
604
+ NULL, /* fold_stride: never fold — value-conversion boundary */
605
+ ca_byte_swap_func_xfer_stride,
606
+ ca_byte_swap_func_xfer_all,
607
+ .fill_addrs = ca_byte_swap_func_fill_addrs,
608
+ .fill_stride = ca_byte_swap_func_fill_stride,
609
+ };
610
+
611
+ /* ------------------------------------------------------------------- */
612
+
613
+ /* Defined in ca_obj_monop.c (single-op CAMonOp builder).
614
+ Called below for primitive-numeric byte swap. */
615
+ extern VALUE rb_ca_monop_build (VALUE cary, uint16_t op_id);
616
+
617
+ VALUE
618
+ rb_ca_byte_swap_new (VALUE cary)
619
+ {
620
+ volatile VALUE obj, data_class;
621
+ CArray *parent;
622
+ CAByteSwap *ca;
623
+ rb_check_carray_object(cary);
624
+ TypedData_Get_Struct(cary, CArray, &carray_data_type, parent);
625
+
626
+ /* Primitive numeric routes to CAMonOp(byte_swap), which owns the
627
+ numeric byte_swap kernel and its writable lifecycle. CAByteSwap
628
+ handles the residual cases the monop kernel table does not
629
+ cover: CA_FIXLEN with data_class (field-recursive swap needs a
630
+ Ruby callback), bare CA_FIXLEN (variable bytes-per-cell), and
631
+ CA_OBJECT (rejected in setup). */
632
+ if ( parent->data_type != CA_FIXLEN && parent->data_type != CA_OBJECT ) {
633
+ return rb_ca_monop_build(cary, CA_MONOP_BYTE_SWAP);
634
+ }
635
+
636
+ /* Snapshot data_class (or Qnil) so attach can do the field-
637
+ recursive swap without needing to resolve `self` again. */
638
+ data_class = rb_ca_data_class(cary);
639
+ ca = ca_byte_swap_new(parent, data_class);
640
+ obj = ca_wrap_struct(ca);
641
+ rb_ca_set_parent(obj, cary);
642
+ /* Lift back into a Face when `self` is a CARecord so field
643
+ projection and data_class queries keep working through the
644
+ swap_bytes view. */
645
+ CA_FACE_LIFT_IF_FACE(obj, cary, parent);
646
+ return obj;
647
+ }
648
+
649
+ static VALUE
650
+ rb_ca_byte_swap_s_allocate (VALUE klass)
651
+ {
652
+ CAByteSwap *ca;
653
+ return TypedData_Make_Struct(klass, CAByteSwap, &cabyteswap_data_type, ca);
654
+ }
655
+
656
+ static VALUE
657
+ rb_ca_byte_swap_initialize_copy (VALUE self, VALUE other)
658
+ {
659
+ CAByteSwap *ca, *cs;
660
+ TypedData_Get_Struct(self, CAByteSwap, &cabyteswap_data_type, ca);
661
+ TypedData_Get_Struct(other, CAByteSwap, &cabyteswap_data_type, cs);
662
+ if ( ca_func[CA_OBJ_BYTE_SWAP].pool_init ) {
663
+ ca_array_pool_alloc(ca, CA_OBJ_BYTE_SWAP, cs->parent->ndim);
664
+ }
665
+ ca_byte_swap_setup(ca, cs->parent, cs->data_class);
666
+ return self;
667
+ }
668
+
669
+ /* CArray#swap_bytes — lazy CAByteSwap (or CAMonOp for primitive
670
+ numeric) view whose cells are byte-swapped versions of self's
671
+ cells; materialises on attach. */
672
+ VALUE
673
+ rb_ca_swap_bytes (VALUE self)
674
+ {
675
+ return rb_ca_byte_swap_new(self);
676
+ }
677
+
678
+ /* CArray#endian(byte_order) — returns a view of self in the
679
+ requested byte order. Accepts :preserve / :native (both
680
+ identity, since CArrays are stored host-endian), :big (identity
681
+ on big-endian hosts, otherwise a byte-swap view), or :little
682
+ (identity on little-endian hosts, otherwise a byte-swap view).
683
+ The keyword set matches bulk-memory-view's
684
+ `BulkMemoryView.from(producer, endian:)`. */
685
+ VALUE
686
+ rb_ca_endian (VALUE self, VALUE byte_order)
687
+ {
688
+ ID sym;
689
+ if ( !SYMBOL_P(byte_order) ) {
690
+ rb_raise(rb_eArgError,
691
+ "endian: must be :preserve, :native, :big, or :little");
692
+ }
693
+ sym = SYM2ID(byte_order);
694
+ if ( sym == rb_intern("preserve") || sym == rb_intern("native") ) {
695
+ return self;
696
+ }
697
+ if ( sym == rb_intern("big") ) {
698
+ return (ca_endian == CA_BIG_ENDIAN) ? self : rb_ca_byte_swap_new(self);
699
+ }
700
+ if ( sym == rb_intern("little") ) {
701
+ return (ca_endian == CA_LITTLE_ENDIAN) ? self : rb_ca_byte_swap_new(self);
702
+ }
703
+ rb_raise(rb_eArgError,
704
+ "endian: must be :preserve, :native, :big, or :little");
705
+ }
706
+
707
+ /* Internal recursion helper for the bulk byte-swap path. Not
708
+ exposed as a Ruby method; the CA_FIXLEN + data_class branches in
709
+ ca_byte_swap_apply / _one call this to walk into each field of a
710
+ struct. */
711
+ VALUE
712
+ rb_ca_swap_bytes_bang (VALUE self)
713
+ {
714
+ CArray *ca;
715
+
716
+ rb_check_frozen(self);
717
+
718
+ if ( rb_ca_is_object_type(self) ) {
719
+ rb_raise(rb_eCADataTypeError, "object array can't swap bytes");
720
+ }
721
+
722
+ /* CA_FIXLEN with a data_class: decompose into its fields and swap each
723
+ (the field views write back to self). */
724
+ if ( rb_ca_is_fixlen_type(self) && rb_ca_has_data_class(self) ) {
725
+ volatile VALUE members = rb_ca_fields(self);
726
+ int i;
727
+ Check_Type(members, T_ARRAY);
728
+ for (i=0; i<RARRAY_LEN(members); i++) {
729
+ rb_ca_swap_bytes_bang(rb_ary_entry(members, i));
730
+ }
731
+ return self;
732
+ }
733
+
734
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
735
+ ca_attach(ca);
736
+ ca_byte_swap_buffer(ca->data_type, ca->bytes, ca->elements, ca->ptr);
737
+ ca_sync(ca);
738
+ ca_detach(ca);
739
+ return self;
740
+ }
741
+
742
+ void
743
+ Init_ca_obj_byte_swap (void)
744
+ {
745
+ rb_cCAByteSwap = rb_define_class("CAByteSwap", rb_cCAView);
746
+
747
+ ca_byte_swap_func.struct_size = sizeof(CAByteSwap);
748
+ ca_byte_swap_func.pool_bytes = ca_byte_swap_pool_bytes;
749
+ ca_byte_swap_func.pool_init = ca_byte_swap_pool_init;
750
+
751
+ CA_OBJ_BYTE_SWAP = ca_install_obj_type(rb_cCAByteSwap,
752
+ &cabyteswap_data_type,
753
+ rb_cCArrayMask,
754
+ &carray_mask_data_type,
755
+ &ca_byte_swap_func, sizeof(ca_byte_swap_func));
756
+ rb_define_const(rb_cObject, "CA_OBJ_BYTE_SWAP", INT2NUM(CA_OBJ_BYTE_SWAP));
757
+
758
+ rb_define_method(rb_cCArray, "swap_bytes", rb_ca_swap_bytes, 0);
759
+ /* `swap_bytes!` intentionally absent; the in-place idiom is
760
+ `ca[] = ca.swap_bytes`. */
761
+ rb_define_method(rb_cCArray, "endian", rb_ca_endian, 1);
762
+
763
+ rb_define_alloc_func(rb_cCAByteSwap, rb_ca_byte_swap_s_allocate);
764
+ rb_define_method(rb_cCAByteSwap, "initialize_copy",
765
+ rb_ca_byte_swap_initialize_copy, 1);
766
+ }