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/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
|
|
@@ -59,6 +60,15 @@ ca_object_pool_init (void *ap, int8_t ndim)
|
|
|
59
60
|
ca->dim = (ca_size_t *) ca->_pool;
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
/* ca->self is the CAObject's own VALUE, which compaction can move; the
|
|
64
|
+
hooks call back through it, so follow the object to its new slot. */
|
|
65
|
+
static void
|
|
66
|
+
ca_object_compact (void *ap)
|
|
67
|
+
{
|
|
68
|
+
CAObject *ca = (CAObject *) ap;
|
|
69
|
+
ca->self = rb_gc_location(ca->self);
|
|
70
|
+
}
|
|
71
|
+
|
|
62
72
|
const rb_data_type_t caobject_data_type = {
|
|
63
73
|
.parent = &caview_data_type,
|
|
64
74
|
.wrap_struct_name = "CAObject",
|
|
@@ -66,7 +76,7 @@ const rb_data_type_t caobject_data_type = {
|
|
|
66
76
|
.dmark = ca_mark,
|
|
67
77
|
.dfree = ca_free,
|
|
68
78
|
.dsize = ca_object_dsize,
|
|
69
|
-
.dcompact =
|
|
79
|
+
.dcompact = ca_object_compact
|
|
70
80
|
},
|
|
71
81
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
72
82
|
};
|
|
@@ -82,14 +92,32 @@ ca_objectmask_dsize (const void *ap)
|
|
|
82
92
|
return sizeof(CAObjectMask) + ca->ndim * sizeof(ca_size_t);
|
|
83
93
|
}
|
|
84
94
|
|
|
95
|
+
/* The mask reads and writes through its CAObject, and its cache is the
|
|
96
|
+
CAObject's; it keeps the CAObject alive, and follows it when compaction
|
|
97
|
+
moves it. */
|
|
98
|
+
static void
|
|
99
|
+
ca_objmask_mark (void *ap)
|
|
100
|
+
{
|
|
101
|
+
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
102
|
+
rb_gc_mark_movable(ca->array);
|
|
103
|
+
ca_mark(ap);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static void
|
|
107
|
+
ca_objmask_compact (void *ap)
|
|
108
|
+
{
|
|
109
|
+
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
110
|
+
ca->array = rb_gc_location(ca->array);
|
|
111
|
+
}
|
|
112
|
+
|
|
85
113
|
const rb_data_type_t caobjectmask_data_type = {
|
|
86
114
|
.parent = &carray_data_type,
|
|
87
115
|
.wrap_struct_name = "CAObjectMask",
|
|
88
116
|
.function = {
|
|
89
|
-
.dmark =
|
|
117
|
+
.dmark = ca_objmask_mark,
|
|
90
118
|
.dfree = ca_free,
|
|
91
119
|
.dsize = ca_objectmask_dsize,
|
|
92
|
-
.dcompact =
|
|
120
|
+
.dcompact = ca_objmask_compact
|
|
93
121
|
},
|
|
94
122
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
95
123
|
};
|
|
@@ -100,6 +128,7 @@ VALUE rb_cCAObjectMask;
|
|
|
100
128
|
static CAObjectMask *
|
|
101
129
|
ca_objmask_new (VALUE array, int8_t ndim, ca_size_t *dim)
|
|
102
130
|
{
|
|
131
|
+
/* check: the mask takes the CAObject's own shape, already checked */
|
|
103
132
|
CAObjectMask *ca = ALLOC(CAObjectMask);
|
|
104
133
|
/* CA_OBJ_OBJECT_MASK registers no pool_init, so it lives on the legacy
|
|
105
134
|
ALLOC_N path (dim allocated separately, freed via free_ca_wrap's else
|
|
@@ -110,6 +139,8 @@ ca_objmask_new (VALUE array, int8_t ndim, ca_size_t *dim)
|
|
|
110
139
|
ca_wrap_setup_null((CArray *)ca, CA_BOOLEAN, ndim, dim, 0, NULL);
|
|
111
140
|
ca->obj_type = CA_OBJ_OBJECT_MASK;
|
|
112
141
|
ca->array = array;
|
|
142
|
+
ca->cache = NULL;
|
|
143
|
+
ca->holds = 0;
|
|
113
144
|
|
|
114
145
|
return ca;
|
|
115
146
|
}
|
|
@@ -122,125 +153,376 @@ ca_objmask_mask_data (void *ap)
|
|
|
122
153
|
rb_intern("mask"), 0);
|
|
123
154
|
}
|
|
124
155
|
|
|
156
|
+
/* A wrap handed to a hook points at a buffer the caller frees once the
|
|
157
|
+
hook returns. Taking it back leaves an array of no cells: a hook that
|
|
158
|
+
kept it holds something that raises when read, not a pointer into freed
|
|
159
|
+
memory. */
|
|
160
|
+
static char ca_object_no_cells[16];
|
|
161
|
+
|
|
162
|
+
static void
|
|
163
|
+
ca_object_empty_wrap (CArray *w)
|
|
164
|
+
{
|
|
165
|
+
int8_t k;
|
|
166
|
+
/* Not NULL: an entity whose pointer is NULL reads as detached. */
|
|
167
|
+
w->ptr = ca_object_no_cells;
|
|
168
|
+
w->elements = 0;
|
|
169
|
+
for ( k = 0; k < w->ndim; k++ ) {
|
|
170
|
+
w->dim[k] = 0;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* Calls copy_data / sync_data with a wrap of a caller's buffer, shaped as
|
|
175
|
+
the object, and takes the buffer back however the call leaves. The wrap
|
|
176
|
+
shares the object's mask (the data's), and whatever mask it holds after
|
|
177
|
+
the call becomes the data's: a hook that writes masked values masks the
|
|
178
|
+
object's cells. The data points at the buffer for the duration too, for
|
|
179
|
+
a hook that reads the object back while it runs. */
|
|
180
|
+
|
|
181
|
+
typedef struct {
|
|
182
|
+
CAObject *ca;
|
|
183
|
+
char *saved;
|
|
184
|
+
ID mid;
|
|
185
|
+
VALUE wrap;
|
|
186
|
+
} ca_object_lend_t;
|
|
187
|
+
|
|
188
|
+
static VALUE
|
|
189
|
+
ca_object_lend_body (VALUE varg)
|
|
190
|
+
{
|
|
191
|
+
ca_object_lend_t *l = (ca_object_lend_t *) varg;
|
|
192
|
+
return rb_funcall(l->ca->self, l->mid, 1, l->wrap);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
static VALUE
|
|
196
|
+
ca_object_lend_restore (VALUE varg)
|
|
197
|
+
{
|
|
198
|
+
ca_object_lend_t *l = (ca_object_lend_t *) varg;
|
|
199
|
+
CArray *w = (CArray *) DATA_PTR(l->wrap);
|
|
200
|
+
l->ca->data->mask = w->mask;
|
|
201
|
+
w->mask = NULL;
|
|
202
|
+
ca_object_empty_wrap(w);
|
|
203
|
+
l->ca->data->ptr = l->saved;
|
|
204
|
+
return Qnil;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
static void
|
|
208
|
+
ca_object_call_lending (CAObject *ca, void *ptr, const char *mid)
|
|
209
|
+
{
|
|
210
|
+
ca_object_lend_t l;
|
|
211
|
+
CArray *data = ca->data;
|
|
212
|
+
CAWrap *w;
|
|
213
|
+
w = ca_wrap_new(data->data_type, data->ndim, data->dim, data->bytes,
|
|
214
|
+
NULL, (char *) ptr);
|
|
215
|
+
l.wrap = ca_wrap_struct(w);
|
|
216
|
+
w->mask = data->mask;
|
|
217
|
+
l.ca = ca;
|
|
218
|
+
l.saved = data->ptr;
|
|
219
|
+
l.mid = rb_intern(mid);
|
|
220
|
+
data->ptr = (char *) ptr;
|
|
221
|
+
rb_ensure(ca_object_lend_body, (VALUE) &l,
|
|
222
|
+
ca_object_lend_restore, (VALUE) &l);
|
|
223
|
+
RB_GC_GUARD(l.wrap);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/* Calls recv.mid(*argv), where some of argv are transient wraps of a
|
|
227
|
+
caller's buffer (ca_object_wrap_transient), and takes the buffer back
|
|
228
|
+
from each of them however the call leaves. The caller frees its buffer
|
|
229
|
+
when it returns, and a wrap outlives the call: the collector scans the
|
|
230
|
+
machine stack conservatively and still finds it there, and an object
|
|
231
|
+
wrap is marked cell by cell -- through a buffer that is gone. A wrap
|
|
232
|
+
taken back has no cells (ca_object_empty_wrap). */
|
|
233
|
+
|
|
234
|
+
typedef struct {
|
|
235
|
+
VALUE recv;
|
|
236
|
+
ID mid;
|
|
237
|
+
int argc;
|
|
238
|
+
const VALUE *argv;
|
|
239
|
+
int ntrans;
|
|
240
|
+
const VALUE *trans;
|
|
241
|
+
} ca_object_hook_t;
|
|
242
|
+
|
|
243
|
+
static VALUE
|
|
244
|
+
ca_object_hook_body (VALUE varg)
|
|
245
|
+
{
|
|
246
|
+
ca_object_hook_t *h = (ca_object_hook_t *) varg;
|
|
247
|
+
return rb_funcallv(h->recv, h->mid, h->argc, h->argv);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
static VALUE
|
|
251
|
+
ca_object_hook_release (VALUE varg)
|
|
252
|
+
{
|
|
253
|
+
ca_object_hook_t *h = (ca_object_hook_t *) varg;
|
|
254
|
+
int i;
|
|
255
|
+
for ( i = 0; i < h->ntrans; i++ ) {
|
|
256
|
+
ca_object_empty_wrap((CArray *) DATA_PTR(h->trans[i]));
|
|
257
|
+
}
|
|
258
|
+
return Qnil;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
static void
|
|
262
|
+
ca_object_call_transient (VALUE recv, const char *mid,
|
|
263
|
+
int argc, const VALUE *argv,
|
|
264
|
+
int ntrans, const VALUE *trans)
|
|
265
|
+
{
|
|
266
|
+
ca_object_hook_t h;
|
|
267
|
+
h.recv = recv;
|
|
268
|
+
h.mid = rb_intern(mid);
|
|
269
|
+
h.argc = argc;
|
|
270
|
+
h.argv = argv;
|
|
271
|
+
h.ntrans = ntrans;
|
|
272
|
+
h.trans = trans;
|
|
273
|
+
rb_ensure(ca_object_hook_body, (VALUE) &h,
|
|
274
|
+
ca_object_hook_release, (VALUE) &h);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
/* Forward declaration: ca_object_wrap_transient (defined further down,
|
|
280
|
+
near the data-side xfer functions). */
|
|
281
|
+
static VALUE
|
|
282
|
+
ca_object_wrap_transient (int8_t data_type, ca_size_t bytes,
|
|
283
|
+
int8_t ndim, ca_size_t *dim, void *data, int dir);
|
|
284
|
+
|
|
125
285
|
static void *
|
|
126
286
|
ca_objmask_func_clone (void *ap)
|
|
127
287
|
{
|
|
128
288
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
129
|
-
|
|
289
|
+
CAObjectMask *co = ca_objmask_new(ca->array, ca->ndim, ca->dim);
|
|
290
|
+
co->cache = ca->cache;
|
|
291
|
+
return co;
|
|
130
292
|
}
|
|
131
293
|
|
|
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)
|
|
294
|
+
/* Whether the CAObject answers one of the mask hooks. A copy made by dup
|
|
295
|
+
holds its own bits and answers none (array is nil). */
|
|
296
|
+
static int
|
|
297
|
+
ca_objmask_answers (CAObjectMask *ca, const char *mid)
|
|
139
298
|
{
|
|
140
|
-
|
|
299
|
+
return ! NIL_P(ca->array) && rb_obj_respond_to(ca->array, rb_intern(mid), Qtrue);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
static VALUE
|
|
303
|
+
ca_objmask_index_of (CAObjectMask *ca, ca_size_t addr)
|
|
304
|
+
{
|
|
305
|
+
ca_size_t idx[CA_RANK_MAX];
|
|
306
|
+
VALUE ridx;
|
|
141
307
|
int i;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
308
|
+
ca_addr2index((CArray *) ca, addr, idx);
|
|
309
|
+
ridx = rb_ary_new2(ca->ndim);
|
|
310
|
+
for (i=0; i<ca->ndim; i++) {
|
|
311
|
+
rb_ary_store(ridx, i, SIZE2NUM(idx[i]));
|
|
312
|
+
}
|
|
313
|
+
return ridx;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* The bit the per-cell hooks give for addr (1 / 0 / true / false), or -1
|
|
317
|
+
when the object has neither mask_fetch_addr nor mask_fetch_index. */
|
|
318
|
+
static int
|
|
319
|
+
ca_objmask_fetch_one (CAObjectMask *ca, ca_size_t addr)
|
|
320
|
+
{
|
|
321
|
+
volatile VALUE rval;
|
|
322
|
+
if ( ca_objmask_answers(ca, "mask_fetch_addr") ) {
|
|
323
|
+
rval = rb_funcall(ca->array, rb_intern("mask_fetch_addr"), 1, SIZE2NUM(addr));
|
|
324
|
+
}
|
|
325
|
+
else if ( ca_objmask_answers(ca, "mask_fetch_index") ) {
|
|
326
|
+
rval = rb_funcall(ca->array, rb_intern("mask_fetch_index"), 1,
|
|
327
|
+
ca_objmask_index_of(ca, addr));
|
|
163
328
|
}
|
|
164
329
|
else {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
330
|
+
return -1;
|
|
331
|
+
}
|
|
332
|
+
if ( rval == Qtrue || rval == Qfalse ) {
|
|
333
|
+
return RTEST(rval);
|
|
334
|
+
}
|
|
335
|
+
return NUM2INT(rval) != 0;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/* Hands one bit to the per-cell hooks; 0 when the object has neither
|
|
339
|
+
mask_store_addr nor mask_store_index. */
|
|
340
|
+
static int
|
|
341
|
+
ca_objmask_store_one (CAObjectMask *ca, ca_size_t addr, boolean8_t bit)
|
|
342
|
+
{
|
|
343
|
+
if ( ca_objmask_answers(ca, "mask_store_addr") ) {
|
|
344
|
+
rb_funcall(ca->array, rb_intern("mask_store_addr"), 2,
|
|
345
|
+
SIZE2NUM(addr), INT2NUM(bit ? 1 : 0));
|
|
346
|
+
return 1;
|
|
347
|
+
}
|
|
348
|
+
if ( ca_objmask_answers(ca, "mask_store_index") ) {
|
|
349
|
+
rb_funcall(ca->array, rb_intern("mask_store_index"), 2,
|
|
350
|
+
ca_objmask_index_of(ca, addr), INT2NUM(bit ? 1 : 0));
|
|
351
|
+
return 1;
|
|
352
|
+
}
|
|
353
|
+
return 0;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
static int
|
|
357
|
+
ca_objmask_stores_cells (CAObjectMask *ca)
|
|
358
|
+
{
|
|
359
|
+
return ca_objmask_answers(ca, "mask_store_addr") ||
|
|
360
|
+
ca_objmask_answers(ca, "mask_store_index");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* Brings the cache up to date from the hooks that give the mask: the bulk
|
|
364
|
+
one, else the per-cell one. With neither, the cache is the mask. */
|
|
365
|
+
static void
|
|
366
|
+
ca_objmask_refresh (CAObjectMask *ca)
|
|
367
|
+
{
|
|
368
|
+
boolean8_t *c = (boolean8_t *) ca->cache;
|
|
369
|
+
ca_size_t addr;
|
|
370
|
+
int bit;
|
|
371
|
+
if ( ca_objmask_answers(ca, "mask_copy_data") ) {
|
|
372
|
+
rb_funcall(ca->array, rb_intern("mask_copy_data"), 1,
|
|
373
|
+
ca_objmask_mask_data(ca));
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
for ( addr = 0; addr < ca->elements; addr++ ) {
|
|
377
|
+
if ( ( bit = ca_objmask_fetch_one(ca, addr) ) < 0 ) {
|
|
378
|
+
return;
|
|
170
379
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
380
|
+
c[addr] = (boolean8_t) bit;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/* Hands the whole cache to the hooks that take the mask: the bulk one,
|
|
385
|
+
else the per-cell one. */
|
|
386
|
+
static void
|
|
387
|
+
ca_objmask_push (CAObjectMask *ca)
|
|
388
|
+
{
|
|
389
|
+
const boolean8_t *c = (const boolean8_t *) ca->cache;
|
|
390
|
+
ca_size_t addr;
|
|
391
|
+
if ( ca_objmask_answers(ca, "mask_sync_data") ) {
|
|
392
|
+
rb_funcall(ca->array, rb_intern("mask_sync_data"), 1,
|
|
393
|
+
ca_objmask_mask_data(ca));
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
for ( addr = 0; addr < ca->elements; addr++ ) {
|
|
397
|
+
if ( ! ca_objmask_store_one(ca, addr, c[addr]) ) {
|
|
398
|
+
return;
|
|
179
399
|
}
|
|
180
400
|
}
|
|
181
401
|
}
|
|
182
402
|
|
|
403
|
+
/* Reads n bits at addrs while the mask is closed: mask_copy_addrs, else
|
|
404
|
+
the per-cell hooks, else the whole mask brought up to date. */
|
|
183
405
|
static void
|
|
184
|
-
|
|
406
|
+
ca_objmask_get_cells (CAObjectMask *ca, ca_size_t n, ca_size_t *addrs,
|
|
407
|
+
boolean8_t *bits)
|
|
185
408
|
{
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
409
|
+
boolean8_t *c = (boolean8_t *) ca->cache;
|
|
410
|
+
ca_size_t i;
|
|
411
|
+
int bit;
|
|
412
|
+
if ( n > 0 && ca_objmask_answers(ca, "mask_copy_addrs") ) {
|
|
413
|
+
volatile VALUE raddrs, rdata;
|
|
414
|
+
ca_size_t dim1[1] = { n };
|
|
415
|
+
raddrs = ca_object_wrap_transient(CA_SIZE, sizeof(ca_size_t),
|
|
416
|
+
1, dim1, addrs, CA_XFER_PUT);
|
|
417
|
+
rdata = ca_object_wrap_transient(CA_BOOLEAN, 1, 1, dim1, bits,
|
|
418
|
+
CA_XFER_GET);
|
|
419
|
+
{
|
|
420
|
+
VALUE args[2];
|
|
421
|
+
args[0] = raddrs;
|
|
422
|
+
args[1] = rdata;
|
|
423
|
+
ca_object_call_transient(ca->array, "mask_copy_addrs", 2, args, 2, args);
|
|
197
424
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
if ( n > 0 && ( bit = ca_objmask_fetch_one(ca, addrs[0]) ) >= 0 ) {
|
|
428
|
+
c[addrs[0]] = bits[0] = (boolean8_t) bit;
|
|
429
|
+
for ( i = 1; i < n; i++ ) {
|
|
430
|
+
c[addrs[i]] = bits[i] = (boolean8_t) ca_objmask_fetch_one(ca, addrs[i]);
|
|
204
431
|
}
|
|
205
|
-
|
|
206
|
-
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
ca_objmask_refresh(ca);
|
|
435
|
+
for ( i = 0; i < n; i++ ) {
|
|
436
|
+
bits[i] = c[addrs[i]];
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/* Writes n bits at addrs while the mask is closed, and hands them over:
|
|
441
|
+
one by one to the per-cell hooks, as a list to mask_sync_addrs, or else
|
|
442
|
+
the whole mask to mask_sync_data -- brought up to date first, so that
|
|
443
|
+
the cells not written go back as they were. */
|
|
444
|
+
static void
|
|
445
|
+
ca_objmask_put_cells (CAObjectMask *ca, ca_size_t n, ca_size_t *addrs,
|
|
446
|
+
const boolean8_t *bits)
|
|
447
|
+
{
|
|
448
|
+
boolean8_t *c = (boolean8_t *) ca->cache;
|
|
449
|
+
ca_size_t i;
|
|
450
|
+
if ( ca_objmask_stores_cells(ca) ) {
|
|
451
|
+
for ( i = 0; i < n; i++ ) {
|
|
452
|
+
c[addrs[i]] = bits[i] ? 1 : 0;
|
|
453
|
+
ca_objmask_store_one(ca, addrs[i], c[addrs[i]]);
|
|
207
454
|
}
|
|
455
|
+
return;
|
|
208
456
|
}
|
|
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);
|
|
457
|
+
if ( n > 0 && ca_objmask_answers(ca, "mask_sync_addrs") ) {
|
|
458
|
+
volatile VALUE raddrs, rdata;
|
|
459
|
+
ca_size_t dim1[1] = { n };
|
|
460
|
+
for ( i = 0; i < n; i++ ) {
|
|
461
|
+
c[addrs[i]] = bits[i] ? 1 : 0;
|
|
218
462
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
463
|
+
raddrs = ca_object_wrap_transient(CA_SIZE, sizeof(ca_size_t),
|
|
464
|
+
1, dim1, addrs, CA_XFER_PUT);
|
|
465
|
+
rdata = ca_object_wrap_transient(CA_BOOLEAN, 1, 1, dim1, (void *) bits,
|
|
466
|
+
CA_XFER_PUT);
|
|
467
|
+
{
|
|
468
|
+
VALUE args[2];
|
|
469
|
+
args[0] = raddrs;
|
|
470
|
+
args[1] = rdata;
|
|
471
|
+
ca_object_call_transient(ca->array, "mask_sync_addrs", 2, args, 2, args);
|
|
472
|
+
}
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
if ( ca_objmask_answers(ca, "mask_sync_data") ) {
|
|
476
|
+
ca_objmask_refresh(ca);
|
|
477
|
+
}
|
|
478
|
+
for ( i = 0; i < n; i++ ) {
|
|
479
|
+
c[addrs[i]] = bits[i] ? 1 : 0;
|
|
480
|
+
}
|
|
481
|
+
ca_objmask_push(ca);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/* Open: the cache is published in ptr, and it is the mask until the sync
|
|
485
|
+
hands it over. The first attach reads the mask in; an allocate does
|
|
486
|
+
not, since whoever allocates writes every cell. */
|
|
487
|
+
static void
|
|
488
|
+
ca_objmask_open (CAObjectMask *ca, int refresh)
|
|
489
|
+
{
|
|
490
|
+
if ( ca->holds == 0 ) {
|
|
491
|
+
if ( refresh ) {
|
|
492
|
+
ca_objmask_refresh(ca);
|
|
223
493
|
}
|
|
494
|
+
ca->ptr = ca->cache;
|
|
224
495
|
}
|
|
496
|
+
ca->holds++;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
static void
|
|
500
|
+
ca_objmask_func_allocate (void *ap)
|
|
501
|
+
{
|
|
502
|
+
ca_objmask_open((CAObjectMask *) ap, 0);
|
|
225
503
|
}
|
|
226
504
|
|
|
227
505
|
static void
|
|
228
506
|
ca_objmask_func_attach (void *ap)
|
|
507
|
+
{
|
|
508
|
+
ca_objmask_open((CAObjectMask *) ap, 1);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
static void
|
|
512
|
+
ca_objmask_func_sync (void *ap)
|
|
229
513
|
{
|
|
230
514
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
231
|
-
if (
|
|
232
|
-
|
|
233
|
-
1, ca_objmask_mask_data(ca));
|
|
515
|
+
if ( ca->ptr ) {
|
|
516
|
+
ca_objmask_push(ca);
|
|
234
517
|
}
|
|
235
518
|
}
|
|
236
519
|
|
|
237
|
-
void
|
|
238
|
-
|
|
520
|
+
static void
|
|
521
|
+
ca_objmask_func_detach (void *ap)
|
|
239
522
|
{
|
|
240
523
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
241
|
-
if (
|
|
242
|
-
|
|
243
|
-
1, ca_objmask_mask_data(ca));
|
|
524
|
+
if ( ca->holds > 0 && --ca->holds == 0 ) {
|
|
525
|
+
ca->ptr = NULL;
|
|
244
526
|
}
|
|
245
527
|
}
|
|
246
528
|
|
|
@@ -248,83 +530,76 @@ static void
|
|
|
248
530
|
ca_objmask_func_xfer_all (void *ap, void *data, int dir)
|
|
249
531
|
{
|
|
250
532
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
533
|
+
size_t len = (size_t) ca->elements * (size_t) ca->bytes;
|
|
251
534
|
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);
|
|
535
|
+
if ( ! ca->ptr ) {
|
|
536
|
+
ca_objmask_refresh(ca);
|
|
261
537
|
}
|
|
538
|
+
memcpy(data, ca->cache, len);
|
|
262
539
|
}
|
|
263
540
|
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);
|
|
541
|
+
memcpy(ca->cache, data, len);
|
|
542
|
+
if ( ! ca->ptr ) {
|
|
543
|
+
ca_objmask_push(ca);
|
|
273
544
|
}
|
|
274
545
|
}
|
|
275
546
|
}
|
|
276
547
|
|
|
277
|
-
void
|
|
278
|
-
|
|
548
|
+
static void
|
|
549
|
+
ca_objmask_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
550
|
+
void *data, int dir)
|
|
279
551
|
{
|
|
280
552
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
553
|
+
boolean8_t *c = (boolean8_t *) ca->cache;
|
|
554
|
+
boolean8_t *d = (boolean8_t *) data;
|
|
555
|
+
ca_size_t i;
|
|
556
|
+
if ( ca->ptr ) {
|
|
557
|
+
for ( i = 0; i < n; i++ ) {
|
|
558
|
+
if ( dir == CA_XFER_GET ) { d[i] = c[addrs[i]]; }
|
|
559
|
+
else { c[addrs[i]] = d[i] ? 1 : 0; }
|
|
560
|
+
}
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
if ( dir == CA_XFER_GET ) {
|
|
564
|
+
ca_objmask_get_cells(ca, n, addrs, d);
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
ca_objmask_put_cells(ca, n, addrs, d);
|
|
285
568
|
}
|
|
286
569
|
}
|
|
287
570
|
|
|
288
571
|
static void
|
|
289
572
|
ca_objmask_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
290
573
|
{
|
|
291
|
-
|
|
574
|
+
ca_size_t addr = ca_index2addr((CArray *) ap, idx);
|
|
575
|
+
ca_objmask_func_xfer_addrs(ap, 1, &addr, data, dir);
|
|
292
576
|
}
|
|
293
577
|
|
|
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
578
|
static void
|
|
303
|
-
|
|
304
|
-
void *data, int dir)
|
|
579
|
+
ca_objmask_func_fill_data (void *ap, void *val)
|
|
305
580
|
{
|
|
306
581
|
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);
|
|
582
|
+
boolean8_t bit = *(boolean8_t *) val ? 1 : 0;
|
|
583
|
+
memset(ca->cache, bit, (size_t) ca->elements);
|
|
584
|
+
if ( ca->ptr ) {
|
|
318
585
|
return;
|
|
319
586
|
}
|
|
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
|
-
}
|
|
587
|
+
if ( ca_objmask_answers(ca, "mask_fill_data") ) {
|
|
588
|
+
rb_funcall(ca->array, rb_intern("mask_fill_data"), 1, INT2NUM(bit));
|
|
589
|
+
return;
|
|
327
590
|
}
|
|
591
|
+
ca_objmask_push(ca);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
static void
|
|
595
|
+
ca_objmask_func_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *val)
|
|
596
|
+
{
|
|
597
|
+
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
598
|
+
volatile VALUE hold = 0;
|
|
599
|
+
boolean8_t *bits = ALLOCV_N(boolean8_t, hold, n > 0 ? n : 1);
|
|
600
|
+
memset(bits, *(boolean8_t *) val ? 1 : 0, (size_t) n);
|
|
601
|
+
ca_objmask_func_xfer_addrs(ca, n, addrs, bits, CA_XFER_PUT);
|
|
602
|
+
ALLOCV_END(hold);
|
|
328
603
|
}
|
|
329
604
|
|
|
330
605
|
/* Mask parallel of the partial-region path. Same per-axis index-step
|
|
@@ -335,6 +610,7 @@ static void
|
|
|
335
610
|
ca_objmask_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
336
611
|
ca_size_t *strides, void *data, int dir)
|
|
337
612
|
{
|
|
613
|
+
if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
|
|
338
614
|
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
339
615
|
int8_t ndim = ca->ndim;
|
|
340
616
|
ca_size_t native[CA_RANK_MAX], steps[CA_RANK_MAX], idx[CA_RANK_MAX];
|
|
@@ -351,7 +627,8 @@ ca_objmask_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
351
627
|
|
|
352
628
|
if ( n == 0 ) return;
|
|
353
629
|
|
|
354
|
-
if (
|
|
630
|
+
if ( ! ca->ptr && ca_objmask_answers(ca, dir == CA_XFER_GET ? "mask_copy_block"
|
|
631
|
+
: "mask_sync_block") ) {
|
|
355
632
|
/* The request is over the view's addresses, so a transposed / flat
|
|
356
633
|
request is legal; the per-axis copy_block dispatch below would
|
|
357
634
|
misread it. See ca_xfer_stride_request_is_axis_box (carray.h). */
|
|
@@ -372,7 +649,15 @@ ca_objmask_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
372
649
|
}
|
|
373
650
|
rdata = ca_object_wrap_transient(ca->data_type, ca->bytes,
|
|
374
651
|
ndim, counts, data, dir);
|
|
375
|
-
|
|
652
|
+
{
|
|
653
|
+
VALUE args[4];
|
|
654
|
+
args[0] = rstarts;
|
|
655
|
+
args[1] = rcounts;
|
|
656
|
+
args[2] = rsteps;
|
|
657
|
+
args[3] = rdata;
|
|
658
|
+
ca_object_call_transient(ca->array, rb_id2name(mid_block),
|
|
659
|
+
4, args, 1, args + 3);
|
|
660
|
+
}
|
|
376
661
|
return;
|
|
377
662
|
}
|
|
378
663
|
}
|
|
@@ -390,15 +675,27 @@ ca_objmask_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
390
675
|
ALLOCV_END(holder);
|
|
391
676
|
}
|
|
392
677
|
|
|
678
|
+
/* A mask copied by dup holds its own bits, and frees them. */
|
|
679
|
+
static void
|
|
680
|
+
ca_objmask_free (void *ap)
|
|
681
|
+
{
|
|
682
|
+
CAObjectMask *ca = (CAObjectMask *) ap;
|
|
683
|
+
if ( ca != NULL && NIL_P(ca->array) && ca->cache ) {
|
|
684
|
+
xfree(ca->cache);
|
|
685
|
+
ca->cache = NULL;
|
|
686
|
+
}
|
|
687
|
+
free_ca_wrap(ap);
|
|
688
|
+
}
|
|
689
|
+
|
|
393
690
|
static ca_operation_function_t ca_objmask_func = {
|
|
394
691
|
-1, /* CA_OBJ_OBJECT_MASK */
|
|
395
692
|
CA_REAL_ARRAY,
|
|
396
|
-
|
|
693
|
+
ca_objmask_free,
|
|
397
694
|
ca_objmask_func_clone,
|
|
398
|
-
|
|
695
|
+
ca_objmask_func_allocate,
|
|
399
696
|
ca_objmask_func_attach,
|
|
400
697
|
ca_objmask_func_sync,
|
|
401
|
-
|
|
698
|
+
ca_objmask_func_detach,
|
|
402
699
|
ca_objmask_func_fill_data,
|
|
403
700
|
ca_array_func_create_mask,
|
|
404
701
|
ca_objmask_func_xfer_index,
|
|
@@ -406,6 +703,7 @@ static ca_operation_function_t ca_objmask_func = {
|
|
|
406
703
|
NULL, /* fold_stride: never-fold (callback boundary) */
|
|
407
704
|
ca_objmask_func_xfer_stride,
|
|
408
705
|
ca_objmask_func_xfer_all,
|
|
706
|
+
.fill_addrs = ca_objmask_func_fill_addrs,
|
|
409
707
|
};
|
|
410
708
|
|
|
411
709
|
static VALUE
|
|
@@ -421,11 +719,18 @@ rb_ca_objmask_initialize_copy (VALUE self, VALUE other)
|
|
|
421
719
|
CAObjectMask *ca, *cs;
|
|
422
720
|
|
|
423
721
|
TypedData_Get_Struct(self, CAObjectMask, &caobjectmask_data_type, ca);
|
|
722
|
+
ca_check_uninitialized(ca);
|
|
424
723
|
TypedData_Get_Struct(other, CAObjectMask, &caobjectmask_data_type, cs);
|
|
425
724
|
|
|
725
|
+
/* A copy of the mask as it reads now, with bits of its own: writing to
|
|
726
|
+
it does not reach the CAObject's hooks. */
|
|
426
727
|
carray_setup((CArray *)ca, CA_BOOLEAN, cs->ndim, cs->dim, 0, NULL);
|
|
427
728
|
ca->obj_type = CA_OBJ_OBJECT_MASK;
|
|
428
|
-
ca->array =
|
|
729
|
+
ca->array = Qnil;
|
|
730
|
+
ca->cache = ca->ptr;
|
|
731
|
+
ca->holds = 0;
|
|
732
|
+
ca_copy_data((CArray *) cs, ca->cache);
|
|
733
|
+
ca->ptr = NULL;
|
|
429
734
|
|
|
430
735
|
return self;
|
|
431
736
|
}
|
|
@@ -437,28 +742,24 @@ ca_object_setup (CAObject *ca,
|
|
|
437
742
|
int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes)
|
|
438
743
|
{
|
|
439
744
|
ca_size_t elements;
|
|
440
|
-
double length;
|
|
441
745
|
int8_t i;
|
|
442
746
|
|
|
443
747
|
/* check arguments */
|
|
444
748
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
749
|
+
CA_CHECK_DATA_TYPE_GIVEN(data_type);
|
|
750
|
+
CA_CHECK_RANK_GIVEN(ndim);
|
|
751
|
+
CA_CHECK_DIM_GIVEN(ndim, dim);
|
|
752
|
+
CA_CHECK_BYTES_GIVEN(data_type, bytes);
|
|
753
|
+
|
|
754
|
+
/* ca == NULL asks for the checks above only, so that a constructor can
|
|
755
|
+
run them before it allocates. */
|
|
756
|
+
if ( ca == NULL ) {
|
|
757
|
+
return 0;
|
|
758
|
+
}
|
|
449
759
|
|
|
450
760
|
/* calculate total number of elements */
|
|
451
761
|
|
|
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
|
-
}
|
|
762
|
+
elements = ca_shape_elements(ndim, dim, bytes);
|
|
462
763
|
|
|
463
764
|
ca->obj_type = CA_OBJ_OBJECT;
|
|
464
765
|
ca->data_type = data_type;
|
|
@@ -486,7 +787,9 @@ ca_object_setup (CAObject *ca,
|
|
|
486
787
|
static CAObject *
|
|
487
788
|
ca_object_new (int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes)
|
|
488
789
|
{
|
|
489
|
-
CAObject *ca
|
|
790
|
+
CAObject *ca;
|
|
791
|
+
ca_object_setup(NULL, data_type, ndim, dim, bytes);
|
|
792
|
+
ca = (CAObject *) ca_array_alloc(CA_OBJ_OBJECT, ndim);
|
|
490
793
|
ca_object_setup(ca, data_type, ndim, dim, bytes);
|
|
491
794
|
return ca;
|
|
492
795
|
}
|
|
@@ -496,7 +799,12 @@ free_ca_object (void *ap)
|
|
|
496
799
|
{
|
|
497
800
|
CAObject *ca = (CAObject *) ap;
|
|
498
801
|
if ( ca != NULL ) {
|
|
499
|
-
/*
|
|
802
|
+
/* A Face's mask is a view over its parent's mask (made by
|
|
803
|
+
ca_view_func_create_mask) and belongs to this struct. Otherwise
|
|
804
|
+
the mask is a Ruby object held in @mask, and the GC frees it. */
|
|
805
|
+
if ( ca_is_face(ca) ) {
|
|
806
|
+
ca_free(ca->mask);
|
|
807
|
+
}
|
|
500
808
|
if ( ca->_pool ) {
|
|
501
809
|
ca_array_free(ca); /* dim lives in _pool */
|
|
502
810
|
}
|
|
@@ -519,6 +827,30 @@ ca_object_func_clone (void *ap)
|
|
|
519
827
|
#define ca_object_func_ptr_at_addr ca_array_func_ptr_at_addr
|
|
520
828
|
#define ca_object_func_ptr_at_index ca_array_func_ptr_at_index
|
|
521
829
|
|
|
830
|
+
/* The bytes of this array's mask. A fetcher that answers UNDEF marks the
|
|
831
|
+
cell there, whether or not the mask is open. */
|
|
832
|
+
static boolean8_t *
|
|
833
|
+
ca_object_mask_bytes (CAObject *ca)
|
|
834
|
+
{
|
|
835
|
+
if ( ca->mask->obj_type == CA_OBJ_OBJECT_MASK ) {
|
|
836
|
+
return (boolean8_t *) ((CAObjectMask *) ca->mask)->cache;
|
|
837
|
+
}
|
|
838
|
+
return (boolean8_t *) ca->mask->ptr;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
/* Whether the mask of this object comes from its mask_* hooks. Then a
|
|
842
|
+
fetched value says nothing about the mask: a cell the hooks mask stays
|
|
843
|
+
masked when its value is read, and only a fetcher answering UNDEF marks
|
|
844
|
+
one. Without hooks the mask is what the fetches have answered, so a
|
|
845
|
+
value fetched clears the cell. */
|
|
846
|
+
static int
|
|
847
|
+
ca_object_mask_from_hooks (CAObject *ca)
|
|
848
|
+
{
|
|
849
|
+
return rb_obj_respond_to(ca->self, rb_intern("mask_fetch_addr"), Qtrue)
|
|
850
|
+
|| rb_obj_respond_to(ca->self, rb_intern("mask_fetch_index"), Qtrue)
|
|
851
|
+
|| rb_obj_respond_to(ca->self, rb_intern("mask_copy_data"), Qtrue);
|
|
852
|
+
}
|
|
853
|
+
|
|
522
854
|
/* per-cell cores: the addr- and index-primary Ruby-callback bridge logic,
|
|
523
855
|
direction-unified. The fetch_* / store_* slots below are thin
|
|
524
856
|
forwarders onto these. */
|
|
@@ -532,18 +864,15 @@ ca_object_xfer_addr_one (CAObject *ca, ca_size_t addr, void *ptr, int dir)
|
|
|
532
864
|
raddr = SIZE2NUM(addr);
|
|
533
865
|
rval = rb_funcall(ca->self, rb_intern("fetch_addr"), 1, raddr);
|
|
534
866
|
if ( rval == CA_UNDEF ) {
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
ca_create_mask(ca);
|
|
538
|
-
}
|
|
539
|
-
*((boolean8_t*)ca->mask->ptr + addr) = 1;
|
|
867
|
+
ca_create_mask(ca);
|
|
868
|
+
ca_object_mask_bytes(ca)[addr] = 1;
|
|
540
869
|
if ( ca->data_type == CA_OBJECT ) {
|
|
541
870
|
rb_ca_obj2ptr(ca->self, INT2NUM(0), ptr);
|
|
542
871
|
}
|
|
543
872
|
}
|
|
544
873
|
else {
|
|
545
|
-
if ( ca_has_mask(ca) ) {
|
|
546
|
-
|
|
874
|
+
if ( ! ca_object_mask_from_hooks(ca) && ca_has_mask(ca) ) {
|
|
875
|
+
ca_object_mask_bytes(ca)[addr] = 0;
|
|
547
876
|
}
|
|
548
877
|
rb_ca_obj2ptr(ca->self, rval, ptr);
|
|
549
878
|
}
|
|
@@ -557,18 +886,15 @@ ca_object_xfer_addr_one (CAObject *ca, ca_size_t addr, void *ptr, int dir)
|
|
|
557
886
|
}
|
|
558
887
|
rval = rb_funcall(ca->self, rb_intern("fetch_index"), 1, ridx);
|
|
559
888
|
if ( rval == CA_UNDEF ) {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
ca_create_mask(ca);
|
|
563
|
-
}
|
|
564
|
-
*((boolean8_t*)ca->mask->ptr + ca_index2addr(ca->mask, idx)) = 1;
|
|
889
|
+
ca_create_mask(ca);
|
|
890
|
+
ca_object_mask_bytes(ca)[ca_index2addr(ca->mask, idx)] = 1;
|
|
565
891
|
if ( ca->data_type == CA_OBJECT ) {
|
|
566
892
|
rb_ca_obj2ptr(ca->self, INT2NUM(0), ptr);
|
|
567
893
|
}
|
|
568
894
|
}
|
|
569
895
|
else {
|
|
570
|
-
if ( ca_has_mask(ca) ) {
|
|
571
|
-
|
|
896
|
+
if ( ! ca_object_mask_from_hooks(ca) && ca_has_mask(ca) ) {
|
|
897
|
+
ca_object_mask_bytes(ca)[ca_index2addr(ca->mask, idx)] = 0;
|
|
572
898
|
}
|
|
573
899
|
rb_ca_obj2ptr(ca->self, rval, ptr);
|
|
574
900
|
}
|
|
@@ -606,18 +932,15 @@ ca_object_xfer_index_one (CAObject *ca, ca_size_t *idx, void *ptr, int dir)
|
|
|
606
932
|
}
|
|
607
933
|
rval = rb_funcall(ca->self, rb_intern("fetch_index"), 1, ridx);
|
|
608
934
|
if ( rval == CA_UNDEF ) {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
ca_create_mask(ca);
|
|
612
|
-
}
|
|
613
|
-
*((boolean8_t*)ca->mask->ptr + ca_index2addr(ca->mask, idx)) = 1;
|
|
935
|
+
ca_create_mask(ca);
|
|
936
|
+
ca_object_mask_bytes(ca)[ca_index2addr(ca->mask, idx)] = 1;
|
|
614
937
|
if ( ca->data_type == CA_OBJECT ) {
|
|
615
938
|
rb_ca_obj2ptr(ca->self, INT2NUM(0), ptr);
|
|
616
939
|
}
|
|
617
940
|
}
|
|
618
941
|
else {
|
|
619
|
-
if ( ca_has_mask(ca) ) {
|
|
620
|
-
|
|
942
|
+
if ( ! ca_object_mask_from_hooks(ca) && ca_has_mask(ca) ) {
|
|
943
|
+
ca_object_mask_bytes(ca)[ca_index2addr(ca->mask, idx)] = 0;
|
|
621
944
|
}
|
|
622
945
|
rb_ca_obj2ptr(ca->self, rval, ptr);
|
|
623
946
|
}
|
|
@@ -627,18 +950,15 @@ ca_object_xfer_index_one (CAObject *ca, ca_size_t *idx, void *ptr, int dir)
|
|
|
627
950
|
raddr = SIZE2NUM(addr);
|
|
628
951
|
rval = rb_funcall(ca->self, rb_intern("fetch_addr"), 1, raddr);
|
|
629
952
|
if ( rval == CA_UNDEF ) {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
ca_create_mask(ca);
|
|
633
|
-
}
|
|
634
|
-
*((boolean8_t*)ca->mask->ptr + addr) = 1;
|
|
953
|
+
ca_create_mask(ca);
|
|
954
|
+
ca_object_mask_bytes(ca)[addr] = 1;
|
|
635
955
|
if ( ca->data_type == CA_OBJECT ) {
|
|
636
956
|
rb_ca_obj2ptr(ca->self, INT2NUM(0), ptr);
|
|
637
957
|
}
|
|
638
958
|
}
|
|
639
959
|
else {
|
|
640
|
-
if ( ca_has_mask(ca) ) {
|
|
641
|
-
|
|
960
|
+
if ( ! ca_object_mask_from_hooks(ca) && ca_has_mask(ca) ) {
|
|
961
|
+
ca_object_mask_bytes(ca)[addr] = 0;
|
|
642
962
|
}
|
|
643
963
|
rb_ca_obj2ptr(ca->self, rval, ptr);
|
|
644
964
|
}
|
|
@@ -666,8 +986,8 @@ static void
|
|
|
666
986
|
ca_object_func_allocate (void *ap)
|
|
667
987
|
{
|
|
668
988
|
CAObject *ca = (CAObject *) ap;
|
|
669
|
-
/*
|
|
670
|
-
ca->data->ptr = xmalloc(ca_length(ca));
|
|
989
|
+
/* cells: seeded with 0, which a copy_data that skips cells leaves visible */
|
|
990
|
+
ca->data->ptr = xmalloc(ca_length(ca));
|
|
671
991
|
if ( ca_is_object_type(ca->data) ) { /* GC safe */
|
|
672
992
|
VALUE *p = (VALUE *) ca->data->ptr;
|
|
673
993
|
VALUE zero = INT2NUM(0);
|
|
@@ -693,15 +1013,51 @@ ca_object_func_allocate (void *ap)
|
|
|
693
1013
|
arithmetic all work via the slow per-element fallback. The fast bulk
|
|
694
1014
|
path is opt-in by defining copy_data / sync_data / fill_data. */
|
|
695
1015
|
|
|
1016
|
+
/* copy_data of an object whose mask comes from its hooks: the array it is
|
|
1017
|
+
handed must not carry the mask's cache, or a store of its values into it
|
|
1018
|
+
(d[] = src) would clear the cells the hooks mask. It is handed without a
|
|
1019
|
+
mask, and a mask the call makes on it is dropped. */
|
|
1020
|
+
typedef struct {
|
|
1021
|
+
CAObject *ca;
|
|
1022
|
+
void *ptr;
|
|
1023
|
+
CArray *mask;
|
|
1024
|
+
} ca_object_copy_bare_t;
|
|
1025
|
+
|
|
1026
|
+
static VALUE
|
|
1027
|
+
ca_object_copy_bare_body (VALUE arg)
|
|
1028
|
+
{
|
|
1029
|
+
ca_object_copy_bare_t *c = (ca_object_copy_bare_t *) arg;
|
|
1030
|
+
ca_object_call_lending(c->ca, c->ptr, "copy_data");
|
|
1031
|
+
return Qnil;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
static VALUE
|
|
1035
|
+
ca_object_copy_bare_restore (VALUE arg)
|
|
1036
|
+
{
|
|
1037
|
+
ca_object_copy_bare_t *c = (ca_object_copy_bare_t *) arg;
|
|
1038
|
+
CArray *made = c->ca->data->mask;
|
|
1039
|
+
if ( made != NULL && made != c->mask ) {
|
|
1040
|
+
ca_free(made);
|
|
1041
|
+
}
|
|
1042
|
+
c->ca->data->mask = c->mask;
|
|
1043
|
+
return Qnil;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
696
1046
|
static void
|
|
697
1047
|
ca_object_dispatch_copy (CAObject *ca, void *ptr)
|
|
698
1048
|
{
|
|
699
1049
|
if ( rb_obj_respond_to(ca->self, rb_intern("copy_data"), Qtrue) ) {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
1050
|
+
if ( ca->data->mask != NULL && ca_object_mask_from_hooks(ca) ) {
|
|
1051
|
+
ca_object_copy_bare_t c;
|
|
1052
|
+
c.ca = ca;
|
|
1053
|
+
c.ptr = ptr;
|
|
1054
|
+
c.mask = ca->data->mask;
|
|
1055
|
+
ca->data->mask = NULL;
|
|
1056
|
+
rb_ensure(ca_object_copy_bare_body, (VALUE) &c,
|
|
1057
|
+
ca_object_copy_bare_restore, (VALUE) &c);
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
ca_object_call_lending(ca, ptr, "copy_data");
|
|
705
1061
|
}
|
|
706
1062
|
else {
|
|
707
1063
|
ca_size_t addr;
|
|
@@ -716,11 +1072,7 @@ static void
|
|
|
716
1072
|
ca_object_dispatch_sync (CAObject *ca, void *ptr)
|
|
717
1073
|
{
|
|
718
1074
|
if ( rb_obj_respond_to(ca->self, rb_intern("sync_data"), Qtrue) ) {
|
|
719
|
-
|
|
720
|
-
ca->data->ptr = ptr;
|
|
721
|
-
rb_funcall(ca->self, rb_intern("sync_data"),
|
|
722
|
-
1, rb_ivar_get(ca->self, rb_intern("__data__")));
|
|
723
|
-
ca->data->ptr = ptr0;
|
|
1075
|
+
ca_object_call_lending(ca, ptr, "sync_data");
|
|
724
1076
|
}
|
|
725
1077
|
else {
|
|
726
1078
|
ca_size_t addr;
|
|
@@ -765,7 +1117,7 @@ ca_object_func_attach (void *ap)
|
|
|
765
1117
|
ca_face_attach(ap);
|
|
766
1118
|
return;
|
|
767
1119
|
}
|
|
768
|
-
/*
|
|
1120
|
+
/* cells: seeded with 0, which a copy_data that skips cells leaves visible */
|
|
769
1121
|
ca->data->ptr = xmalloc(ca_length(ca));
|
|
770
1122
|
if ( ca_is_object_type(ca->data) ) { /* GC safe */
|
|
771
1123
|
VALUE *p = (VALUE *) ca->data->ptr;
|
|
@@ -778,10 +1130,7 @@ ca_object_func_attach (void *ap)
|
|
|
778
1130
|
ca->ptr = ca->data->ptr;
|
|
779
1131
|
ca_object_dispatch_copy(ca, ca->ptr);
|
|
780
1132
|
if ( ca_has_mask(ca->data) ) {
|
|
781
|
-
|
|
782
|
-
if ( ! ca->mask ) {
|
|
783
|
-
ca_create_mask(ca);
|
|
784
|
-
}
|
|
1133
|
+
ca_create_mask(ca);
|
|
785
1134
|
}
|
|
786
1135
|
}
|
|
787
1136
|
|
|
@@ -822,7 +1171,8 @@ ca_object_func_detach (void *ap)
|
|
|
822
1171
|
[n] for addrs) before invoking copy_block / sync_block / copy_addrs /
|
|
823
1172
|
sync_addrs. Lifecycle: buffer is owned by the slot caller; the wrapper
|
|
824
1173
|
installs free_ca_wrap as dfree, so the underlying ptr is NOT freed when
|
|
825
|
-
the wrapper is GC'd.
|
|
1174
|
+
the wrapper is GC'd. Call the hook through ca_object_call_transient,
|
|
1175
|
+
which takes the buffer back from the wrapper when the hook returns.
|
|
826
1176
|
|
|
827
1177
|
Object data_type GC safety: for GET (dir == CA_XFER_GET) the buffer may be
|
|
828
1178
|
uninitialized garbage on entry, so we INT2NUM(0) zero-fill before
|
|
@@ -880,7 +1230,12 @@ ca_object_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
|
880
1230
|
1, dim1, addrs, CA_XFER_PUT);
|
|
881
1231
|
rdata = ca_object_wrap_transient(ca->data_type, ca->bytes,
|
|
882
1232
|
1, dim1, data, dir);
|
|
883
|
-
|
|
1233
|
+
{
|
|
1234
|
+
VALUE args[2];
|
|
1235
|
+
args[0] = raddrs;
|
|
1236
|
+
args[1] = rdata;
|
|
1237
|
+
ca_object_call_transient(ca->self, rb_id2name(mid), 2, args, 2, args);
|
|
1238
|
+
}
|
|
884
1239
|
return;
|
|
885
1240
|
}
|
|
886
1241
|
|
|
@@ -917,6 +1272,7 @@ static void
|
|
|
917
1272
|
ca_object_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
918
1273
|
ca_size_t *strides, void *data, int dir)
|
|
919
1274
|
{
|
|
1275
|
+
if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
|
|
920
1276
|
CAObject *ca = (CAObject *) ap;
|
|
921
1277
|
int8_t ndim;
|
|
922
1278
|
ca_size_t native[CA_RANK_MAX], steps[CA_RANK_MAX], idx[CA_RANK_MAX];
|
|
@@ -969,7 +1325,15 @@ ca_object_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
969
1325
|
}
|
|
970
1326
|
rdata = ca_object_wrap_transient(ca->data_type, ca->bytes,
|
|
971
1327
|
ndim, counts, data, dir);
|
|
972
|
-
|
|
1328
|
+
{
|
|
1329
|
+
VALUE args[4];
|
|
1330
|
+
args[0] = rstarts;
|
|
1331
|
+
args[1] = rcounts;
|
|
1332
|
+
args[2] = rsteps;
|
|
1333
|
+
args[3] = rdata;
|
|
1334
|
+
ca_object_call_transient(ca->self, rb_id2name(mid_block),
|
|
1335
|
+
4, args, 1, args + 3);
|
|
1336
|
+
}
|
|
973
1337
|
return;
|
|
974
1338
|
}
|
|
975
1339
|
}
|
|
@@ -1040,7 +1404,12 @@ ca_object_func_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
|
|
|
1040
1404
|
raddrs = ca_object_wrap_transient(CA_SIZE, sizeof(ca_size_t),
|
|
1041
1405
|
1, dim1, addrs, CA_XFER_PUT);
|
|
1042
1406
|
rval = rb_ca_ptr2obj(ca->self, ptr);
|
|
1043
|
-
|
|
1407
|
+
{
|
|
1408
|
+
VALUE args[2];
|
|
1409
|
+
args[0] = raddrs;
|
|
1410
|
+
args[1] = rval;
|
|
1411
|
+
ca_object_call_transient(ca->self, rb_id2name(mid), 2, args, 1, args);
|
|
1412
|
+
}
|
|
1044
1413
|
return;
|
|
1045
1414
|
}
|
|
1046
1415
|
|
|
@@ -1108,31 +1477,32 @@ ca_object_func_create_mask (void *ap)
|
|
|
1108
1477
|
CAObject *ca = (CAObject *) ap;
|
|
1109
1478
|
volatile VALUE rmask;
|
|
1110
1479
|
if ( ca_is_face(ca) ) {
|
|
1111
|
-
/* Face: the mask
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
ca_update_mask(ca->parent);
|
|
1115
|
-
if ( ! ca->parent->mask ) {
|
|
1116
|
-
ca_create_mask(ca->parent);
|
|
1117
|
-
}
|
|
1118
|
-
ca->mask = (CArray *) ca_refer_new(ca->parent->mask,
|
|
1119
|
-
CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
|
|
1480
|
+
/* Face: storage is the parent, so the mask is the parent's (as for the
|
|
1481
|
+
C-level Faces), not the internal __data__'s. */
|
|
1482
|
+
ca_view_func_create_mask(ca);
|
|
1120
1483
|
return;
|
|
1121
1484
|
}
|
|
1122
1485
|
if ( rb_obj_respond_to(ca->self, rb_intern("create_mask"), Qtrue) ) {
|
|
1123
1486
|
rb_funcall(ca->self, rb_intern("create_mask"), 0);
|
|
1124
1487
|
}
|
|
1125
1488
|
else {
|
|
1126
|
-
rb_raise(
|
|
1489
|
+
rb_raise(rb_eTypeError, "can't create mask for CAObject");
|
|
1127
1490
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1491
|
+
ca_create_mask(ca->data);
|
|
1492
|
+
{
|
|
1493
|
+
CAObjectMask *cm = ca_objmask_new(ca->self, ca->ndim, ca->dim);
|
|
1494
|
+
cm->cache = ca->data->mask->ptr;
|
|
1495
|
+
ca->mask = (CArray *) cm;
|
|
1496
|
+
rmask = ca_wrap_struct(ca->mask);
|
|
1497
|
+
rb_ivar_set(ca->self, rb_intern("mask"), rmask);
|
|
1498
|
+
/* Made while this array is attached, the mask joins it at its level:
|
|
1499
|
+
ca_create_mask attaches it once more when this returns. */
|
|
1500
|
+
if ( ca->attach > 1 ) {
|
|
1501
|
+
ca_objmask_refresh(cm);
|
|
1502
|
+
cm->ptr = cm->cache;
|
|
1503
|
+
cm->holds = ca->attach - 1;
|
|
1504
|
+
}
|
|
1131
1505
|
}
|
|
1132
|
-
ca->mask = (CArray*) ca_objmask_new(ca->self, ca->ndim, ca->dim);
|
|
1133
|
-
ca->mask->ptr = ca->data->mask->ptr;
|
|
1134
|
-
rmask = ca_wrap_struct(ca->mask);
|
|
1135
|
-
rb_ivar_set(ca->self, rb_intern("mask"), rmask);
|
|
1136
1506
|
}
|
|
1137
1507
|
|
|
1138
1508
|
ca_operation_function_t ca_object_func = {
|
|
@@ -1171,6 +1541,7 @@ rb_ca_object_initialize_copy (VALUE self, VALUE other)
|
|
|
1171
1541
|
CAObject *ca, *cs;
|
|
1172
1542
|
|
|
1173
1543
|
TypedData_Get_Struct(self, CAObject, &caobject_data_type, ca);
|
|
1544
|
+
ca_check_uninitialized(ca);
|
|
1174
1545
|
TypedData_Get_Struct(other, CAObject, &caobject_data_type, cs);
|
|
1175
1546
|
|
|
1176
1547
|
if ( ca_func[CA_OBJ_OBJECT].pool_init ) {
|
|
@@ -1197,6 +1568,12 @@ rb_ca_object_initialize_copy (VALUE self, VALUE other)
|
|
|
1197
1568
|
data = ca_wrap_struct(ca->data);
|
|
1198
1569
|
rb_ivar_set(self, rb_intern("__data__"), data);
|
|
1199
1570
|
|
|
1571
|
+
/* A Face's mask is a C struct owned by the Face, so the copy makes its
|
|
1572
|
+
own from the parent when it is asked for one. */
|
|
1573
|
+
if ( ca_is_face(ca) ) {
|
|
1574
|
+
return self;
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1200
1577
|
ca_update_mask(cs);
|
|
1201
1578
|
if ( cs->mask ) {
|
|
1202
1579
|
ca->mask = cs->mask;
|
|
@@ -1212,20 +1589,21 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1212
1589
|
{
|
|
1213
1590
|
volatile VALUE rtype, rdim, ropt, rbytes = Qnil, rrdonly = Qnil,
|
|
1214
1591
|
rparent = Qnil, rface = Qnil, rstorage = Qnil, rdata,
|
|
1215
|
-
rorderable = Qnil, rcomparable = Qnil;
|
|
1592
|
+
rorderable = Qnil, rcomparable = Qnil, rnumeric = Qnil;
|
|
1216
1593
|
CAObject *ca;
|
|
1217
1594
|
int8_t data_type, ndim;
|
|
1218
1595
|
ca_size_t dim[CA_RANK_MAX];
|
|
1219
1596
|
ca_size_t bytes;
|
|
1220
1597
|
int i;
|
|
1598
|
+
int storage_named = 0; /* :storage given by the caller */
|
|
1221
1599
|
|
|
1222
1600
|
rb_scan_args(argc, argv, "21", (VALUE *) &rtype, (VALUE *) &rdim, (VALUE *) &ropt);
|
|
1223
|
-
rb_scan_options(ropt, "bytes,read_only,parent,face,storage,orderable_storage,comparable_storage",
|
|
1601
|
+
rb_scan_options(ropt, "bytes,read_only,parent,face,storage,orderable_storage,comparable_storage,numeric",
|
|
1224
1602
|
&rbytes, &rrdonly, &rparent, &rface, &rstorage,
|
|
1225
|
-
&rorderable, &rcomparable);
|
|
1603
|
+
&rorderable, &rcomparable, &rnumeric);
|
|
1226
1604
|
|
|
1227
1605
|
if ( ( ! NIL_P(rparent) ) && ( ! rb_obj_is_carray(rparent) ) ) {
|
|
1228
|
-
rb_raise(
|
|
1606
|
+
rb_raise(rb_eTypeError, "option :parent should be a carray");
|
|
1229
1607
|
}
|
|
1230
1608
|
|
|
1231
1609
|
/* :storage is meaningful only under face: true (= it documents the
|
|
@@ -1246,6 +1624,16 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1246
1624
|
"meaningful with face: true");
|
|
1247
1625
|
}
|
|
1248
1626
|
|
|
1627
|
+
if ( ! NIL_P(rnumeric) && ! RTEST(rface) ) {
|
|
1628
|
+
rb_raise(rb_eArgError,
|
|
1629
|
+
"CAObject: :numeric is only meaningful with face: true");
|
|
1630
|
+
}
|
|
1631
|
+
if ( ! NIL_P(rnumeric) && ! NIL_P(rstorage) ) {
|
|
1632
|
+
rb_raise(rb_eArgError,
|
|
1633
|
+
"CAObject: give either :numeric or :storage, not both "
|
|
1634
|
+
"(:storage declares a surface of its own)");
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1249
1637
|
/* face: true requires :parent. Under Face semantics the parent is the
|
|
1250
1638
|
true storage owner and CAObject itself carries the semantic identity.
|
|
1251
1639
|
The declared data_type is the SURFACE (= what dispatch sees);
|
|
@@ -1262,7 +1650,30 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1262
1650
|
|
|
1263
1651
|
rb_ca_guess_type_and_bytes(rtype, rbytes, &data_type, &bytes);
|
|
1264
1652
|
|
|
1653
|
+
/* Without :storage the data_type argument names the storage of a Face.
|
|
1654
|
+
A numeric storage is gated by default: the surface becomes CA_FIXLEN,
|
|
1655
|
+
so arithmetic, math and reductions raise instead of computing on the
|
|
1656
|
+
stored numbers, which the Face exists to give another meaning.
|
|
1657
|
+
numeric: true lets them through. An object or fixlen storage keeps
|
|
1658
|
+
its own data_type: fixlen kernels already raise, and an object cell
|
|
1659
|
+
may not be read as bytes. */
|
|
1660
|
+
storage_named = ! NIL_P(rstorage);
|
|
1661
|
+
if ( RTEST(rface) && NIL_P(rstorage) ) {
|
|
1662
|
+
if ( data_type == CA_OBJECT || data_type == CA_FIXLEN ) {
|
|
1663
|
+
if ( ! NIL_P(rnumeric) ) {
|
|
1664
|
+
rb_raise(rb_eArgError,
|
|
1665
|
+
"CAObject Face: :numeric applies to a numeric storage only "
|
|
1666
|
+
"(the storage is %s)", ca_type_name[data_type]);
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
else if ( ! RTEST(rnumeric) ) {
|
|
1670
|
+
rstorage = INT2NUM(data_type);
|
|
1671
|
+
data_type = CA_FIXLEN;
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1265
1675
|
Check_Type(rdim, T_ARRAY);
|
|
1676
|
+
CA_CHECK_RANK_GIVEN(RARRAY_LEN(rdim)); /* before dim[] is filled */
|
|
1266
1677
|
|
|
1267
1678
|
ndim = RARRAY_LEN(rdim);
|
|
1268
1679
|
for (i=0; i<ndim; i++) {
|
|
@@ -1270,6 +1681,7 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1270
1681
|
}
|
|
1271
1682
|
|
|
1272
1683
|
TypedData_Get_Struct(self, CAObject, &caobject_data_type, ca);
|
|
1684
|
+
ca_check_uninitialized(ca);
|
|
1273
1685
|
ca_object_setup(ca, data_type, ndim, dim, bytes);
|
|
1274
1686
|
ca->self = self;
|
|
1275
1687
|
|
|
@@ -1287,17 +1699,11 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1287
1699
|
ca->parent = cp;
|
|
1288
1700
|
rb_ca_set_parent(self, rparent);
|
|
1289
1701
|
|
|
1290
|
-
/* Face mode invariants
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
Numeric Face authors who didn't intend
|
|
1296
|
-
surface/storage to differ.
|
|
1297
|
-
- :storage given → "surface != storage" opted-in:
|
|
1298
|
-
surface is free (= e.g. CA_FIXLEN for
|
|
1299
|
-
NonNumeric Face), :storage must agree with
|
|
1300
|
-
parent.data_type, and bytes must match. */
|
|
1702
|
+
/* Face mode invariants: bytes match the parent's, and the storage
|
|
1703
|
+
(:storage, or the data_type argument when :storage was omitted)
|
|
1704
|
+
is the parent's data_type. The surface is the data_type argument
|
|
1705
|
+
under :storage, CA_FIXLEN for a gated numeric storage (decided
|
|
1706
|
+
above), and the storage itself otherwise. */
|
|
1301
1707
|
if ( RTEST(rface) ) {
|
|
1302
1708
|
if ( bytes != cp->bytes ) {
|
|
1303
1709
|
rb_raise(rb_eTypeError,
|
|
@@ -1306,12 +1712,12 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1306
1712
|
(long long) bytes, (long long) cp->bytes);
|
|
1307
1713
|
}
|
|
1308
1714
|
if ( NIL_P(rstorage) ) {
|
|
1309
|
-
/*
|
|
1715
|
+
/* The data_type argument names the storage. */
|
|
1310
1716
|
if ( cp->data_type != data_type ) {
|
|
1311
1717
|
rb_raise(rb_eTypeError,
|
|
1312
1718
|
"CAObject Face: parent data_type mismatch "
|
|
1313
1719
|
"(declared=%d, parent=%d). Use :storage option to "
|
|
1314
|
-
"
|
|
1720
|
+
"declare a surface that differs from the storage.",
|
|
1315
1721
|
(int) data_type, (int) cp->data_type);
|
|
1316
1722
|
}
|
|
1317
1723
|
}
|
|
@@ -1323,10 +1729,20 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1323
1729
|
&declared_storage, &declared_storage_bytes);
|
|
1324
1730
|
if ( cp->data_type != declared_storage ) {
|
|
1325
1731
|
rb_raise(rb_eTypeError,
|
|
1326
|
-
|
|
1327
|
-
"
|
|
1732
|
+
storage_named
|
|
1733
|
+
? "CAObject Face: :storage mismatch "
|
|
1734
|
+
"(declared=%d, parent.data_type=%d)"
|
|
1735
|
+
: "CAObject Face: parent data_type mismatch "
|
|
1736
|
+
"(declared=%d, parent=%d)",
|
|
1328
1737
|
(int) declared_storage, (int) cp->data_type);
|
|
1329
1738
|
}
|
|
1739
|
+
/* An object cell is a VALUE: reading it under another surface hands
|
|
1740
|
+
out its address, and writing one forges it. */
|
|
1741
|
+
if ( ca_is_object_type(cp) && data_type != CA_OBJECT ) {
|
|
1742
|
+
rb_raise(rb_eTypeError,
|
|
1743
|
+
"CAObject Face: an object storage can't be given "
|
|
1744
|
+
"another surface data_type");
|
|
1745
|
+
}
|
|
1330
1746
|
}
|
|
1331
1747
|
ca_set_flag(ca, CA_FLAG_IS_FACE);
|
|
1332
1748
|
if ( RTEST(rorderable) ) {
|