carray 3.0.2 → 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 (218) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +304 -0
  3. data/README.md +3 -4
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +225 -0
  6. data/ext/ca_axis_group.c +177 -99
  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 +66 -71
  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 +663 -214
  14. data/ext/ca_kernel_iterator.h +231 -167
  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 +132 -22
  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 +1 -0
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +96 -25
  25. data/ext/ca_obj_face.c +406 -64
  26. data/ext/ca_obj_face.h +92 -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 +21 -21
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +189 -107
  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 +543 -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 +47 -49
  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 -118
  46. data/ext/ca_obj_stride.c +195 -34
  47. data/ext/ca_obj_string.c +17 -18
  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 +149 -27
  54. data/ext/ca_op_ipower.c +24 -11
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_sort_kernels.h +70 -0
  58. data/ext/ca_sweep_engine.c +102 -79
  59. data/ext/ca_sweep_engine.h +7 -20
  60. data/ext/ca_triop_dispatch.c +4 -1
  61. data/ext/ca_triop_dispatch.h +5 -2
  62. data/ext/caframe_csv_reader.c +463 -0
  63. data/ext/carray.h +70 -27
  64. data/ext/carray_access.c +455 -211
  65. data/ext/carray_address_basis.c +177 -36
  66. data/ext/carray_attribute.c +45 -3
  67. data/ext/carray_bincount.c +32 -2
  68. data/ext/carray_broadcast.c +46 -14
  69. data/ext/carray_call_cfunc.c +0 -28
  70. data/ext/carray_cast.c +1444 -209
  71. data/ext/carray_cast_func.rb +34 -21
  72. data/ext/carray_conversion.c +197 -73
  73. data/ext/carray_copy.c +32 -11
  74. data/ext/carray_core.c +514 -122
  75. data/ext/carray_count.c +140 -87
  76. data/ext/carray_element.c +18 -27
  77. data/ext/carray_factorize.c +569 -277
  78. data/ext/carray_generate.c +76 -40
  79. data/ext/carray_histogram.c +152 -94
  80. data/ext/carray_hold.c +2 -1
  81. data/ext/carray_index_classifier.c +63 -96
  82. data/ext/carray_internal.h +385 -3
  83. data/ext/carray_lazy.c +834 -79
  84. data/ext/carray_loop.c +81 -65
  85. data/ext/carray_mask.c +682 -316
  86. data/ext/carray_math_kernel.h +1 -0
  87. data/ext/carray_median_percentile.c +221 -76
  88. data/ext/carray_memory_view.c +254 -248
  89. data/ext/carray_operator.c +1089 -359
  90. data/ext/carray_order.c +133 -69
  91. data/ext/carray_partition.c +102 -56
  92. data/ext/carray_random.c +273 -239
  93. data/ext/carray_scatter.c +308 -65
  94. data/ext/carray_segment.c +257 -0
  95. data/ext/carray_slab.c +170 -70
  96. data/ext/carray_sort.c +215 -218
  97. data/ext/carray_sort_kernel.c +8 -1
  98. data/ext/carray_struct.c +99 -21
  99. data/ext/carray_test.c +167 -64
  100. data/ext/carray_time_text.c +1182 -0
  101. data/ext/carray_utils.c +363 -98
  102. data/ext/extconf.rb +27 -2
  103. data/ext/mk_call_cfunc.rb +0 -2
  104. data/ext/mk_pow5_table.rb +35 -0
  105. data/ext/mkkernel.rb +1076 -846
  106. data/ext/ruby_carray.c +7 -1
  107. data/ext/version.h +4 -4
  108. data/ext/version.rb +4 -2
  109. data/lib/carray/attribute.rb +39 -0
  110. data/lib/carray/autoload_carray.rb +19 -0
  111. data/lib/carray/autoload_method_extension.rb +6 -0
  112. data/lib/carray/axis_group.rb +174 -26
  113. data/lib/carray/basics.rb +91 -25
  114. data/lib/carray/bincount_nd.rb +6 -0
  115. data/lib/carray/block_iterator.rb +118 -48
  116. data/lib/carray/boolean_reduce.rb +21 -29
  117. data/lib/carray/categorical.rb +94 -26
  118. data/lib/carray/categorical_iterator.rb +333 -826
  119. data/lib/carray/complex.rb +36 -29
  120. data/lib/carray/conditional.rb +94 -7
  121. data/lib/carray/const_string.rb +46 -0
  122. data/lib/carray/frame/concat.rb +157 -6
  123. data/lib/carray/frame/convert.rb +13 -7
  124. data/lib/carray/frame/csv_parser.rb +589 -82
  125. data/lib/carray/frame/describe.rb +79 -0
  126. data/lib/carray/frame/frame.rb +124 -25
  127. data/lib/carray/frame/group.rb +189 -63
  128. data/lib/carray/frame/io.rb +412 -72
  129. data/lib/carray/frame/join.rb +134 -46
  130. data/lib/carray/frame/records.rb +37 -16
  131. data/lib/carray/frame/reshape.rb +448 -0
  132. data/lib/carray/frame/sort.rb +26 -2
  133. data/lib/carray/frame/verbs.rb +715 -48
  134. data/lib/carray/frame.rb +2 -0
  135. data/lib/carray/fuse_source.rb +111 -2
  136. data/lib/carray/fusion.rb +229 -38
  137. data/lib/carray/inspect.rb +29 -11
  138. data/lib/carray/iterator.rb +14 -2
  139. data/lib/carray/lazy.rb +54 -30
  140. data/lib/carray/mask_gap_fill.rb +66 -52
  141. data/lib/carray/math.rb +32 -19
  142. data/lib/carray/meld_reduce.rb +40 -7
  143. data/lib/carray/methods/align_addr.rb +8 -4
  144. data/lib/carray/methods/bincount.rb +2 -2
  145. data/lib/carray/methods/bit_string.rb +14 -3
  146. data/lib/carray/methods/composition.rb +16 -10
  147. data/lib/carray/methods/factorize.rb +2 -2
  148. data/lib/carray/methods/gather_nd.rb +13 -2
  149. data/lib/carray/methods/insert_block.rb +9 -14
  150. data/lib/carray/methods/is_in.rb +117 -4
  151. data/lib/carray/methods/join.rb +1 -1
  152. data/lib/carray/methods/locate_addr.rb +177 -36
  153. data/lib/carray/methods/mode.rb +18 -1
  154. data/lib/carray/methods/repeat.rb +1 -20
  155. data/lib/carray/methods/resize.rb +21 -23
  156. data/lib/carray/methods/snap.rb +34 -12
  157. data/lib/carray/methods/unique.rb +11 -2
  158. data/lib/carray/record_order.rb +208 -0
  159. data/lib/carray/runtime.rb +14 -11
  160. data/lib/carray/segment_iterator.rb +990 -0
  161. data/lib/carray/serialize.rb +197 -27
  162. data/lib/carray/slab_iterator.rb +51 -27
  163. data/lib/carray/stack.rb +10 -4
  164. data/lib/carray/string_operation_extension.rb +4 -3
  165. data/lib/carray/struct.rb +142 -51
  166. data/lib/carray/struct_builder.rb +110 -14
  167. data/lib/carray/table.rb +2 -2
  168. data/lib/carray/time.rb +517 -103
  169. data/lib/carray/window_iterator.rb +127 -72
  170. data/lib/carray.rb +2 -2
  171. data/yard-stubs/ca_obj_array.rb +4 -4
  172. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  173. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  174. data/yard-stubs/ca_obj_fake.rb +1 -1
  175. data/yard-stubs/ca_obj_field.rb +1 -1
  176. data/yard-stubs/ca_obj_refer.rb +3 -3
  177. data/yard-stubs/ca_obj_roll.rb +0 -1
  178. data/yard-stubs/ca_obj_stride.rb +10 -7
  179. data/yard-stubs/ca_obj_transpose.rb +1 -1
  180. data/yard-stubs/ca_obj_window.rb +1 -2
  181. data/yard-stubs/carray_access.rb +5 -4
  182. data/yard-stubs/carray_broadcast.rb +1 -1
  183. data/yard-stubs/carray_cast.rb +78 -43
  184. data/yard-stubs/carray_conversion.rb +13 -1
  185. data/yard-stubs/carray_copy.rb +8 -3
  186. data/yard-stubs/carray_core.rb +3 -3
  187. data/yard-stubs/carray_count.rb +9 -0
  188. data/yard-stubs/carray_lazy.rb +5 -1
  189. data/yard-stubs/carray_loop.rb +4 -1
  190. data/yard-stubs/carray_mask.rb +34 -10
  191. data/yard-stubs/carray_math.rb +25 -13
  192. data/yard-stubs/carray_median_percentile.rb +10 -6
  193. data/yard-stubs/carray_order.rb +34 -13
  194. data/yard-stubs/carray_scatter.rb +10 -3
  195. data/yard-stubs/carray_segment.rb +72 -0
  196. data/yard-stubs/carray_slab.rb +2 -1
  197. data/yard-stubs/carray_sort.rb +43 -3
  198. data/yard-stubs/carray_test.rb +10 -0
  199. data/yard-stubs/carray_utils.rb +0 -26
  200. metadata +11 -19
  201. data/ext/ca_for_each_element.h +0 -239
  202. data/ext/carray_build_flags.h +0 -3
  203. data/ext/carray_config.h +0 -28
  204. data/ext/carray_kernels_bincmp.c +0 -4446
  205. data/ext/carray_kernels_binop.c +0 -11001
  206. data/ext/carray_kernels_init.c +0 -1131
  207. data/ext/carray_kernels_map.c +0 -3467
  208. data/ext/carray_kernels_moncmp.c +0 -2097
  209. data/ext/carray_kernels_monop.c +0 -18313
  210. data/ext/carray_kernels_reduce_aggregate.c +0 -26005
  211. data/ext/carray_kernels_reduce_boolean.c +0 -330
  212. data/ext/carray_kernels_reduce_cumulative.c +0 -14862
  213. data/ext/carray_kernels_reduce_extreme.c +0 -17494
  214. data/ext/carray_kernels_reduce_variance.c +0 -3910
  215. data/ext/carray_kernels_scan.c +0 -3693
  216. data/ext/carray_kernels_search.c +0 -32218
  217. data/ext/carray_kernels_sort.c +0 -10626
  218. data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_obj_stride.c CHANGED
@@ -20,6 +20,7 @@
20
20
  ---------------------------------------------------------------------------- */
21
21
 
22
22
  #include "carray.h"
23
+ #include "carray_internal.h" /* ca_axis_integer */
23
24
  #include "ca_iter_substrate.h"
24
25
  #include "ca_obj_face.h" /* ca_is_face, used by the compose-fold walk */
25
26
 
@@ -104,13 +105,18 @@ ca_stride_setup (CAStride *ca, int8_t obj_type, CArray *parent,
104
105
  if (ndim < 0 || ndim > CA_RANK_MAX) {
105
106
  rb_raise(rb_eArgError, "invalid ndim %d", (int) ndim);
106
107
  }
107
- elements = 1;
108
108
  for (i = 0; i < ndim; i++) {
109
109
  if (dim[i] < 0) {
110
110
  rb_raise(rb_eIndexError,
111
111
  "invalid size for %i-th dimension (negative)", i);
112
112
  }
113
- elements *= dim[i];
113
+ }
114
+ elements = ca_shape_elements(ndim, dim, bytes);
115
+
116
+ /* ca == NULL asks for the checks above only, so that a constructor can
117
+ run them before it allocates. */
118
+ if ( ca == NULL ) {
119
+ return 0;
114
120
  }
115
121
 
116
122
  ca->obj_type = obj_type;
@@ -151,7 +157,10 @@ ca_stride_new (int8_t obj_type, CArray *parent,
151
157
  int8_t ndim, ca_size_t *dim,
152
158
  ca_size_t *strides, ca_size_t base_offset)
153
159
  {
154
- CAStride *ca = (CAStride *) ca_array_alloc(obj_type, ndim);
160
+ CAStride *ca;
161
+ ca_stride_setup(NULL, obj_type, parent,
162
+ data_type, bytes, ndim, dim, strides, base_offset);
163
+ ca = (CAStride *) ca_array_alloc(obj_type, ndim);
155
164
  ca_stride_setup(ca, obj_type, parent,
156
165
  data_type, bytes, ndim, dim, strides, base_offset);
157
166
  return ca;
@@ -292,6 +301,38 @@ ca_stride_compose_through (CAStride *leaf, CAStride *parent,
292
301
  out_strides[k] = composed;
293
302
  }
294
303
 
304
+ /* A leaf cell wider than the remainder of its first parent element
305
+ (CARefer reinterpreting two float64 as one complex128) covers several
306
+ consecutive parent elements, and the folded access reads the cell as
307
+ one run of bytes from out_base. That is only true when those parent
308
+ elements are adjacent in parent->parent's memory as well: every cell
309
+ must fit inside the parent's trailing row-major contiguous block.
310
+ Cell starts are flat0 + sum idx[k]*advance[k], so their residues
311
+ modulo the block size C step by g = gcd(C, advance...); every cell
312
+ fits when (flat0 mod g) + span <= g. */
313
+ if ( sub_byte + leaf->bytes > parent->bytes ) {
314
+ ca_size_t span = (sub_byte + leaf->bytes + parent->bytes - 1)
315
+ / parent->bytes;
316
+ ca_size_t block = 1;
317
+ ca_size_t g, flat0 = leaf->base_offset / parent->bytes;
318
+ if ( parent->ndim > 0
319
+ && parent->strides[parent->ndim - 1] == parent->bytes ) {
320
+ block = parent->dim[parent->ndim - 1];
321
+ for (m = parent->ndim - 2; m >= 0; m--) {
322
+ if ( parent->strides[m] != parent->strides[m + 1] * parent->dim[m + 1] )
323
+ break;
324
+ block *= parent->dim[m];
325
+ }
326
+ }
327
+ g = block;
328
+ for (k = 0; k < leaf->ndim; k++) {
329
+ ca_size_t a = leaf->strides[k] / parent->bytes;
330
+ if ( a < 0 ) a = -a;
331
+ while ( a != 0 ) { ca_size_t r = g % a; g = a; a = r; }
332
+ }
333
+ if ( g == 0 || (flat0 % g) + span > g ) return 0;
334
+ }
335
+
295
336
  return 1;
296
337
  }
297
338
 
@@ -512,19 +553,32 @@ ca_stride_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
512
553
  ca_xfer_index(ca->parent, pidx, data, dir);
513
554
  }
514
555
  else {
515
- char buf[64]; /* parent cell width <= 16 in practice */
516
- char *scratch = (pbytes <= (ca_size_t) sizeof(buf)) ? buf : xmalloc(pbytes);
556
+ /* Byte-mismatched reinterpret. The cell covers the parent elements
557
+ from off / pbytes through the one holding its last byte: one for a
558
+ narrower cell (CAField .real / .imag), several for a wider one
559
+ (CARefer reading two float64 as one complex128). Read all of
560
+ them; a store writes back all of them.
561
+ ALLOCV: the parent's fetch/store can raise (a CAObject parent runs
562
+ Ruby), and a raise must not leak the scratch. */
563
+ volatile VALUE holder;
564
+ ca_size_t addr = off / pbytes;
565
+ ca_size_t sub = off % pbytes;
566
+ ca_size_t span = (sub + ca->bytes + pbytes - 1) / pbytes;
567
+ ca_size_t i;
568
+ char *scratch = ALLOCV_N(char, holder, span * pbytes);
569
+ for (i = 0; i < span; i++) {
570
+ ca_fetch_addr(ca->parent, addr + i, scratch + i * pbytes);
571
+ }
517
572
  if (dir == CA_XFER_GET) {
518
- ca_fetch_addr(ca->parent, off / pbytes, scratch);
519
- memcpy(data, scratch + (off % pbytes), ca->bytes);
573
+ memcpy(data, scratch + sub, ca->bytes);
520
574
  }
521
575
  else {
522
- /* read-modify-write the parent cell for sub-byte reinterpret */
523
- ca_fetch_addr(ca->parent, off / pbytes, scratch);
524
- memcpy(scratch + (off % pbytes), data, ca->bytes);
525
- ca_store_addr(ca->parent, off / pbytes, scratch);
576
+ memcpy(scratch + sub, data, ca->bytes);
577
+ for (i = 0; i < span; i++) {
578
+ ca_store_addr(ca->parent, addr + i, scratch + i * pbytes);
579
+ }
526
580
  }
527
- if (scratch != buf) xfree(scratch);
581
+ ALLOCV_END(holder);
528
582
  }
529
583
  }
530
584
  }
@@ -656,6 +710,7 @@ static void
656
710
  ca_stride_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
657
711
  ca_size_t *strides, void *data, int dir)
658
712
  {
713
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
659
714
  CAStride *ca = (CAStride *) ap;
660
715
  CArray *root;
661
716
  ca_size_t composed_strides[CA_RANK_MAX];
@@ -736,13 +791,45 @@ ca_stride_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
736
791
  }
737
792
  }
738
793
 
794
+ /* A reshape over a 1-D cold root (ndim != root->ndim): the request has no
795
+ box in the root's single axis, but the root cells it touches lie in one
796
+ flat span. Ask the root for that span once and walk the request over
797
+ it, as xfer_all does for the whole view. A PUT reads the span first so
798
+ the cells between the requested ones go back unchanged. */
799
+ if (aligned && !root->ptr && ca_func[root->obj_type].xfer_stride
800
+ && ca->bytes == root->bytes && root->ndim == 1
801
+ && root_base % root->bytes == 0) {
802
+ ca_size_t span_lo = root_base;
803
+ ca_size_t span_hi = root_base + ca->bytes;
804
+ for (k = 0; k < ndim; k++) {
805
+ ca_size_t ext = (counts[k] - 1) * root_stride[k];
806
+ if ( root_stride[k] >= 0 ) span_hi += ext;
807
+ else span_lo += ext;
808
+ }
809
+ if ( span_lo >= 0 && span_hi <= root->elements * root->bytes ) {
810
+ volatile VALUE holder;
811
+ ca_size_t rlo = span_lo / root->bytes;
812
+ ca_size_t rcount = (span_hi - span_lo) / root->bytes;
813
+ ca_size_t rstep = root->bytes;
814
+ char *scratch = ALLOCV_N(char, holder, rcount * root->bytes);
815
+ ca_xfer_stride(root, &rlo, &rcount, &rstep, scratch, CA_XFER_GET);
816
+ ca_xfer_strided_walk(scratch + (root_base - span_lo), ca->bytes, ndim,
817
+ counts, root_stride, d, dir);
818
+ if ( dir == CA_XFER_PUT ) {
819
+ ca_xfer_stride(root, &rlo, &rcount, &rstep, scratch, CA_XFER_PUT);
820
+ }
821
+ ALLOCV_END(holder);
822
+ return;
823
+ }
824
+ }
825
+
739
826
  /* Per-cell fallback (correct, no whole-view attach): byte-mismatch
740
827
  reinterpret (CAField), a region that is not a box over our axes (a
741
828
  transposed request onto a degenerate axis, a flat index over several
742
- axes), or a cold non-entity root the branch above could not hand a
743
- region to (its ndim differs from the view's -- e.g. a reshape over a
744
- boundary -- or it has no region slot). ca_stride_func_xfer_index
745
- composes one hop and delegates to the parent. */
829
+ axes), or a cold non-entity root the branches above could not hand a
830
+ region to (a reshape over a root of two or more axes, or one with no
831
+ region slot). ca_stride_func_xfer_index composes one hop and
832
+ delegates to the parent. */
746
833
  if (!aligned || !root->ptr) {
747
834
  ca_size_t idx[CA_RANK_MAX], doff = 0;
748
835
  for (k = 0; k < ndim; k++) idx[k] = 0;
@@ -942,6 +1029,8 @@ ca_stride_func_fill_stride (void *ap, ca_size_t base, int8_t ndim,
942
1029
  }
943
1030
 
944
1031
  extern int ca_stride_is_contiguous (CAStride *ca); /* defined below; non-static for Tier A */
1032
+ static int ca_layout_is_contiguous (int8_t ndim, const ca_size_t *dim,
1033
+ const ca_size_t *strides, ca_size_t bytes);
945
1034
 
946
1035
  /* Alias fast path:
947
1036
  When the view's strides describe a contiguous row-major run, the
@@ -1013,6 +1102,27 @@ ca_root_lends_no_memory (void *ap)
1013
1102
  return ca_func[root->obj_type].xfer_stride != NULL;
1014
1103
  }
1015
1104
 
1105
+ /* The same question for the parent of a view that is not itself in the
1106
+ CAStride family (CAGrid, ...): whether the array its cells come from --
1107
+ the parent, or the root a CAStride parent folds to -- has no memory to
1108
+ lend. Like ca_root_lends_no_memory it asks only what those arrays are,
1109
+ so the lifecycle slots can rely on getting the same answer from attach
1110
+ to detach. */
1111
+ int
1112
+ ca_parent_lends_no_memory (void *ap)
1113
+ {
1114
+ CArray *parent = (CArray *) ap;
1115
+
1116
+ if ( ca_is_stride_family(parent) ) {
1117
+ CArray *root;
1118
+ ca_size_t cs[CA_RANK_MAX];
1119
+ ca_size_t base;
1120
+ ca_stride_compose_to_root((CAStride *) parent, &root, cs, &base);
1121
+ return ca_root_lends_no_memory(root);
1122
+ }
1123
+ return ca_root_lends_no_memory(parent);
1124
+ }
1125
+
1016
1126
  /* ca_attach_is_alias asks the same question from carray_core.c: a view whose
1017
1127
  attach owns its buffer does not alias its parent, so writes through
1018
1128
  ca->ptr need a ca_sync and callers must not assume otherwise. */
@@ -1032,7 +1142,16 @@ ca_stride_attach_aliases_root (CAStride *ca)
1032
1142
  return 1;
1033
1143
  }
1034
1144
  ca_stride_compose_to_root(ca, &root, composed_strides, &composed_base);
1035
- return !ca_root_lends_no_memory(root);
1145
+ /* The same test ca_stride_func_attach makes, and then the same question of
1146
+ the fold boundary. The leaf's own strides are in its parent's address
1147
+ space -- a block over a flip is contiguous there and not in the root --
1148
+ and a boundary that is itself a CAStride (a reshape over a transpose
1149
+ stops the fold) is one whose attach may build a buffer of its own, which
1150
+ this view would then alias without reaching the memory below it. */
1151
+ return !ca_root_lends_no_memory(root)
1152
+ && ca_layout_is_contiguous(ca->ndim, ca->dim, composed_strides,
1153
+ ca->bytes)
1154
+ && ca_attach_is_alias(root);
1036
1155
  }
1037
1156
 
1038
1157
  static void
@@ -1324,6 +1443,34 @@ ca_stride_func_xfer_all (void *ap, void *data, int dir)
1324
1443
  return;
1325
1444
  }
1326
1445
 
1446
+ /* A request the bridges above could not express as a region goes to the
1447
+ root as the list of its cells. A write never makes a round trip of
1448
+ the whole root: a root that repeats its cells (CATile) would have the
1449
+ stale copies the caller never wrote land after the written ones, and a
1450
+ root that converts on the way would bring the unwritten cells back
1451
+ changed. A read does not make the root produce cells it was not asked
1452
+ for, unless it is asked for as many as it has. The root's addresses
1453
+ are whole elements here, as in the region hand-off above. */
1454
+ if ( ( dir == CA_XFER_PUT || ca->elements < root->elements )
1455
+ && ca->bytes == root->bytes && composed_base % root->bytes == 0 ) {
1456
+ volatile VALUE holder;
1457
+ ca_size_t *addrs = ALLOCV_N(ca_size_t, holder, ca->elements);
1458
+ ca_size_t idx[CA_RANK_MAX], n = 0;
1459
+ int8_t k;
1460
+ for (k = 0; k < ca->ndim; k++) idx[k] = 0;
1461
+ while (1) {
1462
+ ca_size_t off = composed_base;
1463
+ for (k = 0; k < ca->ndim; k++) off += idx[k] * composed_strides[k];
1464
+ addrs[n++] = off / root->bytes;
1465
+ k = ca->ndim - 1;
1466
+ while (k >= 0) { if (++idx[k] < ca->dim[k]) break; idx[k] = 0; k--; }
1467
+ if (k < 0) break;
1468
+ }
1469
+ ca_xfer_addrs(root, n, addrs, ptr, dir);
1470
+ ALLOCV_END(holder);
1471
+ return;
1472
+ }
1473
+
1327
1474
  /* Cold root without an xfer_stride slot, or an ndim mismatch the bridges
1328
1475
  above could not express: materialise the root into scratch via
1329
1476
  ca_xfer_all and run the direct strided gather/scatter against that.
@@ -1342,11 +1489,14 @@ ca_stride_func_xfer_all (void *ap, void *data, int dir)
1342
1489
  ca_stride_xfer_with_layout(ca, (dir == CA_XFER_PUT) ? 1 : 0,
1343
1490
  root->ptr + composed_base, composed_strides);
1344
1491
  ca->ptr = ptr0;
1492
+ /* Put root->ptr back before the PUT: the PUT can raise (a lazy
1493
+ backing's sync failing), and the scratch is gone once this frame
1494
+ is. */
1495
+ root->ptr = root_ptr_saved;
1345
1496
  if ( dir == CA_XFER_PUT ) {
1346
1497
  /* Push back scratch (modified by scatter) to root. */
1347
1498
  ca_xfer_all(root, root_scratch, CA_XFER_PUT);
1348
1499
  }
1349
- root->ptr = root_ptr_saved;
1350
1500
  ALLOCV_END(holder);
1351
1501
  }
1352
1502
  }
@@ -1849,6 +1999,7 @@ rb_cs_initialize_copy (VALUE self, VALUE other)
1849
1999
  {
1850
2000
  CAStride *ca, *cs;
1851
2001
  TypedData_Get_Struct(self, CAStride, &castride_data_type, ca);
2002
+ ca_check_uninitialized(ca);
1852
2003
  TypedData_Get_Struct(other, CAStride, &castride_data_type, cs);
1853
2004
  /* Pool framework: self was created by rb_cs_s_allocate (= TypedData_Make_Struct),
1854
2005
  so ca->_pool is NULL. Wire up the pool before ca_stride_setup so the
@@ -1939,8 +2090,10 @@ rb_ca_as_strided (int argc, VALUE *argv, VALUE self)
1939
2090
  base_offset = NUM2SIZE(roffset);
1940
2091
  }
1941
2092
 
1942
- return rb_ca_stride_new(self, parent->data_type, parent->bytes,
1943
- ndim, shape, strides, base_offset);
2093
+ VALUE obj = rb_ca_stride_new(self, parent->data_type, parent->bytes,
2094
+ ndim, shape, strides, base_offset);
2095
+ CA_WRAPPER_LIFT(obj, self, parent);
2096
+ return obj;
1944
2097
  }
1945
2098
 
1946
2099
  /* sliding_windows(*window, step: nil) -- overlapping-window view over every
@@ -2051,8 +2204,10 @@ rb_ca_sliding_windows (int argc, VALUE *argv, VALUE self)
2051
2204
  outstrides[ndim + i] = parent_byte_stride[i];
2052
2205
  }
2053
2206
 
2054
- return rb_ca_stride_new(self, parent->data_type, parent->bytes,
2055
- (int8_t)(2 * ndim), outdim, outstrides, 0);
2207
+ VALUE obj = rb_ca_stride_new(self, parent->data_type, parent->bytes,
2208
+ (int8_t)(2 * ndim), outdim, outstrides, 0);
2209
+ CA_WRAPPER_LIFT(obj, self, parent);
2210
+ return obj;
2056
2211
  }
2057
2212
 
2058
2213
  /* unfold(*window, step: nil) -- sliding_windows over the leading `S` axes
@@ -2173,8 +2328,10 @@ rb_ca_unfold (int argc, VALUE *argv, VALUE self)
2173
2328
  outstrides[2 * nspatial + i] = parent_byte_stride[nspatial + i];
2174
2329
  }
2175
2330
 
2176
- return rb_ca_stride_new(self, parent->data_type, parent->bytes,
2177
- (int8_t) outrank, outdim, outstrides, 0);
2331
+ VALUE obj = rb_ca_stride_new(self, parent->data_type, parent->bytes,
2332
+ (int8_t) outrank, outdim, outstrides, 0);
2333
+ CA_WRAPPER_LIFT(obj, self, parent);
2334
+ return obj;
2178
2335
  }
2179
2336
 
2180
2337
  /* block_view(*block) -- non-overlapping tile view. Parent [d0..dN-1]
@@ -2258,8 +2415,12 @@ rb_ca_block_view (int argc, VALUE *argv, VALUE self)
2258
2415
  outstrides[ndim + i] = parent_byte_stride[i];
2259
2416
  }
2260
2417
 
2261
- return rb_ca_stride_new(self, parent->data_type, parent->bytes,
2262
- (int8_t)(2 * ndim), outdim, outstrides, 0);
2418
+ VALUE obj = rb_ca_stride_new(self, parent->data_type, parent->bytes,
2419
+ (int8_t)(2 * ndim), outdim, outstrides, 0);
2420
+ /* The Face stays on top, as for every view: a tile reduction over a
2421
+ bare block_view compared the Face's surface bytes. */
2422
+ CA_WRAPPER_LIFT(obj, self, parent);
2423
+ return obj;
2263
2424
  }
2264
2425
 
2265
2426
  /* defined in ca_obj_transpose.c */
@@ -2300,7 +2461,7 @@ rb_ca_dim_view (int argc, VALUE *argv, VALUE self)
2300
2461
  (int) n_iter, (int) ndim);
2301
2462
  }
2302
2463
  for (i = 0; i < n_iter; i++) {
2303
- iter_axes[i] = NUM2SIZE(RARRAY_AREF(aary, i));
2464
+ iter_axes[i] = ca_axis_integer(RARRAY_AREF(aary, i), NULL);
2304
2465
  }
2305
2466
  }
2306
2467
  else if (nargs >= 1) {
@@ -2311,7 +2472,7 @@ rb_ca_dim_view (int argc, VALUE *argv, VALUE self)
2311
2472
  }
2312
2473
  n_iter = (int8_t) nargs;
2313
2474
  for (i = 0; i < n_iter; i++) {
2314
- iter_axes[i] = NUM2SIZE(RARRAY_AREF(rposary, i));
2475
+ iter_axes[i] = ca_axis_integer(RARRAY_AREF(rposary, i), NULL);
2315
2476
  }
2316
2477
  }
2317
2478
  else {
@@ -2439,8 +2600,8 @@ rb_ca_flip (int argc, VALUE *argv, VALUE self)
2439
2600
 
2440
2601
  for (i = 0; i < ndim; i++) flip[i] = 0;
2441
2602
 
2442
- if (nargs == 0) {
2443
- /* No args: flip every axis. */
2603
+ if (nargs == 0 || (nargs == 1 && NIL_P(RARRAY_AREF(rposary, 0)))) {
2604
+ /* No args, or a lone nil: flip every axis. */
2444
2605
  for (i = 0; i < ndim; i++) flip[i] = 1;
2445
2606
  n_axes = ndim;
2446
2607
  }
@@ -2454,7 +2615,7 @@ rb_ca_flip (int argc, VALUE *argv, VALUE self)
2454
2615
  (int) n_axes, (int) ndim);
2455
2616
  }
2456
2617
  for (i = 0; i < n_axes; i++) {
2457
- axes[i] = NUM2SIZE(RARRAY_AREF(aary, i));
2618
+ axes[i] = ca_axis_integer(RARRAY_AREF(aary, i), NULL);
2458
2619
  }
2459
2620
  }
2460
2621
  else {
@@ -2465,7 +2626,7 @@ rb_ca_flip (int argc, VALUE *argv, VALUE self)
2465
2626
  }
2466
2627
  n_axes = (int8_t) nargs;
2467
2628
  for (i = 0; i < n_axes; i++) {
2468
- axes[i] = NUM2SIZE(RARRAY_AREF(rposary, i));
2629
+ axes[i] = ca_axis_integer(RARRAY_AREF(rposary, i), NULL);
2469
2630
  }
2470
2631
  }
2471
2632
 
@@ -2550,8 +2711,8 @@ rb_ca_diagonal (int argc, VALUE *argv, VALUE self)
2550
2711
  rb_raise(rb_eArgError,
2551
2712
  "diagonal: axis: must be an Array of 2 integers");
2552
2713
  }
2553
- ai = NUM2SIZE(RARRAY_AREF(raxis, 0));
2554
- aj = NUM2SIZE(RARRAY_AREF(raxis, 1));
2714
+ ai = ca_axis_integer(RARRAY_AREF(raxis, 0), NULL);
2715
+ aj = ca_axis_integer(RARRAY_AREF(raxis, 1), NULL);
2555
2716
  if (ai < 0) ai += ndim;
2556
2717
  if (aj < 0) aj += ndim;
2557
2718
  if (ai < 0 || ai >= ndim) {
data/ext/ca_obj_string.c CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  Surface data_type is CA_OBJECT (== storage): unlike the NonNumeric Faces
13
13
  (CATime etc.) there is no CA_FIXLEN gate. Per-cell fetch returns
14
- the stored String VALUE directly (no storage_to_scalar decode). Numeric
14
+ the stored String VALUE directly (no storage_to_element decode). Numeric
15
15
  dispatch lands on the :object kernels, so String-meaningful ops (+, sort
16
16
  via <=>) work and nonsensical ones raise at the Ruby method call.
17
17
 
@@ -20,6 +20,7 @@
20
20
  --------------------------------------------------------------------------- */
21
21
 
22
22
  #include "carray.h"
23
+ #include "carray_internal.h"
23
24
  #include "ca_obj_face.h"
24
25
 
25
26
  typedef struct {
@@ -88,6 +89,12 @@ ca_string_setup (CAString *ca, CArray *parent)
88
89
  "CAString requires object storage (parent.data_type != CA_OBJECT)");
89
90
  }
90
91
 
92
+ /* ca == NULL asks for the checks above only, so that a constructor can
93
+ run them before it allocates. */
94
+ if ( ca == NULL ) {
95
+ return 0;
96
+ }
97
+
91
98
  ca->obj_type = CA_OBJ_STRING;
92
99
  ca->data_type = CA_OBJECT;
93
100
  /* ORDERABLE + COMPARABLE, and both hold by construction: a storage cell
@@ -130,7 +137,9 @@ ca_string_setup (CAString *ca, CArray *parent)
130
137
  CAString *
131
138
  ca_string_new (CArray *parent)
132
139
  {
133
- CAString *ca = (CAString *) ca_array_alloc(CA_OBJ_STRING, parent->ndim);
140
+ CAString *ca;
141
+ ca_string_setup(NULL, parent);
142
+ ca = (CAString *) ca_array_alloc(CA_OBJ_STRING, parent->ndim);
134
143
  ca_string_setup(ca, parent);
135
144
  return ca;
136
145
  }
@@ -169,18 +178,6 @@ ca_string_func_allocate (void *ap)
169
178
  ca->ptr = ca->parent->ptr;
170
179
  }
171
180
 
172
- static void
173
- ca_string_func_create_mask (void *ap)
174
- {
175
- CAString *ca = (CAString *) ap;
176
- ca_update_mask(ca->parent);
177
- if ( ! ca->parent->mask ) {
178
- ca_create_mask(ca->parent);
179
- }
180
- ca->mask = (CArray *) ca_refer_new(ca->parent->mask,
181
- CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
182
- }
183
-
184
181
  ca_operation_function_t ca_string_func = {
185
182
  -1, /* CA_OBJ_STRING — filled by ca_install_obj_type */
186
183
  CA_VIEW_ARRAY,
@@ -191,7 +188,7 @@ ca_operation_function_t ca_string_func = {
191
188
  ca_face_sync,
192
189
  ca_face_detach,
193
190
  ca_face_fill_data,
194
- ca_string_func_create_mask,
191
+ ca_view_func_create_mask,
195
192
  ca_face_xfer_index,
196
193
  ca_face_xfer_addrs,
197
194
  NULL, /* fold_stride: identity Face is not foldable */
@@ -239,6 +236,7 @@ rb_ca_string_initialize_copy (VALUE self, VALUE other)
239
236
  {
240
237
  CAString *ca, *cs;
241
238
  TypedData_Get_Struct(self, CAString, &castring_data_type, ca);
239
+ ca_check_uninitialized(ca);
242
240
  TypedData_Get_Struct(other, CAString, &castring_data_type, cs);
243
241
  if ( ca_func[CA_OBJ_STRING].pool_init ) {
244
242
  ca_array_pool_alloc(ca, CA_OBJ_STRING, cs->parent->ndim);
@@ -268,7 +266,8 @@ Init_ca_obj_string (void)
268
266
  rb_ca_string_initialize_copy, 1);
269
267
  rb_define_singleton_method(rb_cCAString, "wrap", rb_ca_string_wrap_method, 1);
270
268
 
271
- /* VALUE storage is per-process, so the Face cannot be carried across
272
- multi-parent constructions (CAStack / Marshal / MemoryView). */
273
- ca_face_register_state_portable(CA_OBJ_STRING, 0);
269
+ /* A cell is the String itself, so the Face is the same over any parent:
270
+ CAStack / CAMeld / concatenate can carry it (unlike CAConstString, whose
271
+ cells point into one parent's buffer). */
272
+ ca_face_register_state_portable(CA_OBJ_STRING, 1);
274
273
  }
data/ext/ca_obj_tile.c CHANGED
@@ -16,6 +16,7 @@
16
16
  ---------------------------------------------------------------------------- */
17
17
 
18
18
  #include "carray.h"
19
+ #include "carray_internal.h"
19
20
  #include "ca_composite_dispatch.h"
20
21
  #include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE */
21
22
 
@@ -75,17 +76,24 @@ ca_tile_setup (CATile *ca, CArray *parent, ca_size_t *reps)
75
76
  ndim = parent->ndim;
76
77
  bytes = parent->bytes;
77
78
 
78
- elements = 1;
79
- for (i = 0; i < ndim; i++) {
80
- if ( reps[i] <= 0 ) {
81
- rb_raise(rb_eIndexError,
82
- "invalid reps for %d-th dimension (must be positive)", i);
83
- }
84
- if ( parent->dim[i] <= 0 ) {
85
- rb_raise(rb_eIndexError,
86
- "invalid parent dim for %d-th dimension", i);
79
+ {
80
+ ca_size_t tiled[CA_RANK_MAX];
81
+ for (i = 0; i < ndim; i++) {
82
+ if ( reps[i] <= 0 ) {
83
+ rb_raise(rb_eIndexError,
84
+ "invalid reps for %d-th dimension (must be positive)", i);
85
+ }
86
+ if ( __builtin_mul_overflow(parent->dim[i], reps[i], &tiled[i]) ) {
87
+ rb_raise(rb_eArgError, "too large byte length");
88
+ }
87
89
  }
88
- elements *= parent->dim[i] * reps[i];
90
+ elements = ca_shape_elements(ndim, tiled, bytes);
91
+ }
92
+
93
+ /* ca == NULL asks for the checks above only, so that a constructor can
94
+ run them before it allocates. */
95
+ if ( ca == NULL ) {
96
+ return 0;
89
97
  }
90
98
 
91
99
  ca->obj_type = CA_OBJ_TILE;
@@ -118,7 +126,9 @@ ca_tile_setup (CATile *ca, CArray *parent, ca_size_t *reps)
118
126
  CATile *
119
127
  ca_tile_new (CArray *parent, ca_size_t *reps)
120
128
  {
121
- CATile *ca = ALLOC(CATile);
129
+ CATile *ca;
130
+ ca_tile_setup(NULL, parent, reps);
131
+ ca = ALLOC(CATile);
122
132
  ca_tile_setup(ca, parent, reps);
123
133
  return ca;
124
134
  }
@@ -196,6 +206,7 @@ static void
196
206
  ca_tile_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
197
207
  ca_size_t *strides, void *data, int dir)
198
208
  {
209
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
199
210
  CATile *ca = (CATile *) ap;
200
211
  CArray *parent = ca->parent;
201
212
  int8_t ndim = ca->ndim;
@@ -445,10 +456,13 @@ ca_tile_func_xfer_all (void *ap, void *data, int dir)
445
456
  parent->ptr = parent_scratch;
446
457
  if ( dir == CA_XFER_GET ) ca_tile_attach_into(ca, (char *) data);
447
458
  else ca_tile_sync_from(ca, (char *) data);
459
+ /* Put parent->ptr back before the PUT: the PUT can raise (a lazy
460
+ backing's sync failing), and the scratch is gone once this
461
+ frame is. */
462
+ parent->ptr = parent_ptr_saved;
448
463
  if ( dir == CA_XFER_PUT ) {
449
464
  ca_xfer_all(parent, parent_scratch, CA_XFER_PUT);
450
465
  }
451
- parent->ptr = parent_ptr_saved;
452
466
  ALLOCV_END(holder);
453
467
  }
454
468
  }
@@ -466,10 +480,7 @@ static void
466
480
  ca_tile_func_create_mask (void *ap)
467
481
  {
468
482
  CATile *ca = (CATile *) ap;
469
- ca_update_mask(ca->parent);
470
- if ( ! ca->parent->mask ) {
471
- ca_create_mask(ca->parent);
472
- }
483
+ ca_create_mask(ca->parent);
473
484
  ca->mask = (CArray *) ca_tile_new(ca->parent->mask, ca->reps);
474
485
  }
475
486
 
@@ -571,11 +582,13 @@ rb_ca_tile_initialize_copy (VALUE self, VALUE other)
571
582
  {
572
583
  CATile *ca, *cs;
573
584
  TypedData_Get_Struct(self, CATile, &catile_data_type, ca);
585
+ ca_check_uninitialized(ca);
574
586
  TypedData_Get_Struct(other, CATile, &catile_data_type, cs);
575
587
  ca_tile_setup(ca, cs->parent, cs->reps);
576
588
  return self;
577
589
  }
578
590
 
591
+ #ifdef CARRAY_DEV_BUILD
579
592
  /* Debug-only accessor returning the tile descriptor as a Hash.
580
593
  Naming: leading underscore signals internal use. */
581
594
  static VALUE
@@ -597,6 +610,7 @@ rb_ca_tile_descriptor (VALUE self)
597
610
  rb_hash_aset(hash, ID2SYM(rb_intern("ndim")), INT2NUM(ca->ndim));
598
611
  return hash;
599
612
  }
613
+ #endif
600
614
 
601
615
  void
602
616
  Init_ca_obj_tile (void)
@@ -616,7 +630,9 @@ Init_ca_obj_tile (void)
616
630
  rb_define_method(rb_cCATile, "initialize_copy",
617
631
  rb_ca_tile_initialize_copy, 1);
618
632
 
633
+ #ifdef CARRAY_DEV_BUILD
619
634
  /* Debug-only descriptor accessor. */
620
635
  rb_define_method(rb_cCATile, "_tile_descriptor",
621
636
  rb_ca_tile_descriptor, 0);
637
+ #endif
622
638
  }