carray 3.0.4 → 3.0.5
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 +205 -0
- data/carray.gemspec +1 -1
- data/ext/ca_array_pool.c +25 -1
- data/ext/ca_axis_dispatch.c +13 -20
- data/ext/ca_categorical_iterator.c +27 -20
- data/ext/ca_compare.c +4 -4
- data/ext/ca_composite_dispatch.c +9 -9
- data/ext/ca_kernel_iterator.c +6 -6
- data/ext/ca_kernel_iterator.h +112 -83
- data/ext/ca_obj_array.c +69 -19
- data/ext/ca_obj_bincmp.c +1 -0
- data/ext/ca_obj_binop.c +1 -0
- data/ext/ca_obj_bitarray.c +5 -1
- data/ext/ca_obj_bitfield.c +58 -43
- data/ext/ca_obj_byte_swap.c +2 -1
- data/ext/ca_obj_const_string.c +15 -3
- data/ext/ca_obj_face.c +42 -1
- data/ext/ca_obj_field.c +13 -3
- data/ext/ca_obj_grid.c +52 -5
- data/ext/ca_obj_monop.c +46 -10
- data/ext/ca_obj_object.c +64 -12
- data/ext/ca_obj_record.c +3 -0
- data/ext/ca_obj_reduce.c +4 -0
- data/ext/ca_obj_refer.c +18 -9
- data/ext/ca_obj_roll.c +26 -6
- data/ext/ca_obj_select.c +34 -5
- data/ext/ca_obj_shift.c +31 -7
- data/ext/ca_obj_stack.c +1 -0
- data/ext/ca_obj_stride.c +28 -19
- data/ext/ca_obj_string.c +11 -2
- data/ext/ca_obj_tile.c +27 -7
- data/ext/ca_obj_transpose.c +8 -4
- data/ext/ca_obj_triop.c +3 -0
- data/ext/ca_obj_window.c +79 -50
- data/ext/ca_op_ipower.c +4 -4
- data/ext/ca_sort_kernels.h +6 -3
- data/ext/carray.h +33 -0
- data/ext/carray_access.c +16 -3
- data/ext/carray_attribute.c +24 -0
- data/ext/carray_cast.c +243 -82
- data/ext/carray_cast_func.rb +56 -26
- data/ext/carray_conversion.c +2 -2
- data/ext/carray_core.c +3 -0
- data/ext/carray_count.c +6 -0
- data/ext/carray_element.c +9 -4
- data/ext/carray_factorize.c +20 -20
- data/ext/carray_generate.c +8 -2
- data/ext/carray_histogram.c +1 -1
- data/ext/carray_index_classifier.c +4 -4
- data/ext/carray_internal.h +12 -0
- data/ext/carray_kernels_bincmp.c +168 -168
- data/ext/carray_kernels_binop.c +900 -900
- data/ext/carray_kernels_init.c +4 -4
- data/ext/carray_kernels_moncmp.c +96 -96
- data/ext/carray_kernels_monop.c +1984 -1984
- data/ext/carray_kernels_reduce_aggregate.c +1733 -1733
- data/ext/carray_kernels_reduce_cumulative.c +642 -642
- data/ext/carray_kernels_reduce_extreme.c +1150 -1150
- data/ext/carray_kernels_reduce_variance.c +258 -258
- data/ext/carray_kernels_scan.c +128 -128
- data/ext/carray_kernels_search.c +340 -340
- data/ext/carray_kernels_sort.c +295 -304
- data/ext/carray_kernels_triop.c +114 -114
- data/ext/carray_key_windows.c +4 -0
- data/ext/carray_mask.c +45 -22
- data/ext/carray_memory_view.c +2 -2
- data/ext/carray_operator.c +5 -5
- data/ext/carray_order.c +227 -8
- data/ext/carray_random.c +18 -18
- data/ext/carray_scatter.c +24 -7
- data/ext/carray_slab.c +32 -9
- 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_time_text.c +4 -2
- data/ext/carray_utils.c +63 -21
- data/ext/mkkernel.rb +210 -115
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +17 -4
- data/lib/carray/basics.rb +27 -7
- data/lib/carray/categorical.rb +30 -16
- data/lib/carray/categorical_iterator.rb +6 -6
- 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 +4 -3
- data/lib/carray/frame/concat.rb +17 -3
- data/lib/carray/frame/frame.rb +6 -7
- data/lib/carray/frame/group.rb +100 -13
- data/lib/carray/frame/io.rb +3 -1
- data/lib/carray/fuse_source.rb +31 -2
- data/lib/carray/lazy.rb +35 -0
- data/lib/carray/methods/is_in.rb +8 -1
- data/lib/carray/segment_iterator.rb +12 -8
- data/lib/carray/serialize.rb +19 -2
- data/lib/carray/stack.rb +15 -12
- 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 +107 -68
- data/yard-stubs/ca_obj_transpose.rb +5 -4
- data/yard-stubs/carray_attribute.rb +3 -1
- data/yard-stubs/carray_cast.rb +2 -0
- data/yard-stubs/carray_conversion.rb +5 -1
- data/yard-stubs/carray_element.rb +7 -6
- data/yard-stubs/carray_mask.rb +8 -3
- data/yard-stubs/carray_math.rb +14 -4
- data/yard-stubs/carray_order.rb +100 -4
- data/yard-stubs/carray_scatter.rb +7 -5
- metadata +1 -1
data/ext/ca_obj_monop.c
CHANGED
|
@@ -370,12 +370,19 @@ apply_monop_in_place (uint16_t op_id, int8_t cur_dt,
|
|
|
370
370
|
fn(slab_n, mask, (char *) data, 1, (char *) data, 1);
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
-
/*
|
|
374
|
-
ca_cast_block
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
373
|
+
/* A zeroed CArray carrying only data_type and bytes, handed to
|
|
374
|
+
ca_cast_block in place of a real array. It is a whole CArray, not a
|
|
375
|
+
shorter struct cast to one: ca_cast_block reads data_type through a
|
|
376
|
+
CArray pointer, and a fixlen cast reads bytes as well. */
|
|
377
|
+
static CArray
|
|
378
|
+
ca_data_type_stub (int8_t data_type)
|
|
379
|
+
{
|
|
380
|
+
CArray stub;
|
|
381
|
+
memset(&stub, 0, sizeof(stub));
|
|
382
|
+
stub.data_type = data_type;
|
|
383
|
+
stub.bytes = ca_sizeof[data_type];
|
|
384
|
+
return stub;
|
|
385
|
+
}
|
|
379
386
|
|
|
380
387
|
/* Pull leaf into the output buffer. Three paths:
|
|
381
388
|
|
|
@@ -428,8 +435,8 @@ pull_leaf_with_optional_cast (CArray *leaf, uint16_t innermost_op,
|
|
|
428
435
|
if ( has_cast_at_leaf ) {
|
|
429
436
|
/* Path 2: cast scratch → data with output layout in target data_type. */
|
|
430
437
|
int8_t target_dt = (int8_t)(innermost_op - CA_MONOP_CAST_BASE);
|
|
431
|
-
|
|
432
|
-
|
|
438
|
+
CArray src_stub = ca_data_type_stub(leaf->data_type);
|
|
439
|
+
CArray dst_stub = ca_data_type_stub(target_dt);
|
|
433
440
|
ca_cast_block(slab_n, &src_stub, scratch, &dst_stub, data);
|
|
434
441
|
result_dt = target_dt;
|
|
435
442
|
} else {
|
|
@@ -555,6 +562,30 @@ ca_monop_eval (CAMonOp *mo, const ca_lazy_req_t *req, void *data, int dir)
|
|
|
555
562
|
chain_apply_count = chain_len - 1;
|
|
556
563
|
}
|
|
557
564
|
|
|
565
|
+
/* The chain runs in place, so the buffer must hold slab_n cells of the
|
|
566
|
+
widest type along it: the leaf, or a step that widens before a later
|
|
567
|
+
one narrows (cmplx128.lazy.abs pulls 16-byte cells and answers 8-byte
|
|
568
|
+
ones). When that is wider than the output, run in a scratch and copy
|
|
569
|
+
the answer into `data` at the end. */
|
|
570
|
+
void *out = data;
|
|
571
|
+
void *work = NULL;
|
|
572
|
+
{
|
|
573
|
+
ca_size_t max_bytes = leaf->bytes;
|
|
574
|
+
int8_t dt = leaf->data_type;
|
|
575
|
+
for ( i = chain_len - 1; i >= 0; i-- ) {
|
|
576
|
+
dt = ca_monop_is_cast(op_chain[i])
|
|
577
|
+
? (int8_t)(op_chain[i] - CA_MONOP_CAST_BASE)
|
|
578
|
+
: ca_lazy_promote_monop(op_chain[i], dt);
|
|
579
|
+
if ( ca_sizeof[dt] > max_bytes ) max_bytes = ca_sizeof[dt];
|
|
580
|
+
}
|
|
581
|
+
if ( max_bytes > mo->bytes ) {
|
|
582
|
+
work = ( leaf->data_type == CA_OBJECT )
|
|
583
|
+
? ca_lazy_arena_acquire_object((slab_n * max_bytes + sizeof(VALUE) - 1) / sizeof(VALUE))
|
|
584
|
+
: ca_lazy_arena_acquire(slab_n * max_bytes);
|
|
585
|
+
data = work;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
558
589
|
/* === 2. pull leaf into output buffer (with optional cast) === */
|
|
559
590
|
cur_dt = pull_leaf_with_optional_cast(
|
|
560
591
|
leaf,
|
|
@@ -576,8 +607,8 @@ ca_monop_eval (CAMonOp *mo, const ca_lazy_req_t *req, void *data, int dir)
|
|
|
576
607
|
ca_size_t src_bytes = ca_sizeof[cur_dt];
|
|
577
608
|
ca_size_t total_bytes = slab_n * src_bytes;
|
|
578
609
|
void *scratch;
|
|
579
|
-
|
|
580
|
-
|
|
610
|
+
CArray src_stub = ca_data_type_stub(cur_dt);
|
|
611
|
+
CArray dst_stub = ca_data_type_stub(target_dt);
|
|
581
612
|
|
|
582
613
|
/* Copy current data → scratch (in src data_type), then cast scratch
|
|
583
614
|
→ data (in target data_type). Required because in-place cast
|
|
@@ -604,6 +635,10 @@ ca_monop_eval (CAMonOp *mo, const ca_lazy_req_t *req, void *data, int dir)
|
|
|
604
635
|
if ( slab_mask ) {
|
|
605
636
|
ca_lazy_arena_release(slab_mask);
|
|
606
637
|
}
|
|
638
|
+
if ( work ) {
|
|
639
|
+
memcpy(out, work, slab_n * mo->bytes);
|
|
640
|
+
ca_lazy_arena_release(work);
|
|
641
|
+
}
|
|
607
642
|
}
|
|
608
643
|
|
|
609
644
|
static void
|
|
@@ -1116,6 +1151,7 @@ Init_ca_obj_monop (void)
|
|
|
1116
1151
|
rb_define_const(rb_cCAMonOp, "OP_RAD_PI", INT2NUM(CA_MONOP_RAD_PI));
|
|
1117
1152
|
rb_define_const(rb_cCAMonOp, "OP_SIGN", INT2NUM(CA_MONOP_SIGN));
|
|
1118
1153
|
rb_define_const(rb_cCAMonOp, "OP_ARG_I", INT2NUM(CA_MONOP_ARG_I));
|
|
1154
|
+
rb_define_const(rb_cCAMonOp, "OP_BYTE_SWAP", INT2NUM(CA_MONOP_BYTE_SWAP));
|
|
1119
1155
|
rb_define_const(rb_cCAMonOp, "CAST_BASE", INT2NUM(CA_MONOP_CAST_BASE));
|
|
1120
1156
|
|
|
1121
1157
|
rb_define_alloc_func(rb_cCAMonOp, rb_ca_monop_s_allocate);
|
data/ext/ca_obj_object.c
CHANGED
|
@@ -171,18 +171,66 @@ ca_object_empty_wrap (CArray *w)
|
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
/* Moves the cells of a wrap (or of its lent mask, `w`) into an array of
|
|
175
|
+
their own, held by `holder` under `name`, and points `w` at them. The
|
|
176
|
+
cells are those the hook left in the caller's buffer. */
|
|
177
|
+
static void
|
|
178
|
+
ca_object_keep_cells (VALUE holder, const char *name, CArray *w)
|
|
179
|
+
{
|
|
180
|
+
volatile VALUE cells;
|
|
181
|
+
CArray *c;
|
|
182
|
+
cells = rb_carray_new(w->data_type, w->ndim, w->dim, w->bytes, NULL);
|
|
183
|
+
c = (CArray *) DATA_PTR(cells);
|
|
184
|
+
memcpy(c->ptr, w->ptr, (size_t) w->elements * w->bytes);
|
|
185
|
+
rb_ivar_set(holder, rb_intern(name), cells);
|
|
186
|
+
w->ptr = c->ptr;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* Takes the caller's buffer back from a wrap the hook was lent, together
|
|
190
|
+
with `lent_mask`, the wrap of the data's mask bits it was lent with (or
|
|
191
|
+
NULL). When the hook took a view of either, the view outlives the call,
|
|
192
|
+
so both keep their cells; otherwise both are left with none. A mask the
|
|
193
|
+
hook made on the wrap is the wrap's own, with cells of its own. */
|
|
194
|
+
static void
|
|
195
|
+
ca_object_take_back (VALUE wrap, CArray *lent_mask)
|
|
196
|
+
{
|
|
197
|
+
CArray *w = (CArray *) DATA_PTR(wrap);
|
|
198
|
+
CArray *m = ( lent_mask != NULL && w->mask == lent_mask ) ? lent_mask : NULL;
|
|
199
|
+
int viewed = ca_test_flag(w, CA_FLAG_LENT_VIEWED) ||
|
|
200
|
+
( m != NULL && ca_test_flag(m, CA_FLAG_LENT_VIEWED) );
|
|
201
|
+
ca_unset_flag(w, CA_FLAG_LENT | CA_FLAG_LENT_VIEWED);
|
|
202
|
+
if ( lent_mask != NULL ) {
|
|
203
|
+
ca_unset_flag(lent_mask, CA_FLAG_LENT | CA_FLAG_LENT_VIEWED);
|
|
204
|
+
}
|
|
205
|
+
if ( viewed ) {
|
|
206
|
+
ca_object_keep_cells(wrap, "kept_cells", w);
|
|
207
|
+
if ( m != NULL ) {
|
|
208
|
+
ca_object_keep_cells(wrap, "kept_mask_cells", m);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
if ( m != NULL ) {
|
|
213
|
+
ca_object_empty_wrap(m);
|
|
214
|
+
}
|
|
215
|
+
ca_object_empty_wrap(w);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
174
219
|
/* Calls copy_data / sync_data with a wrap of a caller's buffer, shaped as
|
|
175
|
-
the object, and takes the buffer back however the call leaves.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
220
|
+
the object, and takes the buffer back however the call leaves. When the
|
|
221
|
+
data has a mask, the wrap's mask is a wrap of its bits: a hook that writes
|
|
222
|
+
masked values masks the object's cells, and the data keeps its mask
|
|
223
|
+
whatever the hook does with the wrap's. A mask the hook makes on a wrap
|
|
224
|
+
that had none is the wrap's own and goes with it. The data points at the
|
|
225
|
+
buffer for the duration too, for a hook that reads the object back while
|
|
226
|
+
it runs. */
|
|
180
227
|
|
|
181
228
|
typedef struct {
|
|
182
229
|
CAObject *ca;
|
|
183
230
|
char *saved;
|
|
184
231
|
ID mid;
|
|
185
232
|
VALUE wrap;
|
|
233
|
+
CArray *mask; /* the wrap of the data's mask bits, or NULL */
|
|
186
234
|
} ca_object_lend_t;
|
|
187
235
|
|
|
188
236
|
static VALUE
|
|
@@ -196,11 +244,8 @@ static VALUE
|
|
|
196
244
|
ca_object_lend_restore (VALUE varg)
|
|
197
245
|
{
|
|
198
246
|
ca_object_lend_t *l = (ca_object_lend_t *) varg;
|
|
199
|
-
CArray *w = (CArray *) DATA_PTR(l->wrap);
|
|
200
|
-
l->ca->data->mask = w->mask;
|
|
201
|
-
w->mask = NULL;
|
|
202
|
-
ca_object_empty_wrap(w);
|
|
203
247
|
l->ca->data->ptr = l->saved;
|
|
248
|
+
ca_object_take_back(l->wrap, l->mask);
|
|
204
249
|
return Qnil;
|
|
205
250
|
}
|
|
206
251
|
|
|
@@ -213,7 +258,14 @@ ca_object_call_lending (CAObject *ca, void *ptr, const char *mid)
|
|
|
213
258
|
w = ca_wrap_new(data->data_type, data->ndim, data->dim, data->bytes,
|
|
214
259
|
NULL, (char *) ptr);
|
|
215
260
|
l.wrap = ca_wrap_struct(w);
|
|
216
|
-
|
|
261
|
+
l.mask = NULL;
|
|
262
|
+
if ( data->mask != NULL ) {
|
|
263
|
+
l.mask = (CArray *) ca_wrap_new(CA_BOOLEAN, data->ndim, data->dim, 0,
|
|
264
|
+
NULL, data->mask->ptr);
|
|
265
|
+
ca_set_flag(l.mask, CA_FLAG_LENT);
|
|
266
|
+
w->mask = l.mask;
|
|
267
|
+
}
|
|
268
|
+
ca_set_flag(w, CA_FLAG_LENT);
|
|
217
269
|
l.ca = ca;
|
|
218
270
|
l.saved = data->ptr;
|
|
219
271
|
l.mid = rb_intern(mid);
|
|
@@ -253,7 +305,7 @@ ca_object_hook_release (VALUE varg)
|
|
|
253
305
|
ca_object_hook_t *h = (ca_object_hook_t *) varg;
|
|
254
306
|
int i;
|
|
255
307
|
for ( i = 0; i < h->ntrans; i++ ) {
|
|
256
|
-
|
|
308
|
+
ca_object_take_back(h->trans[i], NULL);
|
|
257
309
|
}
|
|
258
310
|
return Qnil;
|
|
259
311
|
}
|
|
@@ -742,7 +794,6 @@ ca_object_setup (CAObject *ca,
|
|
|
742
794
|
int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes)
|
|
743
795
|
{
|
|
744
796
|
ca_size_t elements;
|
|
745
|
-
int8_t i;
|
|
746
797
|
|
|
747
798
|
/* check arguments */
|
|
748
799
|
|
|
@@ -1194,6 +1245,7 @@ ca_object_wrap_transient (int8_t data_type, ca_size_t bytes,
|
|
|
1194
1245
|
}
|
|
1195
1246
|
|
|
1196
1247
|
wrap = ca_wrap_new(data_type, ndim, dim, bytes, NULL, (char *) data);
|
|
1248
|
+
ca_set_flag(wrap, CA_FLAG_LENT);
|
|
1197
1249
|
return ca_wrap_struct(wrap);
|
|
1198
1250
|
}
|
|
1199
1251
|
|
data/ext/ca_obj_record.c
CHANGED
|
@@ -309,6 +309,9 @@ rb_ca_record_s_wrap (int argc, VALUE *argv, VALUE klass)
|
|
|
309
309
|
rb_scan_args(argc, argv, "2", &entity_val, &data_class);
|
|
310
310
|
}
|
|
311
311
|
rb_check_carray_object(entity_val);
|
|
312
|
+
/* A record array (or another Face) is wrapped from its storage, so the
|
|
313
|
+
new record is not a Face over a Face. */
|
|
314
|
+
entity_val = rb_ca_strip_face_value(entity_val);
|
|
312
315
|
return ca_record_build(klass, data_class, entity_val);
|
|
313
316
|
}
|
|
314
317
|
|
data/ext/ca_obj_reduce.c
CHANGED
|
@@ -56,6 +56,10 @@ ca_reduce_setup (CAReduce *ca, CArray *parent, ca_size_t count, ca_size_t offset
|
|
|
56
56
|
"[BUG] CAReduce can't inherit other than boolean array");
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
if ( count <= 0 ) {
|
|
60
|
+
rb_raise(rb_eArgError, "CAReduce: count should be positive");
|
|
61
|
+
}
|
|
62
|
+
|
|
59
63
|
/* ca == NULL asks for the checks above only, so that a constructor can
|
|
60
64
|
run them before it allocates. */
|
|
61
65
|
if ( ca == NULL ) {
|
data/ext/ca_obj_refer.c
CHANGED
|
@@ -145,7 +145,9 @@ ca_refer_setup (CARefer *ca, CArray *parent,
|
|
|
145
145
|
ca_stride_setup_view((CAStride *) ca, CA_OBJ_REFER, parent,
|
|
146
146
|
data_type, bytes, ndim, dim, strides, base_offset);
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
/* A refer of a scalar stays one only while it has the one cell: read as
|
|
149
|
+
narrower elements it is an array of several. */
|
|
150
|
+
if (ca_is_scalar(parent) && ca->elements == 1) {
|
|
149
151
|
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
150
152
|
}
|
|
151
153
|
return 0;
|
|
@@ -211,16 +213,20 @@ ca_refer_func_create_mask (void *ap)
|
|
|
211
213
|
else if (ca->bytes < parent_bytes) {
|
|
212
214
|
/* Divided reinterpret: one parent element splits into
|
|
213
215
|
ratio = parent_bytes / bytes view elements. Build a
|
|
214
|
-
|
|
215
|
-
ratio sub-positions, then
|
|
216
|
-
actual shape.
|
|
216
|
+
repeat of two axes, (parent elements, ratio), that broadcasts
|
|
217
|
+
each parent mask bit across the ratio sub-positions, then
|
|
218
|
+
refer-reshape it to the view's actual shape. Two axes whatever
|
|
219
|
+
the parent's rank, so a parent at CA_RANK_MAX needs no extra
|
|
220
|
+
one. */
|
|
217
221
|
ca_size_t ratio = parent_bytes / ca->bytes;
|
|
218
|
-
ca_size_t
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
+
ca_size_t mdim[2], mstrides[2];
|
|
223
|
+
mdim[0] = ca->parent->elements;
|
|
224
|
+
mdim[1] = ratio;
|
|
225
|
+
mstrides[0] = 1;
|
|
226
|
+
mstrides[1] = 0;
|
|
222
227
|
ca->mask0 =
|
|
223
|
-
(CArray *)
|
|
228
|
+
(CArray *) ca_stride_new(CA_OBJ_REPEAT, ca->parent->mask, CA_BOOLEAN, 1,
|
|
229
|
+
2, mdim, mstrides, 0);
|
|
224
230
|
ca_unset_flag(ca->mask0, CA_FLAG_READ_ONLY);
|
|
225
231
|
/* mask0 has ratio cells per parent element, so the offset is counted
|
|
226
232
|
in those. */
|
|
@@ -619,6 +625,9 @@ rb_ca_reshape (int argc, VALUE *argv, VALUE self)
|
|
|
619
625
|
|
|
620
626
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
621
627
|
|
|
628
|
+
if ( argc == 0 ) {
|
|
629
|
+
rb_raise(rb_eArgError, "reshape: give at least one axis");
|
|
630
|
+
}
|
|
622
631
|
ca_check_rank_fits(argc, "reshape");
|
|
623
632
|
|
|
624
633
|
/* Locate the (at most one) auto-infer placeholder. `-1` is the
|
data/ext/ca_obj_roll.c
CHANGED
|
@@ -112,6 +112,8 @@ ca_roll_setup (CARoll *ca, CArray *parent, ca_size_t *shift)
|
|
|
112
112
|
ca->parent = parent;
|
|
113
113
|
ca->attach = 0;
|
|
114
114
|
ca->nosync = 0;
|
|
115
|
+
ca->reps = NULL; /* set before either allocation can raise */
|
|
116
|
+
ca->dim = NULL;
|
|
115
117
|
ca->reps = ALLOC_N(ca_size_t, ndim); /* repurposed as shift[] */
|
|
116
118
|
ca->dim = ALLOC_N(ca_size_t, ndim);
|
|
117
119
|
|
|
@@ -130,15 +132,33 @@ ca_roll_setup (CARoll *ca, CArray *parent, ca_size_t *shift)
|
|
|
130
132
|
return 0;
|
|
131
133
|
}
|
|
132
134
|
|
|
135
|
+
typedef struct {
|
|
136
|
+
CARoll *ca;
|
|
137
|
+
CArray *parent;
|
|
138
|
+
ca_size_t *shift;
|
|
139
|
+
} ca_roll_new_arg;
|
|
140
|
+
|
|
141
|
+
static VALUE
|
|
142
|
+
ca_roll_new_setup (VALUE varg)
|
|
143
|
+
{
|
|
144
|
+
ca_roll_new_arg *a = (ca_roll_new_arg *) varg;
|
|
145
|
+
ca_roll_setup(a->ca, a->parent, a->shift);
|
|
146
|
+
return Qnil;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* The setup allocates reps and dim after the struct: when either fails,
|
|
150
|
+
the struct goes too. */
|
|
133
151
|
CARoll *
|
|
134
152
|
ca_roll_new (CArray *parent, ca_size_t *shift)
|
|
135
153
|
{
|
|
136
|
-
|
|
154
|
+
ca_roll_new_arg a;
|
|
137
155
|
ca_roll_setup(NULL, parent, shift);
|
|
138
|
-
ca
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
156
|
+
a.ca = ALLOC(CARoll);
|
|
157
|
+
a.parent = parent;
|
|
158
|
+
a.shift = shift;
|
|
159
|
+
ca_fill_or_free((CArray *) a.ca, ca_roll_new_setup, (VALUE) &a);
|
|
160
|
+
ca_fill_or_free((CArray *) a.ca, ca_view_inherit_mask, (VALUE) a.ca);
|
|
161
|
+
return a.ca;
|
|
142
162
|
}
|
|
143
163
|
|
|
144
164
|
static void
|
|
@@ -629,7 +649,7 @@ rb_ca_roll (int argc, VALUE *argv, VALUE self)
|
|
|
629
649
|
}
|
|
630
650
|
for ( i = 0; i < ca->ndim; i++ ) {
|
|
631
651
|
if ( i < argc ) {
|
|
632
|
-
shift[i] =
|
|
652
|
+
shift[i] = ca_integer_arg(argv[i], "a shift", NULL);
|
|
633
653
|
} else {
|
|
634
654
|
shift[i] = 0;
|
|
635
655
|
}
|
data/ext/ca_obj_select.c
CHANGED
|
@@ -130,7 +130,8 @@ ca_select_snapshot (CArray *select)
|
|
|
130
130
|
|
|
131
131
|
/* Set up the view over `parent` from an owned selector snapshot (see
|
|
132
132
|
ca_select_snapshot) and pre-compute ca->indices (TRUE positions in flat
|
|
133
|
-
parent order).
|
|
133
|
+
parent order). Raises only when the indices cannot be allocated, after
|
|
134
|
+
every field free_ca_select reads is set. */
|
|
134
135
|
static int
|
|
135
136
|
ca_select_setup (CASelect *ca, CArray *parent, CArray *snapshot)
|
|
136
137
|
{
|
|
@@ -211,14 +212,42 @@ ca_select_setup (CASelect *ca, CArray *parent, CArray *snapshot)
|
|
|
211
212
|
return 0;
|
|
212
213
|
}
|
|
213
214
|
|
|
215
|
+
typedef struct {
|
|
216
|
+
CASelect *ca;
|
|
217
|
+
CArray *parent;
|
|
218
|
+
CArray *snapshot;
|
|
219
|
+
} ca_select_new_arg;
|
|
220
|
+
|
|
221
|
+
static VALUE
|
|
222
|
+
ca_select_new_alloc (VALUE varg)
|
|
223
|
+
{
|
|
224
|
+
ca_select_new_arg *a = (ca_select_new_arg *) varg;
|
|
225
|
+
a->ca = ALLOC(CASelect);
|
|
226
|
+
return Qnil;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
static VALUE
|
|
230
|
+
ca_select_new_setup (VALUE varg)
|
|
231
|
+
{
|
|
232
|
+
ca_select_new_arg *a = (ca_select_new_arg *) varg;
|
|
233
|
+
ca_select_setup(a->ca, a->parent, a->snapshot);
|
|
234
|
+
return Qnil;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/* The struct and the indices are allocated after the snapshot. When the
|
|
238
|
+
struct cannot be allocated the snapshot goes; when the indices cannot,
|
|
239
|
+
the struct goes and takes the snapshot with it (the setup stores the
|
|
240
|
+
snapshot before it allocates the indices). */
|
|
214
241
|
CArray *
|
|
215
242
|
ca_select_new (CArray *parent, CArray *select)
|
|
216
243
|
{
|
|
217
|
-
|
|
244
|
+
ca_select_new_arg a;
|
|
245
|
+
a.parent = parent;
|
|
246
|
+
a.snapshot = ca_select_snapshot(select);
|
|
218
247
|
/* check: the setup checks nothing */
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return (CArray*) ca;
|
|
248
|
+
ca_fill_or_free(a.snapshot, ca_select_new_alloc, (VALUE) &a);
|
|
249
|
+
ca_fill_or_free((CArray *) a.ca, ca_select_new_setup, (VALUE) &a);
|
|
250
|
+
return (CArray*) a.ca;
|
|
222
251
|
}
|
|
223
252
|
|
|
224
253
|
/* Alias for source compatibility. Both constructors produce a
|
data/ext/ca_obj_shift.c
CHANGED
|
@@ -120,16 +120,40 @@ ca_shift_setup (CAShift *ca, CArray *parent,
|
|
|
120
120
|
return 0;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
typedef struct {
|
|
124
|
+
CAShift *ca;
|
|
125
|
+
CArray *parent;
|
|
126
|
+
ca_size_t *shift;
|
|
127
|
+
char *fill;
|
|
128
|
+
int8_t *roll;
|
|
129
|
+
int fill_mask;
|
|
130
|
+
} ca_shift_new_arg;
|
|
131
|
+
|
|
132
|
+
static VALUE
|
|
133
|
+
ca_shift_new_setup (VALUE varg)
|
|
134
|
+
{
|
|
135
|
+
ca_shift_new_arg *a = (ca_shift_new_arg *) varg;
|
|
136
|
+
ca_shift_setup(a->ca, a->parent, a->shift, a->fill, a->roll, a->fill_mask);
|
|
137
|
+
return Qnil;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* The setup allocates the fill value after the struct and its pool: when
|
|
141
|
+
that fails, the struct goes too. */
|
|
123
142
|
CAShift *
|
|
124
143
|
ca_shift_new (CArray *parent, ca_size_t *shift, char *fill, int8_t *roll,
|
|
125
144
|
int fill_mask)
|
|
126
145
|
{
|
|
127
|
-
|
|
146
|
+
ca_shift_new_arg a;
|
|
128
147
|
ca_shift_setup(NULL, parent, shift, fill, roll, fill_mask);
|
|
129
|
-
ca
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
148
|
+
a.ca = (CAShift *) ca_array_alloc(CA_OBJ_SHIFT, parent->ndim);
|
|
149
|
+
a.parent = parent;
|
|
150
|
+
a.shift = shift;
|
|
151
|
+
a.fill = fill;
|
|
152
|
+
a.roll = roll;
|
|
153
|
+
a.fill_mask = fill_mask;
|
|
154
|
+
ca_fill_or_free((CArray *) a.ca, ca_shift_new_setup, (VALUE) &a);
|
|
155
|
+
ca_fill_or_free((CArray *) a.ca, ca_window_create_bounds_mask, (VALUE) a.ca);
|
|
156
|
+
return a.ca;
|
|
133
157
|
}
|
|
134
158
|
|
|
135
159
|
/* Clone: produce a CAShift (not CAWindow) by rebuilding via setup.
|
|
@@ -216,7 +240,7 @@ rb_ca_shift (int argc, VALUE *argv, VALUE self)
|
|
|
216
240
|
}
|
|
217
241
|
|
|
218
242
|
for (i=0; i<ca->ndim; i++) {
|
|
219
|
-
shift[i] =
|
|
243
|
+
shift[i] = ca_integer_arg(argv[i], "a shift", NULL);
|
|
220
244
|
}
|
|
221
245
|
|
|
222
246
|
if ( rb_block_given_p() ) {
|
|
@@ -264,7 +288,7 @@ rb_ca_shift (int argc, VALUE *argv, VALUE self)
|
|
|
264
288
|
}
|
|
265
289
|
|
|
266
290
|
for (i=0; i<ca->ndim; i++) {
|
|
267
|
-
roll[i] =
|
|
291
|
+
roll[i] = ca_integer_arg(rb_ary_entry(rroll, i), "a shift", NULL);
|
|
268
292
|
}
|
|
269
293
|
}
|
|
270
294
|
|
data/ext/ca_obj_stack.c
CHANGED
|
@@ -970,6 +970,7 @@ ca_stack_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
|
|
|
970
970
|
correct (if non-folded) per-parent dispatch. */
|
|
971
971
|
if ( ca->k_axis != 0 ) return 0;
|
|
972
972
|
if ( ! ca_fast_paths_enabled() ) return 0;
|
|
973
|
+
if ( pbt == 0 ) return 0; /* empty parents: no parent holds the box */
|
|
973
974
|
|
|
974
975
|
for ( i = 0; i < f->ndim; i++ ) {
|
|
975
976
|
ca_size_t span = (f->counts[i] - 1) * f->strides[i];
|
data/ext/ca_obj_stride.c
CHANGED
|
@@ -247,6 +247,10 @@ ca_stride_compose_through (CAStride *leaf, CAStride *parent,
|
|
|
247
247
|
for (k = parent->ndim - 1; k >= 0; k--)
|
|
248
248
|
prod[k] = prod[k + 1] * parent->dim[k];
|
|
249
249
|
|
|
250
|
+
/* A parent with a zero-length axis has no cell for the leaf to start at
|
|
251
|
+
(and prod[] below would divide by zero). */
|
|
252
|
+
if (prod[0] == 0) return 0;
|
|
253
|
+
|
|
250
254
|
/* Compose base offset first. We need the per-dim base position
|
|
251
255
|
to validate stride composition against parent dim bounds (a small
|
|
252
256
|
forward stride starting near the end of a parent dim wraps into
|
|
@@ -1686,19 +1690,19 @@ ca_stride_func_fill_data (void *ap, void *ptr)
|
|
|
1686
1690
|
}
|
|
1687
1691
|
case 2: {
|
|
1688
1692
|
int16_t v; memcpy(&v, ptr, 2);
|
|
1689
|
-
|
|
1693
|
+
ca_u_int16_t *d = (ca_u_int16_t *) dst;
|
|
1690
1694
|
for (i = 0; i < inner_count; i++) d[i] = v;
|
|
1691
1695
|
break;
|
|
1692
1696
|
}
|
|
1693
1697
|
case 4: {
|
|
1694
1698
|
int32_t v; memcpy(&v, ptr, 4);
|
|
1695
|
-
|
|
1699
|
+
ca_u_int32_t *d = (ca_u_int32_t *) dst;
|
|
1696
1700
|
for (i = 0; i < inner_count; i++) d[i] = v;
|
|
1697
1701
|
break;
|
|
1698
1702
|
}
|
|
1699
1703
|
case 8: {
|
|
1700
1704
|
int64_t v; memcpy(&v, ptr, 8);
|
|
1701
|
-
|
|
1705
|
+
ca_u_int64_t *d = (ca_u_int64_t *) dst;
|
|
1702
1706
|
for (i = 0; i < inner_count; i++) d[i] = v;
|
|
1703
1707
|
break;
|
|
1704
1708
|
}
|
|
@@ -2164,11 +2168,11 @@ rb_ca_as_strided (int argc, VALUE *argv, VALUE self)
|
|
|
2164
2168
|
ca_check_rank_fits(len, NULL);
|
|
2165
2169
|
ndim = (int8_t) len;
|
|
2166
2170
|
for (i = 0; i < len; i++) {
|
|
2167
|
-
shape[i] =
|
|
2168
|
-
strides[i] =
|
|
2171
|
+
shape[i] = ca_integer_arg(RARRAY_AREF(rshape, i), "a length", NULL);
|
|
2172
|
+
strides[i] = ca_integer_arg(RARRAY_AREF(rstrides, i), "a stride", NULL);
|
|
2169
2173
|
}
|
|
2170
2174
|
if (! NIL_P(roffset)) {
|
|
2171
|
-
base_offset =
|
|
2175
|
+
base_offset = ca_integer_arg(roffset, "offset", NULL);
|
|
2172
2176
|
}
|
|
2173
2177
|
|
|
2174
2178
|
VALUE obj = rb_ca_stride_new(self, parent->data_type, parent->bytes,
|
|
@@ -2215,12 +2219,12 @@ rb_ca_sliding_windows (int argc, VALUE *argv, VALUE self)
|
|
|
2215
2219
|
RARRAY_LEN(wary), (int) ndim);
|
|
2216
2220
|
}
|
|
2217
2221
|
for (i = 0; i < ndim; i++) {
|
|
2218
|
-
window[i] =
|
|
2222
|
+
window[i] = ca_integer_arg(RARRAY_AREF(wary, i), "a window size", NULL);
|
|
2219
2223
|
}
|
|
2220
2224
|
}
|
|
2221
2225
|
else if (nargs == ndim) {
|
|
2222
2226
|
for (i = 0; i < ndim; i++) {
|
|
2223
|
-
window[i] =
|
|
2227
|
+
window[i] = ca_integer_arg(RARRAY_AREF(rposary, i), "a window size", NULL);
|
|
2224
2228
|
}
|
|
2225
2229
|
}
|
|
2226
2230
|
else {
|
|
@@ -2239,11 +2243,11 @@ rb_ca_sliding_windows (int argc, VALUE *argv, VALUE self)
|
|
|
2239
2243
|
RARRAY_LEN(rstep), (int) ndim);
|
|
2240
2244
|
}
|
|
2241
2245
|
for (i = 0; i < ndim; i++) {
|
|
2242
|
-
step[i] =
|
|
2246
|
+
step[i] = ca_integer_arg(RARRAY_AREF(rstep, i), "a step", NULL);
|
|
2243
2247
|
}
|
|
2244
2248
|
}
|
|
2245
2249
|
else {
|
|
2246
|
-
ca_size_t s =
|
|
2250
|
+
ca_size_t s = ca_integer_arg(rstep, "step", NULL);
|
|
2247
2251
|
for (i = 0; i < ndim; i++) step[i] = s;
|
|
2248
2252
|
}
|
|
2249
2253
|
|
|
@@ -2326,13 +2330,13 @@ rb_ca_unfold (int argc, VALUE *argv, VALUE self)
|
|
|
2326
2330
|
}
|
|
2327
2331
|
nspatial = (int8_t) RARRAY_LEN(wary);
|
|
2328
2332
|
for (i = 0; i < nspatial; i++) {
|
|
2329
|
-
window[i] =
|
|
2333
|
+
window[i] = ca_integer_arg(RARRAY_AREF(wary, i), "a window size", NULL);
|
|
2330
2334
|
}
|
|
2331
2335
|
}
|
|
2332
2336
|
else if (nargs >= 1 && nargs <= ndim) {
|
|
2333
2337
|
nspatial = (int8_t) nargs;
|
|
2334
2338
|
for (i = 0; i < nspatial; i++) {
|
|
2335
|
-
window[i] =
|
|
2339
|
+
window[i] = ca_integer_arg(RARRAY_AREF(rposary, i), "a window size", NULL);
|
|
2336
2340
|
}
|
|
2337
2341
|
}
|
|
2338
2342
|
else {
|
|
@@ -2355,11 +2359,11 @@ rb_ca_unfold (int argc, VALUE *argv, VALUE self)
|
|
|
2355
2359
|
RARRAY_LEN(rstep), (int) nspatial);
|
|
2356
2360
|
}
|
|
2357
2361
|
for (i = 0; i < nspatial; i++) {
|
|
2358
|
-
step[i] =
|
|
2362
|
+
step[i] = ca_integer_arg(RARRAY_AREF(rstep, i), "a step", NULL);
|
|
2359
2363
|
}
|
|
2360
2364
|
}
|
|
2361
2365
|
else {
|
|
2362
|
-
ca_size_t s =
|
|
2366
|
+
ca_size_t s = ca_integer_arg(rstep, "step", NULL);
|
|
2363
2367
|
for (i = 0; i < nspatial; i++) step[i] = s;
|
|
2364
2368
|
}
|
|
2365
2369
|
|
|
@@ -2441,12 +2445,12 @@ rb_ca_block_view (int argc, VALUE *argv, VALUE self)
|
|
|
2441
2445
|
RARRAY_LEN(bary), (int) ndim);
|
|
2442
2446
|
}
|
|
2443
2447
|
for (i = 0; i < ndim; i++) {
|
|
2444
|
-
block[i] =
|
|
2448
|
+
block[i] = ca_integer_arg(RARRAY_AREF(bary, i), "a block size", NULL);
|
|
2445
2449
|
}
|
|
2446
2450
|
}
|
|
2447
2451
|
else if (nargs == ndim) {
|
|
2448
2452
|
for (i = 0; i < ndim; i++) {
|
|
2449
|
-
block[i] =
|
|
2453
|
+
block[i] = ca_integer_arg(RARRAY_AREF(rposary, i), "a block size", NULL);
|
|
2450
2454
|
}
|
|
2451
2455
|
}
|
|
2452
2456
|
else {
|
|
@@ -2571,7 +2575,12 @@ rb_ca_dim_view (int argc, VALUE *argv, VALUE self)
|
|
|
2571
2575
|
if (! seen[i]) imap[k++] = i;
|
|
2572
2576
|
}
|
|
2573
2577
|
|
|
2574
|
-
|
|
2578
|
+
{
|
|
2579
|
+
/* A reordering of the axes, as transpose is: a Face stays its Face. */
|
|
2580
|
+
volatile VALUE obj = rb_ca_trans_new(self, imap);
|
|
2581
|
+
CA_WRAPPER_LIFT(obj, self, parent);
|
|
2582
|
+
return obj;
|
|
2583
|
+
}
|
|
2575
2584
|
}
|
|
2576
2585
|
|
|
2577
2586
|
/* flip(*axes) -- reverses the listed axes by negating their strides; with no
|
|
@@ -2740,14 +2749,14 @@ rb_ca_diagonal (int argc, VALUE *argv, VALUE self)
|
|
|
2740
2749
|
|
|
2741
2750
|
/* offset from positional or keyword (not both) */
|
|
2742
2751
|
if (nargs == 0) {
|
|
2743
|
-
if (! NIL_P(roffset)) offset =
|
|
2752
|
+
if (! NIL_P(roffset)) offset = ca_integer_arg(roffset, "offset", NULL);
|
|
2744
2753
|
}
|
|
2745
2754
|
else if (nargs == 1) {
|
|
2746
2755
|
if (! NIL_P(roffset)) {
|
|
2747
2756
|
rb_raise(rb_eArgError,
|
|
2748
2757
|
"diagonal: give offset positionally OR as keyword, not both");
|
|
2749
2758
|
}
|
|
2750
|
-
offset =
|
|
2759
|
+
offset = ca_integer_arg(RARRAY_AREF(rposary, 0), "offset", NULL);
|
|
2751
2760
|
}
|
|
2752
2761
|
else {
|
|
2753
2762
|
rb_raise(rb_eArgError,
|
data/ext/ca_obj_string.c
CHANGED
|
@@ -216,7 +216,10 @@ 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 an entity 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. */
|
|
220
223
|
static void
|
|
221
224
|
ca_string_check_cells (VALUE parent_val, CArray *parent)
|
|
222
225
|
{
|
|
@@ -226,8 +229,14 @@ ca_string_check_cells (VALUE parent_val, CArray *parent)
|
|
|
226
229
|
VALUE *p = (VALUE *) parent->ptr;
|
|
227
230
|
boolean8_t *m = ( parent->mask && parent->mask->ptr )
|
|
228
231
|
? (boolean8_t *) parent->mask->ptr : NULL;
|
|
232
|
+
int writable = ! ca_is_readonly(parent);
|
|
229
233
|
for (i = 0; i < parent->elements; i++) {
|
|
230
|
-
if ( m && m[i] )
|
|
234
|
+
if ( m && m[i] ) {
|
|
235
|
+
if ( writable && ! RB_TYPE_P(p[i], T_STRING) ) {
|
|
236
|
+
p[i] = rb_utf8_str_new("", 0);
|
|
237
|
+
}
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
231
240
|
if ( ! RB_TYPE_P(p[i], T_STRING) ) {
|
|
232
241
|
snprintf(where, sizeof(where), "cell %" PRId64, (int64_t) i);
|
|
233
242
|
ca_string_refuse_cell(p[i], where);
|