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_grid.c CHANGED
@@ -14,6 +14,7 @@
14
14
  ---------------------------------------------------------------------------- */
15
15
 
16
16
  #include "carray.h"
17
+ #include "carray_internal.h" /* ca_attach_window */
17
18
 
18
19
  /* Per-axis tagged kind. Each axis is either STRIDE (start/step/count,
19
20
  no allocation) or INDEX (an owned ca_size_t index snapshot). A Range
@@ -122,53 +123,81 @@ static VALUE rb_cCAGridMask;
122
123
 
123
124
  static int8_t CA_OBJ_GRID;
124
125
 
125
- /* Setup: caller passes ndim + per-axis protos (cag_axis_t). Copies the
126
- fields and, for INDEX axes, snapshots the indices into an owned buffer.
127
- The share path (share=1, from initialize_copy and create_mask) aliases
128
- the caller's protos buffer instead, tying its lifetime to the source
129
- CAGrid (free_ca_grid skips the xfree under CA_FLAG_SHARE_INDEX). */
130
- int
131
- ca_grid_setup (CAGrid *ca, CArray *parent, int8_t ndim,
132
- cag_axis_t *protos, int share)
126
+ /* Raises when protos cannot describe a view of parent: an ndim that is
127
+ not parent's, a negative count, a byte length over the limit, or a
128
+ parent index out of range. Nothing is allocated here, so the caller
129
+ runs it before taking memory. */
130
+ static void
131
+ ca_grid_check_protos (CArray *parent, int8_t ndim, const cag_axis_t *protos)
133
132
  {
134
133
  int8_t k;
135
- int8_t data_type;
136
- ca_size_t elements, bytes;
137
- double length;
138
- ca_size_t *dim0;
134
+ ca_size_t j;
135
+ double length;
139
136
 
140
- CA_ASSUME(ndim >= 0 && ndim <= CA_RANK_MAX); /* bound loops/allocs over [CA_RANK_MAX] arrays */
141
- data_type = parent->data_type;
142
- bytes = parent->bytes;
143
- dim0 = parent->dim;
144
-
145
- /* parent->ndim should equal ndim (= number of axes provided).
146
- rb_ca_grid pads with nil when fewer args are given, so by the
147
- time we get here ndim == parent->ndim. */
137
+ /* rb_ca_grid pads with nil when fewer args are given, so ndim ==
138
+ parent->ndim for every in-tree caller. */
148
139
  if ( ndim != parent->ndim ) {
149
140
  rb_raise(rb_eArgError,
150
141
  "CAGrid: ndim mismatch (%d args vs parent->ndim %d)",
151
142
  (int) ndim, (int) parent->ndim);
152
143
  }
153
144
 
154
- elements = 1;
155
- length = bytes;
145
+ length = parent->bytes;
156
146
  for (k = 0; k < ndim; k++) {
157
147
  if (protos[k].count < 0) {
158
- rb_raise(rb_eRuntimeError, "negative size for %d-th dimension", k);
148
+ rb_raise(rb_eArgError, "negative size for %d-th dimension", k);
159
149
  }
160
- elements *= protos[k].count;
161
150
  length *= protos[k].count;
162
151
  }
163
152
  if (length > CA_LENGTH_MAX) {
164
- rb_raise(rb_eRuntimeError, "too large byte length");
153
+ rb_raise(rb_eArgError, "too large byte length");
154
+ }
155
+
156
+ for (k = 0; k < ndim; k++) {
157
+ if ( protos[k].count <= 0 ) {
158
+ continue;
159
+ }
160
+ if (protos[k].kind == CAG_AXIS_STRIDE) {
161
+ ca_size_t first = protos[k].start;
162
+ ca_size_t last = first + (protos[k].count - 1) * protos[k].step;
163
+ CA_CHECK_INDEX(first, parent->dim[k]);
164
+ if (protos[k].count > 1) CA_CHECK_INDEX(last, parent->dim[k]);
165
+ }
166
+ else {
167
+ for (j = 0; j < protos[k].count; j++) {
168
+ ca_size_t v = protos[k].indices[j];
169
+ CA_CHECK_INDEX(v, parent->dim[k]);
170
+ }
171
+ }
172
+ }
173
+ }
174
+
175
+ /* Setup: caller passes ndim + per-axis protos (cag_axis_t) that
176
+ ca_grid_check_protos has accepted. Copies the fields and, for INDEX
177
+ axes, snapshots the indices into an owned buffer. The share path
178
+ (share=1, used only by create_mask) aliases the caller's protos buffer
179
+ instead: the mask grid is owned and freed by the grid whose axes it
180
+ aliases (free_ca_grid skips the xfree under CA_FLAG_SHARE_INDEX). */
181
+ static int
182
+ ca_grid_setup (CAGrid *ca, CArray *parent, int8_t ndim,
183
+ cag_axis_t *protos, int share)
184
+ {
185
+ int8_t k;
186
+ ca_size_t elements;
187
+
188
+ CA_ASSUME(ndim >= 0 && ndim <= CA_RANK_MAX); /* bound loops/allocs over [CA_RANK_MAX] arrays */
189
+
190
+ {
191
+ ca_size_t counts[CA_RANK_MAX];
192
+ for (k = 0; k < ndim; k++) counts[k] = protos[k].count;
193
+ elements = ca_shape_elements(ndim, counts, parent->bytes);
165
194
  }
166
195
 
167
196
  ca->obj_type = CA_OBJ_GRID;
168
- ca->data_type = data_type;
197
+ ca->data_type = parent->data_type;
169
198
  ca->flags = 0;
170
199
  ca->ndim = ndim;
171
- ca->bytes = bytes;
200
+ ca->bytes = parent->bytes;
172
201
  ca->elements = elements;
173
202
  ca->ptr = NULL;
174
203
  ca->mask = NULL;
@@ -196,13 +225,6 @@ ca_grid_setup (CAGrid *ca, CArray *parent, int8_t ndim,
196
225
  ca->axes[k].start = protos[k].start;
197
226
  ca->axes[k].step = protos[k].step;
198
227
  ca->axes[k].indices = NULL;
199
- /* Bounds check: first and last parent index must be in range. */
200
- if (protos[k].count > 0) {
201
- ca_size_t first = protos[k].start;
202
- ca_size_t last = first + (protos[k].count - 1) * protos[k].step;
203
- CA_CHECK_INDEX(first, dim0[k]);
204
- if (protos[k].count > 1) CA_CHECK_INDEX(last, dim0[k]);
205
- }
206
228
  } else {
207
229
  ca->axes[k].start = 0;
208
230
  ca->axes[k].step = 0;
@@ -211,8 +233,7 @@ ca_grid_setup (CAGrid *ca, CArray *parent, int8_t ndim,
211
233
  ca_size_t j;
212
234
  for (j = 0; j < protos[k].count; j++) {
213
235
  ca_size_t v = protos[k].indices[j];
214
- CA_CHECK_INDEX(v, dim0[k]);
215
- ca->axes[k].indices[j] = v;
236
+ ca->axes[k].indices[j] = ( v < 0 ) ? v + parent->dim[k] : v;
216
237
  }
217
238
  }
218
239
  }
@@ -228,7 +249,9 @@ ca_grid_setup (CAGrid *ca, CArray *parent, int8_t ndim,
228
249
  CAGrid *
229
250
  ca_grid_new (CArray *parent, int8_t ndim, cag_axis_t *protos)
230
251
  {
231
- CAGrid *ca = (CAGrid *) ca_array_alloc(CA_OBJ_GRID, ndim);
252
+ CAGrid *ca;
253
+ ca_grid_check_protos(parent, ndim, protos);
254
+ ca = (CAGrid *) ca_array_alloc(CA_OBJ_GRID, ndim);
232
255
  ca_grid_setup(ca, parent, ndim, protos, 0);
233
256
  return ca;
234
257
  }
@@ -278,7 +301,7 @@ static void *
278
301
  ca_grid_func_clone (void *ap)
279
302
  {
280
303
  CAGrid *ca = (CAGrid *) ap;
281
- return ca_grid_new_share(ca->parent, ca->ndim, ca->axes);
304
+ return ca_grid_new(ca->parent, ca->ndim, ca->axes);
282
305
  }
283
306
 
284
307
  /* Per-axis parent-index lookup. STRIDE = one multiply, INDEX = one
@@ -451,6 +474,7 @@ static void
451
474
  ca_grid_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
452
475
  ca_size_t *strides, void *data, int dir)
453
476
  {
477
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
454
478
  CAGrid *g = (CAGrid *) ap;
455
479
  CArray *parent = g->parent;
456
480
  int8_t ndim = g->ndim;
@@ -624,24 +648,39 @@ ca_grid_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
624
648
  }
625
649
  }
626
650
 
651
+ /* attach / sync / copy_data / sync_data / fill_data all go through the
652
+ descriptor engine (ca_axis_dispatch.c). This file supplies only
653
+ describe_axes; the engine does the rest.
654
+
655
+ A parent with no memory to lend (ca_parent_lends_no_memory) is never
656
+ attached: attaching it would produce all of its cells to serve the few
657
+ this grid selects. The grid then owns its buffer, filled and drained
658
+ through xfer_all, which asks the parent for the selected cells only.
659
+ The predicate asks what the parent is, not whether it is attached now,
660
+ so attach, sync and detach all take the same branch. */
661
+
627
662
  static void
628
663
  ca_grid_func_allocate (void *ap)
629
664
  {
630
665
  CAGrid *ca = (CAGrid *) ap;
631
- ca_attach(ca->parent);
666
+ if ( ! ca_parent_lends_no_memory(ca->parent) ) {
667
+ ca_attach(ca->parent);
668
+ }
632
669
  ca->ptr = xmalloc(ca_length(ca));
633
670
  }
634
671
 
635
- /* attach / sync / copy_data / sync_data / fill_data all go through the
636
- descriptor engine (ca_axis_dispatch.c). This file supplies only
637
- describe_axes; the engine does the rest. */
638
-
639
672
  static void
640
673
  ca_grid_func_attach (void *ap)
641
674
  {
642
675
  CAGrid *ca = (CAGrid *) ap;
643
676
  ca_axis_desc_t desc[CA_RANK_MAX];
644
677
  ca_size_t pdims[CA_RANK_MAX];
678
+
679
+ if ( ca_parent_lends_no_memory(ca->parent) ) {
680
+ ca_axis_view_attach_owned(ca);
681
+ return;
682
+ }
683
+
645
684
  ca_attach(ca->parent);
646
685
  ca_grid_describe_axes(ca, desc, pdims);
647
686
  ca->ptr = ca_axis_dispatch_attach(ca->parent, pdims, desc, ca->ndim,
@@ -654,6 +693,12 @@ ca_grid_func_sync (void *ap)
654
693
  CAGrid *ca = (CAGrid *) ap;
655
694
  ca_axis_desc_t desc[CA_RANK_MAX];
656
695
  ca_size_t pdims[CA_RANK_MAX];
696
+
697
+ if ( ca_parent_lends_no_memory(ca->parent) ) {
698
+ ca_axis_view_sync_owned(ca);
699
+ return;
700
+ }
701
+
657
702
  ca_grid_describe_axes(ca, desc, pdims);
658
703
  ca_axis_dispatch_scatter(ca->parent, pdims, desc, ca->ndim, ca->bytes,
659
704
  ca->elements, ca->ptr);
@@ -666,16 +711,16 @@ ca_grid_func_detach (void *ap)
666
711
  CAGrid *ca = (CAGrid *) ap;
667
712
  xfree(ca->ptr);
668
713
  ca->ptr = NULL;
669
- ca_detach(ca->parent);
714
+ if ( ! ca_parent_lends_no_memory(ca->parent) ) {
715
+ ca_detach(ca->parent);
716
+ }
670
717
  }
671
718
 
672
- /* xfer_all: fast path on parent->ptr, with no silent transitive attach
673
- of the parent. A cold parent uses a proper 2-pass -- materialise the
674
- parent into scratch via ca_xfer_all, temporarily expose it as
675
- parent->ptr, run the fast path, then (for PUT) write scratch back. */
719
+ /* The transfer against parent->ptr, for ca_axis_view_xfer_all. */
676
720
  static void
677
- ca_grid_func_run_fast_path (CAGrid *ca, char *data, int dir)
721
+ ca_grid_func_run_fast_path (void *ap, char *data, int dir)
678
722
  {
723
+ CAGrid *ca = (CAGrid *) ap;
679
724
  ca_axis_desc_t desc[CA_RANK_MAX];
680
725
  ca_size_t pdims[CA_RANK_MAX];
681
726
  ca_grid_describe_axes(ca, desc, pdims);
@@ -691,27 +736,7 @@ ca_grid_func_run_fast_path (CAGrid *ca, char *data, int dir)
691
736
  static void
692
737
  ca_grid_func_xfer_all (void *ap, void *data, int dir)
693
738
  {
694
- CAGrid *ca = (CAGrid *) ap;
695
- if ( ca->parent->ptr ) {
696
- ca_grid_func_run_fast_path(ca, (char *) data, dir);
697
- return;
698
- }
699
- /* Proper 2-pass cold fallback. */
700
- {
701
- volatile VALUE holder;
702
- CArray *parent = ca->parent;
703
- ca_size_t plen = parent->elements * parent->bytes;
704
- char *parent_scratch = ALLOCV_N(char, holder, plen);
705
- char *parent_ptr_saved = parent->ptr;
706
- ca_xfer_all(parent, parent_scratch, CA_XFER_GET);
707
- parent->ptr = parent_scratch;
708
- ca_grid_func_run_fast_path(ca, (char *) data, dir);
709
- if ( dir == CA_XFER_PUT ) {
710
- ca_xfer_all(parent, parent_scratch, CA_XFER_PUT);
711
- }
712
- parent->ptr = parent_ptr_saved;
713
- ALLOCV_END(holder);
714
- }
739
+ ca_axis_view_xfer_all(ap, ca_grid_func_run_fast_path, 1, data, dir);
715
740
  }
716
741
 
717
742
  static void
@@ -734,11 +759,10 @@ ca_grid_func_fill_data (void *ap, void *ptr)
734
759
  return;
735
760
  }
736
761
 
737
- ca_attach(ca->parent);
762
+ ca_attach(ca->parent); /* window: nothing raises inside */
738
763
  ca_axis_dispatch_fill_value(ca->parent, pdims, desc, ca->ndim, ca->bytes,
739
764
  ca->elements, ptr);
740
- ca_sync(ca->parent);
741
- ca_detach(ca->parent);
765
+ ca_sync_detach(ca->parent);
742
766
  }
743
767
 
744
768
  static void
@@ -746,10 +770,7 @@ ca_grid_func_create_mask (void *ap)
746
770
  {
747
771
  CAGrid *ca = (CAGrid *) ap;
748
772
 
749
- ca_update_mask(ca->parent);
750
- if ( ! ca->parent->mask ) {
751
- ca_create_mask(ca->parent);
752
- }
773
+ ca_create_mask(ca->parent);
753
774
 
754
775
  ca->mask = (CArray *) ca_grid_new_share(ca->parent->mask,
755
776
  ca->ndim, ca->axes);
@@ -824,6 +845,63 @@ cag_range_to_stride (VALUE range, ca_size_t dim_size,
824
845
  return 1;
825
846
  }
826
847
 
848
+ /* The INDEX axes of rb_ca_grid, read with their index arrays attached,
849
+ and the view built from them. */
850
+
851
+ typedef struct {
852
+ VALUE self;
853
+ CArray *ca;
854
+ CArray **ci;
855
+ cag_axis_t *protos;
856
+ } ca_grid_build_ctx_t;
857
+
858
+ static VALUE
859
+ ca_grid_build_body (VALUE arg)
860
+ {
861
+ ca_grid_build_ctx_t *c = (ca_grid_build_ctx_t *) arg;
862
+ volatile VALUE holders[CA_RANK_MAX];
863
+ volatile VALUE obj;
864
+ int8_t i;
865
+
866
+ for (i = 0; i < c->ca->ndim; i++) {
867
+ CArray *ci = c->ci[i];
868
+ holders[i] = Qfalse;
869
+ if ( ! ci ) {
870
+ continue;
871
+ }
872
+ c->protos[i].kind = CAG_AXIS_INDEX;
873
+ if ( ca_is_any_masked(ci) ) {
874
+ /* mask-filtered snapshot: skip masked cells. setup copies the
875
+ indices into its own buffer, so the snapshot only has to live
876
+ until ca_grid_new returns. */
877
+ ca_size_t gsize = ci->elements - ca_count_masked(ci);
878
+ ca_size_t *src = (ca_size_t *) ci->ptr;
879
+ boolean8_t *m = (boolean8_t *) ci->mask->ptr;
880
+ ca_size_t *tmp = ALLOCV_N(ca_size_t, holders[i], gsize > 0 ? gsize : 1);
881
+ ca_size_t j, n = 0;
882
+ for (j = 0; j < ci->elements; j++) {
883
+ if ( ! m[j] ) tmp[n++] = src[j];
884
+ }
885
+ c->protos[i].count = gsize;
886
+ c->protos[i].indices = tmp;
887
+ } else {
888
+ c->protos[i].count = ci->elements;
889
+ c->protos[i].indices = (ca_size_t *) ci->ptr;
890
+ }
891
+ c->protos[i].start = 0;
892
+ c->protos[i].step = 0;
893
+ }
894
+
895
+ obj = rb_ca_grid_new(c->self, c->ca->ndim, c->protos);
896
+
897
+ for (i = 0; i < c->ca->ndim; i++) {
898
+ if ( c->ci[i] && holders[i] != Qfalse ) {
899
+ ALLOCV_END(holders[i]);
900
+ }
901
+ }
902
+ return obj;
903
+ }
904
+
827
905
  VALUE
828
906
  rb_ca_grid (int argc, VALUE *argv, VALUE self)
829
907
  {
@@ -916,49 +994,30 @@ rb_ca_grid (int argc, VALUE *argv, VALUE self)
916
994
  }
917
995
  }
918
996
  else if ( TYPE(rval) == T_ARRAY ) {
919
- rb_raise(rb_eRuntimeError, "not implemented for this index");
997
+ rb_raise(rb_eTypeError, "grid: an axis is an Integer, a Range, nil or a CArray of indices (got Array)");
920
998
  }
921
999
 
922
- /* INDEX axis */
1000
+ /* INDEX axis: converted here, read once the window below opens */
1001
+ ca_check_index_array(rval);
923
1002
  ci[i] = ca_wrap_readonly(rval, CA_SIZE);
924
1003
  rb_ary_push(list, rval);
925
- ca_attach(ci[i]);
926
-
927
- protos[i].kind = CAG_AXIS_INDEX;
928
- if ( ca_is_any_masked(ci[i]) ) {
929
- /* mask-filtered snapshot: skip masked cells. We point protos[i]
930
- .indices at a temp buffer alloc'd here and freed after setup
931
- copies it (setup snapshots into its own ALLOC). Caller-side
932
- lifetime: the temp lives until ca_grid_new returns. */
933
- ca_size_t gsize = ci[i]->elements - ca_count_masked(ci[i]);
934
- ca_size_t *src = (ca_size_t *) ci[i]->ptr;
935
- boolean8_t *m = (boolean8_t *) ci[i]->mask->ptr;
936
- ca_size_t *tmp = ALLOC_N(ca_size_t, gsize > 0 ? gsize : 1);
937
- ca_size_t j, n = 0;
938
- for (j = 0; j < ci[i]->elements; j++) {
939
- if ( ! m[j] ) tmp[n++] = src[j];
940
- }
941
- protos[i].count = gsize;
942
- protos[i].indices = tmp;
943
- } else {
944
- protos[i].count = ci[i]->elements;
945
- protos[i].indices = (ca_size_t *) ci[i]->ptr;
946
- }
947
- protos[i].start = 0;
948
- protos[i].step = 0;
949
1004
  }
950
1005
 
951
- obj = rb_ca_grid_new(self, ca->ndim, protos);
952
-
953
- /* Cleanup: detach CAWraps + free temp masked-snapshot buffers (setup
954
- has already copied indices into its own ALLOC). */
955
- for (i = 0; i < ca->ndim; i++) {
956
- if ( ci[i] ) {
957
- if ( ca_is_any_masked(ci[i]) ) {
958
- xfree(protos[i].indices);
959
- }
960
- ca_detach(ci[i]);
961
- }
1006
+ /* The index arrays are read with all of them attached, and building
1007
+ the view checks every index against the parent -- an index out of
1008
+ range raises there. So the reads and the build are a window body,
1009
+ which detaches the caller's index arrays however it ends. */
1010
+ {
1011
+ ca_grid_build_ctx_t c;
1012
+ char modes[CA_RANK_MAX + 1];
1013
+ memset(modes, 'r', (size_t) ca->ndim);
1014
+ modes[ca->ndim] = '\0';
1015
+ c.self = self;
1016
+ c.ca = ca;
1017
+ c.ci = ci;
1018
+ c.protos = protos;
1019
+ obj = ca_attach_window(ca->ndim, ci, modes, ca_grid_build_body,
1020
+ (VALUE) &c);
962
1021
  }
963
1022
 
964
1023
  return obj;
@@ -977,14 +1036,14 @@ rb_ca_grid_initialize_copy (VALUE self, VALUE other)
977
1036
  CAGrid *ca, *cs;
978
1037
 
979
1038
  TypedData_Get_Struct(self, CAGrid, &cagrid_data_type, ca);
1039
+ ca_check_uninitialized(ca);
980
1040
  TypedData_Get_Struct(other, CAGrid, &cagrid_data_type, cs);
981
1041
 
982
1042
  if ( ca_func[CA_OBJ_GRID].pool_init ) {
983
1043
  ca_array_pool_alloc(ca, CA_OBJ_GRID, cs->ndim);
984
1044
  }
985
- /* Share the source's axes buffer (CA_FLAG_SHARE_INDEX semantics:
986
- source CAGrid owns the lifetime; clone aliases it). */
987
- ca_grid_setup(ca, cs->parent, cs->ndim, cs->axes, 1);
1045
+ /* Copy the axes: the source may be collected before the copy. */
1046
+ ca_grid_setup(ca, cs->parent, cs->ndim, cs->axes, 0);
988
1047
 
989
1048
  return self;
990
1049
  }
@@ -1087,7 +1146,7 @@ rb_ca_grid_dispatch_attach_debug (VALUE self)
1087
1146
  TypedData_Get_Struct(self, CAGrid, &cagrid_data_type, ca);
1088
1147
  ca_grid_describe_axes(ca, desc, pdims);
1089
1148
 
1090
- ca_attach(ca->parent);
1149
+ ca_attach(ca->parent); /* window: nothing raises inside */
1091
1150
  buf = ca_axis_dispatch_attach(ca->parent, pdims, desc, ca->ndim, ca->bytes,
1092
1151
  ca->elements, NULL);
1093
1152
  ca_detach(ca->parent);
@@ -1118,11 +1177,10 @@ rb_ca_grid_dispatch_scatter_debug (VALUE self, VALUE in_str)
1118
1177
  ca_size_t pdims[CA_RANK_MAX];
1119
1178
  ca_grid_describe_axes(ca, desc, pdims);
1120
1179
 
1121
- ca_attach(ca->parent);
1180
+ ca_attach(ca->parent); /* window: nothing raises inside */
1122
1181
  ca_axis_dispatch_scatter(ca->parent, pdims, desc, ca->ndim, ca->bytes,
1123
1182
  ca->elements, RSTRING_PTR(in_str));
1124
- ca_sync(ca->parent);
1125
- ca_detach(ca->parent);
1183
+ ca_sync_detach(ca->parent);
1126
1184
  return Qnil;
1127
1185
  }
1128
1186
 
@@ -1145,11 +1203,10 @@ rb_ca_grid_dispatch_fill_value_debug (VALUE self, VALUE val_str)
1145
1203
  ca_size_t pdims[CA_RANK_MAX];
1146
1204
  ca_grid_describe_axes(ca, desc, pdims);
1147
1205
 
1148
- ca_attach(ca->parent);
1206
+ ca_attach(ca->parent); /* window: nothing raises inside */
1149
1207
  ca_axis_dispatch_fill_value(ca->parent, pdims, desc, ca->ndim, ca->bytes,
1150
1208
  ca->elements, RSTRING_PTR(val_str));
1151
- ca_sync(ca->parent);
1152
- ca_detach(ca->parent);
1209
+ ca_sync_detach(ca->parent);
1153
1210
  return Qnil;
1154
1211
  }
1155
1212
  #endif /* CARRAY_DEV_BUILD */