carray 3.0.2 → 3.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +568 -0
  3. data/README.md +6 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +220 -0
  7. data/ext/ca_axis_group.c +201 -123
  8. data/ext/ca_binop_dispatch.c +46 -52
  9. data/ext/ca_binop_dispatch.h +1 -1
  10. data/ext/ca_categorical_iterator.c +249 -183
  11. data/ext/ca_compare.c +7 -12
  12. data/ext/ca_for_buffer.h +21 -68
  13. data/ext/ca_group_iter.c +38 -23
  14. data/ext/ca_kernel_iterator.c +1765 -2076
  15. data/ext/ca_kernel_iterator.h +584 -566
  16. data/ext/ca_monop_dispatch.c +86 -63
  17. data/ext/ca_monop_dispatch.h +5 -0
  18. data/ext/ca_obj_array.c +223 -56
  19. data/ext/ca_obj_bincmp.c +172 -138
  20. data/ext/ca_obj_binop.c +116 -230
  21. data/ext/ca_obj_bitarray.c +40 -26
  22. data/ext/ca_obj_bitfield.c +100 -68
  23. data/ext/ca_obj_block.c +19 -9
  24. data/ext/ca_obj_byte_swap.c +45 -46
  25. data/ext/ca_obj_const_string.c +269 -44
  26. data/ext/ca_obj_face.c +612 -89
  27. data/ext/ca_obj_face.h +111 -47
  28. data/ext/ca_obj_fake.c +36 -79
  29. data/ext/ca_obj_farray.c +7 -3
  30. data/ext/ca_obj_field.c +33 -8
  31. data/ext/ca_obj_fixlen_string.c +23 -24
  32. data/ext/ca_obj_grid.c +541 -210
  33. data/ext/ca_obj_meld.c +331 -111
  34. data/ext/ca_obj_moncmp.c +80 -65
  35. data/ext/ca_obj_monop.c +177 -149
  36. data/ext/ca_obj_object.c +664 -248
  37. data/ext/ca_obj_record.c +63 -23
  38. data/ext/ca_obj_reduce.c +18 -16
  39. data/ext/ca_obj_refer.c +140 -58
  40. data/ext/ca_obj_remap.c +85 -24
  41. data/ext/ca_obj_repeat.c +24 -9
  42. data/ext/ca_obj_roll.c +121 -16
  43. data/ext/ca_obj_select.c +61 -58
  44. data/ext/ca_obj_select_axis.c +73 -107
  45. data/ext/ca_obj_shift.c +32 -102
  46. data/ext/ca_obj_stack.c +372 -122
  47. data/ext/ca_obj_stride.c +348 -140
  48. data/ext/ca_obj_string.c +88 -22
  49. data/ext/ca_obj_tile.c +38 -21
  50. data/ext/ca_obj_time.c +45 -31
  51. data/ext/ca_obj_timedelta.c +43 -29
  52. data/ext/ca_obj_transpose.c +17 -6
  53. data/ext/ca_obj_triop.c +125 -141
  54. data/ext/ca_obj_window.c +330 -44
  55. data/ext/ca_op_ipower.c +24 -11
  56. data/ext/ca_op_powi.h +57 -30
  57. data/ext/ca_pow5_table.h +656 -0
  58. data/ext/ca_sort_kernels.h +70 -0
  59. data/ext/ca_sweep_engine.c +104 -81
  60. data/ext/ca_sweep_engine.h +7 -20
  61. data/ext/ca_triop_dispatch.c +4 -1
  62. data/ext/ca_triop_dispatch.h +5 -2
  63. data/ext/caframe_csv_reader.c +542 -0
  64. data/ext/carray.h +241 -92
  65. data/ext/carray_access.c +608 -276
  66. data/ext/carray_address_basis.c +494 -97
  67. data/ext/carray_attribute.c +129 -4
  68. data/ext/carray_bincount.c +39 -7
  69. data/ext/carray_broadcast.c +56 -19
  70. data/ext/carray_build_flags.h +1 -1
  71. data/ext/carray_call_cfunc.c +108 -28
  72. data/ext/carray_cast.c +1576 -223
  73. data/ext/carray_cast_func.rb +77 -24
  74. data/ext/carray_class.c +4 -3
  75. data/ext/carray_conversion.c +208 -75
  76. data/ext/carray_copy.c +82 -24
  77. data/ext/carray_core.c +646 -162
  78. data/ext/carray_count.c +171 -88
  79. data/ext/carray_element.c +94 -60
  80. data/ext/carray_factorize.c +670 -324
  81. data/ext/carray_generate.c +260 -83
  82. data/ext/carray_histogram.c +209 -106
  83. data/ext/carray_hold.c +14 -16
  84. data/ext/carray_index_classifier.c +422 -243
  85. data/ext/carray_internal.h +692 -3
  86. data/ext/carray_kernels_bincmp.c +7 -0
  87. data/ext/carray_kernels_binop.c +487 -120
  88. data/ext/carray_kernels_init.c +653 -50
  89. data/ext/carray_kernels_moncmp.c +15 -8
  90. data/ext/carray_kernels_monop.c +99 -43
  91. data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
  92. data/ext/carray_kernels_reduce_boolean.c +112 -36
  93. data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
  94. data/ext/carray_kernels_reduce_extreme.c +3032 -2892
  95. data/ext/carray_kernels_reduce_variance.c +439 -500
  96. data/ext/carray_kernels_scan.c +1097 -488
  97. data/ext/carray_kernels_search.c +3787 -2176
  98. data/ext/carray_kernels_sort.c +1200 -920
  99. data/ext/carray_kernels_triop.c +479 -7
  100. data/ext/carray_key_windows.c +216 -0
  101. data/ext/carray_lazy.c +967 -153
  102. data/ext/carray_loop.c +81 -65
  103. data/ext/carray_mask.c +910 -324
  104. data/ext/carray_math_kernel.h +1 -0
  105. data/ext/carray_median_percentile.c +299 -100
  106. data/ext/carray_memory_view.c +872 -758
  107. data/ext/carray_operator.c +1171 -364
  108. data/ext/carray_order.c +505 -133
  109. data/ext/carray_partition.c +112 -65
  110. data/ext/carray_random.c +327 -239
  111. data/ext/carray_round.c +273 -0
  112. data/ext/carray_scatter.c +346 -78
  113. data/ext/carray_segment.c +257 -0
  114. data/ext/carray_slab.c +249 -86
  115. data/ext/carray_sort.c +224 -227
  116. data/ext/carray_sort_kernel.c +8 -1
  117. data/ext/carray_struct.c +118 -39
  118. data/ext/carray_test.c +193 -69
  119. data/ext/carray_time_text.c +1182 -0
  120. data/ext/carray_undef.c +4 -0
  121. data/ext/carray_utils.c +579 -113
  122. data/ext/extconf.rb +27 -2
  123. data/ext/mk_call_cfunc.rb +19 -4
  124. data/ext/mk_pow5_table.rb +35 -0
  125. data/ext/mkkernel.rb +1202 -1014
  126. data/ext/ruby_carray.c +17 -5
  127. data/ext/version.h +4 -4
  128. data/ext/version.rb +4 -2
  129. data/lib/carray/attribute.rb +160 -17
  130. data/lib/carray/autoload_carray.rb +23 -27
  131. data/lib/carray/autoload_method_extension.rb +20 -5
  132. data/lib/carray/axis_group.rb +360 -63
  133. data/lib/carray/basics.rb +162 -28
  134. data/lib/carray/bincount_nd.rb +18 -2
  135. data/lib/carray/block_iterator.rb +231 -58
  136. data/lib/carray/boolean_reduce.rb +34 -42
  137. data/lib/carray/categorical.rb +242 -52
  138. data/lib/carray/categorical_iterator.rb +437 -827
  139. data/lib/carray/complex.rb +41 -34
  140. data/lib/carray/conditional.rb +150 -14
  141. data/lib/carray/const_string.rb +59 -4
  142. data/lib/carray/construct.rb +15 -11
  143. data/lib/carray/data_type_extension.rb +1 -0
  144. data/lib/carray/distance_limit.rb +77 -0
  145. data/lib/carray/fixlen_string.rb +7 -1
  146. data/lib/carray/frame/column_verbs.rb +70 -0
  147. data/lib/carray/frame/concat.rb +157 -6
  148. data/lib/carray/frame/convert.rb +82 -7
  149. data/lib/carray/frame/csv_parser.rb +688 -87
  150. data/lib/carray/frame/describe.rb +80 -0
  151. data/lib/carray/frame/frame.rb +369 -45
  152. data/lib/carray/frame/group.rb +631 -90
  153. data/lib/carray/frame/io.rb +506 -79
  154. data/lib/carray/frame/join.rb +411 -62
  155. data/lib/carray/frame/records.rb +116 -19
  156. data/lib/carray/frame/reshape.rb +455 -0
  157. data/lib/carray/frame/sort.rb +30 -18
  158. data/lib/carray/frame/verbs.rb +868 -61
  159. data/lib/carray/frame/windows.rb +117 -0
  160. data/lib/carray/frame.rb +4 -0
  161. data/lib/carray/fuse_source.rb +118 -2
  162. data/lib/carray/fusion.rb +257 -42
  163. data/lib/carray/histogram.rb +6 -1
  164. data/lib/carray/inspect.rb +54 -13
  165. data/lib/carray/iterator.rb +99 -9
  166. data/lib/carray/key_windows.rb +620 -0
  167. data/lib/carray/lazy.rb +216 -193
  168. data/lib/carray/mask_gap_fill.rb +112 -92
  169. data/lib/carray/math.rb +32 -19
  170. data/lib/carray/meld_reduce.rb +52 -21
  171. data/lib/carray/methods/align_addr.rb +8 -4
  172. data/lib/carray/methods/bin.rb +26 -18
  173. data/lib/carray/methods/bincount.rb +18 -2
  174. data/lib/carray/methods/bit_string.rb +15 -4
  175. data/lib/carray/methods/choose.rb +16 -3
  176. data/lib/carray/methods/composition.rb +18 -10
  177. data/lib/carray/methods/factorize.rb +2 -2
  178. data/lib/carray/methods/gather_nd.rb +25 -5
  179. data/lib/carray/methods/insert_block.rb +9 -14
  180. data/lib/carray/methods/is_between.rb +59 -0
  181. data/lib/carray/methods/is_in.rb +140 -10
  182. data/lib/carray/methods/join.rb +2 -7
  183. data/lib/carray/methods/lag.rb +49 -0
  184. data/lib/carray/methods/locate_addr.rb +182 -45
  185. data/lib/carray/methods/mode.rb +18 -1
  186. data/lib/carray/methods/nunique.rb +11 -6
  187. data/lib/carray/methods/repeat.rb +1 -20
  188. data/lib/carray/methods/resize.rb +21 -23
  189. data/lib/carray/methods/snap.rb +34 -12
  190. data/lib/carray/methods/unique.rb +11 -2
  191. data/lib/carray/methods/value_counts.rb +4 -11
  192. data/lib/carray/record_order.rb +208 -0
  193. data/lib/carray/rng.rb +3 -0
  194. data/lib/carray/runtime.rb +65 -17
  195. data/lib/carray/segment_iterator.rb +1221 -0
  196. data/lib/carray/serialize.rb +214 -30
  197. data/lib/carray/slab_iterator.rb +101 -27
  198. data/lib/carray/stack.rb +10 -4
  199. data/lib/carray/string.rb +105 -5
  200. data/lib/carray/string_operation_extension.rb +12 -4
  201. data/lib/carray/struct.rb +137 -58
  202. data/lib/carray/struct_builder.rb +124 -17
  203. data/lib/carray/time.rb +1222 -186
  204. data/lib/carray/window_iterator.rb +242 -81
  205. data/lib/carray.rb +9 -2
  206. data/yard-stubs/ca_obj_array.rb +4 -4
  207. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  208. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  209. data/yard-stubs/ca_obj_fake.rb +1 -1
  210. data/yard-stubs/ca_obj_field.rb +5 -1
  211. data/yard-stubs/ca_obj_grid.rb +21 -10
  212. data/yard-stubs/ca_obj_refer.rb +5 -4
  213. data/yard-stubs/ca_obj_roll.rb +2 -3
  214. data/yard-stubs/ca_obj_shift.rb +5 -1
  215. data/yard-stubs/ca_obj_stride.rb +10 -7
  216. data/yard-stubs/ca_obj_tile.rb +1 -1
  217. data/yard-stubs/ca_obj_transpose.rb +1 -1
  218. data/yard-stubs/ca_obj_window.rb +9 -5
  219. data/yard-stubs/carray_access.rb +11 -5
  220. data/yard-stubs/carray_attribute.rb +0 -5
  221. data/yard-stubs/carray_broadcast.rb +1 -1
  222. data/yard-stubs/carray_cast.rb +88 -43
  223. data/yard-stubs/carray_conversion.rb +15 -2
  224. data/yard-stubs/carray_copy.rb +12 -5
  225. data/yard-stubs/carray_core.rb +3 -3
  226. data/yard-stubs/carray_count.rb +9 -0
  227. data/yard-stubs/carray_element.rb +10 -4
  228. data/yard-stubs/carray_generate.rb +21 -1
  229. data/yard-stubs/carray_lazy.rb +5 -1
  230. data/yard-stubs/carray_loop.rb +4 -1
  231. data/yard-stubs/carray_mask.rb +60 -12
  232. data/yard-stubs/carray_math.rb +52 -14
  233. data/yard-stubs/carray_median_percentile.rb +15 -8
  234. data/yard-stubs/carray_memory_view.rb +40 -23
  235. data/yard-stubs/carray_order.rb +61 -29
  236. data/yard-stubs/carray_random.rb +13 -4
  237. data/yard-stubs/carray_scatter.rb +21 -9
  238. data/yard-stubs/carray_segment.rb +72 -0
  239. data/yard-stubs/carray_slab.rb +10 -2
  240. data/yard-stubs/carray_sort.rb +49 -8
  241. data/yard-stubs/carray_test.rb +15 -3
  242. data/yard-stubs/carray_utils.rb +0 -26
  243. metadata +19 -5
  244. data/ext/ca_for_each_element.h +0 -239
  245. data/ext/carray_kernels_map.c +0 -3467
  246. data/lib/carray/arrow_tensor.rb +0 -401
  247. data/lib/carray/table.rb +0 -108
data/ext/ca_obj_repeat.c CHANGED
@@ -39,20 +39,21 @@ 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
+ ca_check_rank_fits(ndim, NULL);
42
43
  for (i = 0; i < ndim; i++) {
43
44
  if (count[i] < 0) {
44
- rb_raise(rb_eRuntimeError,
45
+ rb_raise(rb_eArgError,
45
46
  "negative size for %i-th dimension specified", i);
46
47
  }
47
48
  if (count[i]) nrpt *= count[i];
48
49
  else data_ndim += 1;
49
50
  }
50
51
  if (data_ndim != parent->ndim) {
51
- rb_raise(rb_eRuntimeError,
52
+ rb_raise(rb_eArgError,
52
53
  "mismatch in ndim between original array and determined by # of dummies");
53
54
  }
54
55
  if (((double) parent->elements) * nrpt > CA_LENGTH_MAX) {
55
- rb_raise(rb_eRuntimeError, "too large byte length");
56
+ rb_raise(rb_eArgError, "too large byte length");
56
57
  }
57
58
  (void) total_elements_d;
58
59
 
@@ -77,9 +78,15 @@ ca_repeat_setup (CAStride *ca, CArray *parent, int8_t ndim, ca_size_t *count)
77
78
  }
78
79
  }
79
80
 
80
- ca_stride_setup(ca, CA_OBJ_REPEAT, parent,
81
- parent->data_type, parent->bytes,
82
- ndim, newdim, strides, 0);
81
+ /* ca == NULL asks for the checks above only, so that a constructor can
82
+ run them before it allocates. */
83
+ if ( ca == NULL ) {
84
+ return 0;
85
+ }
86
+
87
+ ca_stride_setup_view(ca, CA_OBJ_REPEAT, parent,
88
+ parent->data_type, parent->bytes,
89
+ ndim, newdim, strides, 0);
83
90
 
84
91
  ca_set_flag(ca, CA_FLAG_READ_ONLY);
85
92
  if (ca->mask) {
@@ -91,8 +98,11 @@ ca_repeat_setup (CAStride *ca, CArray *parent, int8_t ndim, ca_size_t *count)
91
98
  CAStride *
92
99
  ca_repeat_new (CArray *parent, int8_t ndim, ca_size_t *count)
93
100
  {
94
- CAStride *ca = (CAStride *) ca_array_alloc(CA_OBJ_REPEAT, ndim);
101
+ CAStride *ca;
102
+ ca_repeat_setup(NULL, parent, ndim, count);
103
+ ca = (CAStride *) ca_array_alloc(CA_OBJ_REPEAT, ndim);
95
104
  ca_repeat_setup(ca, parent, ndim, count);
105
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
96
106
  return ca;
97
107
  }
98
108
 
@@ -155,7 +165,7 @@ rb_ca_repeat (int argc, VALUE *argv, VALUE self)
155
165
  TypedData_Get_Struct(argv[0], CArray, &carray_data_type, ct);
156
166
  }
157
167
  if ( ct->ndim < ca->ndim ) {
158
- rb_raise(rb_eRuntimeError, "invalid ndim to template");
168
+ rb_raise(rb_eArgError, "invalid ndim to template");
159
169
  }
160
170
  args = rb_ary_new();
161
171
  ndim = 0;
@@ -205,9 +215,13 @@ rb_ca_repeat (int argc, VALUE *argv, VALUE self)
205
215
  self = rb_ca_refer_new(self, ca->data_type, ndim, dim, ca->bytes, 0);
206
216
  }
207
217
  }
208
- return rb_ca_repeat((int)RARRAY_LEN(args), (VALUE *)RARRAY_CONST_PTR(args), self);
218
+ self = rb_ca_repeat((int)RARRAY_LEN(args), (VALUE *)RARRAY_CONST_PTR(args), self);
219
+ RB_GC_GUARD(args); /* the repeat reads its arguments out of args */
220
+ return self;
209
221
  }
210
222
 
223
+ ca_check_rank_fits(argc, NULL); /* count[] and dim[] hold CA_RANK_MAX */
224
+
211
225
  repeat = 1;
212
226
  for (i=0; i<argc; i++) {
213
227
  if ( rb_obj_is_kind_of(argv[i], rb_cSymbol) ) {
@@ -255,6 +269,7 @@ rb_ca_repeat_initialize_copy (VALUE self, VALUE other)
255
269
  {
256
270
  CAStride *ca, *cs;
257
271
  TypedData_Get_Struct(self, CAStride, &castride_data_type, ca);
272
+ ca_check_uninitialized(ca);
258
273
  TypedData_Get_Struct(other, CAStride, &castride_data_type, cs);
259
274
  if ( ca_func[CA_OBJ_REPEAT].pool_init ) {
260
275
  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,14 +118,14 @@ 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
 
122
- if ( ca_has_mask(parent) ) {
123
- ca_create_mask(ca);
124
- }
125
129
 
126
130
  return 0;
127
131
  }
@@ -129,8 +133,11 @@ ca_roll_setup (CARoll *ca, CArray *parent, ca_size_t *shift)
129
133
  CARoll *
130
134
  ca_roll_new (CArray *parent, ca_size_t *shift)
131
135
  {
132
- CARoll *ca = ALLOC(CARoll);
136
+ CARoll *ca;
137
+ ca_roll_setup(NULL, parent, shift);
138
+ ca = ALLOC(CARoll);
133
139
  ca_roll_setup(ca, parent, shift);
140
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
134
141
  return ca;
135
142
  }
136
143
 
@@ -214,6 +221,7 @@ static void
214
221
  ca_roll_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
215
222
  ca_size_t *strides, void *data, int dir)
216
223
  {
224
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
217
225
  CARoll *ca = (CARoll *) ap;
218
226
  CArray *parent = ca->parent;
219
227
  int8_t ndim = ca->ndim;
@@ -251,6 +259,7 @@ ca_roll_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
251
259
  ca_size_t idx[CA_RANK_MAX], doff = 0, base = 0;
252
260
  for (k = 0; k < ndim; k++) base += starts[k] * rnative[k];
253
261
  for (k = 0; k < ndim; k++) idx[k] = 0;
262
+ /* empty: the slot returns on an empty region at its entry */
254
263
  while (1) {
255
264
  ca_size_t roff = base, ridx[CA_RANK_MAX];
256
265
  for (k = 0; k < ndim; k++) roff += idx[k] * strides[k];
@@ -264,7 +273,97 @@ ca_roll_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
264
273
  return;
265
274
  }
266
275
 
276
+ /* The inner range is one run of a parent row, or two when it wraps, and
277
+ the rows along the next axis out are consecutive parent rows except
278
+ across that axis's wrap. So each pass over the axes further out moves
279
+ at most two strided boxes per inner run, instead of one transfer per
280
+ row. A box over an unwrapped inner range is already the request's own
281
+ layout; a box over one of two inner runs goes through a scratch whose
282
+ rows are spliced into the request's. Object cells keep the per-row
283
+ path: a scratch would hold the VALUEs a parent produces where the GC
284
+ cannot see them. */
285
+ if ( inner >= 1 ) {
286
+ int8_t m = inner - 1;
287
+ ca_size_t dim_in = parent->dim[inner];
288
+ ca_size_t p0 = starts[inner] - ca->reps[inner];
289
+ ca_size_t seg_p[2], seg_n[2], seg_i[2];
290
+ int nseg, sg;
291
+ if (p0 < 0) p0 += dim_in;
292
+ if ( p0 + counts[inner] <= dim_in ) {
293
+ nseg = 1;
294
+ seg_p[0] = p0; seg_n[0] = counts[inner]; seg_i[0] = 0;
295
+ }
296
+ else {
297
+ nseg = 2;
298
+ seg_p[0] = p0; seg_n[0] = dim_in - p0; seg_i[0] = 0;
299
+ seg_p[1] = 0; seg_n[1] = counts[inner] - seg_n[0]; seg_i[1] = seg_n[0];
300
+ }
301
+ if ( nseg == 1 || ca->data_type != CA_OBJECT ) {
302
+ volatile VALUE holder = 0;
303
+ char *tmp = NULL;
304
+ if ( nseg == 2 ) {
305
+ ca_size_t wide = seg_n[0] > seg_n[1] ? seg_n[0] : seg_n[1];
306
+ tmp = (char *) ALLOCV(holder, counts[m] * wide * ca->bytes);
307
+ }
308
+ for (k = 0; k < m; k++) o[k] = 0;
309
+ while (1) {
310
+ ca_size_t pbase = 0, doff = 0;
311
+ for (k = 0; k < m; k++) {
312
+ ca_size_t j = (starts[k] + o[k]) - ca->reps[k];
313
+ if (j < 0) j += parent->dim[k];
314
+ pbase += j * pnative[k];
315
+ doff += o[k] * dstride[k];
316
+ }
317
+ for (sg = 0; sg < nseg; sg++) {
318
+ ca_size_t r = 0;
319
+ while (r < counts[m]) {
320
+ ca_size_t pm = (starts[m] + r) - ca->reps[m];
321
+ ca_size_t run, q;
322
+ ca_size_t pstarts[CA_RANK_MAX], pcounts[CA_RANK_MAX], pstrides[CA_RANK_MAX];
323
+ char *rows = d + doff + r * dstride[m] + seg_i[sg] * ca->bytes;
324
+ ca_size_t rowb = seg_n[sg] * ca->bytes;
325
+ if (pm < 0) pm += parent->dim[m];
326
+ run = parent->dim[m] - pm;
327
+ if (run > counts[m] - r) run = counts[m] - r;
328
+ ca_addr2index((CArray *) parent,
329
+ (pbase + pm * pnative[m] + seg_p[sg] * pnative[inner])
330
+ / parent->bytes, pstarts);
331
+ for (k = 0; k < ndim; k++) { pcounts[k] = 1; pstrides[k] = 0; }
332
+ pcounts[m] = run;
333
+ pstrides[m] = pnative[m];
334
+ pcounts[inner] = seg_n[sg];
335
+ pstrides[inner] = pnative[inner];
336
+ if ( nseg == 1 ) {
337
+ ca_xfer_stride(parent, pstarts, pcounts, pstrides, rows, dir);
338
+ }
339
+ else if ( dir == CA_XFER_GET ) {
340
+ ca_xfer_stride(parent, pstarts, pcounts, pstrides, tmp, dir);
341
+ for (q = 0; q < run; q++) {
342
+ memcpy(rows + q * dstride[m], tmp + q * rowb, rowb);
343
+ }
344
+ }
345
+ else {
346
+ for (q = 0; q < run; q++) {
347
+ memcpy(tmp + q * rowb, rows + q * dstride[m], rowb);
348
+ }
349
+ ca_xfer_stride(parent, pstarts, pcounts, pstrides, tmp, dir);
350
+ }
351
+ r += run;
352
+ }
353
+ }
354
+ k = m - 1;
355
+ while (k >= 0) { if (++o[k] < counts[k]) break; o[k] = 0; k--; }
356
+ if (k < 0) break;
357
+ }
358
+ if ( tmp ) {
359
+ ALLOCV_END(holder);
360
+ }
361
+ return;
362
+ }
363
+ }
364
+
267
365
  for (k = 0; k < ndim; k++) o[k] = 0;
366
+ /* empty: the slot returns on an empty region at its entry */
268
367
  while (1) {
269
368
  ca_size_t pbase = 0, doff = 0, i;
270
369
  for (k = 0; k < inner; k++) {
@@ -407,7 +506,7 @@ ca_roll_func_allocate (void *ap)
407
506
  {
408
507
  CARoll *ca = (CARoll *) ap;
409
508
  ca_attach(ca->parent);
410
- ca->ptr = xmalloc(ca_length(ca));
509
+ ca->ptr = ca_alloc_cells((CArray *) ca);
411
510
  }
412
511
 
413
512
  static void
@@ -415,7 +514,7 @@ ca_roll_func_attach (void *ap)
415
514
  {
416
515
  CARoll *ca = (CARoll *) ap;
417
516
  ca_attach(ca->parent);
418
- ca->ptr = xmalloc(ca_length(ca));
517
+ ca->ptr = ca_alloc_cells((CArray *) ca);
419
518
  ca_roll_iterate_regions(ca, ca->ptr, 0);
420
519
  }
421
520
 
@@ -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,14 @@ 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);
662
+ ca_view_inherit_mask((VALUE) ca);
562
663
  return self;
563
664
  }
564
665
 
666
+ #ifdef CARRAY_DEV_BUILD
565
667
  /* Debug-only accessor returning the roll descriptor as a Hash
566
668
  (`shifts`, `n_regions`, `ndim`). Not part of the public surface. */
567
669
  static VALUE
@@ -583,6 +685,7 @@ rb_ca_roll_descriptor (VALUE self)
583
685
  rb_hash_aset(hash, ID2SYM(rb_intern("ndim")), INT2NUM(ca->ndim));
584
686
  return hash;
585
687
  }
688
+ #endif
586
689
 
587
690
  void
588
691
  Init_ca_obj_roll (void)
@@ -618,7 +721,9 @@ Init_ca_obj_roll (void)
618
721
  rb_define_method(rb_cCARoll, "initialize_copy",
619
722
  rb_ca_roll_initialize_copy, 1);
620
723
 
724
+ #ifdef CARRAY_DEV_BUILD
621
725
  /* Debug accessor, not part of the public surface. */
622
726
  rb_define_method(rb_cCARoll, "_roll_descriptor",
623
727
  rb_ca_roll_descriptor, 0);
728
+ #endif
624
729
  }
data/ext/ca_obj_select.c CHANGED
@@ -93,21 +93,24 @@ ca_select_snapshot_masked (VALUE arg)
93
93
  {
94
94
  CArray **pair = (CArray **) arg;
95
95
  CArray *select = pair[0], *snap = pair[1];
96
- boolean8_t *p, *q, *m;
96
+ boolean8_t *q, *m;
97
97
  ca_size_t i;
98
- ca_attach(select);
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);
99
103
  q = (boolean8_t *) snap->ptr;
100
- p = (boolean8_t *) select->ptr;
101
- m = (boolean8_t *) select->mask->ptr;
102
104
  for (i = 0; i < select->elements; i++) {
103
- *q = ( *m ) ? 0 : *p;
104
- q++; p++; m++;
105
+ if ( m[i] ) {
106
+ q[i] = 0;
107
+ }
105
108
  }
106
- ca_detach(select);
109
+ ALLOCV_END(holder);
107
110
  return Qnil;
108
111
  }
109
112
 
110
- static CArray *
113
+ CArray *
111
114
  ca_select_snapshot (CArray *select)
112
115
  {
113
116
  if ( ! ca_is_boolean_type(select) ) {
@@ -159,15 +162,19 @@ ca_select_setup (CASelect *ca, CArray *parent, CArray *snapshot)
159
162
  if ( s[i] ) count++;
160
163
  }
161
164
  ca->elements = count;
162
- /* Placeholder 1-element allocation when count == 0 to avoid
163
- malloc(0) implementation variance; the engine treats
164
- elements==0 as a no-op so the contents are irrelevant. */
165
- ca->indices = (ca_size_t *) xmalloc(
166
- sizeof(ca_size_t) * (count > 0 ? count : 1));
165
+ /* One slot more than count: the loop below writes every position
166
+ and advances only on TRUE, so a run of FALSE after the last TRUE
167
+ writes slot `count`. Writing without a branch keeps a selector
168
+ with TRUE and FALSE mixed at random from mispredicting on most
169
+ cells. The extra slot also keeps count == 0 from malloc(0). */
170
+ ca->indices = (ca_size_t *) xmalloc(sizeof(ca_size_t) * (count + 1));
167
171
  {
168
- ca_size_t j = 0;
169
- for (i = 0; i < ca->select->elements; i++) {
170
- if ( s[i] ) ca->indices[j++] = i;
172
+ ca_size_t *ix = ca->indices;
173
+ ca_size_t n = ca->select->elements;
174
+ ca_size_t j = 0;
175
+ for (i = 0; i < n; i++) {
176
+ ix[j] = i;
177
+ j += ( s[i] != 0 );
171
178
  }
172
179
  }
173
180
  /* Constant-step detection: promotes to STRIDE descriptor kind
@@ -208,6 +215,7 @@ CArray *
208
215
  ca_select_new (CArray *parent, CArray *select)
209
216
  {
210
217
  CArray *snapshot = ca_select_snapshot(select);
218
+ /* check: the setup checks nothing */
211
219
  CASelect *ca = ALLOC(CASelect);
212
220
  ca_select_setup(ca, parent, snapshot);
213
221
  return (CArray*) ca;
@@ -352,6 +360,7 @@ static void
352
360
  ca_select_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
353
361
  ca_size_t *strides, void *data, int dir)
354
362
  {
363
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
355
364
  CASelect *ca = (CASelect *) ap;
356
365
  CArray *parent = ca->parent;
357
366
  ca_size_t n = counts[0];
@@ -414,24 +423,34 @@ ca_select_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
414
423
  }
415
424
  }
416
425
 
426
+ /* A parent with no memory to lend (ca_parent_lends_no_memory) is never
427
+ attached: the view owns its buffer, filled and drained through xfer_all,
428
+ which asks the parent for the selected cells only. The predicate asks
429
+ what the parent is, not whether it is attached now, so attach, sync and
430
+ detach all take the same branch. */
431
+
417
432
  static void
418
433
  ca_select_func_allocate (void *ap)
419
434
  {
420
435
  CASelect *ca = (CASelect *) ap;
421
- ca_attach(ca->parent);
422
- ca->ptr = xmalloc(ca_length(ca));
436
+ if ( ! ca_parent_lends_no_memory(ca->parent) ) {
437
+ ca_attach(ca->parent);
438
+ }
439
+ ca->ptr = ca_alloc_cells((CArray *) ca);
423
440
  }
424
441
 
425
- /* Every attach / sync / xfer_all / xfer_stride / fill_data path
426
- dispatches through the descriptor engine with the same shape
427
- CASelectAxis uses: one axis over a flattened parent. */
428
-
429
442
  static void
430
443
  ca_select_func_attach (void *ap)
431
444
  {
432
445
  CASelect *ca = (CASelect *) ap;
433
446
  ca_axis_desc_t desc[CA_RANK_MAX];
434
447
  ca_size_t pdims[CA_RANK_MAX];
448
+
449
+ if ( ca_parent_lends_no_memory(ca->parent) ) {
450
+ ca_axis_view_attach_owned(ca);
451
+ return;
452
+ }
453
+
435
454
  ca_attach(ca->parent);
436
455
  ca_select_describe_axes(ca, desc, pdims);
437
456
  ca->ptr = ca_axis_dispatch_attach(ca->parent, pdims, desc, ca->ndim,
@@ -444,6 +463,12 @@ ca_select_func_sync (void *ap)
444
463
  CASelect *ca = (CASelect *) ap;
445
464
  ca_axis_desc_t desc[CA_RANK_MAX];
446
465
  ca_size_t pdims[CA_RANK_MAX];
466
+
467
+ if ( ca_parent_lends_no_memory(ca->parent) ) {
468
+ ca_axis_view_sync_owned(ca);
469
+ return;
470
+ }
471
+
447
472
  ca_select_describe_axes(ca, desc, pdims);
448
473
  ca_axis_dispatch_scatter(ca->parent, pdims, desc, ca->ndim, ca->bytes,
449
474
  ca->elements, ca->ptr);
@@ -454,16 +479,20 @@ static void
454
479
  ca_select_func_detach (void *ap)
455
480
  {
456
481
  CASelect *ca = (CASelect *) ap;
457
- xfree(ca->ptr);
458
- ca->ptr = NULL;
459
- ca_detach(ca->parent);
482
+ if ( ca->ptr ) {
483
+ xfree(ca->ptr);
484
+ ca->ptr = NULL;
485
+ }
486
+ if ( ! ca_parent_lends_no_memory(ca->parent) ) {
487
+ ca_detach(ca->parent);
488
+ }
460
489
  }
461
490
 
462
- /* Fast-path core used by xfer_all's attached-parent branch and the
463
- cold-parent 2-pass scratch branch below. */
491
+ /* The transfer against parent->ptr, for ca_axis_view_xfer_all. */
464
492
  static void
465
- ca_select_func_run_fast_path (CASelect *ca, char *data, int dir)
493
+ ca_select_func_run_fast_path (void *ap, char *data, int dir)
466
494
  {
495
+ CASelect *ca = (CASelect *) ap;
467
496
  ca_axis_desc_t desc[CA_RANK_MAX];
468
497
  ca_size_t pdims[CA_RANK_MAX];
469
498
  ca_select_describe_axes(ca, desc, pdims);
@@ -476,33 +505,10 @@ ca_select_func_run_fast_path (CASelect *ca, char *data, int dir)
476
505
  }
477
506
  }
478
507
 
479
- /* Cold parent is served by a 2-pass scratch (gather parent into a
480
- local buffer, dispatch through the fast path against the buffer,
481
- scatter back on PUT). Deliberately avoids ca_attach(parent) so
482
- that a silent transitive attach cannot re-enter through here. */
483
508
  static void
484
509
  ca_select_func_xfer_all (void *ap, void *data, int dir)
485
510
  {
486
- CASelect *ca = (CASelect *) ap;
487
- if ( ca->parent->ptr ) {
488
- ca_select_func_run_fast_path(ca, (char *) data, dir);
489
- return;
490
- }
491
- {
492
- volatile VALUE holder;
493
- CArray *parent = ca->parent;
494
- ca_size_t plen = parent->elements * parent->bytes;
495
- char *parent_scratch = ALLOCV_N(char, holder, plen);
496
- char *parent_ptr_saved = parent->ptr;
497
- ca_xfer_all(parent, parent_scratch, CA_XFER_GET);
498
- parent->ptr = parent_scratch;
499
- ca_select_func_run_fast_path(ca, (char *) data, dir);
500
- if ( dir == CA_XFER_PUT ) {
501
- ca_xfer_all(parent, parent_scratch, CA_XFER_PUT);
502
- }
503
- parent->ptr = parent_ptr_saved;
504
- ALLOCV_END(holder);
505
- }
511
+ ca_axis_view_xfer_all(ap, ca_select_func_run_fast_path, 1, data, dir);
506
512
  }
507
513
 
508
514
  static void
@@ -531,18 +537,14 @@ ca_select_func_fill_data (void *ap, void *ptr)
531
537
  ca_select_describe_axes(ca, desc, pdims);
532
538
  ca_axis_dispatch_fill_value(ca->parent, pdims, desc, ca->ndim, ca->bytes,
533
539
  ca->elements, ptr);
534
- ca_sync(ca->parent);
535
- ca_detach(ca->parent);
540
+ ca_sync_detach(ca->parent);
536
541
  }
537
542
 
538
543
  static void
539
544
  ca_select_func_create_mask (void *ap)
540
545
  {
541
546
  CASelect *ca = (CASelect *) ap;
542
- ca_update_mask(ca->parent);
543
- if ( ! ca->parent->mask ) {
544
- ca_create_mask(ca->parent);
545
- }
547
+ ca_create_mask(ca->parent);
546
548
  ca->mask = (CArray *) ca_select_new_share(ca->parent->mask, ca->select);
547
549
  }
548
550
 
@@ -624,6 +626,7 @@ rb_cm_initialize_copy (VALUE self, VALUE other)
624
626
  CASelect *ca, *cs;
625
627
 
626
628
  TypedData_Get_Struct(self, CASelect, &caselect_data_type, ca);
629
+ ca_check_uninitialized(ca);
627
630
  TypedData_Get_Struct(other, CASelect, &caselect_data_type, cs);
628
631
 
629
632
  /* Re-snapshot from the source's selector copy so the two views