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
@@ -14,13 +14,15 @@
14
14
  - a single negative-index normaliser used by all handlers
15
15
  - fast paths (POINT / ADDRESS, ndim == argc, all-FIXNUM) at
16
16
  the top of the entry point
17
- - single-character alphabetic Symbols (:a-:z / :A-:Z) reserved
18
- for future contraction notation; the classifier raises
19
- NotImplementedError when they appear.
17
+ - single-character alphabetic Symbols (:a-:z / :A-:Z) are
18
+ reserved and kept free of meaning; the classifier raises
19
+ IndexError when they appear.
20
20
 
21
21
  --------------------------------------------------------------------------- */
22
22
 
23
23
  #include "carray.h"
24
+ #include <math.h>
25
+ #include "carray_internal.h" /* ca_index_in_range_at */
24
26
  #include "carray_index_classifier.h"
25
27
 
26
28
  /* Range accessor macros — carray_access.c keeps a private cache
@@ -85,17 +87,42 @@ typedef struct {
85
87
  static inline ca_size_t
86
88
  ca_classifier_normalize_axis_index (ca_size_t k, ca_size_t dim, int axis, int range_check)
87
89
  {
90
+ ca_size_t given = k;
88
91
  if ( k < 0 ) {
89
92
  k += dim;
90
93
  }
91
94
  if ( range_check && ( k < 0 || k >= dim ) ) {
92
- rb_raise(rb_eIndexError,
93
- "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
94
- axis, (ca_size_t) k, (ca_size_t) (dim - 1));
95
+ ca_index_out_of_range_at(given, dim, axis);
95
96
  }
96
97
  return k;
97
98
  }
98
99
 
100
+ /* Whether a range picks no cells along an axis of length dim: an exclusive
101
+ range that ends where it starts, or an endless one that starts at the end
102
+ of the axis. `last` has been counted from the end already; `start` has
103
+ not. A range in CArray otherwise always picks a cell -- one ending
104
+ before its start reads backwards. */
105
+ static inline int
106
+ ca_classifier_range_is_empty (ca_size_t start, ca_size_t last, int excl,
107
+ int endless, ca_size_t dim)
108
+ {
109
+ ca_size_t s = ( start < 0 ) ? start + dim : start;
110
+ return endless ? ( s == dim ) : ( excl && s == last );
111
+ }
112
+
113
+ /* The first index of a run of cells along an axis. A run of no cells may
114
+ start at the end of the axis (position n), as an empty slice at the end
115
+ of a Ruby Array does; a run with cells has to start on one. */
116
+ static inline ca_size_t
117
+ ca_classifier_run_start (ca_size_t idx, ca_size_t n, int axis, int empty)
118
+ {
119
+ ca_size_t i = ( idx < 0 ) ? idx + n : idx;
120
+ if ( i < 0 || i > n || ( ! empty && i == n ) ) {
121
+ ca_index_out_of_range_at(idx, n, axis);
122
+ }
123
+ return i;
124
+ }
125
+
99
126
  /* Flat-address normalisation for the `argc == 1, ndim > 1,
100
127
  Integer` path. CA_CHECK_INDEX does not carry axis info in its
101
128
  message, which is the intended behaviour on the flat path. */
@@ -108,6 +135,129 @@ ca_classifier_normalize_flat_address (ca_size_t addr, ca_size_t elements, int ra
108
135
  return addr;
109
136
  }
110
137
 
138
+ NORETURN(static void ca_classifier_invalid_key (VALUE v, int axis));
139
+ static void
140
+ ca_classifier_invalid_key (VALUE v, int axis)
141
+ {
142
+ volatile VALUE s = rb_inspect(v);
143
+ rb_raise(rb_eIndexError,
144
+ "%s: object '%s' is invalid for the index for reference at %i-dim",
145
+ ca_calling_method_name(), StringValueCStr(s), axis);
146
+ }
147
+
148
+ /* An Integer past int64 is past the end of any axis, but has no ca_size_t
149
+ to report through ca_index_out_of_range_at; it is reported as given. */
150
+ NORETURN(static void ca_classifier_key_too_large (VALUE v, const char *where));
151
+ static void
152
+ ca_classifier_key_too_large (VALUE v, const char *where)
153
+ {
154
+ volatile VALUE s = rb_inspect(v);
155
+ rb_raise(rb_eIndexError, "%s: index %s is out of range%s",
156
+ ca_calling_method_name(), StringValueCStr(s), where);
157
+ }
158
+
159
+ /* A key names a position when it holds an integer that fits ca_size_t
160
+ (int64): an Integer of that size, Bignum included (an axis of a view that
161
+ holds no memory can be longer than a Fixnum reaches), or a Float with no
162
+ fraction while it is exact (|v| <= 2**53; past that it cannot tell
163
+ neighbouring integers apart, and a count from `sum` is a Float).
164
+ Returns 1 with the position in *out, 2 for an Integer past int64 (past
165
+ every axis, which is no longer than int64), and 0 for anything else (a
166
+ Float with a fraction or past 2**53, NaN, Inf, a Rational, a String). */
167
+ static int
168
+ ca_classifier_key_position (VALUE v, ca_size_t *out)
169
+ {
170
+ if ( FIXNUM_P(v) ) {
171
+ *out = (ca_size_t) FIX2LONG(v);
172
+ return 1;
173
+ }
174
+ if ( RB_FLOAT_TYPE_P(v) ) {
175
+ double d = RFLOAT_VALUE(v);
176
+ if ( isfinite(d) && d == floor(d) && fabs(d) <= 9007199254740992.0 ) {
177
+ *out = (ca_size_t) d;
178
+ return 1;
179
+ }
180
+ return 0;
181
+ }
182
+ if ( RB_TYPE_P(v, T_BIGNUM) ) {
183
+ uint64_t mag;
184
+ int sign = rb_integer_pack(v, &mag, 1, sizeof(mag), 0,
185
+ INTEGER_PACK_NATIVE_BYTE_ORDER);
186
+ if ( sign == 2 || sign == -2
187
+ || ( sign > 0 && mag > (uint64_t) INT64_MAX )
188
+ || ( sign < 0 && mag > (uint64_t) INT64_MAX + 1 ) ) {
189
+ return 2; /* does not fit int64 */
190
+ }
191
+ *out = ( sign < 0 ) ? (ca_size_t) (0 - mag) : (ca_size_t) mag;
192
+ return 1;
193
+ }
194
+ return 0;
195
+ }
196
+
197
+ /* A key that has to name a position: a scalar key, or one inside a Range,
198
+ an Array form or a step. `where` follows the value in the out-of-range
199
+ message. */
200
+ static ca_size_t
201
+ ca_classifier_key_int_where (VALUE v, int axis, const char *where)
202
+ {
203
+ ca_size_t k;
204
+ switch ( ca_classifier_key_position(v, &k) ) {
205
+ case 1:
206
+ return k;
207
+ case 2:
208
+ ca_classifier_key_too_large(v, where);
209
+ default:
210
+ ca_classifier_invalid_key(v, axis);
211
+ }
212
+ }
213
+
214
+ static ca_size_t
215
+ ca_classifier_key_int (VALUE v, int axis)
216
+ {
217
+ char where[32];
218
+ snprintf(where, sizeof(where), " on axis %d", axis);
219
+ return ca_classifier_key_int_where(v, axis, where);
220
+ }
221
+
222
+ int
223
+ ca_index_key_is_scalar (VALUE arg)
224
+ {
225
+ return FIXNUM_P(arg) || RB_FLOAT_TYPE_P(arg) || RB_TYPE_P(arg, T_BIGNUM);
226
+ }
227
+
228
+ /* A step: an integer like any key, except that one past int64 is not past
229
+ anything -- it is a step larger than any axis, so it reaches one cell.
230
+ It is read as the largest int64 of its sign, which does the same. */
231
+ static ca_size_t
232
+ ca_classifier_key_step (VALUE v, int axis)
233
+ {
234
+ ca_size_t k;
235
+ if ( ca_classifier_key_position(v, &k) == 2 ) {
236
+ return rb_big_sign(v) ? (ca_size_t) INT64_MAX : (ca_size_t) INT64_MIN;
237
+ }
238
+ return ca_classifier_key_int(v, axis);
239
+ }
240
+
241
+ /* An axis of length 0 has no cells: a range on it reads none when it starts
242
+ at 0 (as `[][0..-1]` does), and is out of range otherwise. Returns 1 when
243
+ the axis was filled in. */
244
+ static int
245
+ ca_classifier_block_on_empty_axis (CAIndexInfo *info, int axis, ca_size_t dim,
246
+ ca_size_t start)
247
+ {
248
+ if ( dim != 0 ) {
249
+ return 0;
250
+ }
251
+ if ( start != 0 ) {
252
+ ca_index_out_of_range_at(start, dim, axis);
253
+ }
254
+ info->index_type[axis] = CA_IDX_BLOCK;
255
+ info->index[axis].block.start = 0;
256
+ info->index[axis].block.count = 0;
257
+ info->index[axis].block.step = 1;
258
+ return 1;
259
+ }
260
+
111
261
  /* -------------------------------------------------------------------- */
112
262
  /* Fast paths. */
113
263
 
@@ -131,8 +281,8 @@ ca_classifier_try_point_fast_path (ca_classifier_ctx_t *ctx)
131
281
  for (i = 0; i < ctx->argc; i++) {
132
282
  ca_size_t k = FIX2LONG(ctx->argv[i]);
133
283
  if ( ctx->info->range_check ) {
134
- /* Bignum is rejected by FIXNUM_P above; the slow path's
135
- rb_obj_is_kind_of(arg, rb_cInteger) picks it up so the
284
+ /* Bignum and Float are rejected by FIXNUM_P above; the slow path's
285
+ integer-key branch picks them up so the
136
286
  Integer semantics are preserved end-to-end. */
137
287
  k = ca_classifier_normalize_axis_index(k, ctx->ca_dim[i], (int) i,
138
288
  ctx->info->range_check);
@@ -162,12 +312,13 @@ ca_classifier_try_address_fast_path (ca_classifier_ctx_t *ctx)
162
312
 
163
313
  /* -------------------------------------------------------------------- */
164
314
  /* Single-character alphabetic Symbols (`:a`-`:z` / `:A`-`:Z`) are
165
- reserved for future contraction notation. Raises
166
- NotImplementedError rather than the generic IndexError. The
167
- caller passes any Symbol that is not `:_` / `:%`; a
168
- non-reserved Symbol returns without action. */
315
+ reserved: no index form gives them a meaning, and none should
316
+ until one is decided. Raises IndexError saying so, rather than
317
+ the generic "invalid as the index" message. The caller passes
318
+ any Symbol that is not `:_` / `:%`; a non-reserved Symbol
319
+ returns without action. */
169
320
  static inline void
170
- ca_classifier_check_reserved_contraction_symbol (VALUE sym)
321
+ ca_classifier_check_reserved_symbol (VALUE sym)
171
322
  {
172
323
  const char *name;
173
324
  if ( ! SYMBOL_P(sym) ) return;
@@ -177,9 +328,8 @@ ca_classifier_check_reserved_contraction_symbol (VALUE sym)
177
328
  && ( ( name[0] >= 'a' && name[0] <= 'z' )
178
329
  || ( name[0] >= 'A' && name[0] <= 'Z' ) )
179
330
  && name[0] != '_' /* :_ is iterator marker, handled separately */ ) {
180
- rb_raise(rb_eNotImpError,
181
- "symbol :%s is reserved for future contraction notation "
182
- "(not yet implemented)",
331
+ rb_raise(rb_eIndexError,
332
+ "symbol :%s is reserved",
183
333
  name);
184
334
  }
185
335
  }
@@ -207,40 +357,38 @@ ca_classifier_axis_from_range (ca_classifier_ctx_t *ctx, int axis, VALUE arg)
207
357
  iv_end = CA_CLASSIFIER_RANGE_END(arg);
208
358
  iv_excl = CA_CLASSIFIER_RANGE_EXCL(arg);
209
359
 
210
- start = NIL_P(iv_beg) ? 0 : NUM2SIZE(iv_beg);
211
- last = NIL_P(iv_end) ? -1 : NUM2SIZE(iv_end);
360
+ start = NIL_P(iv_beg) ? 0 : ca_classifier_key_int(iv_beg, axis);
361
+ last = NIL_P(iv_end) ? -1 : ca_classifier_key_int(iv_end, axis);
212
362
  excl = RTEST(iv_excl);
213
363
 
214
- info->index_type[axis] = CA_IDX_BLOCK;
215
-
216
- if ( info->range_check ) {
217
- /* Inlined CA_CHECK_INDEX_AT so the format string stays
218
- byte-identical with the surrounding helpers. */
219
- if ( start < 0 ) start += dim;
220
- if ( start < 0 || start >= dim ) {
221
- rb_raise(rb_eIndexError,
222
- "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
223
- axis, (ca_size_t) start, (ca_size_t) (dim - 1));
224
- }
364
+ if ( ca_classifier_block_on_empty_axis(info, axis, dim, start) ) {
365
+ return;
225
366
  }
367
+ info->index_type[axis] = CA_IDX_BLOCK;
226
368
 
227
369
  if ( last < 0 ) {
228
370
  last += dim; /* don't use CA_CHECK_INDEX for excl */
229
371
  }
230
- if ( excl && start == last ) {
372
+ /* No cells: an exclusive range that ends where it starts, or an endless
373
+ one that starts at the end of the axis. */
374
+ if ( ca_classifier_range_is_empty(start, last, excl, NIL_P(iv_end), dim) ) {
375
+ if ( info->range_check ) {
376
+ start = ca_classifier_run_start(start, dim, axis, 1);
377
+ }
231
378
  info->index[axis].block.start = start;
232
379
  info->index[axis].block.count = 0;
233
380
  info->index[axis].block.step = 1;
234
381
  return;
235
382
  }
383
+ if ( info->range_check ) {
384
+ start = ca_index_in_range_at(start, dim, axis);
385
+ }
236
386
  if ( excl ) {
237
387
  last += ( last >= start ) ? -1 : 1;
238
388
  }
239
389
  if ( info->range_check ) {
240
390
  if ( last < 0 || last >= dim ) {
241
- rb_raise(rb_eIndexError,
242
- "index %" PRId64 " is out of range (0..%" PRId64 ") at %i-dim",
243
- (ca_size_t) last, (ca_size_t) (dim - 1), axis);
391
+ ca_index_out_of_range_at(last, dim, axis);
244
392
  }
245
393
  }
246
394
  count = llabs(last - start) + 1;
@@ -250,80 +398,89 @@ ca_classifier_axis_from_range (ca_classifier_ctx_t *ctx, int axis, VALUE arg)
250
398
  info->index[axis].block.step = step;
251
399
  }
252
400
 
253
- #ifdef HAVE_RB_ARITHMETIC_SEQUENCE_EXTRACT
254
- /* ArithSeq → BLOCK */
401
+ /* A run of cells from `iv_beg` toward `iv_end` (inclusive unless excl)
402
+ taking every `step`-th: an ArithmeticSequence, or the `[range, step]`
403
+ form. The step says the direction, as it does for Ruby: one that points
404
+ away from the end reads nothing, and an endless run with a negative
405
+ step goes down to the first cell. A begin of nil starts at the end the
406
+ step walks from. */
255
407
  static void
256
- ca_classifier_axis_from_arithseq (ca_classifier_ctx_t *ctx, int axis, VALUE arg)
408
+ ca_classifier_block_stepped (ca_classifier_ctx_t *ctx, int axis,
409
+ VALUE iv_beg, VALUE iv_end, int excl, ca_size_t step)
257
410
  {
258
- ca_size_t start, last, count, step, bound;
259
- int excl;
260
- volatile VALUE iv_beg, iv_end, iv_excl;
261
- rb_arithmetic_sequence_components_t x;
411
+ ca_size_t start, last, count, bound, s;
412
+ int endless = NIL_P(iv_end);
262
413
  CAIndexInfo *info = ctx->info;
263
414
  ca_size_t dim = ctx->ca_dim[axis];
264
415
 
265
- rb_arithmetic_sequence_extract(arg, &x);
266
- iv_beg = x.begin;
267
- iv_end = x.end;
268
- iv_excl = x.exclude_end;
269
- step = NUM2SIZE(x.step);
270
-
271
- start = NIL_P(iv_beg) ? 0 : NUM2SIZE(iv_beg);
272
- last = NIL_P(iv_end) ? -1 : NUM2SIZE(iv_end);
273
- excl = RTEST(iv_excl);
274
-
275
416
  if ( step == 0 ) {
276
- rb_raise(rb_eRuntimeError,
417
+ rb_raise(rb_eArgError,
277
418
  "step in index equals to 0 in block reference");
278
419
  }
279
-
280
- info->index_type[axis] = CA_IDX_BLOCK;
281
-
282
- /* CAREFUL: always range-check start on the ArithSeq path,
283
- ignoring info->range_check. An ArithSeq with a negative or
284
- out-of-range start silently produces an empty region if this
285
- check is deferred, which upstream callers do not expect. */
286
- if ( start < 0 ) start += dim;
287
- if ( start < 0 || start >= dim ) {
288
- rb_raise(rb_eIndexError,
289
- "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
290
- axis, (ca_size_t) start, (ca_size_t) (dim - 1));
420
+ start = NIL_P(iv_beg) ? ( step < 0 ? dim - 1 : 0 )
421
+ : ca_classifier_key_int(iv_beg, axis);
422
+ last = endless ? ( step < 0 ? 0 : dim - 1 )
423
+ : ca_classifier_key_int(iv_end, axis);
424
+ if ( NIL_P(iv_beg) && dim == 0 ) {
425
+ start = 0;
291
426
  }
292
-
293
- if ( last < 0 ) {
427
+ if ( ca_classifier_block_on_empty_axis(info, axis, dim, start) ) {
428
+ return;
429
+ }
430
+ info->index_type[axis] = CA_IDX_BLOCK;
431
+ if ( ! endless && last < 0 ) {
294
432
  last += dim;
295
433
  }
296
- if ( excl && start == last ) {
297
- info->index[axis].block.start = start;
434
+ /* CAREFUL: start is range-checked here whatever info->range_check says.
435
+ A run that starts outside the axis would otherwise read as an empty
436
+ region, which upstream callers do not expect. */
437
+ s = ( start < 0 ) ? start + dim : start;
438
+ if ( ( endless && step > 0 && s == dim ) || ( ! endless && excl && s == last ) ) {
439
+ info->index[axis].block.start = ca_classifier_run_start(start, dim, axis, 1);
298
440
  info->index[axis].block.count = 0;
299
441
  info->index[axis].block.step = 1;
300
442
  return;
301
443
  }
302
- if ( excl ) {
444
+ start = ca_index_in_range_at(start, dim, axis);
445
+ if ( excl && ! endless ) {
303
446
  last += ( last >= start ) ? -1 : 1;
304
447
  }
305
448
  if ( last < 0 || last >= dim ) {
306
- rb_raise(rb_eIndexError,
307
- "index %" PRId64 " is out of range (0..%" PRId64 ") at %i-dim",
308
- (ca_size_t) last, (ca_size_t) (dim - 1), axis);
449
+ ca_index_out_of_range_at(last, dim, axis);
309
450
  }
310
- if ( (last - start) * (long long) step < 0 ) {
311
- count = 1;
451
+ if ( (last > start && step < 0) || (last < start && step > 0) ) {
452
+ info->index[axis].block.start = start;
453
+ info->index[axis].block.count = 0;
454
+ info->index[axis].block.step = 1;
455
+ return;
312
456
  }
313
- else {
314
- count = llabs(last - start) / llabs((long long) step) + 1;
457
+ /* start and last are both inside the axis, so their distance fits; the
458
+ step is taken by magnitude unsigned, since -step overflows at its
459
+ minimum. (count - 1) * step below is then at most that distance. */
460
+ {
461
+ unsigned long long span = (unsigned long long)
462
+ (last >= start ? last - start : start - last);
463
+ unsigned long long ustep = step < 0 ? 0ULL - (unsigned long long) step
464
+ : (unsigned long long) step;
465
+ count = (ca_size_t) (span / ustep) + 1;
315
466
  }
316
467
  bound = start + (count - 1) * step;
317
- if ( bound < 0 ) bound += dim; /* CA_CHECK_INDEX_AT signature */
318
- if ( bound < 0 || bound >= dim ) {
319
- rb_raise(rb_eIndexError,
320
- "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
321
- axis, (ca_size_t) bound, (ca_size_t) (dim - 1));
322
- }
468
+ bound = ca_index_in_range_at(bound, dim, axis);
323
469
  info->index[axis].block.start = start;
324
470
  info->index[axis].block.count = count;
325
471
  info->index[axis].block.step = step;
326
472
  }
473
+
474
+ #ifdef HAVE_RB_ARITHMETIC_SEQUENCE_EXTRACT
475
+ /* ArithSeq → BLOCK */
476
+ static void
477
+ ca_classifier_axis_from_arithseq (ca_classifier_ctx_t *ctx, int axis, VALUE arg)
478
+ {
479
+ rb_arithmetic_sequence_components_t x;
480
+ rb_arithmetic_sequence_extract(arg, &x);
481
+ ca_classifier_block_stepped(ctx, axis, x.begin, x.end, RTEST(x.exclude_end),
482
+ ca_classifier_key_step(x.step, axis));
483
+ }
327
484
  #endif
328
485
 
329
486
  /* T_ARRAY → BLOCK. Accepts [nil] / [Range] / [Integer] (len 1),
@@ -350,13 +507,9 @@ ca_classifier_axis_from_array (ca_classifier_ctx_t *ctx, int axis, VALUE arg)
350
507
  }
351
508
  /* [Integer] */
352
509
  {
353
- ca_size_t start = NUM2SIZE(a0);
354
- if ( start < 0 ) start += dim;
355
- if ( start < 0 || start >= dim ) {
356
- rb_raise(rb_eIndexError,
357
- "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
358
- axis, (ca_size_t) start, (ca_size_t) (dim - 1));
359
- }
510
+ ca_size_t given = ca_classifier_key_int(a0, axis);
511
+ ca_size_t start = given;
512
+ start = ca_index_in_range_at(start, dim, axis);
360
513
  info->index[axis].block.start = start;
361
514
  info->index[axis].block.count = 1;
362
515
  info->index[axis].block.step = 1;
@@ -369,75 +522,24 @@ ca_classifier_axis_from_array (ca_classifier_ctx_t *ctx, int axis, VALUE arg)
369
522
  VALUE a1 = rb_ary_entry(arg, 1);
370
523
 
371
524
  if ( NIL_P(a0) ) { /* [nil, step] */
372
- ca_size_t start = 0, last, count, step, bound;
373
- step = NUM2SIZE(a1);
374
- if ( step == 0 ) {
375
- rb_raise(rb_eRuntimeError,
376
- "step in index equals to 0 in block reference");
377
- }
378
- last = dim - 1;
379
- count = ( step < 0 ) ? 1 : (last / step + 1);
380
- bound = start + (count - 1) * step;
381
- if ( bound < 0 ) bound += dim;
382
- if ( bound < 0 || bound >= dim ) {
383
- rb_raise(rb_eIndexError,
384
- "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
385
- axis, (ca_size_t) bound, (ca_size_t) (dim - 1));
386
- }
387
- info->index[axis].block.start = start;
388
- info->index[axis].block.count = count;
389
- info->index[axis].block.step = step;
390
- return;
391
- }
392
-
393
- if ( rb_obj_is_kind_of(a0, rb_cRange) ) { /* [Range, step] */
394
- ca_size_t start, last, count, step, bound;
395
- int excl;
396
- volatile VALUE iv_beg, iv_end, iv_excl;
397
- iv_beg = CA_CLASSIFIER_RANGE_BEG(a0);
398
- iv_end = CA_CLASSIFIER_RANGE_END(a0);
399
- iv_excl = CA_CLASSIFIER_RANGE_EXCL(a0);
400
- start = NIL_P(iv_beg) ? 0 : NUM2SIZE(iv_beg);
401
- last = NIL_P(iv_end) ? -1 : NUM2SIZE(iv_end);
402
- excl = RTEST(iv_excl);
403
- step = NUM2SIZE(a1);
525
+ ca_size_t start = 0, count, step;
526
+ step = ca_classifier_key_step(a1, axis);
404
527
  if ( step == 0 ) {
405
- rb_raise(rb_eRuntimeError,
528
+ rb_raise(rb_eArgError,
406
529
  "step in index equals to 0 in block reference");
407
530
  }
408
- if ( start < 0 ) start += dim;
409
- if ( start < 0 || start >= dim ) {
410
- rb_raise(rb_eIndexError,
411
- "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
412
- axis, (ca_size_t) start, (ca_size_t) (dim - 1));
413
- }
414
- if ( last < 0 ) last += dim;
415
- if ( excl && start == last ) {
416
- info->index[axis].block.start = start;
417
- info->index[axis].block.count = 0;
418
- info->index[axis].block.step = 1;
419
- return;
420
- }
421
- if ( excl ) {
422
- last += ( last >= start ) ? -1 : 1;
423
- }
424
- if ( last < 0 || last >= dim ) {
425
- rb_raise(rb_eIndexError,
426
- "index %" PRId64 " is out of range (0..%" PRId64 ") at %i-dim",
427
- (ca_size_t) last, (ca_size_t) (dim - 1), axis);
531
+ /* every cell of the axis from the first at that step: none of an
532
+ axis of length 0. A negative step from the first cell reaches only
533
+ it. */
534
+ if ( dim == 0 ) {
535
+ count = 0;
536
+ step = 1;
428
537
  }
429
- if ( (last - start) * (long long) step < 0 ) {
538
+ else if ( step < 0 ) {
430
539
  count = 1;
431
540
  }
432
541
  else {
433
- count = llabs(last - start) / llabs((long long) step) + 1;
434
- }
435
- bound = start + (count - 1) * step;
436
- if ( bound < 0 ) bound += dim;
437
- if ( bound < 0 || bound >= dim ) {
438
- rb_raise(rb_eIndexError,
439
- "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
440
- axis, (ca_size_t) bound, (ca_size_t) (dim - 1));
542
+ count = (dim - 1) / step + 1;
441
543
  }
442
544
  info->index[axis].block.start = start;
443
545
  info->index[axis].block.count = count;
@@ -445,23 +547,32 @@ ca_classifier_axis_from_array (ca_classifier_ctx_t *ctx, int axis, VALUE arg)
445
547
  return;
446
548
  }
447
549
 
550
+ if ( rb_obj_is_kind_of(a0, rb_cRange) ) { /* [Range, step] */
551
+ ca_classifier_block_stepped(ctx, axis,
552
+ CA_CLASSIFIER_RANGE_BEG(a0),
553
+ CA_CLASSIFIER_RANGE_END(a0),
554
+ RTEST(CA_CLASSIFIER_RANGE_EXCL(a0)),
555
+ ca_classifier_key_step(a1, axis));
556
+ return;
557
+ }
558
+
448
559
  /* [start, count] */
449
560
  {
450
561
  ca_size_t start, count, bound;
451
- start = NUM2SIZE(a0);
452
- count = NUM2SIZE(a1);
453
- bound = start + (count - 1);
454
- if ( start < 0 ) start += dim;
455
- if ( start < 0 || start >= dim ) {
562
+ ca_size_t given;
563
+ given = ca_classifier_key_int(a0, axis);
564
+ count = ca_classifier_key_int(a1, axis);
565
+ /* The start counts from the end when negative; the last cell is
566
+ counted from that start and has to be inside as it is. A count
567
+ of 0 may start at the end of the axis. */
568
+ start = ca_classifier_run_start(given, dim, axis, count == 0);
569
+ if ( count > 0 &&
570
+ ( __builtin_add_overflow(start, count - 1, &bound) || bound >= dim ) ) {
456
571
  rb_raise(rb_eIndexError,
457
- "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
458
- axis, (ca_size_t) start, (ca_size_t) (dim - 1));
459
- }
460
- if ( bound < 0 ) bound += dim;
461
- if ( bound < 0 || bound >= dim ) {
462
- rb_raise(rb_eIndexError,
463
- "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
464
- axis, (ca_size_t) bound, (ca_size_t) (dim - 1));
572
+ "%s: index [%" PRId64 ", %" PRId64 "] is out of range for "
573
+ "length %" PRId64 " on axis %i",
574
+ ca_calling_method_name(), (ca_size_t) given, (ca_size_t) count,
575
+ (ca_size_t) dim, axis);
465
576
  }
466
577
  info->index[axis].block.start = start;
467
578
  info->index[axis].block.count = count;
@@ -471,26 +582,28 @@ ca_classifier_axis_from_array (ca_classifier_ctx_t *ctx, int axis, VALUE arg)
471
582
  }
472
583
 
473
584
  if ( len == 3 ) { /* [start, count, step] */
474
- ca_size_t start, count, step, bound;
475
- start = NUM2SIZE(rb_ary_entry(arg, 0));
476
- count = NUM2SIZE(rb_ary_entry(arg, 1));
477
- step = NUM2SIZE(rb_ary_entry(arg, 2));
585
+ ca_size_t given, start, count, step, bound;
586
+ given = ca_classifier_key_int(rb_ary_entry(arg, 0), axis);
587
+ count = ca_classifier_key_int(rb_ary_entry(arg, 1), axis);
588
+ step = ca_classifier_key_step(rb_ary_entry(arg, 2), axis);
478
589
  if ( step == 0 ) {
479
- rb_raise(rb_eRuntimeError,
590
+ rb_raise(rb_eArgError,
480
591
  "step in index equals to 0 in block reference");
481
592
  }
482
- bound = start + (count - 1) * step;
483
- if ( start < 0 ) start += dim;
484
- if ( start < 0 || start >= dim ) {
485
- rb_raise(rb_eIndexError,
486
- "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
487
- axis, (ca_size_t) start, (ca_size_t) (dim - 1));
488
- }
489
- if ( bound < 0 ) bound += dim;
490
- if ( bound < 0 || bound >= dim ) {
593
+ /* The start counts from the end when negative; the last cell is
594
+ counted from that start and has to be inside as it is, not a bound
595
+ that wraps back in from either end. A count of 0 may start at the
596
+ end of the axis. */
597
+ start = ca_classifier_run_start(given, dim, axis, count == 0);
598
+ if ( count > 0 &&
599
+ ( __builtin_mul_overflow(count - 1, step, &bound) ||
600
+ __builtin_add_overflow(start, bound, &bound) ||
601
+ bound < 0 || bound >= dim ) ) {
491
602
  rb_raise(rb_eIndexError,
492
- "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )",
493
- axis, (ca_size_t) bound, (ca_size_t) (dim - 1));
603
+ "%s: index [%" PRId64 ", %" PRId64 ", %" PRId64 "] is out of "
604
+ "range for length %" PRId64 " on axis %i",
605
+ ca_calling_method_name(), (ca_size_t) given, (ca_size_t) count,
606
+ (ca_size_t) step, (ca_size_t) dim, axis);
494
607
  }
495
608
  info->index[axis].block.start = start;
496
609
  info->index[axis].block.count = count;
@@ -519,8 +632,8 @@ ca_classifier_dispatch_axis_arg (ca_classifier_ctx_t *ctx, int axis, VALUE arg,
519
632
  CAIndexInfo *info = ctx->info;
520
633
  ca_size_t dim = ctx->ca_dim[axis];
521
634
 
522
- if ( rb_obj_is_kind_of(arg, rb_cInteger) ) {
523
- ca_size_t k = NUM2SIZE(arg);
635
+ if ( ca_index_key_is_scalar(arg) ) {
636
+ ca_size_t k = ca_classifier_key_int(arg, axis);
524
637
  info->index_type[axis] = CA_IDX_SCALAR;
525
638
  if ( info->range_check ) {
526
639
  k = ca_classifier_normalize_axis_index(k, dim, axis, info->range_check);
@@ -563,11 +676,11 @@ ca_classifier_dispatch_axis_arg (ca_classifier_ctx_t *ctx, int axis, VALUE arg,
563
676
  "symbol :_ (newaxis) is handled at the [] / []= level, "
564
677
  "not valid in scan_index");
565
678
  }
566
- ca_classifier_check_reserved_contraction_symbol(arg); /* raises if reserved */
679
+ ca_classifier_check_reserved_symbol(arg); /* raises if reserved */
567
680
  rb_raise(rb_eIndexError,
568
- "symbol :%s is invalid as the index for slab iterator "
681
+ "symbol :%"PRIsVALUE" is invalid as the index for slab iterator "
569
682
  "(use :> instead)",
570
- rb_id2name(SYM2ID(arg)));
683
+ rb_sym2str(arg));
571
684
  }
572
685
  if ( rb_obj_is_carray(arg) ) {
573
686
  /* CArray (boolean / integer) at an axis position → GRID.
@@ -584,12 +697,7 @@ ca_classifier_dispatch_axis_arg (ca_classifier_ctx_t *ctx, int axis, VALUE arg,
584
697
  "(should be boolean or integer)",
585
698
  ca_type_name[ci->data_type], axis);
586
699
  }
587
- {
588
- VALUE inspect = rb_inspect(arg);
589
- rb_raise(rb_eIndexError,
590
- "object '%s' is invalid for the index for reference at %i-dim",
591
- StringValuePtr(inspect), axis);
592
- }
700
+ ca_classifier_invalid_key(arg, axis);
593
701
  }
594
702
 
595
703
  /* -------------------------------------------------------------------- */
@@ -599,66 +707,117 @@ ca_classifier_dispatch_axis_arg (ca_classifier_ctx_t *ctx, int axis, VALUE arg,
599
707
  rubber marker is honoured; a second one falls through to the
600
708
  per-axis dispatcher and raises. */
601
709
 
602
- static void
603
- ca_classifier_expand_rubber_dim (ca_classifier_ctx_t *ctx)
710
+ /* Expand the rubber marker (`false` or `:~`) of a key list for an
711
+ array of ndim axes into as many nils as it stands for, writing the
712
+ list into out (CA_RANK_MAX slots). Returns the new count, or -1 when
713
+ the list has no rubber marker (out is then untouched). Only the first
714
+ marker is honoured; a later one is left for the axis reader to refuse. */
715
+ long
716
+ ca_index_expand_rubber (int ndim, long argc, const VALUE *argv, VALUE *out)
604
717
  {
605
718
  long i, j;
606
- long argc = ctx->argc;
607
- VALUE *argv = ctx->argv;
608
719
  int rubber_pos = -1;
609
- long expanded_argc;
610
- int rndim;
720
+ int rndim;
611
721
 
722
+ ca_classifier_sym_cache_init();
612
723
  for (i = 0; i < argc; i++) {
613
724
  if ( argv[i] == Qfalse || argv[i] == ca_classifier_sym_tilde ) {
614
- rubber_pos = (int) i; /* :~ is an alias for the `false` rubber marker */
615
- /* Only the first rubber marker is honoured; later occurrences fall
616
- through to the per-axis dispatcher and raise. */
725
+ rubber_pos = (int) i;
617
726
  break;
618
727
  }
619
728
  }
620
-
621
729
  if ( rubber_pos < 0 ) {
622
- /* No rubber dim — validate argc == ndim and pass through. */
623
- if ( argc != ctx->ca_ndim ) {
624
- rb_raise(rb_eIndexError,
625
- "number of indices exceeds the ndim of carray (%i > %i)",
626
- (int) argc, ctx->ca_ndim);
627
- }
628
- return;
730
+ return -1;
629
731
  }
630
-
631
- if ( argc > ctx->ca_ndim + 1 ) {
732
+ if ( argc > ndim + 1 ) {
632
733
  rb_raise(rb_eIndexError,
633
- "index specification exceeds the ndim of carray (%i)",
634
- ctx->ca_ndim);
734
+ "index specification exceeds the ndim of carray (%i)", ndim);
635
735
  }
636
-
637
- /* rndim = number of nils the rubber expands to.
638
- *
639
- * CAREFUL: rndim == 0 is a valid outcome — the rubber consumes
640
- * nothing when argc == ndim + 1 (e.g. `[false, 0, 1]` on
641
- * ndim = 2 collapses to `[0, 1]`). Clamping only at the
642
- * negative side preserves that path. */
643
- rndim = ctx->ca_ndim - (int)argc + 1;
736
+ /* CAREFUL: rndim == 0 is a valid outcome -- the rubber consumes nothing
737
+ when argc == ndim + 1 (e.g. `[false, 0, 1]` on ndim = 2 collapses to
738
+ `[0, 1]`). Clamping only at the negative side preserves that path. */
739
+ rndim = ndim - (int) argc + 1;
644
740
  if ( rndim < 0 ) rndim = 0;
645
- expanded_argc = argc - 1 + rndim;
646
-
647
741
  j = 0;
648
742
  for (i = 0; i < argc; i++) {
649
743
  if ( i == rubber_pos ) {
650
744
  int k;
651
745
  for (k = 0; k < rndim; k++) {
652
- ctx->argv_expanded[j++] = Qnil;
746
+ out[j++] = Qnil;
653
747
  }
654
748
  } else {
655
- ctx->argv_expanded[j++] = argv[i];
749
+ out[j++] = argv[i];
656
750
  }
657
751
  }
658
- ctx->argc = expanded_argc;
752
+ return j;
753
+ }
754
+
755
+ static void
756
+ ca_classifier_expand_rubber_dim (ca_classifier_ctx_t *ctx)
757
+ {
758
+ long n = ca_index_expand_rubber(ctx->ca_ndim, ctx->argc, ctx->argv,
759
+ ctx->argv_expanded);
760
+ if ( n < 0 ) {
761
+ /* No rubber dim -- validate argc == ndim and pass through. */
762
+ if ( ctx->argc != ctx->ca_ndim ) {
763
+ rb_raise(rb_eIndexError,
764
+ "%i indices given for a carray of ndim %i",
765
+ (int) ctx->argc, ctx->ca_ndim);
766
+ }
767
+ return;
768
+ }
769
+ ctx->argc = n;
659
770
  ctx->argv = ctx->argv_expanded;
660
771
  }
661
772
 
773
+ /* Read one key along an axis of length dim, as the indexer reads it when
774
+ the key is not a CArray: an Integer, nil, a Range, an
775
+ ArithmeticSequence or an Array form. Fills *start / *count / *step and
776
+ returns CA_IDX_SCALAR (count 1), CA_IDX_ALL (the whole axis) or
777
+ CA_IDX_BLOCK. Anything else raises IndexError. grid and CASelectAxis
778
+ read their non-CArray keys through this, so a key means the same cells
779
+ whichever view the indexer builds. */
780
+ int
781
+ ca_index_axis_key (VALUE arg, ca_size_t dim, int axis,
782
+ ca_size_t *start, ca_size_t *count, ca_size_t *step)
783
+ {
784
+ ca_classifier_ctx_t ctx;
785
+ CAIndexInfo info;
786
+ ca_size_t dims[CA_RANK_MAX];
787
+ int is_grid = 0;
788
+
789
+ ca_classifier_sym_cache_init();
790
+ if ( axis < 0 || axis >= CA_RANK_MAX ) { /* rank-check: an axis number, not a rank */
791
+ rb_raise(rb_eArgError, "axis %d is out of range", axis);
792
+ }
793
+ dims[axis] = dim;
794
+ ctx.ca_ndim = axis + 1;
795
+ ctx.ca_dim = dims;
796
+ ctx.info = &info;
797
+ info.range_check = 1;
798
+ if ( rb_obj_is_carray(arg) || arg == ca_classifier_sym_gt ) {
799
+ ca_classifier_invalid_key(arg, axis);
800
+ }
801
+ ca_classifier_dispatch_axis_arg(&ctx, axis, arg, &is_grid);
802
+ switch ( info.index_type[axis] ) {
803
+ case CA_IDX_SCALAR:
804
+ *start = info.index[axis].scalar;
805
+ *count = 1;
806
+ *step = 1;
807
+ return CA_IDX_SCALAR;
808
+ case CA_IDX_ALL:
809
+ *start = 0;
810
+ *count = dim;
811
+ *step = 1;
812
+ return CA_IDX_ALL;
813
+ default:
814
+ *start = info.index[axis].block.start;
815
+ *count = info.index[axis].block.count;
816
+ *step = info.index[axis].block.step;
817
+ return CA_IDX_BLOCK;
818
+ }
819
+ }
820
+
662
821
  /* -------------------------------------------------------------------- */
663
822
  /* Final REG decision — walks info->index_type[] and decides
664
823
  POINT / BLOCK / ITERATOR / GRID. */
@@ -718,16 +877,13 @@ ca_classifier_try_argc1_special (ca_classifier_ctx_t *ctx)
718
877
  return 1;
719
878
  }
720
879
 
721
- /* T_STRING: "@name" → ATTRIBUTE, "field" → MEMBER. */
880
+ /* T_STRING: "field" → MEMBER. */
722
881
  if ( TYPE(arg) == T_STRING ) {
723
- const char *s = StringValuePtr(arg);
724
- if ( s[0] == '@' ) {
725
- info->type = CA_REG_ATTRIBUTE;
726
- info->symbol = rb_str_new2(s + 1);
727
- } else {
728
- info->type = CA_REG_MEMBER;
729
- info->symbol = ID2SYM(rb_intern(s));
730
- }
882
+ info->type = CA_REG_MEMBER;
883
+ /* A dynamic Symbol: the collector reclaims it, so indexing with
884
+ strings that name no member does not grow the symbol table. */
885
+ StringValueCStr(arg);
886
+ info->symbol = rb_to_symbol(arg);
731
887
  return 1;
732
888
  }
733
889
 
@@ -744,8 +900,26 @@ ca_classifier_try_argc1_special (ca_classifier_ctx_t *ctx)
744
900
  return 1;
745
901
  }
746
902
  if ( ca_is_boolean_type(cs) ) {
903
+ /* A boolean selector of more than one axis states a shape, and has
904
+ to have the array's; a 1-D one picks by position among all the
905
+ cells. */
906
+ if ( cs->ndim > 1 ) {
907
+ int k, same = ( cs->ndim == ctx->ca_ndim );
908
+ for (k = 0; same && k < cs->ndim; k++) {
909
+ same = ( cs->dim[k] == ctx->ca_dim[k] );
910
+ }
911
+ if ( ! same ) {
912
+ volatile VALUE sshape = rb_ary_new(), ashape = rb_ary_new();
913
+ for (k = 0; k < cs->ndim; k++) rb_ary_push(sshape, SIZE2NUM(cs->dim[k]));
914
+ for (k = 0; k < ctx->ca_ndim; k++) rb_ary_push(ashape, SIZE2NUM(ctx->ca_dim[k]));
915
+ rb_raise(rb_eArgError,
916
+ "boolean selector of shape %"PRIsVALUE" for an array of shape "
917
+ "%"PRIsVALUE" (a selector states its shape; use .flatten to "
918
+ "select by position)", sshape, ashape);
919
+ }
920
+ }
747
921
  if ( ctx->ca_elements != cs->elements ) {
748
- rb_raise(rb_eRuntimeError,
922
+ rb_raise(rb_eArgError,
749
923
  "mismatch of # of elements ( %" PRId64 " <=> %" PRId64 " ) "
750
924
  "in reference by selection",
751
925
  (ca_size_t) cs->elements,
@@ -761,10 +935,11 @@ ca_classifier_try_argc1_special (ca_classifier_ctx_t *ctx)
761
935
  ca_type_name[cs->data_type]);
762
936
  }
763
937
 
764
- /* ndim > 1 with Integer → ADDRESS. Fixnum was caught by the
765
- fast path; this branch handles Bignum. */
766
- if ( ctx->ca_ndim > 1 && rb_obj_is_kind_of(arg, rb_cInteger) ) {
767
- ca_size_t addr = NUM2SIZE(arg);
938
+ /* ndim > 1 with an integer key → ADDRESS. Fixnum was caught by the
939
+ fast path; this branch handles Bignum and Float. */
940
+ if ( ctx->ca_ndim > 1
941
+ && ca_index_key_is_scalar(arg) ) {
942
+ ca_size_t addr = ca_classifier_key_int_where(arg, 0, "");
768
943
  info->type = CA_REG_ADDRESS;
769
944
  info->ndim = 1;
770
945
  if ( info->range_check ) {
@@ -826,7 +1001,7 @@ rb_ca_scan_index_v2 (int ca_ndim, ca_size_t *ca_dim, ca_size_t ca_elements,
826
1001
  /* argv[0] = multi-char Symbol → METHOD_CALL. Single-char
827
1002
  specials (:_ / :%) fall through the strlen check and are
828
1003
  handled downstream (argc == 1 special / fast paths / main
829
- loop). Single-char alphabetic reserved-contraction Symbols
1004
+ loop). Single-char alphabetic reserved Symbols
830
1005
  also fall through here and are raised later by the per-axis
831
1006
  dispatcher's SYMBOL_P branch. */
832
1007
  if ( SYMBOL_P(argv[0]) ) {
@@ -878,7 +1053,7 @@ rb_ca_scan_index_v2 (int ca_ndim, ca_size_t *ca_dim, ca_size_t ca_elements,
878
1053
  here would raise on legitimate grid regions. */
879
1054
  if ( ! is_grid && ctx.ca_ndim != info->ndim ) {
880
1055
  rb_raise(rb_eIndexError,
881
- "number of indices does not equal to the ndim (%i != %i)",
1056
+ "%i indices given for a carray of ndim %i",
882
1057
  info->ndim, ctx.ca_ndim);
883
1058
  }
884
1059
 
@@ -886,6 +1061,7 @@ rb_ca_scan_index_v2 (int ca_ndim, ca_size_t *ca_dim, ca_size_t ca_elements,
886
1061
  }
887
1062
  }
888
1063
 
1064
+ #ifdef CARRAY_DEV_BUILD
889
1065
  /* -------------------------------------------------------------------- */
890
1066
  /* Debug / test surface: CArray._scan_index_v2(dim_array, idx_array)
891
1067
  returns a plain [type_int, index_array] pair rather than the
@@ -911,8 +1087,8 @@ rb_ca_s_scan_index_v2 (VALUE self, VALUE rdim, VALUE ridx)
911
1087
  elements *= dim[i];
912
1088
  }
913
1089
 
914
- CA_CHECK_RANK(ndim);
915
- CA_CHECK_DIM(ndim, dim);
1090
+ CA_CHECK_RANK_GIVEN(ndim);
1091
+ CA_CHECK_DIM_GIVEN(ndim, dim);
916
1092
 
917
1093
  info.range_check = 1;
918
1094
  rb_ca_scan_index_v2(ndim, dim, elements,
@@ -1001,7 +1177,7 @@ rb_ca_s_scan_index_v2 (VALUE self, VALUE rdim, VALUE ridx)
1001
1177
  info.index[i].symbol.spec));
1002
1178
  break;
1003
1179
  default:
1004
- rb_raise(rb_eRuntimeError, "unknown index spec");
1180
+ rb_raise(rb_eIndexError, "unknown index spec");
1005
1181
  }
1006
1182
  }
1007
1183
  break;
@@ -1011,11 +1187,14 @@ rb_ca_s_scan_index_v2 (VALUE self, VALUE rdim, VALUE ridx)
1011
1187
 
1012
1188
  return rb_ary_new3(2, INT2NUM(info.type), rindex);
1013
1189
  }
1190
+ #endif
1014
1191
 
1015
1192
  void
1016
1193
  Init_carray_index_classifier (void)
1017
1194
  {
1018
1195
  ca_classifier_sym_cache_init();
1196
+ #ifdef CARRAY_DEV_BUILD
1019
1197
  rb_define_singleton_method(rb_cCArray, "_scan_index_v2",
1020
1198
  rb_ca_s_scan_index_v2, 2);
1199
+ #endif
1021
1200
  }