carray 3.0.4 → 3.0.6
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 +438 -0
- data/README.md +1 -1
- data/carray.gemspec +3 -2
- data/ext/ca_array_pool.c +25 -1
- data/ext/ca_axis_dispatch.c +19 -20
- data/ext/ca_axis_group.c +1 -1
- data/ext/ca_categorical_iterator.c +34 -27
- data/ext/ca_compare.c +4 -4
- data/ext/ca_composite_dispatch.c +9 -9
- data/ext/ca_kernel_iterator.c +122 -237
- data/ext/ca_kernel_iterator.h +522 -337
- data/ext/ca_obj_array.c +69 -19
- data/ext/ca_obj_bincmp.c +10 -1
- data/ext/ca_obj_binop.c +11 -1
- data/ext/ca_obj_bitarray.c +5 -1
- data/ext/ca_obj_bitfield.c +60 -43
- data/ext/ca_obj_byte_swap.c +4 -1
- data/ext/ca_obj_const_string.c +15 -3
- data/ext/ca_obj_face.c +44 -1
- data/ext/ca_obj_fake.c +3 -1
- data/ext/ca_obj_field.c +13 -3
- data/ext/ca_obj_grid.c +219 -17
- data/ext/ca_obj_meld.c +69 -113
- data/ext/ca_obj_moncmp.c +9 -1
- data/ext/ca_obj_monop.c +86 -12
- data/ext/ca_obj_object.c +118 -32
- data/ext/ca_obj_record.c +3 -0
- data/ext/ca_obj_reduce.c +19 -1
- data/ext/ca_obj_refer.c +80 -26
- data/ext/ca_obj_remap.c +69 -10
- data/ext/ca_obj_roll.c +27 -6
- data/ext/ca_obj_select.c +38 -6
- data/ext/ca_obj_select_axis.c +1 -0
- data/ext/ca_obj_shift.c +32 -7
- data/ext/ca_obj_stack.c +311 -111
- data/ext/ca_obj_stride.c +159 -64
- data/ext/ca_obj_string.c +27 -2
- data/ext/ca_obj_tile.c +28 -7
- data/ext/ca_obj_transpose.c +8 -4
- data/ext/ca_obj_triop.c +12 -1
- data/ext/ca_obj_window.c +80 -50
- data/ext/ca_op_ipower.c +12 -12
- data/ext/ca_sort_kernels.h +6 -3
- data/ext/caframe_csv_reader.c +1 -1
- data/ext/carray.h +35 -1
- data/ext/carray_access.c +43 -67
- data/ext/carray_address_basis.c +134 -0
- data/ext/carray_attribute.c +32 -0
- data/ext/carray_broadcast.c +3 -4
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_cast.c +251 -93
- data/ext/carray_cast_func.rb +56 -26
- data/ext/carray_conversion.c +11 -7
- data/ext/carray_core.c +814 -72
- data/ext/carray_count.c +6 -0
- data/ext/carray_element.c +22 -13
- data/ext/carray_factorize.c +20 -20
- data/ext/carray_generate.c +8 -2
- data/ext/carray_histogram.c +26 -4
- data/ext/carray_index_classifier.c +4 -4
- data/ext/carray_internal.h +159 -12
- data/ext/carray_kernels_bincmp.c +2174 -170
- data/ext/carray_kernels_binop.c +25653 -5487
- data/ext/carray_kernels_init.c +8 -8
- data/ext/carray_kernels_moncmp.c +96 -96
- data/ext/carray_kernels_monop.c +12253 -5235
- data/ext/carray_kernels_reduce_aggregate.c +6150 -2423
- data/ext/carray_kernels_reduce_boolean.c +1533 -15
- data/ext/carray_kernels_reduce_cumulative.c +2442 -882
- data/ext/carray_kernels_reduce_extreme.c +5658 -1661
- data/ext/carray_kernels_reduce_variance.c +2534 -402
- data/ext/carray_kernels_scan.c +368 -368
- data/ext/carray_kernels_search.c +4551 -604
- data/ext/carray_kernels_sort.c +659 -751
- data/ext/carray_kernels_triop.c +114 -114
- data/ext/carray_key_windows.c +4 -0
- data/ext/carray_lazy.c +47 -0
- data/ext/carray_loop.c +1 -1
- data/ext/carray_mask.c +175 -161
- data/ext/carray_median_percentile.c +4 -4
- data/ext/carray_memory_view.c +15 -9
- data/ext/carray_operator.c +152 -49
- data/ext/carray_order.c +230 -10
- data/ext/carray_random.c +22 -19
- data/ext/carray_scatter.c +24 -7
- data/ext/carray_slab.c +128 -29
- 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_test.c +74 -19
- data/ext/carray_time_text.c +6 -4
- data/ext/carray_utils.c +63 -21
- data/ext/extconf.rb +11 -0
- data/ext/mkkernel.rb +546 -199
- data/ext/ruby_carray.c +4 -1
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +42 -5
- data/lib/carray/autoload_carray.rb +3 -3
- data/lib/carray/autoload_method_extension.rb +5 -3
- data/lib/carray/axis_group.rb +13 -7
- data/lib/carray/basics.rb +28 -8
- data/lib/carray/block_iterator.rb +17 -3
- data/lib/carray/categorical.rb +35 -23
- data/lib/carray/categorical_iterator.rb +8 -8
- data/lib/carray/complex.rb +2 -2
- data/lib/carray/conditional.rb +3 -2
- 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 +48 -16
- data/lib/carray/frame/concat.rb +17 -3
- data/lib/carray/frame/convert.rb +19 -0
- data/lib/carray/frame/csv_parser.rb +32 -32
- data/lib/carray/frame/describe.rb +4 -2
- data/lib/carray/frame/frame.rb +405 -85
- data/lib/carray/frame/group.rb +777 -64
- data/lib/carray/frame/io.rb +212 -72
- data/lib/carray/frame/join.rb +146 -37
- data/lib/carray/frame/records.rb +3 -3
- data/lib/carray/frame/reshape.rb +89 -11
- data/lib/carray/frame/sort.rb +57 -9
- data/lib/carray/frame/verbs.rb +384 -49
- data/lib/carray/frame/windows.rb +44 -6
- data/lib/carray/fuse_source.rb +31 -2
- data/lib/carray/inspect.rb +7 -2
- data/lib/carray/iterator.rb +32 -0
- data/lib/carray/lazy.rb +52 -8
- data/lib/carray/mask_gap_fill.rb +37 -17
- data/lib/carray/meld_reduce.rb +1 -1
- data/lib/carray/methods/choose.rb +3 -2
- data/lib/carray/methods/is_in.rb +8 -1
- data/lib/carray/methods/meshgrid.rb +3 -1
- data/lib/carray/runtime.rb +47 -8
- data/lib/carray/segment_iterator.rb +35 -16
- data/lib/carray/serialize.rb +53 -19
- data/lib/carray/stack.rb +33 -18
- 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 +112 -68
- data/lib/carray/window_iterator.rb +16 -4
- data/yard-stubs/ca_obj_array.rb +26 -1
- data/yard-stubs/ca_obj_transpose.rb +5 -4
- data/yard-stubs/carray_attribute.rb +3 -1
- data/yard-stubs/carray_cast.rb +10 -5
- data/yard-stubs/carray_conversion.rb +13 -3
- data/yard-stubs/carray_element.rb +7 -6
- data/yard-stubs/carray_mask.rb +28 -4
- data/yard-stubs/carray_math.rb +45 -20
- data/yard-stubs/carray_memory_view.rb +7 -0
- data/yard-stubs/carray_order.rb +100 -4
- data/yard-stubs/carray_scatter.rb +7 -5
- data/yard-stubs/carray_test.rb +7 -4
- metadata +18 -4
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_test.c
CHANGED
|
@@ -274,10 +274,23 @@ eql_## type (const char *a, const char *b, ca_size_t bytes) \
|
|
|
274
274
|
return ( *(const type*)a == *(const type*)b ); \
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
/* == compares contents: a NaN equals a NaN (whatever its payload), as the
|
|
278
|
+
same array read back or copied holds the same NaN; -0.0 equals 0.0 as
|
|
279
|
+
values do. eql? stays bitwise. */
|
|
280
|
+
static int
|
|
281
|
+
ca_object_cells_equal (VALUE x, VALUE y)
|
|
282
|
+
{
|
|
283
|
+
if ( RB_FLOAT_TYPE_P(x) && RB_FLOAT_TYPE_P(y) &&
|
|
284
|
+
isnan(RFLOAT_VALUE(x)) && isnan(RFLOAT_VALUE(y)) ) {
|
|
285
|
+
return 1;
|
|
286
|
+
}
|
|
287
|
+
return RTEST(rb_funcall(x, id_equal, 1, y)) ? 1 : 0;
|
|
288
|
+
}
|
|
289
|
+
|
|
277
290
|
static int
|
|
278
291
|
eql_VALUE (const char *a, const char *b, ca_size_t bytes)
|
|
279
292
|
{
|
|
280
|
-
return
|
|
293
|
+
return ca_object_cells_equal(*(const VALUE*)a, *(const VALUE*)b);
|
|
281
294
|
}
|
|
282
295
|
|
|
283
296
|
static int
|
|
@@ -295,10 +308,28 @@ eql_type(int32_t)
|
|
|
295
308
|
eql_type(uint32_t)
|
|
296
309
|
eql_type(int64_t)
|
|
297
310
|
eql_type(uint64_t)
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
311
|
+
#define eql_float(type) \
|
|
312
|
+
static int \
|
|
313
|
+
eql_## type (const char *a, const char *b, ca_size_t bytes) \
|
|
314
|
+
{ \
|
|
315
|
+
type x = *(const type*)a, y = *(const type*)b; \
|
|
316
|
+
return ( x == y ) || ( isnan(x) && isnan(y) ); \
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
#define eql_cmplx(type, part) \
|
|
320
|
+
static int \
|
|
321
|
+
eql_## type (const char *a, const char *b, ca_size_t bytes) \
|
|
322
|
+
{ \
|
|
323
|
+
type x = *(const type*)a, y = *(const type*)b; \
|
|
324
|
+
part xr = creal(x), xi = cimag(x), yr = creal(y), yi = cimag(y); \
|
|
325
|
+
return ( ( xr == yr ) || ( isnan(xr) && isnan(yr) ) ) && \
|
|
326
|
+
( ( xi == yi ) || ( isnan(xi) && isnan(yi) ) ); \
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
eql_float(float32_t)
|
|
330
|
+
eql_float(float64_t)
|
|
331
|
+
eql_cmplx(cmplx64_t, float)
|
|
332
|
+
eql_cmplx(cmplx128_t, double)
|
|
302
333
|
|
|
303
334
|
/* Placeholder for CA_FLOAT128 / CA_CMPLX256 slots (ca_valid[12] =
|
|
304
335
|
ca_valid[15] = 0, so never invoked). */
|
|
@@ -371,8 +402,8 @@ ca_compare_body (VALUE arg)
|
|
|
371
402
|
comparison is bitwise (= NaN.eql?(NaN) yields true since their bit
|
|
372
403
|
patterns match), so memcmp gives the right semantics. For non-strict
|
|
373
404
|
(==) of numeric data_types, type-equality is byte-equality EXCEPT for
|
|
374
|
-
floats where -0.0 == +0.0 (different bit pattern, same value) and
|
|
375
|
-
NaN
|
|
405
|
+
floats where -0.0 == +0.0 (different bit pattern, same value) and any
|
|
406
|
+
NaN equals any NaN (payloads may differ) -- so we must keep the
|
|
376
407
|
per-element comparator there.
|
|
377
408
|
|
|
378
409
|
Integer / bool / fixlen data_types are byte-exact, so memcmp matches both
|
|
@@ -380,13 +411,14 @@ ca_compare_body (VALUE arg)
|
|
|
380
411
|
the comparator. */
|
|
381
412
|
if ( ! masked_a && ! masked_b ) {
|
|
382
413
|
if ( is_object ) {
|
|
383
|
-
ID id = strict ? id_eql : id_equal;
|
|
384
414
|
VALUE *va = (VALUE *) pa;
|
|
385
415
|
VALUE *vb = (VALUE *) pb;
|
|
386
416
|
for (i=0; i<ca->elements; i++) {
|
|
387
417
|
volatile VALUE x = va[i];
|
|
388
418
|
volatile VALUE y = vb[i];
|
|
389
|
-
|
|
419
|
+
int eq = strict ? RTEST(rb_funcall(x, id_eql, 1, y))
|
|
420
|
+
: ca_object_cells_equal(x, y);
|
|
421
|
+
if ( ! eq ) {
|
|
390
422
|
flag = 0;
|
|
391
423
|
break;
|
|
392
424
|
}
|
|
@@ -427,8 +459,8 @@ ca_compare_body (VALUE arg)
|
|
|
427
459
|
if ( is_object ) {
|
|
428
460
|
volatile VALUE x = *(VALUE *) pa;
|
|
429
461
|
volatile VALUE y = *(VALUE *) pb;
|
|
430
|
-
|
|
431
|
-
|
|
462
|
+
eq = strict ? RTEST(rb_funcall(x, id_eql, 1, y))
|
|
463
|
+
: ca_object_cells_equal(x, y);
|
|
432
464
|
}
|
|
433
465
|
else if ( strict
|
|
434
466
|
|| ca->data_type <= CA_UINT64
|
|
@@ -451,6 +483,19 @@ ca_compare_body (VALUE arg)
|
|
|
451
483
|
return Qnil;
|
|
452
484
|
}
|
|
453
485
|
|
|
486
|
+
typedef struct {
|
|
487
|
+
CArray **list;
|
|
488
|
+
ca_compare_ctx_t *c;
|
|
489
|
+
} ca_compare_run_t;
|
|
490
|
+
|
|
491
|
+
static VALUE
|
|
492
|
+
ca_compare_run (VALUE arg)
|
|
493
|
+
{
|
|
494
|
+
ca_compare_run_t *r = (ca_compare_run_t *) arg;
|
|
495
|
+
ca_attach_window(2, r->list, "rr", ca_compare_body, (VALUE) r->c);
|
|
496
|
+
return Qnil;
|
|
497
|
+
}
|
|
498
|
+
|
|
454
499
|
/* ca_compare_common(a, b, strict) — shared body of ca_equal (==) and
|
|
455
500
|
* ca_eql_strict (eql?). Returns 1 if arrays match under the selected
|
|
456
501
|
* semantics, else 0.
|
|
@@ -461,7 +506,7 @@ ca_compare_body (VALUE arg)
|
|
|
461
506
|
* four masked/unmasked combinations.
|
|
462
507
|
*
|
|
463
508
|
* The only difference is the per-element comparator:
|
|
464
|
-
* == : ca_eql[data_type] (
|
|
509
|
+
* == : ca_eql[data_type] (by value: NaN equals NaN, -0.0 equals 0.0)
|
|
465
510
|
* eql?: memcmp for numeric, rb_funcall(:eql?) for CA_OBJECT
|
|
466
511
|
*
|
|
467
512
|
* The unmasked-unmasked branch takes a bulk memcmp or per-cell
|
|
@@ -503,8 +548,14 @@ ca_compare_common (void *ap, void *bp, int strict)
|
|
|
503
548
|
c.flag = 1;
|
|
504
549
|
list[0] = ca;
|
|
505
550
|
list[1] = cb;
|
|
506
|
-
/* The object lane calls #== / #eql? with both arrays attached
|
|
507
|
-
|
|
551
|
+
/* The object lane calls #== / #eql? with both arrays attached, and
|
|
552
|
+
recorded as compared over (ca_computing_run), so a cell holding one
|
|
553
|
+
of them is refused as cyclic rather than compared again without
|
|
554
|
+
end. */
|
|
555
|
+
ca_compare_run_t r;
|
|
556
|
+
r.list = list;
|
|
557
|
+
r.c = &c;
|
|
558
|
+
ca_computing_run(2, list, ca_compare_run, (VALUE) &r);
|
|
508
559
|
return c.flag;
|
|
509
560
|
}
|
|
510
561
|
}
|
|
@@ -522,9 +573,10 @@ ca_eql_storage (void *ap, void *bp)
|
|
|
522
573
|
}
|
|
523
574
|
|
|
524
575
|
/* CArray#==(other) — elementwise equality returning true / false.
|
|
525
|
-
* data_class, data_type, shape, and mask state must all match
|
|
526
|
-
*
|
|
527
|
-
*
|
|
576
|
+
* data_class, data_type, shape, and mask state must all match. It asks
|
|
577
|
+
* whether the contents are the same, so a NaN equals a NaN and -0.0
|
|
578
|
+
* equals 0.0; the IEEE comparison of each element is #eq. Non-CArray
|
|
579
|
+
* other returns false. */
|
|
528
580
|
static VALUE
|
|
529
581
|
rb_ca_equal (VALUE self, VALUE other)
|
|
530
582
|
{
|
|
@@ -795,7 +847,8 @@ without_read_only_ensure (VALUE arg)
|
|
|
795
847
|
* the bridge owns.
|
|
796
848
|
*
|
|
797
849
|
* Mechanics: clears CA_FLAG_READ_ONLY on self and on its mask for the
|
|
798
|
-
* duration of the block
|
|
850
|
+
* duration of the block, except on a mask that is a wrap: that mask borrows
|
|
851
|
+
* its bits from a producer (wrap_memory_view's mask:), which set the flag; rb_ensure restores both on normal return AND on
|
|
799
852
|
* raise, setting the flag on whatever mask self has by then. (A read-only
|
|
800
853
|
* array's mask carries the flag once CArray#mask has handed it out.) Frozen
|
|
801
854
|
* objects still raise FrozenError. Does not walk parent chains.
|
|
@@ -822,7 +875,9 @@ rb_ca_without_read_only_flag (VALUE self)
|
|
|
822
875
|
s.was_readonly = ca_test_flag(ca, CA_FLAG_READ_ONLY);
|
|
823
876
|
if (s.was_readonly) {
|
|
824
877
|
ca_unset_flag(ca, CA_FLAG_READ_ONLY);
|
|
825
|
-
|
|
878
|
+
/* A mask that is a wrap borrows its bits (the mask: of
|
|
879
|
+
wrap_memory_view); its flag is the lender's and stays. */
|
|
880
|
+
if (ca->mask && ca->mask->obj_type != CA_OBJ_ARRAY_WRAP) {
|
|
826
881
|
ca_unset_flag(ca->mask, CA_FLAG_READ_ONLY);
|
|
827
882
|
}
|
|
828
883
|
}
|
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;
|
|
@@ -381,7 +383,7 @@ rb_ca_parse_time_text (int argc, VALUE *argv, VALUE self)
|
|
|
381
383
|
if ( ca->data_type != CA_OBJECT ) {
|
|
382
384
|
rb_raise(rb_eArgError, "time text reading needs an object array");
|
|
383
385
|
}
|
|
384
|
-
if ( ! ca_is_entity(ca) ) {
|
|
386
|
+
if ( ! ca_is_entity(ca) || ! ca->ptr ) {
|
|
385
387
|
src = rb_ca_copy(src);
|
|
386
388
|
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
387
389
|
}
|
|
@@ -1075,7 +1077,7 @@ rb_ca_strptime_fields (VALUE self, VALUE rformat, VALUE rstrict)
|
|
|
1075
1077
|
if ( ca->data_type != CA_OBJECT ) {
|
|
1076
1078
|
rb_raise(rb_eArgError, "strptime reading needs an object array");
|
|
1077
1079
|
}
|
|
1078
|
-
if ( ! ca_is_entity(ca) ) {
|
|
1080
|
+
if ( ! ca_is_entity(ca) || ! ca->ptr ) {
|
|
1079
1081
|
src = rb_ca_copy(src);
|
|
1080
1082
|
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
1081
1083
|
}
|
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
|
}
|
data/ext/extconf.rb
CHANGED
|
@@ -118,6 +118,17 @@ if try_compile("int main(void) { return 0; }", "-fwrapv")
|
|
|
118
118
|
$carray_build_flags << "-fwrapv"
|
|
119
119
|
end
|
|
120
120
|
|
|
121
|
+
# --- math functions do not set errno (`-fno-math-errno`)
|
|
122
|
+
#
|
|
123
|
+
# Nothing in carray reads errno after a math call. With errno kept, GCC
|
|
124
|
+
# must call sqrt() for every cell instead of using the vector square root,
|
|
125
|
+
# so `sqrt` ran 2-4x slower than it could. The values do not change.
|
|
126
|
+
# Apple clang already defaults to this.
|
|
127
|
+
if try_compile("int main(void) { return 0; }", "-fno-math-errno")
|
|
128
|
+
$CFLAGS += " -fno-math-errno"
|
|
129
|
+
$carray_build_flags << "-fno-math-errno"
|
|
130
|
+
end
|
|
131
|
+
|
|
121
132
|
# --- probe for `-fopenmp-simd` (SL.1.0, PROPOSAL_REDUCTION_SIMD_LICENSE)
|
|
122
133
|
#
|
|
123
134
|
# `-fopenmp-simd` enables `#pragma omp simd` (and its `reduction(+:acc)`
|