carray 3.0.1 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
|
@@ -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
|
|
@@ -460,6 +458,19 @@ ca_slab_setup_input_slab_view (ca_slab_iter_state_t *st, CArray *src,
|
|
|
460
458
|
}
|
|
461
459
|
}
|
|
462
460
|
|
|
461
|
+
/* The slab is a window onto the source when the fiber is contiguous and
|
|
462
|
+
a copy in the iterator's scratch when it is not, so writing through it
|
|
463
|
+
landed on one axis and vanished on the next. Nothing in the surface
|
|
464
|
+
said which you would get. Refuse the write on both instead: the block
|
|
465
|
+
forms that produce values (map_slab, reduce_slab) hand their result
|
|
466
|
+
back rather than writing into the slab, and an in-place walk belongs
|
|
467
|
+
to `ca[] = ...` or a C kernel with CA_KERNEL_WRITE. */
|
|
468
|
+
{
|
|
469
|
+
CArray *slab;
|
|
470
|
+
TypedData_Get_Struct(st->slab_view, CArray, &carray_data_type, slab);
|
|
471
|
+
ca_set_flag(slab, CA_FLAG_READ_ONLY);
|
|
472
|
+
}
|
|
473
|
+
|
|
463
474
|
return in_alias;
|
|
464
475
|
}
|
|
465
476
|
|
|
@@ -512,6 +523,44 @@ ca_slab_advance_slab_view (ca_slab_iter_state_t *st,
|
|
|
512
523
|
}
|
|
513
524
|
}
|
|
514
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
|
+
|
|
515
564
|
/* Convert a Ruby Numeric scalar into bytes of slab_view's data_type and
|
|
516
565
|
fill the entire slab buffer at out_ptr. Used when the user block
|
|
517
566
|
returns a scalar instead of a CArray (= broadcast over the slab).
|
|
@@ -520,9 +569,6 @@ static void
|
|
|
520
569
|
ca_slab_fill_scalar (VALUE source, char *out_ptr, ca_size_t slab_elements,
|
|
521
570
|
int8_t out_data_type, ca_size_t out_bytes, VALUE val)
|
|
522
571
|
{
|
|
523
|
-
char buf[64];
|
|
524
|
-
char *scratch = (out_bytes <= (ca_size_t) sizeof(buf)) ? buf
|
|
525
|
-
: xmalloc(out_bytes);
|
|
526
572
|
ca_size_t i;
|
|
527
573
|
/* Use source's data_type-aware conversion (rb_ca_obj2ptr looks at the
|
|
528
574
|
receiver's data_type). Build a stand-in scalar buffer via the
|
|
@@ -533,18 +579,51 @@ ca_slab_fill_scalar (VALUE source, char *out_ptr, ca_size_t slab_elements,
|
|
|
533
579
|
conversion through the actual output entity (= we already have
|
|
534
580
|
`source`-keyed obj2ptr in carray_cast.c). Here we construct an
|
|
535
581
|
ephemeral CScalar of the output data_type to anchor the cast. */
|
|
536
|
-
VALUE cs_anchor =
|
|
582
|
+
volatile VALUE cs_anchor =
|
|
537
583
|
rb_cscalar_new_with_value((int) out_data_type, (int) out_bytes, val);
|
|
538
584
|
CScalar *anchor_ca;
|
|
539
585
|
(void) source;
|
|
540
586
|
TypedData_Get_Struct(cs_anchor, CScalar, &cscalar_data_type, anchor_ca);
|
|
541
|
-
ca_attach(anchor_ca);
|
|
542
|
-
memcpy(scratch, anchor_ca->ptr, out_bytes);
|
|
543
|
-
ca_detach(anchor_ca);
|
|
544
587
|
for ( i = 0; i < slab_elements; i++ ) {
|
|
545
|
-
memcpy(out_ptr + i * out_bytes,
|
|
588
|
+
memcpy(out_ptr + i * out_bytes, anchor_ca->ptr, out_bytes);
|
|
546
589
|
}
|
|
547
|
-
|
|
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);
|
|
624
|
+
}
|
|
625
|
+
ALLOCV_END(holder);
|
|
626
|
+
return Qnil;
|
|
548
627
|
}
|
|
549
628
|
|
|
550
629
|
static VALUE
|
|
@@ -560,16 +639,13 @@ ca_slab_run_map (ca_slab_iter_state_t *st)
|
|
|
560
639
|
|
|
561
640
|
TypedData_Get_Struct(st->self, CArray, &carray_data_type, src);
|
|
562
641
|
|
|
563
|
-
/*
|
|
564
|
-
|
|
565
|
-
is intentionally NOT scattered — block return CArray mask info is
|
|
566
|
-
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). */
|
|
567
644
|
|
|
568
645
|
/* Step 1: allocate output entity (same shape as src, data_type from opts). */
|
|
569
646
|
st->output = rb_carray_new(st->out_data_type, src->ndim, src->dim,
|
|
570
647
|
st->out_bytes, NULL);
|
|
571
648
|
TypedData_Get_Struct(st->output, CArray, &carray_data_type, out);
|
|
572
|
-
ca_allocate(out); /* entity ptr usable as both read + write target */
|
|
573
649
|
|
|
574
650
|
/* Step 2: T1 init on both sides. FIBER_CONTIG is naxes==1 only;
|
|
575
651
|
multi-axis omits it. Output side gets CA_KERNEL_WRITE. */
|
|
@@ -685,34 +761,22 @@ ca_slab_run_map (ca_slab_iter_state_t *st)
|
|
|
685
761
|
(long long) slab_elements, (int) slab_cs->ndim);
|
|
686
762
|
}
|
|
687
763
|
if ( res->data_type == st->out_data_type && res->bytes == st->out_bytes ) {
|
|
688
|
-
ca_attach(res);
|
|
689
764
|
ca_xfer_all(res, write_target, CA_XFER_GET);
|
|
690
|
-
ca_detach(res);
|
|
691
765
|
}
|
|
692
766
|
else {
|
|
693
767
|
/* Cast-on-scatter via per-cell obj2ptr. Writes to write_target
|
|
694
|
-
(= either p_out direct or own_out_scratch).
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
int8_t k;
|
|
705
|
-
for ( k = res->ndim - 1; k >= 0; k-- ) {
|
|
706
|
-
idx[k] = flat % res->dim[k];
|
|
707
|
-
flat /= res->dim[k];
|
|
708
|
-
}
|
|
709
|
-
elem = rb_ca_fetch_index(result, idx);
|
|
710
|
-
rb_ca_obj2ptr(st->output_slab_view, elem, scratch);
|
|
711
|
-
memcpy(write_target + i * st->out_bytes, scratch, st->out_bytes);
|
|
712
|
-
}
|
|
713
|
-
ca_detach(res);
|
|
714
|
-
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);
|
|
715
778
|
}
|
|
779
|
+
ca_map_slab_carry_mask(st, out, res, slab_elements);
|
|
716
780
|
}
|
|
717
781
|
else if ( rb_obj_is_kind_of(result, rb_cNumeric) ||
|
|
718
782
|
result == Qtrue || result == Qfalse ||
|
|
@@ -807,7 +871,6 @@ ca_slab_reduce_setup (ca_slab_iter_state_t *st, CArray **out_src,
|
|
|
807
871
|
st->output = rb_carray_new(st->out_data_type, out_ndim, out_dim,
|
|
808
872
|
st->out_bytes, NULL);
|
|
809
873
|
TypedData_Get_Struct(st->output, CArray, &carray_data_type, out);
|
|
810
|
-
ca_allocate(out);
|
|
811
874
|
|
|
812
875
|
/* FIBER_CONTIG is naxes==1 only (T1 substrate contract). Multi-axis
|
|
813
876
|
omits the flag and uses bare CA_SLAB_AXES; T1 picks an in-src
|
|
@@ -849,6 +912,7 @@ ca_slab_run_reduce_slab (ca_slab_iter_state_t *st)
|
|
|
849
912
|
ca_size_t out_idx = 0;
|
|
850
913
|
char buf[64];
|
|
851
914
|
char *scratch;
|
|
915
|
+
volatile VALUE scratch_holder = 0; /* 0, not Qnil: ALLOCV_END reads a non-zero holder */
|
|
852
916
|
|
|
853
917
|
ca_slab_reduce_setup(st, &src, &fiber_len);
|
|
854
918
|
TypedData_Get_Struct(st->output, CArray, &carray_data_type, out);
|
|
@@ -858,8 +922,10 @@ ca_slab_run_reduce_slab (ca_slab_iter_state_t *st)
|
|
|
858
922
|
TypedData_Get_Struct(st->carrier, CAWrap, &cawrap_data_type, carrier_cw);
|
|
859
923
|
}
|
|
860
924
|
|
|
861
|
-
|
|
862
|
-
|
|
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);
|
|
863
929
|
|
|
864
930
|
while ( ca_iter_state_next_slab_axes(st->t1, &p_in, &m_in) ) {
|
|
865
931
|
VALUE result;
|
|
@@ -878,7 +944,6 @@ ca_slab_run_reduce_slab (ca_slab_iter_state_t *st)
|
|
|
878
944
|
if ( rb_obj_is_kind_of(result, rb_cCArray) ) {
|
|
879
945
|
CArray *res;
|
|
880
946
|
TypedData_Get_Struct(result, CArray, &carray_data_type, res);
|
|
881
|
-
if ( scratch != buf ) xfree(scratch);
|
|
882
947
|
rb_raise(rb_eArgError,
|
|
883
948
|
"CArray#reduce_slab: per-slab block must return a scalar "
|
|
884
949
|
"(got CArray with %lld element%s; use `slab[0]` or "
|
|
@@ -892,7 +957,7 @@ ca_slab_run_reduce_slab (ca_slab_iter_state_t *st)
|
|
|
892
957
|
out_idx++;
|
|
893
958
|
}
|
|
894
959
|
|
|
895
|
-
|
|
960
|
+
ALLOCV_END(scratch_holder);
|
|
896
961
|
return st->output;
|
|
897
962
|
}
|
|
898
963
|
|
|
@@ -913,6 +978,7 @@ ca_slab_run_reduce_fiber (ca_slab_iter_state_t *st)
|
|
|
913
978
|
ca_size_t out_idx = 0;
|
|
914
979
|
char buf[64];
|
|
915
980
|
char *scratch;
|
|
981
|
+
volatile VALUE scratch_holder = 0; /* 0, not Qnil: ALLOCV_END reads a non-zero holder */
|
|
916
982
|
|
|
917
983
|
ca_slab_reduce_setup(st, &src, &fiber_len);
|
|
918
984
|
TypedData_Get_Struct(st->output, CArray, &carray_data_type, out);
|
|
@@ -922,8 +988,10 @@ ca_slab_run_reduce_fiber (ca_slab_iter_state_t *st)
|
|
|
922
988
|
TypedData_Get_Struct(st->carrier, CAWrap, &cawrap_data_type, carrier_cw);
|
|
923
989
|
}
|
|
924
990
|
|
|
925
|
-
|
|
926
|
-
|
|
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);
|
|
927
995
|
|
|
928
996
|
while ( ca_iter_state_next_slab_axes(st->t1, &p_in, &m_in) ) {
|
|
929
997
|
VALUE acc;
|
|
@@ -958,7 +1026,7 @@ ca_slab_run_reduce_fiber (ca_slab_iter_state_t *st)
|
|
|
958
1026
|
out_idx++;
|
|
959
1027
|
}
|
|
960
1028
|
|
|
961
|
-
|
|
1029
|
+
ALLOCV_END(scratch_holder);
|
|
962
1030
|
return st->output;
|
|
963
1031
|
}
|
|
964
1032
|
|
|
@@ -1042,11 +1110,56 @@ slab_state_run_body (VALUE arg)
|
|
|
1042
1110
|
return Qnil;
|
|
1043
1111
|
}
|
|
1044
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
|
+
|
|
1045
1156
|
static VALUE
|
|
1046
1157
|
slab_state_finish (VALUE arg)
|
|
1047
1158
|
{
|
|
1048
1159
|
ca_slab_iter_state_t *st = (ca_slab_iter_state_t *)(uintptr_t) arg;
|
|
1049
1160
|
|
|
1161
|
+
slab_state_release_views(st);
|
|
1162
|
+
|
|
1050
1163
|
/* T1 substrate teardown.
|
|
1051
1164
|
CAREFUL: ca_detach(slab_view) is NEVER called — T1 owns the buffer;
|
|
1052
1165
|
dropping the VALUE handles lets GC reclaim the CAStride wrappers
|
|
@@ -1111,7 +1224,7 @@ static VALUE
|
|
|
1111
1224
|
slab_extract_kwargs (int argc, VALUE *argv, const char *method_name)
|
|
1112
1225
|
{
|
|
1113
1226
|
VALUE kw = Qnil;
|
|
1114
|
-
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) ) {
|
|
1115
1228
|
kw = argv[0];
|
|
1116
1229
|
}
|
|
1117
1230
|
else if ( argc != 0 ) {
|