carray 3.0.1 → 3.0.3
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 +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -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_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_obj_object.c
CHANGED
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
36
|
#include "carray.h"
|
|
37
|
+
#include "carray_internal.h"
|
|
37
38
|
#include "ca_obj_face.h" /* ca_face_* helpers for Face mode shortcuts */
|
|
38
39
|
|
|
39
40
|
static size_t
|
|
@@ -82,11 +83,21 @@ ca_objectmask_dsize (const void *ap)
|
|
|
82
83
|
return sizeof(CAObjectMask) + ca->ndim * sizeof(ca_size_t);
|
|
83
84
|
}
|
|
84
85
|
|
|
86
|
+
/* The mask reads and writes through its CAObject, and its cache is the
|
|
87
|
+
CAObject's; it keeps the CAObject alive. */
|
|
88
|
+
static void
|
|
89
|
+
ca_objmask_mark (void *ap)
|
|
90
|
+
{
|
|
91
|
+
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
92
|
+
rb_gc_mark(ca->array);
|
|
93
|
+
ca_mark(ap);
|
|
94
|
+
}
|
|
95
|
+
|
|
85
96
|
const rb_data_type_t caobjectmask_data_type = {
|
|
86
97
|
.parent = &carray_data_type,
|
|
87
98
|
.wrap_struct_name = "CAObjectMask",
|
|
88
99
|
.function = {
|
|
89
|
-
.dmark =
|
|
100
|
+
.dmark = ca_objmask_mark,
|
|
90
101
|
.dfree = ca_free,
|
|
91
102
|
.dsize = ca_objectmask_dsize,
|
|
92
103
|
.dcompact = NULL
|
|
@@ -110,6 +121,8 @@ ca_objmask_new (VALUE array, int8_t ndim, ca_size_t *dim)
|
|
|
110
121
|
ca_wrap_setup_null((CArray *)ca, CA_BOOLEAN, ndim, dim, 0, NULL);
|
|
111
122
|
ca->obj_type = CA_OBJ_OBJECT_MASK;
|
|
112
123
|
ca->array = array;
|
|
124
|
+
ca->cache = NULL;
|
|
125
|
+
ca->holds = 0;
|
|
113
126
|
|
|
114
127
|
return ca;
|
|
115
128
|
}
|
|
@@ -122,125 +135,358 @@ ca_objmask_mask_data (void *ap)
|
|
|
122
135
|
rb_intern("mask"), 0);
|
|
123
136
|
}
|
|
124
137
|
|
|
138
|
+
/* Calls recv.mid(arg(ap)) with *slot pointing at a caller's buffer for
|
|
139
|
+
the duration, and puts *slot back however the call leaves. The bulk
|
|
140
|
+
bridge lends the buffer this way so that copy_data / sync_data write
|
|
141
|
+
straight into it; a raise that skipped the restore would leave the
|
|
142
|
+
array pointing at a buffer its caller is about to free. */
|
|
143
|
+
|
|
144
|
+
typedef struct {
|
|
145
|
+
char **slot;
|
|
146
|
+
char *saved;
|
|
147
|
+
VALUE recv;
|
|
148
|
+
ID mid;
|
|
149
|
+
VALUE (*arg)(void *);
|
|
150
|
+
void *ap;
|
|
151
|
+
} ca_object_lend_t;
|
|
152
|
+
|
|
153
|
+
static VALUE
|
|
154
|
+
ca_object_lend_body (VALUE varg)
|
|
155
|
+
{
|
|
156
|
+
ca_object_lend_t *l = (ca_object_lend_t *) varg;
|
|
157
|
+
return rb_funcall(l->recv, l->mid, 1, l->arg(l->ap));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static VALUE
|
|
161
|
+
ca_object_lend_restore (VALUE varg)
|
|
162
|
+
{
|
|
163
|
+
ca_object_lend_t *l = (ca_object_lend_t *) varg;
|
|
164
|
+
*l->slot = l->saved;
|
|
165
|
+
return Qnil;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static void
|
|
169
|
+
ca_object_call_lending (char **slot, void *ptr, VALUE recv, const char *mid,
|
|
170
|
+
VALUE (*arg)(void *), void *ap)
|
|
171
|
+
{
|
|
172
|
+
ca_object_lend_t l;
|
|
173
|
+
l.slot = slot;
|
|
174
|
+
l.saved = *slot;
|
|
175
|
+
l.recv = recv;
|
|
176
|
+
l.mid = rb_intern(mid);
|
|
177
|
+
l.arg = arg;
|
|
178
|
+
l.ap = ap;
|
|
179
|
+
*slot = (char *) ptr;
|
|
180
|
+
rb_ensure(ca_object_lend_body, (VALUE) &l,
|
|
181
|
+
ca_object_lend_restore, (VALUE) &l);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* Calls recv.mid(*argv), where some of argv are transient wraps of a
|
|
185
|
+
caller's buffer (ca_object_wrap_transient), and takes the buffer back
|
|
186
|
+
from each of them however the call leaves. The caller frees its buffer
|
|
187
|
+
when it returns, and a wrap outlives the call: the collector scans the
|
|
188
|
+
machine stack conservatively and still finds it there, and an object
|
|
189
|
+
wrap is marked cell by cell -- through a buffer that is gone. A wrap
|
|
190
|
+
taken back points at nothing; a hook that kept it holds an empty
|
|
191
|
+
handle, not a stale one. */
|
|
192
|
+
|
|
193
|
+
typedef struct {
|
|
194
|
+
VALUE recv;
|
|
195
|
+
ID mid;
|
|
196
|
+
int argc;
|
|
197
|
+
const VALUE *argv;
|
|
198
|
+
int ntrans;
|
|
199
|
+
const VALUE *trans;
|
|
200
|
+
} ca_object_hook_t;
|
|
201
|
+
|
|
202
|
+
static VALUE
|
|
203
|
+
ca_object_hook_body (VALUE varg)
|
|
204
|
+
{
|
|
205
|
+
ca_object_hook_t *h = (ca_object_hook_t *) varg;
|
|
206
|
+
return rb_funcallv(h->recv, h->mid, h->argc, h->argv);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static VALUE
|
|
210
|
+
ca_object_hook_release (VALUE varg)
|
|
211
|
+
{
|
|
212
|
+
ca_object_hook_t *h = (ca_object_hook_t *) varg;
|
|
213
|
+
int i;
|
|
214
|
+
for ( i = 0; i < h->ntrans; i++ ) {
|
|
215
|
+
((CArray *) DATA_PTR(h->trans[i]))->ptr = NULL;
|
|
216
|
+
}
|
|
217
|
+
return Qnil;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
static void
|
|
221
|
+
ca_object_call_transient (VALUE recv, const char *mid,
|
|
222
|
+
int argc, const VALUE *argv,
|
|
223
|
+
int ntrans, const VALUE *trans)
|
|
224
|
+
{
|
|
225
|
+
ca_object_hook_t h;
|
|
226
|
+
h.recv = recv;
|
|
227
|
+
h.mid = rb_intern(mid);
|
|
228
|
+
h.argc = argc;
|
|
229
|
+
h.argv = argv;
|
|
230
|
+
h.ntrans = ntrans;
|
|
231
|
+
h.trans = trans;
|
|
232
|
+
rb_ensure(ca_object_hook_body, (VALUE) &h,
|
|
233
|
+
ca_object_hook_release, (VALUE) &h);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
static VALUE
|
|
237
|
+
ca_object_data_of (void *ap)
|
|
238
|
+
{
|
|
239
|
+
return rb_ivar_get(((CAObject *) ap)->self, rb_intern("__data__"));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
/* Forward declaration: ca_object_wrap_transient (defined further down,
|
|
244
|
+
near the data-side xfer functions). */
|
|
245
|
+
static VALUE
|
|
246
|
+
ca_object_wrap_transient (int8_t data_type, ca_size_t bytes,
|
|
247
|
+
int8_t ndim, ca_size_t *dim, void *data, int dir);
|
|
248
|
+
|
|
125
249
|
static void *
|
|
126
250
|
ca_objmask_func_clone (void *ap)
|
|
127
251
|
{
|
|
128
252
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
129
|
-
|
|
253
|
+
CAObjectMask *co = ca_objmask_new(ca->array, ca->ndim, ca->dim);
|
|
254
|
+
co->cache = ca->cache;
|
|
255
|
+
return co;
|
|
130
256
|
}
|
|
131
257
|
|
|
132
|
-
/*
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
direction-unified; the slots below forward. */
|
|
137
|
-
static void
|
|
138
|
-
ca_objmask_xfer_addr_one (CAObjectMask *ca, ca_size_t addr, void *ptr, int dir)
|
|
258
|
+
/* Whether the CAObject answers one of the mask hooks. A copy made by dup
|
|
259
|
+
holds its own bits and answers none (array is nil). */
|
|
260
|
+
static int
|
|
261
|
+
ca_objmask_answers (CAObjectMask *ca, const char *mid)
|
|
139
262
|
{
|
|
140
|
-
|
|
263
|
+
return ! NIL_P(ca->array) && rb_obj_respond_to(ca->array, rb_intern(mid), Qtrue);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
static VALUE
|
|
267
|
+
ca_objmask_index_of (CAObjectMask *ca, ca_size_t addr)
|
|
268
|
+
{
|
|
269
|
+
ca_size_t idx[CA_RANK_MAX];
|
|
270
|
+
VALUE ridx;
|
|
141
271
|
int i;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
272
|
+
ca_addr2index((CArray *) ca, addr, idx);
|
|
273
|
+
ridx = rb_ary_new2(ca->ndim);
|
|
274
|
+
for (i=0; i<ca->ndim; i++) {
|
|
275
|
+
rb_ary_store(ridx, i, SIZE2NUM(idx[i]));
|
|
276
|
+
}
|
|
277
|
+
return ridx;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/* The bit the per-cell hooks give for addr (1 / 0 / true / false), or -1
|
|
281
|
+
when the object has neither mask_fetch_addr nor mask_fetch_index. */
|
|
282
|
+
static int
|
|
283
|
+
ca_objmask_fetch_one (CAObjectMask *ca, ca_size_t addr)
|
|
284
|
+
{
|
|
285
|
+
volatile VALUE rval;
|
|
286
|
+
if ( ca_objmask_answers(ca, "mask_fetch_addr") ) {
|
|
287
|
+
rval = rb_funcall(ca->array, rb_intern("mask_fetch_addr"), 1, SIZE2NUM(addr));
|
|
288
|
+
}
|
|
289
|
+
else if ( ca_objmask_answers(ca, "mask_fetch_index") ) {
|
|
290
|
+
rval = rb_funcall(ca->array, rb_intern("mask_fetch_index"), 1,
|
|
291
|
+
ca_objmask_index_of(ca, addr));
|
|
163
292
|
}
|
|
164
293
|
else {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
294
|
+
return -1;
|
|
295
|
+
}
|
|
296
|
+
if ( rval == Qtrue || rval == Qfalse ) {
|
|
297
|
+
return RTEST(rval);
|
|
298
|
+
}
|
|
299
|
+
return NUM2INT(rval) != 0;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* Hands one bit to the per-cell hooks; 0 when the object has neither
|
|
303
|
+
mask_store_addr nor mask_store_index. */
|
|
304
|
+
static int
|
|
305
|
+
ca_objmask_store_one (CAObjectMask *ca, ca_size_t addr, boolean8_t bit)
|
|
306
|
+
{
|
|
307
|
+
if ( ca_objmask_answers(ca, "mask_store_addr") ) {
|
|
308
|
+
rb_funcall(ca->array, rb_intern("mask_store_addr"), 2,
|
|
309
|
+
SIZE2NUM(addr), INT2NUM(bit ? 1 : 0));
|
|
310
|
+
return 1;
|
|
311
|
+
}
|
|
312
|
+
if ( ca_objmask_answers(ca, "mask_store_index") ) {
|
|
313
|
+
rb_funcall(ca->array, rb_intern("mask_store_index"), 2,
|
|
314
|
+
ca_objmask_index_of(ca, addr), INT2NUM(bit ? 1 : 0));
|
|
315
|
+
return 1;
|
|
316
|
+
}
|
|
317
|
+
return 0;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
static int
|
|
321
|
+
ca_objmask_stores_cells (CAObjectMask *ca)
|
|
322
|
+
{
|
|
323
|
+
return ca_objmask_answers(ca, "mask_store_addr") ||
|
|
324
|
+
ca_objmask_answers(ca, "mask_store_index");
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/* Brings the cache up to date from the hooks that give the mask: the bulk
|
|
328
|
+
one, else the per-cell one. With neither, the cache is the mask. */
|
|
329
|
+
static void
|
|
330
|
+
ca_objmask_refresh (CAObjectMask *ca)
|
|
331
|
+
{
|
|
332
|
+
boolean8_t *c = (boolean8_t *) ca->cache;
|
|
333
|
+
ca_size_t addr;
|
|
334
|
+
int bit;
|
|
335
|
+
if ( ca_objmask_answers(ca, "mask_copy_data") ) {
|
|
336
|
+
rb_funcall(ca->array, rb_intern("mask_copy_data"), 1,
|
|
337
|
+
ca_objmask_mask_data(ca));
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
for ( addr = 0; addr < ca->elements; addr++ ) {
|
|
341
|
+
if ( ( bit = ca_objmask_fetch_one(ca, addr) ) < 0 ) {
|
|
342
|
+
return;
|
|
170
343
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
344
|
+
c[addr] = (boolean8_t) bit;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/* Hands the whole cache to the hooks that take the mask: the bulk one,
|
|
349
|
+
else the per-cell one. */
|
|
350
|
+
static void
|
|
351
|
+
ca_objmask_push (CAObjectMask *ca)
|
|
352
|
+
{
|
|
353
|
+
const boolean8_t *c = (const boolean8_t *) ca->cache;
|
|
354
|
+
ca_size_t addr;
|
|
355
|
+
if ( ca_objmask_answers(ca, "mask_sync_data") ) {
|
|
356
|
+
rb_funcall(ca->array, rb_intern("mask_sync_data"), 1,
|
|
357
|
+
ca_objmask_mask_data(ca));
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
for ( addr = 0; addr < ca->elements; addr++ ) {
|
|
361
|
+
if ( ! ca_objmask_store_one(ca, addr, c[addr]) ) {
|
|
362
|
+
return;
|
|
179
363
|
}
|
|
180
364
|
}
|
|
181
365
|
}
|
|
182
366
|
|
|
367
|
+
/* Reads n bits at addrs while the mask is closed: mask_copy_addrs, else
|
|
368
|
+
the per-cell hooks, else the whole mask brought up to date. */
|
|
183
369
|
static void
|
|
184
|
-
|
|
370
|
+
ca_objmask_get_cells (CAObjectMask *ca, ca_size_t n, ca_size_t *addrs,
|
|
371
|
+
boolean8_t *bits)
|
|
185
372
|
{
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
373
|
+
boolean8_t *c = (boolean8_t *) ca->cache;
|
|
374
|
+
ca_size_t i;
|
|
375
|
+
int bit;
|
|
376
|
+
if ( n > 0 && ca_objmask_answers(ca, "mask_copy_addrs") ) {
|
|
377
|
+
volatile VALUE raddrs, rdata;
|
|
378
|
+
ca_size_t dim1[1] = { n };
|
|
379
|
+
raddrs = ca_object_wrap_transient(CA_SIZE, sizeof(ca_size_t),
|
|
380
|
+
1, dim1, addrs, CA_XFER_PUT);
|
|
381
|
+
rdata = ca_object_wrap_transient(CA_BOOLEAN, 1, 1, dim1, bits,
|
|
382
|
+
CA_XFER_GET);
|
|
383
|
+
{
|
|
384
|
+
VALUE args[2];
|
|
385
|
+
args[0] = raddrs;
|
|
386
|
+
args[1] = rdata;
|
|
387
|
+
ca_object_call_transient(ca->array, "mask_copy_addrs", 2, args, 2, args);
|
|
197
388
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
if ( n > 0 && ( bit = ca_objmask_fetch_one(ca, addrs[0]) ) >= 0 ) {
|
|
392
|
+
c[addrs[0]] = bits[0] = (boolean8_t) bit;
|
|
393
|
+
for ( i = 1; i < n; i++ ) {
|
|
394
|
+
c[addrs[i]] = bits[i] = (boolean8_t) ca_objmask_fetch_one(ca, addrs[i]);
|
|
204
395
|
}
|
|
205
|
-
|
|
206
|
-
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
ca_objmask_refresh(ca);
|
|
399
|
+
for ( i = 0; i < n; i++ ) {
|
|
400
|
+
bits[i] = c[addrs[i]];
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/* Writes n bits at addrs while the mask is closed, and hands them over:
|
|
405
|
+
one by one to the per-cell hooks, as a list to mask_sync_addrs, or else
|
|
406
|
+
the whole mask to mask_sync_data -- brought up to date first, so that
|
|
407
|
+
the cells not written go back as they were. */
|
|
408
|
+
static void
|
|
409
|
+
ca_objmask_put_cells (CAObjectMask *ca, ca_size_t n, ca_size_t *addrs,
|
|
410
|
+
const boolean8_t *bits)
|
|
411
|
+
{
|
|
412
|
+
boolean8_t *c = (boolean8_t *) ca->cache;
|
|
413
|
+
ca_size_t i;
|
|
414
|
+
if ( ca_objmask_stores_cells(ca) ) {
|
|
415
|
+
for ( i = 0; i < n; i++ ) {
|
|
416
|
+
c[addrs[i]] = bits[i] ? 1 : 0;
|
|
417
|
+
ca_objmask_store_one(ca, addrs[i], c[addrs[i]]);
|
|
207
418
|
}
|
|
419
|
+
return;
|
|
208
420
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
for (i=0; i<ca->ndim; i++) {
|
|
215
|
-
rb_ary_store(ridx, i, SIZE2NUM(idx[i]));
|
|
216
|
-
}
|
|
217
|
-
rb_funcall(ca->array, rb_intern("mask_store_index"), 2, ridx, rval);
|
|
421
|
+
if ( n > 0 && ca_objmask_answers(ca, "mask_sync_addrs") ) {
|
|
422
|
+
volatile VALUE raddrs, rdata;
|
|
423
|
+
ca_size_t dim1[1] = { n };
|
|
424
|
+
for ( i = 0; i < n; i++ ) {
|
|
425
|
+
c[addrs[i]] = bits[i] ? 1 : 0;
|
|
218
426
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
427
|
+
raddrs = ca_object_wrap_transient(CA_SIZE, sizeof(ca_size_t),
|
|
428
|
+
1, dim1, addrs, CA_XFER_PUT);
|
|
429
|
+
rdata = ca_object_wrap_transient(CA_BOOLEAN, 1, 1, dim1, (void *) bits,
|
|
430
|
+
CA_XFER_PUT);
|
|
431
|
+
{
|
|
432
|
+
VALUE args[2];
|
|
433
|
+
args[0] = raddrs;
|
|
434
|
+
args[1] = rdata;
|
|
435
|
+
ca_object_call_transient(ca->array, "mask_sync_addrs", 2, args, 2, args);
|
|
223
436
|
}
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
if ( ca_objmask_answers(ca, "mask_sync_data") ) {
|
|
440
|
+
ca_objmask_refresh(ca);
|
|
441
|
+
}
|
|
442
|
+
for ( i = 0; i < n; i++ ) {
|
|
443
|
+
c[addrs[i]] = bits[i] ? 1 : 0;
|
|
224
444
|
}
|
|
445
|
+
ca_objmask_push(ca);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/* Open: the cache is published in ptr, and it is the mask until the sync
|
|
449
|
+
hands it over. The first attach reads the mask in; an allocate does
|
|
450
|
+
not, since whoever allocates writes every cell. */
|
|
451
|
+
static void
|
|
452
|
+
ca_objmask_open (CAObjectMask *ca, int refresh)
|
|
453
|
+
{
|
|
454
|
+
if ( ca->holds == 0 ) {
|
|
455
|
+
if ( refresh ) {
|
|
456
|
+
ca_objmask_refresh(ca);
|
|
457
|
+
}
|
|
458
|
+
ca->ptr = ca->cache;
|
|
459
|
+
}
|
|
460
|
+
ca->holds++;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
static void
|
|
464
|
+
ca_objmask_func_allocate (void *ap)
|
|
465
|
+
{
|
|
466
|
+
ca_objmask_open((CAObjectMask *) ap, 0);
|
|
225
467
|
}
|
|
226
468
|
|
|
227
469
|
static void
|
|
228
470
|
ca_objmask_func_attach (void *ap)
|
|
471
|
+
{
|
|
472
|
+
ca_objmask_open((CAObjectMask *) ap, 1);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
static void
|
|
476
|
+
ca_objmask_func_sync (void *ap)
|
|
229
477
|
{
|
|
230
478
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
231
|
-
if (
|
|
232
|
-
|
|
233
|
-
1, ca_objmask_mask_data(ca));
|
|
479
|
+
if ( ca->ptr ) {
|
|
480
|
+
ca_objmask_push(ca);
|
|
234
481
|
}
|
|
235
482
|
}
|
|
236
483
|
|
|
237
|
-
void
|
|
238
|
-
|
|
484
|
+
static void
|
|
485
|
+
ca_objmask_func_detach (void *ap)
|
|
239
486
|
{
|
|
240
487
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
241
|
-
if (
|
|
242
|
-
|
|
243
|
-
1, ca_objmask_mask_data(ca));
|
|
488
|
+
if ( ca->holds > 0 && --ca->holds == 0 ) {
|
|
489
|
+
ca->ptr = NULL;
|
|
244
490
|
}
|
|
245
491
|
}
|
|
246
492
|
|
|
@@ -248,83 +494,76 @@ static void
|
|
|
248
494
|
ca_objmask_func_xfer_all (void *ap, void *data, int dir)
|
|
249
495
|
{
|
|
250
496
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
497
|
+
size_t len = (size_t) ca->elements * (size_t) ca->bytes;
|
|
251
498
|
if ( dir == CA_XFER_GET ) {
|
|
252
|
-
if (
|
|
253
|
-
|
|
254
|
-
ca->ptr = (char *) data;
|
|
255
|
-
rb_funcall(ca->array, rb_intern("mask_copy_data"),
|
|
256
|
-
1, ca_objmask_mask_data(ca));
|
|
257
|
-
ca->ptr = ptr0;
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
ca_array_func_xfer_all(ca, data, CA_XFER_GET);
|
|
499
|
+
if ( ! ca->ptr ) {
|
|
500
|
+
ca_objmask_refresh(ca);
|
|
261
501
|
}
|
|
502
|
+
memcpy(data, ca->cache, len);
|
|
262
503
|
}
|
|
263
504
|
else {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
ca
|
|
267
|
-
rb_funcall(ca->array, rb_intern("mask_sync_data"),
|
|
268
|
-
1, ca_objmask_mask_data(ca));
|
|
269
|
-
ca->ptr = ptr0;
|
|
270
|
-
}
|
|
271
|
-
else {
|
|
272
|
-
ca_array_func_xfer_all(ca, data, CA_XFER_PUT);
|
|
505
|
+
memcpy(ca->cache, data, len);
|
|
506
|
+
if ( ! ca->ptr ) {
|
|
507
|
+
ca_objmask_push(ca);
|
|
273
508
|
}
|
|
274
509
|
}
|
|
275
510
|
}
|
|
276
511
|
|
|
277
|
-
void
|
|
278
|
-
|
|
512
|
+
static void
|
|
513
|
+
ca_objmask_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
514
|
+
void *data, int dir)
|
|
279
515
|
{
|
|
280
516
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
517
|
+
boolean8_t *c = (boolean8_t *) ca->cache;
|
|
518
|
+
boolean8_t *d = (boolean8_t *) data;
|
|
519
|
+
ca_size_t i;
|
|
520
|
+
if ( ca->ptr ) {
|
|
521
|
+
for ( i = 0; i < n; i++ ) {
|
|
522
|
+
if ( dir == CA_XFER_GET ) { d[i] = c[addrs[i]]; }
|
|
523
|
+
else { c[addrs[i]] = d[i] ? 1 : 0; }
|
|
524
|
+
}
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
if ( dir == CA_XFER_GET ) {
|
|
528
|
+
ca_objmask_get_cells(ca, n, addrs, d);
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
ca_objmask_put_cells(ca, n, addrs, d);
|
|
285
532
|
}
|
|
286
533
|
}
|
|
287
534
|
|
|
288
535
|
static void
|
|
289
536
|
ca_objmask_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
290
537
|
{
|
|
291
|
-
|
|
538
|
+
ca_size_t addr = ca_index2addr((CArray *) ap, idx);
|
|
539
|
+
ca_objmask_func_xfer_addrs(ap, 1, &addr, data, dir);
|
|
292
540
|
}
|
|
293
541
|
|
|
294
|
-
/* Forward declaration: ca_object_wrap_transient (defined further down,
|
|
295
|
-
near the data-side xfer functions). */
|
|
296
|
-
static VALUE
|
|
297
|
-
ca_object_wrap_transient (int8_t data_type, ca_size_t bytes,
|
|
298
|
-
int8_t ndim, ca_size_t *dim, void *data, int dir);
|
|
299
|
-
|
|
300
|
-
/* Mask parallel of the bulk-addrs path. When `mask_copy_addrs` /
|
|
301
|
-
`mask_sync_addrs` is defined, 1-call bulk dispatch; else per-cell loop. */
|
|
302
542
|
static void
|
|
303
|
-
|
|
304
|
-
void *data, int dir)
|
|
543
|
+
ca_objmask_func_fill_data (void *ap, void *val)
|
|
305
544
|
{
|
|
306
545
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if ( n > 0 && rb_obj_respond_to(ca->array, mid, Qtrue) ) {
|
|
311
|
-
volatile VALUE raddrs, rdata;
|
|
312
|
-
ca_size_t dim1[1] = { n };
|
|
313
|
-
raddrs = ca_object_wrap_transient(CA_SIZE, sizeof(ca_size_t),
|
|
314
|
-
1, dim1, addrs, CA_XFER_PUT);
|
|
315
|
-
rdata = ca_object_wrap_transient(ca->data_type, ca->bytes,
|
|
316
|
-
1, dim1, data, dir);
|
|
317
|
-
rb_funcall(ca->array, mid, 2, raddrs, rdata);
|
|
546
|
+
boolean8_t bit = *(boolean8_t *) val ? 1 : 0;
|
|
547
|
+
memset(ca->cache, bit, (size_t) ca->elements);
|
|
548
|
+
if ( ca->ptr ) {
|
|
318
549
|
return;
|
|
319
550
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
ca_size_t i;
|
|
324
|
-
for ( i = 0; i < n; i++ ) {
|
|
325
|
-
ca_objmask_xfer_addr_one(ca, addrs[i], d + i * ca->bytes, dir);
|
|
326
|
-
}
|
|
551
|
+
if ( ca_objmask_answers(ca, "mask_fill_data") ) {
|
|
552
|
+
rb_funcall(ca->array, rb_intern("mask_fill_data"), 1, INT2NUM(bit));
|
|
553
|
+
return;
|
|
327
554
|
}
|
|
555
|
+
ca_objmask_push(ca);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
static void
|
|
559
|
+
ca_objmask_func_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *val)
|
|
560
|
+
{
|
|
561
|
+
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
562
|
+
volatile VALUE hold = 0;
|
|
563
|
+
boolean8_t *bits = ALLOCV_N(boolean8_t, hold, n > 0 ? n : 1);
|
|
564
|
+
memset(bits, *(boolean8_t *) val ? 1 : 0, (size_t) n);
|
|
565
|
+
ca_objmask_func_xfer_addrs(ca, n, addrs, bits, CA_XFER_PUT);
|
|
566
|
+
ALLOCV_END(hold);
|
|
328
567
|
}
|
|
329
568
|
|
|
330
569
|
/* Mask parallel of the partial-region path. Same per-axis index-step
|
|
@@ -335,6 +574,7 @@ static void
|
|
|
335
574
|
ca_objmask_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
336
575
|
ca_size_t *strides, void *data, int dir)
|
|
337
576
|
{
|
|
577
|
+
if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
|
|
338
578
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
339
579
|
int8_t ndim = ca->ndim;
|
|
340
580
|
ca_size_t native[CA_RANK_MAX], steps[CA_RANK_MAX], idx[CA_RANK_MAX];
|
|
@@ -351,7 +591,8 @@ ca_objmask_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
351
591
|
|
|
352
592
|
if ( n == 0 ) return;
|
|
353
593
|
|
|
354
|
-
if (
|
|
594
|
+
if ( ! ca->ptr && ca_objmask_answers(ca, dir == CA_XFER_GET ? "mask_copy_block"
|
|
595
|
+
: "mask_sync_block") ) {
|
|
355
596
|
/* The request is over the view's addresses, so a transposed / flat
|
|
356
597
|
request is legal; the per-axis copy_block dispatch below would
|
|
357
598
|
misread it. See ca_xfer_stride_request_is_axis_box (carray.h). */
|
|
@@ -372,7 +613,15 @@ ca_objmask_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
372
613
|
}
|
|
373
614
|
rdata = ca_object_wrap_transient(ca->data_type, ca->bytes,
|
|
374
615
|
ndim, counts, data, dir);
|
|
375
|
-
|
|
616
|
+
{
|
|
617
|
+
VALUE args[4];
|
|
618
|
+
args[0] = rstarts;
|
|
619
|
+
args[1] = rcounts;
|
|
620
|
+
args[2] = rsteps;
|
|
621
|
+
args[3] = rdata;
|
|
622
|
+
ca_object_call_transient(ca->array, rb_id2name(mid_block),
|
|
623
|
+
4, args, 1, args + 3);
|
|
624
|
+
}
|
|
376
625
|
return;
|
|
377
626
|
}
|
|
378
627
|
}
|
|
@@ -390,15 +639,27 @@ ca_objmask_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
390
639
|
ALLOCV_END(holder);
|
|
391
640
|
}
|
|
392
641
|
|
|
642
|
+
/* A mask copied by dup holds its own bits, and frees them. */
|
|
643
|
+
static void
|
|
644
|
+
ca_objmask_free (void *ap)
|
|
645
|
+
{
|
|
646
|
+
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
647
|
+
if ( ca != NULL && NIL_P(ca->array) && ca->cache ) {
|
|
648
|
+
xfree(ca->cache);
|
|
649
|
+
ca->cache = NULL;
|
|
650
|
+
}
|
|
651
|
+
free_ca_wrap(ap);
|
|
652
|
+
}
|
|
653
|
+
|
|
393
654
|
static ca_operation_function_t ca_objmask_func = {
|
|
394
655
|
-1, /* CA_OBJ_OBJECT_MASK */
|
|
395
656
|
CA_REAL_ARRAY,
|
|
396
|
-
|
|
657
|
+
ca_objmask_free,
|
|
397
658
|
ca_objmask_func_clone,
|
|
398
|
-
|
|
659
|
+
ca_objmask_func_allocate,
|
|
399
660
|
ca_objmask_func_attach,
|
|
400
661
|
ca_objmask_func_sync,
|
|
401
|
-
|
|
662
|
+
ca_objmask_func_detach,
|
|
402
663
|
ca_objmask_func_fill_data,
|
|
403
664
|
ca_array_func_create_mask,
|
|
404
665
|
ca_objmask_func_xfer_index,
|
|
@@ -406,6 +667,7 @@ static ca_operation_function_t ca_objmask_func = {
|
|
|
406
667
|
NULL, /* fold_stride: never-fold (callback boundary) */
|
|
407
668
|
ca_objmask_func_xfer_stride,
|
|
408
669
|
ca_objmask_func_xfer_all,
|
|
670
|
+
.fill_addrs = ca_objmask_func_fill_addrs,
|
|
409
671
|
};
|
|
410
672
|
|
|
411
673
|
static VALUE
|
|
@@ -421,11 +683,18 @@ rb_ca_objmask_initialize_copy (VALUE self, VALUE other)
|
|
|
421
683
|
CAObjectMask *ca, *cs;
|
|
422
684
|
|
|
423
685
|
TypedData_Get_Struct(self, CAObjectMask, &caobjectmask_data_type, ca);
|
|
686
|
+
ca_check_uninitialized(ca);
|
|
424
687
|
TypedData_Get_Struct(other, CAObjectMask, &caobjectmask_data_type, cs);
|
|
425
688
|
|
|
689
|
+
/* A copy of the mask as it reads now, with bits of its own: writing to
|
|
690
|
+
it does not reach the CAObject's hooks. */
|
|
426
691
|
carray_setup((CArray *)ca, CA_BOOLEAN, cs->ndim, cs->dim, 0, NULL);
|
|
427
692
|
ca->obj_type = CA_OBJ_OBJECT_MASK;
|
|
428
|
-
ca->array =
|
|
693
|
+
ca->array = Qnil;
|
|
694
|
+
ca->cache = ca->ptr;
|
|
695
|
+
ca->holds = 0;
|
|
696
|
+
ca_copy_data((CArray *) cs, ca->cache);
|
|
697
|
+
ca->ptr = NULL;
|
|
429
698
|
|
|
430
699
|
return self;
|
|
431
700
|
}
|
|
@@ -437,7 +706,6 @@ ca_object_setup (CAObject *ca,
|
|
|
437
706
|
int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes)
|
|
438
707
|
{
|
|
439
708
|
ca_size_t elements;
|
|
440
|
-
double length;
|
|
441
709
|
int8_t i;
|
|
442
710
|
|
|
443
711
|
/* check arguments */
|
|
@@ -449,16 +717,7 @@ ca_object_setup (CAObject *ca,
|
|
|
449
717
|
|
|
450
718
|
/* calculate total number of elements */
|
|
451
719
|
|
|
452
|
-
elements =
|
|
453
|
-
length = bytes;
|
|
454
|
-
for (i=0; i<ndim; i++) {
|
|
455
|
-
elements *= dim[i];
|
|
456
|
-
length *= dim[i];
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
if ( length > CA_LENGTH_MAX ) {
|
|
460
|
-
rb_raise(rb_eRuntimeError, "too large byte length");
|
|
461
|
-
}
|
|
720
|
+
elements = ca_shape_elements(ndim, dim, bytes);
|
|
462
721
|
|
|
463
722
|
ca->obj_type = CA_OBJ_OBJECT;
|
|
464
723
|
ca->data_type = data_type;
|
|
@@ -519,6 +778,17 @@ ca_object_func_clone (void *ap)
|
|
|
519
778
|
#define ca_object_func_ptr_at_addr ca_array_func_ptr_at_addr
|
|
520
779
|
#define ca_object_func_ptr_at_index ca_array_func_ptr_at_index
|
|
521
780
|
|
|
781
|
+
/* The bytes of this array's mask. A fetcher that answers UNDEF marks the
|
|
782
|
+
cell there, whether or not the mask is open. */
|
|
783
|
+
static boolean8_t *
|
|
784
|
+
ca_object_mask_bytes (CAObject *ca)
|
|
785
|
+
{
|
|
786
|
+
if ( ca->mask->obj_type == CA_OBJ_OBJECT_MASK ) {
|
|
787
|
+
return (boolean8_t *) ((CAObjectMask *) ca->mask)->cache;
|
|
788
|
+
}
|
|
789
|
+
return (boolean8_t *) ca->mask->ptr;
|
|
790
|
+
}
|
|
791
|
+
|
|
522
792
|
/* per-cell cores: the addr- and index-primary Ruby-callback bridge logic,
|
|
523
793
|
direction-unified. The fetch_* / store_* slots below are thin
|
|
524
794
|
forwarders onto these. */
|
|
@@ -532,18 +802,15 @@ ca_object_xfer_addr_one (CAObject *ca, ca_size_t addr, void *ptr, int dir)
|
|
|
532
802
|
raddr = SIZE2NUM(addr);
|
|
533
803
|
rval = rb_funcall(ca->self, rb_intern("fetch_addr"), 1, raddr);
|
|
534
804
|
if ( rval == CA_UNDEF ) {
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
ca_create_mask(ca);
|
|
538
|
-
}
|
|
539
|
-
*((boolean8_t*)ca->mask->ptr + addr) = 1;
|
|
805
|
+
ca_create_mask(ca);
|
|
806
|
+
ca_object_mask_bytes(ca)[addr] = 1;
|
|
540
807
|
if ( ca->data_type == CA_OBJECT ) {
|
|
541
808
|
rb_ca_obj2ptr(ca->self, INT2NUM(0), ptr);
|
|
542
809
|
}
|
|
543
810
|
}
|
|
544
811
|
else {
|
|
545
812
|
if ( ca_has_mask(ca) ) {
|
|
546
|
-
|
|
813
|
+
ca_object_mask_bytes(ca)[addr] = 0;
|
|
547
814
|
}
|
|
548
815
|
rb_ca_obj2ptr(ca->self, rval, ptr);
|
|
549
816
|
}
|
|
@@ -557,18 +824,15 @@ ca_object_xfer_addr_one (CAObject *ca, ca_size_t addr, void *ptr, int dir)
|
|
|
557
824
|
}
|
|
558
825
|
rval = rb_funcall(ca->self, rb_intern("fetch_index"), 1, ridx);
|
|
559
826
|
if ( rval == CA_UNDEF ) {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
ca_create_mask(ca);
|
|
563
|
-
}
|
|
564
|
-
*((boolean8_t*)ca->mask->ptr + ca_index2addr(ca->mask, idx)) = 1;
|
|
827
|
+
ca_create_mask(ca);
|
|
828
|
+
ca_object_mask_bytes(ca)[ca_index2addr(ca->mask, idx)] = 1;
|
|
565
829
|
if ( ca->data_type == CA_OBJECT ) {
|
|
566
830
|
rb_ca_obj2ptr(ca->self, INT2NUM(0), ptr);
|
|
567
831
|
}
|
|
568
832
|
}
|
|
569
833
|
else {
|
|
570
834
|
if ( ca_has_mask(ca) ) {
|
|
571
|
-
|
|
835
|
+
ca_object_mask_bytes(ca)[ca_index2addr(ca->mask, idx)] = 0;
|
|
572
836
|
}
|
|
573
837
|
rb_ca_obj2ptr(ca->self, rval, ptr);
|
|
574
838
|
}
|
|
@@ -606,18 +870,15 @@ ca_object_xfer_index_one (CAObject *ca, ca_size_t *idx, void *ptr, int dir)
|
|
|
606
870
|
}
|
|
607
871
|
rval = rb_funcall(ca->self, rb_intern("fetch_index"), 1, ridx);
|
|
608
872
|
if ( rval == CA_UNDEF ) {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
ca_create_mask(ca);
|
|
612
|
-
}
|
|
613
|
-
*((boolean8_t*)ca->mask->ptr + ca_index2addr(ca->mask, idx)) = 1;
|
|
873
|
+
ca_create_mask(ca);
|
|
874
|
+
ca_object_mask_bytes(ca)[ca_index2addr(ca->mask, idx)] = 1;
|
|
614
875
|
if ( ca->data_type == CA_OBJECT ) {
|
|
615
876
|
rb_ca_obj2ptr(ca->self, INT2NUM(0), ptr);
|
|
616
877
|
}
|
|
617
878
|
}
|
|
618
879
|
else {
|
|
619
880
|
if ( ca_has_mask(ca) ) {
|
|
620
|
-
|
|
881
|
+
ca_object_mask_bytes(ca)[ca_index2addr(ca->mask, idx)] = 0;
|
|
621
882
|
}
|
|
622
883
|
rb_ca_obj2ptr(ca->self, rval, ptr);
|
|
623
884
|
}
|
|
@@ -627,18 +888,15 @@ ca_object_xfer_index_one (CAObject *ca, ca_size_t *idx, void *ptr, int dir)
|
|
|
627
888
|
raddr = SIZE2NUM(addr);
|
|
628
889
|
rval = rb_funcall(ca->self, rb_intern("fetch_addr"), 1, raddr);
|
|
629
890
|
if ( rval == CA_UNDEF ) {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
ca_create_mask(ca);
|
|
633
|
-
}
|
|
634
|
-
*((boolean8_t*)ca->mask->ptr + addr) = 1;
|
|
891
|
+
ca_create_mask(ca);
|
|
892
|
+
ca_object_mask_bytes(ca)[addr] = 1;
|
|
635
893
|
if ( ca->data_type == CA_OBJECT ) {
|
|
636
894
|
rb_ca_obj2ptr(ca->self, INT2NUM(0), ptr);
|
|
637
895
|
}
|
|
638
896
|
}
|
|
639
897
|
else {
|
|
640
898
|
if ( ca_has_mask(ca) ) {
|
|
641
|
-
|
|
899
|
+
ca_object_mask_bytes(ca)[addr] = 0;
|
|
642
900
|
}
|
|
643
901
|
rb_ca_obj2ptr(ca->self, rval, ptr);
|
|
644
902
|
}
|
|
@@ -697,11 +955,8 @@ static void
|
|
|
697
955
|
ca_object_dispatch_copy (CAObject *ca, void *ptr)
|
|
698
956
|
{
|
|
699
957
|
if ( rb_obj_respond_to(ca->self, rb_intern("copy_data"), Qtrue) ) {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
rb_funcall(ca->self, rb_intern("copy_data"),
|
|
703
|
-
1, rb_ivar_get(ca->self, rb_intern("__data__")));
|
|
704
|
-
ca->data->ptr = ptr0;
|
|
958
|
+
ca_object_call_lending(&ca->data->ptr, ptr, ca->self, "copy_data",
|
|
959
|
+
ca_object_data_of, ca);
|
|
705
960
|
}
|
|
706
961
|
else {
|
|
707
962
|
ca_size_t addr;
|
|
@@ -716,11 +971,8 @@ static void
|
|
|
716
971
|
ca_object_dispatch_sync (CAObject *ca, void *ptr)
|
|
717
972
|
{
|
|
718
973
|
if ( rb_obj_respond_to(ca->self, rb_intern("sync_data"), Qtrue) ) {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
rb_funcall(ca->self, rb_intern("sync_data"),
|
|
722
|
-
1, rb_ivar_get(ca->self, rb_intern("__data__")));
|
|
723
|
-
ca->data->ptr = ptr0;
|
|
974
|
+
ca_object_call_lending(&ca->data->ptr, ptr, ca->self, "sync_data",
|
|
975
|
+
ca_object_data_of, ca);
|
|
724
976
|
}
|
|
725
977
|
else {
|
|
726
978
|
ca_size_t addr;
|
|
@@ -738,6 +990,14 @@ ca_object_dispatch_fill (CAObject *ca, void *ptr)
|
|
|
738
990
|
volatile VALUE rval = rb_ca_ptr2obj(ca->self, ptr);
|
|
739
991
|
rb_funcall(ca->self, rb_intern("fill_data"), 1, rval);
|
|
740
992
|
}
|
|
993
|
+
else if ( rb_obj_respond_to(ca->self, rb_intern("fill_block"), Qtrue)
|
|
994
|
+
|| rb_obj_respond_to(ca->self, rb_intern("fill_addrs"), Qtrue) ) {
|
|
995
|
+
/* An author who wrote the region slots but not fill_data would otherwise
|
|
996
|
+
get the per-cell default for the one request that is easiest to batch.
|
|
997
|
+
Hand the whole extent to the region path, which reaches `fill_block` in
|
|
998
|
+
one call or `fill_addrs` in address windows. */
|
|
999
|
+
ca_fill_stride_whole(ca, ptr);
|
|
1000
|
+
}
|
|
741
1001
|
else {
|
|
742
1002
|
ca_size_t addr;
|
|
743
1003
|
for ( addr = 0; addr < ca->elements; addr++ ) {
|
|
@@ -770,10 +1030,7 @@ ca_object_func_attach (void *ap)
|
|
|
770
1030
|
ca->ptr = ca->data->ptr;
|
|
771
1031
|
ca_object_dispatch_copy(ca, ca->ptr);
|
|
772
1032
|
if ( ca_has_mask(ca->data) ) {
|
|
773
|
-
|
|
774
|
-
if ( ! ca->mask ) {
|
|
775
|
-
ca_create_mask(ca);
|
|
776
|
-
}
|
|
1033
|
+
ca_create_mask(ca);
|
|
777
1034
|
}
|
|
778
1035
|
}
|
|
779
1036
|
|
|
@@ -814,7 +1071,8 @@ ca_object_func_detach (void *ap)
|
|
|
814
1071
|
[n] for addrs) before invoking copy_block / sync_block / copy_addrs /
|
|
815
1072
|
sync_addrs. Lifecycle: buffer is owned by the slot caller; the wrapper
|
|
816
1073
|
installs free_ca_wrap as dfree, so the underlying ptr is NOT freed when
|
|
817
|
-
the wrapper is GC'd.
|
|
1074
|
+
the wrapper is GC'd. Call the hook through ca_object_call_transient,
|
|
1075
|
+
which takes the buffer back from the wrapper when the hook returns.
|
|
818
1076
|
|
|
819
1077
|
Object data_type GC safety: for GET (dir == CA_XFER_GET) the buffer may be
|
|
820
1078
|
uninitialized garbage on entry, so we INT2NUM(0) zero-fill before
|
|
@@ -872,7 +1130,12 @@ ca_object_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
|
872
1130
|
1, dim1, addrs, CA_XFER_PUT);
|
|
873
1131
|
rdata = ca_object_wrap_transient(ca->data_type, ca->bytes,
|
|
874
1132
|
1, dim1, data, dir);
|
|
875
|
-
|
|
1133
|
+
{
|
|
1134
|
+
VALUE args[2];
|
|
1135
|
+
args[0] = raddrs;
|
|
1136
|
+
args[1] = rdata;
|
|
1137
|
+
ca_object_call_transient(ca->self, rb_id2name(mid), 2, args, 2, args);
|
|
1138
|
+
}
|
|
876
1139
|
return;
|
|
877
1140
|
}
|
|
878
1141
|
|
|
@@ -909,6 +1172,7 @@ static void
|
|
|
909
1172
|
ca_object_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
910
1173
|
ca_size_t *strides, void *data, int dir)
|
|
911
1174
|
{
|
|
1175
|
+
if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
|
|
912
1176
|
CAObject *ca = (CAObject *) ap;
|
|
913
1177
|
int8_t ndim;
|
|
914
1178
|
ca_size_t native[CA_RANK_MAX], steps[CA_RANK_MAX], idx[CA_RANK_MAX];
|
|
@@ -961,7 +1225,15 @@ ca_object_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
961
1225
|
}
|
|
962
1226
|
rdata = ca_object_wrap_transient(ca->data_type, ca->bytes,
|
|
963
1227
|
ndim, counts, data, dir);
|
|
964
|
-
|
|
1228
|
+
{
|
|
1229
|
+
VALUE args[4];
|
|
1230
|
+
args[0] = rstarts;
|
|
1231
|
+
args[1] = rcounts;
|
|
1232
|
+
args[2] = rsteps;
|
|
1233
|
+
args[3] = rdata;
|
|
1234
|
+
ca_object_call_transient(ca->self, rb_id2name(mid_block),
|
|
1235
|
+
4, args, 1, args + 3);
|
|
1236
|
+
}
|
|
965
1237
|
return;
|
|
966
1238
|
}
|
|
967
1239
|
}
|
|
@@ -1032,7 +1304,12 @@ ca_object_func_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
|
|
|
1032
1304
|
raddrs = ca_object_wrap_transient(CA_SIZE, sizeof(ca_size_t),
|
|
1033
1305
|
1, dim1, addrs, CA_XFER_PUT);
|
|
1034
1306
|
rval = rb_ca_ptr2obj(ca->self, ptr);
|
|
1035
|
-
|
|
1307
|
+
{
|
|
1308
|
+
VALUE args[2];
|
|
1309
|
+
args[0] = raddrs;
|
|
1310
|
+
args[1] = rval;
|
|
1311
|
+
ca_object_call_transient(ca->self, rb_id2name(mid), 2, args, 1, args);
|
|
1312
|
+
}
|
|
1036
1313
|
return;
|
|
1037
1314
|
}
|
|
1038
1315
|
|
|
@@ -1100,31 +1377,32 @@ ca_object_func_create_mask (void *ap)
|
|
|
1100
1377
|
CAObject *ca = (CAObject *) ap;
|
|
1101
1378
|
volatile VALUE rmask;
|
|
1102
1379
|
if ( ca_is_face(ca) ) {
|
|
1103
|
-
/* Face: the mask
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
ca_update_mask(ca->parent);
|
|
1107
|
-
if ( ! ca->parent->mask ) {
|
|
1108
|
-
ca_create_mask(ca->parent);
|
|
1109
|
-
}
|
|
1110
|
-
ca->mask = (CArray *) ca_refer_new(ca->parent->mask,
|
|
1111
|
-
CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
|
|
1380
|
+
/* Face: storage is the parent, so the mask is the parent's (as for the
|
|
1381
|
+
C-level Faces), not the internal __data__'s. */
|
|
1382
|
+
ca_view_func_create_mask(ca);
|
|
1112
1383
|
return;
|
|
1113
1384
|
}
|
|
1114
1385
|
if ( rb_obj_respond_to(ca->self, rb_intern("create_mask"), Qtrue) ) {
|
|
1115
1386
|
rb_funcall(ca->self, rb_intern("create_mask"), 0);
|
|
1116
1387
|
}
|
|
1117
1388
|
else {
|
|
1118
|
-
rb_raise(
|
|
1389
|
+
rb_raise(rb_eTypeError, "can't create mask for CAObject");
|
|
1119
1390
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1391
|
+
ca_create_mask(ca->data);
|
|
1392
|
+
{
|
|
1393
|
+
CAObjectMask *cm = ca_objmask_new(ca->self, ca->ndim, ca->dim);
|
|
1394
|
+
cm->cache = ca->data->mask->ptr;
|
|
1395
|
+
ca->mask = (CArray *) cm;
|
|
1396
|
+
rmask = ca_wrap_struct(ca->mask);
|
|
1397
|
+
rb_ivar_set(ca->self, rb_intern("mask"), rmask);
|
|
1398
|
+
/* Made while this array is attached, the mask joins it at its level:
|
|
1399
|
+
ca_create_mask attaches it once more when this returns. */
|
|
1400
|
+
if ( ca->attach > 1 ) {
|
|
1401
|
+
ca_objmask_refresh(cm);
|
|
1402
|
+
cm->ptr = cm->cache;
|
|
1403
|
+
cm->holds = ca->attach - 1;
|
|
1404
|
+
}
|
|
1123
1405
|
}
|
|
1124
|
-
ca->mask = (CArray*) ca_objmask_new(ca->self, ca->ndim, ca->dim);
|
|
1125
|
-
ca->mask->ptr = ca->data->mask->ptr;
|
|
1126
|
-
rmask = ca_wrap_struct(ca->mask);
|
|
1127
|
-
rb_ivar_set(ca->self, rb_intern("mask"), rmask);
|
|
1128
1406
|
}
|
|
1129
1407
|
|
|
1130
1408
|
ca_operation_function_t ca_object_func = {
|
|
@@ -1163,6 +1441,7 @@ rb_ca_object_initialize_copy (VALUE self, VALUE other)
|
|
|
1163
1441
|
CAObject *ca, *cs;
|
|
1164
1442
|
|
|
1165
1443
|
TypedData_Get_Struct(self, CAObject, &caobject_data_type, ca);
|
|
1444
|
+
ca_check_uninitialized(ca);
|
|
1166
1445
|
TypedData_Get_Struct(other, CAObject, &caobject_data_type, cs);
|
|
1167
1446
|
|
|
1168
1447
|
if ( ca_func[CA_OBJ_OBJECT].pool_init ) {
|
|
@@ -1204,20 +1483,21 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1204
1483
|
{
|
|
1205
1484
|
volatile VALUE rtype, rdim, ropt, rbytes = Qnil, rrdonly = Qnil,
|
|
1206
1485
|
rparent = Qnil, rface = Qnil, rstorage = Qnil, rdata,
|
|
1207
|
-
rorderable = Qnil, rcomparable = Qnil;
|
|
1486
|
+
rorderable = Qnil, rcomparable = Qnil, rnumeric = Qnil;
|
|
1208
1487
|
CAObject *ca;
|
|
1209
1488
|
int8_t data_type, ndim;
|
|
1210
1489
|
ca_size_t dim[CA_RANK_MAX];
|
|
1211
1490
|
ca_size_t bytes;
|
|
1212
1491
|
int i;
|
|
1492
|
+
int storage_named = 0; /* :storage given by the caller */
|
|
1213
1493
|
|
|
1214
1494
|
rb_scan_args(argc, argv, "21", (VALUE *) &rtype, (VALUE *) &rdim, (VALUE *) &ropt);
|
|
1215
|
-
rb_scan_options(ropt, "bytes,read_only,parent,face,storage,orderable_storage,comparable_storage",
|
|
1495
|
+
rb_scan_options(ropt, "bytes,read_only,parent,face,storage,orderable_storage,comparable_storage,numeric",
|
|
1216
1496
|
&rbytes, &rrdonly, &rparent, &rface, &rstorage,
|
|
1217
|
-
&rorderable, &rcomparable);
|
|
1497
|
+
&rorderable, &rcomparable, &rnumeric);
|
|
1218
1498
|
|
|
1219
1499
|
if ( ( ! NIL_P(rparent) ) && ( ! rb_obj_is_carray(rparent) ) ) {
|
|
1220
|
-
rb_raise(
|
|
1500
|
+
rb_raise(rb_eTypeError, "option :parent should be a carray");
|
|
1221
1501
|
}
|
|
1222
1502
|
|
|
1223
1503
|
/* :storage is meaningful only under face: true (= it documents the
|
|
@@ -1238,6 +1518,16 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1238
1518
|
"meaningful with face: true");
|
|
1239
1519
|
}
|
|
1240
1520
|
|
|
1521
|
+
if ( ! NIL_P(rnumeric) && ! RTEST(rface) ) {
|
|
1522
|
+
rb_raise(rb_eArgError,
|
|
1523
|
+
"CAObject: :numeric is only meaningful with face: true");
|
|
1524
|
+
}
|
|
1525
|
+
if ( ! NIL_P(rnumeric) && ! NIL_P(rstorage) ) {
|
|
1526
|
+
rb_raise(rb_eArgError,
|
|
1527
|
+
"CAObject: give either :numeric or :storage, not both "
|
|
1528
|
+
"(:storage declares a surface of its own)");
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1241
1531
|
/* face: true requires :parent. Under Face semantics the parent is the
|
|
1242
1532
|
true storage owner and CAObject itself carries the semantic identity.
|
|
1243
1533
|
The declared data_type is the SURFACE (= what dispatch sees);
|
|
@@ -1254,7 +1544,30 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1254
1544
|
|
|
1255
1545
|
rb_ca_guess_type_and_bytes(rtype, rbytes, &data_type, &bytes);
|
|
1256
1546
|
|
|
1547
|
+
/* Without :storage the data_type argument names the storage of a Face.
|
|
1548
|
+
A numeric storage is gated by default: the surface becomes CA_FIXLEN,
|
|
1549
|
+
so arithmetic, math and reductions raise instead of computing on the
|
|
1550
|
+
stored numbers, which the Face exists to give another meaning.
|
|
1551
|
+
numeric: true lets them through. An object or fixlen storage keeps
|
|
1552
|
+
its own data_type: fixlen kernels already raise, and an object cell
|
|
1553
|
+
may not be read as bytes. */
|
|
1554
|
+
storage_named = ! NIL_P(rstorage);
|
|
1555
|
+
if ( RTEST(rface) && NIL_P(rstorage) ) {
|
|
1556
|
+
if ( data_type == CA_OBJECT || data_type == CA_FIXLEN ) {
|
|
1557
|
+
if ( ! NIL_P(rnumeric) ) {
|
|
1558
|
+
rb_raise(rb_eArgError,
|
|
1559
|
+
"CAObject Face: :numeric applies to a numeric storage only "
|
|
1560
|
+
"(the storage is %s)", ca_type_name[data_type]);
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
else if ( ! RTEST(rnumeric) ) {
|
|
1564
|
+
rstorage = INT2NUM(data_type);
|
|
1565
|
+
data_type = CA_FIXLEN;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1257
1569
|
Check_Type(rdim, T_ARRAY);
|
|
1570
|
+
CA_CHECK_RANK(RARRAY_LEN(rdim)); /* before dim[] is filled */
|
|
1258
1571
|
|
|
1259
1572
|
ndim = RARRAY_LEN(rdim);
|
|
1260
1573
|
for (i=0; i<ndim; i++) {
|
|
@@ -1262,6 +1575,7 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1262
1575
|
}
|
|
1263
1576
|
|
|
1264
1577
|
TypedData_Get_Struct(self, CAObject, &caobject_data_type, ca);
|
|
1578
|
+
ca_check_uninitialized(ca);
|
|
1265
1579
|
ca_object_setup(ca, data_type, ndim, dim, bytes);
|
|
1266
1580
|
ca->self = self;
|
|
1267
1581
|
|
|
@@ -1279,17 +1593,11 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1279
1593
|
ca->parent = cp;
|
|
1280
1594
|
rb_ca_set_parent(self, rparent);
|
|
1281
1595
|
|
|
1282
|
-
/* Face mode invariants
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
Numeric Face authors who didn't intend
|
|
1288
|
-
surface/storage to differ.
|
|
1289
|
-
- :storage given → "surface != storage" opted-in:
|
|
1290
|
-
surface is free (= e.g. CA_FIXLEN for
|
|
1291
|
-
NonNumeric Face), :storage must agree with
|
|
1292
|
-
parent.data_type, and bytes must match. */
|
|
1596
|
+
/* Face mode invariants: bytes match the parent's, and the storage
|
|
1597
|
+
(:storage, or the data_type argument when :storage was omitted)
|
|
1598
|
+
is the parent's data_type. The surface is the data_type argument
|
|
1599
|
+
under :storage, CA_FIXLEN for a gated numeric storage (decided
|
|
1600
|
+
above), and the storage itself otherwise. */
|
|
1293
1601
|
if ( RTEST(rface) ) {
|
|
1294
1602
|
if ( bytes != cp->bytes ) {
|
|
1295
1603
|
rb_raise(rb_eTypeError,
|
|
@@ -1298,12 +1606,12 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1298
1606
|
(long long) bytes, (long long) cp->bytes);
|
|
1299
1607
|
}
|
|
1300
1608
|
if ( NIL_P(rstorage) ) {
|
|
1301
|
-
/*
|
|
1609
|
+
/* The data_type argument names the storage. */
|
|
1302
1610
|
if ( cp->data_type != data_type ) {
|
|
1303
1611
|
rb_raise(rb_eTypeError,
|
|
1304
1612
|
"CAObject Face: parent data_type mismatch "
|
|
1305
1613
|
"(declared=%d, parent=%d). Use :storage option to "
|
|
1306
|
-
"
|
|
1614
|
+
"declare a surface that differs from the storage.",
|
|
1307
1615
|
(int) data_type, (int) cp->data_type);
|
|
1308
1616
|
}
|
|
1309
1617
|
}
|
|
@@ -1315,10 +1623,20 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1315
1623
|
&declared_storage, &declared_storage_bytes);
|
|
1316
1624
|
if ( cp->data_type != declared_storage ) {
|
|
1317
1625
|
rb_raise(rb_eTypeError,
|
|
1318
|
-
|
|
1319
|
-
"
|
|
1626
|
+
storage_named
|
|
1627
|
+
? "CAObject Face: :storage mismatch "
|
|
1628
|
+
"(declared=%d, parent.data_type=%d)"
|
|
1629
|
+
: "CAObject Face: parent data_type mismatch "
|
|
1630
|
+
"(declared=%d, parent=%d)",
|
|
1320
1631
|
(int) declared_storage, (int) cp->data_type);
|
|
1321
1632
|
}
|
|
1633
|
+
/* An object cell is a VALUE: reading it under another surface hands
|
|
1634
|
+
out its address, and writing one forges it. */
|
|
1635
|
+
if ( ca_is_object_type(cp) && data_type != CA_OBJECT ) {
|
|
1636
|
+
rb_raise(rb_eTypeError,
|
|
1637
|
+
"CAObject Face: an object storage can't be given "
|
|
1638
|
+
"another surface data_type");
|
|
1639
|
+
}
|
|
1322
1640
|
}
|
|
1323
1641
|
ca_set_flag(ca, CA_FLAG_IS_FACE);
|
|
1324
1642
|
if ( RTEST(rorderable) ) {
|