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/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>
@@ -46,6 +47,91 @@ VALUE rb_ca_count_not_masked (int argc, VALUE *argv, VALUE self);
46
47
  cell; a short String query is padded
47
48
  out to the cell width) */
48
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
+ VALUE sub;
86
+ /* A masked query cell asks nothing: its count is masked. Passing it
87
+ on would ask count(UNDEF), the count of self's masked cells. */
88
+ if ( vk == CA_UNDEF ) {
89
+ sub = CA_UNDEF;
90
+ }
91
+ else {
92
+ inner_argv[0] = vk;
93
+ sub = rb_ca_count(inner_call_argc, inner_argv, c->self);
94
+ }
95
+
96
+ /* Place sub into output[..., k] slot.
97
+ Output stride for v-axis = 1, base stride = v_elements. */
98
+ if ( sub == CA_UNDEF ) {
99
+ if ( ! out_mask ) {
100
+ ca_create_mask(cout);
101
+ out_mask = (boolean8_t *) cout->mask->ptr;
102
+ }
103
+ for (ca_size_t i = 0; i < base_elements; i++) {
104
+ out_ptr[i * v_elements + k] = 0;
105
+ out_mask[i * v_elements + k] = 1;
106
+ }
107
+ } else if ( rb_obj_is_kind_of(sub, rb_cInteger) ) {
108
+ /* Full reduction: sub is a single integer. */
109
+ out_ptr[k] = NUM2LL(sub);
110
+ } else if ( rb_obj_is_kind_of(sub, rb_cCArray) ) {
111
+ CArray *csub;
112
+ GetCArray(sub, csub);
113
+ ca_attach(csub); /* window: the inner count answered an entity; nothing raises inside */
114
+ int64_t *sub_ptr = (int64_t *) csub->ptr;
115
+ boolean8_t *sub_mask = (csub->mask) ? (boolean8_t *) csub->mask->ptr : NULL;
116
+ for (ca_size_t i = 0; i < base_elements; i++) {
117
+ out_ptr[i * v_elements + k] = sub_ptr[i];
118
+ if ( sub_mask && sub_mask[i] ) {
119
+ if ( ! out_mask ) {
120
+ ca_create_mask(cout);
121
+ out_mask = (boolean8_t *) cout->mask->ptr;
122
+ }
123
+ out_mask[i * v_elements + k] = 1;
124
+ }
125
+ }
126
+ ca_detach(csub);
127
+ } else {
128
+ rb_raise(rb_eRuntimeError,
129
+ "count(v: CArray): unexpected sub-result type");
130
+ }
131
+ }
132
+ return Qnil;
133
+ }
134
+
49
135
  static VALUE
50
136
  rb_ca_count (int argc, VALUE *argv, VALUE self)
51
137
  {
@@ -57,10 +143,11 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
57
143
  ladder. kwargs reach a -1 C method as a trailing options hash, so a
58
144
  bare `count(axis: k)` arrives as argc==1 with argv[0] a Hash; discount
59
145
  that trailing hash (same convention as the CArray-broadcast branch
60
- below) before deciding there is no positional value. argv is forwarded
61
- verbatim so the axis: kwarg passes through. */
146
+ below) before deciding there is no positional value. A Hash passed
147
+ positionally is the value to count. argv is forwarded verbatim so the
148
+ axis: kwarg passes through. */
62
149
  {
63
- int has_opts = ( argc >= 1 &&
150
+ int has_opts = ( argc >= 1 && rb_keyword_given_p() &&
64
151
  rb_obj_is_kind_of(argv[argc - 1], rb_cHash) );
65
152
  if ( argc - (has_opts ? 1 : 0) < 1 ) {
66
153
  return rb_ca_count_not_masked(argc, argv, self);
@@ -78,44 +165,36 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
78
165
  /* Face gate, mirroring the search / linear family (ext/carray_order.c):
79
166
  descend an ORDERABLE Face to its storage so the equality runs on the
80
167
  numeric storage, and let the reference reconcile the query into its own
81
- space -- a COMPARABLE Face compares directly (strip a Face query, take a
82
- plain one as-is), a unit-bearing one calls its own to_comparable for any
83
- query type (Face CArray, Element, Time, DateTime). A Face that counts
168
+ space (ca_face_reconcile_operand). A Face that counts
84
169
  by other means never arrives here: CACategorical / CAConstString define
85
170
  their own #count in Ruby. Placed after the mask-state branches above,
86
171
  which read the mask the Face already shares with its storage, and before
87
172
  the broadcast branch, so a reconciled query array recurses as storage. */
88
173
  if ( ca_is_face(src) ) {
89
- volatile VALUE self_ref = self;
90
174
  int query_was_scalar = ! rb_obj_is_carray(rval);
91
- if ( ! ca_test_flag(src, CA_FLAG_FACE_ORDERABLE_STORAGE) ) {
92
- rb_raise(rb_eArgError,
93
- "count(v): Face-typed input (%s) is not orderable by storage; "
94
- "use ca.parent to count the raw storage",
95
- rb_obj_classname(self));
175
+ if ( src->obj_type == CA_OBJ_RECORD && query_was_scalar ) {
176
+ /* A record is its bytes: a struct element counts as its encoding. */
177
+ rval = ca_face_element_to_storage(self, src, rval);
96
178
  }
97
- if ( ca_test_flag(src, CA_FLAG_FACE_COMPARABLE_STORAGE) ) {
98
- if ( ! query_was_scalar ) {
99
- rval = ca_face_operand_descend(rval, "count(v)");
179
+ else {
180
+ if ( src->obj_type != CA_OBJ_RECORD ) {
181
+ ca_face_require_orderable(self, "count(v)", "count");
100
182
  }
101
- }
102
- else if ( rb_respond_to(self_ref, rb_intern("to_comparable")) ) {
103
- rval = rb_ca_strip_face_value(rb_funcall(self_ref,
104
- rb_intern("to_comparable"),
105
- 1, rval));
106
- /* to_comparable lifts a scalar query to a length-1 array; unwrap it so a
107
- scalar query still answers with a count rather than a length-1 array
108
- from the broadcast branch below. */
109
- if ( query_was_scalar && rb_obj_is_carray(rval) ) {
183
+ {
184
+ volatile VALUE ref = self, query = rval;
185
+ ca_face_reconcile_pair(&ref, &query, "count(v)");
186
+ self = ref;
187
+ rval = query;
188
+ }
189
+ /* The reconcile lifts a scalar query to a length-1 array; unwrap it so
190
+ a scalar query still answers with a count rather than a length-1
191
+ array from the broadcast branch below. A Ruby Array is a list of
192
+ queries and stays one, like a CArray query. */
193
+ if ( query_was_scalar && ! RB_TYPE_P(argv[0], T_ARRAY)
194
+ && rb_obj_is_carray(rval) ) {
110
195
  rval = rb_ca_fetch_addr(rval, 0);
111
196
  }
112
197
  }
113
- else {
114
- rb_raise(rb_eArgError,
115
- "count(v): non-comparable Face (%s) has no to_comparable to "
116
- "reconcile the query; use ca.parent to count the raw storage",
117
- rb_obj_classname(self));
118
- }
119
198
  self = rb_ca_strip_face_value(self);
120
199
  GetCArray(self, src);
121
200
  /* Hand the reconciled query down in argv (count_equal_ki pops argv[0],
@@ -145,14 +224,25 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
145
224
  CArray *cv;
146
225
  GetCArray(rval, cv);
147
226
 
227
+ /* The array is counted in the type it and v match in, as `eq` compares
228
+ (ca_query_match_type): each v[k] below is then a value of that type,
229
+ not one cut to the array's. */
230
+ if ( ca_query_match_applies(src, rval) ) {
231
+ int8_t qt = ca_query_match_type(src->data_type, rval);
232
+ if ( qt != src->data_type ) {
233
+ self = rb_ca_wrap_readonly(self, INT2NUM(qt));
234
+ GetCArray(self, src);
235
+ }
236
+ }
237
+
148
238
  /* Pop trailing options hash (min_count / fill_value) before axes
149
239
  parsing so parse_reduce_axes only sees Integer axes. The opts
150
240
  are forwarded verbatim via inner_argv to the recursive count(). */
151
241
  int inner_argc = argc - 1;
152
242
  VALUE *inner_axes = argv + 1;
153
243
  volatile VALUE opt_hash = Qnil;
154
- if ( inner_argc > 0 && rb_obj_is_kind_of(inner_axes[inner_argc - 1],
155
- rb_cHash) ) {
244
+ if ( inner_argc > 0 && rb_keyword_given_p() &&
245
+ rb_obj_is_kind_of(inner_axes[inner_argc - 1], rb_cHash) ) {
156
246
  opt_hash = inner_axes[inner_argc - 1];
157
247
  inner_argc--;
158
248
  }
@@ -199,64 +289,34 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
199
289
  CArray *cout;
200
290
  GetCArray(vout, cout);
201
291
 
292
+ /* The options are checked by the recursive count() below, which an
293
+ empty v never reaches: check them once with a stand-in query, so a
294
+ misspelt keyword raises whatever v holds. */
295
+ if ( cv->elements == 0 && ! NIL_P(opt_hash) &&
296
+ src->data_type != CA_FIXLEN ) {
297
+ VALUE probe_argv[CA_RANK_MAX + 2];
298
+ int j;
299
+ probe_argv[0] = INT2FIX(0);
300
+ for (j = 0; j < inner_argc; j++) probe_argv[1 + j] = inner_axes[j];
301
+ probe_argv[1 + inner_argc] = opt_hash;
302
+ rb_ca_count(inner_argc + 2, probe_argv, self);
303
+ }
304
+
202
305
  /* Iterate v in flat order, call self.count(vk, *axes, **opts)
203
- recursively, place result at output[..., k]. */
204
- ca_attach(cv);
205
- int64_t *out_ptr = (int64_t *) cout->ptr;
206
- boolean8_t *out_mask = NULL;
207
- ca_size_t v_elements = cv->elements;
208
- /* inner_argv layout: [vk_scalar, axis..., axis..., [opt_hash]]
209
- inner_call_argc = 1 (vk) + inner_argc (axes) + (opt_hash ? 1 : 0). */
210
- int inner_call_argc = 1 + inner_argc + (NIL_P(opt_hash) ? 0 : 1);
211
- VALUE inner_argv[CA_RANK_MAX + 2];
212
- for (int j = 0; j < inner_argc; j++) inner_argv[1 + j] = inner_axes[j];
213
- if ( ! NIL_P(opt_hash) ) inner_argv[1 + inner_argc] = opt_hash;
214
-
215
- for (ca_size_t k = 0; k < v_elements; k++) {
216
- /* Extract vk as a scalar VALUE via flat addr. rb_ca_fetch_addr
217
- takes a ca_size_t addr (not a Ruby VALUE). */
218
- VALUE vk = rb_ca_fetch_addr(rval, k);
219
- inner_argv[0] = vk;
220
- VALUE sub = rb_ca_count(inner_call_argc, inner_argv, self);
221
-
222
- /* Place sub into output[..., k] slot.
223
- Output stride for v-axis = 1, base stride = v_elements. */
224
- if ( sub == CA_UNDEF ) {
225
- if ( ! out_mask ) {
226
- ca_create_mask(cout);
227
- out_mask = (boolean8_t *) cout->mask->ptr;
228
- }
229
- for (ca_size_t i = 0; i < base_elements; i++) {
230
- out_ptr[i * v_elements + k] = 0;
231
- out_mask[i * v_elements + k] = 1;
232
- }
233
- } else if ( rb_obj_is_kind_of(sub, rb_cInteger) ) {
234
- /* Full reduction: sub is a single integer. */
235
- out_ptr[k] = NUM2LL(sub);
236
- } else if ( rb_obj_is_kind_of(sub, rb_cCArray) ) {
237
- CArray *csub;
238
- GetCArray(sub, csub);
239
- ca_attach(csub);
240
- int64_t *sub_ptr = (int64_t *) csub->ptr;
241
- boolean8_t *sub_mask = (csub->mask) ? (boolean8_t *) csub->mask->ptr : NULL;
242
- for (ca_size_t i = 0; i < base_elements; i++) {
243
- out_ptr[i * v_elements + k] = sub_ptr[i];
244
- if ( sub_mask && sub_mask[i] ) {
245
- if ( ! out_mask ) {
246
- ca_create_mask(cout);
247
- out_mask = (boolean8_t *) cout->mask->ptr;
248
- }
249
- out_mask[i * v_elements + k] = 1;
250
- }
251
- }
252
- ca_detach(csub);
253
- } else {
254
- ca_detach(cv);
255
- rb_raise(rb_eRuntimeError,
256
- "count(v: CArray): unexpected sub-result type");
257
- }
306
+ recursively, place result at output[..., k]. v is held attached
307
+ for the fetches while Ruby runs, so the loop is a window body. */
308
+ {
309
+ ca_count_each_ctx_t c;
310
+ c.self = self;
311
+ c.rval = rval;
312
+ c.cv = cv;
313
+ c.cout = cout;
314
+ c.base_elements = base_elements;
315
+ c.inner_argc = inner_argc;
316
+ c.inner_axes = inner_axes;
317
+ c.opt_hash = opt_hash;
318
+ ca_attach_window(1, &cv, "r", ca_count_each_body, (VALUE) &c);
258
319
  }
259
- ca_detach(cv);
260
320
  return vout;
261
321
  }
262
322
 
@@ -294,6 +354,29 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
294
354
  "count(v) on numeric array: v must be numeric, got %s",
295
355
  rb_obj_classname(rval));
296
356
  }
357
+ /* The query is compared in the type it and the array match in, as `eq`
358
+ compares (ca_query_match_type): 1.5 does not match 1, and an Integer
359
+ the array's type cannot hold matches nothing. */
360
+ if ( ca_is_integer_type(src) && ! RB_INTEGER_TYPE_P(rval)
361
+ && ! RB_FLOAT_TYPE_P(rval) && ! RB_TYPE_P(rval, T_COMPLEX)
362
+ && rb_obj_is_kind_of(rval, rb_cNumeric) ) {
363
+ /* A Rational or BigDecimal query: an integral one is the Integer it
364
+ equals; any other is compared as a float, like a Float query,
365
+ rather than cut to the array's type. */
366
+ VALUE ival = rb_funcall(rval, rb_intern("to_i"), 0);
367
+ VALUE *nargv = ALLOCA_N(VALUE, argc);
368
+ MEMCPY(nargv, argv, VALUE, argc);
369
+ nargv[0] = RTEST(rb_funcall(rval, rb_intern("=="), 1, ival))
370
+ ? ival : rb_funcall(rval, rb_intern("to_f"), 0);
371
+ argv = nargv;
372
+ rval = nargv[0];
373
+ }
374
+ if ( ca_query_match_applies(src, rval) ) {
375
+ int8_t qt = ca_query_match_type(src->data_type, rval);
376
+ if ( qt != src->data_type ) {
377
+ self = rb_ca_wrap_readonly(self, INT2NUM(qt));
378
+ }
379
+ }
297
380
  /* Pass full argv; count_equal_ki pops argv[0] as value_arg. */
298
381
  return rb_ca_count_equal_ki(argc, argv, self);
299
382
  }
data/ext/carray_element.c CHANGED
@@ -18,6 +18,20 @@
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 */
22
+
23
+ /* An element index is an Integer, as it is for `[]`; a Float would be cut
24
+ to an integer by NUM2SIZE. */
25
+ static inline ca_size_t
26
+ elem_index_value (VALUE v)
27
+ {
28
+ if ( FIXNUM_P(v) ) return (ca_size_t) FIX2LONG(v);
29
+ if ( ! RB_INTEGER_TYPE_P(v) ) {
30
+ rb_raise(rb_eIndexError, "object '%"PRIsVALUE"' is invalid for an index",
31
+ rb_inspect(v));
32
+ }
33
+ return NUM2SIZE(v);
34
+ }
21
35
 
22
36
  /* T_ARRAY index parser. ridx is assumed already known to be T_ARRAY.
23
37
  Direct VALUE * access + FIXNUM_P fast path eliminates rb_ary_entry
@@ -25,12 +39,16 @@
25
39
  static inline void
26
40
  elem_parse_idx_array (CArray *ca, VALUE rary, ca_size_t *idx)
27
41
  {
28
- const VALUE *iarr = RARRAY_CONST_PTR(rary);
42
+ const VALUE *iarr;
29
43
  int8_t ndim = ca->ndim;
30
44
  int8_t i;
45
+ if ( RARRAY_LEN(rary) != ndim ) {
46
+ rb_raise(rb_eIndexError, "%ld indices given for a carray of ndim %i",
47
+ (long) RARRAY_LEN(rary), (int) ndim);
48
+ }
49
+ iarr = RARRAY_CONST_PTR(rary);
31
50
  for (i=0; i<ndim; i++) {
32
- VALUE v = iarr[i];
33
- ca_size_t k = FIXNUM_P(v) ? (ca_size_t)FIX2LONG(v) : NUM2SIZE(v);
51
+ ca_size_t k = elem_index_value(iarr[i]);
34
52
  CA_CHECK_INDEX(k, ca->dim[i]);
35
53
  idx[i] = k;
36
54
  }
@@ -40,7 +58,7 @@ elem_parse_idx_array (CArray *ca, VALUE rary, ca_size_t *idx)
40
58
  static inline ca_size_t
41
59
  elem_parse_idx_scalar (CArray *ca, VALUE ridx)
42
60
  {
43
- ca_size_t k = FIXNUM_P(ridx) ? (ca_size_t)FIX2LONG(ridx) : NUM2SIZE(ridx);
61
+ ca_size_t k = elem_index_value(ridx);
44
62
  CA_CHECK_INDEX(k, ca->elements);
45
63
  return k;
46
64
  }
@@ -85,8 +103,8 @@ rb_ca_elem_swap (VALUE self, VALUE ridx1, VALUE ridx2)
85
103
  ca_size_t idx1[CA_RANK_MAX], idx2[CA_RANK_MAX];
86
104
  ca_size_t addr1 = 0, addr2 = 0;
87
105
  int has_mask, has_index1, has_index2;
88
- char _val1[64], _val2[64];
89
- char *val1 = _val1, *val2 = _val2;
106
+ volatile VALUE holder1, holder2;
107
+ char *val1, *val2;
90
108
  boolean8_t m1 = 0, m2 = 0;
91
109
 
92
110
  rb_ca_modify(self);
@@ -95,10 +113,8 @@ rb_ca_elem_swap (VALUE self, VALUE ridx1, VALUE ridx2)
95
113
 
96
114
  has_mask = elem_probe_mask(ca);
97
115
 
98
- if ( ca->bytes > 64 ) {
99
- val1 = xmalloc(ca->bytes);
100
- val2 = xmalloc(ca->bytes);
101
- }
116
+ val1 = ALLOCV_N(char, holder1, ca->bytes);
117
+ val2 = ALLOCV_N(char, holder2, ca->bytes);
102
118
 
103
119
  if ( TYPE(ridx1) == T_ARRAY ) {
104
120
  elem_parse_idx_array(ca, ridx1, idx1);
@@ -160,10 +176,8 @@ rb_ca_elem_swap (VALUE self, VALUE ridx1, VALUE ridx2)
160
176
  }
161
177
  }
162
178
 
163
- if ( ca->bytes > 64 ) {
164
- xfree(val1);
165
- xfree(val2);
166
- }
179
+ ALLOCV_END(holder2);
180
+ ALLOCV_END(holder1);
167
181
 
168
182
  return self;
169
183
  }
@@ -178,8 +192,8 @@ rb_ca_elem_copy (VALUE self, VALUE ridx1, VALUE ridx2)
178
192
  ca_size_t idx1[CA_RANK_MAX], idx2[CA_RANK_MAX];
179
193
  ca_size_t addr1 = 0, addr2 = 0;
180
194
  int has_mask;
181
- char _val[64];
182
- char *val = _val;
195
+ volatile VALUE holder;
196
+ char *val;
183
197
  boolean8_t m = 0;
184
198
 
185
199
  rb_ca_modify(self);
@@ -188,9 +202,7 @@ rb_ca_elem_copy (VALUE self, VALUE ridx1, VALUE ridx2)
188
202
 
189
203
  has_mask = elem_probe_mask(ca);
190
204
 
191
- if ( ca->bytes > 64 ) {
192
- val = xmalloc(ca->bytes);
193
- }
205
+ val = ALLOCV_N(char, holder, ca->bytes);
194
206
 
195
207
  if ( TYPE(ridx1) == T_ARRAY ) {
196
208
  elem_parse_idx_array(ca, ridx1, idx1);
@@ -222,9 +234,7 @@ rb_ca_elem_copy (VALUE self, VALUE ridx1, VALUE ridx2)
222
234
  }
223
235
  }
224
236
 
225
- if ( ca->bytes > 64 ) {
226
- xfree(val);
227
- }
237
+ ALLOCV_END(holder);
228
238
 
229
239
  return self;
230
240
  }
@@ -285,33 +295,56 @@ rb_ca_elem_store (VALUE self, VALUE ridx, VALUE obj)
285
295
  if ( FIXNUM_P(obj) ) { *(int64_t *)p = (int64_t)FIX2LONG(obj); return obj; }
286
296
  break;
287
297
  case CA_INT32:
288
- if ( FIXNUM_P(obj) ) { *(int32_t *)p = (int32_t)FIX2LONG(obj); return obj; }
298
+ if ( FIXNUM_P(obj) && FIX2LONG(obj) >= INT32_MIN && FIX2LONG(obj) <= INT32_MAX ) {
299
+ /* fits: checked against the type's range above */
300
+ *(int32_t *)p = (int32_t)FIX2LONG(obj); return obj;
301
+ }
289
302
  break;
290
303
  case CA_INT16:
291
- if ( FIXNUM_P(obj) ) { *(int16_t *)p = (int16_t)FIX2LONG(obj); return obj; }
304
+ if ( FIXNUM_P(obj) && FIX2LONG(obj) >= INT16_MIN && FIX2LONG(obj) <= INT16_MAX ) {
305
+ /* fits: checked against the type's range above */
306
+ *(int16_t *)p = (int16_t)FIX2LONG(obj); return obj;
307
+ }
292
308
  break;
293
309
  case CA_INT8:
294
- if ( FIXNUM_P(obj) ) { *(int8_t *)p = (int8_t)FIX2LONG(obj); return obj; }
310
+ if ( FIXNUM_P(obj) && FIX2LONG(obj) >= INT8_MIN && FIX2LONG(obj) <= INT8_MAX ) {
311
+ /* fits: checked against the type's range above */
312
+ *(int8_t *)p = (int8_t)FIX2LONG(obj); return obj;
313
+ }
295
314
  break;
296
315
  case CA_UINT64:
297
- if ( FIXNUM_P(obj) ) { *(uint64_t *)p = (uint64_t)FIX2LONG(obj); return obj; }
316
+ if ( FIXNUM_P(obj) && FIX2LONG(obj) >= 0 ) {
317
+ *(uint64_t *)p = (uint64_t)FIX2LONG(obj); return obj;
318
+ }
298
319
  break;
299
320
  case CA_UINT32:
300
- if ( FIXNUM_P(obj) ) { *(uint32_t *)p = (uint32_t)FIX2LONG(obj); return obj; }
321
+ if ( FIXNUM_P(obj) && FIX2LONG(obj) >= 0 && FIX2LONG(obj) <= (long) UINT32_MAX ) {
322
+ /* fits: checked against the type's range above */
323
+ *(uint32_t *)p = (uint32_t)FIX2LONG(obj); return obj;
324
+ }
301
325
  break;
302
326
  case CA_UINT16:
303
- if ( FIXNUM_P(obj) ) { *(uint16_t *)p = (uint16_t)FIX2LONG(obj); return obj; }
327
+ if ( FIXNUM_P(obj) && FIX2LONG(obj) >= 0 && FIX2LONG(obj) <= (long) UINT16_MAX ) {
328
+ /* fits: checked against the type's range above */
329
+ *(uint16_t *)p = (uint16_t)FIX2LONG(obj); return obj;
330
+ }
304
331
  break;
305
332
  case CA_UINT8:
306
- if ( FIXNUM_P(obj) ) { *(uint8_t *)p = (uint8_t)FIX2LONG(obj); return obj; }
333
+ if ( FIXNUM_P(obj) && FIX2LONG(obj) >= 0 && FIX2LONG(obj) <= (long) UINT8_MAX ) {
334
+ /* fits: checked against the type's range above */
335
+ *(uint8_t *)p = (uint8_t)FIX2LONG(obj); return obj;
336
+ }
307
337
  break;
308
338
  case CA_BOOLEAN:
309
339
  if ( obj == Qtrue ) { *(uint8_t *)p = 1; return obj; }
310
340
  if ( obj == Qfalse ) { *(uint8_t *)p = 0; return obj; }
311
- if ( FIXNUM_P(obj) ) { *(uint8_t *)p = (FIX2LONG(obj) != 0); return obj; }
341
+ if ( obj == INT2FIX(0) || obj == INT2FIX(1) ) {
342
+ *(uint8_t *)p = (obj == INT2FIX(1)); return obj;
343
+ }
312
344
  break;
313
345
  }
314
- /* Fall through: data type matches but obj kind needs general coercion. */
346
+ /* Fall through: the value needs the general coercion, or does not fit
347
+ the cell, which the general path refuses. */
315
348
  }
316
349
  }
317
350
 
@@ -338,14 +371,12 @@ rb_ca_elem_fetch (VALUE self, VALUE ridx)
338
371
 
339
372
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
340
373
 
341
- if ( ca_is_empty(ca) ) return Qnil;
342
-
343
374
  if ( TYPE(ridx) == T_ARRAY ) {
344
375
  volatile VALUE out;
345
376
  elem_parse_idx_array(ca, ridx, idx);
346
377
 
347
378
  /* Super-hot path: entity + common numeric data type + no mask.
348
- Bypass ca_fetch_index dispatch AND rb_ca_ptr2obj cast-table dispatch.
379
+ Bypass ca_fetch_index dispatch AND rb_ca_ptr2obj_storage cast-table dispatch.
349
380
  Covers the bench's float64 / int64 / int32 cases. */
350
381
  if ( ca_is_entity(ca) && ! ca->mask ) {
351
382
  ca_size_t addr = elem_entity_addr(ca, idx);
@@ -377,13 +408,14 @@ rb_ca_elem_fetch (VALUE self, VALUE ridx)
377
408
  else {
378
409
  ca_fetch_index(ca, idx, v);
379
410
  }
380
- out = rb_ca_ptr2obj(self, v);
411
+ out = rb_ca_ptr2obj_storage(self, v);
381
412
  }
382
413
  else {
383
- char *v = xmalloc(ca->bytes);
414
+ volatile VALUE holder;
415
+ char *v = ALLOCV_N(char, holder, ca->bytes);
384
416
  ca_fetch_index(ca, idx, v);
385
- out = rb_ca_ptr2obj(self, v);
386
- xfree(v);
417
+ out = rb_ca_ptr2obj_storage(self, v);
418
+ ALLOCV_END(holder);
387
419
  }
388
420
 
389
421
  /* Mask check with inline skip for the entity+no-mask common case. */
@@ -401,7 +433,7 @@ rb_ca_elem_fetch (VALUE self, VALUE ridx)
401
433
  }
402
434
  }
403
435
 
404
- CA_FACE_STORAGE_TO_SCALAR_IF_FACE(out, self, ca);
436
+ CA_FACE_STORAGE_TO_ELEMENT_IF_FACE(out, self, ca);
405
437
  return out;
406
438
  }
407
439
  else {
@@ -690,10 +722,7 @@ rb_ca_elem_mask (VALUE self, VALUE ridx)
690
722
  /* General path: view array. Walk parent chain + dispatch. */
691
723
  {
692
724
  boolean8_t one = 1;
693
- ca_update_mask(ca);
694
- if ( ! ca->mask ) {
695
- ca_create_mask(ca);
696
- }
725
+ ca_create_mask(ca);
697
726
  if ( TYPE(ridx) == T_ARRAY ) {
698
727
  elem_parse_idx_array(ca, ridx, idx);
699
728
  ca_store_index(ca->mask, idx, &one);
@@ -758,6 +787,11 @@ rb_ca_elem_unmask (VALUE self, VALUE ridx)
758
787
  * rule (NaN is treated as missing: `min(NaN, v)` returns `v`,
759
788
  * `min(x, NaN)` returns `x`). Raises for non-numeric data_type. */
760
789
 
790
+ /* The entity fast path takes a Float into a float cell and an Integer
791
+ that fits the cell. Anything else -- a Float into an integer cell, an
792
+ Integer out of the type's range, a Bignum or Rational -- goes to the
793
+ general path, which compares in Ruby and stores as `self[idx] = v`
794
+ does, so a value that wins but does not fit raises. */
761
795
  #define ELEM_MINMAX_BODY(OP) do { \
762
796
  if ( ca_is_entity(ca) ) { \
763
797
  ca_size_t addr; \
@@ -775,14 +809,6 @@ rb_ca_elem_unmask (VALUE self, VALUE ridx)
775
809
  switch ( ca->data_type ) { \
776
810
  case CA_FLOAT64: { double *q=(double *)p; if (v OP *q || *q != *q) *q = v; return self; } \
777
811
  case CA_FLOAT32: { float *q=(float *)p; float vf=(float)v; if (vf OP *q || *q != *q) *q = vf; return self; } \
778
- case CA_INT64: { int64_t *q=(int64_t *)p; if ((int64_t)v OP *q) *q = (int64_t)v; return self; } \
779
- case CA_INT32: { int32_t *q=(int32_t *)p; if ((int32_t)v OP *q) *q = (int32_t)v; return self; } \
780
- case CA_INT16: { int16_t *q=(int16_t *)p; if ((int16_t)v OP *q) *q = (int16_t)v; return self; } \
781
- case CA_INT8: { int8_t *q=(int8_t *)p; if ((int8_t )v OP *q) *q = (int8_t )v; return self; } \
782
- case CA_UINT64: { uint64_t *q=(uint64_t*)p; if ((uint64_t)v OP *q) *q = (uint64_t)v; return self; } \
783
- case CA_UINT32: { uint32_t *q=(uint32_t*)p; if ((uint32_t)v OP *q) *q = (uint32_t)v; return self; } \
784
- case CA_UINT16: { uint16_t *q=(uint16_t*)p; if ((uint16_t)v OP *q) *q = (uint16_t)v; return self; } \
785
- case CA_UINT8: { uint8_t *q=(uint8_t *)p; if ((uint8_t )v OP *q) *q = (uint8_t )v; return self; } \
786
812
  } \
787
813
  } \
788
814
  else if ( FIXNUM_P(rval) ) { \
@@ -791,13 +817,13 @@ rb_ca_elem_unmask (VALUE self, VALUE ridx)
791
817
  case CA_FLOAT64: { double *q=(double *)p; double vd=(double)v; if (vd OP *q || *q != *q) *q = vd; return self; } \
792
818
  case CA_FLOAT32: { float *q=(float *)p; float vf=(float )v; if (vf OP *q || *q != *q) *q = vf; return self; } \
793
819
  case CA_INT64: { int64_t *q=(int64_t *)p; if ((int64_t)v OP *q) *q = (int64_t)v; return self; } \
794
- case CA_INT32: { int32_t *q=(int32_t *)p; if ((int32_t)v OP *q) *q = (int32_t)v; return self; } \
795
- case CA_INT16: { int16_t *q=(int16_t *)p; if ((int16_t)v OP *q) *q = (int16_t)v; return self; } \
796
- case CA_INT8: { int8_t *q=(int8_t *)p; if ((int8_t )v OP *q) *q = (int8_t )v; return self; } \
797
- case CA_UINT64: { uint64_t *q=(uint64_t*)p; if ((uint64_t)v OP *q) *q = (uint64_t)v; return self; } \
798
- case CA_UINT32: { uint32_t *q=(uint32_t*)p; if ((uint32_t)v OP *q) *q = (uint32_t)v; return self; } \
799
- case CA_UINT16: { uint16_t *q=(uint16_t*)p; if ((uint16_t)v OP *q) *q = (uint16_t)v; return self; } \
800
- case CA_UINT8: { uint8_t *q=(uint8_t *)p; if ((uint8_t )v OP *q) *q = (uint8_t )v; return self; } \
820
+ case CA_INT32: { if ( ! (v >= INT32_MIN && v <= INT32_MAX) ) break; int32_t *q=(int32_t *)p; if ((int32_t)v OP *q) *q = (int32_t)v; return self; } \
821
+ case CA_INT16: { if ( ! (v >= INT16_MIN && v <= INT16_MAX) ) break; int16_t *q=(int16_t *)p; if ((int16_t)v OP *q) *q = (int16_t)v; return self; } \
822
+ case CA_INT8: { if ( ! (v >= INT8_MIN && v <= INT8_MAX) ) break; int8_t *q=(int8_t *)p; if ((int8_t )v OP *q) *q = (int8_t )v; return self; } \
823
+ case CA_UINT64: { if ( ! (v >= 0) ) break; uint64_t *q=(uint64_t*)p; if ((uint64_t)v OP *q) *q = (uint64_t)v; return self; } \
824
+ case CA_UINT32: { if ( ! (v >= 0 && v <= (long) UINT32_MAX) ) break; uint32_t *q=(uint32_t*)p; if ((uint32_t)v OP *q) *q = (uint32_t)v; return self; } \
825
+ case CA_UINT16: { if ( ! (v >= 0 && v <= (long) UINT16_MAX) ) break; uint16_t *q=(uint16_t*)p; if ((uint16_t)v OP *q) *q = (uint16_t)v; return self; } \
826
+ case CA_UINT8: { if ( ! (v >= 0 && v <= (long) UINT8_MAX) ) break; uint8_t *q=(uint8_t *)p; if ((uint8_t )v OP *q) *q = (uint8_t )v; return self; } \
801
827
  } \
802
828
  } \
803
829
  } \
@@ -817,6 +843,10 @@ rb_ca_elem_min (VALUE self, VALUE ridx, VALUE rval)
817
843
  rb_raise(rb_eCADataTypeError,
818
844
  "elem_min requires a numeric array");
819
845
  }
846
+ if ( ca_is_complex_type(ca) ) {
847
+ rb_raise(rb_eCADataTypeError,
848
+ "elem_min requires a real array (complex values have no order)");
849
+ }
820
850
 
821
851
  /* Super-hot path: entity + numeric data type + Fixnum/Float rval. */
822
852
  ELEM_MINMAX_BODY(<);
@@ -846,7 +876,7 @@ rb_ca_elem_min (VALUE self, VALUE ridx, VALUE rval)
846
876
 
847
877
  cur = from_array ? rb_ca_fetch_index(self, idx) : rb_ca_fetch_addr(self, addr);
848
878
  if ( cur == CA_UNDEF ) return self;
849
- if ( RTEST(rb_funcall(rval, rb_intern("<"), 1, cur)) ) {
879
+ if ( ca_obj_extremum_replaces(rval, cur, rb_intern("<")) ) {
850
880
  if ( from_array ) rb_ca_store_index(self, idx, rval);
851
881
  else rb_ca_store_addr(self, addr, rval);
852
882
  }
@@ -873,6 +903,10 @@ rb_ca_elem_max (VALUE self, VALUE ridx, VALUE rval)
873
903
  rb_raise(rb_eCADataTypeError,
874
904
  "elem_max requires a numeric array");
875
905
  }
906
+ if ( ca_is_complex_type(ca) ) {
907
+ rb_raise(rb_eCADataTypeError,
908
+ "elem_max requires a real array (complex values have no order)");
909
+ }
876
910
 
877
911
  ELEM_MINMAX_BODY(>);
878
912
 
@@ -899,7 +933,7 @@ rb_ca_elem_max (VALUE self, VALUE ridx, VALUE rval)
899
933
 
900
934
  cur = from_array ? rb_ca_fetch_index(self, idx) : rb_ca_fetch_addr(self, addr);
901
935
  if ( cur == CA_UNDEF ) return self;
902
- if ( RTEST(rb_funcall(rval, rb_intern(">"), 1, cur)) ) {
936
+ if ( ca_obj_extremum_replaces(rval, cur, rb_intern(">")) ) {
903
937
  if ( from_array ) rb_ca_store_index(self, idx, rval);
904
938
  else rb_ca_store_addr(self, addr, rval);
905
939
  }