carray 3.0.3 → 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 (212) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +1 -6
  7. data/ext/ca_axis_group.c +27 -27
  8. data/ext/ca_binop_dispatch.c +1 -29
  9. data/ext/ca_binop_dispatch.h +0 -1
  10. data/ext/ca_categorical_iterator.c +205 -134
  11. data/ext/ca_compare.c +7 -18
  12. data/ext/ca_group_iter.c +16 -17
  13. data/ext/ca_kernel_iterator.c +1234 -1994
  14. data/ext/ca_kernel_iterator.h +391 -437
  15. data/ext/ca_monop_dispatch.c +82 -59
  16. data/ext/ca_monop_dispatch.h +1 -0
  17. data/ext/ca_obj_array.c +96 -39
  18. data/ext/ca_obj_bincmp.c +24 -21
  19. data/ext/ca_obj_binop.c +15 -26
  20. data/ext/ca_obj_bitarray.c +3 -2
  21. data/ext/ca_obj_bitfield.c +5 -6
  22. data/ext/ca_obj_block.c +18 -9
  23. data/ext/ca_obj_byte_swap.c +5 -6
  24. data/ext/ca_obj_const_string.c +173 -19
  25. data/ext/ca_obj_face.c +238 -57
  26. data/ext/ca_obj_face.h +19 -0
  27. data/ext/ca_obj_fake.c +15 -29
  28. data/ext/ca_obj_farray.c +6 -3
  29. data/ext/ca_obj_field.c +17 -5
  30. data/ext/ca_obj_fixlen_string.c +2 -3
  31. data/ext/ca_obj_grid.c +406 -132
  32. data/ext/ca_obj_meld.c +172 -34
  33. data/ext/ca_obj_moncmp.c +23 -8
  34. data/ext/ca_obj_monop.c +67 -57
  35. data/ext/ca_obj_object.c +157 -51
  36. data/ext/ca_obj_record.c +12 -7
  37. data/ext/ca_obj_reduce.c +13 -8
  38. data/ext/ca_obj_refer.c +25 -27
  39. data/ext/ca_obj_remap.c +30 -9
  40. data/ext/ca_obj_repeat.c +9 -10
  41. data/ext/ca_obj_roll.c +6 -5
  42. data/ext/ca_obj_select.c +14 -9
  43. data/ext/ca_obj_select_axis.c +15 -47
  44. data/ext/ca_obj_shift.c +11 -1
  45. data/ext/ca_obj_stack.c +179 -34
  46. data/ext/ca_obj_stride.c +162 -115
  47. data/ext/ca_obj_string.c +71 -4
  48. data/ext/ca_obj_tile.c +6 -5
  49. data/ext/ca_obj_time.c +22 -6
  50. data/ext/ca_obj_timedelta.c +22 -6
  51. data/ext/ca_obj_transpose.c +5 -3
  52. data/ext/ca_obj_triop.c +23 -32
  53. data/ext/ca_obj_window.c +190 -26
  54. data/ext/ca_sweep_engine.c +2 -2
  55. data/ext/caframe_csv_reader.c +80 -1
  56. data/ext/carray.h +181 -75
  57. data/ext/carray_access.c +184 -96
  58. data/ext/carray_address_basis.c +343 -87
  59. data/ext/carray_attribute.c +89 -6
  60. data/ext/carray_bincount.c +10 -8
  61. data/ext/carray_broadcast.c +13 -8
  62. data/ext/carray_build_flags.h +3 -0
  63. data/ext/carray_call_cfunc.c +108 -0
  64. data/ext/carray_cast.c +142 -24
  65. data/ext/carray_cast_func.rb +46 -6
  66. data/ext/carray_class.c +4 -3
  67. data/ext/carray_config.h +28 -0
  68. data/ext/carray_conversion.c +16 -7
  69. data/ext/carray_copy.c +51 -14
  70. data/ext/carray_core.c +147 -55
  71. data/ext/carray_count.c +50 -20
  72. data/ext/carray_element.c +76 -33
  73. data/ext/carray_factorize.c +118 -64
  74. data/ext/carray_generate.c +191 -50
  75. data/ext/carray_histogram.c +62 -17
  76. data/ext/carray_hold.c +12 -15
  77. data/ext/carray_index_classifier.c +388 -176
  78. data/ext/carray_internal.h +336 -29
  79. data/ext/carray_kernels_bincmp.c +4453 -0
  80. data/ext/carray_kernels_binop.c +11368 -0
  81. data/ext/carray_kernels_init.c +1734 -0
  82. data/ext/carray_kernels_moncmp.c +2104 -0
  83. data/ext/carray_kernels_monop.c +18369 -0
  84. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  85. data/ext/carray_kernels_reduce_boolean.c +406 -0
  86. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  87. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  88. data/ext/carray_kernels_reduce_variance.c +3849 -0
  89. data/ext/carray_kernels_scan.c +4302 -0
  90. data/ext/carray_kernels_search.c +33829 -0
  91. data/ext/carray_kernels_sort.c +10906 -0
  92. data/ext/carray_kernels_triop.c +1864 -0
  93. data/ext/carray_key_windows.c +216 -0
  94. data/ext/carray_lazy.c +170 -111
  95. data/ext/carray_mask.c +292 -72
  96. data/ext/carray_median_percentile.c +82 -28
  97. data/ext/carray_memory_view.c +669 -561
  98. data/ext/carray_operator.c +124 -47
  99. data/ext/carray_order.c +384 -76
  100. data/ext/carray_partition.c +28 -27
  101. data/ext/carray_random.c +67 -13
  102. data/ext/carray_round.c +273 -0
  103. data/ext/carray_scatter.c +63 -38
  104. data/ext/carray_segment.c +3 -3
  105. data/ext/carray_slab.c +91 -28
  106. data/ext/carray_sort.c +35 -35
  107. data/ext/carray_struct.c +19 -18
  108. data/ext/carray_test.c +26 -5
  109. data/ext/carray_undef.c +4 -0
  110. data/ext/carray_utils.c +246 -45
  111. data/ext/mk_call_cfunc.rb +19 -2
  112. data/ext/mkkernel.rb +198 -240
  113. data/ext/ruby_carray.c +10 -4
  114. data/ext/version.h +4 -4
  115. data/lib/carray/attribute.rb +126 -22
  116. data/lib/carray/autoload_carray.rb +8 -31
  117. data/lib/carray/autoload_method_extension.rb +14 -5
  118. data/lib/carray/axis_group.rb +255 -106
  119. data/lib/carray/basics.rb +78 -10
  120. data/lib/carray/bincount_nd.rb +12 -2
  121. data/lib/carray/block_iterator.rb +126 -23
  122. data/lib/carray/boolean_reduce.rb +17 -17
  123. data/lib/carray/categorical.rb +165 -43
  124. data/lib/carray/categorical_iterator.rb +130 -27
  125. data/lib/carray/complex.rb +5 -5
  126. data/lib/carray/conditional.rb +67 -18
  127. data/lib/carray/const_string.rb +14 -5
  128. data/lib/carray/construct.rb +15 -11
  129. data/lib/carray/data_type_extension.rb +1 -0
  130. data/lib/carray/distance_limit.rb +77 -0
  131. data/lib/carray/fixlen_string.rb +7 -1
  132. data/lib/carray/frame/column_verbs.rb +70 -0
  133. data/lib/carray/frame/convert.rb +69 -0
  134. data/lib/carray/frame/csv_parser.rb +111 -17
  135. data/lib/carray/frame/describe.rb +3 -2
  136. data/lib/carray/frame/frame.rb +246 -21
  137. data/lib/carray/frame/group.rb +510 -95
  138. data/lib/carray/frame/io.rb +115 -28
  139. data/lib/carray/frame/join.rb +312 -51
  140. data/lib/carray/frame/records.rb +83 -7
  141. data/lib/carray/frame/reshape.rb +42 -35
  142. data/lib/carray/frame/sort.rb +7 -19
  143. data/lib/carray/frame/verbs.rb +188 -48
  144. data/lib/carray/frame/windows.rb +117 -0
  145. data/lib/carray/frame.rb +2 -0
  146. data/lib/carray/fuse_source.rb +11 -4
  147. data/lib/carray/fusion.rb +40 -16
  148. data/lib/carray/histogram.rb +6 -1
  149. data/lib/carray/inspect.rb +31 -8
  150. data/lib/carray/iterator.rb +85 -7
  151. data/lib/carray/key_windows.rb +620 -0
  152. data/lib/carray/lazy.rb +182 -183
  153. data/lib/carray/mask_gap_fill.rb +63 -57
  154. data/lib/carray/meld_reduce.rb +12 -14
  155. data/lib/carray/methods/bin.rb +26 -18
  156. data/lib/carray/methods/bincount.rb +16 -0
  157. data/lib/carray/methods/bit_string.rb +1 -1
  158. data/lib/carray/methods/choose.rb +16 -3
  159. data/lib/carray/methods/composition.rb +3 -1
  160. data/lib/carray/methods/gather_nd.rb +14 -5
  161. data/lib/carray/methods/insert_block.rb +2 -2
  162. data/lib/carray/methods/is_between.rb +59 -0
  163. data/lib/carray/methods/is_in.rb +53 -36
  164. data/lib/carray/methods/join.rb +1 -6
  165. data/lib/carray/methods/lag.rb +49 -0
  166. data/lib/carray/methods/locate_addr.rb +47 -51
  167. data/lib/carray/methods/mode.rb +1 -1
  168. data/lib/carray/methods/nunique.rb +11 -6
  169. data/lib/carray/methods/resize.rb +3 -3
  170. data/lib/carray/methods/value_counts.rb +4 -11
  171. data/lib/carray/record_order.rb +3 -3
  172. data/lib/carray/rng.rb +3 -0
  173. data/lib/carray/runtime.rb +53 -8
  174. data/lib/carray/segment_iterator.rb +313 -82
  175. data/lib/carray/serialize.rb +24 -10
  176. data/lib/carray/slab_iterator.rb +50 -0
  177. data/lib/carray/string.rb +105 -5
  178. data/lib/carray/string_operation_extension.rb +8 -1
  179. data/lib/carray/struct.rb +9 -21
  180. data/lib/carray/struct_builder.rb +19 -8
  181. data/lib/carray/time.rb +726 -104
  182. data/lib/carray/window_iterator.rb +122 -16
  183. data/lib/carray.rb +7 -0
  184. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  185. data/yard-stubs/ca_obj_field.rb +4 -0
  186. data/yard-stubs/ca_obj_grid.rb +21 -10
  187. data/yard-stubs/ca_obj_refer.rb +2 -1
  188. data/yard-stubs/ca_obj_roll.rb +2 -2
  189. data/yard-stubs/ca_obj_shift.rb +5 -1
  190. data/yard-stubs/ca_obj_tile.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +8 -3
  192. data/yard-stubs/carray_access.rb +6 -1
  193. data/yard-stubs/carray_attribute.rb +0 -5
  194. data/yard-stubs/carray_cast.rb +10 -0
  195. data/yard-stubs/carray_conversion.rb +2 -1
  196. data/yard-stubs/carray_copy.rb +4 -2
  197. data/yard-stubs/carray_count.rb +4 -4
  198. data/yard-stubs/carray_element.rb +10 -4
  199. data/yard-stubs/carray_generate.rb +21 -1
  200. data/yard-stubs/carray_mask.rb +26 -2
  201. data/yard-stubs/carray_math.rb +27 -1
  202. data/yard-stubs/carray_median_percentile.rb +5 -2
  203. data/yard-stubs/carray_memory_view.rb +40 -23
  204. data/yard-stubs/carray_order.rb +29 -18
  205. data/yard-stubs/carray_random.rb +13 -4
  206. data/yard-stubs/carray_scatter.rb +14 -9
  207. data/yard-stubs/carray_slab.rb +9 -2
  208. data/yard-stubs/carray_sort.rb +6 -5
  209. data/yard-stubs/carray_test.rb +5 -3
  210. metadata +25 -3
  211. data/lib/carray/arrow_tensor.rb +0 -401
  212. data/lib/carray/table.rb +0 -108
data/ext/ruby_carray.c CHANGED
@@ -38,6 +38,7 @@ 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 ();
@@ -60,6 +61,7 @@ void Init_carray_median_percentile (); /* median / percentile / quantile */
60
61
  void Init_carray_sort (); /* sort / sort_copy / sort_addr / axis2addr */
61
62
  void Init_carray_count ();
62
63
  void Init_carray_kernels (); /* mkkernel-generated: reductions + maps */
64
+ void Init_carray_round ();
63
65
  void Init_carray_utils ();
64
66
  void Init_carray_generate ();
65
67
  void Init_carray_copy ();
@@ -183,13 +185,13 @@ Init_carray_ext (void)
183
185
  /* The flags this build's arithmetic was compiled with. Anything that
184
186
  computes what these kernels compute, somewhere other than in them, has
185
187
  to be built the same way to arrive at the same answer. */
186
- rb_define_const(rb_cCArray, "BUILD_FLAGS", rb_str_new2(CA_BUILD_FLAGS));
187
- 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)));
188
190
  rb_define_const(rb_cCArray, "VERSION_CODE", INT2NUM(CA_VERSION_CODE));
189
191
  rb_define_const(rb_cCArray, "VERSION_MAJOR", INT2NUM(CA_VERSION_MAJOR));
190
192
  rb_define_const(rb_cCArray, "VERSION_MINOR", INT2NUM(CA_VERSION_MINOR));
191
193
  rb_define_const(rb_cCArray, "VERSION_TEENY", INT2NUM(CA_VERSION_TEENY));
192
- 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)));
193
195
 
194
196
  /* -- system -- */
195
197
  rb_define_const(rb_cObject, "CA_RANK_MAX", INT2NUM(CA_RANK_MAX));
@@ -199,8 +201,10 @@ Init_carray_ext (void)
199
201
  absence. C code only ever compares against it; the value is never
200
202
  read and must never be passed in from Ruby. The constant exists to
201
203
  anchor the object against the GC. */
202
- CA_UNSPECIFIED = rb_funcall(rb_cObject, rb_intern("new"), 0);
204
+ CA_UNSPECIFIED = rb_obj_freeze(rb_funcall(rb_cObject, rb_intern("new"), 0));
203
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);
204
208
 
205
209
  #ifdef HAVE_COMPLEX_H
206
210
  /* @private */
@@ -284,6 +288,7 @@ Init_carray_ext (void)
284
288
  Init_carray_undef();
285
289
  Init_carray_mask();
286
290
  Init_carray_hold();
291
+ Init_carray_key_windows();
287
292
  Init_carray_loop();
288
293
  Init_carray_access();
289
294
  Init_carray_index_classifier();
@@ -308,6 +313,7 @@ Init_carray_ext (void)
308
313
  Init_carray_sort(); /* sort / sort_copy / sort_addr / axis2addr */
309
314
  Init_carray_count();
310
315
  Init_carray_kernels(); /* mkkernel-generated: reductions + maps */
316
+ Init_carray_round(); /* round(ndigits); after the generated round */
311
317
 
312
318
  Init_carray_utils();
313
319
 
data/ext/version.h CHANGED
@@ -1,6 +1,6 @@
1
- #define CA_VERSION "3.0.3"
2
- #define CA_VERSION_CODE 30003
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 3
6
- #define CA_VERSION_DATE "2026/10/13"
5
+ #define CA_VERSION_TEENY 4
6
+ #define CA_VERSION_DATE "2026/10/19"
@@ -31,11 +31,35 @@
31
31
  # The walk stops at a lazy operation view (CAMonOp / CABinOp /
32
32
  # CATriOp / CAMonCmp / CABinCmp): its cells are computed, not the
33
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.
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.
35
44
  #
36
- # Copies: `copy` and `to_type` give the new array the attributes the
37
- # source shows, as its own Hash. Arithmetic and reductions do not
38
- # carry them -- the result is a different quantity.
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.
39
63
 
40
64
  class CArray
41
65
 
@@ -63,9 +87,15 @@ class CArray
63
87
  # store.
64
88
  # @param key [Symbol, String] attribute key.
65
89
  # @param value [Object] JSON-compatible value.
66
- # @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.
67
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.
68
97
  def set_attr (key, value)
98
+ attr_check_writable
69
99
  attr_validate_value(value)
70
100
  (@attr ||= {})[attr_normalize_key(key)] = attr_coerce_value(value)
71
101
  end
@@ -79,7 +109,11 @@ class CArray
79
109
  # @param hash [Hash{Symbol, String => Object}] attributes to set.
80
110
  # @return [CArray] self.
81
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.
82
115
  def set_attrs (hash)
116
+ attr_check_writable
83
117
  unless hash.is_a?(Hash)
84
118
  raise TypeError, "set_attrs takes a Hash (got #{hash.class})"
85
119
  end
@@ -94,8 +128,23 @@ class CArray
94
128
  self
95
129
  end
96
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
+
97
146
  # @overload attrs
98
- # Returns a frozen shallow Hash of all attributes visible on
147
+ # Returns a frozen Hash of all attributes visible on
99
148
  # `self`, merged along the parent chain (deeper writes shadow
100
149
  # shallower ones on a per-key basis).
101
150
  # @return [Hash{String => Object}]
@@ -135,32 +184,85 @@ class CArray
135
184
  private
136
185
 
137
186
  # Yield each non-nil @attr Hash along the parent chain (self first).
138
- # Bounded to MAX_CHAIN_DEPTH for paranoia against unexpected cycles;
139
- # real CArray view chains rarely exceed a handful of levels.
140
- MAX_CHAIN_DEPTH = 64
141
- private_constant :MAX_CHAIN_DEPTH
142
-
187
+ # The chain has no fixed bound; an array seen twice ends the walk.
143
188
  def attr_each_chain
144
189
  ca = self
145
- MAX_CHAIN_DEPTH.times do
190
+ seen = nil
191
+ loop do
146
192
  if ca.instance_variable_defined?(:@attr)
147
193
  h = ca.instance_variable_get(:@attr)
148
194
  yield(h) if h
149
195
  end
150
196
  return nil if attr_computing_view?(ca)
151
- parent = ca.respond_to?(:parent) ? ca.parent : nil
152
- return nil if parent.nil? || parent.equal?(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
153
207
  ca = parent
154
208
  end
155
- nil
156
209
  end
157
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
+
158
245
  def attr_computing_view? (ca)
159
- ca.is_a?(CAMonOp) || ca.is_a?(CABinOp) || ca.is_a?(CATriOp) ||
246
+ return ca.__op_id__ < CAMonOp::CAST_BASE if ca.is_a?(CAMonOp)
247
+ ca.is_a?(CABinOp) || ca.is_a?(CATriOp) ||
160
248
  ca.is_a?(CAMonCmp) || ca.is_a?(CABinCmp)
161
249
  end
162
250
 
163
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)
164
266
  case key
165
267
  when String then key
166
268
  when Symbol then key.to_s
@@ -169,7 +271,7 @@ class CArray
169
271
  end
170
272
  end
171
273
 
172
- def attr_validate_value (v, depth = 0)
274
+ def self.attr_validate_value (v, depth = 0)
173
275
  raise ArgumentError, "attribute value nests too deep" if depth > 32
174
276
  case v
175
277
  when String, Integer, Float, true, false, nil, Symbol
@@ -189,17 +291,19 @@ class CArray
189
291
  end
190
292
  end
191
293
 
192
- def attr_coerce_value (v)
294
+ def self.attr_coerce_value (v)
193
295
  case v
194
- when Symbol then v.to_s
195
- 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
196
299
  when Hash
197
300
  v.each_with_object({}) do |(k, vv), h|
198
- h[k.is_a?(Symbol) ? k.to_s : k] = attr_coerce_value(vv)
199
- end
301
+ h[(k.is_a?(Symbol) ? k.to_s : k.dup).freeze] = attr_coerce_value(vv)
302
+ end.freeze
200
303
  else
201
304
  v
202
305
  end
203
306
  end
307
+ private_class_method :attr_normalize_key, :attr_validate_value, :attr_coerce_value
204
308
 
205
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
@@ -64,21 +49,6 @@ class CARecord
64
49
  autoload_method "marshal_dump", "carray/serialize"
65
50
  end
66
51
 
67
- # ---- Arrow tensor IPC (interop) --------------------------------------------
68
-
69
- class CArray
70
- arrow_tensor_rb = "carray/arrow_tensor"
71
- autoload :ArrowTensor, arrow_tensor_rb
72
- autoload_method "self.load_arrow_tensor", arrow_tensor_rb
73
- autoload_method "save_arrow_tensor", arrow_tensor_rb
74
- end
75
-
76
- # ---- Table (row-major dispatch helper) -------------------------------------
77
-
78
- class CArray
79
- autoload :TableMethods, "carray/table"
80
- end
81
-
82
52
  # ---- Fusion (reading a lazy expression as a plan) --------------------------
83
53
  #
84
54
  # Nothing in the core asks for a plan -- CArray can always walk the view --
@@ -101,6 +71,7 @@ end
101
71
 
102
72
  autoload :CASlabIterator, "carray/slab_iterator"
103
73
  autoload :CAWindowIterator, "carray/window_iterator"
74
+ autoload :CAKeyWindowIterator, "carray/key_windows"
104
75
  autoload :CABlockIterator, "carray/block_iterator"
105
76
 
106
77
  class CArray
@@ -174,6 +145,10 @@ autoload :CAUnion, "carray/struct"
174
145
  autoload :CAFrame, "carray/frame"
175
146
  autoload :GroupedFrame, "carray/frame"
176
147
 
148
+ class CArray
149
+ autoload_method "to_frame", "carray/frame"
150
+ end
151
+
177
152
  class CArray
178
153
  struct_rb = "carray/struct"
179
154
  autoload_method "self.struct", struct_rb
@@ -231,10 +206,12 @@ class CArray
231
206
  autoload_method "intersection", "carray/methods/is_in"
232
207
  autoload_method "difference", "carray/methods/is_in"
233
208
  autoload_method "union", "carray/methods/is_in"
209
+ autoload_method "is_between", "carray/methods/is_between"
234
210
  autoload_method "self.align_addr", "carray/methods/align_addr"
235
211
  autoload_method "self.align_nearest_addr", "carray/methods/align_addr"
236
212
  autoload_method "value_counts", "carray/methods/value_counts"
237
213
  autoload_method "nunique", "carray/methods/nunique"
214
+ autoload_method "lag", "carray/methods/lag"
238
215
  autoload_method "is_mode", "carray/methods/mode"
239
216
  autoload_method "mode", "carray/methods/mode"
240
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,14 +55,13 @@ 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))
56
65
  # The library replaces the stub with a plain `def`, which `ruby -w`
57
66
  # reports as a redefinition. Replacing is what the stub is for, so mark
58
67
  # it as aliased: Ruby does not warn when the old definition has an alias.