carray 3.0.4 → 3.0.5
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 +205 -0
- data/carray.gemspec +1 -1
- data/ext/ca_array_pool.c +25 -1
- data/ext/ca_axis_dispatch.c +13 -20
- data/ext/ca_categorical_iterator.c +27 -20
- data/ext/ca_compare.c +4 -4
- data/ext/ca_composite_dispatch.c +9 -9
- data/ext/ca_kernel_iterator.c +6 -6
- data/ext/ca_kernel_iterator.h +112 -83
- data/ext/ca_obj_array.c +69 -19
- data/ext/ca_obj_bincmp.c +1 -0
- data/ext/ca_obj_binop.c +1 -0
- data/ext/ca_obj_bitarray.c +5 -1
- data/ext/ca_obj_bitfield.c +58 -43
- data/ext/ca_obj_byte_swap.c +2 -1
- data/ext/ca_obj_const_string.c +15 -3
- data/ext/ca_obj_face.c +42 -1
- data/ext/ca_obj_field.c +13 -3
- data/ext/ca_obj_grid.c +52 -5
- data/ext/ca_obj_monop.c +46 -10
- data/ext/ca_obj_object.c +64 -12
- data/ext/ca_obj_record.c +3 -0
- data/ext/ca_obj_reduce.c +4 -0
- data/ext/ca_obj_refer.c +18 -9
- data/ext/ca_obj_roll.c +26 -6
- data/ext/ca_obj_select.c +34 -5
- data/ext/ca_obj_shift.c +31 -7
- data/ext/ca_obj_stack.c +1 -0
- data/ext/ca_obj_stride.c +28 -19
- data/ext/ca_obj_string.c +11 -2
- data/ext/ca_obj_tile.c +27 -7
- data/ext/ca_obj_transpose.c +8 -4
- data/ext/ca_obj_triop.c +3 -0
- data/ext/ca_obj_window.c +79 -50
- data/ext/ca_op_ipower.c +4 -4
- data/ext/ca_sort_kernels.h +6 -3
- data/ext/carray.h +33 -0
- data/ext/carray_access.c +16 -3
- data/ext/carray_attribute.c +24 -0
- data/ext/carray_cast.c +243 -82
- data/ext/carray_cast_func.rb +56 -26
- data/ext/carray_conversion.c +2 -2
- data/ext/carray_core.c +3 -0
- data/ext/carray_count.c +6 -0
- data/ext/carray_element.c +9 -4
- data/ext/carray_factorize.c +20 -20
- data/ext/carray_generate.c +8 -2
- data/ext/carray_histogram.c +1 -1
- data/ext/carray_index_classifier.c +4 -4
- data/ext/carray_internal.h +12 -0
- data/ext/carray_kernels_bincmp.c +168 -168
- data/ext/carray_kernels_binop.c +900 -900
- data/ext/carray_kernels_init.c +4 -4
- data/ext/carray_kernels_moncmp.c +96 -96
- data/ext/carray_kernels_monop.c +1984 -1984
- data/ext/carray_kernels_reduce_aggregate.c +1733 -1733
- data/ext/carray_kernels_reduce_cumulative.c +642 -642
- data/ext/carray_kernels_reduce_extreme.c +1150 -1150
- data/ext/carray_kernels_reduce_variance.c +258 -258
- data/ext/carray_kernels_scan.c +128 -128
- data/ext/carray_kernels_search.c +340 -340
- data/ext/carray_kernels_sort.c +295 -304
- data/ext/carray_kernels_triop.c +114 -114
- data/ext/carray_key_windows.c +4 -0
- data/ext/carray_mask.c +45 -22
- data/ext/carray_memory_view.c +2 -2
- data/ext/carray_operator.c +5 -5
- data/ext/carray_order.c +227 -8
- data/ext/carray_random.c +18 -18
- data/ext/carray_scatter.c +24 -7
- data/ext/carray_slab.c +32 -9
- data/ext/carray_sort.c +224 -16
- data/ext/carray_sort_kernel.c +5 -7
- data/ext/carray_struct.c +35 -43
- data/ext/carray_time_text.c +4 -2
- data/ext/carray_utils.c +63 -21
- data/ext/mkkernel.rb +210 -115
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +17 -4
- data/lib/carray/basics.rb +27 -7
- data/lib/carray/categorical.rb +30 -16
- data/lib/carray/categorical_iterator.rb +6 -6
- data/lib/carray/const_string.rb +10 -0
- data/lib/carray/data_type_extension.rb +8 -1
- data/lib/carray/fixlen_string.rb +41 -2
- data/lib/carray/frame/column_verbs.rb +4 -3
- data/lib/carray/frame/concat.rb +17 -3
- data/lib/carray/frame/frame.rb +6 -7
- data/lib/carray/frame/group.rb +100 -13
- data/lib/carray/frame/io.rb +3 -1
- data/lib/carray/fuse_source.rb +31 -2
- data/lib/carray/lazy.rb +35 -0
- data/lib/carray/methods/is_in.rb +8 -1
- data/lib/carray/segment_iterator.rb +12 -8
- data/lib/carray/serialize.rb +19 -2
- data/lib/carray/stack.rb +15 -12
- data/lib/carray/string.rb +8 -0
- data/lib/carray/string_operation_extension.rb +13 -5
- data/lib/carray/struct_builder.rb +5 -3
- data/lib/carray/time.rb +107 -68
- data/yard-stubs/ca_obj_transpose.rb +5 -4
- data/yard-stubs/carray_attribute.rb +3 -1
- data/yard-stubs/carray_cast.rb +2 -0
- data/yard-stubs/carray_conversion.rb +5 -1
- data/yard-stubs/carray_element.rb +7 -6
- data/yard-stubs/carray_mask.rb +8 -3
- data/yard-stubs/carray_math.rb +14 -4
- data/yard-stubs/carray_order.rb +100 -4
- data/yard-stubs/carray_scatter.rb +7 -5
- metadata +1 -1
data/ext/carray_sort.c
CHANGED
|
@@ -103,16 +103,207 @@ sort_addr_merge (struct sort_addr_key *a, struct sort_addr_key *aux,
|
|
|
103
103
|
ca_size_t n, int (*cmp)(const void *, const void *))
|
|
104
104
|
CA_SORT_MERGE_BY_CMP(struct sort_addr_key)
|
|
105
105
|
|
|
106
|
+
/* -------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
Multi-key sort by refinement (MSD), for keys of the numeric data types.
|
|
109
|
+
|
|
110
|
+
The first key is sorted whole by the typed pair kernel
|
|
111
|
+
(ca_sort_quick_pair_*); then only the runs of rows that tie on it are
|
|
112
|
+
sorted by the second key, and so on, until no run is left or the keys
|
|
113
|
+
run out. The answer is the one sort_addr_cmp gives:
|
|
114
|
+
|
|
115
|
+
- a pair sorts by (value, row), so rows that tie on every key stay in
|
|
116
|
+
row order (the stable tie-break of sort_addr_cmp);
|
|
117
|
+
- each run is split into numbers, NaN and masked cells, in the order
|
|
118
|
+
sort_addr_cmp puts them (numbers, NaN, masked for masked_last;
|
|
119
|
+
masked, numbers, NaN otherwise). The NaN and the masked cells of a
|
|
120
|
+
run tie among themselves (CA_FLOAT_ORDER_CMP / sort_addr_cmp), so
|
|
121
|
+
each is a run for the next key. The split is a stable one done in
|
|
122
|
+
the load, not ca_partition_nan_pair_*, which allocates on every call
|
|
123
|
+
and is called here once per run;
|
|
124
|
+
- -0.0 and 0.0 tie, by == as by CA_FLOAT_ORDER_CMP.
|
|
125
|
+
|
|
126
|
+
A run is (lo, n): the rows perm[lo..lo+n). Within a run the rows are
|
|
127
|
+
in row order, since they tie on every key before it, so the stable
|
|
128
|
+
split keeps them so.
|
|
129
|
+
|
|
130
|
+
------------------------------------------------------------------- */
|
|
131
|
+
|
|
132
|
+
typedef struct {
|
|
133
|
+
ca_size_t lo;
|
|
134
|
+
ca_size_t n;
|
|
135
|
+
} msd_run_t;
|
|
136
|
+
|
|
137
|
+
typedef struct {
|
|
138
|
+
msd_run_t *runs;
|
|
139
|
+
ca_size_t count;
|
|
140
|
+
} msd_runs_t;
|
|
141
|
+
|
|
142
|
+
static void
|
|
143
|
+
msd_add_run (msd_runs_t *out, ca_size_t lo, ca_size_t n)
|
|
144
|
+
{
|
|
145
|
+
if ( out && n > 1 ) {
|
|
146
|
+
out->runs[out->count].lo = lo;
|
|
147
|
+
out->runs[out->count].n = n;
|
|
148
|
+
out->count++;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* Sort each run of +in+ by +key+, writing the new order into perm, and
|
|
153
|
+
add the runs that still tie to +out+ (NULL for the last key). */
|
|
154
|
+
#define DEFINE_MSD_REFINE(TYPE, SUFFIX, IS_FLOAT) \
|
|
155
|
+
static void \
|
|
156
|
+
msd_refine_##SUFFIX (CArray *key, ca_size_t *perm, void *vbuf, \
|
|
157
|
+
msd_runs_t *in, msd_runs_t *out, int masked_last) \
|
|
158
|
+
{ \
|
|
159
|
+
const TYPE *ptr = (const TYPE *) key->ptr; \
|
|
160
|
+
const boolean8_t *m = ( key->mask ) ? (boolean8_t *) key->mask->ptr : NULL; \
|
|
161
|
+
ca_pair_##SUFFIX *buf = (ca_pair_##SUFFIX *) vbuf; \
|
|
162
|
+
ca_size_t r; \
|
|
163
|
+
\
|
|
164
|
+
for (r=0; r<in->count; r++) { \
|
|
165
|
+
ca_size_t lo = in->runs[r].lo; \
|
|
166
|
+
ca_size_t n = in->runs[r].n; \
|
|
167
|
+
ca_size_t *p = perm + lo; \
|
|
168
|
+
ca_size_t n_num = 0, n_nan = 0, n_mask = 0; \
|
|
169
|
+
ca_size_t o_num, o_nan, o_mask; \
|
|
170
|
+
ca_size_t k, s; \
|
|
171
|
+
\
|
|
172
|
+
for (k=0; k<n; k++) { \
|
|
173
|
+
ca_size_t row = p[k]; \
|
|
174
|
+
if ( m && m[row] ) n_mask++; \
|
|
175
|
+
else if ( IS_FLOAT && isnan((double) ptr[row]) ) n_nan++; \
|
|
176
|
+
else n_num++; \
|
|
177
|
+
} \
|
|
178
|
+
o_mask = masked_last ? n_num + n_nan : 0; \
|
|
179
|
+
o_num = masked_last ? 0 : n_mask; \
|
|
180
|
+
o_nan = o_num + n_num; \
|
|
181
|
+
{ \
|
|
182
|
+
ca_size_t i_num = o_num, i_nan = o_nan, i_mask = o_mask; \
|
|
183
|
+
for (k=0; k<n; k++) { \
|
|
184
|
+
ca_size_t row = p[k]; \
|
|
185
|
+
TYPE v = ptr[row]; \
|
|
186
|
+
ca_size_t at; \
|
|
187
|
+
if ( m && m[row] ) at = i_mask++; \
|
|
188
|
+
else if ( IS_FLOAT && isnan((double) v) ) at = i_nan++; \
|
|
189
|
+
else at = i_num++; \
|
|
190
|
+
buf[at].v = v; \
|
|
191
|
+
buf[at].i = row; \
|
|
192
|
+
} \
|
|
193
|
+
} \
|
|
194
|
+
ca_sort_quick_pair_##SUFFIX(buf + o_num, n_num); \
|
|
195
|
+
for (k=0; k<n; k++) { \
|
|
196
|
+
p[k] = buf[k].i; \
|
|
197
|
+
} \
|
|
198
|
+
if ( ! out ) continue; \
|
|
199
|
+
for (s=0, k=1; k<=n_num; k++) { \
|
|
200
|
+
if ( k == n_num || buf[o_num + k].v != buf[o_num + s].v ) { \
|
|
201
|
+
msd_add_run(out, lo + o_num + s, k - s); \
|
|
202
|
+
s = k; \
|
|
203
|
+
} \
|
|
204
|
+
} \
|
|
205
|
+
msd_add_run(out, lo + o_nan, n_nan); \
|
|
206
|
+
msd_add_run(out, lo + o_mask, n_mask); \
|
|
207
|
+
} \
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
DEFINE_MSD_REFINE(int8_t, i8, 0)
|
|
211
|
+
DEFINE_MSD_REFINE(uint8_t, u8, 0)
|
|
212
|
+
DEFINE_MSD_REFINE(int16_t, i16, 0)
|
|
213
|
+
DEFINE_MSD_REFINE(uint16_t, u16, 0)
|
|
214
|
+
DEFINE_MSD_REFINE(int32_t, i32, 0)
|
|
215
|
+
DEFINE_MSD_REFINE(uint32_t, u32, 0)
|
|
216
|
+
DEFINE_MSD_REFINE(int64_t, i64, 0)
|
|
217
|
+
DEFINE_MSD_REFINE(uint64_t, u64, 0)
|
|
218
|
+
DEFINE_MSD_REFINE(float32_t, f32, 1)
|
|
219
|
+
DEFINE_MSD_REFINE(double, f64, 1)
|
|
220
|
+
|
|
221
|
+
/* Whether every key has a typed pair kernel, so that MSD can sort them. */
|
|
222
|
+
static int
|
|
223
|
+
msd_is_sortable (struct cmp_base *base)
|
|
224
|
+
{
|
|
225
|
+
int j;
|
|
226
|
+
for (j=0; j<base->n; j++) {
|
|
227
|
+
switch ( base->ca[j]->data_type ) {
|
|
228
|
+
case CA_BOOLEAN: case CA_INT8: case CA_UINT8:
|
|
229
|
+
case CA_INT16: case CA_UINT16:
|
|
230
|
+
case CA_INT32: case CA_UINT32:
|
|
231
|
+
case CA_INT64: case CA_UINT64:
|
|
232
|
+
case CA_FLOAT32: case CA_FLOAT64:
|
|
233
|
+
break;
|
|
234
|
+
default:
|
|
235
|
+
return 0;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return 1;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
typedef struct {
|
|
242
|
+
struct cmp_base *base;
|
|
243
|
+
ca_size_t *perm; /* elements rows, the answer */
|
|
244
|
+
void *buf; /* elements pairs of 16 bytes */
|
|
245
|
+
msd_run_t *runs[2]; /* elements / 2 + 1 runs each */
|
|
246
|
+
ca_size_t elements;
|
|
247
|
+
} msd_sort_t;
|
|
248
|
+
|
|
249
|
+
static void
|
|
250
|
+
msd_sort (msd_sort_t *s)
|
|
251
|
+
{
|
|
252
|
+
struct cmp_base *base = s->base;
|
|
253
|
+
msd_runs_t a, b, *in = &a, *out = &b;
|
|
254
|
+
ca_size_t i;
|
|
255
|
+
int j;
|
|
256
|
+
|
|
257
|
+
for (i=0; i<s->elements; i++) {
|
|
258
|
+
s->perm[i] = i;
|
|
259
|
+
}
|
|
260
|
+
a.runs = s->runs[0]; a.count = 0;
|
|
261
|
+
b.runs = s->runs[1]; b.count = 0;
|
|
262
|
+
msd_add_run(in, 0, s->elements);
|
|
263
|
+
|
|
264
|
+
for (j=0; j<base->n && in->count > 0; j++) {
|
|
265
|
+
CArray *key = base->ca[j];
|
|
266
|
+
msd_runs_t *next = ( j < base->n - 1 ) ? out : NULL;
|
|
267
|
+
msd_runs_t *t;
|
|
268
|
+
if ( next ) next->count = 0;
|
|
269
|
+
switch ( key->data_type ) {
|
|
270
|
+
case CA_BOOLEAN:
|
|
271
|
+
case CA_INT8: msd_refine_i8 (key, s->perm, s->buf, in, next, base->masked_last); break;
|
|
272
|
+
case CA_UINT8: msd_refine_u8 (key, s->perm, s->buf, in, next, base->masked_last); break;
|
|
273
|
+
case CA_INT16: msd_refine_i16(key, s->perm, s->buf, in, next, base->masked_last); break;
|
|
274
|
+
case CA_UINT16: msd_refine_u16(key, s->perm, s->buf, in, next, base->masked_last); break;
|
|
275
|
+
case CA_INT32: msd_refine_i32(key, s->perm, s->buf, in, next, base->masked_last); break;
|
|
276
|
+
case CA_UINT32: msd_refine_u32(key, s->perm, s->buf, in, next, base->masked_last); break;
|
|
277
|
+
case CA_INT64: msd_refine_i64(key, s->perm, s->buf, in, next, base->masked_last); break;
|
|
278
|
+
case CA_UINT64: msd_refine_u64(key, s->perm, s->buf, in, next, base->masked_last); break;
|
|
279
|
+
case CA_FLOAT32: msd_refine_f32(key, s->perm, s->buf, in, next, base->masked_last); break;
|
|
280
|
+
case CA_FLOAT64: msd_refine_f64(key, s->perm, s->buf, in, next, base->masked_last); break;
|
|
281
|
+
default:
|
|
282
|
+
rb_raise(rb_eRuntimeError, "%s: [BUG] data type %d has no pair kernel",
|
|
283
|
+
ca_calling_method_name(), (int) key->data_type);
|
|
284
|
+
}
|
|
285
|
+
if ( ! next ) break;
|
|
286
|
+
t = in; in = out; out = t;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* ----------------------------------------------------------------- */
|
|
291
|
+
|
|
106
292
|
typedef struct {
|
|
107
293
|
struct sort_addr_key *data;
|
|
108
294
|
struct sort_addr_key *aux; /* NULL: no object key, libc sorts */
|
|
109
295
|
ca_size_t elements;
|
|
296
|
+
msd_sort_t *msd; /* non-NULL: every key is numeric, sort by MSD */
|
|
110
297
|
} sort_addr_run_t;
|
|
111
298
|
|
|
112
299
|
static VALUE
|
|
113
300
|
sort_addr_run (VALUE arg)
|
|
114
301
|
{
|
|
115
302
|
sort_addr_run_t *r = (sort_addr_run_t *) arg;
|
|
303
|
+
if ( r->msd ) {
|
|
304
|
+
msd_sort(r->msd);
|
|
305
|
+
return Qnil;
|
|
306
|
+
}
|
|
116
307
|
if ( r->aux ) {
|
|
117
308
|
sort_addr_merge(r->data, r->aux, r->elements,
|
|
118
309
|
(int (*)(const void*,const void*)) sort_addr_cmp);
|
|
@@ -145,8 +336,9 @@ rb_ca_s_sort_addr_kw (int argc, VALUE *argv, VALUE ropt, VALUE self)
|
|
|
145
336
|
CArray *co;
|
|
146
337
|
struct cmp_base base_s, *base = &base_s;
|
|
147
338
|
struct sort_addr_key *data;
|
|
148
|
-
volatile VALUE hlist = 0, hdata = 0, haux = 0, hmodes = 0;
|
|
339
|
+
volatile VALUE hlist = 0, hdata = 0, haux = 0, hmodes = 0, hruns0 = 0, hruns1 = 0;
|
|
149
340
|
sort_addr_run_t run;
|
|
341
|
+
msd_sort_t msd;
|
|
150
342
|
char *modes;
|
|
151
343
|
int has_object = 0;
|
|
152
344
|
ca_size_t elements;
|
|
@@ -203,26 +395,42 @@ rb_ca_s_sort_addr_kw (int argc, VALUE *argv, VALUE ropt, VALUE self)
|
|
|
203
395
|
}
|
|
204
396
|
modes[argc] = '\0';
|
|
205
397
|
|
|
206
|
-
data = ALLOCV_N(struct sort_addr_key, hdata, elements);
|
|
207
|
-
for (i=0; i<elements; i++) {
|
|
208
|
-
data[i].i = i;
|
|
209
|
-
data[i].base = base;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
run.data = data;
|
|
213
|
-
run.aux = has_object ? ALLOCV_N(struct sort_addr_key, haux, elements) : NULL;
|
|
214
|
-
run.elements = elements;
|
|
215
|
-
ca_attach_window(argc, base->ca, modes, sort_addr_run, (VALUE) &run);
|
|
216
|
-
|
|
217
398
|
out = rb_ca_template_with_type(argv[0], INT2NUM(CA_SIZE), INT2NUM(0));
|
|
218
399
|
TypedData_Get_Struct(out, CArray, &carray_data_type, co);
|
|
219
400
|
q = (ca_size_t *) co->ptr;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
401
|
+
|
|
402
|
+
run.data = NULL;
|
|
403
|
+
run.aux = NULL;
|
|
404
|
+
run.elements = elements;
|
|
405
|
+
run.msd = NULL;
|
|
406
|
+
|
|
407
|
+
if ( msd_is_sortable(base) ) {
|
|
408
|
+
ca_size_t nruns = elements / 2 + 1;
|
|
409
|
+
msd.base = base;
|
|
410
|
+
msd.perm = q;
|
|
411
|
+
msd.buf = ALLOCV(hdata, (size_t) elements * sizeof(ca_pair_f64));
|
|
412
|
+
msd.runs[0] = ALLOCV_N(msd_run_t, hruns0, nruns);
|
|
413
|
+
msd.runs[1] = ( argc > 1 ) ? ALLOCV_N(msd_run_t, hruns1, nruns) : NULL;
|
|
414
|
+
msd.elements = elements;
|
|
415
|
+
run.msd = &msd;
|
|
416
|
+
ca_attach_window(argc, base->ca, modes, sort_addr_run, (VALUE) &run);
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
data = ALLOCV_N(struct sort_addr_key, hdata, elements);
|
|
420
|
+
for (i=0; i<elements; i++) {
|
|
421
|
+
data[i].i = i;
|
|
422
|
+
data[i].base = base;
|
|
423
|
+
}
|
|
424
|
+
run.data = data;
|
|
425
|
+
run.aux = has_object ? ALLOCV_N(struct sort_addr_key, haux, elements) : NULL;
|
|
426
|
+
ca_attach_window(argc, base->ca, modes, sort_addr_run, (VALUE) &run);
|
|
427
|
+
for (i=0; i<elements; i++) {
|
|
428
|
+
q[i] = data[i].i;
|
|
429
|
+
}
|
|
224
430
|
}
|
|
225
431
|
|
|
432
|
+
ALLOCV_END(hruns1);
|
|
433
|
+
ALLOCV_END(hruns0);
|
|
226
434
|
ALLOCV_END(haux);
|
|
227
435
|
ALLOCV_END(hdata);
|
|
228
436
|
ALLOCV_END(hmodes);
|
data/ext/carray_sort_kernel.c
CHANGED
|
@@ -453,16 +453,15 @@ DEFINE_PARTITION_NAN(double, f64);
|
|
|
453
453
|
preserved), so argsort on NaN-containing input keeps NaN indices
|
|
454
454
|
in ascending order.
|
|
455
455
|
|
|
456
|
-
Implementation: 2-pass stable filter
|
|
457
|
-
|
|
458
|
-
|
|
456
|
+
Implementation: 2-pass stable filter through scratch, n pairs that
|
|
457
|
+
the caller provides. The caller takes it before it opens its walks:
|
|
458
|
+
an allocation here, inside the walk, would raise past their finish. */
|
|
459
459
|
#define DEFINE_PARTITION_NAN_PAIR(TYPE, SUFFIX) \
|
|
460
460
|
ca_size_t \
|
|
461
|
-
ca_partition_nan_pair_##SUFFIX (ca_pair_##SUFFIX *a, ca_size_t n
|
|
461
|
+
ca_partition_nan_pair_##SUFFIX (ca_pair_##SUFFIX *a, ca_size_t n, \
|
|
462
|
+
ca_pair_##SUFFIX *scratch) \
|
|
462
463
|
{ \
|
|
463
464
|
if ( n == 0 ) return 0; \
|
|
464
|
-
ca_pair_##SUFFIX *scratch = \
|
|
465
|
-
(ca_pair_##SUFFIX *) xmalloc((size_t) n * sizeof(ca_pair_##SUFFIX)); \
|
|
466
465
|
ca_size_t fin = 0, nan_pos = 0; \
|
|
467
466
|
for ( ca_size_t k = 0; k < n; k++ ) { \
|
|
468
467
|
if ( !isnan(a[k].v) ) scratch[fin++] = a[k]; \
|
|
@@ -472,7 +471,6 @@ ca_partition_nan_pair_##SUFFIX (ca_pair_##SUFFIX *a, ca_size_t n) \
|
|
|
472
471
|
if ( isnan(a[k].v) ) scratch[finite_count + nan_pos++] = a[k]; \
|
|
473
472
|
} \
|
|
474
473
|
memcpy(a, scratch, (size_t) n * sizeof(ca_pair_##SUFFIX)); \
|
|
475
|
-
xfree(scratch); \
|
|
476
474
|
return finite_count; \
|
|
477
475
|
} \
|
|
478
476
|
struct ca_partition_nan_pair_##SUFFIX##_eat_semicolon
|
data/ext/carray_struct.c
CHANGED
|
@@ -194,20 +194,40 @@ ca_struct_write_primitive_fast (char *p, int type_code, VALUE val)
|
|
|
194
194
|
to keep neighbouring bits untouched.
|
|
195
195
|
--------------------------------------------------------------------- */
|
|
196
196
|
|
|
197
|
+
/* The word's bytes are read and written least significant first on
|
|
198
|
+
every host: the layout numbers the bits byte by byte from the record's
|
|
199
|
+
start, so a field read through a wider word than its neighbour still
|
|
200
|
+
sees the same bits. */
|
|
201
|
+
static uint64_t
|
|
202
|
+
ca_struct_load_le (const char *p, int n)
|
|
203
|
+
{
|
|
204
|
+
uint64_t word = 0;
|
|
205
|
+
int i;
|
|
206
|
+
for (i = 0; i < n; i++) {
|
|
207
|
+
word |= (uint64_t) (uint8_t) p[i] << (8 * i);
|
|
208
|
+
}
|
|
209
|
+
return word;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
static void
|
|
213
|
+
ca_struct_store_le (char *p, int n, uint64_t word)
|
|
214
|
+
{
|
|
215
|
+
int i;
|
|
216
|
+
for (i = 0; i < n; i++) {
|
|
217
|
+
p[i] = (char) (word >> (8 * i));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
197
221
|
static VALUE
|
|
198
222
|
ca_struct_read_bitfield_fast (const char *p, int view_bytes,
|
|
199
223
|
int bit_in_word, int bits)
|
|
200
224
|
{
|
|
201
|
-
uint64_t word
|
|
202
|
-
|
|
203
|
-
case 1: { uint8_t v; memcpy(&v, p, 1); word = v; break; }
|
|
204
|
-
case 2: { uint16_t v; memcpy(&v, p, 2); word = v; break; }
|
|
205
|
-
case 4: { uint32_t v; memcpy(&v, p, 4); word = v; break; }
|
|
206
|
-
case 8: { uint64_t v; memcpy(&v, p, 8); word = v; break; }
|
|
207
|
-
default:
|
|
225
|
+
uint64_t word;
|
|
226
|
+
if ( view_bytes != 1 && view_bytes != 2 && view_bytes != 4 && view_bytes != 8 ) {
|
|
208
227
|
rb_raise(rb_eRuntimeError,
|
|
209
228
|
"[BUG] bitfield view_bytes %d not in {1,2,4,8}", view_bytes);
|
|
210
229
|
}
|
|
230
|
+
word = ca_struct_load_le(p, view_bytes);
|
|
211
231
|
uint64_t mask = (bits >= 64) ? ~(uint64_t)0
|
|
212
232
|
: ((uint64_t)1 << bits) - 1;
|
|
213
233
|
uint64_t val = (word >> bit_in_word) & mask;
|
|
@@ -224,7 +244,11 @@ static void
|
|
|
224
244
|
ca_struct_write_bitfield_fast (char *p, int view_bytes,
|
|
225
245
|
int bit_in_word, int bits, VALUE val)
|
|
226
246
|
{
|
|
227
|
-
uint64_t v;
|
|
247
|
+
uint64_t v, word;
|
|
248
|
+
if ( view_bytes != 1 && view_bytes != 2 && view_bytes != 4 && view_bytes != 8 ) {
|
|
249
|
+
rb_raise(rb_eRuntimeError,
|
|
250
|
+
"[BUG] bitfield view_bytes %d not in {1,2,4,8}", view_bytes);
|
|
251
|
+
}
|
|
228
252
|
if ( bits == 1 ) {
|
|
229
253
|
if ( val == Qtrue || val == INT2FIX(1) ) v = 1;
|
|
230
254
|
else if ( val == Qfalse || val == INT2FIX(0) ) v = 0;
|
|
@@ -240,41 +264,9 @@ ca_struct_write_bitfield_fast (char *p, int view_bytes,
|
|
|
240
264
|
uint64_t mask = (bits >= 64) ? ~(uint64_t)0
|
|
241
265
|
: ((uint64_t)1 << bits) - 1;
|
|
242
266
|
v &= mask;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
case 1: {
|
|
247
|
-
uint8_t word;
|
|
248
|
-
memcpy(&word, p, 1);
|
|
249
|
-
word = (uint8_t)((word & ~(uint8_t)shifted_mask) | (uint8_t)shifted_val);
|
|
250
|
-
memcpy(p, &word, 1);
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
case 2: {
|
|
254
|
-
uint16_t word;
|
|
255
|
-
memcpy(&word, p, 2);
|
|
256
|
-
word = (uint16_t)((word & ~(uint16_t)shifted_mask) | (uint16_t)shifted_val);
|
|
257
|
-
memcpy(p, &word, 2);
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
case 4: {
|
|
261
|
-
uint32_t word;
|
|
262
|
-
memcpy(&word, p, 4);
|
|
263
|
-
word = (uint32_t)((word & ~(uint32_t)shifted_mask) | (uint32_t)shifted_val);
|
|
264
|
-
memcpy(p, &word, 4);
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
case 8: {
|
|
268
|
-
uint64_t word;
|
|
269
|
-
memcpy(&word, p, 8);
|
|
270
|
-
word = (word & ~shifted_mask) | shifted_val;
|
|
271
|
-
memcpy(p, &word, 8);
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
default:
|
|
275
|
-
rb_raise(rb_eRuntimeError,
|
|
276
|
-
"[BUG] bitfield view_bytes %d not in {1,2,4,8}", view_bytes);
|
|
277
|
-
}
|
|
267
|
+
word = ca_struct_load_le(p, view_bytes);
|
|
268
|
+
word = (word & ~(mask << bit_in_word)) | (v << bit_in_word);
|
|
269
|
+
ca_struct_store_le(p, view_bytes, word);
|
|
278
270
|
}
|
|
279
271
|
|
|
280
272
|
/* ---------------------------------------------------------------------
|
data/ext/carray_time_text.c
CHANGED
|
@@ -234,7 +234,9 @@ ca_time_text_read (VALUE str, ca_time_text_t *t, int wide)
|
|
|
234
234
|
}
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
|
-
|
|
237
|
+
/* Second 60 is the leap second; it carries into the next minute below,
|
|
238
|
+
as CArray.time reads it. */
|
|
239
|
+
if ( hour > 24 || min > 59 || sec > 60 ) {
|
|
238
240
|
return CA_TIME_TEXT_UNREADABLE;
|
|
239
241
|
}
|
|
240
242
|
/* Hour 24 is the end of the day, 24:00:00, and nothing past it, as in
|
|
@@ -359,7 +361,7 @@ rb_ca_parse_time_text (int argc, VALUE *argv, VALUE self)
|
|
|
359
361
|
boolean8_t *m_in, *m_out;
|
|
360
362
|
int64_t *days, *nsod, *months, *ticks;
|
|
361
363
|
int64_t per_day = 1, ns_per_tick = 1;
|
|
362
|
-
ID unit;
|
|
364
|
+
ID unit = 0;
|
|
363
365
|
int clock = 0, fraction = 0, coarse = 2, any = 0, wide;
|
|
364
366
|
int calendar = 0; /* 1 ticks of months, 2 of years */
|
|
365
367
|
ca_size_t i;
|
data/ext/carray_utils.c
CHANGED
|
@@ -371,6 +371,10 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
|
|
|
371
371
|
last = NUM2SIZE(x.end);
|
|
372
372
|
excl = RTEST(x.exclude_end);
|
|
373
373
|
step = NUM2SIZE(x.step);
|
|
374
|
+
if ( step == 0 ) {
|
|
375
|
+
rb_raise(rb_eArgError, "%s: step should not be 0",
|
|
376
|
+
ca_calling_method_name());
|
|
377
|
+
}
|
|
374
378
|
if ( excl ) {
|
|
375
379
|
last += ( (last>=start) ? -1 : 1 );
|
|
376
380
|
}
|
|
@@ -391,6 +395,10 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
|
|
|
391
395
|
if ( NIL_P(arg0) ) { /* [nil,k] */
|
|
392
396
|
start = 0;
|
|
393
397
|
step = NUM2SIZE(arg1);
|
|
398
|
+
if ( step == 0 ) {
|
|
399
|
+
rb_raise(rb_eArgError, "%s: step should not be 0",
|
|
400
|
+
ca_calling_method_name());
|
|
401
|
+
}
|
|
394
402
|
count = (size-1)/llabs(step) + 1;
|
|
395
403
|
*poffset = start;
|
|
396
404
|
*pcount = count;
|
|
@@ -401,6 +409,10 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
|
|
|
401
409
|
last = NUM2SIZE(RANGE_END(arg0));
|
|
402
410
|
excl = RTEST(RANGE_EXCL(arg0));
|
|
403
411
|
step = NUM2SIZE(arg1);
|
|
412
|
+
if ( step == 0 ) {
|
|
413
|
+
rb_raise(rb_eArgError, "%s: step should not be 0",
|
|
414
|
+
ca_calling_method_name());
|
|
415
|
+
}
|
|
404
416
|
if ( excl ) {
|
|
405
417
|
last += ( (last>=start) ? -1 : 1 );
|
|
406
418
|
}
|
|
@@ -418,6 +430,10 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
|
|
|
418
430
|
last = NUM2SIZE(x.end);
|
|
419
431
|
excl = RTEST(x.exclude_end);
|
|
420
432
|
step = NUM2SIZE(x.step);
|
|
433
|
+
if ( step == 0 ) {
|
|
434
|
+
rb_raise(rb_eArgError, "%s: step should not be 0",
|
|
435
|
+
ca_calling_method_name());
|
|
436
|
+
}
|
|
421
437
|
if ( excl ) {
|
|
422
438
|
last += ( (last>=start) ? -1 : 1 );
|
|
423
439
|
}
|
|
@@ -922,6 +938,15 @@ ca_reduce_fill (VALUE result, VALUE fill, int whole)
|
|
|
922
938
|
if ( ca_has_mask(cr) ) {
|
|
923
939
|
result = rb_ca_mask_fill_copy(result, fill);
|
|
924
940
|
}
|
|
941
|
+
else if ( cr->elements > 0 ) {
|
|
942
|
+
/* No cell needed the fill, but a fill the result cannot hold is
|
|
943
|
+
refused all the same, not only when some cell happens to be
|
|
944
|
+
undefined: it goes into a one-cell array of the result's kind. */
|
|
945
|
+
volatile VALUE one = rb_funcall(rb_funcall(result, rb_intern("flatten"), 0),
|
|
946
|
+
rb_intern("[]"), 1,
|
|
947
|
+
rb_range_new(INT2FIX(0), INT2FIX(0), 0));
|
|
948
|
+
rb_ca_store_addr(rb_ca_template(one), 0, fill);
|
|
949
|
+
}
|
|
925
950
|
return whole ? rb_ca_fetch_addr(result, 0) : result;
|
|
926
951
|
}
|
|
927
952
|
return ( result == CA_UNDEF ) ? fill : result;
|
|
@@ -1253,11 +1278,36 @@ rb_hash_has_key(VALUE hash, VALUE key)
|
|
|
1253
1278
|
return Qfalse;
|
|
1254
1279
|
}
|
|
1255
1280
|
|
|
1281
|
+
/* The next comma-separated key of a spec, its length in *len, or NULL
|
|
1282
|
+
past the last key. The spec is read in place: a copy to cut up would
|
|
1283
|
+
be a C allocation, and its failure has nowhere to go but to drop every
|
|
1284
|
+
keyword. */
|
|
1285
|
+
static const char *
|
|
1286
|
+
option_key (const char **sp, long *len)
|
|
1287
|
+
{
|
|
1288
|
+
const char *p = *sp, *end;
|
|
1289
|
+
|
|
1290
|
+
if ( p == NULL ) {
|
|
1291
|
+
return NULL;
|
|
1292
|
+
}
|
|
1293
|
+
end = strchr(p, ',');
|
|
1294
|
+
if ( end ) {
|
|
1295
|
+
*len = end - p;
|
|
1296
|
+
*sp = end + 1;
|
|
1297
|
+
}
|
|
1298
|
+
else {
|
|
1299
|
+
*len = (long) strlen(p);
|
|
1300
|
+
*sp = NULL;
|
|
1301
|
+
}
|
|
1302
|
+
return p;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1256
1305
|
void
|
|
1257
1306
|
rb_scan_options (VALUE ropt, const char *spec_in, ...)
|
|
1258
1307
|
{
|
|
1259
1308
|
VALUE *vp;
|
|
1260
|
-
char *sp, *tok
|
|
1309
|
+
const char *sp, *tok;
|
|
1310
|
+
long len;
|
|
1261
1311
|
int has_option = 0;
|
|
1262
1312
|
va_list vals;
|
|
1263
1313
|
|
|
@@ -1272,22 +1322,19 @@ rb_scan_options (VALUE ropt, const char *spec_in, ...)
|
|
|
1272
1322
|
}
|
|
1273
1323
|
|
|
1274
1324
|
va_start(vals, spec_in);
|
|
1275
|
-
sp =
|
|
1276
|
-
tok =
|
|
1277
|
-
while ( tok != NULL ) {
|
|
1325
|
+
sp = spec_in;
|
|
1326
|
+
while ( ( tok = option_key(&sp, &len) ) != NULL ) {
|
|
1278
1327
|
vp = va_arg(vals, VALUE*);
|
|
1279
1328
|
if ( has_option ) {
|
|
1280
|
-
VALUE key = ID2SYM(
|
|
1329
|
+
VALUE key = ID2SYM(rb_intern2(tok, len));
|
|
1281
1330
|
if ( rb_hash_has_key(ropt, key) ) {
|
|
1282
1331
|
*vp = rb_hash_aref(ropt, key);
|
|
1283
1332
|
}
|
|
1284
1333
|
/* key absent: leave *vp unchanged (caller's pre-initialized default) */
|
|
1285
1334
|
}
|
|
1286
1335
|
/* opts == Qnil: leave all *vp unchanged */
|
|
1287
|
-
tok = strsep1(&sp, ',');
|
|
1288
1336
|
}
|
|
1289
1337
|
va_end(vals);
|
|
1290
|
-
free(spec);
|
|
1291
1338
|
|
|
1292
1339
|
/* Strict: reject any key not named in spec, matching Ruby's native
|
|
1293
1340
|
keyword-argument behaviour ("unknown keyword: :foo"). Every call
|
|
@@ -1300,15 +1347,12 @@ rb_scan_options (VALUE ropt, const char *spec_in, ...)
|
|
|
1300
1347
|
VALUE key = rb_ary_entry(keys, i);
|
|
1301
1348
|
VALUE kname = SYMBOL_P(key) ? rb_sym2str(key) : rb_obj_as_string(key);
|
|
1302
1349
|
const char *kn = StringValueCStr(kname);
|
|
1303
|
-
|
|
1350
|
+
long kn_len = RSTRING_LEN(kname);
|
|
1304
1351
|
int found = 0;
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
if ( strcmp(tok2, kn) == 0 ) { found = 1; break; }
|
|
1309
|
-
tok2 = strsep1(&sp2, ',');
|
|
1352
|
+
sp = spec_in;
|
|
1353
|
+
while ( ( tok = option_key(&sp, &len) ) != NULL ) {
|
|
1354
|
+
if ( len == kn_len && memcmp(tok, kn, len) == 0 ) { found = 1; break; }
|
|
1310
1355
|
}
|
|
1311
|
-
free(spec2);
|
|
1312
1356
|
if ( ! found ) {
|
|
1313
1357
|
rb_raise(rb_eArgError, "unknown keyword: %"PRIsVALUE, rb_inspect(key));
|
|
1314
1358
|
}
|
|
@@ -1341,7 +1385,8 @@ void
|
|
|
1341
1385
|
rb_set_options (VALUE ropt, const char *spec_in, ...)
|
|
1342
1386
|
{
|
|
1343
1387
|
VALUE rval;
|
|
1344
|
-
char *sp, *tok
|
|
1388
|
+
const char *sp, *tok;
|
|
1389
|
+
long len;
|
|
1345
1390
|
int has_option = 0;
|
|
1346
1391
|
va_list vals;
|
|
1347
1392
|
|
|
@@ -1356,17 +1401,14 @@ rb_set_options (VALUE ropt, const char *spec_in, ...)
|
|
|
1356
1401
|
}
|
|
1357
1402
|
|
|
1358
1403
|
va_start(vals, spec_in);
|
|
1359
|
-
sp =
|
|
1360
|
-
tok =
|
|
1361
|
-
while ( tok != NULL ) {
|
|
1404
|
+
sp = spec_in;
|
|
1405
|
+
while ( ( tok = option_key(&sp, &len) ) != NULL ) {
|
|
1362
1406
|
rval = va_arg(vals, VALUE);
|
|
1363
1407
|
if ( has_option ) {
|
|
1364
|
-
rb_hash_aset(ropt, ID2SYM(
|
|
1408
|
+
rb_hash_aset(ropt, ID2SYM(rb_intern2(tok, len)), rval);
|
|
1365
1409
|
}
|
|
1366
|
-
tok = strsep1(&sp, ',');
|
|
1367
1410
|
}
|
|
1368
1411
|
va_end(vals);
|
|
1369
|
-
free(spec);
|
|
1370
1412
|
|
|
1371
1413
|
return;
|
|
1372
1414
|
}
|