carray 3.0.1 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +824 -0
  3. data/README.md +5 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +258 -4
  6. data/ext/ca_axis_group.c +368 -184
  7. data/ext/ca_binop_dispatch.c +54 -32
  8. data/ext/ca_binop_dispatch.h +1 -0
  9. data/ext/ca_categorical_iterator.c +90 -41
  10. data/ext/ca_compare.c +8 -2
  11. data/ext/ca_for_buffer.h +21 -68
  12. data/ext/ca_group_iter.c +27 -11
  13. data/ext/ca_kernel_iterator.c +960 -245
  14. data/ext/ca_kernel_iterator.h +352 -181
  15. data/ext/ca_monop_dispatch.c +4 -4
  16. data/ext/ca_monop_dispatch.h +4 -0
  17. data/ext/ca_obj_array.c +194 -42
  18. data/ext/ca_obj_bincmp.c +152 -121
  19. data/ext/ca_obj_binop.c +107 -210
  20. data/ext/ca_obj_bitarray.c +37 -24
  21. data/ext/ca_obj_bitfield.c +95 -62
  22. data/ext/ca_obj_block.c +5 -4
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +180 -50
  25. data/ext/ca_obj_face.c +428 -62
  26. data/ext/ca_obj_face.h +107 -47
  27. data/ext/ca_obj_fake.c +21 -50
  28. data/ext/ca_obj_farray.c +1 -0
  29. data/ext/ca_obj_field.c +16 -3
  30. data/ext/ca_obj_fixlen_string.c +39 -26
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +235 -55
  33. data/ext/ca_obj_moncmp.c +61 -61
  34. data/ext/ca_obj_monop.c +125 -107
  35. data/ext/ca_obj_object.c +551 -233
  36. data/ext/ca_obj_record.c +51 -16
  37. data/ext/ca_obj_reduce.c +5 -8
  38. data/ext/ca_obj_refer.c +117 -33
  39. data/ext/ca_obj_remap.c +57 -17
  40. data/ext/ca_obj_repeat.c +21 -5
  41. data/ext/ca_obj_roll.c +115 -11
  42. data/ext/ca_obj_select.c +88 -75
  43. data/ext/ca_obj_select_axis.c +58 -60
  44. data/ext/ca_obj_shift.c +22 -102
  45. data/ext/ca_obj_stack.c +223 -123
  46. data/ext/ca_obj_stride.c +267 -35
  47. data/ext/ca_obj_string.c +25 -22
  48. data/ext/ca_obj_tile.c +32 -16
  49. data/ext/ca_obj_time.c +23 -25
  50. data/ext/ca_obj_timedelta.c +21 -23
  51. data/ext/ca_obj_transpose.c +12 -3
  52. data/ext/ca_obj_triop.c +110 -117
  53. data/ext/ca_obj_window.c +157 -29
  54. data/ext/ca_op_ipower.c +25 -13
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_rng_normal.h +42 -0
  58. data/ext/ca_rng_xoshiro256pp.h +105 -0
  59. data/ext/ca_sort_kernels.h +70 -0
  60. data/ext/ca_sweep_engine.c +385 -198
  61. data/ext/ca_sweep_engine.h +31 -23
  62. data/ext/ca_triop_dispatch.c +4 -1
  63. data/ext/ca_triop_dispatch.h +5 -2
  64. data/ext/caframe_csv_reader.c +463 -0
  65. data/ext/carray.h +90 -28
  66. data/ext/carray_access.c +487 -231
  67. data/ext/carray_address_basis.c +731 -0
  68. data/ext/carray_attribute.c +45 -3
  69. data/ext/carray_bincount.c +32 -2
  70. data/ext/carray_broadcast.c +49 -17
  71. data/ext/carray_call_cfunc.c +667 -511
  72. data/ext/carray_cast.c +1556 -247
  73. data/ext/carray_cast_func.rb +34 -21
  74. data/ext/carray_conversion.c +197 -73
  75. data/ext/carray_copy.c +84 -38
  76. data/ext/carray_core.c +591 -119
  77. data/ext/carray_count.c +148 -96
  78. data/ext/carray_element.c +18 -27
  79. data/ext/carray_factorize.c +604 -291
  80. data/ext/carray_generate.c +76 -40
  81. data/ext/carray_histogram.c +152 -94
  82. data/ext/carray_hold.c +2 -1
  83. data/ext/carray_index_classifier.c +63 -96
  84. data/ext/carray_internal.h +400 -1
  85. data/ext/carray_lazy.c +834 -79
  86. data/ext/carray_loop.c +88 -66
  87. data/ext/carray_mask.c +705 -324
  88. data/ext/carray_math_kernel.h +1 -0
  89. data/ext/carray_median_percentile.c +263 -63
  90. data/ext/carray_memory_view.c +254 -248
  91. data/ext/carray_operator.c +1093 -363
  92. data/ext/carray_order.c +133 -69
  93. data/ext/carray_partition.c +102 -56
  94. data/ext/carray_random.c +582 -204
  95. data/ext/carray_scatter.c +308 -65
  96. data/ext/carray_segment.c +257 -0
  97. data/ext/carray_slab.c +183 -70
  98. data/ext/carray_sort.c +235 -240
  99. data/ext/carray_sort_kernel.c +8 -1
  100. data/ext/carray_struct.c +99 -21
  101. data/ext/carray_test.c +167 -64
  102. data/ext/carray_time_text.c +1182 -0
  103. data/ext/carray_utils.c +363 -98
  104. data/ext/extconf.rb +27 -2
  105. data/ext/mk_call_cfunc.rb +103 -118
  106. data/ext/mk_pow5_table.rb +35 -0
  107. data/ext/mkkernel.rb +1349 -851
  108. data/ext/ruby_carray.c +17 -2
  109. data/ext/version.h +4 -4
  110. data/ext/version.rb +4 -2
  111. data/lib/carray/attribute.rb +39 -0
  112. data/lib/carray/autoload_carray.rb +24 -3
  113. data/lib/carray/autoload_method_extension.rb +18 -0
  114. data/lib/carray/axis_group.rb +245 -20
  115. data/lib/carray/basics.rb +95 -25
  116. data/lib/carray/bincount_nd.rb +6 -0
  117. data/lib/carray/block_iterator.rb +200 -54
  118. data/lib/carray/boolean_reduce.rb +21 -29
  119. data/lib/carray/categorical.rb +244 -59
  120. data/lib/carray/categorical_iterator.rb +391 -757
  121. data/lib/carray/complex.rb +36 -29
  122. data/lib/carray/conditional.rb +94 -7
  123. data/lib/carray/const_string.rb +177 -27
  124. data/lib/carray/construct.rb +40 -0
  125. data/lib/carray/data_type_extension.rb +3 -0
  126. data/lib/carray/data_type_limits.rb +91 -0
  127. data/lib/carray/fixlen_string.rb +1 -1
  128. data/lib/carray/frame/concat.rb +157 -6
  129. data/lib/carray/frame/convert.rb +13 -7
  130. data/lib/carray/frame/csv_parser.rb +590 -76
  131. data/lib/carray/frame/describe.rb +79 -0
  132. data/lib/carray/frame/frame.rb +205 -35
  133. data/lib/carray/frame/group.rb +199 -40
  134. data/lib/carray/frame/io.rb +452 -60
  135. data/lib/carray/frame/join.rb +134 -46
  136. data/lib/carray/frame/records.rb +54 -19
  137. data/lib/carray/frame/reshape.rb +448 -0
  138. data/lib/carray/frame/sort.rb +26 -2
  139. data/lib/carray/frame/verbs.rb +726 -56
  140. data/lib/carray/frame.rb +2 -0
  141. data/lib/carray/fuse_source.rb +111 -2
  142. data/lib/carray/fusion.rb +229 -38
  143. data/lib/carray/inspect.rb +71 -20
  144. data/lib/carray/iterator.rb +157 -2
  145. data/lib/carray/lazy.rb +54 -67
  146. data/lib/carray/mask_gap_fill.rb +66 -50
  147. data/lib/carray/math.rb +32 -19
  148. data/lib/carray/meld_reduce.rb +40 -7
  149. data/lib/carray/methods/align_addr.rb +8 -4
  150. data/lib/carray/methods/bincount.rb +2 -2
  151. data/lib/carray/methods/bit_string.rb +14 -3
  152. data/lib/carray/methods/composition.rb +16 -10
  153. data/lib/carray/methods/discovery_along.rb +74 -0
  154. data/lib/carray/methods/factorize.rb +50 -0
  155. data/lib/carray/methods/gather_nd.rb +13 -2
  156. data/lib/carray/methods/insert_block.rb +9 -14
  157. data/lib/carray/methods/is_in.rb +130 -6
  158. data/lib/carray/methods/join.rb +1 -1
  159. data/lib/carray/methods/locate_addr.rb +235 -21
  160. data/lib/carray/methods/mask_duplicates.rb +35 -1
  161. data/lib/carray/methods/mode.rb +18 -1
  162. data/lib/carray/methods/nunique.rb +22 -1
  163. data/lib/carray/methods/repeat.rb +91 -0
  164. data/lib/carray/methods/resize.rb +21 -23
  165. data/lib/carray/methods/snap.rb +34 -12
  166. data/lib/carray/methods/unique.rb +52 -3
  167. data/lib/carray/record_order.rb +208 -0
  168. data/lib/carray/rng.rb +86 -0
  169. data/lib/carray/runtime.rb +14 -11
  170. data/lib/carray/segment_iterator.rb +990 -0
  171. data/lib/carray/serialize.rb +197 -27
  172. data/lib/carray/slab_iterator.rb +109 -40
  173. data/lib/carray/stack.rb +10 -4
  174. data/lib/carray/string_operation_extension.rb +9 -4
  175. data/lib/carray/struct.rb +142 -51
  176. data/lib/carray/struct_builder.rb +110 -14
  177. data/lib/carray/table.rb +2 -2
  178. data/lib/carray/time.rb +535 -105
  179. data/lib/carray/window_iterator.rb +259 -82
  180. data/lib/carray.rb +4 -2
  181. data/yard-stubs/ca_obj_array.rb +4 -4
  182. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  183. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  184. data/yard-stubs/ca_obj_block.rb +2 -7
  185. data/yard-stubs/ca_obj_fake.rb +1 -1
  186. data/yard-stubs/ca_obj_field.rb +1 -1
  187. data/yard-stubs/ca_obj_refer.rb +3 -3
  188. data/yard-stubs/ca_obj_roll.rb +0 -1
  189. data/yard-stubs/ca_obj_stride.rb +10 -7
  190. data/yard-stubs/ca_obj_transpose.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +11 -4
  192. data/yard-stubs/carray_access.rb +6 -5
  193. data/yard-stubs/carray_broadcast.rb +2 -2
  194. data/yard-stubs/carray_cast.rb +78 -43
  195. data/yard-stubs/carray_conversion.rb +13 -1
  196. data/yard-stubs/carray_copy.rb +8 -3
  197. data/yard-stubs/carray_core.rb +3 -83
  198. data/yard-stubs/carray_count.rb +16 -2
  199. data/yard-stubs/carray_lazy.rb +210 -1
  200. data/yard-stubs/carray_loop.rb +4 -1
  201. data/yard-stubs/carray_mask.rb +34 -10
  202. data/yard-stubs/carray_math.rb +1499 -4
  203. data/yard-stubs/carray_median_percentile.rb +26 -8
  204. data/yard-stubs/carray_order.rb +43 -82
  205. data/yard-stubs/carray_scatter.rb +10 -3
  206. data/yard-stubs/carray_segment.rb +72 -0
  207. data/yard-stubs/carray_slab.rb +11 -8
  208. data/yard-stubs/carray_sort.rb +50 -8
  209. data/yard-stubs/carray_test.rb +10 -0
  210. data/yard-stubs/carray_utils.rb +0 -26
  211. metadata +19 -19
  212. data/ext/ca_for_each_element.h +0 -239
  213. data/ext/carray_build_flags.h +0 -3
  214. data/ext/carray_config.h +0 -28
  215. data/ext/carray_kernels_bincmp.c +0 -4446
  216. data/ext/carray_kernels_binop.c +0 -11001
  217. data/ext/carray_kernels_init.c +0 -1131
  218. data/ext/carray_kernels_map.c +0 -3467
  219. data/ext/carray_kernels_moncmp.c +0 -2097
  220. data/ext/carray_kernels_monop.c +0 -18313
  221. data/ext/carray_kernels_reduce_aggregate.c +0 -25837
  222. data/ext/carray_kernels_reduce_boolean.c +0 -330
  223. data/ext/carray_kernels_reduce_cumulative.c +0 -14593
  224. data/ext/carray_kernels_reduce_extreme.c +0 -16948
  225. data/ext/carray_kernels_reduce_variance.c +0 -3910
  226. data/ext/carray_kernels_scan.c +0 -3693
  227. data/ext/carray_kernels_search.c +0 -32138
  228. data/ext/carray_kernels_sort.c +0 -10626
  229. data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_obj_repeat.c CHANGED
@@ -39,20 +39,23 @@ ca_repeat_setup (CAStride *ca, CArray *parent, int8_t ndim, ca_size_t *count)
39
39
  int8_t data_ndim = 0;
40
40
  int8_t i, j;
41
41
 
42
+ if ( ndim < 0 || ndim > CA_RANK_MAX ) {
43
+ rb_raise(rb_eArgError, "invalid ndim %d", (int) ndim);
44
+ }
42
45
  for (i = 0; i < ndim; i++) {
43
46
  if (count[i] < 0) {
44
- rb_raise(rb_eRuntimeError,
47
+ rb_raise(rb_eArgError,
45
48
  "negative size for %i-th dimension specified", i);
46
49
  }
47
50
  if (count[i]) nrpt *= count[i];
48
51
  else data_ndim += 1;
49
52
  }
50
53
  if (data_ndim != parent->ndim) {
51
- rb_raise(rb_eRuntimeError,
54
+ rb_raise(rb_eArgError,
52
55
  "mismatch in ndim between original array and determined by # of dummies");
53
56
  }
54
57
  if (((double) parent->elements) * nrpt > CA_LENGTH_MAX) {
55
- rb_raise(rb_eRuntimeError, "too large byte length");
58
+ rb_raise(rb_eArgError, "too large byte length");
56
59
  }
57
60
  (void) total_elements_d;
58
61
 
@@ -77,6 +80,12 @@ ca_repeat_setup (CAStride *ca, CArray *parent, int8_t ndim, ca_size_t *count)
77
80
  }
78
81
  }
79
82
 
83
+ /* ca == NULL asks for the checks above only, so that a constructor can
84
+ run them before it allocates. */
85
+ if ( ca == NULL ) {
86
+ return 0;
87
+ }
88
+
80
89
  ca_stride_setup(ca, CA_OBJ_REPEAT, parent,
81
90
  parent->data_type, parent->bytes,
82
91
  ndim, newdim, strides, 0);
@@ -91,7 +100,9 @@ ca_repeat_setup (CAStride *ca, CArray *parent, int8_t ndim, ca_size_t *count)
91
100
  CAStride *
92
101
  ca_repeat_new (CArray *parent, int8_t ndim, ca_size_t *count)
93
102
  {
94
- CAStride *ca = (CAStride *) ca_array_alloc(CA_OBJ_REPEAT, ndim);
103
+ CAStride *ca;
104
+ ca_repeat_setup(NULL, parent, ndim, count);
105
+ ca = (CAStride *) ca_array_alloc(CA_OBJ_REPEAT, ndim);
95
106
  ca_repeat_setup(ca, parent, ndim, count);
96
107
  return ca;
97
108
  }
@@ -155,7 +166,7 @@ rb_ca_repeat (int argc, VALUE *argv, VALUE self)
155
166
  TypedData_Get_Struct(argv[0], CArray, &carray_data_type, ct);
156
167
  }
157
168
  if ( ct->ndim < ca->ndim ) {
158
- rb_raise(rb_eRuntimeError, "invalid ndim to template");
169
+ rb_raise(rb_eArgError, "invalid ndim to template");
159
170
  }
160
171
  args = rb_ary_new();
161
172
  ndim = 0;
@@ -208,6 +219,10 @@ rb_ca_repeat (int argc, VALUE *argv, VALUE self)
208
219
  return rb_ca_repeat((int)RARRAY_LEN(args), (VALUE *)RARRAY_CONST_PTR(args), self);
209
220
  }
210
221
 
222
+ if ( argc > CA_RANK_MAX ) { /* count[] and dim[] hold CA_RANK_MAX */
223
+ rb_raise(rb_eArgError, "invalid ndim %d", argc);
224
+ }
225
+
211
226
  repeat = 1;
212
227
  for (i=0; i<argc; i++) {
213
228
  if ( rb_obj_is_kind_of(argv[i], rb_cSymbol) ) {
@@ -255,6 +270,7 @@ rb_ca_repeat_initialize_copy (VALUE self, VALUE other)
255
270
  {
256
271
  CAStride *ca, *cs;
257
272
  TypedData_Get_Struct(self, CAStride, &castride_data_type, ca);
273
+ ca_check_uninitialized(ca);
258
274
  TypedData_Get_Struct(other, CAStride, &castride_data_type, cs);
259
275
  if ( ca_func[CA_OBJ_REPEAT].pool_init ) {
260
276
  ca_array_pool_alloc(ca, CA_OBJ_REPEAT, cs->ndim);
data/ext/ca_obj_roll.c CHANGED
@@ -17,6 +17,7 @@
17
17
  ---------------------------------------------------------------------------- */
18
18
 
19
19
  #include "carray.h"
20
+ #include "carray_internal.h"
20
21
  #include "ca_composite_dispatch.h"
21
22
  #include "ca_obj_face.h"
22
23
 
@@ -90,12 +91,15 @@ ca_roll_setup (CARoll *ca, CArray *parent, ca_size_t *shift)
90
91
 
91
92
  elements = 1;
92
93
  for (i = 0; i < ndim; i++) {
93
- if ( parent->dim[i] <= 0 ) {
94
- rb_raise(rb_eIndexError, "invalid parent dim for %d-th dimension", i);
95
- }
96
94
  elements *= parent->dim[i];
97
95
  }
98
96
 
97
+ /* ca == NULL asks for the checks above only, so that a constructor can
98
+ run them before it allocates. */
99
+ if ( ca == NULL ) {
100
+ return 0;
101
+ }
102
+
99
103
  ca->obj_type = CA_OBJ_ROLL;
100
104
  ca->data_type = parent->data_type;
101
105
  ca->flags = 0;
@@ -114,8 +118,11 @@ ca_roll_setup (CARoll *ca, CArray *parent, ca_size_t *shift)
114
118
  for (i = 0; i < ndim; i++) {
115
119
  ca->dim[i] = parent->dim[i];
116
120
  /* Normalise: ((shift[i] % dim[i]) + dim[i]) % dim[i] ∈ [0, dim[i]). */
117
- ca_size_t s = shift[i] % parent->dim[i];
118
- if ( s < 0 ) s += parent->dim[i];
121
+ ca_size_t s = 0; /* an empty axis has nothing to roll */
122
+ if ( parent->dim[i] > 0 ) {
123
+ s = shift[i] % parent->dim[i];
124
+ if ( s < 0 ) s += parent->dim[i];
125
+ }
119
126
  ca->reps[i] = s;
120
127
  }
121
128
 
@@ -129,7 +136,9 @@ ca_roll_setup (CARoll *ca, CArray *parent, ca_size_t *shift)
129
136
  CARoll *
130
137
  ca_roll_new (CArray *parent, ca_size_t *shift)
131
138
  {
132
- CARoll *ca = ALLOC(CARoll);
139
+ CARoll *ca;
140
+ ca_roll_setup(NULL, parent, shift);
141
+ ca = ALLOC(CARoll);
133
142
  ca_roll_setup(ca, parent, shift);
134
143
  return ca;
135
144
  }
@@ -214,6 +223,7 @@ static void
214
223
  ca_roll_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
215
224
  ca_size_t *strides, void *data, int dir)
216
225
  {
226
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
217
227
  CARoll *ca = (CARoll *) ap;
218
228
  CArray *parent = ca->parent;
219
229
  int8_t ndim = ca->ndim;
@@ -264,6 +274,95 @@ ca_roll_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
264
274
  return;
265
275
  }
266
276
 
277
+ /* The inner range is one run of a parent row, or two when it wraps, and
278
+ the rows along the next axis out are consecutive parent rows except
279
+ across that axis's wrap. So each pass over the axes further out moves
280
+ at most two strided boxes per inner run, instead of one transfer per
281
+ row. A box over an unwrapped inner range is already the request's own
282
+ layout; a box over one of two inner runs goes through a scratch whose
283
+ rows are spliced into the request's. Object cells keep the per-row
284
+ path: a scratch would hold the VALUEs a parent produces where the GC
285
+ cannot see them. */
286
+ if ( inner >= 1 ) {
287
+ int8_t m = inner - 1;
288
+ ca_size_t dim_in = parent->dim[inner];
289
+ ca_size_t p0 = starts[inner] - ca->reps[inner];
290
+ ca_size_t seg_p[2], seg_n[2], seg_i[2];
291
+ int nseg, sg;
292
+ if (p0 < 0) p0 += dim_in;
293
+ if ( p0 + counts[inner] <= dim_in ) {
294
+ nseg = 1;
295
+ seg_p[0] = p0; seg_n[0] = counts[inner]; seg_i[0] = 0;
296
+ }
297
+ else {
298
+ nseg = 2;
299
+ seg_p[0] = p0; seg_n[0] = dim_in - p0; seg_i[0] = 0;
300
+ seg_p[1] = 0; seg_n[1] = counts[inner] - seg_n[0]; seg_i[1] = seg_n[0];
301
+ }
302
+ if ( nseg == 1 || ca->data_type != CA_OBJECT ) {
303
+ volatile VALUE holder = 0;
304
+ char *tmp = NULL;
305
+ if ( nseg == 2 ) {
306
+ ca_size_t wide = seg_n[0] > seg_n[1] ? seg_n[0] : seg_n[1];
307
+ tmp = (char *) ALLOCV(holder, counts[m] * wide * ca->bytes);
308
+ }
309
+ for (k = 0; k < m; k++) o[k] = 0;
310
+ while (1) {
311
+ ca_size_t pbase = 0, doff = 0;
312
+ for (k = 0; k < m; k++) {
313
+ ca_size_t j = (starts[k] + o[k]) - ca->reps[k];
314
+ if (j < 0) j += parent->dim[k];
315
+ pbase += j * pnative[k];
316
+ doff += o[k] * dstride[k];
317
+ }
318
+ for (sg = 0; sg < nseg; sg++) {
319
+ ca_size_t r = 0;
320
+ while (r < counts[m]) {
321
+ ca_size_t pm = (starts[m] + r) - ca->reps[m];
322
+ ca_size_t run, q;
323
+ ca_size_t pstarts[CA_RANK_MAX], pcounts[CA_RANK_MAX], pstrides[CA_RANK_MAX];
324
+ char *rows = d + doff + r * dstride[m] + seg_i[sg] * ca->bytes;
325
+ ca_size_t rowb = seg_n[sg] * ca->bytes;
326
+ if (pm < 0) pm += parent->dim[m];
327
+ run = parent->dim[m] - pm;
328
+ if (run > counts[m] - r) run = counts[m] - r;
329
+ ca_addr2index((CArray *) parent,
330
+ (pbase + pm * pnative[m] + seg_p[sg] * pnative[inner])
331
+ / parent->bytes, pstarts);
332
+ for (k = 0; k < ndim; k++) { pcounts[k] = 1; pstrides[k] = 0; }
333
+ pcounts[m] = run;
334
+ pstrides[m] = pnative[m];
335
+ pcounts[inner] = seg_n[sg];
336
+ pstrides[inner] = pnative[inner];
337
+ if ( nseg == 1 ) {
338
+ ca_xfer_stride(parent, pstarts, pcounts, pstrides, rows, dir);
339
+ }
340
+ else if ( dir == CA_XFER_GET ) {
341
+ ca_xfer_stride(parent, pstarts, pcounts, pstrides, tmp, dir);
342
+ for (q = 0; q < run; q++) {
343
+ memcpy(rows + q * dstride[m], tmp + q * rowb, rowb);
344
+ }
345
+ }
346
+ else {
347
+ for (q = 0; q < run; q++) {
348
+ memcpy(tmp + q * rowb, rows + q * dstride[m], rowb);
349
+ }
350
+ ca_xfer_stride(parent, pstarts, pcounts, pstrides, tmp, dir);
351
+ }
352
+ r += run;
353
+ }
354
+ }
355
+ k = m - 1;
356
+ while (k >= 0) { if (++o[k] < counts[k]) break; o[k] = 0; k--; }
357
+ if (k < 0) break;
358
+ }
359
+ if ( tmp ) {
360
+ ALLOCV_END(holder);
361
+ }
362
+ return;
363
+ }
364
+ }
365
+
267
366
  for (k = 0; k < ndim; k++) o[k] = 0;
268
367
  while (1) {
269
368
  ca_size_t pbase = 0, doff = 0, i;
@@ -459,10 +558,13 @@ ca_roll_func_xfer_all (void *ap, void *data, int dir)
459
558
  ca_xfer_all(parent, parent_scratch, CA_XFER_GET);
460
559
  parent->ptr = parent_scratch;
461
560
  ca_roll_iterate_regions(ca, (char *) data, dir == CA_XFER_PUT);
561
+ /* Put parent->ptr back before the PUT: the PUT can raise (a lazy
562
+ backing's sync failing), and the scratch is gone once this
563
+ frame is. */
564
+ parent->ptr = parent_ptr_saved;
462
565
  if ( dir == CA_XFER_PUT ) {
463
566
  ca_xfer_all(parent, parent_scratch, CA_XFER_PUT);
464
567
  }
465
- parent->ptr = parent_ptr_saved;
466
568
  ALLOCV_END(holder);
467
569
  }
468
570
  }
@@ -480,10 +582,7 @@ static void
480
582
  ca_roll_func_create_mask (void *ap)
481
583
  {
482
584
  CARoll *ca = (CARoll *) ap;
483
- ca_update_mask(ca->parent);
484
- if ( ! ca->parent->mask ) {
485
- ca_create_mask(ca->parent);
486
- }
585
+ ca_create_mask(ca->parent);
487
586
  ca->mask = (CArray *) ca_roll_new(ca->parent->mask, ca->reps);
488
587
  }
489
588
 
@@ -557,11 +656,13 @@ rb_ca_roll_initialize_copy (VALUE self, VALUE other)
557
656
  {
558
657
  CARoll *ca, *cs;
559
658
  TypedData_Get_Struct(self, CARoll, &caroll_data_type, ca);
659
+ ca_check_uninitialized(ca);
560
660
  TypedData_Get_Struct(other, CARoll, &caroll_data_type, cs);
561
661
  ca_roll_setup(ca, cs->parent, cs->reps);
562
662
  return self;
563
663
  }
564
664
 
665
+ #ifdef CARRAY_DEV_BUILD
565
666
  /* Debug-only accessor returning the roll descriptor as a Hash
566
667
  (`shifts`, `n_regions`, `ndim`). Not part of the public surface. */
567
668
  static VALUE
@@ -583,6 +684,7 @@ rb_ca_roll_descriptor (VALUE self)
583
684
  rb_hash_aset(hash, ID2SYM(rb_intern("ndim")), INT2NUM(ca->ndim));
584
685
  return hash;
585
686
  }
687
+ #endif
586
688
 
587
689
  void
588
690
  Init_ca_obj_roll (void)
@@ -618,7 +720,9 @@ Init_ca_obj_roll (void)
618
720
  rb_define_method(rb_cCARoll, "initialize_copy",
619
721
  rb_ca_roll_initialize_copy, 1);
620
722
 
723
+ #ifdef CARRAY_DEV_BUILD
621
724
  /* Debug accessor, not part of the public surface. */
622
725
  rb_define_method(rb_cCARoll, "_roll_descriptor",
623
726
  rb_ca_roll_descriptor, 0);
727
+ #endif
624
728
  }
data/ext/ca_obj_select.c CHANGED
@@ -83,22 +83,60 @@ VALUE rb_cCASelectMask;
83
83
 
84
84
  /* ------------------------------------------------------------------- */
85
85
 
86
- /* Snapshot the selector into ca->select (always a copy) and pre-compute
87
- ca->indices (TRUE positions in flat parent order). Masked selector
88
- cells become false in the snapshot. After construction, mutating
89
- the caller's live selector does not affect the view. */
90
- static int
91
- ca_select_setup (CASelect *ca, CArray *parent, CArray *select, int share)
86
+ /* Owned snapshot of the selector: masked selector cells become false.
87
+ After construction, mutating the caller's live selector does not affect
88
+ the view. Reading the selector can raise (a lazy boolean view), so the
89
+ snapshot is taken before the view struct is allocated, and a snapshot
90
+ whose fill raises is freed on the way out. */
91
+ static VALUE
92
+ ca_select_snapshot_masked (VALUE arg)
92
93
  {
93
- int8_t data_type;
94
- ca_size_t bytes;
94
+ CArray **pair = (CArray **) arg;
95
+ CArray *select = pair[0], *snap = pair[1];
96
+ boolean8_t *q, *m;
95
97
  ca_size_t i;
98
+ volatile VALUE holder = 0;
99
+ ca_copy_data(select, snap->ptr);
100
+ ca_update_mask(select);
101
+ m = ALLOCV_N(boolean8_t, holder, select->elements);
102
+ ca_copy_data(select->mask, (char *) m);
103
+ q = (boolean8_t *) snap->ptr;
104
+ for (i = 0; i < select->elements; i++) {
105
+ if ( m[i] ) {
106
+ q[i] = 0;
107
+ }
108
+ }
109
+ ALLOCV_END(holder);
110
+ return Qnil;
111
+ }
96
112
 
113
+ CArray *
114
+ ca_select_snapshot (CArray *select)
115
+ {
97
116
  if ( ! ca_is_boolean_type(select) ) {
98
117
  rb_raise(rb_eRuntimeError,
99
118
  "selection array for CASelect should be have "
100
119
  "the data_type of CA_BOOLEAN");
101
120
  }
121
+ if ( ca_has_mask(select) ) {
122
+ CArray *pair[2];
123
+ pair[0] = select;
124
+ pair[1] = ca_template(select);
125
+ ca_fill_or_free(pair[1], ca_select_snapshot_masked, (VALUE) pair);
126
+ return pair[1];
127
+ }
128
+ return ca_copy(select);
129
+ }
130
+
131
+ /* Set up the view over `parent` from an owned selector snapshot (see
132
+ ca_select_snapshot) and pre-compute ca->indices (TRUE positions in flat
133
+ parent order). Does not raise. */
134
+ static int
135
+ ca_select_setup (CASelect *ca, CArray *parent, CArray *snapshot)
136
+ {
137
+ int8_t data_type;
138
+ ca_size_t bytes;
139
+ ca_size_t i;
102
140
 
103
141
  data_type = parent->data_type;
104
142
  bytes = parent->bytes;
@@ -114,26 +152,7 @@ ca_select_setup (CASelect *ca, CArray *parent, CArray *select, int share)
114
152
  ca->attach = 0;
115
153
  ca->nosync = 0;
116
154
  ca->indices = NULL;
117
-
118
- /* The `share` argument is preserved for source compatibility but
119
- no longer toggles a live-reference path; both paths copy.
120
- Masked selector cells become false in the snapshot. */
121
- (void) share;
122
- if ( ca_has_mask(select) ) {
123
- boolean8_t *p, *q, *m;
124
- ca->select = ca_template(select);
125
- ca_attach(select);
126
- q = (boolean8_t *) ca->select->ptr;
127
- p = (boolean8_t *) select->ptr;
128
- m = (boolean8_t *) select->mask->ptr;
129
- for (i = 0; i < select->elements; i++) {
130
- *q = ( *m ) ? 0 : *p;
131
- q++; p++; m++;
132
- }
133
- ca_detach(select);
134
- } else {
135
- ca->select = ca_copy(select);
136
- }
155
+ ca->select = snapshot;
137
156
 
138
157
  /* Count TRUE positions and snapshot them into ca->indices. */
139
158
  {
@@ -181,7 +200,7 @@ ca_select_setup (CASelect *ca, CArray *parent, CArray *select, int share)
181
200
  ca->dim = &(ca->_dim);
182
201
  ca->dim[0] = ca->elements;
183
202
 
184
- if ( ca_is_scalar(select) ) {
203
+ if ( ca_is_scalar(snapshot) ) {
185
204
  ca_set_flag(ca, CA_FLAG_SCALAR);
186
205
  }
187
206
 
@@ -191,8 +210,9 @@ ca_select_setup (CASelect *ca, CArray *parent, CArray *select, int share)
191
210
  CArray *
192
211
  ca_select_new (CArray *parent, CArray *select)
193
212
  {
213
+ CArray *snapshot = ca_select_snapshot(select);
194
214
  CASelect *ca = ALLOC(CASelect);
195
- ca_select_setup(ca, parent, select, 0);
215
+ ca_select_setup(ca, parent, snapshot);
196
216
  return (CArray*) ca;
197
217
  }
198
218
 
@@ -202,9 +222,7 @@ ca_select_new (CArray *parent, CArray *select)
202
222
  CArray *
203
223
  ca_select_new_share (CArray *parent, CArray *select)
204
224
  {
205
- CASelect *ca = ALLOC(CASelect);
206
- ca_select_setup(ca, parent, select, 1);
207
- return (CArray*) ca;
225
+ return ca_select_new(parent, select);
208
226
  }
209
227
 
210
228
  static void
@@ -337,6 +355,7 @@ static void
337
355
  ca_select_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
338
356
  ca_size_t *strides, void *data, int dir)
339
357
  {
358
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
340
359
  CASelect *ca = (CASelect *) ap;
341
360
  CArray *parent = ca->parent;
342
361
  ca_size_t n = counts[0];
@@ -399,24 +418,34 @@ ca_select_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
399
418
  }
400
419
  }
401
420
 
421
+ /* A parent with no memory to lend (ca_parent_lends_no_memory) is never
422
+ attached: the view owns its buffer, filled and drained through xfer_all,
423
+ which asks the parent for the selected cells only. The predicate asks
424
+ what the parent is, not whether it is attached now, so attach, sync and
425
+ detach all take the same branch. */
426
+
402
427
  static void
403
428
  ca_select_func_allocate (void *ap)
404
429
  {
405
430
  CASelect *ca = (CASelect *) ap;
406
- ca_attach(ca->parent);
431
+ if ( ! ca_parent_lends_no_memory(ca->parent) ) {
432
+ ca_attach(ca->parent);
433
+ }
407
434
  ca->ptr = xmalloc(ca_length(ca));
408
435
  }
409
436
 
410
- /* Every attach / sync / xfer_all / xfer_stride / fill_data path
411
- dispatches through the descriptor engine with the same shape
412
- CASelectAxis uses: one axis over a flattened parent. */
413
-
414
437
  static void
415
438
  ca_select_func_attach (void *ap)
416
439
  {
417
440
  CASelect *ca = (CASelect *) ap;
418
441
  ca_axis_desc_t desc[CA_RANK_MAX];
419
442
  ca_size_t pdims[CA_RANK_MAX];
443
+
444
+ if ( ca_parent_lends_no_memory(ca->parent) ) {
445
+ ca_axis_view_attach_owned(ca);
446
+ return;
447
+ }
448
+
420
449
  ca_attach(ca->parent);
421
450
  ca_select_describe_axes(ca, desc, pdims);
422
451
  ca->ptr = ca_axis_dispatch_attach(ca->parent, pdims, desc, ca->ndim,
@@ -429,6 +458,12 @@ ca_select_func_sync (void *ap)
429
458
  CASelect *ca = (CASelect *) ap;
430
459
  ca_axis_desc_t desc[CA_RANK_MAX];
431
460
  ca_size_t pdims[CA_RANK_MAX];
461
+
462
+ if ( ca_parent_lends_no_memory(ca->parent) ) {
463
+ ca_axis_view_sync_owned(ca);
464
+ return;
465
+ }
466
+
432
467
  ca_select_describe_axes(ca, desc, pdims);
433
468
  ca_axis_dispatch_scatter(ca->parent, pdims, desc, ca->ndim, ca->bytes,
434
469
  ca->elements, ca->ptr);
@@ -439,16 +474,20 @@ static void
439
474
  ca_select_func_detach (void *ap)
440
475
  {
441
476
  CASelect *ca = (CASelect *) ap;
442
- xfree(ca->ptr);
443
- ca->ptr = NULL;
444
- ca_detach(ca->parent);
477
+ if ( ca->ptr ) {
478
+ xfree(ca->ptr);
479
+ ca->ptr = NULL;
480
+ }
481
+ if ( ! ca_parent_lends_no_memory(ca->parent) ) {
482
+ ca_detach(ca->parent);
483
+ }
445
484
  }
446
485
 
447
- /* Fast-path core used by xfer_all's attached-parent branch and the
448
- cold-parent 2-pass scratch branch below. */
486
+ /* The transfer against parent->ptr, for ca_axis_view_xfer_all. */
449
487
  static void
450
- ca_select_func_run_fast_path (CASelect *ca, char *data, int dir)
488
+ ca_select_func_run_fast_path (void *ap, char *data, int dir)
451
489
  {
490
+ CASelect *ca = (CASelect *) ap;
452
491
  ca_axis_desc_t desc[CA_RANK_MAX];
453
492
  ca_size_t pdims[CA_RANK_MAX];
454
493
  ca_select_describe_axes(ca, desc, pdims);
@@ -461,33 +500,10 @@ ca_select_func_run_fast_path (CASelect *ca, char *data, int dir)
461
500
  }
462
501
  }
463
502
 
464
- /* Cold parent is served by a 2-pass scratch (gather parent into a
465
- local buffer, dispatch through the fast path against the buffer,
466
- scatter back on PUT). Deliberately avoids ca_attach(parent) so
467
- that a silent transitive attach cannot re-enter through here. */
468
503
  static void
469
504
  ca_select_func_xfer_all (void *ap, void *data, int dir)
470
505
  {
471
- CASelect *ca = (CASelect *) ap;
472
- if ( ca->parent->ptr ) {
473
- ca_select_func_run_fast_path(ca, (char *) data, dir);
474
- return;
475
- }
476
- {
477
- volatile VALUE holder;
478
- CArray *parent = ca->parent;
479
- ca_size_t plen = parent->elements * parent->bytes;
480
- char *parent_scratch = ALLOCV_N(char, holder, plen);
481
- char *parent_ptr_saved = parent->ptr;
482
- ca_xfer_all(parent, parent_scratch, CA_XFER_GET);
483
- parent->ptr = parent_scratch;
484
- ca_select_func_run_fast_path(ca, (char *) data, dir);
485
- if ( dir == CA_XFER_PUT ) {
486
- ca_xfer_all(parent, parent_scratch, CA_XFER_PUT);
487
- }
488
- parent->ptr = parent_ptr_saved;
489
- ALLOCV_END(holder);
490
- }
506
+ ca_axis_view_xfer_all(ap, ca_select_func_run_fast_path, 1, data, dir);
491
507
  }
492
508
 
493
509
  static void
@@ -516,18 +532,14 @@ ca_select_func_fill_data (void *ap, void *ptr)
516
532
  ca_select_describe_axes(ca, desc, pdims);
517
533
  ca_axis_dispatch_fill_value(ca->parent, pdims, desc, ca->ndim, ca->bytes,
518
534
  ca->elements, ptr);
519
- ca_sync(ca->parent);
520
- ca_detach(ca->parent);
535
+ ca_sync_detach(ca->parent);
521
536
  }
522
537
 
523
538
  static void
524
539
  ca_select_func_create_mask (void *ap)
525
540
  {
526
541
  CASelect *ca = (CASelect *) ap;
527
- ca_update_mask(ca->parent);
528
- if ( ! ca->parent->mask ) {
529
- ca_create_mask(ca->parent);
530
- }
542
+ ca_create_mask(ca->parent);
531
543
  ca->mask = (CArray *) ca_select_new_share(ca->parent->mask, ca->select);
532
544
  }
533
545
 
@@ -609,11 +621,12 @@ rb_cm_initialize_copy (VALUE self, VALUE other)
609
621
  CASelect *ca, *cs;
610
622
 
611
623
  TypedData_Get_Struct(self, CASelect, &caselect_data_type, ca);
624
+ ca_check_uninitialized(ca);
612
625
  TypedData_Get_Struct(other, CASelect, &caselect_data_type, cs);
613
626
 
614
627
  /* Re-snapshot from the source's selector copy so the two views
615
628
  end up with independent indices buffers. */
616
- ca_select_setup(ca, cs->parent, cs->select, 1);
629
+ ca_select_setup(ca, cs->parent, ca_select_snapshot(cs->select));
617
630
 
618
631
  return self;
619
632
  }