carray 3.0.0 → 3.0.1
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 +325 -3
- data/{NEWS.md → CHANGELOG.v1.md} +1 -1
- data/README.md +32 -32
- data/carray.gemspec +12 -8
- data/ext/ca_axis_group.c +55 -19
- data/ext/ca_binop_dispatch.c +5 -6
- data/ext/ca_binop_dispatch.h +0 -7
- data/ext/ca_categorical_iterator.c +13 -13
- data/ext/ca_for_each_element.h +6 -8
- data/ext/ca_group_iter.c +1 -1
- data/ext/ca_kernel_iterator.c +69 -23
- data/ext/ca_kernel_iterator.h +3 -10
- data/ext/ca_obj_bincmp.c +57 -27
- data/ext/ca_obj_binop.c +86 -30
- data/ext/ca_obj_const_string.c +3 -1
- data/ext/ca_obj_face.c +80 -0
- data/ext/ca_obj_face.h +33 -1
- data/ext/ca_obj_fake.c +11 -0
- data/ext/ca_obj_fixlen_string.c +3 -1
- data/ext/ca_obj_grid.c +11 -3
- data/ext/ca_obj_meld.c +13 -8
- data/ext/ca_obj_moncmp.c +33 -14
- data/ext/ca_obj_monop.c +19 -7
- data/ext/ca_obj_object.c +99 -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_axis.c +16 -6
- data/ext/ca_obj_shift.c +3 -3
- data/ext/ca_obj_stride.c +106 -23
- data/ext/ca_obj_string.c +3 -1
- 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 +86 -17
- data/ext/ca_op_cmplx64.h +123 -0
- data/ext/ca_op_ipower.c +0 -3
- data/ext/ca_sort_kernels.h +5 -5
- data/ext/ca_sweep_engine.c +78 -35
- data/ext/ca_sweep_engine.h +13 -4
- data/ext/ca_transform_common.c +7 -0
- data/ext/carray.h +127 -130
- data/ext/carray_access.c +56 -34
- data/ext/carray_bincount.c +8 -8
- data/ext/carray_broadcast.c +99 -6
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +1491 -0
- data/ext/carray_call_cfunc.h +153 -0
- data/ext/carray_cast.c +69 -31
- data/ext/carray_conversion.c +22 -22
- data/ext/carray_copy.c +12 -2
- data/ext/carray_core.c +57 -10
- data/ext/carray_count.c +1 -1
- data/ext/carray_element.c +7 -7
- data/ext/carray_factorize.c +28 -28
- data/ext/carray_hold.c +1 -1
- data/ext/carray_index_classifier.c +7 -21
- data/ext/carray_internal.h +19 -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 +88 -87
- data/ext/carray_kernels_reduce_boolean.c +1 -0
- data/ext/carray_kernels_reduce_cumulative.c +54 -53
- data/ext/carray_kernels_reduce_extreme.c +51 -50
- data/ext/carray_kernels_reduce_variance.c +1 -0
- data/ext/carray_kernels_scan.c +1 -0
- data/ext/carray_kernels_search.c +93 -92
- 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_mask.c +6 -5
- data/ext/carray_median_percentile.c +1 -1
- data/ext/carray_memory_view.c +46 -21
- data/ext/carray_operator.c +46 -49
- data/ext/carray_partition.c +4 -4
- data/ext/carray_random.c +7 -7
- data/ext/carray_scatter.c +1 -1
- data/ext/carray_sort.c +3 -3
- 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 +243 -52
- data/ext/mkkernel.rb +354 -100
- data/ext/ruby_carray.c +18 -16
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +19 -0
- data/lib/carray/autoload_method_extension.rb +2 -1
- data/lib/carray/axis_group.rb +7 -7
- data/lib/carray/basics.rb +59 -59
- data/lib/carray/bincount_nd.rb +12 -12
- data/lib/carray/block_iterator.rb +24 -14
- data/lib/carray/categorical.rb +4 -4
- data/lib/carray/categorical_iterator.rb +98 -76
- data/lib/carray/conditional.rb +14 -14
- data/lib/carray/construct.rb +21 -0
- data/lib/carray/core_extensions.rb +62 -5
- data/lib/carray/data_type_extension.rb +18 -1
- data/lib/carray/frame/concat.rb +3 -3
- data/lib/carray/frame/convert.rb +1 -1
- data/lib/carray/frame/frame.rb +4 -11
- data/lib/carray/frame/io.rb +159 -2
- data/lib/carray/frame/sort.rb +1 -1
- data/lib/carray/frame/verbs.rb +18 -1
- 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 +1 -7
- data/lib/carray/iterator.rb +4 -3
- data/lib/carray/lazy.rb +125 -73
- 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/is_in.rb +12 -12
- data/lib/carray/methods/locate_addr.rb +6 -1
- data/lib/carray/methods/mask_duplicates.rb +1 -1
- data/lib/carray/methods/meshgrid.rb +4 -5
- data/lib/carray/methods/mode.rb +2 -2
- data/lib/carray/methods/nunique.rb +1 -1
- data/lib/carray/methods/snap.rb +7 -2
- data/lib/carray/methods/unique.rb +3 -3
- data/lib/carray/methods/value_counts.rb +2 -2
- data/lib/carray/runtime.rb +0 -19
- data/lib/carray/slab_iterator.rb +20 -7
- data/lib/carray/string_operation_extension.rb +5 -5
- data/lib/carray/time.rb +890 -491
- data/lib/carray/window_iterator.rb +285 -13
- data/lib/carray.rb +5 -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 +73 -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 +49 -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 +114 -0
- data/yard-stubs/carray_count.rb +79 -0
- data/yard-stubs/carray_element.rb +108 -0
- data/yard-stubs/carray_generate.rb +66 -0
- data/yard-stubs/carray_lazy.rb +23 -0
- data/yard-stubs/carray_loop.rb +140 -0
- data/yard-stubs/carray_mask.rb +259 -0
- data/yard-stubs/carray_math.rb +132 -0
- data/yard-stubs/carray_mathfunc.rb +45 -0
- data/yard-stubs/carray_median_percentile.rb +89 -0
- data/yard-stubs/carray_memory_view.rb +163 -0
- data/yard-stubs/carray_order.rb +312 -0
- data/yard-stubs/carray_random.rb +89 -0
- data/yard-stubs/carray_scatter.rb +106 -0
- data/yard-stubs/carray_slab.rb +57 -0
- data/yard-stubs/carray_sort.rb +163 -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 +59 -10
- data/ext/ca_obj_unbound_repeat.c +0 -496
data/ext/ca_obj_bincmp.c
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
ca_bincmp_kernel_lookup from ca_bincmp_dispatch.h.
|
|
10
10
|
|
|
11
11
|
Dispatch by data_type:
|
|
12
|
-
numeric (i8..f64, +complex) -> ca_bincmp_<op>_<
|
|
12
|
+
numeric (i8..f64, +complex) -> ca_bincmp_<op>_<type> kernel
|
|
13
13
|
boolean / fixlen / object -> not implemented (raise)
|
|
14
14
|
|
|
15
15
|
CAREFUL: the binop in-place trick (= pull left into the output
|
|
@@ -60,6 +60,12 @@ typedef struct CABinCmp {
|
|
|
60
60
|
CArray *parent; /* = left */
|
|
61
61
|
uint32_t attach;
|
|
62
62
|
uint8_t nosync;
|
|
63
|
+
/* ---- CAMultiParent conformance (CA_FLAG_MULTI_PARENTS): n_parents and
|
|
64
|
+
parents[] sit immediately after the CAView header, as carray.h's
|
|
65
|
+
layout convention requires, so ca_has_mask can fold over both
|
|
66
|
+
operands and build the mask on demand instead of at setup. ---- */
|
|
67
|
+
int32_t n_parents; /* always 2 */
|
|
68
|
+
CArray **parents; /* = &operands[0]; no separate allocation */
|
|
63
69
|
/* CABinCmp-specific tail */
|
|
64
70
|
CArray *right;
|
|
65
71
|
uint16_t op_id;
|
|
@@ -72,6 +78,7 @@ typedef struct CABinCmp {
|
|
|
72
78
|
`eps` name is retained to keep the
|
|
73
79
|
`__eps__` Ruby accessor stable across
|
|
74
80
|
the dual purpose. */
|
|
81
|
+
CArray *operands[2]; /* {left, right}; what parents points at */
|
|
75
82
|
} CABinCmp;
|
|
76
83
|
|
|
77
84
|
static size_t
|
|
@@ -119,7 +126,7 @@ ca_bincmp_setup (CABinCmp *ca, CArray *left, CArray *right, uint16_t op_id,
|
|
|
119
126
|
{
|
|
120
127
|
ca->obj_type = CA_OBJ_BINCMP;
|
|
121
128
|
ca->data_type = CA_BOOLEAN; /* output is always boolean */
|
|
122
|
-
ca->flags = CA_FLAG_READ_ONLY;
|
|
129
|
+
ca->flags = CA_FLAG_READ_ONLY | CA_FLAG_MULTI_PARENTS;
|
|
123
130
|
ca->ndim = left->ndim;
|
|
124
131
|
ca->bytes = 1; /* boolean8_t */
|
|
125
132
|
ca->elements = left->elements;
|
|
@@ -137,12 +144,16 @@ ca_bincmp_setup (CABinCmp *ca, CArray *left, CArray *right, uint16_t op_id,
|
|
|
137
144
|
/* Builder has already cast both operands to common data_type. */
|
|
138
145
|
ca->common_dt = left->data_type;
|
|
139
146
|
ca->eps = eps;
|
|
147
|
+
ca->operands[0] = left;
|
|
148
|
+
ca->operands[1] = right;
|
|
149
|
+
ca->parents = ca->operands;
|
|
150
|
+
ca->n_parents = 2;
|
|
140
151
|
|
|
141
152
|
memcpy(ca->dim, left->dim, left->ndim * sizeof(ca_size_t));
|
|
142
153
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
154
|
+
/* The mask is NOT built here. ca_has_mask folds over parents[] for a
|
|
155
|
+
multi-parent view and creates it on demand, so an expression whose mask
|
|
156
|
+
nobody reads never allocates one. */
|
|
146
157
|
|
|
147
158
|
if ( ca_is_scalar(left) && ca_is_scalar(right) ) {
|
|
148
159
|
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
@@ -294,7 +305,9 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
294
305
|
int8_t k;
|
|
295
306
|
void *left_scratch, *right_scratch;
|
|
296
307
|
ca_size_t operand_bytes;
|
|
308
|
+
ca_size_t operand_strides[CA_RANK_MAX];
|
|
297
309
|
ca_size_t right_step;
|
|
310
|
+
int is_contig;
|
|
298
311
|
int left_is_inplace = 0; /* skip release for leaf-opt path */
|
|
299
312
|
int right_is_inplace = 0;
|
|
300
313
|
|
|
@@ -308,10 +321,33 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
308
321
|
|
|
309
322
|
operand_bytes = ca_sizeof[bc->common_dt];
|
|
310
323
|
|
|
324
|
+
/* An operand cell is operand_bytes wide where this view's is one byte
|
|
325
|
+
(CA_BOOLEAN), so the caller's strides cannot be handed to the operand
|
|
326
|
+
pull the way a binop hands them on -- they have to be restated at the
|
|
327
|
+
operand's cell size. strides[k] / bytes is the index step, which is
|
|
328
|
+
what the two spaces share.
|
|
329
|
+
|
|
330
|
+
is_contig says the caller asked for the row-major slab that xfer_all
|
|
331
|
+
and attach send. Only then does an operand's own buffer hold the
|
|
332
|
+
wanted cells in the packed order the kernel reads them in, so it is
|
|
333
|
+
also the only case the leaf in-place path is good for. */
|
|
334
|
+
{
|
|
335
|
+
ca_size_t native = bc->bytes;
|
|
336
|
+
is_contig = 1;
|
|
337
|
+
for ( k = bc->ndim - 1; k >= 0; k-- ) {
|
|
338
|
+
operand_strides[k] = strides[k] / bc->bytes * operand_bytes;
|
|
339
|
+
if ( strides[k] != native ) {
|
|
340
|
+
is_contig = 0;
|
|
341
|
+
}
|
|
342
|
+
native *= bc->dim[k];
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
311
346
|
/* === 1. pull LEFT (leaf in-place read or arena scratch) === */
|
|
312
347
|
{
|
|
313
348
|
char *left_inplace = NULL;
|
|
314
|
-
if (
|
|
349
|
+
if ( is_contig &&
|
|
350
|
+
ca_bincmp_try_leaf_inplace(bc->parent, bc->common_dt,
|
|
315
351
|
starts, counts, operand_bytes,
|
|
316
352
|
&left_inplace) ) {
|
|
317
353
|
/* Leaf-opt path: use parent->ptr + byte_offset directly. */
|
|
@@ -320,15 +356,11 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
320
356
|
ca_bincmp_leaf_inplace_count++;
|
|
321
357
|
}
|
|
322
358
|
else {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
left_strides[k] = s;
|
|
327
|
-
s *= counts[k];
|
|
328
|
-
}
|
|
329
|
-
left_scratch = ca_lazy_arena_acquire(slab_n * operand_bytes);
|
|
359
|
+
left_scratch = ( bc->common_dt == CA_OBJECT )
|
|
360
|
+
? ca_lazy_arena_acquire_object(slab_n)
|
|
361
|
+
: ca_lazy_arena_acquire(slab_n * operand_bytes);
|
|
330
362
|
ca_bincmp_scratch_acquire_count++;
|
|
331
|
-
ca_xfer_stride(bc->parent, starts, counts,
|
|
363
|
+
ca_xfer_stride(bc->parent, starts, counts, operand_strides, left_scratch,
|
|
332
364
|
CA_XFER_GET);
|
|
333
365
|
}
|
|
334
366
|
}
|
|
@@ -355,7 +387,9 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
355
387
|
else {
|
|
356
388
|
ca_size_t one_strides[CA_RANK_MAX];
|
|
357
389
|
for ( k = 0; k < bc->right->ndim; k++ ) one_strides[k] = operand_bytes;
|
|
358
|
-
right_scratch =
|
|
390
|
+
right_scratch = ( bc->common_dt == CA_OBJECT )
|
|
391
|
+
? ca_lazy_arena_acquire_object(1)
|
|
392
|
+
: ca_lazy_arena_acquire(operand_bytes);
|
|
359
393
|
ca_bincmp_scratch_acquire_count++;
|
|
360
394
|
ca_xfer_stride(bc->right, one_starts, one_counts, one_strides,
|
|
361
395
|
right_scratch, CA_XFER_GET);
|
|
@@ -365,7 +399,8 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
365
399
|
else {
|
|
366
400
|
/* Same-shape right: full slab pull or leaf-opt. */
|
|
367
401
|
char *right_inplace = NULL;
|
|
368
|
-
if (
|
|
402
|
+
if ( is_contig &&
|
|
403
|
+
ca_bincmp_try_leaf_inplace(bc->right, bc->common_dt,
|
|
369
404
|
starts, counts, operand_bytes,
|
|
370
405
|
&right_inplace) ) {
|
|
371
406
|
right_scratch = right_inplace;
|
|
@@ -373,15 +408,11 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
373
408
|
ca_bincmp_leaf_inplace_count++;
|
|
374
409
|
}
|
|
375
410
|
else {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
right_strides[k] = s;
|
|
380
|
-
s *= counts[k];
|
|
381
|
-
}
|
|
382
|
-
right_scratch = ca_lazy_arena_acquire(slab_n * operand_bytes);
|
|
411
|
+
right_scratch = ( bc->common_dt == CA_OBJECT )
|
|
412
|
+
? ca_lazy_arena_acquire_object(slab_n)
|
|
413
|
+
: ca_lazy_arena_acquire(slab_n * operand_bytes);
|
|
383
414
|
ca_bincmp_scratch_acquire_count++;
|
|
384
|
-
ca_xfer_stride(bc->right, starts, counts,
|
|
415
|
+
ca_xfer_stride(bc->right, starts, counts, operand_strides, right_scratch,
|
|
385
416
|
CA_XFER_GET);
|
|
386
417
|
}
|
|
387
418
|
right_step = 1;
|
|
@@ -644,10 +675,9 @@ rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
|
|
|
644
675
|
TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
|
|
645
676
|
}
|
|
646
677
|
else {
|
|
678
|
+
/* Unreachable from Ruby; see the note in ca_obj_binop.c. */
|
|
647
679
|
rb_raise(rb_eArgError,
|
|
648
|
-
"CABinCmp:
|
|
649
|
-
"ndim size-1 broadcast is supported; cross-ndim "
|
|
650
|
-
"promotion is not adopted in CArray",
|
|
680
|
+
"CABinCmp: element count mismatch (%lld vs %lld)",
|
|
651
681
|
(long long) l->elements, (long long) r->elements);
|
|
652
682
|
}
|
|
653
683
|
}
|
data/ext/ca_obj_binop.c
CHANGED
|
@@ -70,11 +70,21 @@ typedef struct CABinOp {
|
|
|
70
70
|
collapse and attach lifecycle traversal) */
|
|
71
71
|
uint32_t attach;
|
|
72
72
|
uint8_t nosync;
|
|
73
|
+
/* ---- CAMultiParent conformance (CA_FLAG_MULTI_PARENTS): n_parents and
|
|
74
|
+
parents[] sit immediately after the CAView header, as the layout
|
|
75
|
+
convention in carray.h requires, so generic code that would walk a
|
|
76
|
+
single ->parent folds over both operands instead. What this buys
|
|
77
|
+
here is ca_has_mask: it answers for a two-parent view by asking both
|
|
78
|
+
and creating the mask on demand, which lets the mask stay unbuilt
|
|
79
|
+
until something reads it. ---- */
|
|
80
|
+
int32_t n_parents; /* always 2 */
|
|
81
|
+
CArray **parents; /* = &operands[0]; no separate allocation */
|
|
73
82
|
/* CABinOp-specific tail */
|
|
74
83
|
CArray *right;
|
|
75
84
|
uint16_t op_id;
|
|
76
85
|
uint8_t right_is_scalar; /* 1 ⇒ right has elements == 1, walk
|
|
77
86
|
with element-stride 0 (= broadcast) */
|
|
87
|
+
CArray *operands[2]; /* {left, right}; what parents points at */
|
|
78
88
|
} CABinOp;
|
|
79
89
|
|
|
80
90
|
static size_t
|
|
@@ -125,7 +135,7 @@ ca_binop_setup (CABinOp *ca, CArray *left, CArray *right, uint16_t op_id)
|
|
|
125
135
|
|
|
126
136
|
ca->obj_type = CA_OBJ_BINOP;
|
|
127
137
|
ca->data_type = out_dt;
|
|
128
|
-
ca->flags = CA_FLAG_READ_ONLY;
|
|
138
|
+
ca->flags = CA_FLAG_READ_ONLY | CA_FLAG_MULTI_PARENTS;
|
|
129
139
|
ca->ndim = left->ndim;
|
|
130
140
|
ca->bytes = out_bytes;
|
|
131
141
|
ca->elements = left->elements;
|
|
@@ -139,6 +149,10 @@ ca_binop_setup (CABinOp *ca, CArray *left, CArray *right, uint16_t op_id)
|
|
|
139
149
|
ca->nosync = 0;
|
|
140
150
|
ca->right = right;
|
|
141
151
|
ca->op_id = op_id;
|
|
152
|
+
ca->operands[0] = left;
|
|
153
|
+
ca->operands[1] = right;
|
|
154
|
+
ca->parents = ca->operands;
|
|
155
|
+
ca->n_parents = 2;
|
|
142
156
|
/* right_is_scalar fast path: when right holds a single element,
|
|
143
157
|
xfer_stride pulls only that cell into scratch and walks the
|
|
144
158
|
kernel with element-stride 0 (broadcast). The symmetric
|
|
@@ -148,9 +162,10 @@ ca_binop_setup (CABinOp *ca, CArray *left, CArray *right, uint16_t op_id)
|
|
|
148
162
|
|
|
149
163
|
memcpy(ca->dim, left->dim, left->ndim * sizeof(ca_size_t));
|
|
150
164
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
165
|
+
/* The mask is NOT built here. ca_has_mask folds over parents[] for a
|
|
166
|
+
multi-parent view and creates it on demand, so an expression whose mask
|
|
167
|
+
nobody reads never allocates one -- and a chain of masked nodes builds
|
|
168
|
+
one array at the end rather than one per node. */
|
|
154
169
|
|
|
155
170
|
if ( ca_is_scalar(left) && ca_is_scalar(right) ) {
|
|
156
171
|
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
@@ -291,25 +306,25 @@ ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
291
306
|
one_counts[k] = 1;
|
|
292
307
|
one_strides[k] = right_bytes;
|
|
293
308
|
}
|
|
294
|
-
scratch =
|
|
309
|
+
scratch = ( bo->data_type == CA_OBJECT )
|
|
310
|
+
? ca_lazy_arena_acquire_object(1)
|
|
311
|
+
: ca_lazy_arena_acquire(right_bytes);
|
|
295
312
|
ca_binop_scratch_acquire_count++;
|
|
296
313
|
ca_xfer_stride(bo->right, one_starts, one_counts, one_strides,
|
|
297
314
|
scratch, CA_XFER_GET);
|
|
298
315
|
right_step = 0;
|
|
299
316
|
}
|
|
300
317
|
else {
|
|
301
|
-
/* Same-shape right.
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
scratch = ca_lazy_arena_acquire(slab_n * right_bytes);
|
|
318
|
+
/* Same-shape right. `strides` is the step through the operand, the
|
|
319
|
+
same one the left was pulled with -- recomputing a packed one here
|
|
320
|
+
reads the right operand's cells 0, 1, 2 against the left's 0, 2, 4.
|
|
321
|
+
right.bytes matches output.bytes because right.data_type ==
|
|
322
|
+
out.data_type by cast-before, so the same steps serve both. */
|
|
323
|
+
scratch = ( bo->data_type == CA_OBJECT )
|
|
324
|
+
? ca_lazy_arena_acquire_object(slab_n)
|
|
325
|
+
: ca_lazy_arena_acquire(slab_n * right_bytes);
|
|
311
326
|
ca_binop_scratch_acquire_count++;
|
|
312
|
-
ca_xfer_stride(bo->right, starts, counts,
|
|
327
|
+
ca_xfer_stride(bo->right, starts, counts, strides, scratch,
|
|
313
328
|
CA_XFER_GET);
|
|
314
329
|
right_step = 1;
|
|
315
330
|
}
|
|
@@ -438,6 +453,14 @@ ca_binop_func_allocate (void *ap)
|
|
|
438
453
|
{
|
|
439
454
|
CABinOp *ca = (CABinOp *) ap;
|
|
440
455
|
ca->ptr = xmalloc(ca_length(ca));
|
|
456
|
+
/* CA_OBJECT cells are VALUEs and this buffer is about to be marked as
|
|
457
|
+
soon as the view is, so it must not be handed to the GC as raw
|
|
458
|
+
xmalloc garbage. */
|
|
459
|
+
if ( ca->data_type == CA_OBJECT ) {
|
|
460
|
+
VALUE *p = (VALUE *) ca->ptr;
|
|
461
|
+
ca_size_t i;
|
|
462
|
+
for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
|
|
463
|
+
}
|
|
441
464
|
}
|
|
442
465
|
|
|
443
466
|
static void
|
|
@@ -459,6 +482,14 @@ ca_binop_func_attach (void *ap)
|
|
|
459
482
|
s = ca->bytes;
|
|
460
483
|
for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
|
|
461
484
|
for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
|
|
485
|
+
/* CA_OBJECT cells are VALUEs and this buffer is about to be marked as
|
|
486
|
+
soon as the view is, so it must not be handed to the GC as raw
|
|
487
|
+
xmalloc garbage. */
|
|
488
|
+
if ( ca->data_type == CA_OBJECT ) {
|
|
489
|
+
VALUE *p = (VALUE *) ca->ptr;
|
|
490
|
+
ca_size_t i;
|
|
491
|
+
for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
|
|
492
|
+
}
|
|
462
493
|
ca_binop_func_xfer_stride(ca, starts, ca->dim, native, ca->ptr, CA_XFER_GET);
|
|
463
494
|
}
|
|
464
495
|
|
|
@@ -517,6 +548,19 @@ ca_binop_func_create_mask (void *ap)
|
|
|
517
548
|
( bo->op_id == CA_BINOP_BIT_AND || bo->op_id == CA_BINOP_BIT_OR ) );
|
|
518
549
|
is_or = ( bo->op_id == CA_BINOP_BIT_OR );
|
|
519
550
|
|
|
551
|
+
/* One masked operand and no Kleene resolution: the answer is that
|
|
552
|
+
operand's mask, cell for cell. Share it the way CAMonOp shares its
|
|
553
|
+
parent's, rather than allocating a copy per node -- a chain of k
|
|
554
|
+
binops over one masked array then holds one boolean array, not k. */
|
|
555
|
+
if ( ! kleene && ( has_l != has_r ) ) {
|
|
556
|
+
CArray *src = has_l ? l : r;
|
|
557
|
+
if ( src->elements == bo->elements ) {
|
|
558
|
+
bo->mask = (CArray *) ca_refer_new(src->mask, CA_BOOLEAN,
|
|
559
|
+
bo->ndim, bo->dim, 0, 0);
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
520
564
|
bo->mask = (CArray *) carray_new(CA_BOOLEAN, bo->ndim, bo->dim, 0, NULL);
|
|
521
565
|
dst = (boolean8_t *) bo->mask->ptr;
|
|
522
566
|
n = bo->elements;
|
|
@@ -524,8 +568,18 @@ ca_binop_func_create_mask (void *ap)
|
|
|
524
568
|
/* Kleene needs operand values even where an operand is unmasked. */
|
|
525
569
|
need_l = has_l || kleene;
|
|
526
570
|
need_r = has_r || kleene;
|
|
527
|
-
|
|
528
|
-
|
|
571
|
+
/* Only Kleene reads operand values. Every other op reads the operand
|
|
572
|
+
masks alone, and attaching the operand to reach its mask materialises
|
|
573
|
+
the whole subexpression under it -- so a chain of k masked binops
|
|
574
|
+
evaluates its own subtree k times over. Attach what is read. */
|
|
575
|
+
if ( kleene ) {
|
|
576
|
+
if ( need_l ) ca_attach(l);
|
|
577
|
+
if ( need_r ) ca_attach(r);
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
if ( has_l ) ca_attach(l->mask);
|
|
581
|
+
if ( has_r ) ca_attach(r->mask);
|
|
582
|
+
}
|
|
529
583
|
|
|
530
584
|
lm = has_l ? (boolean8_t *) l->mask->ptr : NULL;
|
|
531
585
|
rm = has_r ? (boolean8_t *) r->mask->ptr : NULL;
|
|
@@ -550,8 +604,14 @@ ca_binop_func_create_mask (void *ap)
|
|
|
550
604
|
dst[i] = m;
|
|
551
605
|
}
|
|
552
606
|
|
|
553
|
-
if (
|
|
554
|
-
|
|
607
|
+
if ( kleene ) {
|
|
608
|
+
if ( need_r ) ca_detach(r);
|
|
609
|
+
if ( need_l ) ca_detach(l);
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
if ( has_r ) ca_detach(r->mask);
|
|
613
|
+
if ( has_l ) ca_detach(l->mask);
|
|
614
|
+
}
|
|
555
615
|
}
|
|
556
616
|
|
|
557
617
|
ca_operation_function_t ca_binop_func = {
|
|
@@ -682,8 +742,7 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
|
|
|
682
742
|
|
|
683
743
|
/* === Step 2: broadcast via ca_broadcast_pair (same-ndim size-1
|
|
684
744
|
expansion). No-op when shapes already match or either operand
|
|
685
|
-
is scalar;
|
|
686
|
-
final elements-mismatch check below catches. */
|
|
745
|
+
is scalar; refuses a pair that cannot be brought to one shape. */
|
|
687
746
|
ca_broadcast_pair(&l_resolved, &r_resolved);
|
|
688
747
|
TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
|
|
689
748
|
TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
|
|
@@ -735,14 +794,12 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
|
|
|
735
794
|
}
|
|
736
795
|
}
|
|
737
796
|
else {
|
|
738
|
-
/*
|
|
739
|
-
|
|
740
|
-
|
|
797
|
+
/* Unreachable from Ruby: ca_broadcast_pair above refuses a pair
|
|
798
|
+
it cannot bring to one shape, and states the rule there. Kept
|
|
799
|
+
so a caller reaching this builder by another route still finds
|
|
800
|
+
the kernel guarded. */
|
|
741
801
|
rb_raise(rb_eArgError,
|
|
742
|
-
"CABinOp:
|
|
743
|
-
"ndim size-1 broadcast is supported; cross-ndim "
|
|
744
|
-
"promotion is not adopted in CArray "
|
|
745
|
-
"(reshape explicitly)",
|
|
802
|
+
"CABinOp: element count mismatch (%lld vs %lld)",
|
|
746
803
|
(long long) l->elements, (long long) r->elements);
|
|
747
804
|
}
|
|
748
805
|
}
|
|
@@ -866,7 +923,6 @@ Init_ca_obj_binop (void)
|
|
|
866
923
|
rb_define_const(rb_cCABinOp, "OP_AND", INT2NUM(CA_BINOP_AND));
|
|
867
924
|
rb_define_const(rb_cCABinOp, "OP_OR", INT2NUM(CA_BINOP_OR));
|
|
868
925
|
rb_define_const(rb_cCABinOp, "OP_XOR", INT2NUM(CA_BINOP_XOR));
|
|
869
|
-
rb_define_const(rb_cCABinOp, "OP_REMINDER", INT2NUM(CA_BINOP_REMINDER));
|
|
870
926
|
|
|
871
927
|
rb_define_alloc_func(rb_cCABinOp, rb_ca_binop_s_allocate);
|
|
872
928
|
rb_define_method(rb_cCABinOp, "initialize_copy",
|
data/ext/ca_obj_const_string.c
CHANGED
|
@@ -227,7 +227,9 @@ ca_operation_function_t ca_const_string_func = {
|
|
|
227
227
|
ca_face_xfer_addrs,
|
|
228
228
|
NULL, /* fold_stride: identity Face is not foldable */
|
|
229
229
|
ca_face_xfer_stride,
|
|
230
|
-
ca_face_xfer_all
|
|
230
|
+
ca_face_xfer_all,
|
|
231
|
+
.fill_addrs = ca_face_fill_addrs,
|
|
232
|
+
.fill_stride = ca_face_fill_stride,
|
|
231
233
|
};
|
|
232
234
|
|
|
233
235
|
/* ------------------------------------------------------------------- */
|
data/ext/ca_obj_face.c
CHANGED
|
@@ -66,6 +66,21 @@ ca_face_fill_data (void *ap, void *ptr)
|
|
|
66
66
|
ca_fill(cav->parent, ptr);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
void
|
|
70
|
+
ca_face_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
|
|
71
|
+
{
|
|
72
|
+
CAView *cav = (CAView *) ap;
|
|
73
|
+
ca_fill_addrs(cav->parent, n, addrs, ptr);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
void
|
|
77
|
+
ca_face_fill_stride (void *ap, ca_size_t base, int8_t ndim,
|
|
78
|
+
ca_size_t *counts, ca_size_t *steps, void *ptr)
|
|
79
|
+
{
|
|
80
|
+
CAView *cav = (CAView *) ap;
|
|
81
|
+
ca_fill_stride(cav->parent, base, ndim, counts, steps, ptr);
|
|
82
|
+
}
|
|
83
|
+
|
|
69
84
|
void
|
|
70
85
|
ca_face_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
71
86
|
{
|
|
@@ -270,6 +285,71 @@ ca_face_lift (VALUE view, VALUE face_parent)
|
|
|
270
285
|
return lifted;
|
|
271
286
|
}
|
|
272
287
|
|
|
288
|
+
/* ca_lazy_marker_lift(view, marker) — the CALazyMarker half of
|
|
289
|
+
* ca_wrapper_lift. Same invariant as the Face lift (wrapper on top, view
|
|
290
|
+
* built against what the wrapper wraps) reached by a shorter route: a
|
|
291
|
+
* marker carries no subclass state, so there is nothing for
|
|
292
|
+
* rb_ca_face_template's struct copy to preserve, and building a fresh
|
|
293
|
+
* marker over the view gets data_type, bytes, shape, mask and flags right
|
|
294
|
+
* by construction. That last part is load-bearing for `refer(type)`,
|
|
295
|
+
* where the view's data_type differs from the one the old marker copied
|
|
296
|
+
* off the entity.
|
|
297
|
+
*
|
|
298
|
+
* The one piece it shares with the Face lift is the one-level swap: the
|
|
299
|
+
* builder handed us a view whose parent is the marker, and leaving it
|
|
300
|
+
* there would stack a redundant marker in the middle. */
|
|
301
|
+
static VALUE
|
|
302
|
+
ca_lazy_marker_lift (VALUE view, VALUE marker)
|
|
303
|
+
{
|
|
304
|
+
CArray *view_ca, *mp;
|
|
305
|
+
extern VALUE rb_ca_lazy_marker_new (VALUE cary);
|
|
306
|
+
|
|
307
|
+
TypedData_Get_Struct(view, CArray, &carray_data_type, view_ca);
|
|
308
|
+
|
|
309
|
+
/* Idempotent: a builder that wrapped internally already returned a
|
|
310
|
+
marker (mirrors the same guard in ca_face_lift). */
|
|
311
|
+
if ( ca_is_lazy_marker(view_ca) ) {
|
|
312
|
+
return view;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
TypedData_Get_Struct(marker, CArray, &carray_data_type, mp);
|
|
316
|
+
|
|
317
|
+
/* One-level swap (CAFace.md section 8.3, same reasoning): move the view
|
|
318
|
+
off the marker and onto what the marker wraps. Guarded on pointer
|
|
319
|
+
equality so only a view built directly on this marker fires. */
|
|
320
|
+
if ( ca_is_view(view_ca)
|
|
321
|
+
&& ((CAView *) view_ca)->parent == mp
|
|
322
|
+
&& ! ca_test_flag(view_ca, CA_FLAG_MULTI_PARENTS) ) {
|
|
323
|
+
((CAView *) view_ca)->parent = ((CAView *) mp)->parent; /* C pointer */
|
|
324
|
+
rb_ca_set_parent(view, rb_ca_parent(marker)); /* @parent ivar */
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return rb_ca_lazy_marker_new(view);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* ca_wrapper_lift(view, wrapper, wrapper_ca) — dispatch for
|
|
331
|
+
* CA_WRAPPER_LIFT. The macro has already established that wrapper_ca
|
|
332
|
+
* carries one of the two flags and that view is a CArray. */
|
|
333
|
+
VALUE
|
|
334
|
+
ca_wrapper_lift (VALUE view, VALUE wrapper, void *wrapper_ca)
|
|
335
|
+
{
|
|
336
|
+
CArray *ca = (CArray *) wrapper_ca;
|
|
337
|
+
|
|
338
|
+
if ( ca_is_face(ca) ) {
|
|
339
|
+
CArray *view_ca;
|
|
340
|
+
TypedData_Get_Struct(view, CArray, &carray_data_type, view_ca);
|
|
341
|
+
/* Some builders (select / repeat / ...) lift their own result; a
|
|
342
|
+
second lift here would double-wrap. Mirrors the guard the `[]`
|
|
343
|
+
call site used to carry inline. */
|
|
344
|
+
if ( ca_is_face(view_ca) ) {
|
|
345
|
+
return view;
|
|
346
|
+
}
|
|
347
|
+
return ca_face_lift(view, wrapper);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return ca_lazy_marker_lift(view, wrapper);
|
|
351
|
+
}
|
|
352
|
+
|
|
273
353
|
/* ca_strip_face(src) — walk down through Face parents to the storage
|
|
274
354
|
* CArray. Called at kernel_iterator entry and lazy chain endpoints
|
|
275
355
|
* where downstream code needs to observe the storage layout, not the
|
data/ext/ca_obj_face.h
CHANGED
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
via parent)
|
|
35
35
|
- detach: release ptr alias, parent detach
|
|
36
36
|
- xfer_*: delegate to parent's xfer_* (= identical shape / index space)
|
|
37
|
-
- fill_data
|
|
37
|
+
- fill_data / fill_*: delegate to parent (= identical storage bytes,
|
|
38
|
+
and the identity layout makes the parent's addresses ours)
|
|
38
39
|
|
|
39
40
|
Subclasses may override as needed (= default policy, not an invariant;
|
|
40
41
|
does not preclude a future transform Face). */
|
|
@@ -43,6 +44,9 @@ void ca_face_attach (void *ap);
|
|
|
43
44
|
void ca_face_sync (void *ap);
|
|
44
45
|
void ca_face_detach (void *ap);
|
|
45
46
|
void ca_face_fill_data (void *ap, void *ptr);
|
|
47
|
+
void ca_face_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr);
|
|
48
|
+
void ca_face_fill_stride(void *ap, ca_size_t base, int8_t ndim,
|
|
49
|
+
ca_size_t *counts, ca_size_t *steps, void *ptr);
|
|
46
50
|
void ca_face_xfer_index (void *ap, ca_size_t *idx,
|
|
47
51
|
void *data, int dir);
|
|
48
52
|
void ca_face_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
@@ -112,6 +116,34 @@ VALUE rb_ca_record_get_data_class (CArray *ca);
|
|
|
112
116
|
} \
|
|
113
117
|
} while (0)
|
|
114
118
|
|
|
119
|
+
/* -- wrapper lift (Face or CALazyMarker) --
|
|
120
|
+
|
|
121
|
+
A Face and a CALazyMarker are both storage-identical wrappers: they add
|
|
122
|
+
an interpretation over their parent's bytes without changing them. Both
|
|
123
|
+
want the same invariant at a view-creating method -- the wrapper stays on
|
|
124
|
+
top, and the view is built against what the wrapper wraps. For a Face
|
|
125
|
+
that keeps `dt.shift(1)` a CATime; for a marker it keeps a fuse block's
|
|
126
|
+
expression lazy instead of dropping out of the chain.
|
|
127
|
+
|
|
128
|
+
The flag test comes first and covers both bits in one mask, so an
|
|
129
|
+
ordinary array leaves through a single AND. That matters: `[]` is the
|
|
130
|
+
hottest method this is deployed on (see devel/bench_index_percall.rb).
|
|
131
|
+
|
|
132
|
+
NOT interchangeable with CA_FACE_LIFT_IF_FACE. Face is lifted at ~24
|
|
133
|
+
sites, including ones a marker must not follow it through -- `copy` owns
|
|
134
|
+
its data, `sort` reorders values, `value` and `strip_mask` change what
|
|
135
|
+
the mask means. Deploy this only where the result is a view whose shape
|
|
136
|
+
was fixed at construction and which only moves positions
|
|
137
|
+
(PROPOSAL_LAZY_MARKER_LIFT section 4). */
|
|
138
|
+
#define CA_WRAPPER_LIFT(obj, self, ca) do { \
|
|
139
|
+
if ( ca_test_flag((ca), CA_FLAG_IS_FACE | CA_FLAG_IS_LAZY_MARKER) \
|
|
140
|
+
&& rb_obj_is_kind_of((obj), rb_cCArray) ) { \
|
|
141
|
+
(obj) = ca_wrapper_lift((obj), (self), (ca)); \
|
|
142
|
+
} \
|
|
143
|
+
} while (0)
|
|
144
|
+
|
|
145
|
+
VALUE ca_wrapper_lift (VALUE view, VALUE wrapper, void *wrapper_ca);
|
|
146
|
+
|
|
115
147
|
/* -- Scalar fetch decode hook (storage -> surface) --
|
|
116
148
|
On the scalar-return path (= tail of rb_ca_fetch_index /
|
|
117
149
|
rb_ca_fetch_addr), if a Face-derived subclass defines a
|
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
|
@@ -202,7 +202,9 @@ ca_operation_function_t ca_fixlen_string_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
|
/* ------------------------------------------------------------------- */
|
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
|
@@ -89,7 +89,7 @@ static ID id_parents;
|
|
|
89
89
|
/* uniform check */
|
|
90
90
|
/* ------------------------------------------------------------------- */
|
|
91
91
|
|
|
92
|
-
/* Parents must share
|
|
92
|
+
/* Parents must share data type, ndim, bytes, and all dims except meld_axis;
|
|
93
93
|
meld_axis lengths are the ragged dimension (may differ). */
|
|
94
94
|
static void
|
|
95
95
|
ca_meld_check_uniform (int32_t n_parents, CArray **parents, int8_t meld_axis)
|
|
@@ -598,19 +598,24 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
598
598
|
int8_t i;
|
|
599
599
|
int structural = 1;
|
|
600
600
|
|
|
601
|
-
|
|
601
|
+
s = ca->bytes;
|
|
602
|
+
for ( i = ca->ndim - 1; i >= 0; i-- ) { native[i] = s; s *= ca->dim[i]; }
|
|
603
|
+
|
|
604
|
+
/* Bound check on meld_axis. The step along the axis is strides[ma] /
|
|
605
|
+
native[ma] and it can be negative -- a reversed read starts at the far
|
|
606
|
+
end and walks down -- so the region runs between the first and last
|
|
607
|
+
index, which is not the same as starts[ma] .. starts[ma] + counts[ma]. */
|
|
602
608
|
{
|
|
603
|
-
ca_size_t
|
|
604
|
-
ca_size_t
|
|
605
|
-
|
|
609
|
+
ca_size_t step = strides[ma] / native[ma];
|
|
610
|
+
ca_size_t last = starts[ma] + (counts[ma] - 1) * step;
|
|
611
|
+
ca_size_t req_lo = ( last < starts[ma] ) ? last : starts[ma];
|
|
612
|
+
ca_size_t req_hi = (( last < starts[ma] ) ? starts[ma] : last) + 1;
|
|
613
|
+
if ( counts[ma] > 0 && ( req_lo < 0 || req_hi > ca->dim[ma] ) ) {
|
|
606
614
|
rb_raise(rb_eIndexError,
|
|
607
615
|
"CAMeld xfer_stride meld_axis (axis %d) [%lld, %lld) out of range [0, %lld)",
|
|
608
616
|
(int) ma, (long long) req_lo, (long long) req_hi, (long long) ca->dim[ma]);
|
|
609
617
|
}
|
|
610
618
|
}
|
|
611
|
-
|
|
612
|
-
s = ca->bytes;
|
|
613
|
-
for ( i = ca->ndim - 1; i >= 0; i-- ) { native[i] = s; s *= ca->dim[i]; }
|
|
614
619
|
for ( i = 0; i < ca->ndim; i++ ) {
|
|
615
620
|
if ( strides[i] != native[i] ) { structural = 0; break; }
|
|
616
621
|
}
|