carray 3.0.3 → 3.0.4
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 +264 -0
- data/README.md +3 -2
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +1 -6
- data/ext/ca_axis_group.c +27 -27
- data/ext/ca_binop_dispatch.c +1 -29
- data/ext/ca_binop_dispatch.h +0 -1
- data/ext/ca_categorical_iterator.c +205 -134
- data/ext/ca_compare.c +7 -18
- data/ext/ca_group_iter.c +16 -17
- data/ext/ca_kernel_iterator.c +1234 -1994
- data/ext/ca_kernel_iterator.h +391 -437
- data/ext/ca_monop_dispatch.c +82 -59
- data/ext/ca_monop_dispatch.h +1 -0
- data/ext/ca_obj_array.c +96 -39
- data/ext/ca_obj_bincmp.c +24 -21
- data/ext/ca_obj_binop.c +15 -26
- data/ext/ca_obj_bitarray.c +3 -2
- data/ext/ca_obj_bitfield.c +5 -6
- data/ext/ca_obj_block.c +18 -9
- data/ext/ca_obj_byte_swap.c +5 -6
- data/ext/ca_obj_const_string.c +173 -19
- data/ext/ca_obj_face.c +238 -57
- data/ext/ca_obj_face.h +19 -0
- data/ext/ca_obj_fake.c +15 -29
- data/ext/ca_obj_farray.c +6 -3
- data/ext/ca_obj_field.c +17 -5
- data/ext/ca_obj_fixlen_string.c +2 -3
- data/ext/ca_obj_grid.c +406 -132
- data/ext/ca_obj_meld.c +172 -34
- data/ext/ca_obj_moncmp.c +23 -8
- data/ext/ca_obj_monop.c +67 -57
- data/ext/ca_obj_object.c +157 -51
- data/ext/ca_obj_record.c +12 -7
- data/ext/ca_obj_reduce.c +13 -8
- data/ext/ca_obj_refer.c +25 -27
- data/ext/ca_obj_remap.c +30 -9
- data/ext/ca_obj_repeat.c +9 -10
- data/ext/ca_obj_roll.c +6 -5
- data/ext/ca_obj_select.c +14 -9
- data/ext/ca_obj_select_axis.c +15 -47
- data/ext/ca_obj_shift.c +11 -1
- data/ext/ca_obj_stack.c +179 -34
- data/ext/ca_obj_stride.c +162 -115
- data/ext/ca_obj_string.c +71 -4
- data/ext/ca_obj_tile.c +6 -5
- data/ext/ca_obj_time.c +22 -6
- data/ext/ca_obj_timedelta.c +22 -6
- data/ext/ca_obj_transpose.c +5 -3
- data/ext/ca_obj_triop.c +23 -32
- data/ext/ca_obj_window.c +190 -26
- data/ext/ca_sweep_engine.c +2 -2
- data/ext/caframe_csv_reader.c +80 -1
- data/ext/carray.h +181 -75
- data/ext/carray_access.c +184 -96
- data/ext/carray_address_basis.c +343 -87
- data/ext/carray_attribute.c +89 -6
- data/ext/carray_bincount.c +10 -8
- data/ext/carray_broadcast.c +13 -8
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +108 -0
- data/ext/carray_cast.c +142 -24
- data/ext/carray_cast_func.rb +46 -6
- data/ext/carray_class.c +4 -3
- data/ext/carray_config.h +28 -0
- data/ext/carray_conversion.c +16 -7
- data/ext/carray_copy.c +51 -14
- data/ext/carray_core.c +147 -55
- data/ext/carray_count.c +50 -20
- data/ext/carray_element.c +76 -33
- data/ext/carray_factorize.c +118 -64
- data/ext/carray_generate.c +191 -50
- data/ext/carray_histogram.c +62 -17
- data/ext/carray_hold.c +12 -15
- data/ext/carray_index_classifier.c +388 -176
- data/ext/carray_internal.h +336 -29
- data/ext/carray_kernels_bincmp.c +4453 -0
- data/ext/carray_kernels_binop.c +11368 -0
- data/ext/carray_kernels_init.c +1734 -0
- data/ext/carray_kernels_moncmp.c +2104 -0
- data/ext/carray_kernels_monop.c +18369 -0
- data/ext/carray_kernels_reduce_aggregate.c +23818 -0
- data/ext/carray_kernels_reduce_boolean.c +406 -0
- data/ext/carray_kernels_reduce_cumulative.c +10086 -0
- data/ext/carray_kernels_reduce_extreme.c +17634 -0
- data/ext/carray_kernels_reduce_variance.c +3849 -0
- data/ext/carray_kernels_scan.c +4302 -0
- data/ext/carray_kernels_search.c +33829 -0
- data/ext/carray_kernels_sort.c +10906 -0
- data/ext/carray_kernels_triop.c +1864 -0
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +170 -111
- data/ext/carray_mask.c +292 -72
- data/ext/carray_median_percentile.c +82 -28
- data/ext/carray_memory_view.c +669 -561
- data/ext/carray_operator.c +124 -47
- data/ext/carray_order.c +384 -76
- data/ext/carray_partition.c +28 -27
- data/ext/carray_random.c +67 -13
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +63 -38
- data/ext/carray_segment.c +3 -3
- data/ext/carray_slab.c +91 -28
- data/ext/carray_sort.c +35 -35
- data/ext/carray_struct.c +19 -18
- data/ext/carray_test.c +26 -5
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +246 -45
- data/ext/mk_call_cfunc.rb +19 -2
- data/ext/mkkernel.rb +198 -240
- data/ext/ruby_carray.c +10 -4
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +126 -22
- data/lib/carray/autoload_carray.rb +8 -31
- data/lib/carray/autoload_method_extension.rb +14 -5
- data/lib/carray/axis_group.rb +255 -106
- data/lib/carray/basics.rb +78 -10
- data/lib/carray/bincount_nd.rb +12 -2
- data/lib/carray/block_iterator.rb +126 -23
- data/lib/carray/boolean_reduce.rb +17 -17
- data/lib/carray/categorical.rb +165 -43
- data/lib/carray/categorical_iterator.rb +130 -27
- data/lib/carray/complex.rb +5 -5
- data/lib/carray/conditional.rb +67 -18
- data/lib/carray/const_string.rb +14 -5
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +7 -1
- data/lib/carray/frame/column_verbs.rb +70 -0
- data/lib/carray/frame/convert.rb +69 -0
- data/lib/carray/frame/csv_parser.rb +111 -17
- data/lib/carray/frame/describe.rb +3 -2
- data/lib/carray/frame/frame.rb +246 -21
- data/lib/carray/frame/group.rb +510 -95
- data/lib/carray/frame/io.rb +115 -28
- data/lib/carray/frame/join.rb +312 -51
- data/lib/carray/frame/records.rb +83 -7
- data/lib/carray/frame/reshape.rb +42 -35
- data/lib/carray/frame/sort.rb +7 -19
- data/lib/carray/frame/verbs.rb +188 -48
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +11 -4
- data/lib/carray/fusion.rb +40 -16
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +31 -8
- data/lib/carray/iterator.rb +85 -7
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +182 -183
- data/lib/carray/mask_gap_fill.rb +63 -57
- data/lib/carray/meld_reduce.rb +12 -14
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +16 -0
- data/lib/carray/methods/bit_string.rb +1 -1
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +3 -1
- data/lib/carray/methods/gather_nd.rb +14 -5
- data/lib/carray/methods/insert_block.rb +2 -2
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +53 -36
- data/lib/carray/methods/join.rb +1 -6
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +47 -51
- data/lib/carray/methods/mode.rb +1 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/resize.rb +3 -3
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +3 -3
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +53 -8
- data/lib/carray/segment_iterator.rb +313 -82
- data/lib/carray/serialize.rb +24 -10
- data/lib/carray/slab_iterator.rb +50 -0
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +8 -1
- data/lib/carray/struct.rb +9 -21
- data/lib/carray/struct_builder.rb +19 -8
- data/lib/carray/time.rb +726 -104
- data/lib/carray/window_iterator.rb +122 -16
- data/lib/carray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +4 -0
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +2 -1
- data/yard-stubs/ca_obj_roll.rb +2 -2
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +8 -3
- data/yard-stubs/carray_access.rb +6 -1
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_cast.rb +10 -0
- data/yard-stubs/carray_conversion.rb +2 -1
- data/yard-stubs/carray_copy.rb +4 -2
- data/yard-stubs/carray_count.rb +4 -4
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_mask.rb +26 -2
- data/yard-stubs/carray_math.rb +27 -1
- data/yard-stubs/carray_median_percentile.rb +5 -2
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +29 -18
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +14 -9
- data/yard-stubs/carray_slab.rb +9 -2
- data/yard-stubs/carray_sort.rb +6 -5
- data/yard-stubs/carray_test.rb +5 -3
- metadata +25 -3
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_address_basis.c
CHANGED
|
@@ -78,10 +78,16 @@ typedef struct {
|
|
|
78
78
|
ca_size_t *region_start; /* count * CA_RANK_MAX */
|
|
79
79
|
ca_size_t *region_count;
|
|
80
80
|
VALUE bases;
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
int *has_box; /* per slot: 1 when box_start/box_count hold a box */
|
|
82
|
+
ca_size_t *box_start; /* slots * CA_RANK_MAX; the whole array when */
|
|
83
|
+
ca_size_t *box_count; /* has_box is 0 */
|
|
84
|
+
int lent; /* every basis was acquired and the block entered */
|
|
83
85
|
int body_done; /* the block returned without raising */
|
|
84
86
|
volatile VALUE put_error; /* the first write-back that raised, or nil */
|
|
87
|
+
/* ca_with_address_bases: the caller's body and what it is handed */
|
|
88
|
+
VALUE (*c_body)(ca_address_basis_t *bases, VALUE arg);
|
|
89
|
+
VALUE c_arg;
|
|
90
|
+
ca_address_basis_t *c_bases;
|
|
85
91
|
} open_state;
|
|
86
92
|
|
|
87
93
|
/* The view's own row-major byte layout, which is the address space
|
|
@@ -147,28 +153,21 @@ verify_box (VALUE box_starts, VALUE box_counts, int index, CArray *ca)
|
|
|
147
153
|
}
|
|
148
154
|
}
|
|
149
155
|
|
|
150
|
-
/* Reads one array's box
|
|
151
|
-
|
|
152
|
-
|
|
156
|
+
/* Reads one array's box, the whole array when none was given. The box was
|
|
157
|
+
checked when it was given, and is checked again here because this is the
|
|
158
|
+
last thing between a caller's numbers and pointer arithmetic. */
|
|
153
159
|
static void
|
|
154
160
|
read_box (open_state *state, int index, CArray *ca,
|
|
155
161
|
ca_size_t *starts, ca_size_t *counts)
|
|
156
162
|
{
|
|
157
|
-
VALUE per_array_start = Qnil, per_array_count = Qnil;
|
|
158
163
|
int8_t k;
|
|
159
|
-
|
|
160
|
-
if ( ! NIL_P(state->box_starts) ) {
|
|
161
|
-
per_array_start = rb_ary_entry(state->box_starts, index);
|
|
162
|
-
per_array_count = rb_ary_entry(state->box_counts, index);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
164
|
for ( k = 0; k < ca->ndim; k++ ) {
|
|
166
|
-
if (
|
|
165
|
+
if ( state->has_box[index] ) {
|
|
166
|
+
starts[k] = state->box_start[index * CA_RANK_MAX + k];
|
|
167
|
+
counts[k] = state->box_count[index * CA_RANK_MAX + k];
|
|
168
|
+
} else {
|
|
167
169
|
starts[k] = 0;
|
|
168
170
|
counts[k] = ca->dim[k];
|
|
169
|
-
} else {
|
|
170
|
-
starts[k] = NUM2LL(rb_ary_entry(per_array_start, k));
|
|
171
|
-
counts[k] = NUM2LL(rb_ary_entry(per_array_count, k));
|
|
172
171
|
}
|
|
173
172
|
if ( outside_axis(starts[k], counts[k], ca->dim[k]) ) {
|
|
174
173
|
rb_raise(rb_eArgError,
|
|
@@ -202,14 +201,14 @@ size_array (ca_size_t *values, int8_t count)
|
|
|
202
201
|
/* Refuses what a generated kernel cannot express, rather than letting it
|
|
203
202
|
produce quietly wrong numbers. */
|
|
204
203
|
static void
|
|
205
|
-
verify_usable (VALUE
|
|
204
|
+
verify_usable (VALUE klass, CArray *ca, int writable)
|
|
206
205
|
{
|
|
207
206
|
if ( ca->data_type == CA_OBJECT ) {
|
|
208
207
|
rb_raise(rb_eArgError, "object arrays hold Ruby values, not numbers");
|
|
209
208
|
}
|
|
210
209
|
if ( writable && ca_is_readonly(ca) ) {
|
|
211
|
-
|
|
212
|
-
|
|
210
|
+
/* read-only-check: names which array a basis was asked to write through */
|
|
211
|
+
rb_raise(rb_eRuntimeError, "%"PRIsVALUE" is read-only", klass);
|
|
213
212
|
}
|
|
214
213
|
}
|
|
215
214
|
|
|
@@ -237,19 +236,87 @@ folds_to_an_entity (CArray *ca)
|
|
|
237
236
|
its neighbour. A per-cell kernel writes cells independently and cannot
|
|
238
237
|
express that. Checked for every tier: a box transfer moves the same
|
|
239
238
|
mask, and the neighbour is marked when it is written back. */
|
|
240
|
-
static
|
|
241
|
-
|
|
239
|
+
static int
|
|
240
|
+
mask_cells_split (CArray *ca)
|
|
242
241
|
{
|
|
243
242
|
CArray *root;
|
|
244
243
|
ca_size_t strides[CA_RANK_MAX];
|
|
245
244
|
ca_size_t base = 0;
|
|
246
|
-
if ( ! ca->mask || ! ca_is_stride_family(ca) ) return;
|
|
245
|
+
if ( ! ca->mask || ! ca_is_stride_family(ca) ) return 0;
|
|
247
246
|
ca_stride_compose_to_root((CAStride *) ca, &root, strides, &base);
|
|
248
|
-
|
|
247
|
+
return ca->bytes != root->bytes;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
static void
|
|
251
|
+
verify_mask_cells (VALUE klass, CArray *ca)
|
|
252
|
+
{
|
|
253
|
+
if ( mask_cells_split(ca) ) {
|
|
249
254
|
rb_raise(rb_eArgError,
|
|
250
255
|
"%"PRIsVALUE" reinterprets the element size and carries a mask; "
|
|
251
256
|
"its mask cells do not map one to one onto the parent's",
|
|
252
|
-
|
|
257
|
+
klass);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* Why an array would be refused for reading, or NULL. */
|
|
262
|
+
static const char *
|
|
263
|
+
read_refusal (CArray *ca)
|
|
264
|
+
{
|
|
265
|
+
if ( ca->data_type == CA_OBJECT ) {
|
|
266
|
+
return "object arrays hold Ruby values, not numbers";
|
|
267
|
+
}
|
|
268
|
+
if ( mask_cells_split(ca) ) {
|
|
269
|
+
return "it reinterprets the element size and carries a mask";
|
|
270
|
+
}
|
|
271
|
+
return NULL;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* CArray::AddressBasis::Failure. An exception raised while the arrays are
|
|
275
|
+
checked, lent or taken back is extended with it; one raised by the block
|
|
276
|
+
they are lent to is not. Something that hands the arrays to code of its
|
|
277
|
+
own can then tell a refusal or a failing array (a CAObject whose backing
|
|
278
|
+
cannot be read) from a fault of that code. */
|
|
279
|
+
static VALUE mFailure;
|
|
280
|
+
|
|
281
|
+
static void
|
|
282
|
+
mark_failure (VALUE error)
|
|
283
|
+
{
|
|
284
|
+
if ( RTEST(rb_obj_is_kind_of(error, rb_eException)) && ! OBJ_FROZEN(error) ) {
|
|
285
|
+
rb_extend_object(error, mFailure);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
typedef struct {
|
|
290
|
+
VALUE klass;
|
|
291
|
+
CArray *ca;
|
|
292
|
+
int writable;
|
|
293
|
+
} verify_args;
|
|
294
|
+
|
|
295
|
+
static VALUE
|
|
296
|
+
verify_array_body (VALUE argument)
|
|
297
|
+
{
|
|
298
|
+
verify_args *a = (verify_args *) argument;
|
|
299
|
+
/* A view takes its mask from its parent when first asked for it; one
|
|
300
|
+
added to the parent after the view was made is not on ca->mask yet. */
|
|
301
|
+
ca_update_mask(a->ca);
|
|
302
|
+
verify_usable(a->klass, a->ca, a->writable);
|
|
303
|
+
verify_mask_cells(a->klass, a->ca);
|
|
304
|
+
return Qnil;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
static void
|
|
308
|
+
verify_array (VALUE klass, CArray *ca, int writable)
|
|
309
|
+
{
|
|
310
|
+
verify_args a;
|
|
311
|
+
int tag = 0;
|
|
312
|
+
a.klass = klass;
|
|
313
|
+
a.ca = ca;
|
|
314
|
+
a.writable = writable;
|
|
315
|
+
/* protect: marks the exception as a Failure and raises it again; nothing is held */
|
|
316
|
+
rb_protect(verify_array_body, (VALUE) &a, &tag);
|
|
317
|
+
if ( tag ) {
|
|
318
|
+
mark_failure(rb_errinfo());
|
|
319
|
+
rb_jump_tag(tag);
|
|
253
320
|
}
|
|
254
321
|
}
|
|
255
322
|
|
|
@@ -390,7 +457,9 @@ open_body (VALUE argument)
|
|
|
390
457
|
rb_ary_push(state->bases, basis);
|
|
391
458
|
}
|
|
392
459
|
{
|
|
393
|
-
VALUE result
|
|
460
|
+
VALUE result;
|
|
461
|
+
state->lent = 1;
|
|
462
|
+
result = rb_yield(state->bases);
|
|
394
463
|
state->body_done = 1;
|
|
395
464
|
return result;
|
|
396
465
|
}
|
|
@@ -456,16 +525,27 @@ write_back (VALUE argument)
|
|
|
456
525
|
write-back that raises -- the array's own transfer slot failing -- is
|
|
457
526
|
set aside so that every other region is still written and freed and
|
|
458
527
|
every root detached; the block's own exception, if it raised, wins. */
|
|
528
|
+
static VALUE
|
|
529
|
+
sync_root (VALUE root)
|
|
530
|
+
{
|
|
531
|
+
ca_sync((CArray *) root);
|
|
532
|
+
return Qnil;
|
|
533
|
+
}
|
|
534
|
+
|
|
459
535
|
static VALUE
|
|
460
536
|
open_ensure (VALUE argument)
|
|
461
537
|
{
|
|
462
538
|
open_state *state = (open_state *) argument;
|
|
463
539
|
int i;
|
|
540
|
+
/* Raised before the block was entered: by lending an array */
|
|
541
|
+
if ( ! state->lent ) mark_failure(rb_errinfo());
|
|
464
542
|
for ( i = state->slots - 1; i >= 0; i-- ) {
|
|
465
543
|
CArray *ca = state->carrays[i];
|
|
466
544
|
if ( ca == NULL ) continue;
|
|
467
|
-
/* A tier-1 or tier-2 basis addresses the root's own memory
|
|
468
|
-
|
|
545
|
+
/* A tier-1 or tier-2 basis addresses the root's own memory; the root is
|
|
546
|
+
synced before it is detached, for the entity that keeps its cells
|
|
547
|
+
elsewhere while attached (the mask of a CAObject that has mask
|
|
548
|
+
hooks). A region buffer is sent back cell by cell. */
|
|
469
549
|
if ( state->region[i] ) {
|
|
470
550
|
ca_size_t elements = 1;
|
|
471
551
|
int8_t k;
|
|
@@ -483,6 +563,7 @@ open_ensure (VALUE argument)
|
|
|
483
563
|
w.steps = steps;
|
|
484
564
|
w.data = state->region[i];
|
|
485
565
|
w.read = state->region[i] + elements * ca->bytes;
|
|
566
|
+
/* protect: keeps the error so that every region is written back first */
|
|
486
567
|
rb_protect(write_back, (VALUE) &w, &tag);
|
|
487
568
|
if ( tag ) {
|
|
488
569
|
if ( NIL_P(state->put_error) ) {
|
|
@@ -494,12 +575,24 @@ open_ensure (VALUE argument)
|
|
|
494
575
|
xfree(state->region[i]);
|
|
495
576
|
}
|
|
496
577
|
if ( state->attached_root[i] ) {
|
|
578
|
+
if ( ! ca_is_readonly(state->roots[i]) ) {
|
|
579
|
+
int tag = 0;
|
|
580
|
+
/* protect: keeps the error so that every root is detached first */
|
|
581
|
+
rb_protect(sync_root, (VALUE) state->roots[i], &tag);
|
|
582
|
+
if ( tag ) {
|
|
583
|
+
if ( NIL_P(state->put_error) ) {
|
|
584
|
+
state->put_error = rb_errinfo();
|
|
585
|
+
}
|
|
586
|
+
rb_set_errinfo(Qnil);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
497
589
|
ca_detach(state->roots[i]);
|
|
498
590
|
}
|
|
499
591
|
}
|
|
500
592
|
xfree(state->block);
|
|
501
593
|
if ( state->body_done && RTEST(rb_obj_is_kind_of(state->put_error,
|
|
502
594
|
rb_eException)) ) {
|
|
595
|
+
mark_failure(state->put_error);
|
|
503
596
|
rb_exc_raise(state->put_error);
|
|
504
597
|
}
|
|
505
598
|
return Qnil;
|
|
@@ -568,15 +661,100 @@ packed_body (VALUE argument)
|
|
|
568
661
|
for ( k = 0; k < ca->ndim; k++ ) *mask_stride_slot++ = 0;
|
|
569
662
|
}
|
|
570
663
|
}
|
|
664
|
+
/* The slots point into the four Strings, and acquire_basis allocates:
|
|
665
|
+
a String the stack holds is pinned, so compaction leaves it be. */
|
|
666
|
+
RB_GC_GUARD(pointers);
|
|
667
|
+
RB_GC_GUARD(strides);
|
|
668
|
+
RB_GC_GUARD(mask_pointers);
|
|
669
|
+
RB_GC_GUARD(mask_strides);
|
|
571
670
|
|
|
572
671
|
{
|
|
573
|
-
VALUE result
|
|
574
|
-
|
|
672
|
+
VALUE result;
|
|
673
|
+
state->lent = 1;
|
|
674
|
+
result = rb_yield_values(4, pointers, strides, mask_pointers, mask_strides);
|
|
575
675
|
state->body_done = 1;
|
|
576
676
|
return result;
|
|
577
677
|
}
|
|
578
678
|
}
|
|
579
679
|
|
|
680
|
+
/* Allocates the state for n arrays and fills it: the arrays and their masks,
|
|
681
|
+
their tiers, which ones are written, and the boxes. The caller has
|
|
682
|
+
checked every argument already: nothing here raises, so a refusal never
|
|
683
|
+
finds a block to free. `box_start` / `box_count` may be NULL (every
|
|
684
|
+
array whole), and an entry of them may be NULL (that array whole). */
|
|
685
|
+
static void
|
|
686
|
+
ab_prepare (open_state *state, int n, CArray **arrays, const int *writable,
|
|
687
|
+
const ca_size_t *const *box_start, const ca_size_t *const *box_count)
|
|
688
|
+
{
|
|
689
|
+
int i;
|
|
690
|
+
|
|
691
|
+
state->count = n;
|
|
692
|
+
state->slots = n * 2;
|
|
693
|
+
/* One allocation, carved up. Every array here is the same length in
|
|
694
|
+
slots and lives exactly as long as the open, so there is nothing for
|
|
695
|
+
separate lifetimes to buy -- and this is a per-call cost on a path
|
|
696
|
+
whose whole point is to be cheap enough to cross often. Zeroed once
|
|
697
|
+
as a block, which is also what the slots want to start as: a NULL
|
|
698
|
+
array, a NULL root, not writable, not attached, no region, no box. */
|
|
699
|
+
{
|
|
700
|
+
size_t m = (size_t) state->slots + 1;
|
|
701
|
+
size_t pointers = ROUND_UP_8(m * sizeof(CArray *));
|
|
702
|
+
size_t chars = ROUND_UP_8(m * sizeof(char *));
|
|
703
|
+
size_t sizes = ROUND_UP_8(m * CA_RANK_MAX * sizeof(ca_size_t));
|
|
704
|
+
size_t ints = ROUND_UP_8(m * sizeof(int));
|
|
705
|
+
size_t bases = ROUND_UP_8((size_t) (n + 1) * sizeof(ca_address_basis_t));
|
|
706
|
+
size_t total = 2 * pointers + chars + 4 * sizes + 4 * ints + bases;
|
|
707
|
+
char *p;
|
|
708
|
+
state->block = ALLOC_N(char, total);
|
|
709
|
+
MEMZERO(state->block, char, total);
|
|
710
|
+
p = state->block;
|
|
711
|
+
state->carrays = (CArray **) p; p += pointers;
|
|
712
|
+
state->roots = (CArray **) p; p += pointers;
|
|
713
|
+
state->region = (char **) p; p += chars;
|
|
714
|
+
state->region_start = (ca_size_t *) p; p += sizes;
|
|
715
|
+
state->region_count = (ca_size_t *) p; p += sizes;
|
|
716
|
+
state->box_start = (ca_size_t *) p; p += sizes;
|
|
717
|
+
state->box_count = (ca_size_t *) p; p += sizes;
|
|
718
|
+
state->tier = (int *) p; p += ints;
|
|
719
|
+
state->writable = (int *) p; p += ints;
|
|
720
|
+
state->attached_root = (int *) p; p += ints;
|
|
721
|
+
state->has_box = (int *) p; p += ints;
|
|
722
|
+
state->c_bases = (ca_address_basis_t *) p;
|
|
723
|
+
}
|
|
724
|
+
state->lent = 0;
|
|
725
|
+
state->body_done = 0;
|
|
726
|
+
state->put_error = Qnil;
|
|
727
|
+
|
|
728
|
+
for ( i = 0; i < n; i++ ) {
|
|
729
|
+
CArray *ca = arrays[i];
|
|
730
|
+
state->carrays[i] = ca;
|
|
731
|
+
state->writable[i] = writable ? writable[i] : 0;
|
|
732
|
+
state->tier[i] = tier_for(ca);
|
|
733
|
+
if ( box_start && box_start[i] ) {
|
|
734
|
+
state->has_box[i] = 1;
|
|
735
|
+
memcpy(&state->box_start[i * CA_RANK_MAX], box_start[i],
|
|
736
|
+
ca->ndim * sizeof(ca_size_t));
|
|
737
|
+
memcpy(&state->box_count[i * CA_RANK_MAX], box_count[i],
|
|
738
|
+
ca->ndim * sizeof(ca_size_t));
|
|
739
|
+
}
|
|
740
|
+
if ( ca->mask ) {
|
|
741
|
+
CArray *mask = ca->mask;
|
|
742
|
+
state->carrays[n + i] = mask;
|
|
743
|
+
state->writable[n + i] = state->writable[i];
|
|
744
|
+
state->tier[n + i] = tier_for(mask);
|
|
745
|
+
/* The mask is the array's shape, so the array's box is its box: a
|
|
746
|
+
tier-3 mask moves the cells the kernel asked for, not all of them. */
|
|
747
|
+
if ( state->has_box[i] ) {
|
|
748
|
+
state->has_box[n + i] = 1;
|
|
749
|
+
memcpy(&state->box_start[(n + i) * CA_RANK_MAX], box_start[i],
|
|
750
|
+
ca->ndim * sizeof(ca_size_t));
|
|
751
|
+
memcpy(&state->box_count[(n + i) * CA_RANK_MAX], box_count[i],
|
|
752
|
+
ca->ndim * sizeof(ca_size_t));
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
580
758
|
/*
|
|
581
759
|
* Opens every array, yields what it opened, and closes them all on the way
|
|
582
760
|
* out -- including when the block raises.
|
|
@@ -591,7 +769,7 @@ address_basis_open (int argc, VALUE *argv, VALUE module)
|
|
|
591
769
|
{
|
|
592
770
|
VALUE arrays, writable_flags, box_start, box_count, packed;
|
|
593
771
|
open_state state;
|
|
594
|
-
int i;
|
|
772
|
+
int i, n;
|
|
595
773
|
|
|
596
774
|
rb_scan_args(argc, argv, "23", &arrays, &writable_flags, &box_start,
|
|
597
775
|
&box_count, &packed);
|
|
@@ -611,73 +789,57 @@ address_basis_open (int argc, VALUE *argv, VALUE module)
|
|
|
611
789
|
if ( RARRAY_LEN(arrays) != RARRAY_LEN(writable_flags) ) {
|
|
612
790
|
rb_raise(rb_eArgError, "one writable flag per array is required");
|
|
613
791
|
}
|
|
792
|
+
n = (int) RARRAY_LEN(arrays);
|
|
614
793
|
|
|
615
|
-
/* Every argument is checked before the
|
|
616
|
-
|
|
617
|
-
for ( i = 0; i <
|
|
794
|
+
/* Every argument is checked before the state is allocated: a refusal
|
|
795
|
+
raises, and it must find nothing to free. */
|
|
796
|
+
for ( i = 0; i < n; i++ ) {
|
|
618
797
|
VALUE object = rb_ary_entry(arrays, i);
|
|
619
798
|
CArray *ca;
|
|
620
799
|
GetCArray(object, ca);
|
|
621
|
-
|
|
622
|
-
added to the parent after the view was made is not on ca->mask yet. */
|
|
623
|
-
ca_update_mask(ca);
|
|
624
|
-
verify_usable(object, ca, RTEST(rb_ary_entry(writable_flags, i)));
|
|
625
|
-
verify_mask_cells(object, ca);
|
|
800
|
+
verify_array(rb_obj_class(object), ca, RTEST(rb_ary_entry(writable_flags, i)));
|
|
626
801
|
verify_box(box_start, box_count, i, ca);
|
|
627
802
|
}
|
|
628
803
|
|
|
629
|
-
state.count = (int) RARRAY_LEN(arrays);
|
|
630
|
-
state.slots = state.count * 2;
|
|
631
|
-
/* Our own copy: the caller's Array can be emptied inside the block, and
|
|
632
|
-
the arrays it held are attached until open_ensure has run. */
|
|
633
|
-
state.arrays = rb_ary_dup(arrays);
|
|
634
|
-
state.bases = rb_ary_new_capa(state.count);
|
|
635
|
-
/* One allocation, carved up, rather than eight. Every array here is the
|
|
636
|
-
same length in slots and lives exactly as long as the open, so there is
|
|
637
|
-
nothing for eight separate lifetimes to buy -- and this is a per-call
|
|
638
|
-
cost on a path whose whole point is to be cheap enough to cross often.
|
|
639
|
-
Zeroed once as a block, which is also what the slots want to start as:
|
|
640
|
-
a NULL array, a NULL root, not writable, not attached, no region. */
|
|
641
804
|
{
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
state.tier[i] = tier_for(ca);
|
|
673
|
-
|
|
674
|
-
if ( ca->mask ) {
|
|
675
|
-
CArray *mask = ca->mask;
|
|
676
|
-
state.carrays[state.count + i] = mask;
|
|
677
|
-
state.writable[state.count + i] = state.writable[i];
|
|
678
|
-
state.tier[state.count + i] = tier_for(mask);
|
|
805
|
+
/* The boxes and flags in C form, on the stack: they are copied into
|
|
806
|
+
the state, and nothing below raises before that. */
|
|
807
|
+
/* Laid out widest first, so every part is aligned. */
|
|
808
|
+
VALUE vholder = 0;
|
|
809
|
+
CArray **carrays = (CArray **) ALLOCV(vholder, (size_t) n * (sizeof(CArray *)
|
|
810
|
+
+ 2 * sizeof(ca_size_t *)
|
|
811
|
+
+ 2 * CA_RANK_MAX * sizeof(ca_size_t)
|
|
812
|
+
+ sizeof(int)) + 1);
|
|
813
|
+
const ca_size_t **bs = (const ca_size_t **) (carrays + n);
|
|
814
|
+
const ca_size_t **bc = bs + n;
|
|
815
|
+
ca_size_t *cells = (ca_size_t *) (bc + n);
|
|
816
|
+
int *flags = (int *) (cells + (size_t) n * 2 * CA_RANK_MAX);
|
|
817
|
+
for ( i = 0; i < n; i++ ) {
|
|
818
|
+
VALUE object = rb_ary_entry(arrays, i);
|
|
819
|
+
VALUE starts = NIL_P(box_start) ? Qnil : rb_ary_entry(box_start, i);
|
|
820
|
+
VALUE counts = NIL_P(box_count) ? Qnil : rb_ary_entry(box_count, i);
|
|
821
|
+
int8_t k;
|
|
822
|
+
GetCArray(object, carrays[i]);
|
|
823
|
+
flags[i] = RTEST(rb_ary_entry(writable_flags, i));
|
|
824
|
+
bs[i] = bc[i] = NULL;
|
|
825
|
+
if ( ! NIL_P(starts) ) {
|
|
826
|
+
ca_size_t *s0 = cells + (size_t) i * 2 * CA_RANK_MAX;
|
|
827
|
+
ca_size_t *c0 = s0 + CA_RANK_MAX;
|
|
828
|
+
for ( k = 0; k < carrays[i]->ndim; k++ ) {
|
|
829
|
+
s0[k] = NUM2LL(rb_ary_entry(starts, k));
|
|
830
|
+
c0[k] = NUM2LL(rb_ary_entry(counts, k));
|
|
831
|
+
}
|
|
832
|
+
bs[i] = s0;
|
|
833
|
+
bc[i] = c0;
|
|
834
|
+
}
|
|
679
835
|
}
|
|
836
|
+
ab_prepare(&state, n, carrays, flags, bs, bc);
|
|
837
|
+
ALLOCV_END(vholder);
|
|
680
838
|
}
|
|
839
|
+
/* Our own copy: the caller's Array can be emptied inside the block, and
|
|
840
|
+
the arrays it held are attached until open_ensure has run. */
|
|
841
|
+
state.arrays = rb_ary_dup(arrays);
|
|
842
|
+
state.bases = rb_ary_new_capa(n);
|
|
681
843
|
|
|
682
844
|
{
|
|
683
845
|
VALUE result = RTEST(packed)
|
|
@@ -688,6 +850,81 @@ address_basis_open (int argc, VALUE *argv, VALUE module)
|
|
|
688
850
|
}
|
|
689
851
|
}
|
|
690
852
|
|
|
853
|
+
/* The body of ca_with_address_bases: lends each array's basis, then runs
|
|
854
|
+
the caller's body on them. */
|
|
855
|
+
static VALUE
|
|
856
|
+
c_body (VALUE argument)
|
|
857
|
+
{
|
|
858
|
+
open_state *state = (open_state *) argument;
|
|
859
|
+
int i;
|
|
860
|
+
for ( i = 0; i < state->count; i++ ) {
|
|
861
|
+
ca_address_basis_t *b = &state->c_bases[i];
|
|
862
|
+
b->ptr = acquire_basis(state, i, b->strides);
|
|
863
|
+
b->writable = state->writable[i];
|
|
864
|
+
if ( state->carrays[state->count + i] ) {
|
|
865
|
+
b->mask = (boolean8_t *) acquire_basis(state, state->count + i,
|
|
866
|
+
b->mask_strides);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
{
|
|
870
|
+
VALUE result;
|
|
871
|
+
state->lent = 1;
|
|
872
|
+
result = state->c_body(state->c_bases, state->c_arg);
|
|
873
|
+
state->body_done = 1;
|
|
874
|
+
return result;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
VALUE
|
|
879
|
+
ca_with_address_bases (int32_t n, CArray **arrays, const int *writable,
|
|
880
|
+
const ca_size_t *const *box_start,
|
|
881
|
+
const ca_size_t *const *box_count,
|
|
882
|
+
VALUE (*body)(ca_address_basis_t *bases, VALUE arg),
|
|
883
|
+
VALUE arg)
|
|
884
|
+
{
|
|
885
|
+
open_state state;
|
|
886
|
+
int32_t i;
|
|
887
|
+
int8_t k;
|
|
888
|
+
|
|
889
|
+
if ( n < 0 || (n > 0 && arrays == NULL) || body == NULL ) {
|
|
890
|
+
rb_raise(rb_eArgError, "ca_with_address_bases: no arrays or no body");
|
|
891
|
+
}
|
|
892
|
+
if ( (box_start == NULL) != (box_count == NULL) ) {
|
|
893
|
+
rb_raise(rb_eArgError, "a region needs both starts and counts");
|
|
894
|
+
}
|
|
895
|
+
/* Every argument is checked before the state is allocated. */
|
|
896
|
+
for ( i = 0; i < n; i++ ) {
|
|
897
|
+
CArray *ca = arrays[i];
|
|
898
|
+
VALUE klass;
|
|
899
|
+
if ( ca == NULL ) {
|
|
900
|
+
rb_raise(rb_eArgError, "ca_with_address_bases: array %d is NULL", (int) i);
|
|
901
|
+
}
|
|
902
|
+
/* a CAObject (a Face among them) is named by its own class */
|
|
903
|
+
klass = ca_is_caobject(ca) ? rb_obj_class(((CAObject *) ca)->self)
|
|
904
|
+
: ca_class[ca->obj_type];
|
|
905
|
+
verify_array(klass, ca, writable ? writable[i] : 0);
|
|
906
|
+
if ( box_start && ((box_start[i] == NULL) != (box_count[i] == NULL)) ) {
|
|
907
|
+
rb_raise(rb_eArgError, "a region needs both starts and counts");
|
|
908
|
+
}
|
|
909
|
+
if ( box_start && box_start[i] ) {
|
|
910
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
911
|
+
if ( outside_axis(box_start[i][k], box_count[i][k], ca->dim[k]) ) {
|
|
912
|
+
rb_raise(rb_eArgError,
|
|
913
|
+
"the requested region falls outside the array on axis %d",
|
|
914
|
+
(int) k);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
ab_prepare(&state, (int) n, arrays, writable, box_start, box_count);
|
|
921
|
+
state.arrays = Qnil;
|
|
922
|
+
state.bases = Qnil;
|
|
923
|
+
state.c_body = body;
|
|
924
|
+
state.c_arg = arg;
|
|
925
|
+
return rb_ensure(c_body, (VALUE) &state, open_ensure, (VALUE) &state);
|
|
926
|
+
}
|
|
927
|
+
|
|
691
928
|
/* Reports how an array would be opened, without opening it. */
|
|
692
929
|
static VALUE
|
|
693
930
|
address_basis_classify (VALUE module, VALUE object)
|
|
@@ -697,6 +934,7 @@ address_basis_classify (VALUE module, VALUE object)
|
|
|
697
934
|
int tier;
|
|
698
935
|
|
|
699
936
|
GetCArray(object, ca);
|
|
937
|
+
ca_update_mask(ca);
|
|
700
938
|
tier = tier_for(ca);
|
|
701
939
|
|
|
702
940
|
result = rb_hash_new();
|
|
@@ -709,9 +947,24 @@ address_basis_classify (VALUE module, VALUE object)
|
|
|
709
947
|
rb_hash_aset(result, ID2SYM(rb_intern("dim")), size_array(ca->dim, ca->ndim));
|
|
710
948
|
rb_hash_aset(result, ID2SYM(rb_intern("bytes")), LL2NUM((long long) ca->bytes));
|
|
711
949
|
rb_hash_aset(result, ID2SYM(rb_intern("data_type")), INT2NUM(ca->data_type));
|
|
950
|
+
{
|
|
951
|
+
const char *refusal = read_refusal(ca);
|
|
952
|
+
rb_hash_aset(result, ID2SYM(rb_intern("refusal")),
|
|
953
|
+
refusal ? rb_str_new_cstr(refusal) : Qnil);
|
|
954
|
+
}
|
|
712
955
|
return result;
|
|
713
956
|
}
|
|
714
957
|
|
|
958
|
+
/* The tier alone, for a caller that only wants to know which of the three
|
|
959
|
+
an array would be opened at: classify builds a Hash to say it. */
|
|
960
|
+
static VALUE
|
|
961
|
+
address_basis_tier (VALUE module, VALUE object)
|
|
962
|
+
{
|
|
963
|
+
CArray *ca;
|
|
964
|
+
GetCArray(object, ca);
|
|
965
|
+
return INT2NUM(tier_for(ca));
|
|
966
|
+
}
|
|
967
|
+
|
|
715
968
|
/* ------------------------------------------------------------------- */
|
|
716
969
|
/* Init_carray_address_basis */
|
|
717
970
|
/* ------------------------------------------------------------------- */
|
|
@@ -724,8 +977,11 @@ Init_carray_address_basis (void)
|
|
|
724
977
|
rb_define_singleton_method(mAddressBasis, "open", address_basis_open, -1);
|
|
725
978
|
rb_define_singleton_method(mAddressBasis, "classify",
|
|
726
979
|
address_basis_classify, 1);
|
|
980
|
+
rb_define_singleton_method(mAddressBasis, "tier", address_basis_tier, 1);
|
|
727
981
|
|
|
728
982
|
rb_define_const(mAddressBasis, "TIER_ENTITY", INT2NUM(TIER_ENTITY));
|
|
729
983
|
rb_define_const(mAddressBasis, "TIER_STRIDE", INT2NUM(TIER_STRIDE));
|
|
730
984
|
rb_define_const(mAddressBasis, "TIER_XFER", INT2NUM(TIER_XFER));
|
|
985
|
+
|
|
986
|
+
mFailure = rb_define_module_under(mAddressBasis, "Failure");
|
|
731
987
|
}
|