carray 3.0.2 → 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 +304 -0
- data/README.md +3 -4
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +225 -0
- data/ext/ca_axis_group.c +177 -99
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +66 -71
- 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 +663 -214
- data/ext/ca_kernel_iterator.h +231 -167
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +132 -22
- 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 +1 -0
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +96 -25
- data/ext/ca_obj_face.c +406 -64
- data/ext/ca_obj_face.h +92 -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 +21 -21
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +189 -107
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +543 -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 +47 -49
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -118
- data/ext/ca_obj_stride.c +195 -34
- data/ext/ca_obj_string.c +17 -18
- 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 +149 -27
- 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 +102 -79
- 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 +463 -0
- data/ext/carray.h +70 -27
- data/ext/carray_access.c +455 -211
- data/ext/carray_address_basis.c +177 -36
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +46 -14
- data/ext/carray_call_cfunc.c +0 -28
- data/ext/carray_cast.c +1444 -209
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +32 -11
- data/ext/carray_core.c +514 -122
- data/ext/carray_count.c +140 -87
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +569 -277
- 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 +385 -3
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +682 -316
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +221 -76
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1089 -359
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +273 -239
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +170 -70
- data/ext/carray_sort.c +215 -218
- 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 +0 -2
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1076 -846
- data/ext/ruby_carray.c +7 -1
- 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 +19 -0
- data/lib/carray/autoload_method_extension.rb +6 -0
- data/lib/carray/axis_group.rb +174 -26
- data/lib/carray/basics.rb +91 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +118 -48
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +94 -26
- data/lib/carray/categorical_iterator.rb +333 -826
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +46 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +589 -82
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +124 -25
- data/lib/carray/frame/group.rb +189 -63
- data/lib/carray/frame/io.rb +412 -72
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +37 -16
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +715 -48
- 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 +29 -11
- data/lib/carray/iterator.rb +14 -2
- data/lib/carray/lazy.rb +54 -30
- data/lib/carray/mask_gap_fill.rb +66 -52
- 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/factorize.rb +2 -2
- 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 +117 -4
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +177 -36
- data/lib/carray/methods/mode.rb +18 -1
- 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/record_order.rb +208 -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 +51 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +4 -3
- 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 +517 -103
- data/lib/carray/window_iterator.rb +127 -72
- data/lib/carray.rb +2 -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 +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 +1 -2
- data/yard-stubs/carray_access.rb +5 -4
- data/yard-stubs/carray_broadcast.rb +1 -1
- 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 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +25 -13
- data/yard-stubs/carray_median_percentile.rb +10 -6
- data/yard-stubs/carray_order.rb +34 -13
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +2 -1
- data/yard-stubs/carray_sort.rb +43 -3
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +11 -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 -26005
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14862
- data/ext/carray_kernels_reduce_extreme.c +0 -17494
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32218
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
carray_segment.c
|
|
4
|
+
|
|
5
|
+
Conversions between the representations of a flat sequence cut into
|
|
6
|
+
consecutive segments:
|
|
7
|
+
|
|
8
|
+
lengths [2, 0, 3] one count per segment (k)
|
|
9
|
+
offsets [0, 2, 2, 5] every boundary, first and last included (k+1)
|
|
10
|
+
segment index [0, 0, 2, 2, 2] the segment each element belongs to (n)
|
|
11
|
+
|
|
12
|
+
CArray.segment_offsets(lengths: l) lengths -> offsets
|
|
13
|
+
CArray.segment_index(lengths: l) lengths -> segment index
|
|
14
|
+
CArray.segment_index(offsets: o) offsets -> segment index
|
|
15
|
+
|
|
16
|
+
Everything is computed in int64, so a total beyond 2**53 stays exact
|
|
17
|
+
(a cumsum would go through float64). Offsets need not start at 0: the
|
|
18
|
+
offsets of rows a..b cut out of a longer table start at offsets[a], and
|
|
19
|
+
the segment index then covers offsets[0]...offsets[-1] with the segments
|
|
20
|
+
numbered from 0.
|
|
21
|
+
|
|
22
|
+
Inputs are read through ca_copy_data straight into an int64 array that
|
|
23
|
+
Ruby already owns, so a refusal after reading leaks nothing.
|
|
24
|
+
|
|
25
|
+
--------------------------------------------------------------------------- */
|
|
26
|
+
|
|
27
|
+
#include "carray.h"
|
|
28
|
+
|
|
29
|
+
static ID id_lengths, id_offsets;
|
|
30
|
+
|
|
31
|
+
/* Read `v` (any integer or boolean CArray, or an Array of Integers) as
|
|
32
|
+
int64 into a fresh Ruby-owned array of `pad_front + v.elements`
|
|
33
|
+
elements, starting after `pad_front` cells. Refuses a non-integer
|
|
34
|
+
data type and masked cells, since neither names a count or a
|
|
35
|
+
position. */
|
|
36
|
+
static VALUE
|
|
37
|
+
segment_read_int64 (VALUE v, const char *name, int is_lengths,
|
|
38
|
+
ca_size_t pad_front, CArray **out_ca, ca_size_t *out_k)
|
|
39
|
+
{
|
|
40
|
+
CArray *src, *dst;
|
|
41
|
+
VALUE rsrc, rdst;
|
|
42
|
+
ca_size_t k;
|
|
43
|
+
const char *role = is_lengths ? "lengths" : "offsets";
|
|
44
|
+
|
|
45
|
+
if ( TYPE(v) == T_ARRAY ) {
|
|
46
|
+
long i;
|
|
47
|
+
for (i = 0; i < RARRAY_LEN(v); i++) {
|
|
48
|
+
if ( ! RB_INTEGER_TYPE_P(RARRAY_AREF(v, i)) ) {
|
|
49
|
+
rb_raise(rb_eArgError, "%s: %s must be integers", name, role);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else if ( ! rb_obj_is_carray(v) ) {
|
|
54
|
+
rb_raise(rb_eTypeError, "%s: %s must be a CArray or an Array of Integers",
|
|
55
|
+
name, role);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
GetCArray(v, src);
|
|
59
|
+
if ( ! ca_is_integer_type(src) && src->data_type != CA_BOOLEAN ) {
|
|
60
|
+
rb_raise(rb_eCADataTypeError, "%s: %s must be integers (got %s)",
|
|
61
|
+
name, role, ca_type_name[src->data_type]);
|
|
62
|
+
}
|
|
63
|
+
if ( ca_has_mask(src) &&
|
|
64
|
+
NUM2LL(rb_funcall(v, rb_intern("count_masked"), 0)) > 0 ) {
|
|
65
|
+
rb_raise(rb_eArgError, is_lengths ? "%s: a masked length is not a count"
|
|
66
|
+
: "%s: a masked offset is not a position",
|
|
67
|
+
name);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
rsrc = rb_ca_wrap_readonly(v, INT2NUM(CA_INT64));
|
|
72
|
+
GetCArray(rsrc, src);
|
|
73
|
+
k = src->elements;
|
|
74
|
+
{
|
|
75
|
+
ca_size_t dim[1];
|
|
76
|
+
dim[0] = pad_front + k;
|
|
77
|
+
rdst = rb_carray_new(CA_INT64, 1, dim, 0, NULL);
|
|
78
|
+
}
|
|
79
|
+
GetCArray(rdst, dst);
|
|
80
|
+
if ( k > 0 ) {
|
|
81
|
+
ca_copy_data(src, dst->ptr + pad_front * sizeof(int64_t));
|
|
82
|
+
}
|
|
83
|
+
RB_GC_GUARD(rsrc);
|
|
84
|
+
*out_ca = dst;
|
|
85
|
+
*out_k = k;
|
|
86
|
+
return rdst;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Turn a lengths array read into o[1..k] into offsets in place, o[0] = 0. */
|
|
90
|
+
static void
|
|
91
|
+
segment_prefix_sum (int64_t *o, ca_size_t k, const char *name)
|
|
92
|
+
{
|
|
93
|
+
int64_t s = 0;
|
|
94
|
+
ca_size_t c;
|
|
95
|
+
o[0] = 0;
|
|
96
|
+
for (c = 1; c <= k; c++) {
|
|
97
|
+
int64_t l = o[c];
|
|
98
|
+
if ( l < 0 ) {
|
|
99
|
+
rb_raise(rb_eArgError, "%s: lengths must not be negative (got %lld at %lld)",
|
|
100
|
+
name, (long long) l, (long long) (c - 1));
|
|
101
|
+
}
|
|
102
|
+
if ( s > INT64_MAX - l ) {
|
|
103
|
+
rb_raise(rb_eRangeError, "%s: the total length overflows int64", name);
|
|
104
|
+
}
|
|
105
|
+
s += l;
|
|
106
|
+
o[c] = s;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Parse the one role keyword. Returns the value and sets *is_lengths. */
|
|
111
|
+
static VALUE
|
|
112
|
+
segment_role (int argc, VALUE *argv, const char *name, int allow_offsets,
|
|
113
|
+
int *is_lengths)
|
|
114
|
+
{
|
|
115
|
+
VALUE opts, vals[2];
|
|
116
|
+
ID ids[2];
|
|
117
|
+
int nids;
|
|
118
|
+
|
|
119
|
+
rb_scan_args(argc, argv, ":", &opts);
|
|
120
|
+
ids[0] = id_lengths;
|
|
121
|
+
ids[1] = id_offsets;
|
|
122
|
+
nids = allow_offsets ? 2 : 1;
|
|
123
|
+
vals[0] = vals[1] = Qundef;
|
|
124
|
+
rb_get_kwargs(opts, ids, 0, nids, vals);
|
|
125
|
+
|
|
126
|
+
if ( vals[0] != Qundef && nids == 2 && vals[1] != Qundef ) {
|
|
127
|
+
rb_raise(rb_eArgError, "%s: give lengths: or offsets:, not both", name);
|
|
128
|
+
}
|
|
129
|
+
if ( vals[0] != Qundef ) {
|
|
130
|
+
*is_lengths = 1;
|
|
131
|
+
return vals[0];
|
|
132
|
+
}
|
|
133
|
+
if ( nids == 2 && vals[1] != Qundef ) {
|
|
134
|
+
*is_lengths = 0;
|
|
135
|
+
return vals[1];
|
|
136
|
+
}
|
|
137
|
+
rb_raise(rb_eArgError, allow_offsets ? "%s: lengths: or offsets: is required"
|
|
138
|
+
: "%s: lengths: is required", name);
|
|
139
|
+
return Qnil;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* CArray.segment_offsets(lengths: l) -> int64[k+1] */
|
|
143
|
+
static VALUE
|
|
144
|
+
rb_ca_s_segment_offsets (int argc, VALUE *argv, VALUE klass)
|
|
145
|
+
{
|
|
146
|
+
const char *name = "segment_offsets";
|
|
147
|
+
int is_lengths;
|
|
148
|
+
VALUE v, ro;
|
|
149
|
+
CArray *co;
|
|
150
|
+
ca_size_t k;
|
|
151
|
+
|
|
152
|
+
v = segment_role(argc, argv, name, 0, &is_lengths);
|
|
153
|
+
ro = segment_read_int64(v, name, 1, 1, &co, &k);
|
|
154
|
+
segment_prefix_sum((int64_t *) co->ptr, k, name);
|
|
155
|
+
return ro;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* The boundaries named by the one role keyword, as a validated int64 array
|
|
159
|
+
of k+1 elements that Ruby owns: lengths are summed, offsets are checked
|
|
160
|
+
to be non-empty and non-decreasing. */
|
|
161
|
+
static VALUE
|
|
162
|
+
segment_bounds (int argc, VALUE *argv, const char *name, CArray **out_co,
|
|
163
|
+
ca_size_t *out_k)
|
|
164
|
+
{
|
|
165
|
+
int is_lengths;
|
|
166
|
+
VALUE v, ro;
|
|
167
|
+
CArray *co;
|
|
168
|
+
ca_size_t k, c;
|
|
169
|
+
int64_t *o;
|
|
170
|
+
|
|
171
|
+
v = segment_role(argc, argv, name, 1, &is_lengths);
|
|
172
|
+
|
|
173
|
+
if ( is_lengths ) {
|
|
174
|
+
ro = segment_read_int64(v, name, 1, 1, &co, &k);
|
|
175
|
+
segment_prefix_sum((int64_t *) co->ptr, k, name);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
ro = segment_read_int64(v, name, 0, 0, &co, &k);
|
|
179
|
+
if ( k == 0 ) {
|
|
180
|
+
rb_raise(rb_eArgError,
|
|
181
|
+
"%s: offsets need at least one element (the start of the first segment)",
|
|
182
|
+
name);
|
|
183
|
+
}
|
|
184
|
+
o = (int64_t *) co->ptr;
|
|
185
|
+
for (c = 1; c < k; c++) {
|
|
186
|
+
if ( o[c] < o[c-1] ) {
|
|
187
|
+
rb_raise(rb_eArgError,
|
|
188
|
+
"%s: offsets must not decrease (%lld after %lld at %lld)",
|
|
189
|
+
name, (long long) o[c], (long long) o[c-1], (long long) c);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
k -= 1; /* k+1 boundaries -> k segments */
|
|
193
|
+
}
|
|
194
|
+
*out_co = co;
|
|
195
|
+
*out_k = k;
|
|
196
|
+
return ro;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/* CArray.segment_index(lengths: l) -> int64[l.sum]
|
|
200
|
+
CArray.segment_index(offsets: o) -> int64[o[-1] - o[0]] */
|
|
201
|
+
static VALUE
|
|
202
|
+
rb_ca_s_segment_index (int argc, VALUE *argv, VALUE klass)
|
|
203
|
+
{
|
|
204
|
+
VALUE ro, rout;
|
|
205
|
+
CArray *co, *cout;
|
|
206
|
+
ca_size_t k, c;
|
|
207
|
+
int64_t *o, *q, base, total;
|
|
208
|
+
|
|
209
|
+
ro = segment_bounds(argc, argv, "segment_index", &co, &k);
|
|
210
|
+
o = (int64_t *) co->ptr;
|
|
211
|
+
|
|
212
|
+
base = o[0];
|
|
213
|
+
total = o[k] - base;
|
|
214
|
+
{
|
|
215
|
+
ca_size_t dim[1];
|
|
216
|
+
dim[0] = (ca_size_t) total;
|
|
217
|
+
rout = rb_carray_new(CA_INT64, 1, dim, 0, NULL);
|
|
218
|
+
}
|
|
219
|
+
GetCArray(rout, cout);
|
|
220
|
+
q = (int64_t *) cout->ptr;
|
|
221
|
+
for (c = 0; c < k; c++) {
|
|
222
|
+
int64_t p = o[c] - base, e = o[c+1] - base;
|
|
223
|
+
for (; p < e; p++) {
|
|
224
|
+
q[p] = (int64_t) c;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
RB_GC_GUARD(ro);
|
|
228
|
+
return rout;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* CArray.__segment_bounds__(name, lengths: l | offsets: o) -> int64[k+1]
|
|
232
|
+
|
|
233
|
+
Internal: the validated boundaries, for a Ruby caller that takes the same
|
|
234
|
+
two keywords (CArray#segments). `name` heads the error messages. */
|
|
235
|
+
static VALUE
|
|
236
|
+
rb_ca_s_segment_bounds (int argc, VALUE *argv, VALUE klass)
|
|
237
|
+
{
|
|
238
|
+
CArray *co;
|
|
239
|
+
ca_size_t k;
|
|
240
|
+
VALUE rname;
|
|
241
|
+
if ( argc < 1 ) {
|
|
242
|
+
rb_raise(rb_eArgError, "__segment_bounds__: the caller's name is required");
|
|
243
|
+
}
|
|
244
|
+
rname = argv[0];
|
|
245
|
+
StringValue(rname);
|
|
246
|
+
return segment_bounds(argc - 1, argv + 1, RSTRING_PTR(rname), &co, &k);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
void
|
|
250
|
+
Init_carray_segment (void)
|
|
251
|
+
{
|
|
252
|
+
id_lengths = rb_intern("lengths");
|
|
253
|
+
id_offsets = rb_intern("offsets");
|
|
254
|
+
rb_define_singleton_method(rb_cCArray, "segment_offsets", rb_ca_s_segment_offsets, -1);
|
|
255
|
+
rb_define_singleton_method(rb_cCArray, "segment_index", rb_ca_s_segment_index, -1);
|
|
256
|
+
rb_define_singleton_method(rb_cCArray, "__segment_bounds__", rb_ca_s_segment_bounds, -1);
|
|
257
|
+
}
|
data/ext/carray_slab.c
CHANGED
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
--------------------------------------------------------------------------- */
|
|
29
29
|
|
|
30
30
|
#include "carray.h"
|
|
31
|
+
#include "carray_internal.h" /* ca_attach_window, ca_calling_method_name, ca_axis_integer */
|
|
31
32
|
#include "carray_slab.h"
|
|
32
33
|
|
|
33
34
|
/* Forward declarations: per-form loop bodies are defined later in this
|
|
@@ -67,22 +68,23 @@ ca_slab_parse_axes (ca_slab_iter_state_t *st, VALUE axis_arg, int8_t src_ndim)
|
|
|
67
68
|
n = (int) RARRAY_LEN(arr);
|
|
68
69
|
if ( n < 1 || n > CA_RANK_MAX ) {
|
|
69
70
|
rb_raise(rb_eArgError,
|
|
70
|
-
"
|
|
71
|
-
n, CA_RANK_MAX);
|
|
71
|
+
"%s: axis count %d out of range [1..%d]",
|
|
72
|
+
ca_calling_method_name(), n, CA_RANK_MAX);
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
for ( i = 0; i < n; i++ ) {
|
|
75
|
-
int k =
|
|
76
|
+
int k = (int) ca_axis_integer(rb_ary_entry(arr, i), NULL);
|
|
76
77
|
if ( k < 0 ) k += src_ndim;
|
|
77
78
|
if ( k < 0 || k >= src_ndim ) {
|
|
78
79
|
rb_raise(rb_eArgError,
|
|
79
|
-
"
|
|
80
|
-
NUM2INT(rb_ary_entry(arr, i)),
|
|
80
|
+
"%s: axis %d out of range for ndim %d",
|
|
81
|
+
ca_calling_method_name(), NUM2INT(rb_ary_entry(arr, i)),
|
|
82
|
+
src_ndim);
|
|
81
83
|
}
|
|
82
84
|
for ( j = 0; j < i; j++ ) {
|
|
83
85
|
if ( st->slab_axes[j] == (int8_t) k ) {
|
|
84
86
|
rb_raise(rb_eArgError,
|
|
85
|
-
"
|
|
87
|
+
"%s: duplicate axis %d", ca_calling_method_name(), k);
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
st->slab_axes[i] = (int8_t) k;
|
|
@@ -368,23 +370,16 @@ ca_slab_setup_input_slab_view (ca_slab_iter_state_t *st, CArray *src,
|
|
|
368
370
|
p_in via slab_strides into the scratch, present slab_view as
|
|
369
371
|
a CAStride over the carrier with contig strides.
|
|
370
372
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
int contig
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
"multi-axis slab with non-ALIAS T1 mode not implemented yet "
|
|
382
|
-
"(alias_mode = %d)", (int) am);
|
|
383
|
-
}
|
|
384
|
-
contig = ca_slab_strides_are_row_major_contig(slab_ndim,
|
|
385
|
-
st->t1->slab_dims,
|
|
386
|
-
st->t1->slab_strides,
|
|
387
|
-
src->bytes);
|
|
373
|
+
Path (a) needs p_in to lie in src's own buffer, which holds only
|
|
374
|
+
when src is an entity. Any other source -- a view, whose cells the
|
|
375
|
+
iterator hands out from the root, a parent or its own scratch --
|
|
376
|
+
takes path (b): the iterator describes every slab by p_in and
|
|
377
|
+
slab_strides, whatever its mode. */
|
|
378
|
+
int contig = ca_is_entity(src)
|
|
379
|
+
&& ca_slab_strides_are_row_major_contig(slab_ndim,
|
|
380
|
+
st->t1->slab_dims,
|
|
381
|
+
st->t1->slab_strides,
|
|
382
|
+
src->bytes);
|
|
388
383
|
if ( contig ) {
|
|
389
384
|
/* (a) contig multi-axis ALIAS: parent=src, K-D strides match src. */
|
|
390
385
|
st->slab_view = ca_slab_build_slab_view(st->self, src->data_type,
|
|
@@ -440,7 +435,10 @@ ca_slab_setup_input_slab_view (ca_slab_iter_state_t *st, CArray *src,
|
|
|
440
435
|
ca_size_t strides[1];
|
|
441
436
|
dim[0] = fiber_len;
|
|
442
437
|
strides[0] = src->bytes;
|
|
443
|
-
|
|
438
|
+
/* A window onto src only when the fiber lies in src's own buffer:
|
|
439
|
+
an entity whose fiber is contiguous. A view's fiber comes from
|
|
440
|
+
the root or the iterator's scratch, so it goes through a carrier. */
|
|
441
|
+
in_alias = ca_is_entity(src) && (in_stride == src->bytes);
|
|
444
442
|
|
|
445
443
|
if ( in_alias ) {
|
|
446
444
|
/* ALIAS: parent = src. ca_stride_setup auto-creates slab_view->mask
|
|
@@ -525,6 +523,44 @@ ca_slab_advance_slab_view (ca_slab_iter_state_t *st,
|
|
|
525
523
|
}
|
|
526
524
|
}
|
|
527
525
|
|
|
526
|
+
/* map_slab: mark in the output the cells the block's result has masked.
|
|
527
|
+
The output is an entity walked in place, so the slab starts at
|
|
528
|
+
last_data_off in its buffer and steps by slab_strides; the output gets
|
|
529
|
+
a mask only when some result has a masked cell. */
|
|
530
|
+
static void
|
|
531
|
+
ca_map_slab_carry_mask (ca_slab_iter_state_t *st, CArray *out, CArray *res,
|
|
532
|
+
ca_size_t slab_elements)
|
|
533
|
+
{
|
|
534
|
+
ca_iter_state *t = st->t1_out;
|
|
535
|
+
volatile VALUE h = 0;
|
|
536
|
+
boolean8_t *m;
|
|
537
|
+
ca_size_t idx[CA_RANK_MAX];
|
|
538
|
+
ca_size_t i;
|
|
539
|
+
int8_t k;
|
|
540
|
+
|
|
541
|
+
if ( ! ca_has_mask(res) ) return;
|
|
542
|
+
ca_update_mask(res);
|
|
543
|
+
m = (boolean8_t *) ALLOCV(h, slab_elements);
|
|
544
|
+
ca_xfer_all(res->mask, m, CA_XFER_GET);
|
|
545
|
+
for ( i = 0; i < slab_elements && ! m[i]; i++ ) ;
|
|
546
|
+
if ( i < slab_elements ) {
|
|
547
|
+
ca_create_mask(out);
|
|
548
|
+
for ( k = 0; k < t->slab_ndim; k++ ) idx[k] = 0;
|
|
549
|
+
for ( i = 0; i < slab_elements; i++ ) {
|
|
550
|
+
if ( m[i] ) {
|
|
551
|
+
ca_size_t off = t->last_data_off;
|
|
552
|
+
for ( k = 0; k < t->slab_ndim; k++ ) off += idx[k] * t->slab_strides[k];
|
|
553
|
+
((boolean8_t *) out->mask->ptr)[off / out->bytes] = 1;
|
|
554
|
+
}
|
|
555
|
+
for ( k = t->slab_ndim - 1; k >= 0; k-- ) {
|
|
556
|
+
if ( ++idx[k] < t->slab_dims[k] ) break;
|
|
557
|
+
idx[k] = 0;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
ALLOCV_END(h);
|
|
562
|
+
}
|
|
563
|
+
|
|
528
564
|
/* Convert a Ruby Numeric scalar into bytes of slab_view's data_type and
|
|
529
565
|
fill the entire slab buffer at out_ptr. Used when the user block
|
|
530
566
|
returns a scalar instead of a CArray (= broadcast over the slab).
|
|
@@ -533,9 +569,6 @@ static void
|
|
|
533
569
|
ca_slab_fill_scalar (VALUE source, char *out_ptr, ca_size_t slab_elements,
|
|
534
570
|
int8_t out_data_type, ca_size_t out_bytes, VALUE val)
|
|
535
571
|
{
|
|
536
|
-
char buf[64];
|
|
537
|
-
char *scratch = (out_bytes <= (ca_size_t) sizeof(buf)) ? buf
|
|
538
|
-
: xmalloc(out_bytes);
|
|
539
572
|
ca_size_t i;
|
|
540
573
|
/* Use source's data_type-aware conversion (rb_ca_obj2ptr looks at the
|
|
541
574
|
receiver's data_type). Build a stand-in scalar buffer via the
|
|
@@ -546,18 +579,51 @@ ca_slab_fill_scalar (VALUE source, char *out_ptr, ca_size_t slab_elements,
|
|
|
546
579
|
conversion through the actual output entity (= we already have
|
|
547
580
|
`source`-keyed obj2ptr in carray_cast.c). Here we construct an
|
|
548
581
|
ephemeral CScalar of the output data_type to anchor the cast. */
|
|
549
|
-
VALUE cs_anchor =
|
|
582
|
+
volatile VALUE cs_anchor =
|
|
550
583
|
rb_cscalar_new_with_value((int) out_data_type, (int) out_bytes, val);
|
|
551
584
|
CScalar *anchor_ca;
|
|
552
585
|
(void) source;
|
|
553
586
|
TypedData_Get_Struct(cs_anchor, CScalar, &cscalar_data_type, anchor_ca);
|
|
554
|
-
ca_attach(anchor_ca);
|
|
555
|
-
memcpy(scratch, anchor_ca->ptr, out_bytes);
|
|
556
|
-
ca_detach(anchor_ca);
|
|
557
587
|
for ( i = 0; i < slab_elements; i++ ) {
|
|
558
|
-
memcpy(out_ptr + i * out_bytes,
|
|
588
|
+
memcpy(out_ptr + i * out_bytes, anchor_ca->ptr, out_bytes);
|
|
589
|
+
}
|
|
590
|
+
RB_GC_GUARD(cs_anchor);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/* map_slab's cast-on-scatter: each cell of the block's result converted
|
|
594
|
+
into the output data type, with the result attached for the fetches. */
|
|
595
|
+
|
|
596
|
+
typedef struct {
|
|
597
|
+
VALUE result;
|
|
598
|
+
CArray *res;
|
|
599
|
+
VALUE output_view;
|
|
600
|
+
char *write_target;
|
|
601
|
+
ca_size_t out_bytes;
|
|
602
|
+
ca_size_t slab_elements;
|
|
603
|
+
} ca_map_slab_cast_ctx_t;
|
|
604
|
+
|
|
605
|
+
static VALUE
|
|
606
|
+
ca_map_slab_cast_body (VALUE arg)
|
|
607
|
+
{
|
|
608
|
+
ca_map_slab_cast_ctx_t *c = (ca_map_slab_cast_ctx_t *) arg;
|
|
609
|
+
volatile VALUE holder;
|
|
610
|
+
char *scratch = ALLOCV_N(char, holder, c->out_bytes);
|
|
611
|
+
ca_size_t i;
|
|
612
|
+
for ( i = 0; i < c->slab_elements; i++ ) {
|
|
613
|
+
VALUE elem;
|
|
614
|
+
ca_size_t idx[CA_RANK_MAX] = { 0 };
|
|
615
|
+
ca_size_t flat = i;
|
|
616
|
+
int8_t k;
|
|
617
|
+
for ( k = c->res->ndim - 1; k >= 0; k-- ) {
|
|
618
|
+
idx[k] = flat % c->res->dim[k];
|
|
619
|
+
flat /= c->res->dim[k];
|
|
620
|
+
}
|
|
621
|
+
elem = rb_ca_fetch_index(c->result, idx);
|
|
622
|
+
rb_ca_obj2ptr(c->output_view, elem, scratch);
|
|
623
|
+
memcpy(c->write_target + i * c->out_bytes, scratch, c->out_bytes);
|
|
559
624
|
}
|
|
560
|
-
|
|
625
|
+
ALLOCV_END(holder);
|
|
626
|
+
return Qnil;
|
|
561
627
|
}
|
|
562
628
|
|
|
563
629
|
static VALUE
|
|
@@ -573,16 +639,13 @@ ca_slab_run_map (ca_slab_iter_state_t *st)
|
|
|
573
639
|
|
|
574
640
|
TypedData_Get_Struct(st->self, CArray, &carray_data_type, src);
|
|
575
641
|
|
|
576
|
-
/*
|
|
577
|
-
|
|
578
|
-
is intentionally NOT scattered — block return CArray mask info is
|
|
579
|
-
dropped (= simplest contract). */
|
|
642
|
+
/* The input slab carries the source's mask; a CArray the block
|
|
643
|
+
returns carries its mask into the output (ca_map_slab_carry_mask). */
|
|
580
644
|
|
|
581
645
|
/* Step 1: allocate output entity (same shape as src, data_type from opts). */
|
|
582
646
|
st->output = rb_carray_new(st->out_data_type, src->ndim, src->dim,
|
|
583
647
|
st->out_bytes, NULL);
|
|
584
648
|
TypedData_Get_Struct(st->output, CArray, &carray_data_type, out);
|
|
585
|
-
ca_allocate(out); /* entity ptr usable as both read + write target */
|
|
586
649
|
|
|
587
650
|
/* Step 2: T1 init on both sides. FIBER_CONTIG is naxes==1 only;
|
|
588
651
|
multi-axis omits it. Output side gets CA_KERNEL_WRITE. */
|
|
@@ -698,34 +761,22 @@ ca_slab_run_map (ca_slab_iter_state_t *st)
|
|
|
698
761
|
(long long) slab_elements, (int) slab_cs->ndim);
|
|
699
762
|
}
|
|
700
763
|
if ( res->data_type == st->out_data_type && res->bytes == st->out_bytes ) {
|
|
701
|
-
ca_attach(res);
|
|
702
764
|
ca_xfer_all(res, write_target, CA_XFER_GET);
|
|
703
|
-
ca_detach(res);
|
|
704
765
|
}
|
|
705
766
|
else {
|
|
706
767
|
/* Cast-on-scatter via per-cell obj2ptr. Writes to write_target
|
|
707
|
-
(= either p_out direct or own_out_scratch).
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
int8_t k;
|
|
718
|
-
for ( k = res->ndim - 1; k >= 0; k-- ) {
|
|
719
|
-
idx[k] = flat % res->dim[k];
|
|
720
|
-
flat /= res->dim[k];
|
|
721
|
-
}
|
|
722
|
-
elem = rb_ca_fetch_index(result, idx);
|
|
723
|
-
rb_ca_obj2ptr(st->output_slab_view, elem, scratch);
|
|
724
|
-
memcpy(write_target + i * st->out_bytes, scratch, st->out_bytes);
|
|
725
|
-
}
|
|
726
|
-
ca_detach(res);
|
|
727
|
-
if ( scratch != buf ) xfree(scratch);
|
|
768
|
+
(= either p_out direct or own_out_scratch). The conversion
|
|
769
|
+
can raise, so the result is read in a window. */
|
|
770
|
+
ca_map_slab_cast_ctx_t c;
|
|
771
|
+
c.result = result;
|
|
772
|
+
c.res = res;
|
|
773
|
+
c.output_view = st->output_slab_view;
|
|
774
|
+
c.write_target = write_target;
|
|
775
|
+
c.out_bytes = st->out_bytes;
|
|
776
|
+
c.slab_elements = slab_elements;
|
|
777
|
+
ca_attach_window(1, &res, "r", ca_map_slab_cast_body, (VALUE) &c);
|
|
728
778
|
}
|
|
779
|
+
ca_map_slab_carry_mask(st, out, res, slab_elements);
|
|
729
780
|
}
|
|
730
781
|
else if ( rb_obj_is_kind_of(result, rb_cNumeric) ||
|
|
731
782
|
result == Qtrue || result == Qfalse ||
|
|
@@ -820,7 +871,6 @@ ca_slab_reduce_setup (ca_slab_iter_state_t *st, CArray **out_src,
|
|
|
820
871
|
st->output = rb_carray_new(st->out_data_type, out_ndim, out_dim,
|
|
821
872
|
st->out_bytes, NULL);
|
|
822
873
|
TypedData_Get_Struct(st->output, CArray, &carray_data_type, out);
|
|
823
|
-
ca_allocate(out);
|
|
824
874
|
|
|
825
875
|
/* FIBER_CONTIG is naxes==1 only (T1 substrate contract). Multi-axis
|
|
826
876
|
omits the flag and uses bare CA_SLAB_AXES; T1 picks an in-src
|
|
@@ -862,6 +912,7 @@ ca_slab_run_reduce_slab (ca_slab_iter_state_t *st)
|
|
|
862
912
|
ca_size_t out_idx = 0;
|
|
863
913
|
char buf[64];
|
|
864
914
|
char *scratch;
|
|
915
|
+
volatile VALUE scratch_holder = 0; /* 0, not Qnil: ALLOCV_END reads a non-zero holder */
|
|
865
916
|
|
|
866
917
|
ca_slab_reduce_setup(st, &src, &fiber_len);
|
|
867
918
|
TypedData_Get_Struct(st->output, CArray, &carray_data_type, out);
|
|
@@ -871,8 +922,10 @@ ca_slab_run_reduce_slab (ca_slab_iter_state_t *st)
|
|
|
871
922
|
TypedData_Get_Struct(st->carrier, CAWrap, &cawrap_data_type, carrier_cw);
|
|
872
923
|
}
|
|
873
924
|
|
|
874
|
-
|
|
875
|
-
|
|
925
|
+
/* The block and the conversion of its value can raise, so a scratch
|
|
926
|
+
too wide for buf is Ruby's temporary. */
|
|
927
|
+
scratch = (st->out_bytes <= (ca_size_t) sizeof(buf))
|
|
928
|
+
? buf : ALLOCV_N(char, scratch_holder, st->out_bytes);
|
|
876
929
|
|
|
877
930
|
while ( ca_iter_state_next_slab_axes(st->t1, &p_in, &m_in) ) {
|
|
878
931
|
VALUE result;
|
|
@@ -891,7 +944,6 @@ ca_slab_run_reduce_slab (ca_slab_iter_state_t *st)
|
|
|
891
944
|
if ( rb_obj_is_kind_of(result, rb_cCArray) ) {
|
|
892
945
|
CArray *res;
|
|
893
946
|
TypedData_Get_Struct(result, CArray, &carray_data_type, res);
|
|
894
|
-
if ( scratch != buf ) xfree(scratch);
|
|
895
947
|
rb_raise(rb_eArgError,
|
|
896
948
|
"CArray#reduce_slab: per-slab block must return a scalar "
|
|
897
949
|
"(got CArray with %lld element%s; use `slab[0]` or "
|
|
@@ -905,7 +957,7 @@ ca_slab_run_reduce_slab (ca_slab_iter_state_t *st)
|
|
|
905
957
|
out_idx++;
|
|
906
958
|
}
|
|
907
959
|
|
|
908
|
-
|
|
960
|
+
ALLOCV_END(scratch_holder);
|
|
909
961
|
return st->output;
|
|
910
962
|
}
|
|
911
963
|
|
|
@@ -926,6 +978,7 @@ ca_slab_run_reduce_fiber (ca_slab_iter_state_t *st)
|
|
|
926
978
|
ca_size_t out_idx = 0;
|
|
927
979
|
char buf[64];
|
|
928
980
|
char *scratch;
|
|
981
|
+
volatile VALUE scratch_holder = 0; /* 0, not Qnil: ALLOCV_END reads a non-zero holder */
|
|
929
982
|
|
|
930
983
|
ca_slab_reduce_setup(st, &src, &fiber_len);
|
|
931
984
|
TypedData_Get_Struct(st->output, CArray, &carray_data_type, out);
|
|
@@ -935,8 +988,10 @@ ca_slab_run_reduce_fiber (ca_slab_iter_state_t *st)
|
|
|
935
988
|
TypedData_Get_Struct(st->carrier, CAWrap, &cawrap_data_type, carrier_cw);
|
|
936
989
|
}
|
|
937
990
|
|
|
938
|
-
|
|
939
|
-
|
|
991
|
+
/* The block and the conversion of its value can raise, so a scratch
|
|
992
|
+
too wide for buf is Ruby's temporary. */
|
|
993
|
+
scratch = (st->out_bytes <= (ca_size_t) sizeof(buf))
|
|
994
|
+
? buf : ALLOCV_N(char, scratch_holder, st->out_bytes);
|
|
940
995
|
|
|
941
996
|
while ( ca_iter_state_next_slab_axes(st->t1, &p_in, &m_in) ) {
|
|
942
997
|
VALUE acc;
|
|
@@ -971,7 +1026,7 @@ ca_slab_run_reduce_fiber (ca_slab_iter_state_t *st)
|
|
|
971
1026
|
out_idx++;
|
|
972
1027
|
}
|
|
973
1028
|
|
|
974
|
-
|
|
1029
|
+
ALLOCV_END(scratch_holder);
|
|
975
1030
|
return st->output;
|
|
976
1031
|
}
|
|
977
1032
|
|
|
@@ -1055,11 +1110,56 @@ slab_state_run_body (VALUE arg)
|
|
|
1055
1110
|
return Qnil;
|
|
1056
1111
|
}
|
|
1057
1112
|
|
|
1113
|
+
/* The slab views outlive the walk: the block may keep the slab or a view
|
|
1114
|
+
of it (`row.dup`), and the GC marks an object array's cells for as long
|
|
1115
|
+
as it has a ptr. Before the scratch they point into is freed, the
|
|
1116
|
+
input slab and its carrier are moved onto a copy of the last slab,
|
|
1117
|
+
held by the carrier, and the internal output view lets go of its
|
|
1118
|
+
buffer. A slab that is a window onto the source itself points into
|
|
1119
|
+
the source and needs nothing. */
|
|
1120
|
+
static void
|
|
1121
|
+
slab_state_release_views (ca_slab_iter_state_t *st)
|
|
1122
|
+
{
|
|
1123
|
+
if ( st->output_slab_view != Qnil ) {
|
|
1124
|
+
CArray *ov;
|
|
1125
|
+
TypedData_Get_Struct(st->output_slab_view, CArray, &carray_data_type, ov);
|
|
1126
|
+
ov->ptr = NULL;
|
|
1127
|
+
}
|
|
1128
|
+
if ( st->carrier != Qnil && st->slab_view != Qnil ) {
|
|
1129
|
+
CArray *cw, *cs, *backing;
|
|
1130
|
+
volatile VALUE bv;
|
|
1131
|
+
TypedData_Get_Struct(st->carrier, CArray, &carray_data_type, cw);
|
|
1132
|
+
TypedData_Get_Struct(st->slab_view, CArray, &carray_data_type, cs);
|
|
1133
|
+
if ( cw->ptr == NULL ) {
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
backing = ca_copy(cw);
|
|
1137
|
+
bv = ca_wrap_struct(backing);
|
|
1138
|
+
if ( cw->mask && ! backing->mask ) {
|
|
1139
|
+
ca_create_mask(backing);
|
|
1140
|
+
}
|
|
1141
|
+
rb_ivar_set(st->carrier, rb_intern("__slab_backing__"), bv);
|
|
1142
|
+
if ( cs->ptr ) {
|
|
1143
|
+
cs->ptr = backing->ptr;
|
|
1144
|
+
}
|
|
1145
|
+
if ( cs->mask && cs->mask->ptr ) {
|
|
1146
|
+
cs->mask->ptr = backing->mask->ptr;
|
|
1147
|
+
}
|
|
1148
|
+
cw->ptr = backing->ptr;
|
|
1149
|
+
if ( cw->mask ) {
|
|
1150
|
+
cw->mask->ptr = backing->mask->ptr;
|
|
1151
|
+
}
|
|
1152
|
+
RB_GC_GUARD(bv);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1058
1156
|
static VALUE
|
|
1059
1157
|
slab_state_finish (VALUE arg)
|
|
1060
1158
|
{
|
|
1061
1159
|
ca_slab_iter_state_t *st = (ca_slab_iter_state_t *)(uintptr_t) arg;
|
|
1062
1160
|
|
|
1161
|
+
slab_state_release_views(st);
|
|
1162
|
+
|
|
1063
1163
|
/* T1 substrate teardown.
|
|
1064
1164
|
CAREFUL: ca_detach(slab_view) is NEVER called — T1 owns the buffer;
|
|
1065
1165
|
dropping the VALUE handles lets GC reclaim the CAStride wrappers
|
|
@@ -1124,7 +1224,7 @@ static VALUE
|
|
|
1124
1224
|
slab_extract_kwargs (int argc, VALUE *argv, const char *method_name)
|
|
1125
1225
|
{
|
|
1126
1226
|
VALUE kw = Qnil;
|
|
1127
|
-
if ( argc == 1 && RB_TYPE_P(argv[0], T_HASH) ) {
|
|
1227
|
+
if ( argc == 1 && rb_keyword_given_p() && RB_TYPE_P(argv[0], T_HASH) ) {
|
|
1128
1228
|
kw = argv[0];
|
|
1129
1229
|
}
|
|
1130
1230
|
else if ( argc != 0 ) {
|