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/ca_compare.c CHANGED
@@ -14,6 +14,7 @@
14
14
  #include "ruby.h"
15
15
  #include "carray.h"
16
16
  #include "ca_compare.h"
17
+ #include "carray_internal.h" /* CA_FLOAT_ORDER_CMP, ca_obj_order_cmp */
17
18
  #include <math.h>
18
19
 
19
20
  #define DEFINE_ELEM_CMP(type) \
@@ -27,18 +28,14 @@ elem_cmp_## type (const void *va, const void *vb) \
27
28
  return 0; \
28
29
  }
29
30
 
30
- /* Float order: NaN sorts last (matches the sort kernels' NaN-at-end). */
31
+ /* Float order: NaN after every number (CA_FLOAT_ORDER_CMP). */
31
32
  #define DEFINE_ELEM_CMP_FLOAT(type) \
32
33
  static int \
33
34
  elem_cmp_## type (const void *va, const void *vb) \
34
35
  { \
35
- const type *a = (const type *) va; \
36
- const type *b = (const type *) vb; \
37
- if ( isnan(*a) && ( ! isnan(*b) ) ) return 1; \
38
- if ( isnan(*b) && ( ! isnan(*a) ) ) return -1; \
39
- if ( *a > *b ) return 1; \
40
- if ( *a < *b ) return -1; \
41
- return 0; \
36
+ const type a = *(const type *) va; \
37
+ const type b = *(const type *) vb; \
38
+ return CA_FLOAT_ORDER_CMP(a, b); \
42
39
  }
43
40
 
44
41
  DEFINE_ELEM_CMP(boolean8_t)
@@ -53,13 +50,11 @@ DEFINE_ELEM_CMP(uint64_t)
53
50
  DEFINE_ELEM_CMP_FLOAT(float32_t)
54
51
  DEFINE_ELEM_CMP_FLOAT(float64_t)
55
52
 
56
- /* CA_OBJECT: compare via Ruby Comparable (`<=>`). */
53
+ /* CA_OBJECT: the object order (ca_obj_order_cmp). */
57
54
  static int
58
55
  elem_cmp_VALUE (const void *va, const void *vb)
59
56
  {
60
- const VALUE *a = (const VALUE *) va;
61
- const VALUE *b = (const VALUE *) vb;
62
- return NUM2INT(rb_funcall(*a, rb_intern("<=>"), 1, *b));
57
+ return ca_obj_order_cmp(*(const VALUE *) va, *(const VALUE *) vb);
63
58
  }
64
59
 
65
60
  /* FIXLEN / retired / otherwise unorderable data_types: callers must handle
data/ext/ca_for_buffer.h CHANGED
@@ -1,43 +1,33 @@
1
1
  /* ---------------------------------------------------------------------------
2
2
  *
3
- * ca_for_buffer.h -- sweep WHOLE_BUFFER macro family (whole contig buffer
4
- * handed to author / third-party library)
3
+ * ca_for_buffer.h -- whole contig buffer handed to author / third-party
4
+ * library
5
5
  *
6
- * PROPOSAL_L0_AUTHOR_SURFACE L0.2c (2026-06-11). C-side counterpart of
7
- * Ruby's `ca.attach! { |a| ... }` block: scope the ca_attach + ca_sync +
8
- * ca_detach lifecycle to a block, hand the author a contig buffer ptr
9
- * and element count, let the author do whatever (typically pass the
10
- * ptr to a third-party library: FFTW, akima init, fitpack surf1, ...).
6
+ * C-side counterpart of Ruby's `ca.attach! { |a| ... }` block: the
7
+ * attach / sync / detach lifecycle is scoped to a body function, which
8
+ * receives a contig buffer ptr and element count and may do whatever
9
+ * (typically pass the ptr to a third-party library: FFTW, akima init,
10
+ * fitpack surf1, ...).
11
11
  *
12
- * Two forms (Q8 = M1 alias-when-possible; non-contig source materialises
13
- * into a transient buffer; writable form syncs back on exit):
12
+ * The buffer aliases ca->ptr when the array is a contig entity and is a
13
+ * materialised scratch otherwise. A writable call syncs the buffer back
14
+ * to the array's storage when the body returns.
14
15
  *
15
- * CA_WITH_BUFFER(ca, T, ptr, n)
16
- * Read-only access. ptr : T const * pointing at native contig
17
- * layout of `ca` (= ca->ptr alias when contig entity, scratch
18
- * otherwise). n : ca->elements. No write-back on exit.
19
- *
20
- * CA_WITH_BUFFER_WRITABLE(ca, T, ptr, n)
21
- * Writable; same ptr/n semantics, plus ca_sync on block exit so
22
- * author writes propagate back to the view's storage.
16
+ * The body may raise. The view is closed however the body is left: a
17
+ * writable view is synced first, so what the body wrote before raising
18
+ * reaches the view's storage, and the view is detached even if that sync
19
+ * raises. The body's exception is the one that propagates.
23
20
  *
24
21
  * Author pattern:
25
22
  *
26
- * double *ptr;
27
- * ca_size_t n;
28
- * CA_WITH_BUFFER_WRITABLE(ca, double, ptr, n) {
23
+ * static void
24
+ * fft_body (void *user_data, void *ptr, ca_size_t n)
25
+ * {
26
+ * fftw_plan plan = (fftw_plan) user_data;
29
27
  * fftw_execute_dft(plan, ptr, ptr);
30
28
  * }
31
29
  *
32
- * Constraints (same as CA_FOR_EACH_FIBER family):
33
- * - `break;` from body exits cleanly (= outer for's advance clause
34
- * runs ca_sync / ca_detach).
35
- * - `return;` from body LEAKS the attach; restructure to break.
36
- * - Macros are NOT statement-equivalent (= nested for); no trailing
37
- * `else`.
38
- * - For Ruby-exception-safe lifecycle (e.g. when calling Ruby code or
39
- * anything that may raise from inside the body), use the function
40
- * form `rb_ca_call_with_buffer` instead (= rb_ensure-protected).
30
+ * rb_ca_call_with_buffer(rca, 1, fft_body, plan);
41
31
  *
42
32
  * --------------------------------------------------------------------------- */
43
33
 
@@ -47,46 +37,9 @@
47
37
  #include "carray.h"
48
38
  #include "ca_sweep_engine.h"
49
39
 
50
- /* ---------- macro forms ---------- */
51
-
52
- /* Read-only: ca_attach (alias-when-possible) + author body + ca_detach. */
53
- #define CA_WITH_BUFFER(_ca, T, _ptr, _n) \
54
- for ( CArray *__cwv_ca = (CArray *)(_ca); \
55
- __cwv_ca; \
56
- ca_detach(__cwv_ca), __cwv_ca = NULL ) \
57
- for ( int __cwv_once = (ca_attach(__cwv_ca), \
58
- (_ptr) = (T *)__cwv_ca->ptr, \
59
- (_n) = __cwv_ca->elements, \
60
- 1); \
61
- __cwv_once; \
62
- __cwv_once = 0 )
63
-
64
- /* Writable: same as above + ca_sync on block exit. */
65
- #define CA_WITH_BUFFER_WRITABLE(_ca, T, _ptr, _n) \
66
- for ( CArray *__cwvw_ca = (CArray *)(_ca); \
67
- __cwvw_ca; \
68
- ca_sync(__cwvw_ca), ca_detach(__cwvw_ca), __cwvw_ca = NULL ) \
69
- for ( int __cwvw_once = (ca_attach(__cwvw_ca), \
70
- (_ptr) = (T *)__cwvw_ca->ptr, \
71
- (_n) = __cwvw_ca->elements, \
72
- 1); \
73
- __cwvw_once; \
74
- __cwvw_once = 0 )
75
-
76
- /* ---------- function form (rb_ensure-protected, AC8) ----------
77
- *
78
- * Use this when the body may raise a Ruby exception (= calling rb_funcall,
79
- * type-checking with rb_check_type, indirect Ruby code, etc.). The
80
- * engine ca_attach's the view, runs body via rb_ensure, then guarantees
81
- * ca_sync (if writable) and ca_detach run before the exception
82
- * propagates.
83
- *
84
- * body_fn(user_data, ptr, n_elements) -> may raise
40
+ /* body_fn(user_data, ptr, n_elements) -> may raise
85
41
  *
86
- * Returns whatever body_fn returns via its own propagation (= the
87
- * function itself returns Qnil since rb_ensure body must be VALUE).
88
- * For richer return semantics, box your result in user_data.
89
- */
42
+ * Returns nothing; box a result in user_data. */
90
43
  typedef void (*ca_with_buffer_body_fn) (void *user_data, void *ptr,
91
44
  ca_size_t n_elements);
92
45
 
data/ext/ca_group_iter.c CHANGED
@@ -14,13 +14,14 @@
14
14
  Split summary:
15
15
  - ca_argv_has_group / rb_ca_fetch_group : here (called by carray_access.c)
16
16
  - CAGroupIterator + the tier-1 reduction methods driving
17
- __axis_group_reduce__ : here
17
+ __reduce_by_axis_groups__ : here
18
18
  - reduce_plan / bundle assembly / output-axis permutation (metadata) : Ruby
19
- - the O(N) compute kernel __axis_group_reduce__ : ca_axis_group.c
19
+ - the O(N) compute kernel __reduce_by_axis_groups__ : ca_axis_group.c
20
20
 
21
21
  --------------------------------------------------------------------------- */
22
22
 
23
23
  #include "carray.h"
24
+ #include "carray_internal.h" /* ca_check_rank_fits */
24
25
 
25
26
  /* lib/carray/axis_group.rb registers these classes here on first load (and
26
27
  loading is wired so that load happens as soon as any categorical exists —
@@ -34,16 +35,20 @@ static VALUE rb_cCAGroupIterator = Qnil;
34
35
  static ID id_value, id_spec, id_axis_group, id_reduce_plan, id_parse_axis;
35
36
  static ID id_axis_group_reduce, id_reshape, id_transpose, id_labels;
36
37
 
37
- /* CArray.__register_axis_group_classes__(CACategorical, AxisGroup) — called
38
+ /* CArray.register_axis_group_classes(CACategorical, AxisGroup) — called
38
39
  from the top of lib/carray/axis_group.rb so the C type gate can recognise
39
40
  the classifier/spec types without triggering autoload on every [] call. */
40
41
  static VALUE
41
42
  rb_ca_register_axis_group_classes (VALUE klass, VALUE cat, VALUE ag)
42
43
  {
44
+ static int registered = 0;
43
45
  rb_cCategorical = cat;
44
46
  rb_cAxisGroup = ag;
45
- rb_gc_register_address(&rb_cCategorical);
46
- rb_gc_register_address(&rb_cAxisGroup);
47
+ if ( ! registered ) { /* one GC root per address, not per call */
48
+ rb_gc_register_address(&rb_cCategorical);
49
+ rb_gc_register_address(&rb_cAxisGroup);
50
+ registered = 1;
51
+ }
47
52
  return Qnil;
48
53
  }
49
54
 
@@ -116,7 +121,7 @@ rb_ca_fetch_group (int argc, VALUE *argv, VALUE self)
116
121
  validates the slot layout = one slot per source axis). */
117
122
  spec = rb_funcallv(self, id_axis_group, argc, argv);
118
123
  }
119
- return rb_funcall(rb_cCAGroupIterator, rb_intern("__build__"), 2, self, spec);
124
+ return rb_funcall(rb_cCAGroupIterator, rb_intern("build_for"), 2, self, spec);
120
125
  }
121
126
 
122
127
  /* --- CAGroupIterator -------------------------------------------------------
@@ -171,9 +176,7 @@ group_iter_shape_output (VALUE result, VALUE group_dims, VALUE perm, VALUE squee
171
176
  ng = RARRAY_LEN(group_dims);
172
177
  nband = cr->ndim - 1;
173
178
  nd = ng + nband;
174
- if ( nd > CA_RANK_MAX ) {
175
- rb_raise(rb_eRuntimeError, "axis_group: output ndim %ld too large", nd);
176
- }
179
+ ca_check_rank_fits(nd, "axis_group");
177
180
  for ( i = 0; i < ng; i++ ) {
178
181
  dims[i] = RARRAY_AREF(group_dims, i);
179
182
  }
@@ -215,7 +218,7 @@ group_iter_shape_output (VALUE result, VALUE group_dims, VALUE perm, VALUE squee
215
218
  static VALUE
216
219
  group_iter_reduce (int argc, VALUE *argv, VALUE self)
217
220
  {
218
- ID op_id = rb_frame_this_func();
221
+ ID op_id = rb_frame_this_func(); /* frame-name: picks the op, names no error */
219
222
  VALUE op_sym = ID2SYM(op_id);
220
223
  VALUE value = rb_ivar_get(self, id_value);
221
224
  VALUE spec = rb_ivar_get(self, id_spec);
@@ -233,17 +236,19 @@ group_iter_reduce (int argc, VALUE *argv, VALUE self)
233
236
  parsed = rb_funcall(rb_cAxisGroup, id_parse_axis,
234
237
  1, (vaxis == Qundef) ? Qnil : vaxis);
235
238
  if ( RTEST(RARRAY_AREF(parsed, 0)) == 0 ) {
236
- /* no :group -> plain reduction on the value (grouping not engaged) */
237
- if ( vaxis == Qundef ) {
239
+ /* no :group -> plain reduction on the value (grouping not engaged),
240
+ with every keyword the caller gave */
241
+ if ( NIL_P(kw) ) {
238
242
  return rb_funcall(value, op_id, 0);
239
243
  }
240
- else {
241
- VALUE h = rb_hash_new();
242
- rb_hash_aset(h, ID2SYM(rb_intern("axis")), vaxis);
243
- return rb_funcallv_kw(value, op_id, 1, &h, RB_PASS_KEYWORDS);
244
- }
244
+ return rb_funcallv_kw(value, op_id, 1, &kw, RB_PASS_KEYWORDS);
245
245
  }
246
246
 
247
+ /* min_count: / fill_value: are applied to the grouped result; any other
248
+ keyword is refused before the work is done. */
249
+ rb_funcall(self, rb_intern("check_reduce_keywords"), 2,
250
+ op_sym, NIL_P(kw) ? rb_hash_new() : kw);
251
+
247
252
  /* group reduction */
248
253
  fused = RARRAY_AREF(parsed, 1);
249
254
  plan = rb_funcall(spec, id_reduce_plan, 1, fused);
@@ -253,9 +258,19 @@ group_iter_reduce (int argc, VALUE *argv, VALUE self)
253
258
  perm = RARRAY_AREF(plan, 3);
254
259
  squeeze = RARRAY_AREF(plan, 4);
255
260
 
261
+ /* a count reads only the mask, so a payload the kernel cannot read
262
+ (object, fixlen, ...) is counted through a boolean stand-in */
263
+ if ( op_id == rb_intern("count") || op_id == rb_intern("count_not_masked") ) {
264
+ value = rb_funcall(rb_cAxisGroup, rb_intern("count_stand_in"), 1, value);
265
+ }
256
266
  result = rb_funcall(value, id_axis_group_reduce, 3,
257
267
  group_axes, bundles, op_sym);
258
- return group_iter_shape_output(result, group_dims, perm, squeeze);
268
+ result = group_iter_shape_output(result, group_dims, perm, squeeze);
269
+ if ( ! NIL_P(kw) ) {
270
+ result = rb_funcall(self, rb_intern("finish_reduction"), 3,
271
+ op_sym, kw, result);
272
+ }
273
+ return result;
259
274
  }
260
275
 
261
276
  void
@@ -266,21 +281,21 @@ Init_ca_group_iter (void)
266
281
  id_axis_group = rb_intern("axis_group");
267
282
  id_reduce_plan = rb_intern("reduce_plan");
268
283
  id_parse_axis = rb_intern("parse_axis");
269
- id_axis_group_reduce = rb_intern("__axis_group_reduce__");
284
+ id_axis_group_reduce = rb_intern("__reduce_by_axis_groups__");
270
285
  id_reshape = rb_intern("reshape");
271
286
  id_transpose = rb_intern("transpose");
272
287
  id_labels = rb_intern("labels");
273
288
 
274
- rb_define_singleton_method(rb_cCArray, "__register_axis_group_classes__",
275
- rb_ca_register_axis_group_classes, 2);
289
+ rb_define_private_method(rb_singleton_class(rb_cCArray), "register_axis_group_classes",
290
+ rb_ca_register_axis_group_classes, 2);
276
291
 
277
292
  rb_cCAGroupIterator =
278
293
  rb_define_class("CAGroupIterator",
279
294
  rb_const_get(rb_cObject, rb_intern("CAIterator")));
280
295
  rb_gc_register_address(&rb_cCAGroupIterator);
281
296
 
282
- rb_define_singleton_method(rb_cCAGroupIterator, "__build__",
283
- rb_ca_group_iter_build, 2);
297
+ rb_define_private_method(rb_singleton_class(rb_cCAGroupIterator), "build_for",
298
+ rb_ca_group_iter_build, 2);
284
299
  rb_define_method(rb_cCAGroupIterator, "value", rb_ca_group_iter_value, 0);
285
300
  rb_define_method(rb_cCAGroupIterator, "spec", rb_ca_group_iter_spec, 0);
286
301
  rb_define_method(rb_cCAGroupIterator, "labels", rb_ca_group_iter_labels, -1);