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,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
+ }