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_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;
@@ -836,6 +923,59 @@ ca_stride_region_axes (CAStride *ca, ca_size_t base, int8_t ndim,
836
923
  root in units root does not share, so there is no address to hand over
837
924
  and the per-cell descent stands in. */
838
925
 
926
+ static void
927
+ ca_stride_func_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
928
+ {
929
+ CAStride *ca = (CAStride *) ap;
930
+ CArray *root;
931
+ ca_size_t composed_strides[CA_RANK_MAX];
932
+ ca_size_t composed_base;
933
+ ca_size_t rbytes;
934
+ ca_size_t *paddrs;
935
+ ca_size_t i;
936
+ int8_t k;
937
+ int all_aligned = 1;
938
+ volatile VALUE holder;
939
+
940
+ /* Addresses name cells one by one, so unlike fill_stride there is nothing
941
+ here that only the whole extent can express: translate each view address
942
+ into the root's and hand the list down in one call. Without this the
943
+ region is still the only thing touched -- ca_fill_addrs_default sees to
944
+ that -- but it costs the parent one call per cell, which is the whole
945
+ difference on a backing where a call is a request. */
946
+ if ( n == 0 ) {
947
+ return;
948
+ }
949
+
950
+ ca_stride_compose_to_root(ca, &root, composed_strides, &composed_base);
951
+ rbytes = root->bytes;
952
+
953
+ if ( ca->bytes != rbytes ) {
954
+ ca_fill_addrs_default(ca, n, addrs, ptr);
955
+ return;
956
+ }
957
+
958
+ paddrs = ALLOCV_N(ca_size_t, holder, n);
959
+ for ( i = 0; i < n; i++ ) {
960
+ ca_size_t idx[CA_RANK_MAX];
961
+ ca_size_t off = composed_base;
962
+ ca_addr2index((CArray *) ca, addrs[i], idx);
963
+ for ( k = 0; k < ca->ndim; k++ ) {
964
+ off += idx[k] * composed_strides[k];
965
+ }
966
+ if ( off % rbytes != 0 ) { all_aligned = 0; break; }
967
+ paddrs[i] = off / rbytes;
968
+ }
969
+
970
+ if ( all_aligned ) {
971
+ ca_fill_addrs(root, n, paddrs, ptr);
972
+ }
973
+ else {
974
+ ca_fill_addrs_default(ca, n, addrs, ptr);
975
+ }
976
+ ALLOCV_END(holder);
977
+ }
978
+
839
979
  static void
840
980
  ca_stride_func_fill_stride (void *ap, ca_size_t base, int8_t ndim,
841
981
  ca_size_t *counts, ca_size_t *steps, void *ptr)
@@ -889,6 +1029,8 @@ ca_stride_func_fill_stride (void *ap, ca_size_t base, int8_t ndim,
889
1029
  }
890
1030
 
891
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);
892
1034
 
893
1035
  /* Alias fast path:
894
1036
  When the view's strides describe a contiguous row-major run, the
@@ -960,6 +1102,27 @@ ca_root_lends_no_memory (void *ap)
960
1102
  return ca_func[root->obj_type].xfer_stride != NULL;
961
1103
  }
962
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
+
963
1126
  /* ca_attach_is_alias asks the same question from carray_core.c: a view whose
964
1127
  attach owns its buffer does not alias its parent, so writes through
965
1128
  ca->ptr need a ca_sync and callers must not assume otherwise. */
@@ -979,7 +1142,16 @@ ca_stride_attach_aliases_root (CAStride *ca)
979
1142
  return 1;
980
1143
  }
981
1144
  ca_stride_compose_to_root(ca, &root, composed_strides, &composed_base);
982
- 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);
983
1155
  }
984
1156
 
985
1157
  static void
@@ -1003,6 +1175,15 @@ ca_stride_func_allocate (void *ap)
1003
1175
  }
1004
1176
  }
1005
1177
 
1178
+ /* Region request into the cold-root attach buffer; a lazy root can raise. */
1179
+ static VALUE
1180
+ ca_stride_cold_fill (VALUE arg)
1181
+ {
1182
+ void **args = (void **) arg;
1183
+ ca_copy_data((CArray *) args[0], (char *) args[1]);
1184
+ return Qnil;
1185
+ }
1186
+
1006
1187
  static void
1007
1188
  ca_stride_func_attach (void *ap)
1008
1189
  {
@@ -1018,7 +1199,15 @@ ca_stride_func_attach (void *ap)
1018
1199
  view with a live ptr is what makes the per-cell dispatchers bypass the
1019
1200
  transfer slots. */
1020
1201
  char *buf = xmalloc(ca_length(ca));
1021
- ca_copy_data(ca, buf); /* region request, root stays cold */
1202
+ void *args[2];
1203
+ int tag = 0;
1204
+ args[0] = ca;
1205
+ args[1] = buf;
1206
+ rb_protect(ca_stride_cold_fill, (VALUE) args, &tag); /* root stays cold */
1207
+ if (tag) {
1208
+ xfree(buf);
1209
+ rb_jump_tag(tag);
1210
+ }
1022
1211
  ca->ptr = buf;
1023
1212
  return;
1024
1213
  }
@@ -1254,6 +1443,34 @@ ca_stride_func_xfer_all (void *ap, void *data, int dir)
1254
1443
  return;
1255
1444
  }
1256
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
+
1257
1474
  /* Cold root without an xfer_stride slot, or an ndim mismatch the bridges
1258
1475
  above could not express: materialise the root into scratch via
1259
1476
  ca_xfer_all and run the direct strided gather/scatter against that.
@@ -1272,11 +1489,14 @@ ca_stride_func_xfer_all (void *ap, void *data, int dir)
1272
1489
  ca_stride_xfer_with_layout(ca, (dir == CA_XFER_PUT) ? 1 : 0,
1273
1490
  root->ptr + composed_base, composed_strides);
1274
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;
1275
1496
  if ( dir == CA_XFER_PUT ) {
1276
1497
  /* Push back scratch (modified by scatter) to root. */
1277
1498
  ca_xfer_all(root, root_scratch, CA_XFER_PUT);
1278
1499
  }
1279
- root->ptr = root_ptr_saved;
1280
1500
  ALLOCV_END(holder);
1281
1501
  }
1282
1502
  }
@@ -1483,6 +1703,7 @@ ca_operation_function_t ca_stride_func = {
1483
1703
  sizeof(CAStride), /* struct_size: pool framework */
1484
1704
  ca_stride_pool_bytes, /* pool_bytes */
1485
1705
  ca_stride_pool_init, /* pool_init */
1706
+ .fill_addrs = ca_stride_func_fill_addrs,
1486
1707
  .fill_stride = ca_stride_func_fill_stride,
1487
1708
  };
1488
1709
 
@@ -1778,6 +1999,7 @@ rb_cs_initialize_copy (VALUE self, VALUE other)
1778
1999
  {
1779
2000
  CAStride *ca, *cs;
1780
2001
  TypedData_Get_Struct(self, CAStride, &castride_data_type, ca);
2002
+ ca_check_uninitialized(ca);
1781
2003
  TypedData_Get_Struct(other, CAStride, &castride_data_type, cs);
1782
2004
  /* Pool framework: self was created by rb_cs_s_allocate (= TypedData_Make_Struct),
1783
2005
  so ca->_pool is NULL. Wire up the pool before ca_stride_setup so the
@@ -1868,8 +2090,10 @@ rb_ca_as_strided (int argc, VALUE *argv, VALUE self)
1868
2090
  base_offset = NUM2SIZE(roffset);
1869
2091
  }
1870
2092
 
1871
- return rb_ca_stride_new(self, parent->data_type, parent->bytes,
1872
- 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;
1873
2097
  }
1874
2098
 
1875
2099
  /* sliding_windows(*window, step: nil) -- overlapping-window view over every
@@ -1980,8 +2204,10 @@ rb_ca_sliding_windows (int argc, VALUE *argv, VALUE self)
1980
2204
  outstrides[ndim + i] = parent_byte_stride[i];
1981
2205
  }
1982
2206
 
1983
- return rb_ca_stride_new(self, parent->data_type, parent->bytes,
1984
- (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;
1985
2211
  }
1986
2212
 
1987
2213
  /* unfold(*window, step: nil) -- sliding_windows over the leading `S` axes
@@ -2102,8 +2328,10 @@ rb_ca_unfold (int argc, VALUE *argv, VALUE self)
2102
2328
  outstrides[2 * nspatial + i] = parent_byte_stride[nspatial + i];
2103
2329
  }
2104
2330
 
2105
- return rb_ca_stride_new(self, parent->data_type, parent->bytes,
2106
- (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;
2107
2335
  }
2108
2336
 
2109
2337
  /* block_view(*block) -- non-overlapping tile view. Parent [d0..dN-1]
@@ -2187,8 +2415,12 @@ rb_ca_block_view (int argc, VALUE *argv, VALUE self)
2187
2415
  outstrides[ndim + i] = parent_byte_stride[i];
2188
2416
  }
2189
2417
 
2190
- return rb_ca_stride_new(self, parent->data_type, parent->bytes,
2191
- (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;
2192
2424
  }
2193
2425
 
2194
2426
  /* defined in ca_obj_transpose.c */
@@ -2229,7 +2461,7 @@ rb_ca_dim_view (int argc, VALUE *argv, VALUE self)
2229
2461
  (int) n_iter, (int) ndim);
2230
2462
  }
2231
2463
  for (i = 0; i < n_iter; i++) {
2232
- iter_axes[i] = NUM2SIZE(RARRAY_AREF(aary, i));
2464
+ iter_axes[i] = ca_axis_integer(RARRAY_AREF(aary, i), NULL);
2233
2465
  }
2234
2466
  }
2235
2467
  else if (nargs >= 1) {
@@ -2240,7 +2472,7 @@ rb_ca_dim_view (int argc, VALUE *argv, VALUE self)
2240
2472
  }
2241
2473
  n_iter = (int8_t) nargs;
2242
2474
  for (i = 0; i < n_iter; i++) {
2243
- iter_axes[i] = NUM2SIZE(RARRAY_AREF(rposary, i));
2475
+ iter_axes[i] = ca_axis_integer(RARRAY_AREF(rposary, i), NULL);
2244
2476
  }
2245
2477
  }
2246
2478
  else {
@@ -2368,8 +2600,8 @@ rb_ca_flip (int argc, VALUE *argv, VALUE self)
2368
2600
 
2369
2601
  for (i = 0; i < ndim; i++) flip[i] = 0;
2370
2602
 
2371
- if (nargs == 0) {
2372
- /* 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. */
2373
2605
  for (i = 0; i < ndim; i++) flip[i] = 1;
2374
2606
  n_axes = ndim;
2375
2607
  }
@@ -2383,7 +2615,7 @@ rb_ca_flip (int argc, VALUE *argv, VALUE self)
2383
2615
  (int) n_axes, (int) ndim);
2384
2616
  }
2385
2617
  for (i = 0; i < n_axes; i++) {
2386
- axes[i] = NUM2SIZE(RARRAY_AREF(aary, i));
2618
+ axes[i] = ca_axis_integer(RARRAY_AREF(aary, i), NULL);
2387
2619
  }
2388
2620
  }
2389
2621
  else {
@@ -2394,7 +2626,7 @@ rb_ca_flip (int argc, VALUE *argv, VALUE self)
2394
2626
  }
2395
2627
  n_axes = (int8_t) nargs;
2396
2628
  for (i = 0; i < n_axes; i++) {
2397
- axes[i] = NUM2SIZE(RARRAY_AREF(rposary, i));
2629
+ axes[i] = ca_axis_integer(RARRAY_AREF(rposary, i), NULL);
2398
2630
  }
2399
2631
  }
2400
2632
 
@@ -2479,8 +2711,8 @@ rb_ca_diagonal (int argc, VALUE *argv, VALUE self)
2479
2711
  rb_raise(rb_eArgError,
2480
2712
  "diagonal: axis: must be an Array of 2 integers");
2481
2713
  }
2482
- ai = NUM2SIZE(RARRAY_AREF(raxis, 0));
2483
- 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);
2484
2716
  if (ai < 0) ai += ndim;
2485
2717
  if (aj < 0) aj += ndim;
2486
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,12 +89,22 @@ 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
- /* ORDERABLE: object storage sorts by <=> (= String order on the surface),
94
- so the sort family may descend to storage. COMPARABLE is left off for
95
- now; ordered search (bsearch) is a later phase. */
96
- ca->flags = CA_FLAG_IS_FACE | CA_FLAG_FACE_ORDERABLE_STORAGE;
100
+ /* ORDERABLE + COMPARABLE, and both hold by construction: a storage cell
101
+ IS the Ruby String the surface shows, so storage order is surface
102
+ order and an external String compares against storage directly, with
103
+ nothing to reconcile. (A unit-bearing Face like CATime is the case
104
+ that has to stop at ORDERABLE; this one carries no unit.) */
105
+ ca->flags = CA_FLAG_IS_FACE
106
+ | CA_FLAG_FACE_ORDERABLE_STORAGE
107
+ | CA_FLAG_FACE_COMPARABLE_STORAGE;
97
108
  ca->ndim = parent->ndim;
98
109
  ca->bytes = sizeof(VALUE);
99
110
  ca->elements = parent->elements;
@@ -126,7 +137,9 @@ ca_string_setup (CAString *ca, CArray *parent)
126
137
  CAString *
127
138
  ca_string_new (CArray *parent)
128
139
  {
129
- 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);
130
143
  ca_string_setup(ca, parent);
131
144
  return ca;
132
145
  }
@@ -165,18 +178,6 @@ ca_string_func_allocate (void *ap)
165
178
  ca->ptr = ca->parent->ptr;
166
179
  }
167
180
 
168
- static void
169
- ca_string_func_create_mask (void *ap)
170
- {
171
- CAString *ca = (CAString *) ap;
172
- ca_update_mask(ca->parent);
173
- if ( ! ca->parent->mask ) {
174
- ca_create_mask(ca->parent);
175
- }
176
- ca->mask = (CArray *) ca_refer_new(ca->parent->mask,
177
- CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
178
- }
179
-
180
181
  ca_operation_function_t ca_string_func = {
181
182
  -1, /* CA_OBJ_STRING — filled by ca_install_obj_type */
182
183
  CA_VIEW_ARRAY,
@@ -187,7 +188,7 @@ ca_operation_function_t ca_string_func = {
187
188
  ca_face_sync,
188
189
  ca_face_detach,
189
190
  ca_face_fill_data,
190
- ca_string_func_create_mask,
191
+ ca_view_func_create_mask,
191
192
  ca_face_xfer_index,
192
193
  ca_face_xfer_addrs,
193
194
  NULL, /* fold_stride: identity Face is not foldable */
@@ -235,6 +236,7 @@ rb_ca_string_initialize_copy (VALUE self, VALUE other)
235
236
  {
236
237
  CAString *ca, *cs;
237
238
  TypedData_Get_Struct(self, CAString, &castring_data_type, ca);
239
+ ca_check_uninitialized(ca);
238
240
  TypedData_Get_Struct(other, CAString, &castring_data_type, cs);
239
241
  if ( ca_func[CA_OBJ_STRING].pool_init ) {
240
242
  ca_array_pool_alloc(ca, CA_OBJ_STRING, cs->parent->ndim);
@@ -264,7 +266,8 @@ Init_ca_obj_string (void)
264
266
  rb_ca_string_initialize_copy, 1);
265
267
  rb_define_singleton_method(rb_cCAString, "wrap", rb_ca_string_wrap_method, 1);
266
268
 
267
- /* VALUE storage is per-process, so the Face cannot be carried across
268
- multi-parent constructions (CAStack / Marshal / MemoryView). */
269
- 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);
270
273
  }