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
@@ -9,13 +9,16 @@
9
9
 
10
10
  #include "ruby.h"
11
11
  #include "carray.h"
12
+ #include "carray_internal.h" /* ca_attach_window, ca_normalize_axis_arg */
13
+ #include "ca_obj_face.h" /* ca_face_element_to_storage */
12
14
 
13
15
  /* ----------------------------------------------------------------- */
14
16
 
15
17
  /* CArray#where -- collect the flat addresses of all non-zero (or
16
- true) cells in self into a fresh 1-D CA_SIZE array. Non-boolean
17
- inputs are first coerced to boolean via rb_ca_to_boolean. Masked
18
- cells are excluded.
18
+ true) cells in self into a fresh 1-D CA_SIZE array. An integer,
19
+ float or complex array selects its non-zero cells (NaN is non-zero);
20
+ any other non-boolean array is cast to boolean, which takes only
21
+ 0 / 1 / true / false. Masked cells are excluded.
19
22
 
20
23
  Also used internally by ext/ca_obj_grid.c when it needs to extract
21
24
  the addresses of true cells from a boolean axis selector. */
@@ -26,28 +29,44 @@ rb_ca_where (VALUE self)
26
29
  CArray *ca, *co;
27
30
  boolean8_t *p, *m;
28
31
  ca_size_t *q;
29
- ca_size_t i, count;
32
+ ca_size_t i, j, n, last, count;
30
33
 
31
- bool0 = ( ! rb_ca_is_boolean_type(self) ) ? rb_ca_to_boolean(self) : self;
34
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
35
+ if ( ca_is_boolean_type(ca) ) {
36
+ bool0 = self;
37
+ }
38
+ else if ( ! ca_is_face(ca) &&
39
+ ( ca_is_integer_type(ca) || ca_is_float_type(ca) ||
40
+ ca_is_complex_type(ca) ) ) {
41
+ bool0 = rb_funcall(self, rb_intern("ne"), 1, INT2FIX(0));
42
+ }
43
+ else {
44
+ bool0 = rb_ca_to_boolean(self);
45
+ }
32
46
 
33
47
  TypedData_Get_Struct(bool0, CArray, &carray_data_type, ca);
34
48
 
35
- ca_attach(ca);
49
+ ca_attach(ca); /* window: nothing raises inside */
36
50
 
37
- /* calculate elements of output array */
51
+ /* calculate elements of output array, and the last selected cell */
38
52
  p = (boolean8_t *) ca->ptr;
39
53
  m = ca_mask_ptr(ca);
54
+ n = ca->elements;
40
55
  count = 0;
41
56
  if ( m ) {
42
- for (i=0; i<ca->elements; i++) {
43
- if ( ( ! *m ) && ( *p ) ) { count++; } /* not-masked && true */
44
- m++; p++;
57
+ for (i=0; i<n; i++) {
58
+ count += ( ! m[i] ) & ( p[i] != 0 ); /* not-masked && true */
45
59
  }
46
60
  }
47
61
  else {
48
- for (i=0; i<ca->elements; i++) {
49
- if ( *p ) { count++; } /* true */
50
- p++;
62
+ for (i=0; i<n; i++) {
63
+ count += ( p[i] != 0 ); /* true */
64
+ }
65
+ }
66
+ last = n - 1;
67
+ if ( count > 0 ) {
68
+ while ( m ? ( m[last] || ! p[last] ) : ! p[last] ) {
69
+ last--;
51
70
  }
52
71
  }
53
72
 
@@ -55,20 +74,25 @@ rb_ca_where (VALUE self)
55
74
  obj = rb_carray_new(CA_SIZE, 1, &count, 0, NULL);
56
75
  TypedData_Get_Struct(obj, CArray, &carray_data_type, co);
57
76
 
58
- /* store address which elements is true to output array */
59
- p = (boolean8_t *) ca->ptr;
77
+ /* Store the address of each selected cell. Every cell up to the last
78
+ selected one is written and the output position advances only on a
79
+ selected cell, so a selection with true and false mixed at random
80
+ does not mispredict a branch on most cells. Stopping at the last
81
+ selected cell keeps the writes inside the count slots. */
60
82
  q = (ca_size_t *) co->ptr;
61
- m = ca_mask_ptr(ca);
62
- if ( m ) {
63
- for (i=0; i<ca->elements; i++) { /* not-masked && true */
64
- if ( ( ! *m ) && ( *p ) ) { *q = i; q++; }
65
- m++; p++;
83
+ j = 0;
84
+ if ( count > 0 ) {
85
+ if ( m ) {
86
+ for (i=0; i<=last; i++) { /* not-masked && true */
87
+ q[j] = i;
88
+ j += ( ! m[i] ) & ( p[i] != 0 );
89
+ }
66
90
  }
67
- }
68
- else { /* true */
69
- for (i=0; i<ca->elements; i++) {
70
- if ( *p ) { *q = i; q++; }
71
- p++;
91
+ else { /* true */
92
+ for (i=0; i<=last; i++) {
93
+ q[j] = i;
94
+ j += ( p[i] != 0 );
95
+ }
72
96
  }
73
97
  }
74
98
 
@@ -79,6 +103,17 @@ rb_ca_where (VALUE self)
79
103
 
80
104
  /* ----------------------------------------------------------------- */
81
105
 
106
+ /* A number that is not an Integer (a Float, a Rational, a BigDecimal) makes
107
+ the progression a real one: every cell is offset + step*i computed in
108
+ double, and an integer array takes it as a store takes a float (cut
109
+ toward zero; the run is checked to fit before anything is written). */
110
+ static int
111
+ ca_seq_is_real (VALUE v)
112
+ {
113
+ return ! NIL_P(v) && ! RB_INTEGER_TYPE_P(v) && ! RB_TYPE_P(v, T_COMPLEX)
114
+ && RTEST(rb_obj_is_kind_of(v, rb_cNumeric));
115
+ }
116
+
82
117
  /* Fill the whole array in row-major order with `step*i + offset`. */
83
118
  #define proc_seq_bang(type, from, to) \
84
119
  { \
@@ -89,9 +124,8 @@ rb_ca_where (VALUE self)
89
124
  *p++ = (type) to(i); \
90
125
  } \
91
126
  } \
92
- else if ( rb_obj_is_kind_of(rstep, rb_cFloat) || \
93
- rb_obj_is_kind_of(roffset, rb_cFloat) ) { \
94
- type offset = (NIL_P(roffset)) ? (type) 0 : (type) from(roffset); \
127
+ else if ( ca_seq_is_real(rstep) || ca_seq_is_real(roffset) ) { \
128
+ double offset = (NIL_P(roffset)) ? 0 : NUM2DBL(roffset); \
95
129
  double step = (NIL_P(rstep)) ? 1 : NUM2DBL(rstep); \
96
130
  for (i=0; i<ca->elements; i++) { \
97
131
  *p++ = (type) to(step*i+offset); \
@@ -117,9 +151,8 @@ rb_ca_where (VALUE self)
117
151
  { \
118
152
  type *p = (type *)ca->ptr; \
119
153
  ca_size_t o, k, in; \
120
- if ( rb_obj_is_kind_of(rstep, rb_cFloat) || \
121
- rb_obj_is_kind_of(roffset, rb_cFloat) ) { \
122
- type offset = (NIL_P(roffset)) ? (type) 0 : (type) from(roffset); \
154
+ if ( ca_seq_is_real(rstep) || ca_seq_is_real(roffset) ) { \
155
+ double offset = (NIL_P(roffset)) ? 0 : NUM2DBL(roffset); \
123
156
  double step = (NIL_P(rstep)) ? 1 : NUM2DBL(rstep); \
124
157
  for (o=0; o<outer_size; o++) { \
125
158
  for (k=0; k<len; k++) { \
@@ -179,16 +212,10 @@ ca_seq_resolve_axis (CArray *ca, VALUE raxis)
179
212
  }
180
213
  if ( TYPE(raxis) == T_ARRAY ) {
181
214
  rb_raise(rb_eArgError,
182
- "seq axis must be a single integer (multi-axis seq is not supported)");
183
- }
184
- axis = NUM2INT(raxis);
185
- if ( axis < 0 ) {
186
- axis += ca->ndim;
187
- }
188
- if ( axis < 0 || axis >= ca->ndim ) {
189
- rb_raise(rb_eArgError,
190
- "axis out of range for seq (0...%d)", ca->ndim);
215
+ "%s: axis must be a single Integer (a seq over several axes is not supported)",
216
+ ca_calling_method_name());
191
217
  }
218
+ axis = ca_normalize_axis_arg(raxis, ca->ndim, NULL);
192
219
  return axis;
193
220
  }
194
221
 
@@ -208,27 +235,39 @@ ca_seq_geometry (CArray *ca, int axis,
208
235
  *outer = out;
209
236
  }
210
237
 
238
+ /* The object fill calls Ruby per cell (`+`, or the method given as the
239
+ step), which can raise part way, so it runs in a window that attaches:
240
+ the cells filled before the raise then reach the parent with the rest
241
+ left as they were, as they would for an entity. */
242
+
243
+ typedef struct {
244
+ VALUE self;
245
+ CArray *ca;
246
+ VALUE roffset;
247
+ VALUE rstep;
248
+ VALUE rmethod;
249
+ int axis;
250
+ } ca_seq_ctx_t;
251
+
252
+ /* A value of the progression as it goes into a cell: a Face receiver (a
253
+ CAString) checks it as it checks any value stored into it. */
211
254
  static VALUE
212
- rb_ca_seq_bang_object (VALUE self, VALUE roffset, VALUE rstep, int axis)
255
+ ca_seq_cell (ca_seq_ctx_t *c, VALUE v)
213
256
  {
214
- volatile VALUE rval, rmethod = Qnil;
215
- CArray *ca;
257
+ return ca_face_element_to_storage(c->self, c->ca, v);
258
+ }
259
+
260
+ static VALUE
261
+ ca_seq_bang_object_body (VALUE arg)
262
+ {
263
+ ca_seq_ctx_t *c = (ca_seq_ctx_t *) arg;
264
+ CArray *ca = c->ca;
265
+ volatile VALUE rval;
266
+ VALUE roffset = c->roffset, rstep = c->rstep, rmethod = c->rmethod;
267
+ int axis = c->axis;
216
268
  VALUE *p;
217
269
  ca_size_t i;
218
270
 
219
- TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
220
-
221
- if ( TYPE(rstep) == T_SYMBOL ) { /* e.g. a.seq("a", :succ) */
222
- rmethod = rstep;
223
- rstep = Qnil;
224
- }
225
-
226
- ca_allocate(ca);
227
-
228
- if ( ca_has_mask(ca) ) {
229
- ca_clear_mask(ca); /* clear all mask */
230
- }
231
-
232
271
  if ( axis < 0 ) { /* flat fill */
233
272
  p = (VALUE *)ca->ptr;
234
273
  if ( rb_obj_is_kind_of(roffset, rb_cFloat) ||
@@ -236,7 +275,7 @@ rb_ca_seq_bang_object (VALUE self, VALUE roffset, VALUE rstep, int axis)
236
275
  double offset = ( NIL_P(roffset) ) ? 0 : NUM2DBL(roffset);
237
276
  double step = ( NIL_P(rstep) ) ? 1 : NUM2DBL(rstep);
238
277
  for (i=0; i<ca->elements; i++) {
239
- *p++ = rb_float_new(step*i+offset);
278
+ *p++ = ca_seq_cell(c, rb_float_new(step*i+offset));
240
279
  }
241
280
  }
242
281
  else if ( NIL_P(roffset) ) {
@@ -245,22 +284,22 @@ rb_ca_seq_bang_object (VALUE self, VALUE roffset, VALUE rstep, int axis)
245
284
  "nil is invalid as offset for seq([offset[,step])");
246
285
  }
247
286
  for (i=0; i<ca->elements; i++) { /* a.seq() */
248
- *p++ = LL2NUM(i);
287
+ *p++ = ca_seq_cell(c, LL2NUM(i));
249
288
  }
250
289
  }
251
290
  else if ( ! NIL_P(rmethod) ) { /* a.seq(obj, :method) */
252
291
  ID id_method = SYM2ID(rmethod);
253
- *p++ = rval = roffset;
292
+ *p++ = ca_seq_cell(c, rval = roffset);
254
293
  for (i=1; i<ca->elements; i++) {
255
- *p++ = rval = rb_funcall(rval, id_method, 0);
294
+ *p++ = ca_seq_cell(c, rval = rb_funcall(rval, id_method, 0));
256
295
  }
257
296
  }
258
297
  else { /* a.seq(obj, step) */
259
298
  ID id_plus = rb_intern("+");
260
299
  rstep = ( NIL_P(rstep) ) ? INT2NUM(1) : rstep;
261
- *p++ = rval = roffset;
300
+ *p++ = ca_seq_cell(c, rval = roffset);
262
301
  for (i=1; i<ca->elements; i++) {
263
- *p++ = rval = rb_funcall(rval, id_plus, 1, rstep);
302
+ *p++ = ca_seq_cell(c, rval = rb_funcall(rval, id_plus, 1, rstep));
264
303
  }
265
304
  }
266
305
  }
@@ -278,7 +317,7 @@ rb_ca_seq_bang_object (VALUE self, VALUE roffset, VALUE rstep, int axis)
278
317
  double offset = ( NIL_P(roffset) ) ? 0 : NUM2DBL(roffset);
279
318
  double step = ( NIL_P(rstep) ) ? 1 : NUM2DBL(rstep);
280
319
  for (k=0; k<len; k++) {
281
- rb_ary_push(vtbl, rb_float_new(step*k+offset));
320
+ rb_ary_push(vtbl, ca_seq_cell(c, rb_float_new(step*k+offset)));
282
321
  }
283
322
  }
284
323
  else if ( NIL_P(roffset) ) {
@@ -287,26 +326,26 @@ rb_ca_seq_bang_object (VALUE self, VALUE roffset, VALUE rstep, int axis)
287
326
  "nil is invalid as offset for seq([offset[,step])");
288
327
  }
289
328
  for (k=0; k<len; k++) {
290
- rb_ary_push(vtbl, LL2NUM(k));
329
+ rb_ary_push(vtbl, ca_seq_cell(c, LL2NUM(k)));
291
330
  }
292
331
  }
293
332
  else if ( ! NIL_P(rmethod) ) {
294
333
  ID id_method = SYM2ID(rmethod);
295
334
  rval = roffset;
296
- rb_ary_push(vtbl, rval);
335
+ rb_ary_push(vtbl, ca_seq_cell(c, rval));
297
336
  for (k=1; k<len; k++) {
298
337
  rval = rb_funcall(rval, id_method, 0);
299
- rb_ary_push(vtbl, rval);
338
+ rb_ary_push(vtbl, ca_seq_cell(c, rval));
300
339
  }
301
340
  }
302
341
  else {
303
342
  ID id_plus = rb_intern("+");
304
343
  rstep = ( NIL_P(rstep) ) ? INT2NUM(1) : rstep;
305
344
  rval = roffset;
306
- rb_ary_push(vtbl, rval);
345
+ rb_ary_push(vtbl, ca_seq_cell(c, rval));
307
346
  for (k=1; k<len; k++) {
308
347
  rval = rb_funcall(rval, id_plus, 1, rstep);
309
- rb_ary_push(vtbl, rval);
348
+ rb_ary_push(vtbl, ca_seq_cell(c, rval));
310
349
  }
311
350
  }
312
351
  p = (VALUE *)ca->ptr;
@@ -318,12 +357,130 @@ rb_ca_seq_bang_object (VALUE self, VALUE roffset, VALUE rstep, int axis)
318
357
  }
319
358
  }
320
359
 
321
- ca_sync(ca);
322
- ca_detach(ca);
360
+ /* Cleared last, so a fill that raises leaves the mask as it was. */
361
+ if ( ca_has_mask(ca) ) {
362
+ ca_clear_mask(ca);
363
+ }
364
+ return Qnil;
365
+ }
366
+
367
+ static VALUE
368
+ rb_ca_seq_bang_object (VALUE self, VALUE roffset, VALUE rstep, int axis)
369
+ {
370
+ ca_seq_ctx_t c;
371
+
372
+ TypedData_Get_Struct(self, CArray, &carray_data_type, c.ca);
373
+
374
+ c.self = self;
375
+ c.rmethod = Qnil;
376
+ if ( TYPE(rstep) == T_SYMBOL ) { /* e.g. a.seq("a", :succ) */
377
+ c.rmethod = rstep;
378
+ rstep = Qnil;
379
+ }
380
+ c.roffset = roffset;
381
+ c.rstep = rstep;
382
+ c.axis = axis;
383
+
384
+ ca_attach_window(1, &c.ca, "w", ca_seq_bang_object_body, (VALUE) &c);
323
385
 
324
386
  return self;
325
387
  }
326
388
 
389
+ /* The numeric fill runs in an allocate window, which clears an entity's
390
+ mask as it opens (an entity has no separate buffer), so nothing in it may
391
+ raise: offset and step are checked to be numbers before it opens. */
392
+ static VALUE
393
+ ca_seq_bang_numeric_body (VALUE arg)
394
+ {
395
+ ca_seq_ctx_t *c = (ca_seq_ctx_t *) arg;
396
+ CArray *ca = c->ca;
397
+ VALUE roffset = c->roffset, rstep = c->rstep;
398
+
399
+ if ( ca_has_mask(ca) ) {
400
+ ca_clear_mask(ca); /* clear all mask */
401
+ }
402
+
403
+ if ( c->axis < 0 ) {
404
+ seq_bang_switch(proc_seq_bang);
405
+ }
406
+ else {
407
+ ca_size_t len, inner_size, outer_size;
408
+ ca_seq_geometry(ca, c->axis, &len, &inner_size, &outer_size);
409
+ seq_bang_switch(proc_seq_bang_axis);
410
+ }
411
+ return Qnil;
412
+ }
413
+
414
+ /* An integer array refuses a first value it cannot hold, as a store does,
415
+ and an Integer step whose size it cannot hold. An unsigned array takes
416
+ a negative step (a descending run). A run that passes the end of the
417
+ type wraps, as integer arithmetic does. */
418
+ static void
419
+ ca_seq_check_integer_args (CArray *ca, VALUE roffset, VALUE rstep)
420
+ {
421
+ int8_t dt = ca->data_type;
422
+ /* Only a number is checked here; anything else is left to the fill's
423
+ own conversion, which refuses it with TypeError. */
424
+ if ( RB_INTEGER_TYPE_P(roffset) || RB_FLOAT_TYPE_P(roffset) ) {
425
+ VALUE first = RB_INTEGER_TYPE_P(roffset) ? roffset : rb_Integer(roffset);
426
+ if ( ca_integer_range_side(first, dt) != 0 ) {
427
+ rb_raise(rb_eRangeError, "%s: first value %"PRIsVALUE" is out of range for %s",
428
+ ca_calling_method_name(), rb_inspect(roffset), ca_type_name[dt]);
429
+ }
430
+ }
431
+ if ( RB_INTEGER_TYPE_P(rstep) ) {
432
+ int is_unsigned = ( dt == CA_UINT8 || dt == CA_UINT16 ||
433
+ dt == CA_UINT32 || dt == CA_UINT64 );
434
+ VALUE size = rstep;
435
+ if ( is_unsigned && RTEST(rb_funcall(rstep, rb_intern("negative?"), 0)) ) {
436
+ size = rb_funcall(rstep, rb_intern("-@"), 0);
437
+ }
438
+ if ( ca_integer_range_side(size, dt) != 0 ) {
439
+ rb_raise(rb_eRangeError, "%s: step %"PRIsVALUE" is out of range for %s",
440
+ ca_calling_method_name(), rb_inspect(rstep), ca_type_name[dt]);
441
+ }
442
+ }
443
+ }
444
+
445
+ /* A real progression on an integer array: each cell takes offset + step*i
446
+ cut toward zero, as a store takes a float, so the first and the last
447
+ value (the extremes of a linear run) must fit the type, and NaN raises
448
+ as it does in a store. Checked before the fill writes anything. */
449
+ static void
450
+ ca_seq_check_real_run (CArray *ca, VALUE roffset, VALUE rstep, ca_size_t n)
451
+ {
452
+ int8_t dt = ca->data_type;
453
+ double offset = NIL_P(roffset) ? 0.0 : NUM2DBL(roffset);
454
+ double step = NIL_P(rstep) ? 1.0 : NUM2DBL(rstep);
455
+ double ends[2];
456
+ double lo, hi_excl;
457
+ int k;
458
+ if ( n == 0 ) return;
459
+ ends[0] = offset;
460
+ ends[1] = step * (double) (n - 1) + offset;
461
+ switch ( dt ) {
462
+ case CA_INT8: lo = INT8_MIN; hi_excl = (double) INT8_MAX + 1; break;
463
+ case CA_UINT8: lo = 0; hi_excl = (double) UINT8_MAX + 1; break;
464
+ case CA_INT16: lo = INT16_MIN; hi_excl = (double) INT16_MAX + 1; break;
465
+ case CA_UINT16: lo = 0; hi_excl = (double) UINT16_MAX + 1; break;
466
+ case CA_INT32: lo = INT32_MIN; hi_excl = (double) INT32_MAX + 1; break;
467
+ case CA_UINT32: lo = 0; hi_excl = (double) UINT32_MAX + 1; break;
468
+ case CA_INT64: lo = -ldexp(1.0, 63); hi_excl = ldexp(1.0, 63); break;
469
+ default: lo = 0; hi_excl = ldexp(1.0, 64); break;
470
+ }
471
+ for (k = 0; k < 2; k++) {
472
+ double t = trunc(ends[k]);
473
+ if ( isnan(ends[k]) || ( step != 0.0 && isnan(step) ) ) {
474
+ rb_raise(rb_eFloatDomainError, "%s: the run has NaN",
475
+ ca_calling_method_name());
476
+ }
477
+ if ( ! ( t >= lo && t < hi_excl ) ) {
478
+ rb_raise(rb_eRangeError, "%s: value %g is out of range for %s",
479
+ ca_calling_method_name(), ends[k], ca_type_name[dt]);
480
+ }
481
+ }
482
+ }
483
+
327
484
  /* CArray#seq!(init_val=0, step=1, axis: nil) -- arithmetic-progression
328
485
  fill, in place. Without `axis:` the fill runs in row-major order
329
486
  over the whole array; with `axis: k` the progression runs along axis
@@ -353,23 +510,43 @@ rb_ca_seq_bang_method (int argc, VALUE *argv, VALUE self)
353
510
  return rb_ca_seq_bang_object(self, roffset, rstep, axis);
354
511
  }
355
512
 
356
- ca_allocate(ca);
357
-
358
- if ( ca_has_mask(ca) ) {
359
- ca_clear_mask(ca); /* clear all mask */
513
+ {
514
+ VALUE args[2];
515
+ const char *names[2] = { "offset", "step" };
516
+ int k;
517
+ args[0] = roffset;
518
+ args[1] = rstep;
519
+ for (k = 0; k < 2; k++) {
520
+ VALUE v = args[k];
521
+ if ( NIL_P(v) ) continue;
522
+ if ( ! RTEST(rb_obj_is_kind_of(v, rb_cNumeric)) ||
523
+ ( RB_TYPE_P(v, T_COMPLEX) && ! ca_is_complex_type(ca) ) ) {
524
+ rb_raise(rb_eTypeError, "%s: %s must be a %snumber (got %"PRIsVALUE")",
525
+ ca_calling_method_name(), names[k],
526
+ ca_is_complex_type(ca) ? "" : "real ", rb_inspect(v));
527
+ }
528
+ }
360
529
  }
361
530
 
362
- if ( axis < 0 ) {
363
- seq_bang_switch(proc_seq_bang);
364
- }
365
- else {
366
- ca_size_t len, inner_size, outer_size;
367
- ca_seq_geometry(ca, axis, &len, &inner_size, &outer_size);
368
- seq_bang_switch(proc_seq_bang_axis);
531
+ if ( ca_is_integer_type(ca) ) {
532
+ if ( ca_seq_is_real(roffset) || ca_seq_is_real(rstep) ) {
533
+ ca_seq_check_real_run(ca, roffset, rstep,
534
+ axis < 0 ? ca->elements : ca->dim[axis]);
535
+ }
536
+ else {
537
+ ca_seq_check_integer_args(ca, roffset, rstep);
538
+ }
369
539
  }
370
540
 
371
- ca_sync(ca);
372
- ca_detach(ca);
541
+ {
542
+ ca_seq_ctx_t c;
543
+ c.ca = ca;
544
+ c.roffset = roffset;
545
+ c.rstep = rstep;
546
+ c.rmethod = Qnil;
547
+ c.axis = axis;
548
+ ca_attach_window(1, &ca, "a", ca_seq_bang_numeric_body, (VALUE) &c);
549
+ }
373
550
 
374
551
  return self;
375
552
  }