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
data/ext/ca_obj_refer.c CHANGED
@@ -1,22 +1,49 @@
1
1
  /* ---------------------------------------------------------------------------
2
2
 
3
- ca_obj_refer.c
3
+ CARefer view: strided reinterpretation of the parent (`#refer`)
4
+ plus the two shape-only rewrites `#reshape` and `#flatten`.
5
+ Byte-level reinterpret (a different `data_type` / `bytes`) that
6
+ CAStride cannot express is what makes CARefer distinct — plain
7
+ same-shape reshape usually rewrites to CAStride directly through
8
+ ca_reshape_try_strides.
4
9
 
5
- This file is part of Ruby/CArray extension library.
6
-
7
- Copyright (C) 2005-2020 Hiroki Motoyoshi
10
+ Sibling of ca_obj_stride.c (CARefer's operation table is
11
+ ca_stride_func with `free_object` / `clone` / `create_mask`
12
+ overridden for the byte-reinterpret mask paths).
8
13
 
9
14
  ---------------------------------------------------------------------------- */
10
15
 
11
16
  #include "carray.h"
17
+ #include "carray_internal.h" /* per-obj_type view constructors */
18
+ #include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE for CARecord parent */
19
+
20
+ extern ca_operation_function_t ca_stride_func;
21
+
22
+ VALUE rb_cCARefer;
23
+ VALUE rb_cCAReferMask;
24
+
25
+ /* CARefer ops: ca_stride_func + custom free + custom create_mask.
26
+ Filled in at Init time so the function pointers are valid before
27
+ carray_core's baseline registration is overridden. */
28
+ static ca_operation_function_t ca_refer_func;
12
29
 
30
+ static size_t
31
+ ca_refer_dsize (const void *ap)
32
+ {
33
+ const CARefer *ca = (const CARefer *) ap;
34
+ return sizeof(CARefer) + 2 * ca->ndim * sizeof(ca_size_t);
35
+ }
36
+
37
+ /* TypedData parent chain: carefer -> castride -> caview -> carray.
38
+ Inheriting from castride_data_type lets CAStride accessor methods
39
+ (#strides, #byte_offset) accept CARefer instances. */
13
40
  const rb_data_type_t carefer_data_type = {
14
- .parent = &cavirtual_data_type,
41
+ .parent = &castride_data_type,
15
42
  .wrap_struct_name = "CARefer",
16
43
  .function = {
17
44
  .dmark = ca_mark,
18
45
  .dfree = ca_free,
19
- .dsize = NULL,
46
+ .dsize = ca_refer_dsize,
20
47
  .dcompact = NULL
21
48
  },
22
49
  .flags = RUBY_TYPED_FREE_IMMEDIATELY
@@ -28,104 +55,77 @@ const rb_data_type_t carefer_mask_data_type = {
28
55
  .function = {
29
56
  .dmark = NULL,
30
57
  .dfree = ca_free_nop,
31
- .dsize = NULL,
58
+ .dsize = ca_refer_dsize,
32
59
  .dcompact = NULL
33
60
  },
34
61
  .flags = RUBY_TYPED_FREE_IMMEDIATELY
35
62
  };
36
63
 
37
- VALUE rb_cCARefer;
38
- VALUE rb_cCAReferMask;
39
-
40
- /* yard:
41
- class CARefer < CAVirtual # :nodoc:
42
- end
43
- */
64
+ /* ------------------------------------------------------------------- */
44
65
 
45
- static int
66
+ int
46
67
  ca_refer_setup (CARefer *ca, CArray *parent,
47
68
  int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
48
69
  ca_size_t offset)
49
70
  {
50
- ca_size_t elements, ratio;
71
+ ca_size_t elements, strides[CA_RANK_MAX];
72
+ ca_size_t parent_bytes = parent->bytes;
73
+ ca_size_t base_offset;
74
+ ca_size_t s;
51
75
  int8_t i;
52
- int is_deformed;
53
76
 
54
77
  CA_CHECK_DATA_TYPE(data_type);
55
78
  CA_CHECK_RANK(ndim);
56
79
  CA_CHECK_DIM(ndim, dim);
57
80
  CA_CHECK_BYTES(data_type, bytes);
58
81
 
59
- if ( ca_is_object_type(parent) && data_type != CA_OBJECT ) {
60
- rb_raise(rb_eRuntimeError, "object array can't be referred by other data type");
82
+ if (ca_is_object_type(parent) && data_type != CA_OBJECT) {
83
+ rb_raise(rb_eRuntimeError,
84
+ "object array can't be referred by other data type");
61
85
  }
62
-
63
- if ( parent->elements && bytes > parent->bytes * parent->elements ) {
86
+ if (parent->elements && bytes > parent_bytes * parent->elements) {
64
87
  rb_raise(rb_eRuntimeError, "bytes exceeds the data size of referent");
65
88
  }
66
-
67
- /* calc datanum and check deformation */
68
- is_deformed = ( ndim == parent->ndim ) ? 0 : 1;
69
- ratio = 1;
70
- elements = 1;
71
- for (i=0; i<ndim; i++) {
72
- elements *= dim[i];
73
- if ( dim[i] != parent->dim[i] ) {
74
- is_deformed |= 1;
75
- }
76
- }
77
- if ( bytes < parent->bytes ) {
78
- if ( parent->bytes % bytes != 0 ) {
79
- rb_raise(rb_eRuntimeError, "bytes of reference array must be a multiple of that of referent");
80
- }
81
- is_deformed = -2;
82
- ratio = parent->bytes / bytes;
89
+ if (bytes < parent_bytes && parent_bytes % bytes != 0) {
90
+ rb_raise(rb_eRuntimeError,
91
+ "bytes of reference array must be a multiple of that of referent");
83
92
  }
84
- else if ( bytes > parent->bytes ) {
85
- if ( bytes % parent->bytes != 0 ) {
86
- rb_raise(rb_eRuntimeError, "bytes of reference array must be a multiple of that of referent");
87
- }
88
- is_deformed = 2;
89
- ratio = bytes / parent->bytes;
93
+ if (bytes > parent_bytes && bytes % parent_bytes != 0) {
94
+ rb_raise(rb_eRuntimeError,
95
+ "bytes of reference array must be a multiple of that of referent");
90
96
  }
91
- if ( offset < 0 ) {
97
+ if (offset < 0) {
92
98
  rb_raise(rb_eRuntimeError, "negative offset is not permitted for CARefer");
93
99
  }
94
-
95
- if ( ( bytes * elements + parent->bytes * offset ) >
96
- ( parent->bytes * parent->elements ) ) {
97
- rb_raise(rb_eRuntimeError, "data size of reference array must not exceed that of referent");
100
+ elements = 1;
101
+ for (i = 0; i < ndim; i++) elements *= dim[i];
102
+ if ((bytes * elements + parent_bytes * offset) >
103
+ (parent_bytes * parent->elements)) {
104
+ rb_raise(rb_eRuntimeError,
105
+ "data size of reference array must not exceed that of referent");
98
106
  }
99
107
 
100
- ca->obj_type = CA_OBJ_REFER;
101
- ca->data_type = data_type;
102
- ca->flags = 0;
103
- ca->ndim = ndim;
104
- ca->bytes = bytes;
105
- ca->elements = elements;
106
- ca->dim = ALLOC_N(ca_size_t, ndim);
107
- ca->ptr = NULL;
108
- ca->mask = NULL;
109
- ca->mask0 = NULL;
110
-
111
- ca->parent = parent;
112
- ca->attach = 0;
113
- ca->nosync = 0;
114
-
115
- ca->is_deformed = (int8_t) is_deformed;
116
- ca->ratio = ratio;
117
- ca->offset = offset;
118
-
119
- if ( ca->offset > 0 && ca->is_deformed == 0 ) {
120
- ca->is_deformed = 1;
108
+ /* strides: row-major contiguous over the view's own dim, in view bytes */
109
+ s = bytes;
110
+ for (i = ndim - 1; i >= 0; i--) {
111
+ strides[i] = s;
112
+ s *= dim[i];
121
113
  }
114
+ /* base_offset is in bytes: `offset` is in parent-element units. */
115
+ base_offset = offset * parent_bytes;
116
+
117
+ /* CAREFUL: initialise mask0 before ca_stride_setup — the setup
118
+ may dispatch to ca_refer_func_create_mask, which writes to
119
+ mask0. Leaving it uninitialised risks freeing a garbage
120
+ pointer during error unwind. */
121
+ ca->mask0 = NULL;
122
122
 
123
- memcpy(ca->dim, dim, ndim * sizeof(ca_size_t));
123
+ ca_stride_setup((CAStride *) ca, CA_OBJ_REFER, parent,
124
+ data_type, bytes, ndim, dim, strides, base_offset);
124
125
 
125
- if ( ca_is_scalar(parent) ) {
126
+ if (ca_is_scalar(parent)) {
126
127
  ca_set_flag(ca, CA_FLAG_SCALAR);
127
128
  }
128
-
129
129
  return 0;
130
130
  }
131
131
 
@@ -134,7 +134,7 @@ ca_refer_new (CArray *parent,
134
134
  int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
135
135
  ca_size_t offset)
136
136
  {
137
- CARefer *ca = ALLOC(CARefer);
137
+ CARefer *ca = (CARefer *) ca_array_alloc(CA_OBJ_REFER, ndim);
138
138
  ca_refer_setup(ca, parent, data_type, ndim, dim, bytes, offset);
139
139
  return ca;
140
140
  }
@@ -143,351 +143,81 @@ static void
143
143
  free_ca_refer (void *ap)
144
144
  {
145
145
  CARefer *ca = (CARefer *) ap;
146
- if ( ca != NULL ) {
146
+ if (ca == NULL) return;
147
+ /* Free the byte-reinterpret intermediate mask, if any. */
148
+ ca_free(ca->mask0);
149
+ /* The rest mirrors free_ca_stride. */
150
+ ca_free(ca->mask);
151
+ if (ca->_pool) {
152
+ ca_array_free(ca);
153
+ } else {
154
+ xfree(ca->strides);
147
155
  xfree(ca->dim);
148
- ca_free(ca->mask);
149
- ca_free(ca->mask0);
150
156
  xfree(ca);
151
157
  }
152
158
  }
153
159
 
154
- /* ------------------------------------------------------------------- */
155
-
156
160
  static void *
157
161
  ca_refer_func_clone (void *ap)
158
162
  {
159
163
  CARefer *ca = (CARefer *) ap;
160
- return ca_refer_new(ca->parent,
161
- ca->data_type, ca->ndim, ca->dim, ca->bytes, ca->offset);
162
- }
163
-
164
- static char *
165
- ca_refer_func_ptr_at_addr (void *ap, ca_size_t addr)
166
- {
167
- CARefer *ca = (CARefer *) ap;
168
- ca_size_t minor;
169
- switch ( ca->is_deformed ) {
170
- case 0:
171
- case 1:
172
- return ca->ptr + ca->bytes * addr;
173
- case -2:
174
- minor = (addr * ca->bytes) % ca->parent->bytes;
175
- return ca->ptr + ca->bytes * addr + minor;
176
- case 2:
177
- return ca->ptr + ca->bytes * (addr * ca->ratio);
178
- default:
179
- rb_raise(rb_eRuntimeError, "[BUG]");
180
- }
181
- }
182
-
183
- static char *
184
- ca_refer_func_ptr_at_index (void *ap, ca_size_t *idx)
185
- {
186
- CARefer *ca = (CARefer*) ap;
187
- ca_size_t *dim = ca->dim;
188
- int8_t i;
189
- ca_size_t n;
190
- n = idx[0]; /* n = idx[0]*dim[1]*dim[2]*...*dim[ndim-1] */
191
- for (i=1; i<ca->ndim; i++) { /* + idx[1]*dim[1]*dim[2]*...*dim[ndim-1] */
192
- n = dim[i]*n+idx[i]; /* ... + idx[ndim-2]*dim[1] + idx[ndim-1] */
193
- }
194
- return ca->ptr + ca->bytes * n;
195
- }
196
-
197
- static void
198
- ca_refer_func_fetch_addr (void *ap, ca_size_t addr, void *ptr)
199
- {
200
- CARefer *ca = (CARefer *) ap;
201
- ca_size_t major, minor;
202
- switch ( ca->is_deformed ) {
203
- case 0:
204
- ca_fetch_addr(ca->parent, addr, ptr);
205
- case 1:
206
- ca_fetch_addr(ca->parent, addr + ca->offset, ptr);
207
- break;
208
- case -2: {
209
- major = (addr * ca->bytes) / ca->parent->bytes;
210
- minor = (addr * ca->bytes) % ca->parent->bytes;
211
- if ( ca->parent->bytes <= 256 ) {
212
- char val[256];
213
- ca_fetch_addr(ca->parent, major + ca->offset, val);
214
- memcpy(ptr, val+minor, ca->bytes);
215
- }
216
- else {
217
- char *val = malloc_with_check(ca->parent->bytes);
218
- ca_fetch_addr(ca->parent, major + ca->offset, val);
219
- memcpy(ptr, val+minor, ca->bytes);
220
- free(val);
221
- }
222
- break;
223
- }
224
- case 2: {
225
- int i;
226
- for (i=0; i<ca->ratio; i++) {
227
- ca_fetch_addr(ca->parent,
228
- addr * ca->ratio + i + ca->offset,
229
- (char *) ptr + i * ca->parent->bytes);
230
- }
231
- break;
232
- }
233
- }
234
- }
235
-
236
- static void
237
- ca_refer_func_fetch_index (void *ap, ca_size_t *idx, void *ptr)
238
- {
239
- CARefer *ca = (CARefer *) ap;
240
- if ( ca->is_deformed ) {
241
- ca_size_t *dim = ca->dim;
242
- int8_t i;
243
- ca_size_t n;
244
- n = idx[0];
245
- for (i=1; i<ca->ndim; i++) {
246
- n = dim[i]*n+idx[i];
247
- }
248
- ca_refer_func_fetch_addr(ca, n, ptr);
249
- }
250
- else {
251
- ca_fetch_index(ca->parent, idx, ptr);
252
- }
253
- }
254
-
255
- static void
256
- ca_refer_func_store_addr (void *ap, ca_size_t addr, void *ptr)
257
- {
258
- CARefer *ca = (CARefer *) ap;
259
- ca_size_t major, minor;
260
- switch ( ca->is_deformed ) {
261
- case 0:
262
- ca_store_addr(ca->parent, addr, ptr);
263
- break;
264
- case 1:
265
- ca_store_addr(ca->parent, addr + ca->offset, ptr);
266
- break;
267
- case -2: {
268
- major = (addr * ca->bytes) / ca->parent->bytes;
269
- minor = (addr * ca->bytes) % ca->parent->bytes;
270
- if ( ca->parent->bytes <= 256 ) {
271
- char val[256];
272
- ca_fetch_addr(ca->parent, major + ca->offset, val);
273
- memcpy(val+minor, ptr, ca->bytes);
274
- ca_store_addr(ca->parent, major + ca->offset, val);
275
- }
276
- else {
277
- char *val = malloc_with_check(ca->parent->bytes);
278
- ca_fetch_addr(ca->parent, major + ca->offset, val);
279
- memcpy(val+minor, ptr, ca->bytes);
280
- ca_store_addr(ca->parent, major + ca->offset, val);
281
- free(val);
282
- }
283
- break;
284
- }
285
- case 2: {
286
- int i;
287
- for (i=0; i<ca->ratio; i++) {
288
- ca_store_addr(ca->parent,
289
- addr * ca->ratio + i + ca->offset,
290
- (char *) ptr + i * ca->parent->bytes);
291
- }
292
- break;
293
- }
294
- }
295
- }
296
-
297
- static void
298
- ca_refer_func_store_index (void *ap, ca_size_t *idx, void *ptr)
299
- {
300
- CARefer *ca = (CARefer *) ap;
301
- if ( ca->is_deformed ) {
302
- ca_size_t *dim = ca->dim;
303
- int8_t i;
304
- ca_size_t n;
305
- n = idx[0];
306
- for (i=1; i<ca->ndim; i++) {
307
- n = dim[i]*n+idx[i];
308
- }
309
- ca_refer_func_store_addr(ca, n, ptr);
310
- }
311
- else {
312
- ca_store_index(ca->parent, idx, ptr);
313
- }
314
- }
315
-
316
- static void
317
- ca_refer_func_allocate (void *ap)
318
- {
319
- CARefer *ca = (CARefer *) ap;
320
- ca_allocate(ca->parent);
321
- ca->ptr = ca->parent->ptr + ca->parent->bytes * ca->offset;
322
- return;
323
- }
324
-
325
- static void
326
- ca_refer_func_attach (void *ap)
327
- {
328
- CARefer *ca = (CARefer *) ap;
329
- ca_attach(ca->parent);
330
- ca->ptr = ca->parent->ptr + ca->parent->bytes * ca->offset;
331
- return;
332
- }
333
-
334
- static void
335
- ca_refer_func_sync (void *ap)
336
- {
337
- CARefer *ca = (CARefer *) ap;
338
- ca_sync(ca->parent);
339
- return;
340
- }
341
-
342
- static void
343
- ca_refer_func_detach (void *ap)
344
- {
345
- CARefer *ca = (CARefer *) ap;
346
- ca->ptr = NULL;
347
- ca_detach(ca->parent);
348
- return;
349
- }
350
-
351
- static void
352
- ca_refer_func_copy_data (void *ap, void *ptr)
353
- {
354
- CARefer *ca = (CARefer *) ap;
355
- if ( ptr != ca->ptr ) {
356
- ca_attach(ca->parent);
357
- memmove(ptr,
358
- ca->parent->ptr + ca->parent->bytes * ca->offset,
359
- ca_length(ca));
360
- ca_detach(ca->parent);
361
- }
362
- }
363
-
364
- static void
365
- ca_refer_func_sync_data (void *ap, void *ptr)
366
- {
367
- CARefer *ca = (CARefer *) ap;
368
- if ( ptr != ca->ptr ) {
369
- ca_allocate(ca->parent);
370
- memmove(ca->parent->ptr + ca->parent->bytes * ca->offset,
371
- ptr,
372
- ca_length(ca));
373
- ca_sync(ca->parent);
374
- ca_detach(ca->parent);
375
- }
376
- }
377
-
378
- #define proc_fill_bang_fixlen() \
379
- { \
380
- ca_size_t i; \
381
- ca_size_t bytes = ca->bytes; \
382
- char *p = ca->parent->ptr + ca->parent->bytes * ca->offset; \
383
- for (i=ca->elements; i; i--, p+=bytes) { \
384
- memcpy(p, val, bytes); \
385
- } \
386
- }
387
-
388
- #define proc_fill_bang(type) \
389
- { \
390
- ca_size_t i; \
391
- type *p = (type *)(ca->parent->ptr + ca->parent->bytes * ca->offset); \
392
- type v = *(type *)val; \
393
- for (i=ca->elements; i; i--, p++) { \
394
- *p = v; \
395
- } \
396
- }
397
-
398
- static void
399
- ca_refer_func_fill_data (void *ap, void *val)
400
- {
401
- CARefer *ca = (CARefer *) ap;
402
-
403
- ca_allocate(ca->parent);
404
-
405
- switch ( ca->data_type ) {
406
- case CA_FIXLEN: proc_fill_bang_fixlen(); break;
407
- case CA_BOOLEAN:
408
- case CA_INT8:
409
- case CA_UINT8: proc_fill_bang(int8_t); break;
410
- case CA_INT16:
411
- case CA_UINT16: proc_fill_bang(int16_t); break;
412
- case CA_INT32:
413
- case CA_UINT32:
414
- case CA_FLOAT32: proc_fill_bang(int32_t); break;
415
- case CA_INT64:
416
- case CA_UINT64:
417
- case CA_FLOAT64: proc_fill_bang(float64_t); break;
418
- case CA_FLOAT128: proc_fill_bang(float128_t); break;
419
- #ifdef HAVE_COMPLEX_H
420
- case CA_CMPLX64: proc_fill_bang(cmplx64_t); break;
421
- case CA_CMPLX128: proc_fill_bang(cmplx128_t); break;
422
- case CA_CMPLX256: proc_fill_bang(cmplx256_t); break;
423
- #endif
424
- case CA_OBJECT: proc_fill_bang(VALUE); break;
425
- default: rb_bug("array has an unknown data type");
426
- }
427
- ca_sync(ca->parent);
428
- ca_detach(ca->parent);
164
+ return ca_refer_new(ca->parent, ca->data_type, ca->ndim, ca->dim,
165
+ ca->bytes, ca->base_offset / ca->parent->bytes);
429
166
  }
430
167
 
431
168
  static void
432
169
  ca_refer_func_create_mask (void *ap)
433
170
  {
434
171
  CARefer *ca = (CARefer *) ap;
172
+ ca_size_t parent_bytes = ca->parent->bytes;
173
+ ca_size_t parent_offset;
435
174
 
436
175
  ca_update_mask(ca->parent);
437
- if ( ! ca->parent->mask ) {
176
+ if (! ca->parent->mask) {
438
177
  ca_create_mask(ca->parent);
439
178
  }
440
179
 
441
- if ( ca->bytes == ca->parent->bytes ) {
180
+ parent_offset = ca->base_offset / parent_bytes;
181
+
182
+ if (ca->bytes == parent_bytes) {
183
+ /* Same-width reinterpret / reshape. Mask is a CARefer over
184
+ the parent's mask with the same logical shape and offset. */
442
185
  ca->mask =
443
186
  (CArray *) ca_refer_new(ca->parent->mask,
444
- CA_BOOLEAN, ca->ndim, ca->dim, 0, ca->offset);
445
- }
446
- else if ( ca->is_deformed == -2 ) {
187
+ CA_BOOLEAN, ca->ndim, ca->dim, 0, parent_offset);
188
+ }
189
+ else if (ca->bytes < parent_bytes) {
190
+ /* Divided reinterpret: one parent element splits into
191
+ ratio = parent_bytes / bytes view elements. Build a
192
+ CARepeat that broadcasts each parent mask bit across the
193
+ ratio sub-positions, then refer-reshape it to the view's
194
+ actual shape. */
195
+ ca_size_t ratio = parent_bytes / ca->bytes;
447
196
  ca_size_t count[CA_RANK_MAX];
448
- int i;
449
- for (i=0; i<ca->parent->ndim; i++) {
450
- count[i] = 0;
451
- }
452
- count[ca->parent->ndim] = ca->ratio;
453
- ca->mask0 =
454
- (CArray *) ca_repeat_new(ca->parent->mask, ca->parent->ndim+1, count);
197
+ int8_t i;
198
+ for (i = 0; i < ca->parent->ndim; i++) count[i] = 0;
199
+ count[ca->parent->ndim] = ratio;
200
+ ca->mask0 =
201
+ (CArray *) ca_repeat_new(ca->parent->mask, ca->parent->ndim + 1, count);
455
202
  ca_unset_flag(ca->mask0, CA_FLAG_READ_ONLY);
456
-
457
- ca->mask =
458
- (CArray *) ca_refer_new(ca->mask0,
459
- CA_BOOLEAN, ca->ndim, ca->dim, 0, ca->offset);
203
+ ca->mask =
204
+ (CArray *) ca_refer_new(ca->mask0,
205
+ CA_BOOLEAN, ca->ndim, ca->dim, 0, parent_offset);
460
206
  }
461
- else if ( ca->is_deformed == 2 ) {
462
- /* TODO */
463
- ca->mask0 =
464
- (CArray *) ca_reduce_new(ca->parent->mask, ca->ratio, ca->offset);
465
- ca->mask =
466
- (CArray *) ca_refer_new(ca->mask0, CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
207
+ else {
208
+ /* Spanned reinterpret: ratio = bytes / parent_bytes parent
209
+ elements fold into one view element. Build a CAReduce that
210
+ OR-reduces the ratio adjacent parent mask bits into one
211
+ mask bit, then refer-reshape to the view's shape. */
212
+ ca_size_t ratio = ca->bytes / parent_bytes;
213
+ ca->mask0 =
214
+ (CArray *) ca_reduce_new(ca->parent->mask, ratio, parent_offset);
215
+ ca->mask =
216
+ (CArray *) ca_refer_new(ca->mask0,
217
+ CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
467
218
  }
468
219
  }
469
220
 
470
- ca_operation_function_t ca_refer_func = {
471
- CA_OBJ_REFER,
472
- CA_VIRTUAL_ARRAY,
473
- free_ca_refer,
474
- ca_refer_func_clone,
475
- ca_refer_func_ptr_at_addr,
476
- ca_refer_func_ptr_at_index,
477
- ca_refer_func_fetch_addr,
478
- ca_refer_func_fetch_index,
479
- ca_refer_func_store_addr,
480
- ca_refer_func_store_index,
481
- ca_refer_func_allocate,
482
- ca_refer_func_attach,
483
- ca_refer_func_sync,
484
- ca_refer_func_detach,
485
- ca_refer_func_copy_data,
486
- ca_refer_func_sync_data,
487
- ca_refer_func_fill_data,
488
- ca_refer_func_create_mask,
489
- };
490
-
491
221
  /* ------------------------------------------------------------------- */
492
222
 
493
223
  static VALUE
@@ -501,31 +231,175 @@ static VALUE
501
231
  rb_ca_refer_initialize_copy (VALUE self, VALUE other)
502
232
  {
503
233
  CARefer *ca, *cs;
504
-
505
234
  TypedData_Get_Struct(self, CARefer, &carefer_data_type, ca);
506
235
  TypedData_Get_Struct(other, CARefer, &carefer_data_type, cs);
507
-
236
+ if ( ca_func[CA_OBJ_REFER].pool_init ) {
237
+ ca_array_pool_alloc(ca, CA_OBJ_REFER, cs->ndim);
238
+ }
239
+ /* CAREFUL: rebuild through ca_refer_setup's (data_type, ndim,
240
+ dim, bytes, offset) form. The CAStride (strides, base_offset)
241
+ form would lose the parent-element offset semantics on
242
+ unusual mod-bytes alignments. */
508
243
  ca_refer_setup(ca, cs->parent, cs->data_type, cs->ndim, cs->dim,
509
- cs->bytes, cs->offset);
510
-
244
+ cs->bytes, cs->base_offset / cs->parent->bytes);
511
245
  return self;
512
246
  }
513
247
 
514
- /* yard:
515
- class CArray
516
- # call-seq:
517
- # CArray.refer()
518
- # CArray.refer(data_type, dim[, :bytes=>bytes, :offset=>offset])
519
- # CArray.refer(data_class, dim)
520
- #
521
- # Returns CARefer object which refers self.
522
- # In second form, `data_type` can be different data_type of self,
523
- # as long as the total byte length of new array is smaller than
524
- # that of self.
525
- def refer (*argv)
526
- end
527
- end
528
- */
248
+ /* Reshape-stride rewrite.
249
+ *
250
+ * Try to express `parent` reshaped to `new_dim` as a CAStride over
251
+ * the deepest non-CAStride ancestor (returned in *out_root) with
252
+ * explicit strides + base_offset in that root's byte coord. Used
253
+ * by rb_ca_reshape and rb_ca_flatten before falling back to
254
+ * ca_refer_new.
255
+ *
256
+ * Pre-conditions (contract from the callers):
257
+ * - product of new_dim == parent->elements
258
+ * - bytes (== parent->bytes) and data_type (== parent->data_type)
259
+ * unchanged, offset == 0 implicit
260
+ *
261
+ * Returns 1 on success with *out_root, out_strides[0..new_ndim-1]
262
+ * and *out_base filled. The caller then constructs
263
+ * ca_stride_new(CA_OBJ_STRIDE, *out_root, ..., out_strides, *out_base);
264
+ * the CAStride's parent is *out_root (not the immediate caller
265
+ * parent), which lets compose-fold treat the whole reshape as a
266
+ * single-step gather from the entity.
267
+ *
268
+ * Returns 0 on failure: the caller must fall back to ca_refer_new.
269
+ *
270
+ * Algorithm:
271
+ * 1. Resolve parent into (root, root_strides, root_base) via
272
+ * ca_stride_compose_to_root for the CAStride family, or
273
+ * row-major derivation for a plain CArray entity. Other
274
+ * obj_types fail immediately.
275
+ * 2. Match ranges of parent axes to new axes so element products
276
+ * agree. Inside each matched range, root_strides must be
277
+ * inter-axis contiguous. */
278
+ static int
279
+ ca_reshape_try_strides (CArray *parent,
280
+ const ca_size_t *new_dim,
281
+ int8_t new_ndim,
282
+ CArray **out_root,
283
+ ca_size_t *out_strides,
284
+ ca_size_t *out_base)
285
+ {
286
+ ca_size_t pstrides_buf[CA_RANK_MAX];
287
+ ca_size_t pstrides_composed[CA_RANK_MAX];
288
+ const ca_size_t *pstrides;
289
+ ca_size_t pbase;
290
+ ca_size_t bytes = parent->bytes;
291
+ int8_t pndim = parent->ndim;
292
+ int8_t k;
293
+ CArray *root;
294
+
295
+ /* Resolve parent into (root, pstrides, pbase) in root's byte coord. */
296
+ if (ca_func[parent->obj_type].attach == ca_stride_func.attach) {
297
+ /* CAStride family: fold the parent's own view through its
298
+ ancestor chain, producing strides + base in the deepest
299
+ non-CAStride ancestor's coord. */
300
+ ca_stride_compose_to_root((CAStride *) parent,
301
+ &root, pstrides_composed, &pbase);
302
+ pstrides = pstrides_composed;
303
+ } else if (parent->obj_type == CA_OBJ_ARRAY
304
+ || parent->obj_type == CA_OBJ_ARRAY_WRAP
305
+ || parent->obj_type == CA_OBJ_SCALAR) {
306
+ /* Plain CArray entity: row-major contig, base 0. */
307
+ ca_size_t s = bytes;
308
+ for (k = pndim - 1; k >= 0; k--) {
309
+ pstrides_buf[k] = s;
310
+ s *= parent->dim[k];
311
+ }
312
+ pstrides = pstrides_buf;
313
+ pbase = 0;
314
+ root = parent;
315
+ (void) pstrides_composed;
316
+ } else {
317
+ /* CASelect / CAReduce / CAGrid / CAObject / CAField etc. — no usable
318
+ strides representation for reshape rewrite. */
319
+ return 0;
320
+ }
321
+
322
+ *out_root = root;
323
+
324
+ /* Zero-element corner case: nothing to gather; trivial reshape. */
325
+ if (parent->elements == 0) {
326
+ for (k = 0; k < new_ndim; k++) out_strides[k] = 0;
327
+ *out_base = pbase;
328
+ return 1;
329
+ }
330
+
331
+ /* Scalar reshape (new_ndim == 0) only valid if elements == 1 — but
332
+ CArray's reshape rejects argc==0 earlier; defensive return for safety. */
333
+ if (new_ndim == 0) {
334
+ *out_base = pbase;
335
+ return parent->elements == 1 ? 1 : 0;
336
+ }
337
+
338
+ /* Match ranges outer-to-inner. Skip dim==1 axes on either side
339
+ (they contribute no displacement; we'll assign stride 0 to dim==1
340
+ new axes after matching). */
341
+ int8_t oi = 0, ni = 0;
342
+
343
+ while (oi < pndim && ni < new_ndim) {
344
+ /* Skip leading dim==1 new axes (no parent axis consumed) */
345
+ if (new_dim[ni] == 1) {
346
+ out_strides[ni] = 0;
347
+ ni++;
348
+ continue;
349
+ }
350
+ /* Skip leading dim==1 parent axes (no contribution) */
351
+ if (parent->dim[oi] == 1) {
352
+ oi++;
353
+ continue;
354
+ }
355
+
356
+ int8_t oj = oi + 1;
357
+ int8_t nj = ni + 1;
358
+ ca_size_t old_prod = parent->dim[oi];
359
+ ca_size_t new_prod = new_dim[ni];
360
+
361
+ while (old_prod != new_prod) {
362
+ if (old_prod < new_prod) {
363
+ /* Need to extend old range; require inter-axis contig */
364
+ if (oj >= pndim) return 0;
365
+ if (parent->dim[oj] == 0) return 0; /* shouldn't happen */
366
+ if (pstrides[oj - 1] != pstrides[oj] * parent->dim[oj]) return 0;
367
+ old_prod *= parent->dim[oj];
368
+ oj++;
369
+ } else {
370
+ if (nj >= new_ndim) return 0;
371
+ if (new_dim[nj] == 0) return 0;
372
+ new_prod *= new_dim[nj];
373
+ nj++;
374
+ }
375
+ }
376
+
377
+ /* Range matched: assign strides to new axes [ni..nj).
378
+ Innermost gets parent's innermost stride in the matched old range.
379
+ Outer new axes scale by following new_dim. */
380
+ out_strides[nj - 1] = pstrides[oj - 1];
381
+ for (k = nj - 2; k >= ni; k--) {
382
+ out_strides[k] = out_strides[k + 1] * new_dim[k + 1];
383
+ }
384
+
385
+ oi = oj;
386
+ ni = nj;
387
+ }
388
+
389
+ /* Trailing dim==1 axes in either side */
390
+ while (ni < new_ndim) {
391
+ if (new_dim[ni] != 1) return 0;
392
+ out_strides[ni] = 0;
393
+ ni++;
394
+ }
395
+ while (oi < pndim) {
396
+ if (parent->dim[oi] != 1) return 0;
397
+ oi++;
398
+ }
399
+
400
+ *out_base = pbase;
401
+ return 1;
402
+ }
529
403
 
530
404
  static VALUE
531
405
  rb_ca_refer (int argc, VALUE *argv, VALUE self)
@@ -541,85 +415,66 @@ rb_ca_refer (int argc, VALUE *argv, VALUE self)
541
415
 
542
416
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
543
417
 
544
- if ( argc == 0 ) { /* CArray#refer() */
418
+ if (argc == 0) {
545
419
  data_type = ca->data_type;
546
420
  bytes = ca->bytes;
547
421
  ndim = ca->ndim;
548
- for (i=0; i<ndim; i++) {
549
- dim[i] = ca->dim[i];
550
- }
551
- cr = ca_refer_new((CArray*)ca, data_type, ndim, dim, bytes, offset);
422
+ for (i = 0; i < ndim; i++) dim[i] = ca->dim[i];
423
+ cr = ca_refer_new((CArray *) ca, data_type, ndim, dim, bytes, offset);
552
424
  obj = ca_wrap_struct(cr);
553
425
  rb_ca_set_parent(obj, self);
554
- rb_ca_data_type_inherit(obj, self);
555
426
  }
556
427
  else {
557
428
  volatile VALUE rtype, rdim, ropt, rbytes = Qnil, roffset = Qnil;
558
-
559
429
  ropt = rb_pop_options(&argc, &argv);
560
430
  rb_scan_args(argc, argv, "11", (VALUE *) &rtype, (VALUE *) &rdim);
561
431
  rb_scan_options(ropt, "bytes,offset", &rbytes, &roffset);
562
-
563
- if ( NIL_P(rbytes) ) {
564
- rbytes = rb_ca_bytes(self);
565
- }
566
-
432
+ if (NIL_P(rbytes)) rbytes = rb_ca_bytes(self);
567
433
  rb_ca_guess_type_and_bytes(rtype, rbytes, &data_type, &bytes);
568
-
569
- if ( NIL_P(rdim) ) {
570
- if ( ca->bytes != bytes ) {
571
- rb_raise(rb_eRuntimeError,
434
+ if (NIL_P(rdim)) {
435
+ if (ca->bytes != bytes) {
436
+ rb_raise(rb_eRuntimeError,
572
437
  "specify dimension shape for different byte size");
573
- }
574
- else {
438
+ } else {
575
439
  rdim = rb_ca_dim(self);
576
440
  }
577
441
  }
578
-
579
442
  Check_Type(rdim, T_ARRAY);
580
443
  ndim = RARRAY_LEN(rdim);
581
-
582
- for (i=0; i<ndim; i++) {
583
- dim[i] = NUM2SIZE(rb_ary_entry(rdim, i));
584
- }
585
-
586
- if ( ! NIL_P(roffset) ) {
587
- offset = NUM2SIZE(roffset);
588
- }
589
-
590
- cr = ca_refer_new((CArray*)ca, data_type, ndim, dim, bytes, offset);
444
+ for (i = 0; i < ndim; i++) dim[i] = NUM2SIZE(rb_ary_entry(rdim, i));
445
+ if (! NIL_P(roffset)) offset = NUM2SIZE(roffset);
446
+ cr = ca_refer_new((CArray *) ca, data_type, ndim, dim, bytes, offset);
591
447
  obj = ca_wrap_struct(cr);
592
448
  rb_ca_set_parent(obj, self);
593
- rb_ca_data_type_import(obj, rtype);
449
+ /* When rtype is a data_class, wrap the result in CARecord so
450
+ the data_class is carried even if self is not itself a Face. */
451
+ if ( rb_obj_is_data_class(rtype) ) {
452
+ obj = rb_funcall(rb_const_get(rb_cObject, rb_intern("CARecord")),
453
+ rb_intern("wrap"), 2, obj, rtype);
454
+ return obj;
455
+ }
594
456
  }
595
-
457
+ CA_FACE_LIFT_IF_FACE(obj, self, ca);
596
458
  return obj;
597
459
  }
598
460
 
599
- /* api: rb_ca_refer_new
600
- */
601
-
602
461
  VALUE
603
462
  rb_ca_refer_new (VALUE self,
604
463
  int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
605
464
  ca_size_t offset)
606
465
  {
607
466
  volatile VALUE list, rdim, ropt;
608
- CArray *ca;
609
467
  int8_t i;
610
468
 
611
- TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
612
-
613
469
  rdim = rb_ary_new2(ndim);
614
- for (i=0; i<ndim; i++) {
470
+ for (i = 0; i < ndim; i++) {
615
471
  rb_ary_store(rdim, i, SIZE2NUM(dim[i]));
616
472
  }
617
473
 
618
474
  list = rb_ary_new2(3);
619
- if ( data_type == CA_FIXLEN && rb_ca_has_data_class(self) ) {
475
+ if (data_type == CA_FIXLEN && rb_ca_has_data_class(self)) {
620
476
  rb_ary_store(list, 0, rb_ca_data_class(self));
621
- }
622
- else {
477
+ } else {
623
478
  rb_ary_store(list, 0, INT2NUM(data_type));
624
479
  }
625
480
  rb_ary_store(list, 1, rdim);
@@ -627,21 +482,276 @@ rb_ca_refer_new (VALUE self,
627
482
  rb_set_options(ropt, "bytes,offset", SIZE2NUM(bytes), SIZE2NUM(offset));
628
483
  rb_ary_store(list, 2, ropt);
629
484
 
630
- return rb_ca_refer(3, RARRAY_PTR(list), self);
485
+ return rb_ca_refer(3, (VALUE *) RARRAY_CONST_PTR(list), self);
631
486
  }
632
487
 
488
+ /* CArray#reshape(*newdim) — returns a view of self with the new
489
+ shape (a CAStride when ca_reshape_try_strides succeeds, otherwise
490
+ a CARefer). Each element of `newdim` is either:
491
+ - Integer : the new size for that axis
492
+ - nil : copy from the source. Axes left of the auto-infer
493
+ placeholder use ca->dim[i] in position order; axes
494
+ to its right use ca->dim[ca->ndim - (argc - i)] so
495
+ trailing nils mirror trailing source axes.
496
+ - -1 / `:~` : one axis inferred from elements / (product of the
497
+ others). At most one placeholder is allowed.
498
+
499
+ Also exported (declared in carray.h) so downstream C extensions
500
+ can build a reshape view directly:
501
+
502
+ VALUE args[] = {INT2NUM(3), INT2NUM(2)};
503
+ VALUE view = rb_ca_reshape(2, args, ca);
504
+
505
+ For typed-dim usage (bypassing the placeholder vocabulary) call
506
+ rb_ca_refer_new(self, ca->data_type, ndim, dim, ca->bytes, 0). */
507
+ VALUE
508
+ rb_ca_reshape (int argc, VALUE *argv, VALUE self)
509
+ {
510
+ CArray *ca;
511
+ CARefer *cr;
512
+ ca_size_t new_dim[CA_RANK_MAX];
513
+ ca_size_t prod = 1;
514
+ int placeholder_idx = -1; /* axis with `-1` or `:~` infer placeholder */
515
+ int i;
516
+ volatile VALUE obj;
517
+ VALUE sym_tilde = ID2SYM(rb_intern("~")); /* :~ = infer-placeholder alias for -1 */
633
518
 
634
- void
635
- Init_ca_obj_refer ()
519
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
520
+
521
+ if (argc < 0 || argc > CA_RANK_MAX) {
522
+ rb_raise(rb_eArgError, "reshape: invalid number of dims (%d)", argc);
523
+ }
524
+
525
+ /* Locate the (at most one) auto-infer placeholder. `-1` is the
526
+ conventional spelling; `:~` is the unified auto-fill sigil
527
+ (same meaning). */
528
+ for (i = 0; i < argc; i++) {
529
+ if ( (FIXNUM_P(argv[i]) && FIX2LONG(argv[i]) == -1)
530
+ || argv[i] == sym_tilde ) {
531
+ if (placeholder_idx >= 0) {
532
+ rb_raise(rb_eRuntimeError,
533
+ "reshape: only one auto-infer placeholder (-1 / :~) allowed");
534
+ }
535
+ placeholder_idx = i;
536
+ }
537
+ }
538
+
539
+ /* Resolve every non-placeholder axis. */
540
+ for (i = 0; i < argc; i++) {
541
+ if (i == placeholder_idx) continue;
542
+ if (NIL_P(argv[i])) {
543
+ /* Two-sweep nil resolution:
544
+ - With a placeholder: forward-map before it, mirror from
545
+ the end after.
546
+ - Without a placeholder: forward-map while in range,
547
+ otherwise mirror from the end so trailing nils pick up
548
+ the tail source axes (e.g. b.ndim=1, b.reshape(1, nil)
549
+ -> (1, 3)). */
550
+ int src;
551
+ if (placeholder_idx >= 0) {
552
+ src = (i < placeholder_idx) ? i : ca->ndim - (argc - i);
553
+ } else {
554
+ src = (i < ca->ndim) ? i : ca->ndim - (argc - i);
555
+ }
556
+ if (src < 0 || src >= ca->ndim) {
557
+ rb_raise(rb_eRuntimeError,
558
+ "reshape: nil at axis %d has no source dim", i);
559
+ }
560
+ new_dim[i] = ca->dim[src];
561
+ }
562
+ else {
563
+ new_dim[i] = NUM2SIZE(argv[i]);
564
+ }
565
+ prod *= new_dim[i];
566
+ }
567
+
568
+ /* Resolve placeholder dim from the leftover total. */
569
+ if (placeholder_idx >= 0) {
570
+ if (prod == 0 || ca->elements % prod != 0) {
571
+ rb_raise(rb_eRuntimeError,
572
+ "reshape: cannot infer dim for `-1` placeholder");
573
+ }
574
+ new_dim[placeholder_idx] = ca->elements / prod;
575
+ }
576
+ else {
577
+ /* CAREFUL: strict element conservation. Without a placeholder
578
+ the resolved product must equal the source element count.
579
+ A smaller shape would silently truncate data (a CARefer over
580
+ a subset), and on non-contiguous parents the compose-fold
581
+ path corrupts data outright — hence the raise. */
582
+ if (prod != ca->elements) {
583
+ rb_raise(rb_eRuntimeError,
584
+ "reshape: cannot reshape array of %lld elements into a shape "
585
+ "of %lld elements (use -1 / :~ to infer a dim)",
586
+ (long long) ca->elements, (long long) prod);
587
+ }
588
+ }
589
+
590
+ /* Try the stride rewrite first. On success, construct a
591
+ CAStride directly over the deepest non-CAStride ancestor
592
+ (out_root) with composed strides + base in that root's byte
593
+ coord. The Ruby-level parent ref is still `self`, so the
594
+ immediate parent stays alive through GC. On failure, fall
595
+ through to the CARefer path. */
596
+ {
597
+ CArray *out_root;
598
+ ca_size_t out_strides[CA_RANK_MAX];
599
+ ca_size_t out_base;
600
+ if (ca_reshape_try_strides(ca, new_dim, (int8_t) argc,
601
+ &out_root, out_strides, &out_base)) {
602
+ CAStride *cs = ca_stride_new(CA_OBJ_STRIDE, out_root,
603
+ ca->data_type, ca->bytes,
604
+ (int8_t) argc, new_dim,
605
+ out_strides, out_base);
606
+ obj = ca_wrap_struct(cs);
607
+ rb_ca_set_parent(obj, self);
608
+ CA_FACE_LIFT_IF_FACE(obj, self, ca);
609
+ return obj;
610
+ }
611
+ }
612
+
613
+ cr = ca_refer_new(ca, ca->data_type, (int8_t) argc,
614
+ new_dim, ca->bytes, 0);
615
+ obj = ca_wrap_struct(cr);
616
+ rb_ca_set_parent(obj, self);
617
+ CA_FACE_LIFT_IF_FACE(obj, self, ca);
618
+ return obj;
619
+ }
620
+
621
+ /* CArray#flatten — a 1-D view of all elements in row-major order
622
+ (a CAStride when ca_reshape_try_strides succeeds, otherwise a
623
+ CARefer). Also exported (declared in carray.h). */
624
+ VALUE
625
+ rb_ca_flatten (VALUE self)
636
626
  {
637
- /* rb_cCARefer, CA_OBJ_REFER are defined in ruby_carray.c */
627
+ CArray *ca;
628
+ CARefer *cr;
629
+ ca_size_t dim[1];
630
+ volatile VALUE obj;
638
631
 
639
- rb_define_const(rb_cObject, "CA_OBJ_REFER", INT2NUM(CA_OBJ_REFER));
632
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
633
+ dim[0] = ca->elements;
634
+
635
+ {
636
+ CArray *out_root;
637
+ ca_size_t out_strides[1];
638
+ ca_size_t out_base;
639
+ if (ca_reshape_try_strides(ca, dim, 1, &out_root, out_strides, &out_base)) {
640
+ CAStride *cs = ca_stride_new(CA_OBJ_STRIDE, out_root,
641
+ ca->data_type, ca->bytes,
642
+ 1, dim, out_strides, out_base);
643
+ obj = ca_wrap_struct(cs);
644
+ rb_ca_set_parent(obj, self);
645
+ CA_FACE_LIFT_IF_FACE(obj, self, ca);
646
+ return obj;
647
+ }
648
+ }
640
649
 
641
- rb_define_method(rb_cCArray, "refer", rb_ca_refer, -1);
650
+ cr = ca_refer_new(ca, ca->data_type, 1, dim, ca->bytes, 0);
651
+ obj = ca_wrap_struct(cr);
652
+ rb_ca_set_parent(obj, self);
653
+ CA_FACE_LIFT_IF_FACE(obj, self, ca);
654
+ return obj;
655
+ }
642
656
 
657
+ /* The bare size-1 insertion primitive, in the SOURCE frame: each position
658
+ names the existing axis the new axis goes *before* (ndim = append at the
659
+ end; negatives count from the end gap). A position given more than once
660
+ stacks several length-1 axes before that source axis. Positions do not
661
+ shift as other axes are inserted.
662
+
663
+ a = CArray.int32(2, 3) # shape [2, 3]
664
+ insert before axis 0 -> [1, 2, 3]
665
+ insert before axis 2 (= -1, end) -> [2, 3, 1]
666
+ before axis 0 and the end -> [1, 2, 3, 1]
667
+ before axis 0 twice -> [1, 1, 2, 3]
668
+
669
+ Returns a CARefer view (zero-copy alias to +self+'s data, via reshape).
670
+ Bound to the internal name __insert_axis_size1__; the user-facing
671
+ insert_axis (with the repeat: keyword) is the Ruby method in
672
+ lib/carray/basics.rb, which builds on this primitive.
673
+
674
+ Non-static so external CIFY consumers (= carray_order.c,
675
+ carray_median_percentile.c) can call directly; they pass a single axis,
676
+ for which the source and output frames coincide. */
677
+ VALUE
678
+ rb_ca_insert_axis (int argc, VALUE *argv, VALUE self)
679
+ {
680
+ CArray *ca;
681
+ VALUE new_argv[CA_RANK_MAX];
682
+ int gap_count[CA_RANK_MAX + 1];
683
+ int ndim, new_ndim, ngap;
684
+ int i, c, k;
685
+
686
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
687
+
688
+ ndim = (int) ca->ndim;
689
+ new_ndim = ndim + argc;
690
+ if (new_ndim > CA_RANK_MAX) {
691
+ rb_raise(rb_eArgError,
692
+ "insert_axis: resulting ndim %d exceeds CA_RANK_MAX %d",
693
+ new_ndim, CA_RANK_MAX);
694
+ }
695
+
696
+ ngap = ndim + 1; /* gaps live in [0, ndim] (ndim = the end gap) */
697
+
698
+ /* Tally how many new axes go before each source axis (gap). Negative
699
+ positions count from the end gap; duplicates are allowed (stacking). */
700
+ for (i = 0; i <= ndim; i++) {
701
+ gap_count[i] = 0;
702
+ }
703
+ for (i = 0; i < argc; i++) {
704
+ int raw = NUM2INT(argv[i]);
705
+ int g = (raw < 0) ? raw + ngap : raw;
706
+ if (g < 0 || g >= ngap) {
707
+ rb_raise(rb_eArgError,
708
+ "insert_axis: axis %d out of range for ndim %d", raw, ndim);
709
+ }
710
+ gap_count[g]++;
711
+ }
712
+
713
+ /* Build the output dim list: before each source axis emit its tally of
714
+ length-1 axes, then the source dim; finally the end-gap tally. */
715
+ k = 0;
716
+ for (i = 0; i < ndim; i++) {
717
+ for (c = 0; c < gap_count[i]; c++) {
718
+ new_argv[k++] = INT2NUM(1);
719
+ }
720
+ new_argv[k++] = SIZE2NUM(ca->dim[i]);
721
+ }
722
+ for (c = 0; c < gap_count[ndim]; c++) {
723
+ new_argv[k++] = INT2NUM(1);
724
+ }
725
+
726
+ return rb_ca_reshape(new_ndim, new_argv, self);
727
+ }
728
+
729
+ void
730
+ Init_ca_obj_refer (void)
731
+ {
732
+ /* rb_cCARefer, CA_OBJ_REFER are defined in ruby_carray.c /
733
+ carray_core.c. Build the custom op table and override the
734
+ baseline registration installed by Init_carray_core. */
735
+ ca_refer_func = ca_stride_func;
736
+ ca_refer_func.free_object = free_ca_refer;
737
+ ca_refer_func.clone = ca_refer_func_clone;
738
+ ca_refer_func.create_mask = ca_refer_func_create_mask;
739
+ /* CARefer's struct is larger than CAStride (adds mask0); inherit
740
+ CAStride's pool_bytes / pool_init (dim + strides) but override
741
+ struct_size so ca_array_alloc reserves the right amount. */
742
+ ca_refer_func.struct_size = sizeof(CARefer);
743
+ ca_func[CA_OBJ_REFER] = ca_refer_func;
744
+
745
+ rb_define_const(rb_cObject, "CA_OBJ_REFER", INT2NUM(CA_OBJ_REFER));
746
+
747
+ rb_define_method(rb_cCArray, "refer", rb_ca_refer, -1);
748
+ rb_define_method(rb_cCArray, "reshape", rb_ca_reshape, -1);
749
+ rb_define_method(rb_cCArray, "flatten", rb_ca_flatten, 0);
750
+ /* The bare size-1 primitive. The user-facing `insert_axis` (with its
751
+ `repeat:` keyword) is the Ruby method in lib/carray/basics.rb, which
752
+ owns the name and calls this primitive. */
753
+ rb_define_method(rb_cCArray, "__insert_axis_size1__", rb_ca_insert_axis, -1);
643
754
  rb_define_alloc_func(rb_cCARefer, rb_ca_refer_s_allocate);
644
755
  rb_define_method(rb_cCARefer, "initialize_copy",
645
- rb_ca_refer_initialize_copy, 1);
756
+ rb_ca_refer_initialize_copy, 1);
646
757
  }
647
-