carray 3.0.2 → 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 +568 -0
- data/README.md +6 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +220 -0
- data/ext/ca_axis_group.c +201 -123
- data/ext/ca_binop_dispatch.c +46 -52
- data/ext/ca_binop_dispatch.h +1 -1
- data/ext/ca_categorical_iterator.c +249 -183
- data/ext/ca_compare.c +7 -12
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +38 -23
- data/ext/ca_kernel_iterator.c +1765 -2076
- data/ext/ca_kernel_iterator.h +584 -566
- data/ext/ca_monop_dispatch.c +86 -63
- data/ext/ca_monop_dispatch.h +5 -0
- data/ext/ca_obj_array.c +223 -56
- data/ext/ca_obj_bincmp.c +172 -138
- data/ext/ca_obj_binop.c +116 -230
- data/ext/ca_obj_bitarray.c +40 -26
- data/ext/ca_obj_bitfield.c +100 -68
- data/ext/ca_obj_block.c +19 -9
- data/ext/ca_obj_byte_swap.c +45 -46
- data/ext/ca_obj_const_string.c +269 -44
- data/ext/ca_obj_face.c +612 -89
- data/ext/ca_obj_face.h +111 -47
- data/ext/ca_obj_fake.c +36 -79
- data/ext/ca_obj_farray.c +7 -3
- data/ext/ca_obj_field.c +33 -8
- data/ext/ca_obj_fixlen_string.c +23 -24
- data/ext/ca_obj_grid.c +541 -210
- data/ext/ca_obj_meld.c +331 -111
- data/ext/ca_obj_moncmp.c +80 -65
- data/ext/ca_obj_monop.c +177 -149
- data/ext/ca_obj_object.c +664 -248
- data/ext/ca_obj_record.c +63 -23
- data/ext/ca_obj_reduce.c +18 -16
- data/ext/ca_obj_refer.c +140 -58
- data/ext/ca_obj_remap.c +85 -24
- data/ext/ca_obj_repeat.c +24 -9
- data/ext/ca_obj_roll.c +121 -16
- data/ext/ca_obj_select.c +61 -58
- data/ext/ca_obj_select_axis.c +73 -107
- data/ext/ca_obj_shift.c +32 -102
- data/ext/ca_obj_stack.c +372 -122
- data/ext/ca_obj_stride.c +348 -140
- data/ext/ca_obj_string.c +88 -22
- data/ext/ca_obj_tile.c +38 -21
- data/ext/ca_obj_time.c +45 -31
- data/ext/ca_obj_timedelta.c +43 -29
- data/ext/ca_obj_transpose.c +17 -6
- data/ext/ca_obj_triop.c +125 -141
- data/ext/ca_obj_window.c +330 -44
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +104 -81
- data/ext/ca_sweep_engine.h +7 -20
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +542 -0
- data/ext/carray.h +241 -92
- data/ext/carray_access.c +608 -276
- data/ext/carray_address_basis.c +494 -97
- data/ext/carray_attribute.c +129 -4
- data/ext/carray_bincount.c +39 -7
- data/ext/carray_broadcast.c +56 -19
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_call_cfunc.c +108 -28
- data/ext/carray_cast.c +1576 -223
- data/ext/carray_cast_func.rb +77 -24
- data/ext/carray_class.c +4 -3
- data/ext/carray_conversion.c +208 -75
- data/ext/carray_copy.c +82 -24
- data/ext/carray_core.c +646 -162
- data/ext/carray_count.c +171 -88
- data/ext/carray_element.c +94 -60
- data/ext/carray_factorize.c +670 -324
- data/ext/carray_generate.c +260 -83
- data/ext/carray_histogram.c +209 -106
- data/ext/carray_hold.c +14 -16
- data/ext/carray_index_classifier.c +422 -243
- data/ext/carray_internal.h +692 -3
- data/ext/carray_kernels_bincmp.c +7 -0
- data/ext/carray_kernels_binop.c +487 -120
- data/ext/carray_kernels_init.c +653 -50
- data/ext/carray_kernels_moncmp.c +15 -8
- data/ext/carray_kernels_monop.c +99 -43
- data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
- data/ext/carray_kernels_reduce_boolean.c +112 -36
- data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
- data/ext/carray_kernels_reduce_extreme.c +3032 -2892
- data/ext/carray_kernels_reduce_variance.c +439 -500
- data/ext/carray_kernels_scan.c +1097 -488
- data/ext/carray_kernels_search.c +3787 -2176
- data/ext/carray_kernels_sort.c +1200 -920
- data/ext/carray_kernels_triop.c +479 -7
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +967 -153
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +910 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +299 -100
- data/ext/carray_memory_view.c +872 -758
- data/ext/carray_operator.c +1171 -364
- data/ext/carray_order.c +505 -133
- data/ext/carray_partition.c +112 -65
- data/ext/carray_random.c +327 -239
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +346 -78
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +249 -86
- data/ext/carray_sort.c +224 -227
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +118 -39
- data/ext/carray_test.c +193 -69
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +579 -113
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +19 -4
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1202 -1014
- data/ext/ruby_carray.c +17 -5
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +160 -17
- data/lib/carray/autoload_carray.rb +23 -27
- data/lib/carray/autoload_method_extension.rb +20 -5
- data/lib/carray/axis_group.rb +360 -63
- data/lib/carray/basics.rb +162 -28
- data/lib/carray/bincount_nd.rb +18 -2
- data/lib/carray/block_iterator.rb +231 -58
- data/lib/carray/boolean_reduce.rb +34 -42
- data/lib/carray/categorical.rb +242 -52
- data/lib/carray/categorical_iterator.rb +437 -827
- data/lib/carray/complex.rb +41 -34
- data/lib/carray/conditional.rb +150 -14
- data/lib/carray/const_string.rb +59 -4
- 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/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +82 -7
- data/lib/carray/frame/csv_parser.rb +688 -87
- data/lib/carray/frame/describe.rb +80 -0
- data/lib/carray/frame/frame.rb +369 -45
- data/lib/carray/frame/group.rb +631 -90
- data/lib/carray/frame/io.rb +506 -79
- data/lib/carray/frame/join.rb +411 -62
- data/lib/carray/frame/records.rb +116 -19
- data/lib/carray/frame/reshape.rb +455 -0
- data/lib/carray/frame/sort.rb +30 -18
- data/lib/carray/frame/verbs.rb +868 -61
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +4 -0
- data/lib/carray/fuse_source.rb +118 -2
- data/lib/carray/fusion.rb +257 -42
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +54 -13
- data/lib/carray/iterator.rb +99 -9
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +216 -193
- data/lib/carray/mask_gap_fill.rb +112 -92
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +52 -21
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +18 -2
- data/lib/carray/methods/bit_string.rb +15 -4
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +18 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +25 -5
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +140 -10
- data/lib/carray/methods/join.rb +2 -7
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +182 -45
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +65 -17
- data/lib/carray/segment_iterator.rb +1221 -0
- data/lib/carray/serialize.rb +214 -30
- data/lib/carray/slab_iterator.rb +101 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +12 -4
- data/lib/carray/struct.rb +137 -58
- data/lib/carray/struct_builder.rb +124 -17
- data/lib/carray/time.rb +1222 -186
- data/lib/carray/window_iterator.rb +242 -81
- data/lib/carray.rb +9 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +5 -1
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +5 -4
- data/yard-stubs/ca_obj_roll.rb +2 -3
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +9 -5
- data/yard-stubs/carray_access.rb +11 -5
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +88 -43
- data/yard-stubs/carray_conversion.rb +15 -2
- data/yard-stubs/carray_copy.rb +12 -5
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +60 -12
- data/yard-stubs/carray_math.rb +52 -14
- data/yard-stubs/carray_median_percentile.rb +15 -8
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +61 -29
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +21 -9
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +10 -2
- data/yard-stubs/carray_sort.rb +49 -8
- data/yard-stubs/carray_test.rb +15 -3
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -5
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_kernels_map.c +0 -3467
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_address_basis.c
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "carray.h"
|
|
2
|
+
#include "carray_internal.h"
|
|
2
3
|
|
|
3
4
|
/* ---------------------------------------------------------------------------
|
|
4
5
|
|
|
@@ -8,8 +9,8 @@
|
|
|
8
9
|
writes a[i] from its own loop, so what it needs from CArray is not element
|
|
9
10
|
delivery but an addressing basis: a pointer, already shifted to cell zero,
|
|
10
11
|
and one byte stride per axis. That is why this does not sit on the kernel
|
|
11
|
-
iterator (per-cell / per-slab delivery, and no N-ary form) or on the
|
|
12
|
-
|
|
12
|
+
iterator (per-cell / per-slab delivery, and no N-ary form) or on the
|
|
13
|
+
call_cfunc families (which flatten the array and cannot recover the axis
|
|
13
14
|
structure a stencil needs).
|
|
14
15
|
|
|
15
16
|
This is a runtime facility at the same layer as ca_attach, not a user
|
|
@@ -77,8 +78,16 @@ typedef struct {
|
|
|
77
78
|
ca_size_t *region_start; /* count * CA_RANK_MAX */
|
|
78
79
|
ca_size_t *region_count;
|
|
79
80
|
VALUE bases;
|
|
80
|
-
|
|
81
|
-
|
|
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 */
|
|
85
|
+
int body_done; /* the block returned without raising */
|
|
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;
|
|
82
91
|
} open_state;
|
|
83
92
|
|
|
84
93
|
/* The view's own row-major byte layout, which is the address space
|
|
@@ -94,6 +103,15 @@ native_steps (CArray *ca, ca_size_t *steps)
|
|
|
94
103
|
}
|
|
95
104
|
}
|
|
96
105
|
|
|
106
|
+
/* Whether [start, start + count) leaves [0, dim). Written so that no sum
|
|
107
|
+
is formed: a start and a count near the top of the integer range add up
|
|
108
|
+
to a negative number, which `start + count > dim` lets through. */
|
|
109
|
+
static int
|
|
110
|
+
outside_axis (ca_size_t start, ca_size_t count, ca_size_t dim)
|
|
111
|
+
{
|
|
112
|
+
return start < 0 || count < 0 || start > dim || count > dim - start;
|
|
113
|
+
}
|
|
114
|
+
|
|
97
115
|
/* Checks one array's box description, all of it: that it is one start and one
|
|
98
116
|
count per axis, that they are numbers, and that the box they describe is
|
|
99
117
|
inside the array.
|
|
@@ -124,39 +142,34 @@ verify_box (VALUE box_starts, VALUE box_counts, int index, CArray *ca)
|
|
|
124
142
|
"this array has %d", (int) ca->ndim);
|
|
125
143
|
}
|
|
126
144
|
for ( k = 0; k < ca->ndim; k++ ) {
|
|
127
|
-
ca_size_t start =
|
|
128
|
-
|
|
129
|
-
|
|
145
|
+
ca_size_t start = ca_integer_arg(rb_ary_entry(starts, k), "a region start",
|
|
146
|
+
"CArray::AddressBasis.open");
|
|
147
|
+
ca_size_t count = ca_integer_arg(rb_ary_entry(counts, k), "a region count",
|
|
148
|
+
"CArray::AddressBasis.open");
|
|
149
|
+
if ( outside_axis(start, count, ca->dim[k]) ) {
|
|
130
150
|
rb_raise(rb_eArgError,
|
|
131
151
|
"the requested region falls outside the array on axis %d", (int) k);
|
|
132
152
|
}
|
|
133
153
|
}
|
|
134
154
|
}
|
|
135
155
|
|
|
136
|
-
/* Reads one array's box
|
|
137
|
-
|
|
138
|
-
|
|
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. */
|
|
139
159
|
static void
|
|
140
160
|
read_box (open_state *state, int index, CArray *ca,
|
|
141
161
|
ca_size_t *starts, ca_size_t *counts)
|
|
142
162
|
{
|
|
143
|
-
VALUE per_array_start = Qnil, per_array_count = Qnil;
|
|
144
163
|
int8_t k;
|
|
145
|
-
|
|
146
|
-
if ( ! NIL_P(state->box_starts) ) {
|
|
147
|
-
per_array_start = rb_ary_entry(state->box_starts, index);
|
|
148
|
-
per_array_count = rb_ary_entry(state->box_counts, index);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
164
|
for ( k = 0; k < ca->ndim; k++ ) {
|
|
152
|
-
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 {
|
|
153
169
|
starts[k] = 0;
|
|
154
170
|
counts[k] = ca->dim[k];
|
|
155
|
-
} else {
|
|
156
|
-
starts[k] = NUM2LL(rb_ary_entry(per_array_start, k));
|
|
157
|
-
counts[k] = NUM2LL(rb_ary_entry(per_array_count, k));
|
|
158
171
|
}
|
|
159
|
-
if ( starts[k]
|
|
172
|
+
if ( outside_axis(starts[k], counts[k], ca->dim[k]) ) {
|
|
160
173
|
rb_raise(rb_eArgError,
|
|
161
174
|
"the requested region falls outside the array on axis %d", (int) k);
|
|
162
175
|
}
|
|
@@ -188,14 +201,14 @@ size_array (ca_size_t *values, int8_t count)
|
|
|
188
201
|
/* Refuses what a generated kernel cannot express, rather than letting it
|
|
189
202
|
produce quietly wrong numbers. */
|
|
190
203
|
static void
|
|
191
|
-
verify_usable (VALUE
|
|
204
|
+
verify_usable (VALUE klass, CArray *ca, int writable)
|
|
192
205
|
{
|
|
193
206
|
if ( ca->data_type == CA_OBJECT ) {
|
|
194
207
|
rb_raise(rb_eArgError, "object arrays hold Ruby values, not numbers");
|
|
195
208
|
}
|
|
196
209
|
if ( writable && ca_is_readonly(ca) ) {
|
|
197
|
-
|
|
198
|
-
|
|
210
|
+
/* read-only-check: names which array a basis was asked to write through */
|
|
211
|
+
rb_raise(rb_eRuntimeError, "%"PRIsVALUE" is read-only", klass);
|
|
199
212
|
}
|
|
200
213
|
}
|
|
201
214
|
|
|
@@ -217,6 +230,96 @@ folds_to_an_entity (CArray *ca)
|
|
|
217
230
|
return ca_is_entity(root);
|
|
218
231
|
}
|
|
219
232
|
|
|
233
|
+
/* A view that reinterprets the element size -- refer(CA_INT32, ...) over
|
|
234
|
+
a float64 array -- gets a mask of its own shape, but one mask cell of it
|
|
235
|
+
covers a fraction of a parent cell, so writing cell i's mask also marks
|
|
236
|
+
its neighbour. A per-cell kernel writes cells independently and cannot
|
|
237
|
+
express that. Checked for every tier: a box transfer moves the same
|
|
238
|
+
mask, and the neighbour is marked when it is written back. */
|
|
239
|
+
static int
|
|
240
|
+
mask_cells_split (CArray *ca)
|
|
241
|
+
{
|
|
242
|
+
CArray *root;
|
|
243
|
+
ca_size_t strides[CA_RANK_MAX];
|
|
244
|
+
ca_size_t base = 0;
|
|
245
|
+
if ( ! ca->mask || ! ca_is_stride_family(ca) ) return 0;
|
|
246
|
+
ca_stride_compose_to_root((CAStride *) ca, &root, strides, &base);
|
|
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) ) {
|
|
254
|
+
rb_raise(rb_eArgError,
|
|
255
|
+
"%"PRIsVALUE" reinterprets the element size and carries a mask; "
|
|
256
|
+
"its mask cells do not map one to one onto the parent's",
|
|
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);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
220
323
|
static int
|
|
221
324
|
tier_for (CArray *ca)
|
|
222
325
|
{
|
|
@@ -239,7 +342,7 @@ acquire_basis (open_state *state, int index, ca_size_t *strides)
|
|
|
239
342
|
switch ( state->tier[index] ) {
|
|
240
343
|
case TIER_ENTITY: {
|
|
241
344
|
CArray *root = ca;
|
|
242
|
-
ca_attach(root);
|
|
345
|
+
ca_attach(root); /* window: released by open_ensure */
|
|
243
346
|
state->roots[index] = root;
|
|
244
347
|
state->attached_root[index] = 1;
|
|
245
348
|
row_major_strides(ca, strides);
|
|
@@ -250,18 +353,7 @@ acquire_basis (open_state *state, int index, ca_size_t *strides)
|
|
|
250
353
|
case TIER_STRIDE: {
|
|
251
354
|
CArray *root;
|
|
252
355
|
ca_stride_compose_to_root((CAStride *) ca, &root, strides, &base);
|
|
253
|
-
/*
|
|
254
|
-
a float64 array -- gets a mask of its own shape, but one mask cell of
|
|
255
|
-
it covers a fraction of a parent cell, so writing cell i's mask also
|
|
256
|
-
marks its neighbour. A per-cell kernel writes cells independently and
|
|
257
|
-
cannot express that. */
|
|
258
|
-
if ( ca->mask && ca->bytes != root->bytes ) {
|
|
259
|
-
rb_raise(rb_eArgError,
|
|
260
|
-
"%"PRIsVALUE" reinterprets the element size and carries a mask; "
|
|
261
|
-
"its mask cells do not map one to one onto the parent's",
|
|
262
|
-
rb_obj_class(rb_ary_entry(state->arrays, index)));
|
|
263
|
-
}
|
|
264
|
-
ca_attach(root);
|
|
356
|
+
ca_attach(root); /* window: released by open_ensure */
|
|
265
357
|
state->roots[index] = root;
|
|
266
358
|
state->attached_root[index] = 1;
|
|
267
359
|
pointer = root->ptr + base;
|
|
@@ -287,12 +379,26 @@ acquire_basis (open_state *state, int index, ca_size_t *strides)
|
|
|
287
379
|
step *= counts[k];
|
|
288
380
|
}
|
|
289
381
|
|
|
290
|
-
|
|
382
|
+
/* Recorded before the read: the read can raise, and open_ensure
|
|
383
|
+
frees what state->region holds. The counts stay zero until the
|
|
384
|
+
read is done, so a buffer that was never filled is not written
|
|
385
|
+
back. */
|
|
386
|
+
/* A writable box keeps a second copy of what it read, so that the
|
|
387
|
+
write-back can send only the cells the kernel changed (see
|
|
388
|
+
put_changed). */
|
|
389
|
+
buffer = ALLOC_N(char, (state->writable[index] ? 2 : 1)
|
|
390
|
+
* (elements > 0 ? elements : 1) * ca->bytes);
|
|
391
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
392
|
+
state->region_count[index * CA_RANK_MAX + k] = 0;
|
|
393
|
+
}
|
|
394
|
+
state->region[index] = buffer;
|
|
291
395
|
if ( elements > 0 ) {
|
|
292
396
|
ca_xfer_stride(ca, starts, counts, steps, buffer, CA_XFER_GET);
|
|
397
|
+
if ( state->writable[index] ) {
|
|
398
|
+
memcpy(buffer + elements * ca->bytes, buffer, elements * ca->bytes);
|
|
399
|
+
}
|
|
293
400
|
}
|
|
294
401
|
|
|
295
|
-
state->region[index] = buffer;
|
|
296
402
|
for ( k = 0; k < ca->ndim; k++ ) {
|
|
297
403
|
state->region_start[index * CA_RANK_MAX + k] = starts[k];
|
|
298
404
|
state->region_count[index * CA_RANK_MAX + k] = counts[k];
|
|
@@ -350,20 +456,96 @@ open_body (VALUE argument)
|
|
|
350
456
|
}
|
|
351
457
|
rb_ary_push(state->bases, basis);
|
|
352
458
|
}
|
|
353
|
-
|
|
459
|
+
{
|
|
460
|
+
VALUE result;
|
|
461
|
+
state->lent = 1;
|
|
462
|
+
result = rb_yield(state->bases);
|
|
463
|
+
state->body_done = 1;
|
|
464
|
+
return result;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
typedef struct {
|
|
469
|
+
CArray *ca;
|
|
470
|
+
ca_size_t *start;
|
|
471
|
+
ca_size_t *count;
|
|
472
|
+
ca_size_t *steps;
|
|
473
|
+
char *data;
|
|
474
|
+
char *read; /* the box as it was read */
|
|
475
|
+
} write_back_args;
|
|
476
|
+
|
|
477
|
+
/* Sends back the cells whose bytes differ from what was read, one run
|
|
478
|
+
along the last axis at a time. Sending the whole box would also send the
|
|
479
|
+
cells the kernel never wrote, and those do not come back unchanged
|
|
480
|
+
through a view that converts -- a float64 array seen through an int32
|
|
481
|
+
view reads 1.75 as 1 and would be left holding 1.0. It would also
|
|
482
|
+
overwrite what the kernel wrote to the same cells through another basis
|
|
483
|
+
that addresses them in place. */
|
|
484
|
+
static VALUE
|
|
485
|
+
write_back (VALUE argument)
|
|
486
|
+
{
|
|
487
|
+
write_back_args *w = (write_back_args *) argument;
|
|
488
|
+
CArray *ca = w->ca;
|
|
489
|
+
int8_t nd = ca->ndim;
|
|
490
|
+
size_t bytes = ca->bytes;
|
|
491
|
+
ca_size_t inner = w->count[nd - 1];
|
|
492
|
+
ca_size_t outer = 1;
|
|
493
|
+
ca_size_t idx[CA_RANK_MAX], start[CA_RANK_MAX], count[CA_RANK_MAX];
|
|
494
|
+
ca_size_t o, j, e;
|
|
495
|
+
int8_t k;
|
|
496
|
+
|
|
497
|
+
for ( k = 0; k < nd - 1; k++ ) {
|
|
498
|
+
outer *= w->count[k];
|
|
499
|
+
idx[k] = 0;
|
|
500
|
+
count[k] = 1;
|
|
501
|
+
}
|
|
502
|
+
for ( o = 0; o < outer; o++ ) {
|
|
503
|
+
char *row = w->data + o * inner * bytes;
|
|
504
|
+
char *read = w->read + o * inner * bytes;
|
|
505
|
+
for ( k = 0; k < nd - 1; k++ ) start[k] = w->start[k] + idx[k];
|
|
506
|
+
j = 0;
|
|
507
|
+
while ( j < inner ) {
|
|
508
|
+
if ( ! memcmp(row + j * bytes, read + j * bytes, bytes) ) { j++; continue; }
|
|
509
|
+
e = j + 1;
|
|
510
|
+
while ( e < inner && memcmp(row + e * bytes, read + e * bytes, bytes) ) e++;
|
|
511
|
+
start[nd - 1] = w->start[nd - 1] + j;
|
|
512
|
+
count[nd - 1] = e - j;
|
|
513
|
+
ca_xfer_stride(ca, start, count, w->steps, row + j * bytes, CA_XFER_PUT);
|
|
514
|
+
j = e;
|
|
515
|
+
}
|
|
516
|
+
for ( k = nd - 2; k >= 0; k-- ) {
|
|
517
|
+
if ( ++idx[k] < w->count[k] ) break;
|
|
518
|
+
idx[k] = 0;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return Qnil;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/* Closes in reverse order, and runs whether or not the kernel raised. A
|
|
525
|
+
write-back that raises -- the array's own transfer slot failing -- is
|
|
526
|
+
set aside so that every other region is still written and freed and
|
|
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;
|
|
354
533
|
}
|
|
355
534
|
|
|
356
|
-
/* Closes in reverse order, and runs whether or not the kernel raised. */
|
|
357
535
|
static VALUE
|
|
358
536
|
open_ensure (VALUE argument)
|
|
359
537
|
{
|
|
360
538
|
open_state *state = (open_state *) argument;
|
|
361
539
|
int i;
|
|
540
|
+
/* Raised before the block was entered: by lending an array */
|
|
541
|
+
if ( ! state->lent ) mark_failure(rb_errinfo());
|
|
362
542
|
for ( i = state->slots - 1; i >= 0; i-- ) {
|
|
363
543
|
CArray *ca = state->carrays[i];
|
|
364
544
|
if ( ca == NULL ) continue;
|
|
365
|
-
/* A tier-1 or tier-2 basis addresses the root's own memory
|
|
366
|
-
|
|
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. */
|
|
367
549
|
if ( state->region[i] ) {
|
|
368
550
|
ca_size_t elements = 1;
|
|
369
551
|
int8_t k;
|
|
@@ -371,19 +553,48 @@ open_ensure (VALUE argument)
|
|
|
371
553
|
elements *= state->region_count[i * CA_RANK_MAX + k];
|
|
372
554
|
}
|
|
373
555
|
if ( state->writable[i] && elements > 0 ) {
|
|
374
|
-
ca_size_t
|
|
556
|
+
ca_size_t steps[CA_RANK_MAX];
|
|
557
|
+
write_back_args w;
|
|
558
|
+
int tag = 0;
|
|
375
559
|
native_steps(ca, steps);
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
560
|
+
w.ca = ca;
|
|
561
|
+
w.start = &state->region_start[i * CA_RANK_MAX];
|
|
562
|
+
w.count = &state->region_count[i * CA_RANK_MAX];
|
|
563
|
+
w.steps = steps;
|
|
564
|
+
w.data = state->region[i];
|
|
565
|
+
w.read = state->region[i] + elements * ca->bytes;
|
|
566
|
+
/* protect: keeps the error so that every region is written back first */
|
|
567
|
+
rb_protect(write_back, (VALUE) &w, &tag);
|
|
568
|
+
if ( tag ) {
|
|
569
|
+
if ( NIL_P(state->put_error) ) {
|
|
570
|
+
state->put_error = rb_errinfo();
|
|
571
|
+
}
|
|
572
|
+
rb_set_errinfo(Qnil);
|
|
573
|
+
}
|
|
379
574
|
}
|
|
380
575
|
xfree(state->region[i]);
|
|
381
576
|
}
|
|
382
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
|
+
}
|
|
383
589
|
ca_detach(state->roots[i]);
|
|
384
590
|
}
|
|
385
591
|
}
|
|
386
592
|
xfree(state->block);
|
|
593
|
+
if ( state->body_done && RTEST(rb_obj_is_kind_of(state->put_error,
|
|
594
|
+
rb_eException)) ) {
|
|
595
|
+
mark_failure(state->put_error);
|
|
596
|
+
rb_exc_raise(state->put_error);
|
|
597
|
+
}
|
|
387
598
|
return Qnil;
|
|
388
599
|
}
|
|
389
600
|
|
|
@@ -450,8 +661,98 @@ packed_body (VALUE argument)
|
|
|
450
661
|
for ( k = 0; k < ca->ndim; k++ ) *mask_stride_slot++ = 0;
|
|
451
662
|
}
|
|
452
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);
|
|
453
670
|
|
|
454
|
-
|
|
671
|
+
{
|
|
672
|
+
VALUE result;
|
|
673
|
+
state->lent = 1;
|
|
674
|
+
result = rb_yield_values(4, pointers, strides, mask_pointers, mask_strides);
|
|
675
|
+
state->body_done = 1;
|
|
676
|
+
return result;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
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
|
+
}
|
|
455
756
|
}
|
|
456
757
|
|
|
457
758
|
/*
|
|
@@ -468,7 +769,7 @@ address_basis_open (int argc, VALUE *argv, VALUE module)
|
|
|
468
769
|
{
|
|
469
770
|
VALUE arrays, writable_flags, box_start, box_count, packed;
|
|
470
771
|
open_state state;
|
|
471
|
-
int i;
|
|
772
|
+
int i, n;
|
|
472
773
|
|
|
473
774
|
rb_scan_args(argc, argv, "23", &arrays, &writable_flags, &box_start,
|
|
474
775
|
&box_count, &packed);
|
|
@@ -488,63 +789,140 @@ address_basis_open (int argc, VALUE *argv, VALUE module)
|
|
|
488
789
|
if ( RARRAY_LEN(arrays) != RARRAY_LEN(writable_flags) ) {
|
|
489
790
|
rb_raise(rb_eArgError, "one writable flag per array is required");
|
|
490
791
|
}
|
|
792
|
+
n = (int) RARRAY_LEN(arrays);
|
|
491
793
|
|
|
492
|
-
state
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
state.bases = rb_ary_new_capa(state.count);
|
|
496
|
-
/* One allocation, carved up, rather than eight. Every array here is the
|
|
497
|
-
same length in slots and lives exactly as long as the open, so there is
|
|
498
|
-
nothing for eight separate lifetimes to buy -- and this is a per-call
|
|
499
|
-
cost on a path whose whole point is to be cheap enough to cross often.
|
|
500
|
-
Zeroed once as a block, which is also what the slots want to start as:
|
|
501
|
-
a NULL array, a NULL root, not writable, not attached, no region. */
|
|
502
|
-
{
|
|
503
|
-
size_t n = (size_t) state.slots + 1;
|
|
504
|
-
size_t pointers = ROUND_UP_8(n * sizeof(CArray *));
|
|
505
|
-
size_t chars = ROUND_UP_8(n * sizeof(char *));
|
|
506
|
-
size_t sizes = ROUND_UP_8(n * CA_RANK_MAX * sizeof(ca_size_t));
|
|
507
|
-
size_t ints = ROUND_UP_8(n * sizeof(int));
|
|
508
|
-
size_t total = 2 * pointers + chars + 2 * sizes + 3 * ints;
|
|
509
|
-
char *p;
|
|
510
|
-
state.block = ALLOC_N(char, total);
|
|
511
|
-
MEMZERO(state.block, char, total);
|
|
512
|
-
p = state.block;
|
|
513
|
-
state.carrays = (CArray **) p; p += pointers;
|
|
514
|
-
state.roots = (CArray **) p; p += pointers;
|
|
515
|
-
state.region = (char **) p; p += chars;
|
|
516
|
-
state.region_start = (ca_size_t *) p; p += sizes;
|
|
517
|
-
state.region_count = (ca_size_t *) p; p += sizes;
|
|
518
|
-
state.tier = (int *) p; p += ints;
|
|
519
|
-
state.writable = (int *) p; p += ints;
|
|
520
|
-
state.attached_root = (int *) p;
|
|
521
|
-
}
|
|
522
|
-
state.box_starts = box_start;
|
|
523
|
-
state.box_counts = box_count;
|
|
524
|
-
|
|
525
|
-
for ( i = 0; i < state.count; 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++ ) {
|
|
526
797
|
VALUE object = rb_ary_entry(arrays, i);
|
|
527
798
|
CArray *ca;
|
|
528
799
|
GetCArray(object, ca);
|
|
529
|
-
|
|
530
|
-
state.writable[i] = RTEST(rb_ary_entry(writable_flags, i));
|
|
531
|
-
verify_usable(object, ca, state.writable[i]);
|
|
800
|
+
verify_array(rb_obj_class(object), ca, RTEST(rb_ary_entry(writable_flags, i)));
|
|
532
801
|
verify_box(box_start, box_count, i, ca);
|
|
533
|
-
|
|
802
|
+
}
|
|
534
803
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
804
|
+
{
|
|
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
|
+
}
|
|
835
|
+
}
|
|
836
|
+
ab_prepare(&state, n, carrays, flags, bs, bc);
|
|
837
|
+
ALLOCV_END(vholder);
|
|
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);
|
|
843
|
+
|
|
844
|
+
{
|
|
845
|
+
VALUE result = RTEST(packed)
|
|
846
|
+
? rb_ensure(packed_body, (VALUE) &state, open_ensure, (VALUE) &state)
|
|
847
|
+
: rb_ensure(open_body, (VALUE) &state, open_ensure, (VALUE) &state);
|
|
848
|
+
RB_GC_GUARD(state.arrays);
|
|
849
|
+
return result;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
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);
|
|
540
867
|
}
|
|
541
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
|
+
}
|
|
542
877
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
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");
|
|
547
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);
|
|
548
926
|
}
|
|
549
927
|
|
|
550
928
|
/* Reports how an array would be opened, without opening it. */
|
|
@@ -556,6 +934,7 @@ address_basis_classify (VALUE module, VALUE object)
|
|
|
556
934
|
int tier;
|
|
557
935
|
|
|
558
936
|
GetCArray(object, ca);
|
|
937
|
+
ca_update_mask(ca);
|
|
559
938
|
tier = tier_for(ca);
|
|
560
939
|
|
|
561
940
|
result = rb_hash_new();
|
|
@@ -568,9 +947,24 @@ address_basis_classify (VALUE module, VALUE object)
|
|
|
568
947
|
rb_hash_aset(result, ID2SYM(rb_intern("dim")), size_array(ca->dim, ca->ndim));
|
|
569
948
|
rb_hash_aset(result, ID2SYM(rb_intern("bytes")), LL2NUM((long long) ca->bytes));
|
|
570
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
|
+
}
|
|
571
955
|
return result;
|
|
572
956
|
}
|
|
573
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
|
+
|
|
574
968
|
/* ------------------------------------------------------------------- */
|
|
575
969
|
/* Init_carray_address_basis */
|
|
576
970
|
/* ------------------------------------------------------------------- */
|
|
@@ -583,8 +977,11 @@ Init_carray_address_basis (void)
|
|
|
583
977
|
rb_define_singleton_method(mAddressBasis, "open", address_basis_open, -1);
|
|
584
978
|
rb_define_singleton_method(mAddressBasis, "classify",
|
|
585
979
|
address_basis_classify, 1);
|
|
980
|
+
rb_define_singleton_method(mAddressBasis, "tier", address_basis_tier, 1);
|
|
586
981
|
|
|
587
982
|
rb_define_const(mAddressBasis, "TIER_ENTITY", INT2NUM(TIER_ENTITY));
|
|
588
983
|
rb_define_const(mAddressBasis, "TIER_STRIDE", INT2NUM(TIER_STRIDE));
|
|
589
984
|
rb_define_const(mAddressBasis, "TIER_XFER", INT2NUM(TIER_XFER));
|
|
985
|
+
|
|
986
|
+
mFailure = rb_define_module_under(mAddressBasis, "Failure");
|
|
590
987
|
}
|