carray 3.0.4 → 3.0.6
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/CHANGELOG.md +438 -0
- data/README.md +1 -1
- data/carray.gemspec +3 -2
- data/ext/ca_array_pool.c +25 -1
- data/ext/ca_axis_dispatch.c +19 -20
- data/ext/ca_axis_group.c +1 -1
- data/ext/ca_categorical_iterator.c +34 -27
- data/ext/ca_compare.c +4 -4
- data/ext/ca_composite_dispatch.c +9 -9
- data/ext/ca_kernel_iterator.c +122 -237
- data/ext/ca_kernel_iterator.h +522 -337
- data/ext/ca_obj_array.c +69 -19
- data/ext/ca_obj_bincmp.c +10 -1
- data/ext/ca_obj_binop.c +11 -1
- data/ext/ca_obj_bitarray.c +5 -1
- data/ext/ca_obj_bitfield.c +60 -43
- data/ext/ca_obj_byte_swap.c +4 -1
- data/ext/ca_obj_const_string.c +15 -3
- data/ext/ca_obj_face.c +44 -1
- data/ext/ca_obj_fake.c +3 -1
- data/ext/ca_obj_field.c +13 -3
- data/ext/ca_obj_grid.c +219 -17
- data/ext/ca_obj_meld.c +69 -113
- data/ext/ca_obj_moncmp.c +9 -1
- data/ext/ca_obj_monop.c +86 -12
- data/ext/ca_obj_object.c +118 -32
- data/ext/ca_obj_record.c +3 -0
- data/ext/ca_obj_reduce.c +19 -1
- data/ext/ca_obj_refer.c +80 -26
- data/ext/ca_obj_remap.c +69 -10
- data/ext/ca_obj_roll.c +27 -6
- data/ext/ca_obj_select.c +38 -6
- data/ext/ca_obj_select_axis.c +1 -0
- data/ext/ca_obj_shift.c +32 -7
- data/ext/ca_obj_stack.c +311 -111
- data/ext/ca_obj_stride.c +159 -64
- data/ext/ca_obj_string.c +27 -2
- data/ext/ca_obj_tile.c +28 -7
- data/ext/ca_obj_transpose.c +8 -4
- data/ext/ca_obj_triop.c +12 -1
- data/ext/ca_obj_window.c +80 -50
- data/ext/ca_op_ipower.c +12 -12
- data/ext/ca_sort_kernels.h +6 -3
- data/ext/caframe_csv_reader.c +1 -1
- data/ext/carray.h +35 -1
- data/ext/carray_access.c +43 -67
- data/ext/carray_address_basis.c +134 -0
- data/ext/carray_attribute.c +32 -0
- data/ext/carray_broadcast.c +3 -4
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_cast.c +251 -93
- data/ext/carray_cast_func.rb +56 -26
- data/ext/carray_conversion.c +11 -7
- data/ext/carray_core.c +814 -72
- data/ext/carray_count.c +6 -0
- data/ext/carray_element.c +22 -13
- data/ext/carray_factorize.c +20 -20
- data/ext/carray_generate.c +8 -2
- data/ext/carray_histogram.c +26 -4
- data/ext/carray_index_classifier.c +4 -4
- data/ext/carray_internal.h +159 -12
- data/ext/carray_kernels_bincmp.c +2174 -170
- data/ext/carray_kernels_binop.c +25653 -5487
- data/ext/carray_kernels_init.c +8 -8
- data/ext/carray_kernels_moncmp.c +96 -96
- data/ext/carray_kernels_monop.c +12253 -5235
- data/ext/carray_kernels_reduce_aggregate.c +6150 -2423
- data/ext/carray_kernels_reduce_boolean.c +1533 -15
- data/ext/carray_kernels_reduce_cumulative.c +2442 -882
- data/ext/carray_kernels_reduce_extreme.c +5658 -1661
- data/ext/carray_kernels_reduce_variance.c +2534 -402
- data/ext/carray_kernels_scan.c +368 -368
- data/ext/carray_kernels_search.c +4551 -604
- data/ext/carray_kernels_sort.c +659 -751
- data/ext/carray_kernels_triop.c +114 -114
- data/ext/carray_key_windows.c +4 -0
- data/ext/carray_lazy.c +47 -0
- data/ext/carray_loop.c +1 -1
- data/ext/carray_mask.c +175 -161
- data/ext/carray_median_percentile.c +4 -4
- data/ext/carray_memory_view.c +15 -9
- data/ext/carray_operator.c +152 -49
- data/ext/carray_order.c +230 -10
- data/ext/carray_random.c +22 -19
- data/ext/carray_scatter.c +24 -7
- data/ext/carray_slab.c +128 -29
- data/ext/carray_sort.c +224 -16
- data/ext/carray_sort_kernel.c +5 -7
- data/ext/carray_struct.c +35 -43
- data/ext/carray_test.c +74 -19
- data/ext/carray_time_text.c +6 -4
- data/ext/carray_utils.c +63 -21
- data/ext/extconf.rb +11 -0
- data/ext/mkkernel.rb +546 -199
- data/ext/ruby_carray.c +4 -1
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +42 -5
- data/lib/carray/autoload_carray.rb +3 -3
- data/lib/carray/autoload_method_extension.rb +5 -3
- data/lib/carray/axis_group.rb +13 -7
- data/lib/carray/basics.rb +28 -8
- data/lib/carray/block_iterator.rb +17 -3
- data/lib/carray/categorical.rb +35 -23
- data/lib/carray/categorical_iterator.rb +8 -8
- data/lib/carray/complex.rb +2 -2
- data/lib/carray/conditional.rb +3 -2
- data/lib/carray/const_string.rb +10 -0
- data/lib/carray/data_type_extension.rb +8 -1
- data/lib/carray/fixlen_string.rb +41 -2
- data/lib/carray/frame/column_verbs.rb +48 -16
- data/lib/carray/frame/concat.rb +17 -3
- data/lib/carray/frame/convert.rb +19 -0
- data/lib/carray/frame/csv_parser.rb +32 -32
- data/lib/carray/frame/describe.rb +4 -2
- data/lib/carray/frame/frame.rb +405 -85
- data/lib/carray/frame/group.rb +777 -64
- data/lib/carray/frame/io.rb +212 -72
- data/lib/carray/frame/join.rb +146 -37
- data/lib/carray/frame/records.rb +3 -3
- data/lib/carray/frame/reshape.rb +89 -11
- data/lib/carray/frame/sort.rb +57 -9
- data/lib/carray/frame/verbs.rb +384 -49
- data/lib/carray/frame/windows.rb +44 -6
- data/lib/carray/fuse_source.rb +31 -2
- data/lib/carray/inspect.rb +7 -2
- data/lib/carray/iterator.rb +32 -0
- data/lib/carray/lazy.rb +52 -8
- data/lib/carray/mask_gap_fill.rb +37 -17
- data/lib/carray/meld_reduce.rb +1 -1
- data/lib/carray/methods/choose.rb +3 -2
- data/lib/carray/methods/is_in.rb +8 -1
- data/lib/carray/methods/meshgrid.rb +3 -1
- data/lib/carray/runtime.rb +47 -8
- data/lib/carray/segment_iterator.rb +35 -16
- data/lib/carray/serialize.rb +53 -19
- data/lib/carray/stack.rb +33 -18
- data/lib/carray/string.rb +8 -0
- data/lib/carray/string_operation_extension.rb +13 -5
- data/lib/carray/struct_builder.rb +5 -3
- data/lib/carray/time.rb +112 -68
- data/lib/carray/window_iterator.rb +16 -4
- data/yard-stubs/ca_obj_array.rb +26 -1
- data/yard-stubs/ca_obj_transpose.rb +5 -4
- data/yard-stubs/carray_attribute.rb +3 -1
- data/yard-stubs/carray_cast.rb +10 -5
- data/yard-stubs/carray_conversion.rb +13 -3
- data/yard-stubs/carray_element.rb +7 -6
- data/yard-stubs/carray_mask.rb +28 -4
- data/yard-stubs/carray_math.rb +45 -20
- data/yard-stubs/carray_memory_view.rb +7 -0
- data/yard-stubs/carray_order.rb +100 -4
- data/yard-stubs/carray_scatter.rb +7 -5
- data/yard-stubs/carray_test.rb +7 -4
- metadata +18 -4
data/ext/ca_obj_stride.c
CHANGED
|
@@ -183,6 +183,9 @@ free_ca_stride (void *ap)
|
|
|
183
183
|
{
|
|
184
184
|
CAStride *ca = (CAStride *) ap;
|
|
185
185
|
if (ca == NULL) return;
|
|
186
|
+
if ( ca_test_flag(ca, CA_FLAG_FOLDED) ) {
|
|
187
|
+
ca_fold_forget((CArray *) ca);
|
|
188
|
+
}
|
|
186
189
|
ca_free(ca->mask);
|
|
187
190
|
if (ca->_pool) {
|
|
188
191
|
/* Pool path: one xfree covers dim/strides via the pool buffer,
|
|
@@ -247,6 +250,10 @@ ca_stride_compose_through (CAStride *leaf, CAStride *parent,
|
|
|
247
250
|
for (k = parent->ndim - 1; k >= 0; k--)
|
|
248
251
|
prod[k] = prod[k + 1] * parent->dim[k];
|
|
249
252
|
|
|
253
|
+
/* A parent with a zero-length axis has no cell for the leaf to start at
|
|
254
|
+
(and prod[] below would divide by zero). */
|
|
255
|
+
if (prod[0] == 0) return 0;
|
|
256
|
+
|
|
250
257
|
/* Compose base offset first. We need the per-dim base position
|
|
251
258
|
to validate stride composition against parent dim bounds (a small
|
|
252
259
|
forward stride starting near the end of a parent dim wraps into
|
|
@@ -274,11 +281,15 @@ ca_stride_compose_through (CAStride *leaf, CAStride *parent,
|
|
|
274
281
|
|
|
275
282
|
/* Compose each leaf dim's stride.
|
|
276
283
|
Validity rule: leaf dim k must advance exactly one parent dim
|
|
277
|
-
(not cross multiple parent dims)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
284
|
+
(not cross multiple parent dims), and every parent dim must stay
|
|
285
|
+
within its bounds across the leaf's full extent *given the base
|
|
286
|
+
position*. Several leaf dims can advance the same parent dim (a block
|
|
287
|
+
of a reshape: rows step 4 parent columns, columns step 1), so the
|
|
288
|
+
bound is on the sum of their extents, kept in lo[] / hi[]. Otherwise
|
|
289
|
+
the leaf's traversal would wrap across parent dim boundaries, which
|
|
290
|
+
is a non-strided access pattern that cannot be folded. */
|
|
291
|
+
ca_size_t lo[CA_RANK_MAX], hi[CA_RANK_MAX];
|
|
292
|
+
for (m = 0; m < parent->ndim; m++) lo[m] = hi[m] = base_idx[m];
|
|
282
293
|
for (k = 0; k < leaf->ndim; k++) {
|
|
283
294
|
if (leaf->strides[k] % parent->bytes != 0) return 0;
|
|
284
295
|
ca_size_t advance = leaf->strides[k] / parent->bytes;
|
|
@@ -298,20 +309,15 @@ ca_stride_compose_through (CAStride *leaf, CAStride *parent,
|
|
|
298
309
|
}
|
|
299
310
|
if (advance != 0) return 0;
|
|
300
311
|
if (nonzero_count > 1) return 0; /* crosses parent dims */
|
|
301
|
-
if (nonzero_count == 1) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
ca_size_t final_pos =
|
|
306
|
-
base_idx[nonzero_dim] + (leaf->dim[k] - 1) * nonzero_step;
|
|
307
|
-
if (nonzero_step > 0) {
|
|
308
|
-
if (final_pos >= parent->dim[nonzero_dim]) return 0;
|
|
309
|
-
} else {
|
|
310
|
-
if (final_pos < 0) return 0;
|
|
311
|
-
}
|
|
312
|
+
if (nonzero_count == 1 && leaf->dim[k] > 1) {
|
|
313
|
+
ca_size_t extent = (leaf->dim[k] - 1) * nonzero_step;
|
|
314
|
+
if (extent > 0) hi[nonzero_dim] += extent;
|
|
315
|
+
else lo[nonzero_dim] += extent;
|
|
312
316
|
}
|
|
313
317
|
out_strides[k] = composed;
|
|
314
318
|
}
|
|
319
|
+
for (m = 0; m < parent->ndim; m++)
|
|
320
|
+
if (lo[m] < 0 || hi[m] >= parent->dim[m]) return 0;
|
|
315
321
|
|
|
316
322
|
/* A leaf cell wider than the remainder of its first parent element
|
|
317
323
|
(CARefer reinterpreting two float64 as one complex128) covers several
|
|
@@ -675,14 +681,20 @@ ca_stride_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
|
675
681
|
}
|
|
676
682
|
}
|
|
677
683
|
else {
|
|
684
|
+
/* Peel the axes from the innermost: a % dim[k] is the index on
|
|
685
|
+
axis k and a / dim[k] carries the rest outward. The outermost
|
|
686
|
+
axis takes whatever is left, so ndim-1 divisions per address. */
|
|
687
|
+
ca_size_t *dim = ca->dim;
|
|
688
|
+
int8_t ndim = ca->ndim;
|
|
678
689
|
for ( i = 0; i < n; i++ ) {
|
|
679
|
-
ca_size_t
|
|
690
|
+
ca_size_t a = addrs[i];
|
|
680
691
|
ca_size_t off = ebase;
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
off +=
|
|
692
|
+
for ( k = ndim - 1; k > 0; k-- ) {
|
|
693
|
+
ca_size_t q = a / dim[k];
|
|
694
|
+
off += ( a - q * dim[k] ) * esteps[k];
|
|
695
|
+
a = q;
|
|
684
696
|
}
|
|
685
|
-
paddrs[i] = off;
|
|
697
|
+
paddrs[i] = off + a * esteps[0];
|
|
686
698
|
}
|
|
687
699
|
}
|
|
688
700
|
ca_xfer_addrs(root, n, paddrs, data, dir);
|
|
@@ -817,9 +829,12 @@ ca_stride_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
817
829
|
|
|
818
830
|
/* A reshape over a 1-D cold root (ndim != root->ndim): the request has no
|
|
819
831
|
box in the root's single axis, but the root cells it touches lie in one
|
|
820
|
-
flat span.
|
|
821
|
-
it, as xfer_all does for the whole view. A PUT
|
|
822
|
-
the
|
|
832
|
+
flat span. A GET asks the root for that span once and walks the
|
|
833
|
+
request over it, as xfer_all does for the whole view. A PUT hands the
|
|
834
|
+
root the list of the requested cells' addresses instead: sending the
|
|
835
|
+
span back would write the cells between them too, and a root that
|
|
836
|
+
repeats its cells (CATile) would have a stale copy land after the
|
|
837
|
+
written one. */
|
|
823
838
|
if (aligned && !root->ptr && ca_func[root->obj_type].xfer_stride
|
|
824
839
|
&& ca->bytes == root->bytes && root->ndim == 1
|
|
825
840
|
&& root_base % root->bytes == 0) {
|
|
@@ -832,15 +847,33 @@ ca_stride_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
832
847
|
}
|
|
833
848
|
if ( span_lo >= 0 && span_hi <= root->elements * root->bytes ) {
|
|
834
849
|
volatile VALUE holder;
|
|
835
|
-
ca_size_t rlo = span_lo / root->bytes;
|
|
836
|
-
ca_size_t rcount = (span_hi - span_lo) / root->bytes;
|
|
837
|
-
ca_size_t rstep = root->bytes;
|
|
838
|
-
char *scratch = ALLOCV_N(char, holder, rcount * root->bytes);
|
|
839
|
-
ca_xfer_stride(root, &rlo, &rcount, &rstep, scratch, CA_XFER_GET);
|
|
840
|
-
ca_xfer_strided_walk(scratch + (root_base - span_lo), ca->bytes, ndim,
|
|
841
|
-
counts, root_stride, d, dir);
|
|
842
850
|
if ( dir == CA_XFER_PUT ) {
|
|
843
|
-
|
|
851
|
+
ca_size_t n = 1, m = 0, idx[CA_RANK_MAX];
|
|
852
|
+
ca_size_t *addrs;
|
|
853
|
+
for (k = 0; k < ndim; k++) {
|
|
854
|
+
n *= counts[k];
|
|
855
|
+
idx[k] = 0;
|
|
856
|
+
}
|
|
857
|
+
addrs = ALLOCV_N(ca_size_t, holder, n);
|
|
858
|
+
/* empty: the slot returns on an empty region at its entry */
|
|
859
|
+
while (1) {
|
|
860
|
+
ca_size_t off = root_base;
|
|
861
|
+
for (k = 0; k < ndim; k++) off += idx[k] * root_stride[k];
|
|
862
|
+
addrs[m++] = off / root->bytes;
|
|
863
|
+
k = ndim - 1;
|
|
864
|
+
while (k >= 0) { if (++idx[k] < counts[k]) break; idx[k] = 0; k--; }
|
|
865
|
+
if (k < 0) break;
|
|
866
|
+
}
|
|
867
|
+
ca_xfer_addrs(root, n, addrs, d, CA_XFER_PUT);
|
|
868
|
+
}
|
|
869
|
+
else {
|
|
870
|
+
ca_size_t rlo = span_lo / root->bytes;
|
|
871
|
+
ca_size_t rcount = (span_hi - span_lo) / root->bytes;
|
|
872
|
+
ca_size_t rstep = root->bytes;
|
|
873
|
+
char *scratch = ALLOCV_N(char, holder, rcount * root->bytes);
|
|
874
|
+
ca_xfer_stride(root, &rlo, &rcount, &rstep, scratch, CA_XFER_GET);
|
|
875
|
+
ca_xfer_strided_walk(scratch + (root_base - span_lo), ca->bytes, ndim,
|
|
876
|
+
counts, root_stride, d, dir);
|
|
844
877
|
}
|
|
845
878
|
ALLOCV_END(holder);
|
|
846
879
|
return;
|
|
@@ -1114,10 +1147,12 @@ static int ca_layout_is_contiguous (int8_t ndim, const ca_size_t *dim,
|
|
|
1114
1147
|
folds onward from itself, so the answer is the one for the root it folds
|
|
1115
1148
|
to. What is left is the
|
|
1116
1149
|
boundary views that compute or fetch their contents -- CAObject, the lazy
|
|
1117
|
-
per-element transforms, whatever a companion gem installed
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1150
|
+
per-element transforms, whatever a companion gem installed. All of them
|
|
1151
|
+
answer a region request: through their xfer_stride slot, or, when a type
|
|
1152
|
+
leaves it out, through the dispatcher's default, which hands the cells'
|
|
1153
|
+
addresses to xfer_addrs. Attaching one instead would produce all of it
|
|
1154
|
+
and write all of it back, so a cell nobody touched would go through the
|
|
1155
|
+
view's conversion both ways. */
|
|
1121
1156
|
int
|
|
1122
1157
|
ca_root_lends_no_memory (void *ap)
|
|
1123
1158
|
{
|
|
@@ -1135,7 +1170,7 @@ ca_root_lends_no_memory (void *ap)
|
|
|
1135
1170
|
ca_stride_compose_to_root((CAStride *) root, &below, cs, &base);
|
|
1136
1171
|
return ca_root_lends_no_memory(below);
|
|
1137
1172
|
}
|
|
1138
|
-
return
|
|
1173
|
+
return 1;
|
|
1139
1174
|
}
|
|
1140
1175
|
|
|
1141
1176
|
/* The same question for the parent of a view that is not itself in the
|
|
@@ -1431,8 +1466,10 @@ ca_stride_func_xfer_all (void *ap, void *data, int dir)
|
|
|
1431
1466
|
the request is exact) and ca->bytes == root->bytes (no byte
|
|
1432
1467
|
reinterpret, so the span endpoints are whole root elements). A wider
|
|
1433
1468
|
lazy root has no single strided box to ask for, so it takes the
|
|
1434
|
-
whole-root fallback below -- correct, just not partial.
|
|
1435
|
-
|
|
1469
|
+
whole-root fallback below -- correct, just not partial. Reads only:
|
|
1470
|
+
a write goes to the root as the list of its cells below, since
|
|
1471
|
+
sending the span back would write the cells between them too. */
|
|
1472
|
+
if ( dir == CA_XFER_GET && root->ndim == 1 && ca->bytes == root->bytes ) {
|
|
1436
1473
|
ca_size_t span_lo = composed_base;
|
|
1437
1474
|
ca_size_t span_hi = composed_base + ca->bytes;
|
|
1438
1475
|
int8_t k;
|
|
@@ -1449,13 +1486,10 @@ ca_stride_func_xfer_all (void *ap, void *data, int dir)
|
|
|
1449
1486
|
char *scratch = ALLOCV_N(char, holder, rcount * root->bytes);
|
|
1450
1487
|
ca_xfer_stride(root, &rlo, &rcount, &rstep, scratch, CA_XFER_GET);
|
|
1451
1488
|
ca->ptr = ptr;
|
|
1452
|
-
ca_stride_xfer_with_layout(ca,
|
|
1489
|
+
ca_stride_xfer_with_layout(ca, 0,
|
|
1453
1490
|
scratch + (composed_base - span_lo),
|
|
1454
1491
|
composed_strides);
|
|
1455
1492
|
ca->ptr = ptr0;
|
|
1456
|
-
if ( dir == CA_XFER_PUT ) {
|
|
1457
|
-
ca_xfer_stride(root, &rlo, &rcount, &rstep, scratch, CA_XFER_PUT);
|
|
1458
|
-
}
|
|
1459
1493
|
ALLOCV_END(holder);
|
|
1460
1494
|
}
|
|
1461
1495
|
return;
|
|
@@ -1581,6 +1615,51 @@ ca_stride_func_xfer_all (void *ap, void *data, int dir)
|
|
|
1581
1615
|
}
|
|
1582
1616
|
}
|
|
1583
1617
|
|
|
1618
|
+
/* Whether a layout of `ndim` axes (dims, byte strides, byte base) addresses
|
|
1619
|
+
each cell of a packed array of the same number of cells exactly once:
|
|
1620
|
+
ordered by the size of their strides, the axes longer than one must be
|
|
1621
|
+
packed (the smallest stride is `bytes`, each next one the previous times
|
|
1622
|
+
its axis length), and the lowest address must be 0. Equal counts alone
|
|
1623
|
+
do not say this: a zero or repeated stride covers fewer cells. */
|
|
1624
|
+
static int
|
|
1625
|
+
ca_stride_layout_is_permutation (int8_t ndim, const ca_size_t *dim,
|
|
1626
|
+
const ca_size_t *strides, ca_size_t base,
|
|
1627
|
+
ca_size_t bytes)
|
|
1628
|
+
{
|
|
1629
|
+
int8_t order[CA_RANK_MAX];
|
|
1630
|
+
int8_t n = 0, i, j;
|
|
1631
|
+
ca_size_t lowest = base, expect = bytes;
|
|
1632
|
+
|
|
1633
|
+
for (i=0; i<ndim; i++) {
|
|
1634
|
+
if ( dim[i] <= 1 ) {
|
|
1635
|
+
continue;
|
|
1636
|
+
}
|
|
1637
|
+
if ( strides[i] < 0 ) {
|
|
1638
|
+
lowest += (dim[i] - 1) * strides[i];
|
|
1639
|
+
}
|
|
1640
|
+
for (j=n; j>0; j--) {
|
|
1641
|
+
ca_size_t a = strides[order[j-1]], b = strides[i];
|
|
1642
|
+
if ( (a < 0 ? -a : a) <= (b < 0 ? -b : b) ) {
|
|
1643
|
+
break;
|
|
1644
|
+
}
|
|
1645
|
+
order[j] = order[j-1];
|
|
1646
|
+
}
|
|
1647
|
+
order[j] = i;
|
|
1648
|
+
n++;
|
|
1649
|
+
}
|
|
1650
|
+
if ( lowest != 0 ) {
|
|
1651
|
+
return 0;
|
|
1652
|
+
}
|
|
1653
|
+
for (i=0; i<n; i++) {
|
|
1654
|
+
ca_size_t s = strides[order[i]];
|
|
1655
|
+
if ( (s < 0 ? -s : s) != expect ) {
|
|
1656
|
+
return 0;
|
|
1657
|
+
}
|
|
1658
|
+
expect *= dim[order[i]];
|
|
1659
|
+
}
|
|
1660
|
+
return 1;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1584
1663
|
static void
|
|
1585
1664
|
ca_stride_func_fill_data (void *ap, void *ptr)
|
|
1586
1665
|
{
|
|
@@ -1616,7 +1695,9 @@ ca_stride_func_fill_data (void *ap, void *ptr)
|
|
|
1616
1695
|
into scratch only to overwrite every byte with *ptr -- wasted
|
|
1617
1696
|
work. Delegate to root.fill_data instead.
|
|
1618
1697
|
Safety gates:
|
|
1619
|
-
(1) elements match
|
|
1698
|
+
(1) elements match and the composed layout addresses each root cell
|
|
1699
|
+
exactly once -- our view covers every root cell (a zero or
|
|
1700
|
+
repeated stride has as many cells but covers fewer);
|
|
1620
1701
|
(2) bytes match -- our cell width equals root's cell width.
|
|
1621
1702
|
Without (2), a type-reinterpreting CAStride (CAField over a
|
|
1622
1703
|
complex entity for `.real`/`.imag`) would corrupt root: root
|
|
@@ -1628,7 +1709,9 @@ ca_stride_func_fill_data (void *ap, void *ptr)
|
|
|
1628
1709
|
if ( ca_func[root->obj_type].attach != ca_stride_func.attach &&
|
|
1629
1710
|
ca_func[root->obj_type].attach != ca_window_func.attach &&
|
|
1630
1711
|
ca->elements == root->elements &&
|
|
1631
|
-
ca->bytes == root->bytes
|
|
1712
|
+
ca->bytes == root->bytes &&
|
|
1713
|
+
ca_stride_layout_is_permutation(ca->ndim, ca->dim, composed_strides,
|
|
1714
|
+
composed_base, bytes) ) {
|
|
1632
1715
|
ca_func[root->obj_type].fill_data(root, ptr);
|
|
1633
1716
|
return;
|
|
1634
1717
|
}
|
|
@@ -1686,19 +1769,19 @@ ca_stride_func_fill_data (void *ap, void *ptr)
|
|
|
1686
1769
|
}
|
|
1687
1770
|
case 2: {
|
|
1688
1771
|
int16_t v; memcpy(&v, ptr, 2);
|
|
1689
|
-
|
|
1772
|
+
ca_u_int16_t *d = (ca_u_int16_t *) dst;
|
|
1690
1773
|
for (i = 0; i < inner_count; i++) d[i] = v;
|
|
1691
1774
|
break;
|
|
1692
1775
|
}
|
|
1693
1776
|
case 4: {
|
|
1694
1777
|
int32_t v; memcpy(&v, ptr, 4);
|
|
1695
|
-
|
|
1778
|
+
ca_u_int32_t *d = (ca_u_int32_t *) dst;
|
|
1696
1779
|
for (i = 0; i < inner_count; i++) d[i] = v;
|
|
1697
1780
|
break;
|
|
1698
1781
|
}
|
|
1699
1782
|
case 8: {
|
|
1700
1783
|
int64_t v; memcpy(&v, ptr, 8);
|
|
1701
|
-
|
|
1784
|
+
ca_u_int64_t *d = (ca_u_int64_t *) dst;
|
|
1702
1785
|
for (i = 0; i < inner_count; i++) d[i] = v;
|
|
1703
1786
|
break;
|
|
1704
1787
|
}
|
|
@@ -2090,6 +2173,13 @@ rb_cs_initialize_copy (VALUE self, VALUE other)
|
|
|
2090
2173
|
ca_stride_setup(ca, cs->obj_type, cs->parent, cs->data_type, cs->bytes,
|
|
2091
2174
|
cs->ndim, cs->dim, cs->strides, cs->base_offset);
|
|
2092
2175
|
rb_ca_set_parent(self, rb_ca_parent(other));
|
|
2176
|
+
if ( ca_test_flag(cs, CA_FLAG_FOLDED) ) {
|
|
2177
|
+
/* the copy has the same @parent, so it answers to the same source */
|
|
2178
|
+
CArray *src = ca_fold_source((CArray *) cs);
|
|
2179
|
+
if ( src ) {
|
|
2180
|
+
ca_fold_note_source((CArray *) ca, src);
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2093
2183
|
return self;
|
|
2094
2184
|
}
|
|
2095
2185
|
|
|
@@ -2164,11 +2254,11 @@ rb_ca_as_strided (int argc, VALUE *argv, VALUE self)
|
|
|
2164
2254
|
ca_check_rank_fits(len, NULL);
|
|
2165
2255
|
ndim = (int8_t) len;
|
|
2166
2256
|
for (i = 0; i < len; i++) {
|
|
2167
|
-
shape[i] =
|
|
2168
|
-
strides[i] =
|
|
2257
|
+
shape[i] = ca_integer_arg(RARRAY_AREF(rshape, i), "a length", NULL);
|
|
2258
|
+
strides[i] = ca_integer_arg(RARRAY_AREF(rstrides, i), "a stride", NULL);
|
|
2169
2259
|
}
|
|
2170
2260
|
if (! NIL_P(roffset)) {
|
|
2171
|
-
base_offset =
|
|
2261
|
+
base_offset = ca_integer_arg(roffset, "offset", NULL);
|
|
2172
2262
|
}
|
|
2173
2263
|
|
|
2174
2264
|
VALUE obj = rb_ca_stride_new(self, parent->data_type, parent->bytes,
|
|
@@ -2215,12 +2305,12 @@ rb_ca_sliding_windows (int argc, VALUE *argv, VALUE self)
|
|
|
2215
2305
|
RARRAY_LEN(wary), (int) ndim);
|
|
2216
2306
|
}
|
|
2217
2307
|
for (i = 0; i < ndim; i++) {
|
|
2218
|
-
window[i] =
|
|
2308
|
+
window[i] = ca_integer_arg(RARRAY_AREF(wary, i), "a window size", NULL);
|
|
2219
2309
|
}
|
|
2220
2310
|
}
|
|
2221
2311
|
else if (nargs == ndim) {
|
|
2222
2312
|
for (i = 0; i < ndim; i++) {
|
|
2223
|
-
window[i] =
|
|
2313
|
+
window[i] = ca_integer_arg(RARRAY_AREF(rposary, i), "a window size", NULL);
|
|
2224
2314
|
}
|
|
2225
2315
|
}
|
|
2226
2316
|
else {
|
|
@@ -2239,11 +2329,11 @@ rb_ca_sliding_windows (int argc, VALUE *argv, VALUE self)
|
|
|
2239
2329
|
RARRAY_LEN(rstep), (int) ndim);
|
|
2240
2330
|
}
|
|
2241
2331
|
for (i = 0; i < ndim; i++) {
|
|
2242
|
-
step[i] =
|
|
2332
|
+
step[i] = ca_integer_arg(RARRAY_AREF(rstep, i), "a step", NULL);
|
|
2243
2333
|
}
|
|
2244
2334
|
}
|
|
2245
2335
|
else {
|
|
2246
|
-
ca_size_t s =
|
|
2336
|
+
ca_size_t s = ca_integer_arg(rstep, "step", NULL);
|
|
2247
2337
|
for (i = 0; i < ndim; i++) step[i] = s;
|
|
2248
2338
|
}
|
|
2249
2339
|
|
|
@@ -2326,13 +2416,13 @@ rb_ca_unfold (int argc, VALUE *argv, VALUE self)
|
|
|
2326
2416
|
}
|
|
2327
2417
|
nspatial = (int8_t) RARRAY_LEN(wary);
|
|
2328
2418
|
for (i = 0; i < nspatial; i++) {
|
|
2329
|
-
window[i] =
|
|
2419
|
+
window[i] = ca_integer_arg(RARRAY_AREF(wary, i), "a window size", NULL);
|
|
2330
2420
|
}
|
|
2331
2421
|
}
|
|
2332
2422
|
else if (nargs >= 1 && nargs <= ndim) {
|
|
2333
2423
|
nspatial = (int8_t) nargs;
|
|
2334
2424
|
for (i = 0; i < nspatial; i++) {
|
|
2335
|
-
window[i] =
|
|
2425
|
+
window[i] = ca_integer_arg(RARRAY_AREF(rposary, i), "a window size", NULL);
|
|
2336
2426
|
}
|
|
2337
2427
|
}
|
|
2338
2428
|
else {
|
|
@@ -2355,11 +2445,11 @@ rb_ca_unfold (int argc, VALUE *argv, VALUE self)
|
|
|
2355
2445
|
RARRAY_LEN(rstep), (int) nspatial);
|
|
2356
2446
|
}
|
|
2357
2447
|
for (i = 0; i < nspatial; i++) {
|
|
2358
|
-
step[i] =
|
|
2448
|
+
step[i] = ca_integer_arg(RARRAY_AREF(rstep, i), "a step", NULL);
|
|
2359
2449
|
}
|
|
2360
2450
|
}
|
|
2361
2451
|
else {
|
|
2362
|
-
ca_size_t s =
|
|
2452
|
+
ca_size_t s = ca_integer_arg(rstep, "step", NULL);
|
|
2363
2453
|
for (i = 0; i < nspatial; i++) step[i] = s;
|
|
2364
2454
|
}
|
|
2365
2455
|
|
|
@@ -2441,12 +2531,12 @@ rb_ca_block_view (int argc, VALUE *argv, VALUE self)
|
|
|
2441
2531
|
RARRAY_LEN(bary), (int) ndim);
|
|
2442
2532
|
}
|
|
2443
2533
|
for (i = 0; i < ndim; i++) {
|
|
2444
|
-
block[i] =
|
|
2534
|
+
block[i] = ca_integer_arg(RARRAY_AREF(bary, i), "a block size", NULL);
|
|
2445
2535
|
}
|
|
2446
2536
|
}
|
|
2447
2537
|
else if (nargs == ndim) {
|
|
2448
2538
|
for (i = 0; i < ndim; i++) {
|
|
2449
|
-
block[i] =
|
|
2539
|
+
block[i] = ca_integer_arg(RARRAY_AREF(rposary, i), "a block size", NULL);
|
|
2450
2540
|
}
|
|
2451
2541
|
}
|
|
2452
2542
|
else {
|
|
@@ -2571,7 +2661,12 @@ rb_ca_dim_view (int argc, VALUE *argv, VALUE self)
|
|
|
2571
2661
|
if (! seen[i]) imap[k++] = i;
|
|
2572
2662
|
}
|
|
2573
2663
|
|
|
2574
|
-
|
|
2664
|
+
{
|
|
2665
|
+
/* A reordering of the axes, as transpose is: a Face stays its Face. */
|
|
2666
|
+
volatile VALUE obj = rb_ca_trans_new(self, imap);
|
|
2667
|
+
CA_WRAPPER_LIFT(obj, self, parent);
|
|
2668
|
+
return obj;
|
|
2669
|
+
}
|
|
2575
2670
|
}
|
|
2576
2671
|
|
|
2577
2672
|
/* flip(*axes) -- reverses the listed axes by negating their strides; with no
|
|
@@ -2740,14 +2835,14 @@ rb_ca_diagonal (int argc, VALUE *argv, VALUE self)
|
|
|
2740
2835
|
|
|
2741
2836
|
/* offset from positional or keyword (not both) */
|
|
2742
2837
|
if (nargs == 0) {
|
|
2743
|
-
if (! NIL_P(roffset)) offset =
|
|
2838
|
+
if (! NIL_P(roffset)) offset = ca_integer_arg(roffset, "offset", NULL);
|
|
2744
2839
|
}
|
|
2745
2840
|
else if (nargs == 1) {
|
|
2746
2841
|
if (! NIL_P(roffset)) {
|
|
2747
2842
|
rb_raise(rb_eArgError,
|
|
2748
2843
|
"diagonal: give offset positionally OR as keyword, not both");
|
|
2749
2844
|
}
|
|
2750
|
-
offset =
|
|
2845
|
+
offset = ca_integer_arg(RARRAY_AREF(rposary, 0), "offset", NULL);
|
|
2751
2846
|
}
|
|
2752
2847
|
else {
|
|
2753
2848
|
rb_raise(rb_eArgError,
|
data/ext/ca_obj_string.c
CHANGED
|
@@ -216,7 +216,11 @@ ca_string_refuse_cell (VALUE v, const char *where)
|
|
|
216
216
|
"UNDEF masks a cell)", where, rb_obj_classname(v));
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
-
/* Every cell of `parent` that is not masked is a String.
|
|
219
|
+
/* Every cell of `parent` that is not masked is a String. Under a masked
|
|
220
|
+
cell of a parent that can be written, a value that is not a String (the
|
|
221
|
+
0 an object array starts with) becomes an empty String, so that the cell
|
|
222
|
+
is still a String once it is unmasked. A view is written through its
|
|
223
|
+
value array, which leaves the mask as it is. */
|
|
220
224
|
static void
|
|
221
225
|
ca_string_check_cells (VALUE parent_val, CArray *parent)
|
|
222
226
|
{
|
|
@@ -226,8 +230,14 @@ ca_string_check_cells (VALUE parent_val, CArray *parent)
|
|
|
226
230
|
VALUE *p = (VALUE *) parent->ptr;
|
|
227
231
|
boolean8_t *m = ( parent->mask && parent->mask->ptr )
|
|
228
232
|
? (boolean8_t *) parent->mask->ptr : NULL;
|
|
233
|
+
int writable = ! ca_is_readonly(parent);
|
|
229
234
|
for (i = 0; i < parent->elements; i++) {
|
|
230
|
-
if ( m && m[i] )
|
|
235
|
+
if ( m && m[i] ) {
|
|
236
|
+
if ( writable && ! RB_TYPE_P(p[i], T_STRING) ) {
|
|
237
|
+
p[i] = rb_utf8_str_new("", 0);
|
|
238
|
+
}
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
231
241
|
if ( ! RB_TYPE_P(p[i], T_STRING) ) {
|
|
232
242
|
snprintf(where, sizeof(where), "cell %" PRId64, (int64_t) i);
|
|
233
243
|
ca_string_refuse_cell(p[i], where);
|
|
@@ -238,6 +248,7 @@ ca_string_check_cells (VALUE parent_val, CArray *parent)
|
|
|
238
248
|
volatile VALUE list =
|
|
239
249
|
rb_funcall(rb_funcall(parent_val, rb_intern("flatten"), 0),
|
|
240
250
|
rb_intern("to_a"), 0);
|
|
251
|
+
volatile VALUE values = Qnil, raw = Qnil;
|
|
241
252
|
long n = RARRAY_LEN(list), j;
|
|
242
253
|
for (j = 0; j < n; j++) {
|
|
243
254
|
VALUE v = rb_ary_entry(list, j);
|
|
@@ -247,6 +258,20 @@ ca_string_check_cells (VALUE parent_val, CArray *parent)
|
|
|
247
258
|
ca_string_refuse_cell(v, where);
|
|
248
259
|
}
|
|
249
260
|
}
|
|
261
|
+
if ( ! ca_is_readonly(parent) ) {
|
|
262
|
+
for (j = 0; j < n; j++) {
|
|
263
|
+
if ( rb_ary_entry(list, j) != CA_UNDEF ) continue;
|
|
264
|
+
if ( NIL_P(values) ) {
|
|
265
|
+
values = rb_funcall(rb_funcall(parent_val, rb_intern("value"), 0),
|
|
266
|
+
rb_intern("flatten"), 0);
|
|
267
|
+
raw = rb_funcall(values, rb_intern("to_a"), 0);
|
|
268
|
+
}
|
|
269
|
+
if ( ! RB_TYPE_P(rb_ary_entry(raw, j), T_STRING) ) {
|
|
270
|
+
rb_funcall(values, rb_intern("[]="), 2, LONG2NUM(j),
|
|
271
|
+
rb_utf8_str_new("", 0));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
250
275
|
}
|
|
251
276
|
}
|
|
252
277
|
|
data/ext/ca_obj_tile.c
CHANGED
|
@@ -108,6 +108,8 @@ ca_tile_setup (CATile *ca, CArray *parent, ca_size_t *reps)
|
|
|
108
108
|
ca->parent = parent;
|
|
109
109
|
ca->attach = 0;
|
|
110
110
|
ca->nosync = 0;
|
|
111
|
+
ca->reps = NULL; /* set before either allocation can raise */
|
|
112
|
+
ca->dim = NULL;
|
|
111
113
|
ca->reps = ALLOC_N(ca_size_t, ndim);
|
|
112
114
|
ca->dim = ALLOC_N(ca_size_t, ndim);
|
|
113
115
|
|
|
@@ -120,15 +122,33 @@ ca_tile_setup (CATile *ca, CArray *parent, ca_size_t *reps)
|
|
|
120
122
|
return 0;
|
|
121
123
|
}
|
|
122
124
|
|
|
125
|
+
typedef struct {
|
|
126
|
+
CATile *ca;
|
|
127
|
+
CArray *parent;
|
|
128
|
+
ca_size_t *reps;
|
|
129
|
+
} ca_tile_new_arg;
|
|
130
|
+
|
|
131
|
+
static VALUE
|
|
132
|
+
ca_tile_new_setup (VALUE varg)
|
|
133
|
+
{
|
|
134
|
+
ca_tile_new_arg *a = (ca_tile_new_arg *) varg;
|
|
135
|
+
ca_tile_setup(a->ca, a->parent, a->reps);
|
|
136
|
+
return Qnil;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* The setup allocates reps and dim after the struct: when either fails,
|
|
140
|
+
the struct goes too. */
|
|
123
141
|
CATile *
|
|
124
142
|
ca_tile_new (CArray *parent, ca_size_t *reps)
|
|
125
143
|
{
|
|
126
|
-
|
|
144
|
+
ca_tile_new_arg a;
|
|
127
145
|
ca_tile_setup(NULL, parent, reps);
|
|
128
|
-
ca
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
146
|
+
a.ca = ALLOC(CATile);
|
|
147
|
+
a.parent = parent;
|
|
148
|
+
a.reps = reps;
|
|
149
|
+
ca_fill_or_free((CArray *) a.ca, ca_tile_new_setup, (VALUE) &a);
|
|
150
|
+
ca_fill_or_free((CArray *) a.ca, ca_view_inherit_mask, (VALUE) a.ca);
|
|
151
|
+
return a.ca;
|
|
132
152
|
}
|
|
133
153
|
|
|
134
154
|
static void
|
|
@@ -548,7 +568,7 @@ rb_ca_tile (int argc, VALUE *argv, VALUE self)
|
|
|
548
568
|
len, ca->ndim);
|
|
549
569
|
}
|
|
550
570
|
for ( i = 0; i < ca->ndim; i++ ) {
|
|
551
|
-
reps[i] =
|
|
571
|
+
reps[i] = ca_integer_arg(rb_ary_entry(ary, i), "a repeat count", NULL);
|
|
552
572
|
}
|
|
553
573
|
}
|
|
554
574
|
else {
|
|
@@ -559,7 +579,7 @@ rb_ca_tile (int argc, VALUE *argv, VALUE self)
|
|
|
559
579
|
ca->ndim, argc);
|
|
560
580
|
}
|
|
561
581
|
for ( i = 0; i < ca->ndim; i++ ) {
|
|
562
|
-
reps[i] =
|
|
582
|
+
reps[i] = ca_integer_arg(argv[i], "a repeat count", NULL);
|
|
563
583
|
}
|
|
564
584
|
}
|
|
565
585
|
|
|
@@ -623,6 +643,7 @@ Init_ca_obj_tile (void)
|
|
|
623
643
|
&catile_data_type,
|
|
624
644
|
rb_cCATileMask,
|
|
625
645
|
&catile_mask_data_type, &ca_tile_func, sizeof(ca_tile_func));
|
|
646
|
+
ca_register_cell_moving_view(CA_OBJ_TILE);
|
|
626
647
|
rb_define_const(rb_cObject, "CA_OBJ_TILE", INT2NUM(CA_OBJ_TILE));
|
|
627
648
|
|
|
628
649
|
rb_define_method(rb_cCArray, "tile", rb_ca_tile, -1);
|
data/ext/ca_obj_transpose.c
CHANGED
|
@@ -42,8 +42,8 @@ ca_trans_setup (CAStride *ca, CArray *parent, ca_size_t *imap)
|
|
|
42
42
|
"specified %i-th dimension number out of range", i);
|
|
43
43
|
}
|
|
44
44
|
if (map[idim] != -1) {
|
|
45
|
-
rb_raise(rb_eArgError,
|
|
46
|
-
|
|
45
|
+
rb_raise(rb_eArgError, "%s: axis %" PRId64 " is given twice",
|
|
46
|
+
ca_calling_method_name(), (int64_t) idim);
|
|
47
47
|
}
|
|
48
48
|
map[idim] = i;
|
|
49
49
|
newdim[i] = dim0[idim];
|
|
@@ -120,10 +120,14 @@ rb_ca_trans (int argc, VALUE *argv, VALUE self)
|
|
|
120
120
|
for (i = 0; i < ca->ndim; i++) imap[i] = ca->ndim - i - 1;
|
|
121
121
|
}
|
|
122
122
|
else if (argc == ca->ndim) {
|
|
123
|
-
|
|
123
|
+
/* Each axis read as every axis argument is: negative from the end. */
|
|
124
|
+
for (i = 0; i < ca->ndim; i++) {
|
|
125
|
+
imap[i] = ca_normalize_axis_arg(argv[i], ca->ndim, NULL);
|
|
126
|
+
}
|
|
124
127
|
}
|
|
125
128
|
else {
|
|
126
|
-
rb_raise(rb_eArgError, "
|
|
129
|
+
rb_raise(rb_eArgError, "%s: %d axes given for ndim %d",
|
|
130
|
+
ca_calling_method_name(), argc, (int) ca->ndim);
|
|
127
131
|
}
|
|
128
132
|
|
|
129
133
|
obj = rb_ca_trans_new(self, imap);
|
data/ext/ca_obj_triop.c
CHANGED
|
@@ -267,9 +267,11 @@ pull_operand (CArray *op, int is_scalar, const ca_lazy_req_t *req,
|
|
|
267
267
|
|
|
268
268
|
/* Evaluate the cells a request names into `data` (packed, n cells). */
|
|
269
269
|
static void
|
|
270
|
-
|
|
270
|
+
ca_triop_eval_cells (void *node, const ca_lazy_req_t *req, void *data, int dir)
|
|
271
271
|
{
|
|
272
|
+
CATriOp *to = (CATriOp *) node;
|
|
272
273
|
ca_size_t slab_n = req->n;
|
|
274
|
+
(void) dir;
|
|
273
275
|
void *scratch2, *scratch3;
|
|
274
276
|
ca_size_t op2_step, op3_step;
|
|
275
277
|
|
|
@@ -316,6 +318,12 @@ ca_triop_eval (CATriOp *to, const ca_lazy_req_t *req, void *data)
|
|
|
316
318
|
ca_lazy_arena_release(scratch2);
|
|
317
319
|
}
|
|
318
320
|
|
|
321
|
+
static void
|
|
322
|
+
ca_triop_eval (CATriOp *to, const ca_lazy_req_t *req, void *data)
|
|
323
|
+
{
|
|
324
|
+
ca_lazy_eval_recorded(to, 3, to->operands, 0, NULL, ca_triop_eval_cells, req, data, CA_XFER_GET);
|
|
325
|
+
}
|
|
326
|
+
|
|
319
327
|
static void
|
|
320
328
|
ca_triop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
321
329
|
ca_size_t *strides, void *data, int dir)
|
|
@@ -542,6 +550,9 @@ rb_ca_triop_build (VALUE cary1, VALUE cary2, VALUE cary3, uint16_t op_id)
|
|
|
542
550
|
r3 = ca_lazy_settle_scalar(r3, r3_scalar);
|
|
543
551
|
}
|
|
544
552
|
|
|
553
|
+
ca_refuse_without_common_type(r1, r2);
|
|
554
|
+
ca_refuse_without_common_type(r1, r3);
|
|
555
|
+
ca_refuse_without_common_type(r2, r3);
|
|
545
556
|
TypedData_Get_Struct(r1, CArray, &carray_data_type, op1);
|
|
546
557
|
TypedData_Get_Struct(r2, CArray, &carray_data_type, op2);
|
|
547
558
|
TypedData_Get_Struct(r3, CArray, &carray_data_type, op3);
|