carray 3.0.1 → 3.0.3

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 (229) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +824 -0
  3. data/README.md +5 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +258 -4
  6. data/ext/ca_axis_group.c +368 -184
  7. data/ext/ca_binop_dispatch.c +54 -32
  8. data/ext/ca_binop_dispatch.h +1 -0
  9. data/ext/ca_categorical_iterator.c +90 -41
  10. data/ext/ca_compare.c +8 -2
  11. data/ext/ca_for_buffer.h +21 -68
  12. data/ext/ca_group_iter.c +27 -11
  13. data/ext/ca_kernel_iterator.c +960 -245
  14. data/ext/ca_kernel_iterator.h +352 -181
  15. data/ext/ca_monop_dispatch.c +4 -4
  16. data/ext/ca_monop_dispatch.h +4 -0
  17. data/ext/ca_obj_array.c +194 -42
  18. data/ext/ca_obj_bincmp.c +152 -121
  19. data/ext/ca_obj_binop.c +107 -210
  20. data/ext/ca_obj_bitarray.c +37 -24
  21. data/ext/ca_obj_bitfield.c +95 -62
  22. data/ext/ca_obj_block.c +5 -4
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +180 -50
  25. data/ext/ca_obj_face.c +428 -62
  26. data/ext/ca_obj_face.h +107 -47
  27. data/ext/ca_obj_fake.c +21 -50
  28. data/ext/ca_obj_farray.c +1 -0
  29. data/ext/ca_obj_field.c +16 -3
  30. data/ext/ca_obj_fixlen_string.c +39 -26
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +235 -55
  33. data/ext/ca_obj_moncmp.c +61 -61
  34. data/ext/ca_obj_monop.c +125 -107
  35. data/ext/ca_obj_object.c +551 -233
  36. data/ext/ca_obj_record.c +51 -16
  37. data/ext/ca_obj_reduce.c +5 -8
  38. data/ext/ca_obj_refer.c +117 -33
  39. data/ext/ca_obj_remap.c +57 -17
  40. data/ext/ca_obj_repeat.c +21 -5
  41. data/ext/ca_obj_roll.c +115 -11
  42. data/ext/ca_obj_select.c +88 -75
  43. data/ext/ca_obj_select_axis.c +58 -60
  44. data/ext/ca_obj_shift.c +22 -102
  45. data/ext/ca_obj_stack.c +223 -123
  46. data/ext/ca_obj_stride.c +267 -35
  47. data/ext/ca_obj_string.c +25 -22
  48. data/ext/ca_obj_tile.c +32 -16
  49. data/ext/ca_obj_time.c +23 -25
  50. data/ext/ca_obj_timedelta.c +21 -23
  51. data/ext/ca_obj_transpose.c +12 -3
  52. data/ext/ca_obj_triop.c +110 -117
  53. data/ext/ca_obj_window.c +157 -29
  54. data/ext/ca_op_ipower.c +25 -13
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_rng_normal.h +42 -0
  58. data/ext/ca_rng_xoshiro256pp.h +105 -0
  59. data/ext/ca_sort_kernels.h +70 -0
  60. data/ext/ca_sweep_engine.c +385 -198
  61. data/ext/ca_sweep_engine.h +31 -23
  62. data/ext/ca_triop_dispatch.c +4 -1
  63. data/ext/ca_triop_dispatch.h +5 -2
  64. data/ext/caframe_csv_reader.c +463 -0
  65. data/ext/carray.h +90 -28
  66. data/ext/carray_access.c +487 -231
  67. data/ext/carray_address_basis.c +731 -0
  68. data/ext/carray_attribute.c +45 -3
  69. data/ext/carray_bincount.c +32 -2
  70. data/ext/carray_broadcast.c +49 -17
  71. data/ext/carray_call_cfunc.c +667 -511
  72. data/ext/carray_cast.c +1556 -247
  73. data/ext/carray_cast_func.rb +34 -21
  74. data/ext/carray_conversion.c +197 -73
  75. data/ext/carray_copy.c +84 -38
  76. data/ext/carray_core.c +591 -119
  77. data/ext/carray_count.c +148 -96
  78. data/ext/carray_element.c +18 -27
  79. data/ext/carray_factorize.c +604 -291
  80. data/ext/carray_generate.c +76 -40
  81. data/ext/carray_histogram.c +152 -94
  82. data/ext/carray_hold.c +2 -1
  83. data/ext/carray_index_classifier.c +63 -96
  84. data/ext/carray_internal.h +400 -1
  85. data/ext/carray_lazy.c +834 -79
  86. data/ext/carray_loop.c +88 -66
  87. data/ext/carray_mask.c +705 -324
  88. data/ext/carray_math_kernel.h +1 -0
  89. data/ext/carray_median_percentile.c +263 -63
  90. data/ext/carray_memory_view.c +254 -248
  91. data/ext/carray_operator.c +1093 -363
  92. data/ext/carray_order.c +133 -69
  93. data/ext/carray_partition.c +102 -56
  94. data/ext/carray_random.c +582 -204
  95. data/ext/carray_scatter.c +308 -65
  96. data/ext/carray_segment.c +257 -0
  97. data/ext/carray_slab.c +183 -70
  98. data/ext/carray_sort.c +235 -240
  99. data/ext/carray_sort_kernel.c +8 -1
  100. data/ext/carray_struct.c +99 -21
  101. data/ext/carray_test.c +167 -64
  102. data/ext/carray_time_text.c +1182 -0
  103. data/ext/carray_utils.c +363 -98
  104. data/ext/extconf.rb +27 -2
  105. data/ext/mk_call_cfunc.rb +103 -118
  106. data/ext/mk_pow5_table.rb +35 -0
  107. data/ext/mkkernel.rb +1349 -851
  108. data/ext/ruby_carray.c +17 -2
  109. data/ext/version.h +4 -4
  110. data/ext/version.rb +4 -2
  111. data/lib/carray/attribute.rb +39 -0
  112. data/lib/carray/autoload_carray.rb +24 -3
  113. data/lib/carray/autoload_method_extension.rb +18 -0
  114. data/lib/carray/axis_group.rb +245 -20
  115. data/lib/carray/basics.rb +95 -25
  116. data/lib/carray/bincount_nd.rb +6 -0
  117. data/lib/carray/block_iterator.rb +200 -54
  118. data/lib/carray/boolean_reduce.rb +21 -29
  119. data/lib/carray/categorical.rb +244 -59
  120. data/lib/carray/categorical_iterator.rb +391 -757
  121. data/lib/carray/complex.rb +36 -29
  122. data/lib/carray/conditional.rb +94 -7
  123. data/lib/carray/const_string.rb +177 -27
  124. data/lib/carray/construct.rb +40 -0
  125. data/lib/carray/data_type_extension.rb +3 -0
  126. data/lib/carray/data_type_limits.rb +91 -0
  127. data/lib/carray/fixlen_string.rb +1 -1
  128. data/lib/carray/frame/concat.rb +157 -6
  129. data/lib/carray/frame/convert.rb +13 -7
  130. data/lib/carray/frame/csv_parser.rb +590 -76
  131. data/lib/carray/frame/describe.rb +79 -0
  132. data/lib/carray/frame/frame.rb +205 -35
  133. data/lib/carray/frame/group.rb +199 -40
  134. data/lib/carray/frame/io.rb +452 -60
  135. data/lib/carray/frame/join.rb +134 -46
  136. data/lib/carray/frame/records.rb +54 -19
  137. data/lib/carray/frame/reshape.rb +448 -0
  138. data/lib/carray/frame/sort.rb +26 -2
  139. data/lib/carray/frame/verbs.rb +726 -56
  140. data/lib/carray/frame.rb +2 -0
  141. data/lib/carray/fuse_source.rb +111 -2
  142. data/lib/carray/fusion.rb +229 -38
  143. data/lib/carray/inspect.rb +71 -20
  144. data/lib/carray/iterator.rb +157 -2
  145. data/lib/carray/lazy.rb +54 -67
  146. data/lib/carray/mask_gap_fill.rb +66 -50
  147. data/lib/carray/math.rb +32 -19
  148. data/lib/carray/meld_reduce.rb +40 -7
  149. data/lib/carray/methods/align_addr.rb +8 -4
  150. data/lib/carray/methods/bincount.rb +2 -2
  151. data/lib/carray/methods/bit_string.rb +14 -3
  152. data/lib/carray/methods/composition.rb +16 -10
  153. data/lib/carray/methods/discovery_along.rb +74 -0
  154. data/lib/carray/methods/factorize.rb +50 -0
  155. data/lib/carray/methods/gather_nd.rb +13 -2
  156. data/lib/carray/methods/insert_block.rb +9 -14
  157. data/lib/carray/methods/is_in.rb +130 -6
  158. data/lib/carray/methods/join.rb +1 -1
  159. data/lib/carray/methods/locate_addr.rb +235 -21
  160. data/lib/carray/methods/mask_duplicates.rb +35 -1
  161. data/lib/carray/methods/mode.rb +18 -1
  162. data/lib/carray/methods/nunique.rb +22 -1
  163. data/lib/carray/methods/repeat.rb +91 -0
  164. data/lib/carray/methods/resize.rb +21 -23
  165. data/lib/carray/methods/snap.rb +34 -12
  166. data/lib/carray/methods/unique.rb +52 -3
  167. data/lib/carray/record_order.rb +208 -0
  168. data/lib/carray/rng.rb +86 -0
  169. data/lib/carray/runtime.rb +14 -11
  170. data/lib/carray/segment_iterator.rb +990 -0
  171. data/lib/carray/serialize.rb +197 -27
  172. data/lib/carray/slab_iterator.rb +109 -40
  173. data/lib/carray/stack.rb +10 -4
  174. data/lib/carray/string_operation_extension.rb +9 -4
  175. data/lib/carray/struct.rb +142 -51
  176. data/lib/carray/struct_builder.rb +110 -14
  177. data/lib/carray/table.rb +2 -2
  178. data/lib/carray/time.rb +535 -105
  179. data/lib/carray/window_iterator.rb +259 -82
  180. data/lib/carray.rb +4 -2
  181. data/yard-stubs/ca_obj_array.rb +4 -4
  182. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  183. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  184. data/yard-stubs/ca_obj_block.rb +2 -7
  185. data/yard-stubs/ca_obj_fake.rb +1 -1
  186. data/yard-stubs/ca_obj_field.rb +1 -1
  187. data/yard-stubs/ca_obj_refer.rb +3 -3
  188. data/yard-stubs/ca_obj_roll.rb +0 -1
  189. data/yard-stubs/ca_obj_stride.rb +10 -7
  190. data/yard-stubs/ca_obj_transpose.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +11 -4
  192. data/yard-stubs/carray_access.rb +6 -5
  193. data/yard-stubs/carray_broadcast.rb +2 -2
  194. data/yard-stubs/carray_cast.rb +78 -43
  195. data/yard-stubs/carray_conversion.rb +13 -1
  196. data/yard-stubs/carray_copy.rb +8 -3
  197. data/yard-stubs/carray_core.rb +3 -83
  198. data/yard-stubs/carray_count.rb +16 -2
  199. data/yard-stubs/carray_lazy.rb +210 -1
  200. data/yard-stubs/carray_loop.rb +4 -1
  201. data/yard-stubs/carray_mask.rb +34 -10
  202. data/yard-stubs/carray_math.rb +1499 -4
  203. data/yard-stubs/carray_median_percentile.rb +26 -8
  204. data/yard-stubs/carray_order.rb +43 -82
  205. data/yard-stubs/carray_scatter.rb +10 -3
  206. data/yard-stubs/carray_segment.rb +72 -0
  207. data/yard-stubs/carray_slab.rb +11 -8
  208. data/yard-stubs/carray_sort.rb +50 -8
  209. data/yard-stubs/carray_test.rb +10 -0
  210. data/yard-stubs/carray_utils.rb +0 -26
  211. metadata +19 -19
  212. data/ext/ca_for_each_element.h +0 -239
  213. data/ext/carray_build_flags.h +0 -3
  214. data/ext/carray_config.h +0 -28
  215. data/ext/carray_kernels_bincmp.c +0 -4446
  216. data/ext/carray_kernels_binop.c +0 -11001
  217. data/ext/carray_kernels_init.c +0 -1131
  218. data/ext/carray_kernels_map.c +0 -3467
  219. data/ext/carray_kernels_moncmp.c +0 -2097
  220. data/ext/carray_kernels_monop.c +0 -18313
  221. data/ext/carray_kernels_reduce_aggregate.c +0 -25837
  222. data/ext/carray_kernels_reduce_boolean.c +0 -330
  223. data/ext/carray_kernels_reduce_cumulative.c +0 -14593
  224. data/ext/carray_kernels_reduce_extreme.c +0 -16948
  225. data/ext/carray_kernels_reduce_variance.c +0 -3910
  226. data/ext/carray_kernels_scan.c +0 -3693
  227. data/ext/carray_kernels_search.c +0 -32138
  228. data/ext/carray_kernels_sort.c +0 -10626
  229. data/ext/carray_kernels_triop.c +0 -1392
data/ext/carray_count.c CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  #include "ruby.h"
14
14
  #include "carray.h"
15
+ #include "carray_internal.h" /* ca_attach_window */
15
16
  #include "ca_obj_face.h"
16
17
  #include <math.h>
17
18
  #include <float.h>
@@ -39,11 +40,89 @@ VALUE rb_ca_count_not_masked (int argc, VALUE *argv, VALUE self);
39
40
  - v is a CArray -> broadcast: count each v[k] and stack
40
41
  (rejected for boolean self; see below)
41
42
  - self is boolean, v scalar -> v must be true/false literal
42
- - self is numeric, v scalar -> count_equal_ki (numeric equality)
43
+ - self is numeric or object, v scalar -> count_equal_ki (numeric ==
44
+ for a number, Ruby == for an object)
43
45
 
44
- FIXLEN and OBJECT data_types raise CArray::DataTypeError (the
45
- kernel-iterator helpers do not implement them). Extend
46
- count_equal_ki if demand returns. */
46
+ - self is fixlen, v scalar -> count_equal_ki (memcmp over the whole
47
+ cell; a short String query is padded
48
+ out to the cell width) */
49
+
50
+ static VALUE rb_ca_count (int argc, VALUE *argv, VALUE self);
51
+
52
+ /* count(v: CArray): the per-cell counts, run with v attached. */
53
+
54
+ typedef struct {
55
+ VALUE self;
56
+ VALUE rval;
57
+ CArray *cv;
58
+ CArray *cout;
59
+ ca_size_t base_elements;
60
+ int inner_argc;
61
+ VALUE *inner_axes;
62
+ volatile VALUE opt_hash;
63
+ } ca_count_each_ctx_t;
64
+
65
+ static VALUE
66
+ ca_count_each_body (VALUE arg)
67
+ {
68
+ ca_count_each_ctx_t *c = (ca_count_each_ctx_t *) arg;
69
+ CArray *cout = c->cout;
70
+ int64_t *out_ptr = (int64_t *) cout->ptr;
71
+ boolean8_t *out_mask = NULL;
72
+ ca_size_t v_elements = c->cv->elements;
73
+ ca_size_t base_elements = c->base_elements;
74
+ /* inner_argv layout: [vk_scalar, axis..., axis..., [opt_hash]]
75
+ inner_call_argc = 1 (vk) + inner_argc (axes) + (opt_hash ? 1 : 0). */
76
+ int inner_call_argc = 1 + c->inner_argc + (NIL_P(c->opt_hash) ? 0 : 1);
77
+ VALUE inner_argv[CA_RANK_MAX + 2];
78
+ for (int j = 0; j < c->inner_argc; j++) inner_argv[1 + j] = c->inner_axes[j];
79
+ if ( ! NIL_P(c->opt_hash) ) inner_argv[1 + c->inner_argc] = c->opt_hash;
80
+
81
+ for (ca_size_t k = 0; k < v_elements; k++) {
82
+ /* Extract vk as a scalar VALUE via flat addr. rb_ca_fetch_addr
83
+ takes a ca_size_t addr (not a Ruby VALUE). */
84
+ VALUE vk = rb_ca_fetch_addr(c->rval, k);
85
+ inner_argv[0] = vk;
86
+ VALUE sub = rb_ca_count(inner_call_argc, inner_argv, c->self);
87
+
88
+ /* Place sub into output[..., k] slot.
89
+ Output stride for v-axis = 1, base stride = v_elements. */
90
+ if ( sub == CA_UNDEF ) {
91
+ if ( ! out_mask ) {
92
+ ca_create_mask(cout);
93
+ out_mask = (boolean8_t *) cout->mask->ptr;
94
+ }
95
+ for (ca_size_t i = 0; i < base_elements; i++) {
96
+ out_ptr[i * v_elements + k] = 0;
97
+ out_mask[i * v_elements + k] = 1;
98
+ }
99
+ } else if ( rb_obj_is_kind_of(sub, rb_cInteger) ) {
100
+ /* Full reduction: sub is a single integer. */
101
+ out_ptr[k] = NUM2LL(sub);
102
+ } else if ( rb_obj_is_kind_of(sub, rb_cCArray) ) {
103
+ CArray *csub;
104
+ GetCArray(sub, csub);
105
+ ca_attach(csub); /* window: the inner count answered an entity; nothing raises inside */
106
+ int64_t *sub_ptr = (int64_t *) csub->ptr;
107
+ boolean8_t *sub_mask = (csub->mask) ? (boolean8_t *) csub->mask->ptr : NULL;
108
+ for (ca_size_t i = 0; i < base_elements; i++) {
109
+ out_ptr[i * v_elements + k] = sub_ptr[i];
110
+ if ( sub_mask && sub_mask[i] ) {
111
+ if ( ! out_mask ) {
112
+ ca_create_mask(cout);
113
+ out_mask = (boolean8_t *) cout->mask->ptr;
114
+ }
115
+ out_mask[i * v_elements + k] = 1;
116
+ }
117
+ }
118
+ ca_detach(csub);
119
+ } else {
120
+ rb_raise(rb_eRuntimeError,
121
+ "count(v: CArray): unexpected sub-result type");
122
+ }
123
+ }
124
+ return Qnil;
125
+ }
47
126
 
48
127
  static VALUE
49
128
  rb_ca_count (int argc, VALUE *argv, VALUE self)
@@ -56,10 +135,11 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
56
135
  ladder. kwargs reach a -1 C method as a trailing options hash, so a
57
136
  bare `count(axis: k)` arrives as argc==1 with argv[0] a Hash; discount
58
137
  that trailing hash (same convention as the CArray-broadcast branch
59
- below) before deciding there is no positional value. argv is forwarded
60
- verbatim so the axis: kwarg passes through. */
138
+ below) before deciding there is no positional value. A Hash passed
139
+ positionally is the value to count. argv is forwarded verbatim so the
140
+ axis: kwarg passes through. */
61
141
  {
62
- int has_opts = ( argc >= 1 &&
142
+ int has_opts = ( argc >= 1 && rb_keyword_given_p() &&
63
143
  rb_obj_is_kind_of(argv[argc - 1], rb_cHash) );
64
144
  if ( argc - (has_opts ? 1 : 0) < 1 ) {
65
145
  return rb_ca_count_not_masked(argc, argv, self);
@@ -77,48 +157,30 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
77
157
  /* Face gate, mirroring the search / linear family (ext/carray_order.c):
78
158
  descend an ORDERABLE Face to its storage so the equality runs on the
79
159
  numeric storage, and let the reference reconcile the query into its own
80
- space -- a COMPARABLE Face compares directly (strip a Face query, take a
81
- plain one as-is), a unit-bearing one calls its own to_comparable for any
82
- query type (Face CArray, Element, Time, DateTime). A Face that counts
160
+ space (ca_face_reconcile_operand). A Face that counts
83
161
  by other means never arrives here: CACategorical / CAConstString define
84
162
  their own #count in Ruby. Placed after the mask-state branches above,
85
163
  which read the mask the Face already shares with its storage, and before
86
164
  the broadcast branch, so a reconciled query array recurses as storage. */
87
165
  if ( ca_is_face(src) ) {
88
- volatile VALUE self_ref = self;
89
166
  int query_was_scalar = ! rb_obj_is_carray(rval);
90
- if ( ! ca_test_flag(src, CA_FLAG_FACE_ORDERABLE_STORAGE) ) {
91
- rb_raise(rb_eArgError,
92
- "count(v): Face-typed input (%s) is not orderable by storage; "
93
- "use ca.parent to count the raw storage",
94
- rb_obj_classname(self));
167
+ if ( src->obj_type == CA_OBJ_RECORD && query_was_scalar ) {
168
+ /* A record is its bytes: a struct element counts as its encoding. */
169
+ rval = ca_face_element_to_storage(self, src, rval);
95
170
  }
96
- if ( ca_test_flag(src, CA_FLAG_FACE_COMPARABLE_STORAGE) ) {
97
- if ( ! query_was_scalar ) {
98
- CArray *cv;
99
- GetCArray(rval, cv);
100
- if ( ca_is_face(cv) ) {
101
- rval = rb_ca_strip_face_value(rval);
102
- }
171
+ else {
172
+ if ( src->obj_type != CA_OBJ_RECORD
173
+ && ! ca_test_flag(src, CA_FLAG_FACE_ORDERABLE_STORAGE) ) {
174
+ ca_face_refuse_order("count(v)", self, "count");
103
175
  }
104
- }
105
- else if ( rb_respond_to(self_ref, rb_intern("to_comparable")) ) {
106
- rval = rb_ca_strip_face_value(rb_funcall(self_ref,
107
- rb_intern("to_comparable"),
108
- 1, rval));
109
- /* to_comparable lifts a scalar query to a length-1 array; unwrap it so a
110
- scalar query still answers with a count rather than a length-1 array
111
- from the broadcast branch below. */
176
+ rval = ca_face_reconcile_operand(self, rval, "count(v)");
177
+ /* to_comparable lifts a scalar query to a length-1 array; unwrap it so
178
+ a scalar query still answers with a count rather than a length-1
179
+ array from the broadcast branch below. */
112
180
  if ( query_was_scalar && rb_obj_is_carray(rval) ) {
113
181
  rval = rb_ca_fetch_addr(rval, 0);
114
182
  }
115
183
  }
116
- else {
117
- rb_raise(rb_eArgError,
118
- "count(v): non-comparable Face (%s) has no to_comparable to "
119
- "reconcile the query; use ca.parent to count the raw storage",
120
- rb_obj_classname(self));
121
- }
122
184
  self = rb_ca_strip_face_value(self);
123
185
  GetCArray(self, src);
124
186
  /* Hand the reconciled query down in argv (count_equal_ki pops argv[0],
@@ -148,14 +210,26 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
148
210
  CArray *cv;
149
211
  GetCArray(rval, cv);
150
212
 
213
+ /* A query of a wider type than an integer array is counted in the type
214
+ the two share, as `eq` compares: each v[k] below is then a value of
215
+ that type, not one truncated to the array's. */
216
+ if ( ca_is_integer_type(src) &&
217
+ ( ca_is_integer_type(cv) || ca_is_float_type(cv) ) ) {
218
+ int8_t qt = ca_promote_type(src->data_type, cv->data_type);
219
+ if ( qt != src->data_type ) {
220
+ self = rb_ca_wrap_readonly(self, INT2NUM(qt));
221
+ GetCArray(self, src);
222
+ }
223
+ }
224
+
151
225
  /* Pop trailing options hash (min_count / fill_value) before axes
152
226
  parsing so parse_reduce_axes only sees Integer axes. The opts
153
227
  are forwarded verbatim via inner_argv to the recursive count(). */
154
228
  int inner_argc = argc - 1;
155
229
  VALUE *inner_axes = argv + 1;
156
230
  volatile VALUE opt_hash = Qnil;
157
- if ( inner_argc > 0 && rb_obj_is_kind_of(inner_axes[inner_argc - 1],
158
- rb_cHash) ) {
231
+ if ( inner_argc > 0 && rb_keyword_given_p() &&
232
+ rb_obj_is_kind_of(inner_axes[inner_argc - 1], rb_cHash) ) {
159
233
  opt_hash = inner_axes[inner_argc - 1];
160
234
  inner_argc--;
161
235
  }
@@ -202,64 +276,34 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
202
276
  CArray *cout;
203
277
  GetCArray(vout, cout);
204
278
 
279
+ /* The options are checked by the recursive count() below, which an
280
+ empty v never reaches: check them once with a stand-in query, so a
281
+ misspelt keyword raises whatever v holds. */
282
+ if ( cv->elements == 0 && ! NIL_P(opt_hash) &&
283
+ src->data_type != CA_FIXLEN ) {
284
+ VALUE probe_argv[CA_RANK_MAX + 2];
285
+ int j;
286
+ probe_argv[0] = INT2FIX(0);
287
+ for (j = 0; j < inner_argc; j++) probe_argv[1 + j] = inner_axes[j];
288
+ probe_argv[1 + inner_argc] = opt_hash;
289
+ rb_ca_count(inner_argc + 2, probe_argv, self);
290
+ }
291
+
205
292
  /* Iterate v in flat order, call self.count(vk, *axes, **opts)
206
- recursively, place result at output[..., k]. */
207
- ca_attach(cv);
208
- int64_t *out_ptr = (int64_t *) cout->ptr;
209
- boolean8_t *out_mask = NULL;
210
- ca_size_t v_elements = cv->elements;
211
- /* inner_argv layout: [vk_scalar, axis..., axis..., [opt_hash]]
212
- inner_call_argc = 1 (vk) + inner_argc (axes) + (opt_hash ? 1 : 0). */
213
- int inner_call_argc = 1 + inner_argc + (NIL_P(opt_hash) ? 0 : 1);
214
- VALUE inner_argv[CA_RANK_MAX + 2];
215
- for (int j = 0; j < inner_argc; j++) inner_argv[1 + j] = inner_axes[j];
216
- if ( ! NIL_P(opt_hash) ) inner_argv[1 + inner_argc] = opt_hash;
217
-
218
- for (ca_size_t k = 0; k < v_elements; k++) {
219
- /* Extract vk as a scalar VALUE via flat addr. rb_ca_fetch_addr
220
- takes a ca_size_t addr (not a Ruby VALUE). */
221
- VALUE vk = rb_ca_fetch_addr(rval, k);
222
- inner_argv[0] = vk;
223
- VALUE sub = rb_ca_count(inner_call_argc, inner_argv, self);
224
-
225
- /* Place sub into output[..., k] slot.
226
- Output stride for v-axis = 1, base stride = v_elements. */
227
- if ( sub == CA_UNDEF ) {
228
- if ( ! out_mask ) {
229
- ca_create_mask(cout);
230
- out_mask = (boolean8_t *) cout->mask->ptr;
231
- }
232
- for (ca_size_t i = 0; i < base_elements; i++) {
233
- out_ptr[i * v_elements + k] = 0;
234
- out_mask[i * v_elements + k] = 1;
235
- }
236
- } else if ( rb_obj_is_kind_of(sub, rb_cInteger) ) {
237
- /* Full reduction: sub is a single integer. */
238
- out_ptr[k] = NUM2LL(sub);
239
- } else if ( rb_obj_is_kind_of(sub, rb_cCArray) ) {
240
- CArray *csub;
241
- GetCArray(sub, csub);
242
- ca_attach(csub);
243
- int64_t *sub_ptr = (int64_t *) csub->ptr;
244
- boolean8_t *sub_mask = (csub->mask) ? (boolean8_t *) csub->mask->ptr : NULL;
245
- for (ca_size_t i = 0; i < base_elements; i++) {
246
- out_ptr[i * v_elements + k] = sub_ptr[i];
247
- if ( sub_mask && sub_mask[i] ) {
248
- if ( ! out_mask ) {
249
- ca_create_mask(cout);
250
- out_mask = (boolean8_t *) cout->mask->ptr;
251
- }
252
- out_mask[i * v_elements + k] = 1;
253
- }
254
- }
255
- ca_detach(csub);
256
- } else {
257
- ca_detach(cv);
258
- rb_raise(rb_eRuntimeError,
259
- "count(v: CArray): unexpected sub-result type");
260
- }
293
+ recursively, place result at output[..., k]. v is held attached
294
+ for the fetches while Ruby runs, so the loop is a window body. */
295
+ {
296
+ ca_count_each_ctx_t c;
297
+ c.self = self;
298
+ c.rval = rval;
299
+ c.cv = cv;
300
+ c.cout = cout;
301
+ c.base_elements = base_elements;
302
+ c.inner_argc = inner_argc;
303
+ c.inner_axes = inner_axes;
304
+ c.opt_hash = opt_hash;
305
+ ca_attach_window(1, &cv, "r", ca_count_each_body, (VALUE) &c);
261
306
  }
262
- ca_detach(cv);
263
307
  return vout;
264
308
  }
265
309
 
@@ -290,11 +334,19 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
290
334
  rb_obj_classname(rval));
291
335
  }
292
336
  } else {
293
- if ( rval == Qtrue || rval == Qfalse ) {
337
+ /* true / false are the boolean array's own domain, not a number --
338
+ except in an object array, where they are ordinary stored values. */
339
+ if ( ( rval == Qtrue || rval == Qfalse ) && src->data_type != CA_OBJECT ) {
294
340
  rb_raise(rb_eTypeError,
295
341
  "count(v) on numeric array: v must be numeric, got %s",
296
342
  rb_obj_classname(rval));
297
343
  }
344
+ /* A Float query on an integer array is compared as a float, as `eq`
345
+ compares and `search` searches: 1.5 must not match 1. An Integer
346
+ query keeps the array's type and is refused when it does not fit. */
347
+ if ( ca_is_integer_type(src) && RB_FLOAT_TYPE_P(rval) ) {
348
+ self = rb_ca_wrap_readonly(self, INT2NUM(CA_FLOAT64));
349
+ }
298
350
  /* Pass full argv; count_equal_ki pops argv[0] as value_arg. */
299
351
  return rb_ca_count_equal_ki(argc, argv, self);
300
352
  }
data/ext/carray_element.c CHANGED
@@ -18,6 +18,7 @@
18
18
  #include "ruby.h"
19
19
  #include "carray.h"
20
20
  #include "ca_obj_face.h"
21
+ #include "carray_internal.h" /* ca_obj_extremum_replaces */
21
22
 
22
23
  /* T_ARRAY index parser. ridx is assumed already known to be T_ARRAY.
23
24
  Direct VALUE * access + FIXNUM_P fast path eliminates rb_ary_entry
@@ -85,8 +86,8 @@ rb_ca_elem_swap (VALUE self, VALUE ridx1, VALUE ridx2)
85
86
  ca_size_t idx1[CA_RANK_MAX], idx2[CA_RANK_MAX];
86
87
  ca_size_t addr1 = 0, addr2 = 0;
87
88
  int has_mask, has_index1, has_index2;
88
- char _val1[64], _val2[64];
89
- char *val1 = _val1, *val2 = _val2;
89
+ volatile VALUE holder1, holder2;
90
+ char *val1, *val2;
90
91
  boolean8_t m1 = 0, m2 = 0;
91
92
 
92
93
  rb_ca_modify(self);
@@ -95,10 +96,8 @@ rb_ca_elem_swap (VALUE self, VALUE ridx1, VALUE ridx2)
95
96
 
96
97
  has_mask = elem_probe_mask(ca);
97
98
 
98
- if ( ca->bytes > 64 ) {
99
- val1 = xmalloc(ca->bytes);
100
- val2 = xmalloc(ca->bytes);
101
- }
99
+ val1 = ALLOCV_N(char, holder1, ca->bytes);
100
+ val2 = ALLOCV_N(char, holder2, ca->bytes);
102
101
 
103
102
  if ( TYPE(ridx1) == T_ARRAY ) {
104
103
  elem_parse_idx_array(ca, ridx1, idx1);
@@ -160,10 +159,8 @@ rb_ca_elem_swap (VALUE self, VALUE ridx1, VALUE ridx2)
160
159
  }
161
160
  }
162
161
 
163
- if ( ca->bytes > 64 ) {
164
- xfree(val1);
165
- xfree(val2);
166
- }
162
+ ALLOCV_END(holder2);
163
+ ALLOCV_END(holder1);
167
164
 
168
165
  return self;
169
166
  }
@@ -178,8 +175,8 @@ rb_ca_elem_copy (VALUE self, VALUE ridx1, VALUE ridx2)
178
175
  ca_size_t idx1[CA_RANK_MAX], idx2[CA_RANK_MAX];
179
176
  ca_size_t addr1 = 0, addr2 = 0;
180
177
  int has_mask;
181
- char _val[64];
182
- char *val = _val;
178
+ volatile VALUE holder;
179
+ char *val;
183
180
  boolean8_t m = 0;
184
181
 
185
182
  rb_ca_modify(self);
@@ -188,9 +185,7 @@ rb_ca_elem_copy (VALUE self, VALUE ridx1, VALUE ridx2)
188
185
 
189
186
  has_mask = elem_probe_mask(ca);
190
187
 
191
- if ( ca->bytes > 64 ) {
192
- val = xmalloc(ca->bytes);
193
- }
188
+ val = ALLOCV_N(char, holder, ca->bytes);
194
189
 
195
190
  if ( TYPE(ridx1) == T_ARRAY ) {
196
191
  elem_parse_idx_array(ca, ridx1, idx1);
@@ -222,9 +217,7 @@ rb_ca_elem_copy (VALUE self, VALUE ridx1, VALUE ridx2)
222
217
  }
223
218
  }
224
219
 
225
- if ( ca->bytes > 64 ) {
226
- xfree(val);
227
- }
220
+ ALLOCV_END(holder);
228
221
 
229
222
  return self;
230
223
  }
@@ -380,10 +373,11 @@ rb_ca_elem_fetch (VALUE self, VALUE ridx)
380
373
  out = rb_ca_ptr2obj(self, v);
381
374
  }
382
375
  else {
383
- char *v = xmalloc(ca->bytes);
376
+ volatile VALUE holder;
377
+ char *v = ALLOCV_N(char, holder, ca->bytes);
384
378
  ca_fetch_index(ca, idx, v);
385
379
  out = rb_ca_ptr2obj(self, v);
386
- xfree(v);
380
+ ALLOCV_END(holder);
387
381
  }
388
382
 
389
383
  /* Mask check with inline skip for the entity+no-mask common case. */
@@ -401,7 +395,7 @@ rb_ca_elem_fetch (VALUE self, VALUE ridx)
401
395
  }
402
396
  }
403
397
 
404
- CA_FACE_STORAGE_TO_SCALAR_IF_FACE(out, self, ca);
398
+ CA_FACE_STORAGE_TO_ELEMENT_IF_FACE(out, self, ca);
405
399
  return out;
406
400
  }
407
401
  else {
@@ -690,10 +684,7 @@ rb_ca_elem_mask (VALUE self, VALUE ridx)
690
684
  /* General path: view array. Walk parent chain + dispatch. */
691
685
  {
692
686
  boolean8_t one = 1;
693
- ca_update_mask(ca);
694
- if ( ! ca->mask ) {
695
- ca_create_mask(ca);
696
- }
687
+ ca_create_mask(ca);
697
688
  if ( TYPE(ridx) == T_ARRAY ) {
698
689
  elem_parse_idx_array(ca, ridx, idx);
699
690
  ca_store_index(ca->mask, idx, &one);
@@ -846,7 +837,7 @@ rb_ca_elem_min (VALUE self, VALUE ridx, VALUE rval)
846
837
 
847
838
  cur = from_array ? rb_ca_fetch_index(self, idx) : rb_ca_fetch_addr(self, addr);
848
839
  if ( cur == CA_UNDEF ) return self;
849
- if ( RTEST(rb_funcall(rval, rb_intern("<"), 1, cur)) ) {
840
+ if ( ca_obj_extremum_replaces(rval, cur, rb_intern("<")) ) {
850
841
  if ( from_array ) rb_ca_store_index(self, idx, rval);
851
842
  else rb_ca_store_addr(self, addr, rval);
852
843
  }
@@ -899,7 +890,7 @@ rb_ca_elem_max (VALUE self, VALUE ridx, VALUE rval)
899
890
 
900
891
  cur = from_array ? rb_ca_fetch_index(self, idx) : rb_ca_fetch_addr(self, addr);
901
892
  if ( cur == CA_UNDEF ) return self;
902
- if ( RTEST(rb_funcall(rval, rb_intern(">"), 1, cur)) ) {
893
+ if ( ca_obj_extremum_replaces(rval, cur, rb_intern(">")) ) {
903
894
  if ( from_array ) rb_ca_store_index(self, idx, rval);
904
895
  else rb_ca_store_addr(self, addr, rval);
905
896
  }