carray 3.0.0 → 3.0.2
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.
- checksums.yaml +4 -4
- data/.yardopts +2 -1
- data/CHANGELOG.md +845 -3
- data/{NEWS.md → CHANGELOG.v1.md} +1 -1
- data/README.md +33 -33
- data/carray.gemspec +12 -8
- data/ext/ca_axis_dispatch.c +33 -4
- data/ext/ca_axis_group.c +256 -114
- data/ext/ca_binop_dispatch.c +5 -6
- data/ext/ca_binop_dispatch.h +0 -7
- data/ext/ca_categorical_iterator.c +121 -67
- data/ext/ca_for_each_element.h +6 -8
- data/ext/ca_group_iter.c +1 -1
- data/ext/ca_kernel_iterator.c +386 -74
- data/ext/ca_kernel_iterator.h +145 -45
- data/ext/ca_obj_array.c +62 -20
- data/ext/ca_obj_bincmp.c +57 -27
- data/ext/ca_obj_binop.c +86 -30
- data/ext/ca_obj_block.c +4 -4
- data/ext/ca_obj_const_string.c +88 -27
- data/ext/ca_obj_face.c +104 -0
- data/ext/ca_obj_face.h +48 -1
- data/ext/ca_obj_fake.c +11 -0
- data/ext/ca_obj_fixlen_string.c +21 -6
- data/ext/ca_obj_grid.c +11 -3
- data/ext/ca_obj_meld.c +125 -22
- data/ext/ca_obj_moncmp.c +33 -14
- data/ext/ca_obj_monop.c +19 -7
- data/ext/ca_obj_object.c +107 -4
- data/ext/ca_obj_record.c +3 -1
- data/ext/ca_obj_refer.c +30 -6
- data/ext/ca_obj_roll.c +13 -5
- data/ext/ca_obj_select.c +49 -34
- data/ext/ca_obj_select_axis.c +16 -6
- data/ext/ca_obj_shift.c +3 -3
- data/ext/ca_obj_stack.c +3 -8
- data/ext/ca_obj_stride.c +178 -24
- data/ext/ca_obj_string.c +11 -5
- data/ext/ca_obj_tile.c +13 -5
- data/ext/ca_obj_time.c +3 -1
- data/ext/ca_obj_timedelta.c +3 -1
- data/ext/ca_obj_transpose.c +1 -1
- data/ext/ca_obj_triop.c +62 -23
- data/ext/ca_obj_window.c +94 -19
- data/ext/ca_op_cmplx64.h +123 -0
- data/ext/ca_op_ipower.c +1 -5
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +5 -5
- data/ext/ca_sweep_engine.c +362 -155
- data/ext/ca_sweep_engine.h +39 -9
- data/ext/ca_transform_common.c +7 -0
- data/ext/carray.h +148 -132
- data/ext/carray_access.c +83 -49
- data/ext/carray_address_basis.c +590 -0
- data/ext/carray_bincount.c +8 -8
- data/ext/carray_broadcast.c +102 -9
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +2010 -335
- data/ext/carray_call_cfunc.h +153 -0
- data/ext/carray_cast.c +184 -72
- data/ext/carray_conversion.c +22 -22
- data/ext/carray_copy.c +67 -32
- data/ext/carray_core.c +140 -13
- data/ext/carray_count.c +10 -11
- data/ext/carray_element.c +7 -7
- data/ext/carray_factorize.c +72 -51
- data/ext/carray_hold.c +1 -1
- data/ext/carray_index_classifier.c +7 -21
- data/ext/carray_internal.h +36 -3
- data/ext/carray_kernels_bincmp.c +1 -0
- data/ext/carray_kernels_binop.c +320 -298
- data/ext/carray_kernels_init.c +1095 -0
- data/ext/carray_kernels_map.c +1 -0
- data/ext/carray_kernels_moncmp.c +1 -0
- data/ext/carray_kernels_monop.c +412 -411
- data/ext/carray_kernels_reduce_aggregate.c +256 -87
- data/ext/carray_kernels_reduce_boolean.c +1 -0
- data/ext/carray_kernels_reduce_cumulative.c +324 -54
- data/ext/carray_kernels_reduce_extreme.c +605 -58
- data/ext/carray_kernels_reduce_variance.c +1 -0
- data/ext/carray_kernels_scan.c +5 -4
- data/ext/carray_kernels_search.c +187 -106
- data/ext/carray_kernels_sort.c +1 -0
- data/ext/carray_kernels_triop.c +1 -0
- data/ext/carray_lazy.c +175 -5
- data/ext/carray_loop.c +7 -1
- data/ext/carray_mask.c +29 -13
- data/ext/carray_median_percentile.c +56 -1
- data/ext/carray_memory_view.c +46 -21
- data/ext/carray_operator.c +50 -53
- data/ext/carray_order.c +1 -1
- data/ext/carray_partition.c +4 -4
- data/ext/carray_random.c +391 -47
- data/ext/carray_scatter.c +1 -1
- data/ext/carray_slab.c +13 -0
- data/ext/carray_sort.c +22 -24
- data/ext/carray_sort_kernel.c +10 -10
- data/ext/carray_test.c +1 -1
- data/ext/extconf.rb +18 -0
- data/ext/mk_call_cfunc.rb +323 -145
- data/ext/mkkernel.rb +651 -129
- data/ext/ruby_carray.c +28 -17
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +14 -1
- data/lib/carray/axis_group.rb +84 -7
- data/lib/carray/basics.rb +63 -59
- data/lib/carray/bincount_nd.rb +12 -12
- data/lib/carray/block_iterator.rb +111 -25
- data/lib/carray/categorical.rb +154 -37
- data/lib/carray/categorical_iterator.rb +300 -151
- data/lib/carray/conditional.rb +14 -14
- data/lib/carray/const_string.rb +131 -27
- data/lib/carray/construct.rb +61 -0
- data/lib/carray/core_extensions.rb +62 -5
- data/lib/carray/data_type_extension.rb +21 -1
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +3 -3
- data/lib/carray/frame/convert.rb +1 -1
- data/lib/carray/frame/csv_parser.rb +11 -4
- data/lib/carray/frame/frame.rb +85 -21
- data/lib/carray/frame/group.rb +36 -3
- data/lib/carray/frame/io.rb +224 -15
- data/lib/carray/frame/records.rb +18 -4
- data/lib/carray/frame/sort.rb +1 -1
- data/lib/carray/frame/verbs.rb +32 -12
- data/lib/carray/fuse_source.rb +123 -0
- data/lib/carray/fusion.rb +218 -0
- data/lib/carray/histogram.rb +16 -16
- data/lib/carray/inspect.rb +43 -16
- data/lib/carray/iterator.rb +147 -3
- data/lib/carray/lazy.rb +88 -73
- data/lib/carray/mask_gap_fill.rb +3 -1
- data/lib/carray/meld_reduce.rb +2 -2
- data/lib/carray/methods/align_addr.rb +1 -1
- data/lib/carray/methods/composition.rb +1 -1
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/is_in.rb +25 -14
- data/lib/carray/methods/locate_addr.rb +81 -3
- data/lib/carray/methods/mask_duplicates.rb +36 -2
- data/lib/carray/methods/meshgrid.rb +4 -5
- data/lib/carray/methods/mode.rb +2 -2
- data/lib/carray/methods/nunique.rb +23 -2
- data/lib/carray/methods/repeat.rb +110 -0
- data/lib/carray/methods/snap.rb +7 -2
- data/lib/carray/methods/unique.rb +44 -4
- data/lib/carray/methods/value_counts.rb +2 -2
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +0 -19
- data/lib/carray/slab_iterator.rb +77 -19
- data/lib/carray/string_operation_extension.rb +10 -6
- data/lib/carray/time.rb +906 -491
- data/lib/carray/window_iterator.rb +421 -27
- data/lib/carray.rb +7 -5
- data/yard-stubs/ca_obj_array.rb +385 -0
- data/yard-stubs/ca_obj_bitarray.rb +38 -0
- data/yard-stubs/ca_obj_bitfield.rb +43 -0
- data/yard-stubs/ca_obj_block.rb +68 -0
- data/yard-stubs/ca_obj_byte_swap.rb +56 -0
- data/yard-stubs/ca_obj_fake.rb +31 -0
- data/yard-stubs/ca_obj_farray.rb +32 -0
- data/yard-stubs/ca_obj_field.rb +45 -0
- data/yard-stubs/ca_obj_grid.rb +35 -0
- data/yard-stubs/ca_obj_refer.rb +72 -0
- data/yard-stubs/ca_obj_roll.rb +45 -0
- data/yard-stubs/ca_obj_shift.rb +43 -0
- data/yard-stubs/ca_obj_stride.rb +181 -0
- data/yard-stubs/ca_obj_tile.rb +29 -0
- data/yard-stubs/ca_obj_transpose.rb +40 -0
- data/yard-stubs/ca_obj_window.rb +57 -0
- data/yard-stubs/carray_access.rb +131 -0
- data/yard-stubs/carray_attribute.rb +246 -0
- data/yard-stubs/carray_broadcast.rb +37 -0
- data/yard-stubs/carray_cast.rb +489 -0
- data/yard-stubs/carray_class.rb +65 -0
- data/yard-stubs/carray_conversion.rb +76 -0
- data/yard-stubs/carray_copy.rb +79 -0
- data/yard-stubs/carray_core.rb +34 -0
- data/yard-stubs/carray_count.rb +84 -0
- data/yard-stubs/carray_element.rb +108 -0
- data/yard-stubs/carray_generate.rb +66 -0
- data/yard-stubs/carray_lazy.rb +228 -0
- data/yard-stubs/carray_loop.rb +140 -0
- data/yard-stubs/carray_mask.rb +259 -0
- data/yard-stubs/carray_math.rb +1615 -0
- data/yard-stubs/carray_mathfunc.rb +45 -0
- data/yard-stubs/carray_median_percentile.rb +103 -0
- data/yard-stubs/carray_memory_view.rb +163 -0
- data/yard-stubs/carray_order.rb +252 -0
- data/yard-stubs/carray_random.rb +89 -0
- data/yard-stubs/carray_scatter.rb +106 -0
- data/yard-stubs/carray_slab.rb +59 -0
- data/yard-stubs/carray_sort.rb +165 -0
- data/yard-stubs/carray_test.rb +85 -0
- data/yard-stubs/carray_undef.rb +64 -0
- data/yard-stubs/carray_utils.rb +97 -0
- data/yard-stubs/ruby_carray.rb +193 -0
- metadata +67 -10
- data/ext/ca_obj_unbound_repeat.c +0 -496
data/ext/ca_obj_fake.c
CHANGED
|
@@ -462,6 +462,17 @@ rb_ca_fake_new (VALUE cary, int8_t data_type, ca_size_t bytes)
|
|
|
462
462
|
CAFake *ca;
|
|
463
463
|
rb_check_carray_object(cary);
|
|
464
464
|
TypedData_Get_Struct(cary, CArray, &carray_data_type, parent);
|
|
465
|
+
if ( ca_is_face(parent) && ( data_type == CA_OBJECT
|
|
466
|
+
|| parent->data_type == CA_FIXLEN ) ) {
|
|
467
|
+
/* A Face's cells do not mean their storage bytes, so reading them
|
|
468
|
+
under another data_type hands back what the surface exists to hide.
|
|
469
|
+
Both ways down stay open and say which one they are. A Numeric Face
|
|
470
|
+
is not one of these: its surface is its storage. */
|
|
471
|
+
rb_raise(rb_eTypeError,
|
|
472
|
+
"%s has no view of its values in another data_type: "
|
|
473
|
+
"#to_type gives the values, #parent.fake the raw storage",
|
|
474
|
+
rb_obj_classname(cary));
|
|
475
|
+
}
|
|
465
476
|
ca = ca_fake_new(parent, data_type, bytes);
|
|
466
477
|
obj = ca_wrap_struct(ca);
|
|
467
478
|
rb_ca_set_parent(obj, cary);
|
data/ext/ca_obj_fixlen_string.c
CHANGED
|
@@ -91,11 +91,24 @@ ca_fixlen_string_setup (CAFixlenString *ca, CArray *parent)
|
|
|
91
91
|
|
|
92
92
|
ca->obj_type = CA_OBJ_FIXLEN_STRING;
|
|
93
93
|
ca->data_type = CA_FIXLEN;
|
|
94
|
-
/* ORDERABLE + COMPARABLE
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
/* ORDERABLE + COMPARABLE. The descent is NOT the identity map -- the
|
|
95
|
+
scalar decode below strips trailing NUL -- but both flags still hold,
|
|
96
|
+
for a reason worth stating exactly, since it is what a Face author
|
|
97
|
+
copying this would need:
|
|
98
|
+
|
|
99
|
+
ORDERABLE: every cell is padded to the same K with NUL, and NUL is
|
|
100
|
+
the smallest byte, so memcmp on the padded cells orders them the same
|
|
101
|
+
way String#<=> orders the stripped strings (a prefix sorts before any
|
|
102
|
+
continuation, which is what the padding reproduces). Stripping is
|
|
103
|
+
order-preserving; it is not order-irrelevant by being absent.
|
|
104
|
+
|
|
105
|
+
COMPARABLE: a String query is padded out to the cell width before it
|
|
106
|
+
is compared, so byte equality on the padded form is equality on the
|
|
107
|
+
stripped form -- for a query that fits. A query longer than K is
|
|
108
|
+
truncated to its own first K bytes by that same padding step, and
|
|
109
|
+
then matches a cell it is not equal to.
|
|
110
|
+
|
|
111
|
+
Which is what the equality families need (docs/topics/CAFace.md §6.3).
|
|
99
112
|
Without the flags the sort family still worked (it exempts CA_FIXLEN
|
|
100
113
|
storage from the gate and orders by memcmp), but the value-hash family
|
|
101
114
|
handed its results back as a plain fixlen array, and search refused a
|
|
@@ -202,7 +215,9 @@ ca_operation_function_t ca_fixlen_string_func = {
|
|
|
202
215
|
ca_face_xfer_addrs,
|
|
203
216
|
NULL, /* fold_stride: identity Face is not foldable */
|
|
204
217
|
ca_face_xfer_stride,
|
|
205
|
-
ca_face_xfer_all
|
|
218
|
+
ca_face_xfer_all,
|
|
219
|
+
.fill_addrs = ca_face_fill_addrs,
|
|
220
|
+
.fill_stride = ca_face_fill_stride,
|
|
206
221
|
};
|
|
207
222
|
|
|
208
223
|
/* ------------------------------------------------------------------- */
|
data/ext/ca_obj_grid.c
CHANGED
|
@@ -478,9 +478,17 @@ ca_grid_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
478
478
|
transposed leaf breaks this (cross-axis / non-multiple strides); fall back
|
|
479
479
|
to per-cell delivery (correct, still no whole-view attach). The wiring
|
|
480
480
|
guards ndim == grid->ndim, so counts/strides have ndim entries here. */
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
481
|
+
/* The request is over the view's addresses, so a transposed / flat request
|
|
482
|
+
is legal and must not be composed axis-by-axis; see
|
|
483
|
+
ca_xfer_stride_request_is_axis_box (carray.h). */
|
|
484
|
+
if ( ! ca_xfer_stride_request_is_axis_box(g, starts, counts, strides) ) {
|
|
485
|
+
aligned = 0;
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
for (k = 0; k < ndim; k++) {
|
|
489
|
+
if (strides[k] % gnative[k] != 0) { aligned = 0; break; }
|
|
490
|
+
src_step[k] = strides[k] / gnative[k];
|
|
491
|
+
}
|
|
484
492
|
}
|
|
485
493
|
|
|
486
494
|
if (!aligned) {
|
data/ext/ca_obj_meld.c
CHANGED
|
@@ -39,6 +39,8 @@
|
|
|
39
39
|
---------------------------------------------------------------------------- */
|
|
40
40
|
|
|
41
41
|
#include "carray.h"
|
|
42
|
+
#include "carray_internal.h" /* ca_attach_all */
|
|
43
|
+
#include "ca_obj_face.h" /* ca_face_state_portable */
|
|
42
44
|
|
|
43
45
|
/* ------------------------------------------------------------------- */
|
|
44
46
|
/* TypedData */
|
|
@@ -89,7 +91,7 @@ static ID id_parents;
|
|
|
89
91
|
/* uniform check */
|
|
90
92
|
/* ------------------------------------------------------------------- */
|
|
91
93
|
|
|
92
|
-
/* Parents must share
|
|
94
|
+
/* Parents must share data type, ndim, bytes, and all dims except meld_axis;
|
|
93
95
|
meld_axis lengths are the ragged dimension (may differ). */
|
|
94
96
|
static void
|
|
95
97
|
ca_meld_check_uniform (int32_t n_parents, CArray **parents, int8_t meld_axis)
|
|
@@ -150,6 +152,19 @@ ca_meld_setup (CAMeld *ca, int32_t n_parents, CArray **parents, int8_t meld_axis
|
|
|
150
152
|
int32_t i;
|
|
151
153
|
int8_t a;
|
|
152
154
|
|
|
155
|
+
/* Pre-strip Face parents one level to storage, as CAStack does, so a
|
|
156
|
+
melded Face lifts to a single-Face chain (CATime[CAMeld[entity, ...]])
|
|
157
|
+
rather than a Face sitting on Face parents. One level, not a full walk,
|
|
158
|
+
preserves any distinct Face a parent melded underneath. A Face is
|
|
159
|
+
storage-transparent, so welding over storage reads the same bytes; the
|
|
160
|
+
lifted top Face (rb_ca_meld_s_new) carries the identity. The @parents
|
|
161
|
+
accessor keeps the originals, which the callers set. */
|
|
162
|
+
for ( i = 0; i < n_parents; i++ ) {
|
|
163
|
+
if ( ca_is_face(parents[i]) ) {
|
|
164
|
+
parents[i] = CAVIEW(parents[i])->parent;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
153
168
|
ca_meld_check_uniform(n_parents, parents, meld_axis);
|
|
154
169
|
ref = parents[0];
|
|
155
170
|
|
|
@@ -598,19 +613,9 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
598
613
|
int8_t i;
|
|
599
614
|
int structural = 1;
|
|
600
615
|
|
|
601
|
-
/* Bound check on meld_axis */
|
|
602
|
-
{
|
|
603
|
-
ca_size_t req_lo = starts[ma];
|
|
604
|
-
ca_size_t req_hi = starts[ma] + counts[ma];
|
|
605
|
-
if ( req_lo < 0 || req_hi > ca->dim[ma] ) {
|
|
606
|
-
rb_raise(rb_eIndexError,
|
|
607
|
-
"CAMeld xfer_stride meld_axis (axis %d) [%lld, %lld) out of range [0, %lld)",
|
|
608
|
-
(int) ma, (long long) req_lo, (long long) req_hi, (long long) ca->dim[ma]);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
|
|
612
616
|
s = ca->bytes;
|
|
613
617
|
for ( i = ca->ndim - 1; i >= 0; i-- ) { native[i] = s; s *= ca->dim[i]; }
|
|
618
|
+
|
|
614
619
|
for ( i = 0; i < ca->ndim; i++ ) {
|
|
615
620
|
if ( strides[i] != native[i] ) { structural = 0; break; }
|
|
616
621
|
}
|
|
@@ -619,6 +624,23 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
619
624
|
ca_meld_xfer_stride_per_cell(ca, starts, counts, strides, data, dir);
|
|
620
625
|
return;
|
|
621
626
|
}
|
|
627
|
+
|
|
628
|
+
/* Bound check on meld_axis, after the gate and not before it. Only once
|
|
629
|
+
strides == native is established does request axis ma mean view axis ma;
|
|
630
|
+
asked earlier, strides[ma] / native[ma] is not a step along the meld axis
|
|
631
|
+
and legal requests get rejected. Inside the gate the step is 1, so the
|
|
632
|
+
region is starts[ma] .. starts[ma] + counts[ma]. ca_meld_xfer_stride_ma_
|
|
633
|
+
internal below is handed no strides at all and depends on both facts. */
|
|
634
|
+
{
|
|
635
|
+
ca_size_t req_lo = starts[ma];
|
|
636
|
+
ca_size_t req_hi = starts[ma] + counts[ma];
|
|
637
|
+
if ( counts[ma] > 0 && ( req_lo < 0 || req_hi > ca->dim[ma] ) ) {
|
|
638
|
+
rb_raise(rb_eIndexError,
|
|
639
|
+
"CAMeld xfer_stride meld_axis (axis %d) [%lld, %lld) out of range [0, %lld)",
|
|
640
|
+
(int) ma, (long long) req_lo, (long long) req_hi, (long long) ca->dim[ma]);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
622
644
|
if ( ma == 0 ) {
|
|
623
645
|
ca_meld_xfer_stride_ma0(ca, starts, counts, strides, data, dir);
|
|
624
646
|
} else {
|
|
@@ -765,10 +787,7 @@ static void
|
|
|
765
787
|
ca_meld_func_allocate (void *ap)
|
|
766
788
|
{
|
|
767
789
|
CAMeld *ca = (CAMeld *) ap;
|
|
768
|
-
|
|
769
|
-
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
770
|
-
ca_attach(ca->parents[k]);
|
|
771
|
-
}
|
|
790
|
+
ca_attach_all(ca->parents, ca->n_parents);
|
|
772
791
|
ca->ptr = xmalloc(ca_length(ca));
|
|
773
792
|
}
|
|
774
793
|
|
|
@@ -776,10 +795,7 @@ static void
|
|
|
776
795
|
ca_meld_func_attach (void *ap)
|
|
777
796
|
{
|
|
778
797
|
CAMeld *ca = (CAMeld *) ap;
|
|
779
|
-
|
|
780
|
-
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
781
|
-
ca_attach(ca->parents[k]);
|
|
782
|
-
}
|
|
798
|
+
ca_attach_all(ca->parents, ca->n_parents);
|
|
783
799
|
ca->ptr = xmalloc(ca_length(ca));
|
|
784
800
|
ca_meld_func_xfer_all(ca, ca->ptr, CA_XFER_GET);
|
|
785
801
|
}
|
|
@@ -882,6 +898,17 @@ ca_operation_function_t ca_meld_func = {
|
|
|
882
898
|
/* Ruby surface */
|
|
883
899
|
/* ------------------------------------------------------------------- */
|
|
884
900
|
|
|
901
|
+
/* One-level strip of a Face VALUE to its storage-side parent (non-Face as-is).
|
|
902
|
+
Keeps the @parent ivar in step with the pre-stripped C parents, so the
|
|
903
|
+
Ruby-visible chain of a melded Face is single-Face too. */
|
|
904
|
+
static VALUE
|
|
905
|
+
ca_meld_face_parent1 (VALUE v)
|
|
906
|
+
{
|
|
907
|
+
CArray *c;
|
|
908
|
+
TypedData_Get_Struct(v, CArray, &carray_data_type, c);
|
|
909
|
+
return ca_is_face(c) ? rb_ca_parent(v) : v;
|
|
910
|
+
}
|
|
911
|
+
|
|
885
912
|
VALUE
|
|
886
913
|
rb_ca_meld_new (VALUE parents_ary, int8_t meld_axis)
|
|
887
914
|
{
|
|
@@ -905,7 +932,7 @@ rb_ca_meld_new (VALUE parents_ary, int8_t meld_axis)
|
|
|
905
932
|
ca = ca_meld_new((int32_t) n, parents, meld_axis);
|
|
906
933
|
obj = ca_wrap_struct(ca);
|
|
907
934
|
rb_ivar_set(obj, id_parents, rb_ary_dup(parents_ary));
|
|
908
|
-
rb_ca_set_parent(obj, rb_ary_entry(parents_ary, 0));
|
|
935
|
+
rb_ca_set_parent(obj, ca_meld_face_parent1(rb_ary_entry(parents_ary, 0)));
|
|
909
936
|
ALLOCV_END(holder);
|
|
910
937
|
return obj;
|
|
911
938
|
}
|
|
@@ -962,11 +989,86 @@ rb_ca_meld_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
962
989
|
}
|
|
963
990
|
ca_meld_setup(ca, (int32_t) n, parents, meld_axis);
|
|
964
991
|
rb_ivar_set(self, id_parents, rb_ary_dup(list));
|
|
965
|
-
rb_ca_set_parent(self, rb_ary_entry(list, 0));
|
|
992
|
+
rb_ca_set_parent(self, ca_meld_face_parent1(rb_ary_entry(list, 0)));
|
|
966
993
|
ALLOCV_END(holder);
|
|
967
994
|
return self;
|
|
968
995
|
}
|
|
969
996
|
|
|
997
|
+
/* CAMeld.new(list, axis: 0) -- Class#new override, the twin of
|
|
998
|
+
rb_ca_stack_s_new. A melded view has one surface over many parents, so a
|
|
999
|
+
homogeneous Face list is treated the way CAStack treats it: refuse a Face
|
|
1000
|
+
whose state is per-parent (the cells of parent i are only readable against
|
|
1001
|
+
parent i's own state -- a CAConstString's cells are byte ranges into ITS
|
|
1002
|
+
buffer), and lift the rest so the Face survives the weld.
|
|
1003
|
+
|
|
1004
|
+
Without this meld was the one multi-parent constructor that neither asked
|
|
1005
|
+
nor lifted: it returned the raw storage of whatever it was given, which for
|
|
1006
|
+
CAConstString meant 16-byte (start,end) pairs presented as the string cells,
|
|
1007
|
+
and for CATime meant raw int64 ticks. Both looked like data.
|
|
1008
|
+
|
|
1009
|
+
Doing it here rather than in CArray.meld covers CAFrame.meld and a direct
|
|
1010
|
+
CAMeld.new by the same check. */
|
|
1011
|
+
static VALUE
|
|
1012
|
+
rb_ca_meld_s_new (int argc, VALUE *argv, VALUE klass)
|
|
1013
|
+
{
|
|
1014
|
+
VALUE list, kwargs;
|
|
1015
|
+
long n, i;
|
|
1016
|
+
int all_face = 1;
|
|
1017
|
+
VALUE face_class = Qnil;
|
|
1018
|
+
CArray *ref_face = NULL;
|
|
1019
|
+
VALUE obj;
|
|
1020
|
+
|
|
1021
|
+
rb_scan_args(argc, argv, "1:", &list, &kwargs);
|
|
1022
|
+
Check_Type(list, T_ARRAY);
|
|
1023
|
+
n = RARRAY_LEN(list);
|
|
1024
|
+
if ( n <= 0 ) {
|
|
1025
|
+
rb_raise(rb_eArgError, "CAMeld.new requires at least one parent");
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
for ( i = 0; i < n; i++ ) {
|
|
1029
|
+
VALUE p = rb_ary_entry(list, i);
|
|
1030
|
+
CArray *ca;
|
|
1031
|
+
rb_check_carray_object(p);
|
|
1032
|
+
TypedData_Get_Struct(p, CArray, &carray_data_type, ca);
|
|
1033
|
+
if ( !ca_is_face(ca) ) { all_face = 0; break; }
|
|
1034
|
+
if ( i == 0 ) {
|
|
1035
|
+
face_class = rb_obj_class(p);
|
|
1036
|
+
ref_face = ca;
|
|
1037
|
+
} else if ( rb_obj_class(p) != face_class ) {
|
|
1038
|
+
all_face = 0; break;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/* A single parent has nothing to weld against, so its Face rides the
|
|
1043
|
+
chain as it always did; refuse and lift only apply from two up. */
|
|
1044
|
+
if ( all_face && n > 1
|
|
1045
|
+
&& !ca_face_state_portable(ref_face->obj_type, face_class) ) {
|
|
1046
|
+
rb_raise(rb_eArgError,
|
|
1047
|
+
"CAMeld.new: %s state is not portable across multiple "
|
|
1048
|
+
"parents (= per-parent storage like CAConstString's buffer); "
|
|
1049
|
+
"strip Face with .parent if a storage-level CAMeld is intended",
|
|
1050
|
+
rb_class2name(face_class));
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
obj = rb_obj_alloc(klass);
|
|
1054
|
+
rb_obj_call_init_kw(obj, argc, argv, RB_PASS_CALLED_KEYWORDS);
|
|
1055
|
+
|
|
1056
|
+
if ( !all_face || n < 2 ) return obj;
|
|
1057
|
+
|
|
1058
|
+
for ( i = 1; i < n; i++ ) {
|
|
1059
|
+
VALUE p = rb_ary_entry(list, i);
|
|
1060
|
+
CArray *ca;
|
|
1061
|
+
TypedData_Get_Struct(p, CArray, &carray_data_type, ca);
|
|
1062
|
+
if ( !ca_face_state_compatible(rb_ary_entry(list, 0), ref_face, p, ca) ) {
|
|
1063
|
+
rb_raise(rb_eArgError,
|
|
1064
|
+
"CAMeld.new: Face state mismatch across parents "
|
|
1065
|
+
"(= %s instance at index %ld differs in state from index 0)",
|
|
1066
|
+
rb_class2name(face_class), i);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
return ca_face_lift(obj, rb_ary_entry(list, 0));
|
|
1070
|
+
}
|
|
1071
|
+
|
|
970
1072
|
static VALUE
|
|
971
1073
|
rb_ca_meld_n_parents (VALUE self)
|
|
972
1074
|
{
|
|
@@ -1022,6 +1124,7 @@ Init_ca_obj_meld (void)
|
|
|
1022
1124
|
id_parents = rb_intern("parents");
|
|
1023
1125
|
|
|
1024
1126
|
rb_define_alloc_func(rb_cCAMeld, rb_ca_meld_s_allocate);
|
|
1127
|
+
rb_define_singleton_method(rb_cCAMeld, "new", rb_ca_meld_s_new, -1);
|
|
1025
1128
|
rb_define_method(rb_cCAMeld, "initialize",
|
|
1026
1129
|
rb_ca_meld_initialize, -1);
|
|
1027
1130
|
rb_define_method(rb_cCAMeld, "initialize_copy",
|
data/ext/ca_obj_moncmp.c
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
CAMonCmp — lazy monadic element-wise comparison view: is_nan /
|
|
4
4
|
is_inf / is_finite / is_invalid / signbit. Output data_type =
|
|
5
|
-
CA_BOOLEAN (1 byte); operand keeps its native data_type (per-
|
|
5
|
+
CA_BOOLEAN (1 byte); operand keeps its native data_type (per-type
|
|
6
6
|
kernels cover integer as well, so is_nan / is_inf on integer parents
|
|
7
7
|
return const-false and is_finite const-true without a cast layer).
|
|
8
8
|
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
Peak scratch: 1 operand-data_type slab.
|
|
21
21
|
|
|
22
22
|
Mask propagation:
|
|
23
|
-
Per-
|
|
23
|
+
Per-type moncmp kernels write only at non-masked positions, so
|
|
24
24
|
the standard create_mask = parent.mask machinery carries mask bits
|
|
25
25
|
to the caller-visible result. No in-flight mask handling in
|
|
26
26
|
xfer_stride.
|
|
@@ -121,9 +121,8 @@ ca_moncmp_setup (CAMonCmp *ca, CArray *parent, uint16_t op_id)
|
|
|
121
121
|
|
|
122
122
|
memcpy(ca->dim, parent->dim, parent->ndim * sizeof(ca_size_t));
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
124
|
+
/* The mask is NOT built here: ca_has_mask creates a view's mask on
|
|
125
|
+
demand from its parent's. */
|
|
127
126
|
if ( ca_is_scalar(parent) ) {
|
|
128
127
|
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
129
128
|
}
|
|
@@ -252,6 +251,8 @@ ca_moncmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
252
251
|
int8_t k;
|
|
253
252
|
void *scratch;
|
|
254
253
|
ca_size_t operand_bytes;
|
|
254
|
+
ca_size_t operand_strides[CA_RANK_MAX];
|
|
255
|
+
int is_contig;
|
|
255
256
|
|
|
256
257
|
if ( dir != CA_XFER_GET ) {
|
|
257
258
|
rb_raise(rb_eRuntimeError, "CAMonCmp is read-only (xfer_stride PUT)");
|
|
@@ -263,26 +264,44 @@ ca_moncmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
263
264
|
|
|
264
265
|
operand_bytes = mc->parent->bytes;
|
|
265
266
|
|
|
267
|
+
/* The operand's cell is operand_bytes wide where this view's is one byte
|
|
268
|
+
(CA_BOOLEAN), so the caller's strides have to be restated at the
|
|
269
|
+
operand's cell size before the pull; strides[k] / bytes is the index
|
|
270
|
+
step, which is what the two spaces share.
|
|
271
|
+
|
|
272
|
+
is_contig says the caller asked for the row-major slab that xfer_all
|
|
273
|
+
and attach send. Only then does the parent's own buffer hold the
|
|
274
|
+
wanted cells in the packed order the kernel reads them in, so it is
|
|
275
|
+
also the only case the leaf in-place path is good for. */
|
|
276
|
+
{
|
|
277
|
+
ca_size_t native = mc->bytes;
|
|
278
|
+
is_contig = 1;
|
|
279
|
+
for ( k = mc->ndim - 1; k >= 0; k-- ) {
|
|
280
|
+
operand_strides[k] = strides[k] / mc->bytes * operand_bytes;
|
|
281
|
+
if ( strides[k] != native ) {
|
|
282
|
+
is_contig = 0;
|
|
283
|
+
}
|
|
284
|
+
native *= mc->dim[k];
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
266
288
|
/* === 1. pull parent (leaf-opt or scratch) === */
|
|
267
289
|
int scratch_is_inplace = 0;
|
|
268
290
|
{
|
|
269
291
|
char *inplace = NULL;
|
|
270
|
-
if (
|
|
292
|
+
if ( is_contig &&
|
|
293
|
+
ca_moncmp_try_leaf_inplace(mc->parent, starts, counts,
|
|
271
294
|
operand_bytes, &inplace) ) {
|
|
272
295
|
scratch = inplace;
|
|
273
296
|
scratch_is_inplace = 1;
|
|
274
297
|
ca_moncmp_leaf_inplace_count++;
|
|
275
298
|
}
|
|
276
299
|
else {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
scratch_strides[k] = s;
|
|
281
|
-
s *= counts[k];
|
|
282
|
-
}
|
|
283
|
-
scratch = ca_lazy_arena_acquire(slab_n * operand_bytes);
|
|
300
|
+
scratch = ( mc->parent->data_type == CA_OBJECT )
|
|
301
|
+
? ca_lazy_arena_acquire_object(slab_n)
|
|
302
|
+
: ca_lazy_arena_acquire(slab_n * operand_bytes);
|
|
284
303
|
ca_moncmp_scratch_acquire_count++;
|
|
285
|
-
ca_xfer_stride(mc->parent, starts, counts,
|
|
304
|
+
ca_xfer_stride(mc->parent, starts, counts, operand_strides, scratch,
|
|
286
305
|
CA_XFER_GET);
|
|
287
306
|
}
|
|
288
307
|
}
|
data/ext/ca_obj_monop.c
CHANGED
|
@@ -207,9 +207,9 @@ ca_monop_setup (CAMonOp *ca, CArray *parent, uint16_t op_id)
|
|
|
207
207
|
|
|
208
208
|
memcpy(ca->dim, parent->dim, parent->ndim * sizeof(ca_size_t));
|
|
209
209
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
210
|
+
/* The mask is NOT built here: ca_has_mask creates a view's mask on
|
|
211
|
+
demand from its parent's, so an expression whose mask nobody reads
|
|
212
|
+
never allocates one. */
|
|
213
213
|
|
|
214
214
|
if ( ca_is_scalar(parent) ) {
|
|
215
215
|
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
@@ -380,8 +380,8 @@ ca_size_t ca_monop_materialise_call_count = 0;
|
|
|
380
380
|
but they are unobservable: the output mask is built separately via
|
|
381
381
|
the attach lifecycle (ca_monop_func_create_mask + parent.mask
|
|
382
382
|
CARefer), so reads of masked cells return UNDEF regardless of byte
|
|
383
|
-
contents.
|
|
384
|
-
|
|
383
|
+
contents. The mask marks cells as undefined; it does not guard their
|
|
384
|
+
bytes, so writing garbage into a masked cell is licensed.
|
|
385
385
|
|
|
386
386
|
A "partial mask slow path" (= a cell-wise branch to skip masked-cell
|
|
387
387
|
compute) is a possible future micro-optimisation; it is not done
|
|
@@ -461,7 +461,9 @@ pull_leaf_with_optional_cast (CArray *leaf, uint16_t innermost_op,
|
|
|
461
461
|
}
|
|
462
462
|
}
|
|
463
463
|
(void) holder;
|
|
464
|
-
scratch =
|
|
464
|
+
scratch = ( leaf->data_type == CA_OBJECT )
|
|
465
|
+
? ca_lazy_arena_acquire_object(slab_n)
|
|
466
|
+
: ca_lazy_arena_acquire(total_bytes);
|
|
465
467
|
ca_monop_scratch_acquire_count++;
|
|
466
468
|
ca_xfer_stride(leaf, starts, counts, parent_strides, scratch, CA_XFER_GET);
|
|
467
469
|
|
|
@@ -615,7 +617,9 @@ ca_monop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
615
617
|
→ data (in target data_type). Required because in-place cast
|
|
616
618
|
would overlap source/dest reads when target_bytes > src_bytes
|
|
617
619
|
(forward-walk reads cells past their own write boundary). */
|
|
618
|
-
scratch =
|
|
620
|
+
scratch = ( cur_dt == CA_OBJECT )
|
|
621
|
+
? ca_lazy_arena_acquire_object(slab_n)
|
|
622
|
+
: ca_lazy_arena_acquire(total_bytes);
|
|
619
623
|
ca_monop_scratch_acquire_count++;
|
|
620
624
|
memcpy(scratch, data, total_bytes);
|
|
621
625
|
ca_cast_block(slab_n, &src_stub, scratch, &dst_stub, data);
|
|
@@ -728,6 +732,14 @@ ca_monop_func_attach (void *ap)
|
|
|
728
732
|
s = ca->bytes;
|
|
729
733
|
for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
|
|
730
734
|
for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
|
|
735
|
+
/* CA_OBJECT cells are VALUEs and this buffer is about to be marked as
|
|
736
|
+
soon as the view is, so it must not be handed to the GC as raw
|
|
737
|
+
xmalloc garbage. */
|
|
738
|
+
if ( ca->data_type == CA_OBJECT ) {
|
|
739
|
+
VALUE *p = (VALUE *) ca->ptr;
|
|
740
|
+
ca_size_t i;
|
|
741
|
+
for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
|
|
742
|
+
}
|
|
731
743
|
ca_monop_func_xfer_stride(ca, starts, ca->dim, native, ca->ptr, CA_XFER_GET);
|
|
732
744
|
}
|
|
733
745
|
|
data/ext/ca_obj_object.c
CHANGED
|
@@ -352,8 +352,11 @@ ca_objmask_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
352
352
|
if ( n == 0 ) return;
|
|
353
353
|
|
|
354
354
|
if ( rb_obj_respond_to(ca->array, mid_block, Qtrue) ) {
|
|
355
|
-
|
|
356
|
-
|
|
355
|
+
/* The request is over the view's addresses, so a transposed / flat
|
|
356
|
+
request is legal; the per-axis copy_block dispatch below would
|
|
357
|
+
misread it. See ca_xfer_stride_request_is_axis_box (carray.h). */
|
|
358
|
+
int aligned = ca_xfer_stride_request_is_axis_box(ca, starts, counts, strides);
|
|
359
|
+
for ( k = 0; aligned && k < ndim; k++ ) {
|
|
357
360
|
if ( strides[k] <= 0 || strides[k] % native[k] != 0 ) { aligned = 0; break; }
|
|
358
361
|
steps[k] = strides[k] / native[k];
|
|
359
362
|
}
|
|
@@ -735,6 +738,14 @@ ca_object_dispatch_fill (CAObject *ca, void *ptr)
|
|
|
735
738
|
volatile VALUE rval = rb_ca_ptr2obj(ca->self, ptr);
|
|
736
739
|
rb_funcall(ca->self, rb_intern("fill_data"), 1, rval);
|
|
737
740
|
}
|
|
741
|
+
else if ( rb_obj_respond_to(ca->self, rb_intern("fill_block"), Qtrue)
|
|
742
|
+
|| rb_obj_respond_to(ca->self, rb_intern("fill_addrs"), Qtrue) ) {
|
|
743
|
+
/* An author who wrote the region slots but not fill_data would otherwise
|
|
744
|
+
get the per-cell default for the one request that is easiest to batch.
|
|
745
|
+
Hand the whole extent to the region path, which reaches `fill_block` in
|
|
746
|
+
one call or `fill_addrs` in address windows. */
|
|
747
|
+
ca_fill_stride_whole(ca, ptr);
|
|
748
|
+
}
|
|
738
749
|
else {
|
|
739
750
|
ca_size_t addr;
|
|
740
751
|
for ( addr = 0; addr < ca->elements; addr++ ) {
|
|
@@ -937,8 +948,11 @@ ca_object_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
937
948
|
before the % check
|
|
938
949
|
- given %==0 + >0, strides/native >= 1 holds automatically */
|
|
939
950
|
if ( rb_obj_respond_to(ca->self, mid_block, Qtrue) ) {
|
|
940
|
-
|
|
941
|
-
|
|
951
|
+
/* The request is over the view's addresses, so a transposed / flat
|
|
952
|
+
request is legal; the per-axis copy_block dispatch below would
|
|
953
|
+
misread it. See ca_xfer_stride_request_is_axis_box (carray.h). */
|
|
954
|
+
int aligned = ca_xfer_stride_request_is_axis_box(ca, starts, counts, strides);
|
|
955
|
+
for ( k = 0; aligned && k < ndim; k++ ) {
|
|
942
956
|
if ( strides[k] <= 0 || strides[k] % native[k] != 0 ) { aligned = 0; break; }
|
|
943
957
|
steps[k] = strides[k] / native[k]; /* >= 1 by construction */
|
|
944
958
|
}
|
|
@@ -1001,6 +1015,93 @@ ca_object_func_fill_data (void *ap, void *ptr)
|
|
|
1001
1015
|
ca_object_dispatch_fill((CAObject *) ap, ptr);
|
|
1002
1016
|
}
|
|
1003
1017
|
|
|
1018
|
+
/* Partial fill. fill_data carries no region and can only say "fill
|
|
1019
|
+
everything I cover", so before these two slots existed the only way to
|
|
1020
|
+
fill part of a CAObject was the per-cell default -- one store_addr per
|
|
1021
|
+
cell. The region arrives in the view's own address space. With
|
|
1022
|
+
`fill_block` defined (and the region an axis-aligned forward sub-box of
|
|
1023
|
+
self) it becomes one call; with `fill_addrs` defined it becomes one call
|
|
1024
|
+
per address window. With neither defined the behaviour is exactly the
|
|
1025
|
+
old default, so an existing subclass sees no change. */
|
|
1026
|
+
static void
|
|
1027
|
+
ca_object_func_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
|
|
1028
|
+
{
|
|
1029
|
+
CAObject *ca = (CAObject *) ap;
|
|
1030
|
+
ID mid = rb_intern("fill_addrs");
|
|
1031
|
+
|
|
1032
|
+
if ( ca_is_face(ca) ) {
|
|
1033
|
+
ca_face_fill_addrs(ap, n, addrs, ptr);
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
if ( n > 0 && rb_obj_respond_to(ca->self, mid, Qtrue) ) {
|
|
1038
|
+
volatile VALUE raddrs, rval;
|
|
1039
|
+
ca_size_t dim1[1] = { n };
|
|
1040
|
+
raddrs = ca_object_wrap_transient(CA_SIZE, sizeof(ca_size_t),
|
|
1041
|
+
1, dim1, addrs, CA_XFER_PUT);
|
|
1042
|
+
rval = rb_ca_ptr2obj(ca->self, ptr);
|
|
1043
|
+
rb_funcall(ca->self, mid, 2, raddrs, rval);
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
ca_fill_addrs_default(ap, n, addrs, ptr);
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/* Gate: one region axis per view axis, forward, and a whole number of
|
|
1051
|
+
elements per step. native is strictly decreasing, so steps[k] =
|
|
1052
|
+
m_k * native[k] with m_k >= 1 admits only the identity permutation --
|
|
1053
|
+
transpose, negative and zero (broadcast) steps, sub-element steps and
|
|
1054
|
+
dimension-dropping regions all fail it and take the addrs route. The
|
|
1055
|
+
bound check then confirms the decomposed box lies inside self. */
|
|
1056
|
+
static void
|
|
1057
|
+
ca_object_func_fill_stride (void *ap, ca_size_t base, int8_t ndim,
|
|
1058
|
+
ca_size_t *counts, ca_size_t *steps, void *ptr)
|
|
1059
|
+
{
|
|
1060
|
+
CAObject *ca = (CAObject *) ap;
|
|
1061
|
+
ca_size_t native[CA_RANK_MAX], istep[CA_RANK_MAX], start[CA_RANK_MAX];
|
|
1062
|
+
ca_size_t s;
|
|
1063
|
+
int8_t k;
|
|
1064
|
+
ID mid = rb_intern("fill_block");
|
|
1065
|
+
|
|
1066
|
+
if ( ca_is_face(ca) ) {
|
|
1067
|
+
ca_face_fill_stride(ap, base, ndim, counts, steps, ptr);
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
if ( ndim == ca->ndim && rb_obj_respond_to(ca->self, mid, Qtrue) ) {
|
|
1072
|
+
int aligned = 1;
|
|
1073
|
+
s = 1;
|
|
1074
|
+
for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
|
|
1075
|
+
for ( k = 0; k < ndim; k++ ) {
|
|
1076
|
+
if ( steps[k] <= 0 || steps[k] % native[k] != 0 ) { aligned = 0; break; }
|
|
1077
|
+
istep[k] = steps[k] / native[k];
|
|
1078
|
+
start[k] = ( base / native[k] ) % ca->dim[k];
|
|
1079
|
+
if ( start[k] + ( counts[k] - 1 ) * istep[k] >= ca->dim[k] ) {
|
|
1080
|
+
aligned = 0;
|
|
1081
|
+
break;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
if ( aligned ) {
|
|
1085
|
+
volatile VALUE rstarts, rcounts, rsteps, rval;
|
|
1086
|
+
rstarts = rb_ary_new_capa(ndim);
|
|
1087
|
+
rcounts = rb_ary_new_capa(ndim);
|
|
1088
|
+
rsteps = rb_ary_new_capa(ndim);
|
|
1089
|
+
for ( k = 0; k < ndim; k++ ) {
|
|
1090
|
+
rb_ary_push(rstarts, SIZE2NUM(start[k]));
|
|
1091
|
+
rb_ary_push(rcounts, SIZE2NUM(counts[k]));
|
|
1092
|
+
rb_ary_push(rsteps, SIZE2NUM(istep[k]));
|
|
1093
|
+
}
|
|
1094
|
+
rval = rb_ca_ptr2obj(ca->self, ptr);
|
|
1095
|
+
rb_funcall(ca->self, mid, 4, rstarts, rcounts, rsteps, rval);
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
/* addrs route: address windows -> ca_fill_addrs -> `fill_addrs` when the
|
|
1101
|
+
author defined it, else the per-cell default. */
|
|
1102
|
+
ca_fill_stride_via_addrs(ap, base, ndim, counts, steps, ptr);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1004
1105
|
static void
|
|
1005
1106
|
ca_object_func_create_mask (void *ap)
|
|
1006
1107
|
{
|
|
@@ -1050,6 +1151,8 @@ ca_operation_function_t ca_object_func = {
|
|
|
1050
1151
|
NULL, /* fold_stride: never-fold (callback boundary) */
|
|
1051
1152
|
ca_object_func_xfer_stride,
|
|
1052
1153
|
ca_object_func_xfer_all,
|
|
1154
|
+
.fill_addrs = ca_object_func_fill_addrs,
|
|
1155
|
+
.fill_stride = ca_object_func_fill_stride,
|
|
1053
1156
|
};
|
|
1054
1157
|
|
|
1055
1158
|
/* ------------------------------------------------------------------- */
|
data/ext/ca_obj_record.c
CHANGED
|
@@ -202,7 +202,9 @@ ca_operation_function_t ca_record_func = {
|
|
|
202
202
|
ca_face_xfer_addrs,
|
|
203
203
|
NULL, /* fold_stride: identity Face is not foldable */
|
|
204
204
|
ca_face_xfer_stride,
|
|
205
|
-
ca_face_xfer_all
|
|
205
|
+
ca_face_xfer_all,
|
|
206
|
+
.fill_addrs = ca_face_fill_addrs,
|
|
207
|
+
.fill_stride = ca_face_fill_stride,
|
|
206
208
|
};
|
|
207
209
|
|
|
208
210
|
/* ------------------------------------------------------------------- */
|