carray 3.0.2 → 3.0.4

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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +568 -0
  3. data/README.md +6 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +220 -0
  7. data/ext/ca_axis_group.c +201 -123
  8. data/ext/ca_binop_dispatch.c +46 -52
  9. data/ext/ca_binop_dispatch.h +1 -1
  10. data/ext/ca_categorical_iterator.c +249 -183
  11. data/ext/ca_compare.c +7 -12
  12. data/ext/ca_for_buffer.h +21 -68
  13. data/ext/ca_group_iter.c +38 -23
  14. data/ext/ca_kernel_iterator.c +1765 -2076
  15. data/ext/ca_kernel_iterator.h +584 -566
  16. data/ext/ca_monop_dispatch.c +86 -63
  17. data/ext/ca_monop_dispatch.h +5 -0
  18. data/ext/ca_obj_array.c +223 -56
  19. data/ext/ca_obj_bincmp.c +172 -138
  20. data/ext/ca_obj_binop.c +116 -230
  21. data/ext/ca_obj_bitarray.c +40 -26
  22. data/ext/ca_obj_bitfield.c +100 -68
  23. data/ext/ca_obj_block.c +19 -9
  24. data/ext/ca_obj_byte_swap.c +45 -46
  25. data/ext/ca_obj_const_string.c +269 -44
  26. data/ext/ca_obj_face.c +612 -89
  27. data/ext/ca_obj_face.h +111 -47
  28. data/ext/ca_obj_fake.c +36 -79
  29. data/ext/ca_obj_farray.c +7 -3
  30. data/ext/ca_obj_field.c +33 -8
  31. data/ext/ca_obj_fixlen_string.c +23 -24
  32. data/ext/ca_obj_grid.c +541 -210
  33. data/ext/ca_obj_meld.c +331 -111
  34. data/ext/ca_obj_moncmp.c +80 -65
  35. data/ext/ca_obj_monop.c +177 -149
  36. data/ext/ca_obj_object.c +664 -248
  37. data/ext/ca_obj_record.c +63 -23
  38. data/ext/ca_obj_reduce.c +18 -16
  39. data/ext/ca_obj_refer.c +140 -58
  40. data/ext/ca_obj_remap.c +85 -24
  41. data/ext/ca_obj_repeat.c +24 -9
  42. data/ext/ca_obj_roll.c +121 -16
  43. data/ext/ca_obj_select.c +61 -58
  44. data/ext/ca_obj_select_axis.c +73 -107
  45. data/ext/ca_obj_shift.c +32 -102
  46. data/ext/ca_obj_stack.c +372 -122
  47. data/ext/ca_obj_stride.c +348 -140
  48. data/ext/ca_obj_string.c +88 -22
  49. data/ext/ca_obj_tile.c +38 -21
  50. data/ext/ca_obj_time.c +45 -31
  51. data/ext/ca_obj_timedelta.c +43 -29
  52. data/ext/ca_obj_transpose.c +17 -6
  53. data/ext/ca_obj_triop.c +125 -141
  54. data/ext/ca_obj_window.c +330 -44
  55. data/ext/ca_op_ipower.c +24 -11
  56. data/ext/ca_op_powi.h +57 -30
  57. data/ext/ca_pow5_table.h +656 -0
  58. data/ext/ca_sort_kernels.h +70 -0
  59. data/ext/ca_sweep_engine.c +104 -81
  60. data/ext/ca_sweep_engine.h +7 -20
  61. data/ext/ca_triop_dispatch.c +4 -1
  62. data/ext/ca_triop_dispatch.h +5 -2
  63. data/ext/caframe_csv_reader.c +542 -0
  64. data/ext/carray.h +241 -92
  65. data/ext/carray_access.c +608 -276
  66. data/ext/carray_address_basis.c +494 -97
  67. data/ext/carray_attribute.c +129 -4
  68. data/ext/carray_bincount.c +39 -7
  69. data/ext/carray_broadcast.c +56 -19
  70. data/ext/carray_build_flags.h +1 -1
  71. data/ext/carray_call_cfunc.c +108 -28
  72. data/ext/carray_cast.c +1576 -223
  73. data/ext/carray_cast_func.rb +77 -24
  74. data/ext/carray_class.c +4 -3
  75. data/ext/carray_conversion.c +208 -75
  76. data/ext/carray_copy.c +82 -24
  77. data/ext/carray_core.c +646 -162
  78. data/ext/carray_count.c +171 -88
  79. data/ext/carray_element.c +94 -60
  80. data/ext/carray_factorize.c +670 -324
  81. data/ext/carray_generate.c +260 -83
  82. data/ext/carray_histogram.c +209 -106
  83. data/ext/carray_hold.c +14 -16
  84. data/ext/carray_index_classifier.c +422 -243
  85. data/ext/carray_internal.h +692 -3
  86. data/ext/carray_kernels_bincmp.c +7 -0
  87. data/ext/carray_kernels_binop.c +487 -120
  88. data/ext/carray_kernels_init.c +653 -50
  89. data/ext/carray_kernels_moncmp.c +15 -8
  90. data/ext/carray_kernels_monop.c +99 -43
  91. data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
  92. data/ext/carray_kernels_reduce_boolean.c +112 -36
  93. data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
  94. data/ext/carray_kernels_reduce_extreme.c +3032 -2892
  95. data/ext/carray_kernels_reduce_variance.c +439 -500
  96. data/ext/carray_kernels_scan.c +1097 -488
  97. data/ext/carray_kernels_search.c +3787 -2176
  98. data/ext/carray_kernels_sort.c +1200 -920
  99. data/ext/carray_kernels_triop.c +479 -7
  100. data/ext/carray_key_windows.c +216 -0
  101. data/ext/carray_lazy.c +967 -153
  102. data/ext/carray_loop.c +81 -65
  103. data/ext/carray_mask.c +910 -324
  104. data/ext/carray_math_kernel.h +1 -0
  105. data/ext/carray_median_percentile.c +299 -100
  106. data/ext/carray_memory_view.c +872 -758
  107. data/ext/carray_operator.c +1171 -364
  108. data/ext/carray_order.c +505 -133
  109. data/ext/carray_partition.c +112 -65
  110. data/ext/carray_random.c +327 -239
  111. data/ext/carray_round.c +273 -0
  112. data/ext/carray_scatter.c +346 -78
  113. data/ext/carray_segment.c +257 -0
  114. data/ext/carray_slab.c +249 -86
  115. data/ext/carray_sort.c +224 -227
  116. data/ext/carray_sort_kernel.c +8 -1
  117. data/ext/carray_struct.c +118 -39
  118. data/ext/carray_test.c +193 -69
  119. data/ext/carray_time_text.c +1182 -0
  120. data/ext/carray_undef.c +4 -0
  121. data/ext/carray_utils.c +579 -113
  122. data/ext/extconf.rb +27 -2
  123. data/ext/mk_call_cfunc.rb +19 -4
  124. data/ext/mk_pow5_table.rb +35 -0
  125. data/ext/mkkernel.rb +1202 -1014
  126. data/ext/ruby_carray.c +17 -5
  127. data/ext/version.h +4 -4
  128. data/ext/version.rb +4 -2
  129. data/lib/carray/attribute.rb +160 -17
  130. data/lib/carray/autoload_carray.rb +23 -27
  131. data/lib/carray/autoload_method_extension.rb +20 -5
  132. data/lib/carray/axis_group.rb +360 -63
  133. data/lib/carray/basics.rb +162 -28
  134. data/lib/carray/bincount_nd.rb +18 -2
  135. data/lib/carray/block_iterator.rb +231 -58
  136. data/lib/carray/boolean_reduce.rb +34 -42
  137. data/lib/carray/categorical.rb +242 -52
  138. data/lib/carray/categorical_iterator.rb +437 -827
  139. data/lib/carray/complex.rb +41 -34
  140. data/lib/carray/conditional.rb +150 -14
  141. data/lib/carray/const_string.rb +59 -4
  142. data/lib/carray/construct.rb +15 -11
  143. data/lib/carray/data_type_extension.rb +1 -0
  144. data/lib/carray/distance_limit.rb +77 -0
  145. data/lib/carray/fixlen_string.rb +7 -1
  146. data/lib/carray/frame/column_verbs.rb +70 -0
  147. data/lib/carray/frame/concat.rb +157 -6
  148. data/lib/carray/frame/convert.rb +82 -7
  149. data/lib/carray/frame/csv_parser.rb +688 -87
  150. data/lib/carray/frame/describe.rb +80 -0
  151. data/lib/carray/frame/frame.rb +369 -45
  152. data/lib/carray/frame/group.rb +631 -90
  153. data/lib/carray/frame/io.rb +506 -79
  154. data/lib/carray/frame/join.rb +411 -62
  155. data/lib/carray/frame/records.rb +116 -19
  156. data/lib/carray/frame/reshape.rb +455 -0
  157. data/lib/carray/frame/sort.rb +30 -18
  158. data/lib/carray/frame/verbs.rb +868 -61
  159. data/lib/carray/frame/windows.rb +117 -0
  160. data/lib/carray/frame.rb +4 -0
  161. data/lib/carray/fuse_source.rb +118 -2
  162. data/lib/carray/fusion.rb +257 -42
  163. data/lib/carray/histogram.rb +6 -1
  164. data/lib/carray/inspect.rb +54 -13
  165. data/lib/carray/iterator.rb +99 -9
  166. data/lib/carray/key_windows.rb +620 -0
  167. data/lib/carray/lazy.rb +216 -193
  168. data/lib/carray/mask_gap_fill.rb +112 -92
  169. data/lib/carray/math.rb +32 -19
  170. data/lib/carray/meld_reduce.rb +52 -21
  171. data/lib/carray/methods/align_addr.rb +8 -4
  172. data/lib/carray/methods/bin.rb +26 -18
  173. data/lib/carray/methods/bincount.rb +18 -2
  174. data/lib/carray/methods/bit_string.rb +15 -4
  175. data/lib/carray/methods/choose.rb +16 -3
  176. data/lib/carray/methods/composition.rb +18 -10
  177. data/lib/carray/methods/factorize.rb +2 -2
  178. data/lib/carray/methods/gather_nd.rb +25 -5
  179. data/lib/carray/methods/insert_block.rb +9 -14
  180. data/lib/carray/methods/is_between.rb +59 -0
  181. data/lib/carray/methods/is_in.rb +140 -10
  182. data/lib/carray/methods/join.rb +2 -7
  183. data/lib/carray/methods/lag.rb +49 -0
  184. data/lib/carray/methods/locate_addr.rb +182 -45
  185. data/lib/carray/methods/mode.rb +18 -1
  186. data/lib/carray/methods/nunique.rb +11 -6
  187. data/lib/carray/methods/repeat.rb +1 -20
  188. data/lib/carray/methods/resize.rb +21 -23
  189. data/lib/carray/methods/snap.rb +34 -12
  190. data/lib/carray/methods/unique.rb +11 -2
  191. data/lib/carray/methods/value_counts.rb +4 -11
  192. data/lib/carray/record_order.rb +208 -0
  193. data/lib/carray/rng.rb +3 -0
  194. data/lib/carray/runtime.rb +65 -17
  195. data/lib/carray/segment_iterator.rb +1221 -0
  196. data/lib/carray/serialize.rb +214 -30
  197. data/lib/carray/slab_iterator.rb +101 -27
  198. data/lib/carray/stack.rb +10 -4
  199. data/lib/carray/string.rb +105 -5
  200. data/lib/carray/string_operation_extension.rb +12 -4
  201. data/lib/carray/struct.rb +137 -58
  202. data/lib/carray/struct_builder.rb +124 -17
  203. data/lib/carray/time.rb +1222 -186
  204. data/lib/carray/window_iterator.rb +242 -81
  205. data/lib/carray.rb +9 -2
  206. data/yard-stubs/ca_obj_array.rb +4 -4
  207. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  208. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  209. data/yard-stubs/ca_obj_fake.rb +1 -1
  210. data/yard-stubs/ca_obj_field.rb +5 -1
  211. data/yard-stubs/ca_obj_grid.rb +21 -10
  212. data/yard-stubs/ca_obj_refer.rb +5 -4
  213. data/yard-stubs/ca_obj_roll.rb +2 -3
  214. data/yard-stubs/ca_obj_shift.rb +5 -1
  215. data/yard-stubs/ca_obj_stride.rb +10 -7
  216. data/yard-stubs/ca_obj_tile.rb +1 -1
  217. data/yard-stubs/ca_obj_transpose.rb +1 -1
  218. data/yard-stubs/ca_obj_window.rb +9 -5
  219. data/yard-stubs/carray_access.rb +11 -5
  220. data/yard-stubs/carray_attribute.rb +0 -5
  221. data/yard-stubs/carray_broadcast.rb +1 -1
  222. data/yard-stubs/carray_cast.rb +88 -43
  223. data/yard-stubs/carray_conversion.rb +15 -2
  224. data/yard-stubs/carray_copy.rb +12 -5
  225. data/yard-stubs/carray_core.rb +3 -3
  226. data/yard-stubs/carray_count.rb +9 -0
  227. data/yard-stubs/carray_element.rb +10 -4
  228. data/yard-stubs/carray_generate.rb +21 -1
  229. data/yard-stubs/carray_lazy.rb +5 -1
  230. data/yard-stubs/carray_loop.rb +4 -1
  231. data/yard-stubs/carray_mask.rb +60 -12
  232. data/yard-stubs/carray_math.rb +52 -14
  233. data/yard-stubs/carray_median_percentile.rb +15 -8
  234. data/yard-stubs/carray_memory_view.rb +40 -23
  235. data/yard-stubs/carray_order.rb +61 -29
  236. data/yard-stubs/carray_random.rb +13 -4
  237. data/yard-stubs/carray_scatter.rb +21 -9
  238. data/yard-stubs/carray_segment.rb +72 -0
  239. data/yard-stubs/carray_slab.rb +10 -2
  240. data/yard-stubs/carray_sort.rb +49 -8
  241. data/yard-stubs/carray_test.rb +15 -3
  242. data/yard-stubs/carray_utils.rb +0 -26
  243. metadata +19 -5
  244. data/ext/ca_for_each_element.h +0 -239
  245. data/ext/carray_kernels_map.c +0 -3467
  246. data/lib/carray/arrow_tensor.rb +0 -401
  247. data/lib/carray/table.rb +0 -108
data/ext/ruby_carray.c CHANGED
@@ -38,12 +38,14 @@ void Init_carray_attribute ();
38
38
  void Init_carray_loop ();
39
39
  void Init_carray_mask ();
40
40
  void Init_carray_hold ();
41
+ void Init_carray_key_windows ();
41
42
  void Init_carray_mask_fast_paths (); /* patches generated bit-op tables;
42
43
  must run AFTER Init_ca_op_ipower */
43
44
  void Init_carray_access ();
44
45
  void Init_carray_index_classifier ();
45
46
  void Init_carray_element ();
46
47
  void Init_carray_scatter (); /* scatter_*! family */
48
+ void Init_carray_segment (); /* segment lengths / offsets / index */
47
49
  void Init_ca_axis_group (); /* devel/MEMO_AXIS_GROUP.md — axis-group reduction kernel */
48
50
  void Init_ca_group_iter (); /* devel/MEMO_AXIS_GROUP.md — axis-group [] surface */
49
51
  void Init_carray_bincount (); /* bincount dedicated kernel */
@@ -59,6 +61,7 @@ void Init_carray_median_percentile (); /* median / percentile / quantile */
59
61
  void Init_carray_sort (); /* sort / sort_copy / sort_addr / axis2addr */
60
62
  void Init_carray_count ();
61
63
  void Init_carray_kernels (); /* mkkernel-generated: reductions + maps */
64
+ void Init_carray_round ();
62
65
  void Init_carray_utils ();
63
66
  void Init_carray_generate ();
64
67
  void Init_carray_copy ();
@@ -89,6 +92,8 @@ void Init_ca_obj_byte_swap ();
89
92
  void Init_ca_face (); /* CAFace abstract base; must precede CATime / CATimedelta / CARecord / CAConstString */
90
93
  void Init_ca_source (); /* CASource abstract base; concrete sources live in C extensions */
91
94
  void Init_ca_obj_time (); /* first numeric Face */
95
+ void Init_carray_time_text ();
96
+ void Init_caframe_csv_reader ();
92
97
  void Init_ca_obj_timedelta (); /* CATime sibling */
93
98
  void Init_ca_obj_record (); /* composite Face for CAStruct backing */
94
99
  void Init_ca_obj_const_string ();/* read-only variable-length string Face */
@@ -169,7 +174,7 @@ Init_carray_ext (void)
169
174
  /* -- Exception class -- */
170
175
 
171
176
  rb_eCADataTypeError =
172
- rb_define_class_under(rb_cCArray, "DataTypeError", rb_eStandardError);
177
+ rb_define_class_under(rb_cCArray, "DataTypeError", rb_eTypeError);
173
178
 
174
179
  /* -- CA module -- namespace for misc utilities related to CArray */
175
180
 
@@ -180,13 +185,13 @@ Init_carray_ext (void)
180
185
  /* The flags this build's arithmetic was compiled with. Anything that
181
186
  computes what these kernels compute, somewhere other than in them, has
182
187
  to be built the same way to arrive at the same answer. */
183
- rb_define_const(rb_cCArray, "BUILD_FLAGS", rb_str_new2(CA_BUILD_FLAGS));
184
- rb_define_const(rb_cCArray, "VERSION", rb_str_new2(CA_VERSION));
188
+ rb_define_const(rb_cCArray, "BUILD_FLAGS", rb_obj_freeze(rb_str_new2(CA_BUILD_FLAGS)));
189
+ rb_define_const(rb_cCArray, "VERSION", rb_obj_freeze(rb_str_new2(CA_VERSION)));
185
190
  rb_define_const(rb_cCArray, "VERSION_CODE", INT2NUM(CA_VERSION_CODE));
186
191
  rb_define_const(rb_cCArray, "VERSION_MAJOR", INT2NUM(CA_VERSION_MAJOR));
187
192
  rb_define_const(rb_cCArray, "VERSION_MINOR", INT2NUM(CA_VERSION_MINOR));
188
193
  rb_define_const(rb_cCArray, "VERSION_TEENY", INT2NUM(CA_VERSION_TEENY));
189
- rb_define_const(rb_cCArray, "VERSION_DATE", rb_str_new2(CA_VERSION_DATE));
194
+ rb_define_const(rb_cCArray, "VERSION_DATE", rb_obj_freeze(rb_str_new2(CA_VERSION_DATE)));
190
195
 
191
196
  /* -- system -- */
192
197
  rb_define_const(rb_cObject, "CA_RANK_MAX", INT2NUM(CA_RANK_MAX));
@@ -196,8 +201,10 @@ Init_carray_ext (void)
196
201
  absence. C code only ever compares against it; the value is never
197
202
  read and must never be passed in from Ruby. The constant exists to
198
203
  anchor the object against the GC. */
199
- CA_UNSPECIFIED = rb_funcall(rb_cObject, rb_intern("new"), 0);
204
+ CA_UNSPECIFIED = rb_obj_freeze(rb_funcall(rb_cObject, rb_intern("new"), 0));
200
205
  rb_define_const(rb_cCArray, "UNSPECIFIED", CA_UNSPECIFIED);
206
+ /* Compared by identity in C, so it must not move. */
207
+ rb_gc_register_mark_object(CA_UNSPECIFIED);
201
208
 
202
209
  #ifdef HAVE_COMPLEX_H
203
210
  /* @private */
@@ -281,11 +288,13 @@ Init_carray_ext (void)
281
288
  Init_carray_undef();
282
289
  Init_carray_mask();
283
290
  Init_carray_hold();
291
+ Init_carray_key_windows();
284
292
  Init_carray_loop();
285
293
  Init_carray_access();
286
294
  Init_carray_index_classifier();
287
295
  Init_carray_element();
288
296
  Init_carray_scatter();
297
+ Init_carray_segment();
289
298
  Init_ca_axis_group(); /* devel/MEMO_AXIS_GROUP.md — axis-group reduction kernel */
290
299
  Init_carray_bincount();
291
300
  Init_carray_factorize();
@@ -304,6 +313,7 @@ Init_carray_ext (void)
304
313
  Init_carray_sort(); /* sort / sort_copy / sort_addr / axis2addr */
305
314
  Init_carray_count();
306
315
  Init_carray_kernels(); /* mkkernel-generated: reductions + maps */
316
+ Init_carray_round(); /* round(ndigits); after the generated round */
307
317
 
308
318
  Init_carray_utils();
309
319
 
@@ -343,6 +353,8 @@ Init_carray_ext (void)
343
353
  (datetime / timedelta / record /
344
354
  const_string). */
345
355
  Init_ca_obj_time();
356
+ Init_carray_time_text();
357
+ Init_caframe_csv_reader();
346
358
  Init_ca_obj_timedelta();
347
359
  Init_ca_obj_record();
348
360
  Init_ca_obj_const_string();
data/ext/version.h CHANGED
@@ -1,6 +1,6 @@
1
- #define CA_VERSION "3.0.2"
2
- #define CA_VERSION_CODE 302
1
+ #define CA_VERSION "3.0.4"
2
+ #define CA_VERSION_CODE 30004
3
3
  #define CA_VERSION_MAJOR 3
4
4
  #define CA_VERSION_MINOR 0
5
- #define CA_VERSION_TEENY 2
6
- #define CA_VERSION_DATE "2026/09/24"
5
+ #define CA_VERSION_TEENY 4
6
+ #define CA_VERSION_DATE "2026/10/19"
data/ext/version.rb CHANGED
@@ -21,8 +21,10 @@ def carray_version
21
21
 
22
22
  ca_version2 = format("%i.%i.%i",
23
23
  ca_version_major, ca_version_minor, ca_version_teeny)
24
- ca_version_code2 =
25
- 100 * ca_version_major + 10*ca_version_minor + ca_version_teeny
24
+ # Two decimal digits for each of minor and teeny, so 3.0.10 (30010)
25
+ # comes after 3.0.9 (30009) and before 3.1.0 (30100).
26
+ ca_version_code2 =
27
+ 10000 * ca_version_major + 100 * ca_version_minor + ca_version_teeny
26
28
 
27
29
  # Allow pre-release suffix like "3.0.0.dev" / "3.0.0.alpha1" while still
28
30
  # validating the numeric MAJOR.MINOR.TEENY prefix.
@@ -4,6 +4,7 @@
4
4
  # Surface:
5
5
  # ca.attr(:unit) # => getter; nil if absent
6
6
  # ca.set_attr(:unit, "m/s") # => setter; writes to self's @attr
7
+ # ca.set_attrs(other.attrs) # => sets every key of a Hash at once
7
8
  # ca.attrs # => frozen shallow clone of the full Hash
8
9
  # ca.has_attr? # => any attribute present?
9
10
  # ca.has_attr?(:unit) # => specific key present?
@@ -27,6 +28,38 @@
27
28
  # `attrs` returns the effective merged Hash (deeper writes
28
29
  # override shallower ones), frozen.
29
30
  # Setter side always writes to self's @attr.
31
+ # The walk stops at a lazy operation view (CAMonOp / CABinOp /
32
+ # CATriOp / CAMonCmp / CABinCmp): its cells are computed, not the
33
+ # parent's cells, so the parent's attributes do not describe them.
34
+ # `a.lazy` itself (CALazyMarker) is a view of `a` and walks through,
35
+ # and so does a lazy type conversion (the cast lane `promote_list`
36
+ # and `wrap_readonly` build), for the reason `to_type` carries them.
37
+ # A view of a Face shows the attributes of the Face it was taken
38
+ # from (the walk goes to that Face, which the view's own parent
39
+ # chain skips).
40
+ # A view of several arrays (CAStack / CAMeld, so `stack`, `meld` and
41
+ # `montage`) shows, below its own @attr, the keys every one of its
42
+ # arrays shows with the same value; a key they disagree on, or one
43
+ # some of them lack, is not shown.
44
+ #
45
+ # Stored values are frozen copies, nested Arrays and Hashes included, so
46
+ # an attribute changes only through set_attr / set_attrs: a value read
47
+ # back cannot be changed in place, and a copy that shares it with its
48
+ # source cannot change the source. A frozen array takes no new
49
+ # attribute.
50
+ #
51
+ # A mask array (`a.mask`) holds no attributes: set_attr / set_attrs raise.
52
+ #
53
+ # Copies: `dup` and `clone` give the new array its own Hash of the
54
+ # receiver's own attributes. `copy` and `to_type` give the new array the attributes the
55
+ # source shows, as its own Hash; `concatenate`, `mosaic` and `tabulate`
56
+ # give it the keys every piece shows with the same value, as the views
57
+ # do. A conversion to another type or representation (`to_type`,
58
+ # `categorize`, a CAFrame `cast` / `parse_to_time` / `to_time`) carries
59
+ # them. Arithmetic and reductions do not -- the result is a different
60
+ # quantity -- including those that pick a value (`first`, `last`, `min`,
61
+ # `max`, `unique`). A CAFrame index built from a key column's values
62
+ # (group and pivot) shows the key column's attributes.
30
63
 
31
64
  class CArray
32
65
 
@@ -54,15 +87,64 @@ class CArray
54
87
  # store.
55
88
  # @param key [Symbol, String] attribute key.
56
89
  # @param value [Object] JSON-compatible value.
57
- # @return [Object] the coerced stored value.
90
+ # The value is stored as a frozen copy (nested Arrays and Hashes
91
+ # too).
92
+ # @return [Object] the stored value.
58
93
  # @raise [TypeError] when `key` or `value` is not accepted.
94
+ # @raise [ArgumentError] when `value` nests more than 32 levels.
95
+ # @raise [FrozenError] when `self` is frozen.
96
+ # @raise [TypeError] when `self` is a mask array.
59
97
  def set_attr (key, value)
98
+ attr_check_writable
60
99
  attr_validate_value(value)
61
100
  (@attr ||= {})[attr_normalize_key(key)] = attr_coerce_value(value)
62
101
  end
63
102
 
103
+ # @overload set_attrs(hash)
104
+ # Sets every key of `hash` on `self`, as {#set_attr} does one key.
105
+ # Keys already on `self` and not in `hash` are kept. Every value is
106
+ # validated before any is written, so a rejected value leaves `self`
107
+ # unchanged. `b.set_attrs(a.attrs)` gives `b` the attributes `a`
108
+ # shows.
109
+ # @param hash [Hash{Symbol, String => Object}] attributes to set.
110
+ # @return [CArray] self.
111
+ # @raise [TypeError] when a key or a value is not accepted.
112
+ # @raise [ArgumentError] when a value nests more than 32 levels.
113
+ # @raise [FrozenError] when `self` is frozen.
114
+ # @raise [TypeError] when `self` is a mask array.
115
+ def set_attrs (hash)
116
+ attr_check_writable
117
+ unless hash.is_a?(Hash)
118
+ raise TypeError, "set_attrs takes a Hash (got #{hash.class})"
119
+ end
120
+ entries = hash.map do |key, value|
121
+ attr_validate_value(value)
122
+ [attr_normalize_key(key), attr_coerce_value(value)]
123
+ end
124
+ unless entries.empty?
125
+ h = (@attr ||= {})
126
+ entries.each { |k, v| h[k] = v }
127
+ end
128
+ self
129
+ end
130
+
131
+ # @overload delete_attr(key)
132
+ # Removes attribute `key` from `self` (not from any parent) and
133
+ # returns its value, or `nil` when `self` has no such key. A key a
134
+ # view shows from its parent stays visible after this, as `set_attr`
135
+ # writes to `self` only.
136
+ # @param key [Symbol, String] attribute key.
137
+ # @return [Object, nil] the removed value.
138
+ # @raise [FrozenError] when `self` is frozen.
139
+ def delete_attr (key)
140
+ k = attr_normalize_key(key)
141
+ return nil unless instance_variable_defined?(:@attr) && @attr
142
+ attr_check_not_frozen
143
+ @attr.delete(k)
144
+ end
145
+
64
146
  # @overload attrs
65
- # Returns a frozen shallow Hash of all attributes visible on
147
+ # Returns a frozen Hash of all attributes visible on
66
148
  # `self`, merged along the parent chain (deeper writes shadow
67
149
  # shallower ones on a per-key basis).
68
150
  # @return [Hash{String => Object}]
@@ -102,26 +184,85 @@ class CArray
102
184
  private
103
185
 
104
186
  # Yield each non-nil @attr Hash along the parent chain (self first).
105
- # Bounded to MAX_CHAIN_DEPTH for paranoia against unexpected cycles;
106
- # real CArray view chains rarely exceed a handful of levels.
107
- MAX_CHAIN_DEPTH = 64
108
- private_constant :MAX_CHAIN_DEPTH
109
-
187
+ # The chain has no fixed bound; an array seen twice ends the walk.
110
188
  def attr_each_chain
111
189
  ca = self
112
- MAX_CHAIN_DEPTH.times do
190
+ seen = nil
191
+ loop do
113
192
  if ca.instance_variable_defined?(:@attr)
114
193
  h = ca.instance_variable_get(:@attr)
115
194
  yield(h) if h
116
195
  end
117
- parent = ca.respond_to?(:parent) ? ca.parent : nil
118
- return nil if parent.nil? || parent.equal?(ca)
196
+ return nil if attr_computing_view?(ca)
197
+ if ca.is_a?(CAStack) || ca.is_a?(CAMeld)
198
+ shared = CArray.__send__(:attrs_shared_by, ca.parents)
199
+ yield(shared) unless shared.empty?
200
+ return nil
201
+ end
202
+ parent = ca.is_a?(CArray) ? ca.__send__(:attribute_parent) : nil
203
+ return nil if parent.nil?
204
+ seen ||= {}.compare_by_identity
205
+ return nil if seen.key?(parent)
206
+ seen[ca] = true
119
207
  ca = parent
120
208
  end
121
- nil
209
+ end
210
+
211
+ def attr_check_not_frozen
212
+ raise FrozenError.new("can't modify frozen #{self.class}: attributes", receiver: self) if frozen?
213
+ end
214
+
215
+ def attr_check_writable
216
+ attr_check_not_frozen
217
+ raise TypeError, "a mask array holds no attributes" if mask_array?
218
+ end
219
+
220
+ # Give `out`, a new array holding self's values in another type or
221
+ # representation, the attributes self shows; returns `out`. A view of
222
+ # self that already shows them is left alone.
223
+ def carry_attrs (out)
224
+ return out if out.equal?(self)
225
+ shown = attrs
226
+ out.set_attrs(shown) unless shown.empty? || out.attrs == shown
227
+ out
228
+ end
229
+
230
+ # Remove what `out`, a new array a reduction made, holds of self's
231
+ # attributes; returns `out`.
232
+ def drop_carried_attrs (out)
233
+ out.remove_instance_variable(:@attr) if out.instance_variable_defined?(:@attr)
234
+ out
235
+ end
236
+
237
+ # The attributes every array in `list` shows with the same value.
238
+ def self.attrs_shared_by (list)
239
+ first, *rest = list.map(&:attrs)
240
+ return {} if first.nil?
241
+ first.select { |k, v| rest.all? { |h| h.key?(k) && h[k] == v } }
242
+ end
243
+ private_class_method :attrs_shared_by
244
+
245
+ def attr_computing_view? (ca)
246
+ return ca.__op_id__ < CAMonOp::CAST_BASE if ca.is_a?(CAMonOp)
247
+ ca.is_a?(CABinOp) || ca.is_a?(CATriOp) ||
248
+ ca.is_a?(CAMonCmp) || ca.is_a?(CABinCmp)
122
249
  end
123
250
 
124
251
  def attr_normalize_key (key)
252
+ CArray.__send__(:attr_normalize_key, key)
253
+ end
254
+
255
+ def attr_validate_value (v)
256
+ CArray.__send__(:attr_validate_value, v)
257
+ end
258
+
259
+ def attr_coerce_value (v)
260
+ CArray.__send__(:attr_coerce_value, v)
261
+ end
262
+
263
+ # The key and value rules, as class methods so that CAFrame's attributes
264
+ # follow the same ones.
265
+ def self.attr_normalize_key (key)
125
266
  case key
126
267
  when String then key
127
268
  when Symbol then key.to_s
@@ -130,7 +271,7 @@ class CArray
130
271
  end
131
272
  end
132
273
 
133
- def attr_validate_value (v, depth = 0)
274
+ def self.attr_validate_value (v, depth = 0)
134
275
  raise ArgumentError, "attribute value nests too deep" if depth > 32
135
276
  case v
136
277
  when String, Integer, Float, true, false, nil, Symbol
@@ -150,17 +291,19 @@ class CArray
150
291
  end
151
292
  end
152
293
 
153
- def attr_coerce_value (v)
294
+ def self.attr_coerce_value (v)
154
295
  case v
155
- when Symbol then v.to_s
156
- when Array then v.map { |e| attr_coerce_value(e) }
296
+ when Symbol then v.to_s.freeze
297
+ when String then v.frozen? ? v : v.dup.freeze
298
+ when Array then v.map { |e| attr_coerce_value(e) }.freeze
157
299
  when Hash
158
300
  v.each_with_object({}) do |(k, vv), h|
159
- h[k.is_a?(Symbol) ? k.to_s : k] = attr_coerce_value(vv)
160
- end
301
+ h[(k.is_a?(Symbol) ? k.to_s : k.dup).freeze] = attr_coerce_value(vv)
302
+ end.freeze
161
303
  else
162
304
  v
163
305
  end
164
306
  end
307
+ private_class_method :attr_normalize_key, :attr_validate_value, :attr_coerce_value
165
308
 
166
309
  end
@@ -6,7 +6,7 @@
6
6
  # after autoload_method_extension is installed. Split by intent:
7
7
  #
8
8
  # (1) Top-level feature files under carray/ — constant class + entry
9
- # methods (Serializer, TableMethods, iterators, aggregation
9
+ # methods (Serializer, iterators, aggregation
10
10
  # accumulators, categorical / axis-group).
11
11
  # (2) Single-feature method files under carray/methods/ — each first
12
12
  # call requires its file, whose definitions overwrite the stubs
@@ -20,21 +20,6 @@
20
20
  # (1) Top-level feature files
21
21
  # ============================================================================
22
22
 
23
- # ---- Inspection (#inspect / #source_code) ----------------------------------
24
- #
25
- # CArray::Inspector (:nodoc:) and #inspect / #source_code live in carray/inspect.rb.
26
- # #inspect is an implicit method (p / pp / irb / error interpolation), so the
27
- # stub loads the file the first time any CArray is displayed. Nothing in the
28
- # eager core references it at load time; #desc is private (code-internal) and
29
- # Inspector is internal, so only the two public methods need stubs.
30
-
31
- class CArray
32
- inspect_rb = "carray/inspect"
33
- autoload_method "inspect", inspect_rb
34
- autoload_method "inspect_full", inspect_rb
35
- autoload_method "source_code", inspect_rb
36
- end
37
-
38
23
  # ---- Serializer / Marshal / dump / load ------------------------------------
39
24
 
40
25
  class CArray
@@ -47,19 +32,21 @@ class CArray
47
32
  autoload_method "marshal_load", serialize_rb
48
33
  end
49
34
 
50
- # ---- Arrow tensor IPC (interop) --------------------------------------------
51
-
52
- class CArray
53
- arrow_tensor_rb = "carray/arrow_tensor"
54
- autoload :ArrowTensor, arrow_tensor_rb
55
- autoload_method "self.load_arrow_tensor", arrow_tensor_rb
56
- autoload_method "save_arrow_tensor", arrow_tensor_rb
35
+ # A view, a wrap and a scalar are marshalled through _dump / self._load,
36
+ # which return a new array: with marshal_dump Marshal records the class and
37
+ # loads into an empty instance of it, which the plain array the payload
38
+ # holds cannot become. A record array keeps marshal_dump, under which it
39
+ # already round-trips with its class.
40
+ [CAView, CAWrap, CScalar].each do |klass|
41
+ klass.class_eval do
42
+ undef_method :marshal_dump
43
+ autoload_method "_dump", "carray/serialize"
44
+ autoload_method "self._load", "carray/serialize"
45
+ end
57
46
  end
58
47
 
59
- # ---- Table (row-major dispatch helper) -------------------------------------
60
-
61
- class CArray
62
- autoload :TableMethods, "carray/table"
48
+ class CARecord
49
+ autoload_method "marshal_dump", "carray/serialize"
63
50
  end
64
51
 
65
52
  # ---- Fusion (reading a lazy expression as a plan) --------------------------
@@ -84,6 +71,7 @@ end
84
71
 
85
72
  autoload :CASlabIterator, "carray/slab_iterator"
86
73
  autoload :CAWindowIterator, "carray/window_iterator"
74
+ autoload :CAKeyWindowIterator, "carray/key_windows"
87
75
  autoload :CABlockIterator, "carray/block_iterator"
88
76
 
89
77
  class CArray
@@ -126,10 +114,12 @@ class CArray
126
114
  categorical_iterator_rb = "carray/categorical_iterator"
127
115
  autoload_method "group_by_category", categorical_iterator_rb
128
116
  autoload_method "group_by_run", categorical_iterator_rb
117
+ autoload_method "segments", "carray/segment_iterator"
129
118
  end
130
119
 
131
120
  autoload :CACategorical, "carray/categorical"
132
121
  autoload :CACategoricalIterator, "carray/categorical_iterator"
122
+ autoload :CASegmentIterator, "carray/segment_iterator"
133
123
  autoload :AxisGroup, "carray/axis_group"
134
124
  autoload :GroupLabels, "carray/axis_group"
135
125
 
@@ -155,6 +145,10 @@ autoload :CAUnion, "carray/struct"
155
145
  autoload :CAFrame, "carray/frame"
156
146
  autoload :GroupedFrame, "carray/frame"
157
147
 
148
+ class CArray
149
+ autoload_method "to_frame", "carray/frame"
150
+ end
151
+
158
152
  class CArray
159
153
  struct_rb = "carray/struct"
160
154
  autoload_method "self.struct", struct_rb
@@ -212,10 +206,12 @@ class CArray
212
206
  autoload_method "intersection", "carray/methods/is_in"
213
207
  autoload_method "difference", "carray/methods/is_in"
214
208
  autoload_method "union", "carray/methods/is_in"
209
+ autoload_method "is_between", "carray/methods/is_between"
215
210
  autoload_method "self.align_addr", "carray/methods/align_addr"
216
211
  autoload_method "self.align_nearest_addr", "carray/methods/align_addr"
217
212
  autoload_method "value_counts", "carray/methods/value_counts"
218
213
  autoload_method "nunique", "carray/methods/nunique"
214
+ autoload_method "lag", "carray/methods/lag"
219
215
  autoload_method "is_mode", "carray/methods/mode"
220
216
  autoload_method "mode", "carray/methods/mode"
221
217
  autoload_method "snap", "carray/methods/snap"
@@ -32,8 +32,18 @@ module AutoloadMethodExtension
32
32
  private
33
33
 
34
34
  def autoload_define (target, name, library, original_spec)
35
- stub = nil
36
- target.define_method(name) do |*args, **kwargs, &block|
35
+ library = Ractor.make_shareable(library.to_s.dup)
36
+ original_spec = Ractor.make_shareable(original_spec.to_s.dup)
37
+ # Shareable, so the stub answers in any Ractor. Only the main Ractor
38
+ # loads the library: Ractors that require at the same time can deadlock
39
+ # (Ruby 3.4), so another Ractor is told what to load there instead.
40
+ target.define_method(name, &Ractor.make_shareable(proc do |*args, **kwargs, &block|
41
+ unless Ractor.current == Ractor.main
42
+ raise Ractor::IsolationError,
43
+ "'#{original_spec}' is loaded on first use from '#{library}'; " \
44
+ "require it in the main Ractor before other Ractors use it"
45
+ end
46
+ stub_location = target.instance_method(name).source_location
37
47
  begin
38
48
  require library
39
49
  rescue LoadError
@@ -45,13 +55,18 @@ module AutoloadMethodExtension
45
55
  # forwarding would land straight back here and keep doing so until the
46
56
  # stack gave out -- naming neither the method nor the library. Say
47
57
  # which, once.
48
- if target.instance_method(name) == stub
58
+ if target.instance_method(name).source_location == stub_location
49
59
  raise NoMethodError,
50
60
  "'#{original_spec}' is registered for autoload from " \
51
61
  "'#{library}', but that library defines no such method"
52
62
  end
53
63
  send(name, *args, **kwargs, &block)
54
- end
55
- stub = target.instance_method(name)
64
+ end))
65
+ # The library replaces the stub with a plain `def`, which `ruby -w`
66
+ # reports as a redefinition. Replacing is what the stub is for, so mark
67
+ # it as aliased: Ruby does not warn when the old definition has an alias.
68
+ tmp = :"__autoload_stub_#{name}__"
69
+ target.send(:alias_method, tmp, name)
70
+ target.send(:remove_method, tmp)
56
71
  end
57
72
  end