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,468 @@
1
+ /* ---------------------------------------------------------------------------
2
+
3
+ CARecord — composite Face for CAStruct-backed arrays. Face wrap for
4
+ arrays whose element type is a CAStruct subclass; data_class is
5
+ attached only to CARecord (not to bare CArray).
6
+
7
+ Storage layout matches the CAStruct backing (CA_FIXLEN bytes blob,
8
+ unchanged). Storage ops thin-forward to the parent via `ca_face_*`;
9
+ the tail holds `VALUE data_class`, pinned by a custom dmark.
10
+
11
+ Also housed here: data_class identity predicates
12
+ (`rb_obj_is_data_class` / `ca_check_data_class` /
13
+ `CArray.data_class?`) since data_class is a CARecord concern.
14
+
15
+ Sibling pattern references (VALUE tail + custom dmark):
16
+ ca_obj_time.c numeric Face
17
+ ca_obj_byte_swap.c endian Face
18
+
19
+ ---------------------------------------------------------------------------- */
20
+
21
+ #include "carray.h"
22
+ #include "ca_obj_face.h"
23
+
24
+ typedef struct {
25
+ /* === CAView prefix === */
26
+ int16_t obj_type;
27
+ int8_t data_type; /* fixed to CA_FIXLEN */
28
+ int8_t ndim;
29
+ int32_t flags; /* CA_FLAG_IS_FACE set */
30
+ ca_size_t bytes; /* = data_class::DATA_SIZE */
31
+ ca_size_t elements;
32
+ ca_size_t *dim;
33
+ char *ptr;
34
+ CArray *mask;
35
+ char *_pool; /* framework-managed pool buffer (NULL = legacy ALLOC_N path). */
36
+ CArray *parent;
37
+ uint32_t attach;
38
+ uint8_t nosync;
39
+ /* === Face tail === */
40
+ VALUE data_class; /* CAStruct subclass (marked by custom dmark) */
41
+ } CARecord;
42
+
43
+ static size_t
44
+ ca_record_dsize (const void *ap)
45
+ {
46
+ const CARecord *ca = (const CARecord *) ap;
47
+ return sizeof(CARecord) + ca->ndim * sizeof(ca_size_t);
48
+ }
49
+
50
+ /* Pool framework hooks: single ndim-sized tail (dim) in the _pool
51
+ buffer, uniform with the rest of the pool-migrated views. */
52
+ static size_t
53
+ ca_record_pool_bytes (int8_t ndim)
54
+ {
55
+ ca_size_t n = (ndim > 0) ? ndim : 1;
56
+ return (size_t) n * sizeof(ca_size_t);
57
+ }
58
+
59
+ static void
60
+ ca_record_pool_init (void *ap, int8_t ndim)
61
+ {
62
+ CARecord *ca = (CARecord *) ap;
63
+ ca->dim = (ca_size_t *) ca->_pool;
64
+ }
65
+
66
+ /* Custom dmark: ca_mark handles the standard prefix; the data_class
67
+ tail VALUE must be marked explicitly (CAFace itself carries none). */
68
+ static void
69
+ ca_record_mark (void *ap)
70
+ {
71
+ CARecord *ca = (CARecord *) ap;
72
+ ca_mark(ca);
73
+ rb_gc_mark(ca->data_class);
74
+ }
75
+
76
+ const rb_data_type_t carecord_data_type = {
77
+ .parent = &caface_data_type,
78
+ .wrap_struct_name = "CARecord",
79
+ .function = {
80
+ .dmark = ca_record_mark,
81
+ .dfree = ca_free,
82
+ .dsize = ca_record_dsize,
83
+ .dcompact = NULL
84
+ },
85
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
86
+ };
87
+
88
+ int8_t CA_OBJ_RECORD; /* non-static: read by rb_ca_data_class in carray_attribute.c */
89
+ VALUE rb_cCARecord; /* non-static: exported for cross-file use */
90
+
91
+ /* ------------------------------------------------------------------- */
92
+
93
+ int
94
+ ca_record_setup (CARecord *ca, CArray *parent, VALUE data_class)
95
+ {
96
+ if ( parent->data_type != CA_FIXLEN ) {
97
+ rb_raise(rb_eTypeError,
98
+ "CARecord requires a CA_FIXLEN parent (got data_type=%d)",
99
+ parent->data_type);
100
+ }
101
+
102
+ ca->obj_type = CA_OBJ_RECORD;
103
+ ca->data_type = CA_FIXLEN;
104
+ ca->flags = CA_FLAG_IS_FACE;
105
+ ca->ndim = parent->ndim;
106
+ ca->bytes = parent->bytes;
107
+ ca->elements = parent->elements;
108
+ ca->ptr = NULL;
109
+ ca->mask = NULL;
110
+ if ( ! ca->_pool ) {
111
+ ca->dim = ALLOC_N(ca_size_t, parent->ndim);
112
+ }
113
+ memcpy(ca->dim, parent->dim, sizeof(ca_size_t) * parent->ndim);
114
+
115
+ ca->parent = parent;
116
+ ca->attach = 0;
117
+ ca->nosync = 0;
118
+
119
+ ca->data_class = data_class;
120
+
121
+ if ( ca_has_mask(parent) ) {
122
+ ca_create_mask((CArray *) ca);
123
+ }
124
+
125
+ if ( ca_is_scalar(parent) ) {
126
+ ca_set_flag(ca, CA_FLAG_SCALAR);
127
+ }
128
+
129
+ if ( ca_test_flag(parent, CA_FLAG_READ_ONLY) ) {
130
+ ca_set_flag(ca, CA_FLAG_READ_ONLY);
131
+ }
132
+
133
+ return 0;
134
+ }
135
+
136
+ CARecord *
137
+ ca_record_new (CArray *parent, VALUE data_class)
138
+ {
139
+ CARecord *ca = (CARecord *) ca_array_alloc(CA_OBJ_RECORD, parent->ndim);
140
+ ca_record_setup(ca, parent, data_class);
141
+ return ca;
142
+ }
143
+
144
+ static void
145
+ free_ca_record (void *ap)
146
+ {
147
+ CARecord *ca = (CARecord *) ap;
148
+ if ( ca != NULL ) {
149
+ ca_free(ca->mask);
150
+ if ( ca->_pool ) {
151
+ ca_array_free(ca); /* dim lives in _pool */
152
+ }
153
+ else {
154
+ xfree(ca->dim);
155
+ xfree(ca);
156
+ }
157
+ }
158
+ }
159
+
160
+ /* ------------------------------------------------------------------- */
161
+
162
+ static void *
163
+ ca_record_func_clone (void *ap)
164
+ {
165
+ CARecord *ca = (CARecord *) ap;
166
+ return ca_record_new(ca->parent, ca->data_class);
167
+ }
168
+
169
+ static void
170
+ ca_record_func_allocate (void *ap)
171
+ {
172
+ CARecord *ca = (CARecord *) ap;
173
+ /* alias: parent attach + alias parent->ptr (Face has identical data layout) */
174
+ ca_attach(ca->parent);
175
+ ca->ptr = ca->parent->ptr;
176
+ }
177
+
178
+ static void
179
+ ca_record_func_create_mask (void *ap)
180
+ {
181
+ CARecord *ca = (CARecord *) ap;
182
+ ca_update_mask(ca->parent);
183
+ if ( ! ca->parent->mask ) {
184
+ ca_create_mask(ca->parent);
185
+ }
186
+ ca->mask = (CArray *) ca_refer_new(ca->parent->mask,
187
+ CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
188
+ }
189
+
190
+ ca_operation_function_t ca_record_func = {
191
+ -1, /* CA_OBJ_RECORD — filled by ca_install_obj_type */
192
+ CA_VIEW_ARRAY,
193
+ free_ca_record,
194
+ ca_record_func_clone,
195
+ ca_record_func_allocate,
196
+ ca_face_attach,
197
+ ca_face_sync,
198
+ ca_face_detach,
199
+ ca_face_fill_data,
200
+ ca_record_func_create_mask,
201
+ ca_face_xfer_index,
202
+ ca_face_xfer_addrs,
203
+ NULL, /* fold_stride: identity Face is not foldable */
204
+ ca_face_xfer_stride,
205
+ ca_face_xfer_all
206
+ };
207
+
208
+ /* ------------------------------------------------------------------- */
209
+
210
+ /* Internal C builder — shared by .new (self-allocated parent) and
211
+ .wrap (user-supplied parent) paths. Pins parent_val via
212
+ rb_ca_set_parent for GC + lifecycle protection, and preallocates
213
+ the `member` ivar Hash used by rb_ca_face_field as a field-view
214
+ memoisation cache. */
215
+ static VALUE
216
+ ca_record_build (VALUE klass, VALUE data_class, VALUE parent_val)
217
+ {
218
+ CArray *parent_ca;
219
+ CARecord *ca;
220
+ VALUE obj;
221
+
222
+ if ( ! RTEST(rb_obj_is_data_class(data_class)) ) {
223
+ rb_raise(rb_eTypeError, "data_class must be a CAStruct subclass");
224
+ }
225
+ TypedData_Get_Struct(parent_val, CArray, &carray_data_type, parent_ca);
226
+ if ( parent_ca->data_type != CA_FIXLEN ) {
227
+ rb_raise(rb_eTypeError,
228
+ "CARecord requires a CA_FIXLEN parent (got data_type=%d)",
229
+ parent_ca->data_type);
230
+ }
231
+ ca = ca_record_new(parent_ca, data_class);
232
+ obj = TypedData_Wrap_Struct(klass, &carecord_data_type, ca);
233
+ rb_ca_set_parent(obj, parent_val);
234
+ rb_ivar_set(obj, rb_intern("member"), rb_hash_new());
235
+ return obj;
236
+ }
237
+
238
+ /* CARecord.new(data_class, *shape) or Sub.new(*shape) — atomic path:
239
+ allocate a fresh CA_FIXLEN entity and wrap it. Base class takes
240
+ `data_class` explicitly; a subclass that pinned its type via the
241
+ `data_class GeoCoord` DSL accepts only shape args. */
242
+ static VALUE
243
+ rb_ca_record_s_new (int argc, VALUE *argv, VALUE klass)
244
+ {
245
+ VALUE data_class, klass_dc, parent_val;
246
+ ca_size_t bytes;
247
+ ca_size_t dim[CA_RANK_MAX];
248
+ int ndim, shape_offset, i;
249
+
250
+ klass_dc = rb_iv_get(klass, "@data_class");
251
+ if ( ! NIL_P(klass_dc) ) {
252
+ /* subclass with DSL fix: shape args only */
253
+ data_class = klass_dc;
254
+ shape_offset = 0;
255
+ if ( argc > 0 && RTEST(rb_obj_is_data_class(argv[0])) ) {
256
+ rb_raise(rb_eArgError,
257
+ "subclass has fixed data_class via DSL; don't pass it again");
258
+ }
259
+ }
260
+ else {
261
+ /* base direct: first arg = data_class */
262
+ if ( argc < 1 ) {
263
+ rb_raise(rb_eArgError, "data_class required as first argument");
264
+ }
265
+ data_class = argv[0];
266
+ shape_offset = 1;
267
+ }
268
+ ndim = argc - shape_offset;
269
+ if ( ndim < 0 || ndim > CA_RANK_MAX ) {
270
+ rb_raise(rb_eArgError, "invalid number of shape arguments (%d)", ndim);
271
+ }
272
+ for ( i = 0; i < ndim; i++ ) {
273
+ dim[i] = NUM2SIZE(argv[shape_offset + i]);
274
+ }
275
+
276
+ if ( ! RTEST(rb_obj_is_data_class(data_class)) ) {
277
+ rb_raise(rb_eTypeError, "data_class must be a CAStruct subclass");
278
+ }
279
+ bytes = NUM2SIZE(rb_const_get(data_class, rb_intern("DATA_SIZE")));
280
+
281
+ parent_val = rb_carray_new(CA_FIXLEN, ndim, dim, bytes, NULL);
282
+ return ca_record_build(klass, data_class, parent_val);
283
+ }
284
+
285
+ /* CARecord.wrap(entity, data_class) or Sub.wrap(entity) — zero-copy
286
+ Face wrap of an existing CA_FIXLEN entity. Sibling of
287
+ CATime.wrap. */
288
+ static VALUE
289
+ rb_ca_record_s_wrap (int argc, VALUE *argv, VALUE klass)
290
+ {
291
+ VALUE entity_val, data_class, klass_dc;
292
+
293
+ klass_dc = rb_iv_get(klass, "@data_class");
294
+ if ( ! NIL_P(klass_dc) ) {
295
+ rb_scan_args(argc, argv, "1", &entity_val);
296
+ data_class = klass_dc;
297
+ }
298
+ else {
299
+ rb_scan_args(argc, argv, "2", &entity_val, &data_class);
300
+ }
301
+ rb_check_carray_object(entity_val);
302
+ return ca_record_build(klass, data_class, entity_val);
303
+ }
304
+
305
+ /* Direct C accessor for the CARecord tail data_class. Called by
306
+ rb_ca_data_class in carray_attribute.c, dispatched on obj_type so
307
+ there is no Ruby roundtrip. */
308
+ VALUE
309
+ rb_ca_record_get_data_class (CArray *ca)
310
+ {
311
+ return ((CARecord *) ca)->data_class;
312
+ }
313
+
314
+ /* Subclass DSL: `data_class Foo` inside `class Sub < CARecord`.
315
+ Set once and then immutable (reassignment raises). A zero-arg call
316
+ acts as a getter. The class ivar is what `.new` / `.wrap` read via
317
+ `rb_iv_get(klass, "@data_class")` to omit the explicit arg. */
318
+ static VALUE
319
+ rb_ca_record_s_data_class_dsl (int argc, VALUE *argv, VALUE klass)
320
+ {
321
+ VALUE current, given;
322
+
323
+ current = rb_iv_get(klass, "@data_class");
324
+ if ( argc == 0 ) {
325
+ return NIL_P(current) ? Qnil : current;
326
+ }
327
+ rb_scan_args(argc, argv, "1", &given);
328
+ if ( ! NIL_P(current) ) {
329
+ rb_raise(rb_eRuntimeError,
330
+ "data_class already fixed to %"PRIsVALUE
331
+ "; CARecord subclass data_class is immutable once set",
332
+ current);
333
+ }
334
+ if ( ! RTEST(rb_obj_is_data_class(given)) ) {
335
+ rb_raise(rb_eTypeError, "data_class must be a CAStruct subclass");
336
+ }
337
+ rb_iv_set(klass, "@data_class", given);
338
+ return given;
339
+ }
340
+
341
+ static VALUE
342
+ rb_ca_record_s_allocate (VALUE klass)
343
+ {
344
+ CARecord *ca;
345
+ return TypedData_Make_Struct(klass, CARecord, &carecord_data_type, ca);
346
+ }
347
+
348
+ static VALUE
349
+ rb_ca_record_initialize_copy (VALUE self, VALUE other)
350
+ {
351
+ CARecord *ca, *cs;
352
+ TypedData_Get_Struct(self, CARecord, &carecord_data_type, ca);
353
+ TypedData_Get_Struct(other, CARecord, &carecord_data_type, cs);
354
+ if ( ca_func[CA_OBJ_RECORD].pool_init ) {
355
+ ca_array_pool_alloc(ca, CA_OBJ_RECORD, cs->parent->ndim);
356
+ }
357
+ ca_record_setup(ca, cs->parent, cs->data_class);
358
+ return self;
359
+ }
360
+
361
+ /* ---------------------------------------------------------------------------
362
+ data_class identity predicates. A Ruby class that can serve as the
363
+ element type of a CARecord (i.e. the inner struct definition such as
364
+ GeoCoord / Pixel, not the CARecord subclass CAGeoCoord) must provide
365
+ the constants + methods checked below. `CArray.struct {...}` /
366
+ `CArray.union {...}` generate them automatically.
367
+
368
+ rb_obj_is_data_class(klass) duck-type predicate, Qtrue/Qfalse
369
+ ca_check_data_class(klass) same, raises on failure
370
+ CArray.data_class?(klass) Ruby surface for the predicate
371
+
372
+ Signatures stay in carray.h for cross-file extern use.
373
+ ------------------------------------------------------------------------- */
374
+
375
+ VALUE
376
+ rb_obj_is_data_class (VALUE rtype)
377
+ {
378
+ VALUE has_data_size, has_member_names, has_member_table;
379
+ VALUE has_encode, has_decode;
380
+ if ( TYPE(rtype) == T_CLASS ) {
381
+ has_data_size =
382
+ rb_funcall(rtype, rb_intern("const_defined?"), 1, rb_str_new2("DATA_SIZE"));
383
+ has_member_names =
384
+ rb_funcall(rtype, rb_intern("const_defined?"), 1, rb_str_new2("MEMBERS"));
385
+ has_member_table =
386
+ rb_funcall(rtype, rb_intern("const_defined?"), 1, rb_str_new2("MEMBER_TABLE"));
387
+ has_encode =
388
+ rb_funcall(rtype, rb_intern("method_defined?"), 1, rb_str_new2("encode"));
389
+ has_decode = rb_respond_to(rtype, rb_intern("decode"));
390
+ return ( RTEST(has_data_size) &&
391
+ RTEST(has_member_table) && RTEST(has_member_names) &&
392
+ RTEST(has_encode) && RTEST(has_decode) ) ? Qtrue : Qfalse;
393
+ }
394
+ return Qfalse;
395
+ }
396
+
397
+ void
398
+ ca_check_data_class (VALUE rtype)
399
+ {
400
+ if ( ! rb_obj_is_data_class(rtype) ) {
401
+ VALUE inspect = rb_inspect(rtype);
402
+ rb_raise(rb_eRuntimeError,
403
+ "<%s> is not a data_class, which should has the features\n" \
404
+ " * constant data_class::DATA_SIZE -> integer\n" \
405
+ " * constant data_class::MEMBERS -> array of string\n" \
406
+ " * constant data_class::MEMBER_TABLE -> hash\n" \
407
+ " * method data_class.decode(str) -> data_class object\n" \
408
+ " * method data_class#encode() -> string", StringValuePtr(inspect));
409
+ }
410
+ }
411
+
412
+ static VALUE
413
+ rb_ca_s_is_data_class (VALUE self, VALUE rklass)
414
+ {
415
+ return rb_obj_is_data_class(rklass);
416
+ }
417
+
418
+ /* Face-state homogeneity callback for promote_list / CAStack. Two
419
+ CARecord instances are compatible iff their data_class is identical;
420
+ without this, multi-parent constructions would silently mix records
421
+ with different DATA_SIZE or field schema. */
422
+ static int
423
+ ca_record_state_compatible (CArray *a, CArray *b)
424
+ {
425
+ CARecord *ra = (CARecord *) a;
426
+ CARecord *rb = (CARecord *) b;
427
+ return (ra->data_class == rb->data_class) ? 1 : 0;
428
+ }
429
+
430
+ /* ------------------------------------------------------------------------- */
431
+
432
+ void
433
+ Init_ca_obj_record (void)
434
+ {
435
+ rb_cCARecord = rb_define_class("CARecord", rb_cCAFace);
436
+
437
+ ca_record_func.struct_size = sizeof(CARecord);
438
+ ca_record_func.pool_bytes = ca_record_pool_bytes;
439
+ ca_record_func.pool_init = ca_record_pool_init;
440
+
441
+ CA_OBJ_RECORD = ca_install_obj_type(rb_cCARecord,
442
+ &carecord_data_type,
443
+ rb_cCArrayMask,
444
+ &carray_mask_data_type,
445
+ &ca_record_func, sizeof(ca_record_func));
446
+ rb_define_const(rb_cObject, "CA_OBJ_RECORD", INT2NUM(CA_OBJ_RECORD));
447
+
448
+ /* Homogeneity gate for promote_list / CAStack. The Ruby class is
449
+ always CARecord, so the default class-equality check cannot tell
450
+ GeoCoord apart from Pixel; the callback compares data_class per
451
+ instance. */
452
+ ca_face_register_state_compatible(CA_OBJ_RECORD,
453
+ ca_record_state_compatible);
454
+
455
+ rb_define_alloc_func(rb_cCARecord, rb_ca_record_s_allocate);
456
+ rb_define_method(rb_cCARecord, "initialize_copy",
457
+ rb_ca_record_initialize_copy, 1);
458
+
459
+ rb_define_singleton_method(rb_cCARecord, "new", rb_ca_record_s_new, -1);
460
+ rb_define_singleton_method(rb_cCARecord, "wrap", rb_ca_record_s_wrap, -1);
461
+ rb_define_singleton_method(rb_cCARecord, "data_class",
462
+ rb_ca_record_s_data_class_dsl, -1);
463
+
464
+ /* #data_class is inherited from CArray via the universal Face
465
+ dispatch (rb_ca_data_class reads the tail through obj_type). */
466
+
467
+ rb_define_singleton_method(rb_cCArray, "data_class?", rb_ca_s_is_data_class, 1);
468
+ }