carray 3.0.6 → 3.0.7
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 +110 -0
- data/README.md +24 -3
- data/carray.gemspec +1 -1
- data/ext/ca_axis_group.c +6 -6
- data/ext/ca_binop_dispatch.c +8 -0
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +7 -7
- data/ext/ca_kernel_iterator.h +6 -4
- data/ext/ca_obj_array.c +4 -4
- data/ext/ca_obj_bincmp.c +19 -3
- data/ext/ca_obj_binop.c +36 -11
- data/ext/ca_obj_bitarray.c +2 -4
- data/ext/ca_obj_bitfield.c +86 -4
- data/ext/ca_obj_byte_swap.c +2 -4
- data/ext/ca_obj_const_string.c +422 -257
- data/ext/ca_obj_face.c +71 -33
- data/ext/ca_obj_fake.c +112 -13
- data/ext/ca_obj_farray.c +7 -1
- data/ext/ca_obj_fixlen_string.c +51 -17
- data/ext/ca_obj_grid.c +12 -7
- data/ext/ca_obj_meld.c +5 -5
- data/ext/ca_obj_monop.c +65 -39
- data/ext/ca_obj_object.c +9 -9
- data/ext/ca_obj_reduce.c +2 -4
- data/ext/ca_obj_refer.c +104 -10
- data/ext/ca_obj_repeat.c +1 -1
- data/ext/ca_obj_roll.c +2 -4
- data/ext/ca_obj_select.c +8 -6
- data/ext/ca_obj_select_axis.c +8 -6
- data/ext/ca_obj_stack.c +5 -5
- data/ext/ca_obj_stride.c +46 -8
- data/ext/ca_obj_string.c +2 -2
- data/ext/ca_obj_tile.c +2 -4
- data/ext/ca_obj_triop.c +15 -12
- data/ext/ca_obj_window.c +22 -15
- data/ext/ca_op_ipower.c +63 -15
- data/ext/ca_op_powi.h +6 -29
- data/ext/ca_sort_kernels.h +3 -0
- data/ext/ca_sweep_engine.c +90 -23
- data/ext/ca_sweep_engine.h +5 -6
- data/ext/caframe_csv_reader.c +1 -1
- data/ext/carray.h +3 -1
- data/ext/carray_access.c +98 -39
- data/ext/carray_address_basis.c +98 -24
- data/ext/carray_broadcast.c +2 -2
- data/ext/carray_call_cfunc.c +5 -8
- data/ext/carray_cast.c +311 -37
- data/ext/carray_cast_func.rb +37 -5
- data/ext/carray_conversion.c +56 -2
- data/ext/carray_copy.c +24 -0
- data/ext/carray_core.c +69 -6
- data/ext/carray_count.c +28 -9
- data/ext/carray_element.c +9 -3
- data/ext/carray_factorize.c +11 -11
- data/ext/carray_histogram.c +2 -2
- data/ext/carray_index_classifier.c +7 -5
- data/ext/carray_internal.h +94 -0
- data/ext/carray_kernels_binop.c +55 -55
- data/ext/carray_kernels_init.c +14 -14
- data/ext/carray_kernels_monop.c +90 -140
- data/ext/carray_lazy.c +16 -1
- data/ext/carray_loop.c +9 -2
- data/ext/carray_mask.c +118 -11
- data/ext/carray_median_percentile.c +13 -8
- data/ext/carray_memory_view.c +41 -22
- data/ext/carray_operator.c +72 -11
- data/ext/carray_order.c +52 -9
- data/ext/carray_partition.c +1 -1
- data/ext/carray_random.c +1 -1
- data/ext/carray_round.c +24 -1
- data/ext/carray_scatter.c +4 -0
- data/ext/carray_segment.c +1 -1
- data/ext/carray_slab.c +13 -4
- data/ext/carray_sort.c +6 -3
- data/ext/carray_sort_kernel.c +24 -0
- data/ext/carray_struct.c +21 -6
- data/ext/carray_test.c +85 -39
- data/ext/carray_time_text.c +6 -0
- data/ext/carray_utils.c +124 -54
- data/ext/mk_call_cfunc.rb +6 -11
- data/ext/mkkernel.rb +37 -27
- data/ext/version.h +4 -4
- data/lib/carray/axis_group.rb +9 -6
- data/lib/carray/basics.rb +26 -8
- data/lib/carray/bincount_nd.rb +8 -2
- data/lib/carray/block_iterator.rb +48 -21
- data/lib/carray/categorical.rb +21 -8
- data/lib/carray/categorical_iterator.rb +2 -1
- data/lib/carray/conditional.rb +52 -4
- data/lib/carray/const_string.rb +74 -0
- data/lib/carray/construct.rb +2 -2
- data/lib/carray/core_extensions.rb +19 -68
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/fixlen_string.rb +83 -1
- data/lib/carray/frame/column_verbs.rb +61 -6
- data/lib/carray/frame/concat.rb +50 -6
- data/lib/carray/frame/csv_parser.rb +13 -4
- data/lib/carray/frame/frame.rb +38 -6
- data/lib/carray/frame/group.rb +67 -40
- data/lib/carray/frame/io.rb +10 -5
- data/lib/carray/frame/join.rb +20 -6
- data/lib/carray/frame/records.rb +6 -4
- data/lib/carray/frame/reshape.rb +25 -5
- data/lib/carray/frame/verbs.rb +78 -25
- data/lib/carray/frame/windows.rb +30 -6
- data/lib/carray/fuse_source.rb +4 -2
- data/lib/carray/iterator.rb +8 -0
- data/lib/carray/key_windows.rb +10 -4
- data/lib/carray/lazy.rb +12 -17
- data/lib/carray/methods/bin.rb +3 -0
- data/lib/carray/methods/composition.rb +1 -1
- data/lib/carray/methods/factorize.rb +2 -0
- data/lib/carray/methods/gather_nd.rb +4 -1
- data/lib/carray/methods/is_in.rb +23 -3
- data/lib/carray/methods/locate_addr.rb +63 -12
- data/lib/carray/methods/repeat.rb +11 -1
- data/lib/carray/record_order.rb +35 -6
- data/lib/carray/runtime.rb +10 -0
- data/lib/carray/segment_iterator.rb +19 -16
- data/lib/carray/serialize.rb +22 -0
- data/lib/carray/slab_iterator.rb +1 -1
- data/lib/carray/stack.rb +3 -3
- data/lib/carray/string.rb +6 -6
- data/lib/carray/string_operation_extension.rb +25 -4
- data/lib/carray/struct_builder.rb +4 -1
- data/lib/carray/time.rb +190 -46
- data/lib/carray/window_iterator.rb +48 -12
- data/yard-stubs/ca_obj_bitfield.rb +4 -1
- data/yard-stubs/ca_obj_refer.rb +3 -0
- data/yard-stubs/ca_obj_window.rb +2 -1
- data/yard-stubs/carray_access.rb +4 -2
- data/yard-stubs/carray_cast.rb +6 -0
- data/yard-stubs/carray_count.rb +6 -3
- data/yard-stubs/carray_math.rb +5 -0
- data/yard-stubs/carray_order.rb +6 -0
- data/yard-stubs/carray_scatter.rb +2 -1
- data/yard-stubs/carray_test.rb +18 -5
- metadata +2 -2
data/ext/ca_sweep_engine.c
CHANGED
|
@@ -36,6 +36,28 @@ ca_sweep_shape_str (CArray *ca)
|
|
|
36
36
|
return s;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/* fsync is the kernel author's string: one '0' (input) or '1' (output) per
|
|
40
|
+
* operand. Any other character would read as neither, and that operand
|
|
41
|
+
* would be neither written back nor given a mask. */
|
|
42
|
+
static void
|
|
43
|
+
ca_sweep_check_fsync (ca_sweep_state_t *st, const char *fallback_label)
|
|
44
|
+
{
|
|
45
|
+
int k_op;
|
|
46
|
+
if ((int) strlen(st->fsync) != st->n_ops) {
|
|
47
|
+
rb_raise(rb_eRuntimeError,
|
|
48
|
+
"[BUG] invalid length of fsync arg in %s (expected %d)",
|
|
49
|
+
st->src_label ? st->src_label : fallback_label, st->n_ops);
|
|
50
|
+
}
|
|
51
|
+
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
52
|
+
if (st->fsync[k_op] != '0' && st->fsync[k_op] != '1') {
|
|
53
|
+
rb_raise(rb_eRuntimeError,
|
|
54
|
+
"[BUG] invalid character '%c' in fsync arg \"%s\" in %s "
|
|
55
|
+
"(expected '0' or '1')", st->fsync[k_op], st->fsync,
|
|
56
|
+
st->src_label ? st->src_label : fallback_label);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
39
61
|
void
|
|
40
62
|
ca_sweep_refuse_shapes (CArray *a, CArray *b)
|
|
41
63
|
{
|
|
@@ -60,8 +82,10 @@ ca_sweep_same_shape (CArray *a, CArray *b)
|
|
|
60
82
|
|
|
61
83
|
/* Pair the operands: a scalar walks with stride 0, every other operand
|
|
62
84
|
* must have the shape of the first non-scalar one, which is returned (NULL
|
|
63
|
-
* when all operands are scalars).
|
|
64
|
-
*
|
|
85
|
+
* when all operands are scalars). A scalar OUTPUT would have every cell of
|
|
86
|
+
* the walk written over one cell, so it is refused beside an array. Sets
|
|
87
|
+
* stride[] and n_kernel. Allocates nothing, so it runs before any operand
|
|
88
|
+
* is acquired. */
|
|
65
89
|
static CArray *
|
|
66
90
|
ca_sweep_pair_operands (ca_sweep_state_t *st)
|
|
67
91
|
{
|
|
@@ -82,6 +106,14 @@ ca_sweep_pair_operands (ca_sweep_state_t *st)
|
|
|
82
106
|
ca_sweep_refuse_shapes(donor, ca);
|
|
83
107
|
}
|
|
84
108
|
}
|
|
109
|
+
for (k_op = 0; donor && k_op < st->n_ops; k_op++) {
|
|
110
|
+
if (st->fsync[k_op] == '1' && ca_is_scalar(st->cx[k_op])) {
|
|
111
|
+
rb_raise(rb_eArgError,
|
|
112
|
+
"%s: a scalar output has one cell, and an array of %lld cells "
|
|
113
|
+
"was given as an operand; a scalar output pairs only with "
|
|
114
|
+
"scalars", ca_calling_method_name(), (long long) st->n_kernel);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
85
117
|
return donor;
|
|
86
118
|
}
|
|
87
119
|
|
|
@@ -117,6 +149,29 @@ ca_sweep_any_input_mask (ca_sweep_state_t *st)
|
|
|
117
149
|
return 0;
|
|
118
150
|
}
|
|
119
151
|
|
|
152
|
+
/* The whole-buffer scratch for INPUT ca. Object cells read from a lazy
|
|
153
|
+
* operand or a CAObject exist nowhere else until the kernel has used them,
|
|
154
|
+
* and the kernel may call Ruby, so the scratch is held for GC as long as it
|
|
155
|
+
* lives. It is recorded in owned_buf before the hold, which can raise. */
|
|
156
|
+
static char *
|
|
157
|
+
ca_sweep_scratch_alloc (ca_sweep_state_t *st, int k_op)
|
|
158
|
+
{
|
|
159
|
+
CArray *ca = st->cx[k_op];
|
|
160
|
+
st->owned_buf[k_op] = xmalloc(ca->elements * ca->bytes);
|
|
161
|
+
if (ca->data_type == CA_OBJECT) {
|
|
162
|
+
ca_object_cells_clear(st->owned_buf[k_op], ca->elements);
|
|
163
|
+
ca_gc_hold_buffer(st->owned_buf[k_op], ca->elements);
|
|
164
|
+
}
|
|
165
|
+
return st->owned_buf[k_op];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static void
|
|
169
|
+
ca_sweep_scratch_free (void *buf)
|
|
170
|
+
{
|
|
171
|
+
ca_gc_release_buffer(buf);
|
|
172
|
+
xfree(buf);
|
|
173
|
+
}
|
|
174
|
+
|
|
120
175
|
/* Give back everything acquire has taken so far, without syncing: detach
|
|
121
176
|
* attached operands, free owned scratch (xmalloc on the whole-buffer path,
|
|
122
177
|
* arena on the chunked one) and the mask buffers. Called when a read
|
|
@@ -132,7 +187,7 @@ ca_sweep_abort (ca_sweep_state_t *st, int chunked)
|
|
|
132
187
|
ca_detach(st->cx[k_op]);
|
|
133
188
|
} else if (st->owned_buf[k_op]) {
|
|
134
189
|
if (chunked) ca_lazy_arena_release(st->owned_buf[k_op]);
|
|
135
|
-
else
|
|
190
|
+
else ca_sweep_scratch_free(st->owned_buf[k_op]);
|
|
136
191
|
}
|
|
137
192
|
st->owned_buf[k_op] = NULL;
|
|
138
193
|
}
|
|
@@ -147,6 +202,21 @@ ca_sweep_abort (ca_sweep_state_t *st, int chunked)
|
|
|
147
202
|
}
|
|
148
203
|
}
|
|
149
204
|
|
|
205
|
+
/* The outputs' masks are overwritten by the OR of the input masks. When no
|
|
206
|
+
* input is masked that is all clear, and there is no m0 to carry it: clear
|
|
207
|
+
* them here, before an output is attached, so a view gathers the cleared
|
|
208
|
+
* mask. An output without a mask does not get one. */
|
|
209
|
+
static void
|
|
210
|
+
ca_sweep_clear_output_masks (ca_sweep_state_t *st)
|
|
211
|
+
{
|
|
212
|
+
int k_op;
|
|
213
|
+
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
214
|
+
if (st->fsync[k_op] == '1' && ca_has_mask(st->cx[k_op])) {
|
|
215
|
+
ca_clear_mask(st->cx[k_op]);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
150
220
|
typedef struct {
|
|
151
221
|
ca_sweep_state_t *st;
|
|
152
222
|
int any_input_mask;
|
|
@@ -163,6 +233,8 @@ ca_sweep_acquire_body (VALUE arg)
|
|
|
163
233
|
ca_sweep_state_t *st = ctx->st;
|
|
164
234
|
int k_op;
|
|
165
235
|
|
|
236
|
+
if (!ctx->any_input_mask) ca_sweep_clear_output_masks(st);
|
|
237
|
+
|
|
166
238
|
/* Per-operand acquire:
|
|
167
239
|
* OUTPUT (fsync == '1') -> ca_attach + base = ca->ptr
|
|
168
240
|
* INPUT alias -> ca_attach + base = ca->ptr
|
|
@@ -178,9 +250,7 @@ ca_sweep_acquire_body (VALUE arg)
|
|
|
178
250
|
st->attached[k_op] = 1;
|
|
179
251
|
st->base[k_op] = (char *) ca->ptr;
|
|
180
252
|
} else {
|
|
181
|
-
|
|
182
|
-
st->owned_buf[k_op] = xmalloc(bytes_total);
|
|
183
|
-
st->base[k_op] = st->owned_buf[k_op];
|
|
253
|
+
st->base[k_op] = ca_sweep_scratch_alloc(st, k_op);
|
|
184
254
|
ca_xfer_all(ca, st->base[k_op], CA_XFER_GET);
|
|
185
255
|
}
|
|
186
256
|
}
|
|
@@ -209,7 +279,7 @@ ca_sweep_acquire_body (VALUE arg)
|
|
|
209
279
|
}
|
|
210
280
|
|
|
211
281
|
/* Overwrite each OUTPUT mask with the iter mask (creating the
|
|
212
|
-
OUTPUT mask if it did not exist).
|
|
282
|
+
OUTPUT mask if it did not exist). */
|
|
213
283
|
if (st->m0) {
|
|
214
284
|
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
215
285
|
CArray *ca = st->cx[k_op];
|
|
@@ -228,12 +298,7 @@ ca_sweep_acquire (ca_sweep_state_t *st)
|
|
|
228
298
|
int k_op;
|
|
229
299
|
int tag = 0;
|
|
230
300
|
|
|
231
|
-
|
|
232
|
-
rb_raise(rb_eRuntimeError,
|
|
233
|
-
"[BUG] invalid length of fsync arg in %s (expected %d)",
|
|
234
|
-
st->src_label ? st->src_label : "ca_sweep_acquire",
|
|
235
|
-
st->n_ops);
|
|
236
|
-
}
|
|
301
|
+
ca_sweep_check_fsync(st, "ca_sweep_acquire");
|
|
237
302
|
|
|
238
303
|
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
239
304
|
st->base[k_op] = NULL;
|
|
@@ -343,7 +408,7 @@ ca_sweep_release (ca_sweep_state_t *st)
|
|
|
343
408
|
if (st->attached[k_op]) {
|
|
344
409
|
ca_detach(st->cx[k_op]);
|
|
345
410
|
} else if (st->owned_buf[k_op]) {
|
|
346
|
-
|
|
411
|
+
ca_sweep_scratch_free(st->owned_buf[k_op]);
|
|
347
412
|
st->owned_buf[k_op] = NULL;
|
|
348
413
|
}
|
|
349
414
|
}
|
|
@@ -363,6 +428,8 @@ ca_sweep_acquire_chunked_body (VALUE arg)
|
|
|
363
428
|
ca_sweep_state_t *st = ctx->st;
|
|
364
429
|
int k_op;
|
|
365
430
|
|
|
431
|
+
if (!ctx->any_input_mask) ca_sweep_clear_output_masks(st);
|
|
432
|
+
|
|
366
433
|
/* per-operand acquire:
|
|
367
434
|
* OUTPUT (fsync == '1') : ca_attach + base_orig = ca->ptr (legitimate)
|
|
368
435
|
* INPUT alias : ca_attach + base_orig = ca->ptr (zero-copy)
|
|
@@ -378,9 +445,14 @@ ca_sweep_acquire_chunked_body (VALUE arg)
|
|
|
378
445
|
st->attached[k_op] = 1;
|
|
379
446
|
st->base_orig[k_op] = (char *) ca->ptr;
|
|
380
447
|
} else {
|
|
381
|
-
/* non-alias non-scalar INPUT: arena scratch sized for chunk_n_max
|
|
382
|
-
|
|
383
|
-
|
|
448
|
+
/* non-alias non-scalar INPUT: arena scratch sized for chunk_n_max;
|
|
449
|
+
* the arena marks an object scratch while it is in use */
|
|
450
|
+
if (ca->data_type == CA_OBJECT) {
|
|
451
|
+
st->owned_buf[k_op] = (char *) ca_lazy_arena_acquire_object(st->chunk_n_max);
|
|
452
|
+
} else {
|
|
453
|
+
ca_size_t scratch_bytes = st->chunk_n_max * ca->bytes;
|
|
454
|
+
st->owned_buf[k_op] = (char *) ca_lazy_arena_acquire(scratch_bytes);
|
|
455
|
+
}
|
|
384
456
|
/* base_orig stays NULL -- per-chunk gather lands the data in
|
|
385
457
|
* owned_buf[k_op]; base[k_op] will be set to owned_buf[k_op] at
|
|
386
458
|
* each chunk boundary. */
|
|
@@ -424,12 +496,7 @@ ca_sweep_acquire_chunked (ca_sweep_state_t *st)
|
|
|
424
496
|
int tag = 0;
|
|
425
497
|
CArray *shape_donor = NULL;
|
|
426
498
|
|
|
427
|
-
|
|
428
|
-
rb_raise(rb_eRuntimeError,
|
|
429
|
-
"[BUG] invalid length of fsync arg in %s (expected %d)",
|
|
430
|
-
st->src_label ? st->src_label : "ca_sweep_acquire_chunked",
|
|
431
|
-
st->n_ops);
|
|
432
|
-
}
|
|
499
|
+
ca_sweep_check_fsync(st, "ca_sweep_acquire_chunked");
|
|
433
500
|
|
|
434
501
|
for (k_op = 0; k_op < st->n_ops; k_op++) {
|
|
435
502
|
st->base[k_op] = NULL;
|
data/ext/ca_sweep_engine.h
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
*
|
|
3
3
|
* ca_sweep_engine.h -- sweep (xfer_all) author surface engine, shared helper
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* ext/carray_call_cfunc.c (= one body per arity 1..7) into a single shared
|
|
8
|
-
* helper, also used by the chunked slab family (ca_call_cslab_*).
|
|
5
|
+
* The xfer_all-aware lifecycle shared by ext/carray_call_cfunc.c (one body
|
|
6
|
+
* per arity 1..7) and the chunked slab family (ca_call_cslab_*).
|
|
9
7
|
*
|
|
10
8
|
* Lifecycle template:
|
|
11
9
|
* (1) per-operand acquire
|
|
@@ -14,7 +12,8 @@
|
|
|
14
12
|
* INPUT (fsync=='0') non-alias -> xmalloc + ca_xfer_all(GET)
|
|
15
13
|
* (2) operand pairing (scalar collapse; arrays must agree in shape)
|
|
16
14
|
* (3) mask OR across INPUT operands -> m0 (xmalloc, NULL if none)
|
|
17
|
-
* (4) mask propagate to OUTPUT operands (overwrite output->mask
|
|
15
|
+
* (4) mask propagate to OUTPUT operands (overwrite output->mask; cleared
|
|
16
|
+
* when no INPUT is masked)
|
|
18
17
|
* (5) caller runs the per-cell loop using base[] + stride[]
|
|
19
18
|
* (6) per-operand release (reverse order):
|
|
20
19
|
* sync OUTPUTs, detach attached or xfree owned_buf, xfree m0
|
|
@@ -64,7 +63,7 @@ typedef struct ca_sweep_state {
|
|
|
64
63
|
ca_size_t n_kernel;
|
|
65
64
|
const char *src_label;
|
|
66
65
|
|
|
67
|
-
/* === chunked path fields
|
|
66
|
+
/* === chunked path fields === */
|
|
68
67
|
/* Used by ca_sweep_acquire_chunked / ca_sweep_next_chunk / ca_sweep_release_chunked
|
|
69
68
|
* (= the chunked slab family, ca_call_cslab_*). Unused by the whole-materialise path
|
|
70
69
|
* (ca_sweep_acquire / ca_sweep_release) — cfunc and other whole-buffer callers
|
data/ext/caframe_csv_reader.c
CHANGED
|
@@ -498,7 +498,7 @@ ca_csv_build_const_string_columns (VALUE text, ca_csv_walk_t *w)
|
|
|
498
498
|
CArray *pe;
|
|
499
499
|
int64_t *range;
|
|
500
500
|
boolean8_t *m = NULL;
|
|
501
|
-
VALUE col = rb_carray_new(CA_FIXLEN, 1, dim, 2 * sizeof(int64_t), NULL);
|
|
501
|
+
volatile VALUE col = rb_carray_new(CA_FIXLEN, 1, dim, 2 * sizeof(int64_t), NULL);
|
|
502
502
|
rb_ary_push(cols, col);
|
|
503
503
|
TypedData_Get_Struct(col, CArray, &carray_data_type, pe);
|
|
504
504
|
range = (int64_t *) pe->ptr;
|
data/ext/carray.h
CHANGED
|
@@ -1201,7 +1201,9 @@ double OBJ2DBL (VALUE v);
|
|
|
1201
1201
|
/* Mask-aware object->numeric parsers: return 1 with *out set on success, or
|
|
1202
1202
|
0 (no value; caller masks the cell) on parse failure. Used by the
|
|
1203
1203
|
object->int/float cast loop so an unparseable cell becomes UNDEF instead
|
|
1204
|
-
of a silent 0.0 (float) or a raise (int).
|
|
1204
|
+
of a silent 0.0 (float) or a raise (int). An Integer wider than the C
|
|
1205
|
+
type gives its low bytes (two's complement), as a narrowing C cast does;
|
|
1206
|
+
these parsers do not raise. See ext/carray_cast.c. */
|
|
1205
1207
|
int ca_obj2dbl_ok (VALUE v, double *out);
|
|
1206
1208
|
int ca_obj2cmplx_ok (VALUE v, double complex *out);
|
|
1207
1209
|
int rb_obj2long_ok (VALUE v, long *out);
|
data/ext/carray_access.c
CHANGED
|
@@ -39,15 +39,9 @@ rb_ca_store_index (VALUE self, ca_size_t *idx, VALUE rval)
|
|
|
39
39
|
ca_create_mask(ca);
|
|
40
40
|
ca_store_index(ca->mask, idx, &one);
|
|
41
41
|
}
|
|
42
|
-
else { /*
|
|
42
|
+
else { /* set value of the element at the index 'idx' and unset its mask */
|
|
43
43
|
|
|
44
|
-
/*
|
|
45
|
-
ca_update_mask(ca);
|
|
46
|
-
if ( ca->mask ) {
|
|
47
|
-
ca_store_index(ca->mask, idx, &zero);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/* store value */
|
|
44
|
+
/* A value that can not be stored leaves the cell masked. */
|
|
51
45
|
{
|
|
52
46
|
volatile VALUE holder;
|
|
53
47
|
char *v = ALLOCV_N(char, holder, ca->bytes);
|
|
@@ -55,6 +49,11 @@ rb_ca_store_index (VALUE self, ca_size_t *idx, VALUE rval)
|
|
|
55
49
|
ca_store_index(ca, idx, v);
|
|
56
50
|
ALLOCV_END(holder);
|
|
57
51
|
}
|
|
52
|
+
|
|
53
|
+
ca_update_mask(ca);
|
|
54
|
+
if ( ca->mask ) {
|
|
55
|
+
ca_store_index(ca->mask, idx, &zero);
|
|
56
|
+
}
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
return rval;
|
|
@@ -123,13 +122,9 @@ rb_ca_store_addr (VALUE self, ca_size_t addr, VALUE rval)
|
|
|
123
122
|
ca_create_mask(ca);
|
|
124
123
|
ca_store_addr(ca->mask, addr, &one);
|
|
125
124
|
}
|
|
126
|
-
else { /* set value at the element */
|
|
127
|
-
ca_update_mask(ca);
|
|
128
|
-
if ( ca->mask ) {
|
|
129
|
-
ca_store_addr(ca->mask, addr, &zero); /* unset mask */
|
|
130
|
-
}
|
|
125
|
+
else { /* set value at the element and unset its mask */
|
|
131
126
|
|
|
132
|
-
/*
|
|
127
|
+
/* A value that can not be stored leaves the cell masked. */
|
|
133
128
|
{
|
|
134
129
|
volatile VALUE holder;
|
|
135
130
|
char *v = ALLOCV_N(char, holder, ca->bytes);
|
|
@@ -137,6 +132,11 @@ rb_ca_store_addr (VALUE self, ca_size_t addr, VALUE rval)
|
|
|
137
132
|
ca_store_addr(ca, addr, v);
|
|
138
133
|
ALLOCV_END(holder);
|
|
139
134
|
}
|
|
135
|
+
|
|
136
|
+
ca_update_mask(ca);
|
|
137
|
+
if ( ca->mask ) {
|
|
138
|
+
ca_store_addr(ca->mask, addr, &zero);
|
|
139
|
+
}
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
return rval;
|
|
@@ -426,14 +426,38 @@ rb_ca_ref_address (VALUE self, CAIndexInfo *info)
|
|
|
426
426
|
return rb_ca_fetch_addr(self, addr);
|
|
427
427
|
}
|
|
428
428
|
|
|
429
|
+
/* What a store to one cell takes from an array: its one cell. A cell of an
|
|
430
|
+
object array holds any value, the array itself included, so only a
|
|
431
|
+
CScalar is opened there. */
|
|
432
|
+
static VALUE
|
|
433
|
+
ca_cell_of_store_value (VALUE self, VALUE rval)
|
|
434
|
+
{
|
|
435
|
+
CArray *ca, *cv;
|
|
436
|
+
if ( rb_obj_is_cscalar(rval) ) {
|
|
437
|
+
return rb_ca_fetch_addr(rval, 0);
|
|
438
|
+
}
|
|
439
|
+
if ( ! rb_obj_is_carray(rval) ) {
|
|
440
|
+
return rval;
|
|
441
|
+
}
|
|
442
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
443
|
+
if ( ca->data_type == CA_OBJECT ) {
|
|
444
|
+
return rval;
|
|
445
|
+
}
|
|
446
|
+
TypedData_Get_Struct(rval, CArray, &carray_data_type, cv);
|
|
447
|
+
if ( cv->elements != 1 ) {
|
|
448
|
+
rb_raise(rb_eArgError,
|
|
449
|
+
"%s: shape mismatch writing to one cell (<- %" PRIi64 " cells)",
|
|
450
|
+
ca_calling_method_name(), (int64_t) cv->elements);
|
|
451
|
+
}
|
|
452
|
+
return rb_ca_fetch_addr(rval, 0);
|
|
453
|
+
}
|
|
454
|
+
|
|
429
455
|
static VALUE
|
|
430
456
|
rb_ca_store_address (VALUE self, CAIndexInfo *info, volatile VALUE rval)
|
|
431
457
|
{
|
|
432
458
|
ca_size_t addr;
|
|
433
459
|
addr = info->index[0].scalar;
|
|
434
|
-
|
|
435
|
-
rval = rb_ca_fetch_addr(rval, 0);
|
|
436
|
-
}
|
|
460
|
+
rval = ca_cell_of_store_value(self, rval);
|
|
437
461
|
rb_ca_store_addr(self, addr, rval);
|
|
438
462
|
return rval;
|
|
439
463
|
}
|
|
@@ -461,9 +485,7 @@ rb_ca_store_point (VALUE self, CAIndexInfo *info, volatile VALUE val)
|
|
|
461
485
|
for (i=0; i<ca->ndim; i++) {
|
|
462
486
|
idx[i] = info->index[i].scalar;
|
|
463
487
|
}
|
|
464
|
-
|
|
465
|
-
val = rb_ca_fetch_addr(val, 0);
|
|
466
|
-
}
|
|
488
|
+
val = ca_cell_of_store_value(self, val);
|
|
467
489
|
rb_ca_store_index(self, idx, val);
|
|
468
490
|
return val;
|
|
469
491
|
}
|
|
@@ -522,8 +544,8 @@ ca_store_all_cast_body (VALUE arg)
|
|
|
522
544
|
memset(ca->mask->ptr, 0, ca->elements);
|
|
523
545
|
}
|
|
524
546
|
if ( ca->mask ) {
|
|
525
|
-
|
|
526
|
-
|
|
547
|
+
ca_cast_block_skip_masked(ca->elements, c->cv, c->scratch, ca, ca->ptr,
|
|
548
|
+
(boolean8_t*)ca->mask->ptr);
|
|
527
549
|
}
|
|
528
550
|
else {
|
|
529
551
|
ca_cast_block(ca->elements, c->cv, c->scratch, ca, ca->ptr);
|
|
@@ -567,9 +589,9 @@ ca_store_all_list_body (VALUE arg)
|
|
|
567
589
|
}
|
|
568
590
|
m++;
|
|
569
591
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
592
|
+
ca_cast_block_skip_masked(ca->elements, c->ico, (VALUE *)RARRAY_CONST_PTR(list),
|
|
593
|
+
cast_target, ca->ptr,
|
|
594
|
+
(boolean8_t*)ca->mask->ptr);
|
|
573
595
|
}
|
|
574
596
|
else {
|
|
575
597
|
/* Every cell gets a value, so none stays masked. */
|
|
@@ -617,8 +639,8 @@ ca_face_source_for_store (VALUE self, CArray *ca, VALUE rval)
|
|
|
617
639
|
rb_ca_data_class(rval), rb_ca_data_class(self));
|
|
618
640
|
}
|
|
619
641
|
rb_raise(rb_eTypeError,
|
|
620
|
-
"can not store a %
|
|
621
|
-
|
|
642
|
+
"can not store a %"PRIsVALUE" array into a record array of %"PRIsVALUE,
|
|
643
|
+
rb_obj_class(rval), rb_ca_data_class(self));
|
|
622
644
|
}
|
|
623
645
|
if ( ca_is_face(ca) ) {
|
|
624
646
|
if ( rb_obj_class(self) == rb_obj_class(rval)
|
|
@@ -637,9 +659,9 @@ ca_face_source_for_store (VALUE self, CArray *ca, VALUE rval)
|
|
|
637
659
|
return rval;
|
|
638
660
|
}
|
|
639
661
|
rb_raise(rb_eTypeError,
|
|
640
|
-
"can not store a %
|
|
662
|
+
"can not store a %"PRIsVALUE" array into %s array "
|
|
641
663
|
"(to_type(:object) gives its values)",
|
|
642
|
-
|
|
664
|
+
rb_obj_class(rval), ca_type_name[ca->data_type]);
|
|
643
665
|
}
|
|
644
666
|
return rb_funcall(rval, rb_intern("to_type"), 1, INT2NUM(CA_OBJECT));
|
|
645
667
|
}
|
|
@@ -647,6 +669,20 @@ ca_face_source_for_store (VALUE self, CArray *ca, VALUE rval)
|
|
|
647
669
|
/* A store into no cells writes nothing, but the value is checked as it
|
|
648
670
|
would be for any cells: the same statement does not raise or pass
|
|
649
671
|
depending on how many cells the index picks. */
|
|
672
|
+
/* Writing complex cells into real ones would drop the imaginary parts
|
|
673
|
+
without a word, where a Complex scalar is refused. */
|
|
674
|
+
void
|
|
675
|
+
ca_refuse_complex_into_real (CArray *ca, CArray *cv)
|
|
676
|
+
{
|
|
677
|
+
if ( ca_is_complex_type(cv) && ! ca_is_complex_type(ca)
|
|
678
|
+
&& ca->data_type != CA_OBJECT ) {
|
|
679
|
+
rb_raise(rb_eCADataTypeError,
|
|
680
|
+
"%s: cannot store %s cells in %s (#real and #to_type take the part wanted)",
|
|
681
|
+
ca_calling_method_name(), ca_type_name[cv->data_type],
|
|
682
|
+
ca_type_name[ca->data_type]);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
650
686
|
static void
|
|
651
687
|
ca_store_all_check_empty (VALUE self, VALUE rval)
|
|
652
688
|
{
|
|
@@ -661,7 +697,10 @@ ca_store_all_check_empty (VALUE self, VALUE rval)
|
|
|
661
697
|
rval = rb_funcall(rval, id_to_ca, 0);
|
|
662
698
|
}
|
|
663
699
|
if ( rb_obj_is_carray(rval) ) {
|
|
700
|
+
CArray *cv;
|
|
664
701
|
ca_broadcast_to_destination(self, (volatile VALUE *) &rval);
|
|
702
|
+
TypedData_Get_Struct(rval, CArray, &carray_data_type, cv);
|
|
703
|
+
ca_refuse_complex_into_real(ca, cv);
|
|
665
704
|
}
|
|
666
705
|
else if ( TYPE(rval) == T_ARRAY ) {
|
|
667
706
|
if ( NIL_P(rb_ary_flatten_for_elements(rval, ca->elements, ca)) ) {
|
|
@@ -733,6 +772,7 @@ rb_ca_store_all (VALUE self, VALUE rval)
|
|
|
733
772
|
/* The destination owns the shape; see ca_broadcast_to_destination. */
|
|
734
773
|
ca_broadcast_to_destination(self, &rval);
|
|
735
774
|
TypedData_Get_Struct(rval, CArray, &carray_data_type, cv);
|
|
775
|
+
ca_refuse_complex_into_real(ca, cv);
|
|
736
776
|
|
|
737
777
|
/* Fixlen cells of another width are fitted cell by cell, padded with
|
|
738
778
|
NUL or cut to the destination's width, as a String or an Array of
|
|
@@ -1053,7 +1093,7 @@ extern VALUE rb_ca_remap_new (VALUE cary, VALUE rmapper);
|
|
|
1053
1093
|
reads as masked (a CAGrid hole); the same-shape fast path is left to a
|
|
1054
1094
|
mapper with no masked cell. */
|
|
1055
1095
|
static VALUE
|
|
1056
|
-
rb_ca_fancy_index_chain (VALUE self, VALUE rmapper)
|
|
1096
|
+
rb_ca_fancy_index_chain (VALUE self, volatile VALUE rmapper)
|
|
1057
1097
|
{
|
|
1058
1098
|
CArray *ca, *cm;
|
|
1059
1099
|
volatile VALUE flat_self, flat_mapper, gridded, result;
|
|
@@ -1144,7 +1184,7 @@ ca_argv_is_method_call (int argc, VALUE *argv)
|
|
|
1144
1184
|
{
|
|
1145
1185
|
const char *name;
|
|
1146
1186
|
if ( argc < 1 || ! SYMBOL_P(argv[0]) ) return 0;
|
|
1147
|
-
name = rb_id2name(SYM2ID(argv[0]));
|
|
1187
|
+
name = rb_id2name(SYM2ID(argv[0])); /* name: read at once by strlen */
|
|
1148
1188
|
return ( name != NULL && strlen(name) > 1 );
|
|
1149
1189
|
}
|
|
1150
1190
|
|
|
@@ -1660,14 +1700,14 @@ ca_face_convert_store_rval (VALUE self, CArray *ca, VALUE val)
|
|
|
1660
1700
|
const char *method = ca_face_storage_method(self);
|
|
1661
1701
|
if ( method ) {
|
|
1662
1702
|
rb_raise(rb_eTypeError,
|
|
1663
|
-
"%
|
|
1703
|
+
"%"PRIsVALUE" cannot store a bare %s array as raw storage "
|
|
1664
1704
|
"(write the %s storage, which #%s gives, directly)",
|
|
1665
|
-
|
|
1705
|
+
rb_obj_class(self), ca_type_name[cval->data_type],
|
|
1666
1706
|
ca_type_name[storage->data_type], method);
|
|
1667
1707
|
}
|
|
1668
1708
|
rb_raise(rb_eTypeError,
|
|
1669
|
-
"%
|
|
1670
|
-
|
|
1709
|
+
"%"PRIsVALUE" cannot store a bare %s array as raw storage",
|
|
1710
|
+
rb_obj_class(self), ca_type_name[cval->data_type]);
|
|
1671
1711
|
}
|
|
1672
1712
|
}
|
|
1673
1713
|
return val;
|
|
@@ -1888,7 +1928,7 @@ rb_ca_store2 (VALUE self, int n, VALUE *rindex, VALUE rval)
|
|
|
1888
1928
|
}
|
|
1889
1929
|
|
|
1890
1930
|
static VALUE
|
|
1891
|
-
rb_ca_s_scan_index (VALUE self, VALUE rdim, VALUE ridx)
|
|
1931
|
+
rb_ca_s_scan_index (VALUE self, VALUE rdim, volatile VALUE ridx)
|
|
1892
1932
|
{
|
|
1893
1933
|
volatile VALUE rtype, rindex;
|
|
1894
1934
|
CAIndexInfo info;
|
|
@@ -1899,11 +1939,13 @@ rb_ca_s_scan_index (VALUE self, VALUE rdim, VALUE ridx)
|
|
|
1899
1939
|
|
|
1900
1940
|
Check_Type(rdim, T_ARRAY);
|
|
1901
1941
|
Check_Type(ridx, T_ARRAY);
|
|
1942
|
+
/* Converting an entry can run Ruby that changes the Array: read a copy. */
|
|
1943
|
+
ridx = rb_ary_dup(ridx);
|
|
1902
1944
|
|
|
1903
1945
|
ndim = (int) RARRAY_LEN(rdim);
|
|
1904
1946
|
CA_CHECK_RANK_GIVEN(ndim);
|
|
1905
1947
|
for (i=0; i<ndim; i++) {
|
|
1906
|
-
dim[i] =
|
|
1948
|
+
dim[i] = ca_integer_arg(rb_ary_entry(rdim, i), "a dimension", NULL);
|
|
1907
1949
|
}
|
|
1908
1950
|
CA_CHECK_DIM_GIVEN(ndim, dim);
|
|
1909
1951
|
elements = ca_shape_elements(ndim, dim, 1);
|
|
@@ -1988,7 +2030,7 @@ rb_ca_s_scan_index (VALUE self, VALUE rdim, VALUE ridx)
|
|
|
1988
2030
|
}
|
|
1989
2031
|
|
|
1990
2032
|
static VALUE
|
|
1991
|
-
rb_ca_normalize_index (VALUE self, VALUE ridx)
|
|
2033
|
+
rb_ca_normalize_index (VALUE self, volatile VALUE ridx)
|
|
1992
2034
|
{
|
|
1993
2035
|
volatile VALUE rindex;
|
|
1994
2036
|
CArray *ca;
|
|
@@ -1997,6 +2039,8 @@ rb_ca_normalize_index (VALUE self, VALUE ridx)
|
|
|
1997
2039
|
|
|
1998
2040
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1999
2041
|
Check_Type(ridx, T_ARRAY);
|
|
2042
|
+
/* Converting an entry can run Ruby that changes the Array: read a copy. */
|
|
2043
|
+
ridx = rb_ary_dup(ridx);
|
|
2000
2044
|
|
|
2001
2045
|
info.range_check = 1;
|
|
2002
2046
|
rb_ca_scan_index(ca->ndim, ca->dim, ca->elements,
|
|
@@ -2080,7 +2124,7 @@ parse_shape_kwarg (VALUE rshape, int *out_ndim, ca_size_t *dim,
|
|
|
2080
2124
|
}
|
|
2081
2125
|
ca_check_rank_fits(ndim, NULL);
|
|
2082
2126
|
for (i = 0; i < ndim; i++) {
|
|
2083
|
-
dim[i] =
|
|
2127
|
+
dim[i] = ca_integer_arg(rb_ary_entry(rshape, i), "a dimension", NULL);
|
|
2084
2128
|
if ( dim[i] < 0 ) {
|
|
2085
2129
|
rb_raise(rb_eArgError, "negative dim %" PRId64 " at axis %d",
|
|
2086
2130
|
(ca_size_t) dim[i], i);
|
|
@@ -2091,12 +2135,21 @@ parse_shape_kwarg (VALUE rshape, int *out_ndim, ca_size_t *dim,
|
|
|
2091
2135
|
*out_elements = elements;
|
|
2092
2136
|
}
|
|
2093
2137
|
|
|
2138
|
+
/* A scalar key of index2addr / addr2index, by the rule of `[]`: a Float that
|
|
2139
|
+
is a whole number is that position, any other is no position at all. */
|
|
2140
|
+
static VALUE
|
|
2141
|
+
ca_scalar_position_key (VALUE v)
|
|
2142
|
+
{
|
|
2143
|
+
return RB_FLOAT_TYPE_P(v) ? SIZE2NUM(ca_index_key_value(v)) : v;
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2094
2146
|
static VALUE
|
|
2095
2147
|
addr2index_do (int ndim, ca_size_t *dim, ca_size_t elements, VALUE raddr)
|
|
2096
2148
|
{
|
|
2097
2149
|
volatile VALUE out;
|
|
2098
2150
|
int i;
|
|
2099
2151
|
|
|
2152
|
+
raddr = ca_scalar_position_key(raddr);
|
|
2100
2153
|
/* Scalar path (Integer input): returns Ruby Array of N Integers.
|
|
2101
2154
|
* Preserves legacy shape for callers like `i, j = ca.addr2index(k)`. */
|
|
2102
2155
|
if ( rb_obj_is_kind_of(raddr, rb_cInteger) ) {
|
|
@@ -2253,12 +2306,18 @@ index2addr_do (int ndim, ca_size_t *dim, int argc, VALUE *argv)
|
|
|
2253
2306
|
ca_size_t out_dim[CA_RANK_MAX];
|
|
2254
2307
|
ca_size_t out_elements = 1;
|
|
2255
2308
|
int shape_from = -1;
|
|
2309
|
+
VALUE keys[CA_RANK_MAX];
|
|
2256
2310
|
|
|
2257
2311
|
if ( argc != ndim ) {
|
|
2258
2312
|
rb_raise(rb_eArgError,
|
|
2259
2313
|
"wrong number of indices (%d for %d)", argc, ndim);
|
|
2260
2314
|
}
|
|
2261
2315
|
|
|
2316
|
+
for (i = 0; i < ndim; i++) {
|
|
2317
|
+
keys[i] = ca_scalar_position_key(argv[i]);
|
|
2318
|
+
}
|
|
2319
|
+
argv = keys;
|
|
2320
|
+
|
|
2262
2321
|
for (i = 0; i < ndim; i++) {
|
|
2263
2322
|
if ( ! rb_obj_is_kind_of(argv[i], rb_cInteger) ) {
|
|
2264
2323
|
all_number = 0;
|