carray 3.0.6 → 3.0.7
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 +110 -0
- data/README.md +24 -3
- data/carray.gemspec +1 -1
- data/ext/ca_axis_group.c +6 -6
- data/ext/ca_binop_dispatch.c +8 -0
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +7 -7
- data/ext/ca_kernel_iterator.h +6 -4
- data/ext/ca_obj_array.c +4 -4
- data/ext/ca_obj_bincmp.c +19 -3
- data/ext/ca_obj_binop.c +36 -11
- data/ext/ca_obj_bitarray.c +2 -4
- data/ext/ca_obj_bitfield.c +86 -4
- data/ext/ca_obj_byte_swap.c +2 -4
- data/ext/ca_obj_const_string.c +422 -257
- data/ext/ca_obj_face.c +71 -33
- data/ext/ca_obj_fake.c +112 -13
- data/ext/ca_obj_farray.c +7 -1
- data/ext/ca_obj_fixlen_string.c +51 -17
- data/ext/ca_obj_grid.c +12 -7
- data/ext/ca_obj_meld.c +5 -5
- data/ext/ca_obj_monop.c +65 -39
- data/ext/ca_obj_object.c +9 -9
- data/ext/ca_obj_reduce.c +2 -4
- data/ext/ca_obj_refer.c +104 -10
- data/ext/ca_obj_repeat.c +1 -1
- data/ext/ca_obj_roll.c +2 -4
- data/ext/ca_obj_select.c +8 -6
- data/ext/ca_obj_select_axis.c +8 -6
- data/ext/ca_obj_stack.c +5 -5
- data/ext/ca_obj_stride.c +46 -8
- data/ext/ca_obj_string.c +2 -2
- data/ext/ca_obj_tile.c +2 -4
- data/ext/ca_obj_triop.c +15 -12
- data/ext/ca_obj_window.c +22 -15
- data/ext/ca_op_ipower.c +63 -15
- data/ext/ca_op_powi.h +6 -29
- data/ext/ca_sort_kernels.h +3 -0
- data/ext/ca_sweep_engine.c +90 -23
- data/ext/ca_sweep_engine.h +5 -6
- data/ext/caframe_csv_reader.c +1 -1
- data/ext/carray.h +3 -1
- data/ext/carray_access.c +98 -39
- data/ext/carray_address_basis.c +98 -24
- data/ext/carray_broadcast.c +2 -2
- data/ext/carray_call_cfunc.c +5 -8
- data/ext/carray_cast.c +311 -37
- data/ext/carray_cast_func.rb +37 -5
- data/ext/carray_conversion.c +56 -2
- data/ext/carray_copy.c +24 -0
- data/ext/carray_core.c +69 -6
- data/ext/carray_count.c +28 -9
- data/ext/carray_element.c +9 -3
- data/ext/carray_factorize.c +11 -11
- data/ext/carray_histogram.c +2 -2
- data/ext/carray_index_classifier.c +7 -5
- data/ext/carray_internal.h +94 -0
- data/ext/carray_kernels_binop.c +55 -55
- data/ext/carray_kernels_init.c +14 -14
- data/ext/carray_kernels_monop.c +90 -140
- data/ext/carray_lazy.c +16 -1
- data/ext/carray_loop.c +9 -2
- data/ext/carray_mask.c +118 -11
- data/ext/carray_median_percentile.c +13 -8
- data/ext/carray_memory_view.c +41 -22
- data/ext/carray_operator.c +72 -11
- data/ext/carray_order.c +52 -9
- data/ext/carray_partition.c +1 -1
- data/ext/carray_random.c +1 -1
- data/ext/carray_round.c +24 -1
- data/ext/carray_scatter.c +4 -0
- data/ext/carray_segment.c +1 -1
- data/ext/carray_slab.c +13 -4
- data/ext/carray_sort.c +6 -3
- data/ext/carray_sort_kernel.c +24 -0
- data/ext/carray_struct.c +21 -6
- data/ext/carray_test.c +85 -39
- data/ext/carray_time_text.c +6 -0
- data/ext/carray_utils.c +124 -54
- data/ext/mk_call_cfunc.rb +6 -11
- data/ext/mkkernel.rb +37 -27
- data/ext/version.h +4 -4
- data/lib/carray/axis_group.rb +9 -6
- data/lib/carray/basics.rb +26 -8
- data/lib/carray/bincount_nd.rb +8 -2
- data/lib/carray/block_iterator.rb +48 -21
- data/lib/carray/categorical.rb +21 -8
- data/lib/carray/categorical_iterator.rb +2 -1
- data/lib/carray/conditional.rb +52 -4
- data/lib/carray/const_string.rb +74 -0
- data/lib/carray/construct.rb +2 -2
- data/lib/carray/core_extensions.rb +19 -68
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/fixlen_string.rb +83 -1
- data/lib/carray/frame/column_verbs.rb +61 -6
- data/lib/carray/frame/concat.rb +50 -6
- data/lib/carray/frame/csv_parser.rb +13 -4
- data/lib/carray/frame/frame.rb +38 -6
- data/lib/carray/frame/group.rb +67 -40
- data/lib/carray/frame/io.rb +10 -5
- data/lib/carray/frame/join.rb +20 -6
- data/lib/carray/frame/records.rb +6 -4
- data/lib/carray/frame/reshape.rb +25 -5
- data/lib/carray/frame/verbs.rb +78 -25
- data/lib/carray/frame/windows.rb +30 -6
- data/lib/carray/fuse_source.rb +4 -2
- data/lib/carray/iterator.rb +8 -0
- data/lib/carray/key_windows.rb +10 -4
- data/lib/carray/lazy.rb +12 -17
- data/lib/carray/methods/bin.rb +3 -0
- data/lib/carray/methods/composition.rb +1 -1
- data/lib/carray/methods/factorize.rb +2 -0
- data/lib/carray/methods/gather_nd.rb +4 -1
- data/lib/carray/methods/is_in.rb +23 -3
- data/lib/carray/methods/locate_addr.rb +63 -12
- data/lib/carray/methods/repeat.rb +11 -1
- data/lib/carray/record_order.rb +35 -6
- data/lib/carray/runtime.rb +10 -0
- data/lib/carray/segment_iterator.rb +19 -16
- data/lib/carray/serialize.rb +22 -0
- data/lib/carray/slab_iterator.rb +1 -1
- data/lib/carray/stack.rb +3 -3
- data/lib/carray/string.rb +6 -6
- data/lib/carray/string_operation_extension.rb +25 -4
- data/lib/carray/struct_builder.rb +4 -1
- data/lib/carray/time.rb +190 -46
- data/lib/carray/window_iterator.rb +48 -12
- data/yard-stubs/ca_obj_bitfield.rb +4 -1
- data/yard-stubs/ca_obj_refer.rb +3 -0
- data/yard-stubs/ca_obj_window.rb +2 -1
- data/yard-stubs/carray_access.rb +4 -2
- data/yard-stubs/carray_cast.rb +6 -0
- data/yard-stubs/carray_count.rb +6 -3
- data/yard-stubs/carray_math.rb +5 -0
- data/yard-stubs/carray_order.rb +6 -0
- data/yard-stubs/carray_scatter.rb +2 -1
- data/yard-stubs/carray_test.rb +18 -5
- metadata +2 -2
data/ext/carray_order.c
CHANGED
|
@@ -169,7 +169,7 @@ ca_project (CArray *ca, CArray *ci, char *lfill, char *ufill)
|
|
|
169
169
|
else CA_COUNT_BELOW_LOOP(T, <)
|
|
170
170
|
|
|
171
171
|
static VALUE
|
|
172
|
-
rb_ca_count_below (VALUE self, VALUE vq, VALUE vinclusive)
|
|
172
|
+
rb_ca_count_below (VALUE self, volatile VALUE vq, VALUE vinclusive)
|
|
173
173
|
{
|
|
174
174
|
volatile VALUE vout;
|
|
175
175
|
CArray *cr, *cq, *co;
|
|
@@ -387,7 +387,7 @@ extern VALUE rb_ca_rank_index_ki_kind_dense (VALUE self, VALUE vaxis, int stable
|
|
|
387
387
|
* search_kw / search_nearest_kw and their _addr siblings) on the
|
|
388
388
|
* no-axis path. */
|
|
389
389
|
static VALUE
|
|
390
|
-
ca_reshape_search_result (VALUE query, VALUE rraw)
|
|
390
|
+
ca_reshape_search_result (volatile VALUE query, VALUE rraw)
|
|
391
391
|
{
|
|
392
392
|
CArray *cq;
|
|
393
393
|
GetCArray(query, cq);
|
|
@@ -441,6 +441,28 @@ rb_ca_bsearch_addr_kw (int argc, VALUE *argv, VALUE self)
|
|
|
441
441
|
return rb_ca_bsearch_addr_ki(self, argv[0], raxis);
|
|
442
442
|
}
|
|
443
443
|
|
|
444
|
+
/* The query of search as the array reads it. true and false are 1 and 0
|
|
445
|
+
to a numeric array. A value the array can not hold (nil, a String)
|
|
446
|
+
finds nothing, as an Integer outside the array's type does. The query is asked of the
|
|
447
|
+
cells that matched (none), in the type that holds the answer. A Face that
|
|
448
|
+
can not be searched is refused as for any query, and a complex array,
|
|
449
|
+
which search does not take, goes on to its refusal. */
|
|
450
|
+
static void
|
|
451
|
+
ca_search_query_read (VALUE *pself, VALUE *pquery)
|
|
452
|
+
{
|
|
453
|
+
CArray *ca;
|
|
454
|
+
GetCArray(*pself, ca);
|
|
455
|
+
*pquery = ca_truth_as_number(ca, *pquery);
|
|
456
|
+
if ( ! ca_query_matches_nothing(ca, *pquery) || ca_is_complex_type(ca) ) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
if ( ca_is_face(ca) ) {
|
|
460
|
+
ca_face_require_orderable(*pself, "search", "search");
|
|
461
|
+
}
|
|
462
|
+
*pself = rb_funcall(*pself, rb_intern("eq"), 1, *pquery);
|
|
463
|
+
*pquery = Qtrue;
|
|
464
|
+
}
|
|
465
|
+
|
|
444
466
|
static VALUE
|
|
445
467
|
rb_ca_search_kw (int argc, VALUE *argv, VALUE self)
|
|
446
468
|
{
|
|
@@ -448,10 +470,12 @@ rb_ca_search_kw (int argc, VALUE *argv, VALUE self)
|
|
|
448
470
|
VALUE raxis = Qnil;
|
|
449
471
|
rb_scan_options(ropt, "axis", &raxis);
|
|
450
472
|
rb_check_arity(argc, 1, 2);
|
|
473
|
+
VALUE rquery = argv[0];
|
|
474
|
+
ca_search_query_read(&self, &rquery);
|
|
451
475
|
|
|
452
476
|
if ( NIL_P(raxis) ) {
|
|
453
477
|
VALUE flat = rb_ca_flatten(self);
|
|
454
|
-
VALUE q = rb_obj_is_carray(
|
|
478
|
+
VALUE q = rb_obj_is_carray(rquery) ? rb_ca_flatten(rquery) : rquery;
|
|
455
479
|
VALUE r;
|
|
456
480
|
VALUE ki_argv[3] = { q, INT2FIX(0), argv[1] };
|
|
457
481
|
if ( argc >= 2 ) {
|
|
@@ -460,10 +484,10 @@ rb_ca_search_kw (int argc, VALUE *argv, VALUE self)
|
|
|
460
484
|
else {
|
|
461
485
|
r = rb_ca_search_ki(2, ki_argv, flat);
|
|
462
486
|
}
|
|
463
|
-
return rb_obj_is_carray(
|
|
487
|
+
return rb_obj_is_carray(rquery) ? ca_reshape_search_result(rquery, r) : r;
|
|
464
488
|
}
|
|
465
489
|
/* search_ki(val, axis, eps) -- argc=2 (val,axis) or 3 (val,axis,eps) */
|
|
466
|
-
VALUE ki_argv[3] = {
|
|
490
|
+
VALUE ki_argv[3] = { rquery, raxis, argv[1] };
|
|
467
491
|
if ( argc >= 2 ) {
|
|
468
492
|
return rb_ca_search_ki(3, ki_argv, self);
|
|
469
493
|
}
|
|
@@ -477,11 +501,13 @@ rb_ca_search_addr_kw (int argc, VALUE *argv, VALUE self)
|
|
|
477
501
|
VALUE raxis = Qnil;
|
|
478
502
|
rb_scan_options(ropt, "axis", &raxis);
|
|
479
503
|
rb_check_arity(argc, 1, 2);
|
|
504
|
+
VALUE rquery = argv[0];
|
|
505
|
+
ca_search_query_read(&self, &rquery);
|
|
480
506
|
|
|
481
507
|
if ( NIL_P(raxis) ) {
|
|
482
508
|
/* 1-D self: addr == index reuses _ki (not _addr_ki). */
|
|
483
509
|
VALUE flat = rb_ca_flatten(self);
|
|
484
|
-
VALUE q = rb_obj_is_carray(
|
|
510
|
+
VALUE q = rb_obj_is_carray(rquery) ? rb_ca_flatten(rquery) : rquery;
|
|
485
511
|
VALUE r;
|
|
486
512
|
VALUE ki_argv[3] = { q, INT2FIX(0), argv[1] };
|
|
487
513
|
if ( argc >= 2 ) {
|
|
@@ -490,9 +516,9 @@ rb_ca_search_addr_kw (int argc, VALUE *argv, VALUE self)
|
|
|
490
516
|
else {
|
|
491
517
|
r = rb_ca_search_ki(2, ki_argv, flat);
|
|
492
518
|
}
|
|
493
|
-
return rb_obj_is_carray(
|
|
519
|
+
return rb_obj_is_carray(rquery) ? ca_reshape_search_result(rquery, r) : r;
|
|
494
520
|
}
|
|
495
|
-
VALUE ki_argv[3] = {
|
|
521
|
+
VALUE ki_argv[3] = { rquery, raxis, argv[1] };
|
|
496
522
|
if ( argc >= 2 ) {
|
|
497
523
|
return rb_ca_search_addr_ki(3, ki_argv, self);
|
|
498
524
|
}
|
|
@@ -597,6 +623,21 @@ rb_ca_sort_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
597
623
|
return rb_ca_fetch(self, addrs);
|
|
598
624
|
}
|
|
599
625
|
|
|
626
|
+
/* The extreme kernels have no fixlen lane: a fixlen key is read through the
|
|
627
|
+
rank of its cells, which keeps ties and masked cells. */
|
|
628
|
+
static VALUE
|
|
629
|
+
ca_by_key_comparable (VALUE key)
|
|
630
|
+
{
|
|
631
|
+
CArray *ca;
|
|
632
|
+
TypedData_Get_Struct(key, CArray, &carray_data_type, ca);
|
|
633
|
+
if ( ca->data_type == CA_FIXLEN ) {
|
|
634
|
+
VALUE opts = rb_hash_new();
|
|
635
|
+
rb_hash_aset(opts, ID2SYM(rb_intern("method")), ID2SYM(rb_intern("dense")));
|
|
636
|
+
return rb_funcallv_kw(key, rb_intern("order"), 1, &opts, RB_PASS_KEYWORDS);
|
|
637
|
+
}
|
|
638
|
+
return key;
|
|
639
|
+
}
|
|
640
|
+
|
|
600
641
|
/* max_by_key(key, axis: nil) -- self[key.max_addr(axis:)] (or UNDEF if empty). */
|
|
601
642
|
static VALUE
|
|
602
643
|
rb_ca_max_by_key (int argc, VALUE *argv, VALUE self)
|
|
@@ -609,6 +650,7 @@ rb_ca_max_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
609
650
|
return CA_UNDEF;
|
|
610
651
|
}
|
|
611
652
|
rkey = ca_order_key(rkey, "max_by_key");
|
|
653
|
+
rkey = ca_by_key_comparable(rkey);
|
|
612
654
|
|
|
613
655
|
VALUE addrs;
|
|
614
656
|
|
|
@@ -636,6 +678,7 @@ rb_ca_min_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
636
678
|
return CA_UNDEF;
|
|
637
679
|
}
|
|
638
680
|
rkey = ca_order_key(rkey, "min_by_key");
|
|
681
|
+
rkey = ca_by_key_comparable(rkey);
|
|
639
682
|
|
|
640
683
|
VALUE addrs;
|
|
641
684
|
|
|
@@ -1100,7 +1143,7 @@ ca_topk_buf_fiber (const ca_topk_fiber_t *f, ca_size_t len, ca_size_t cap,
|
|
|
1100
1143
|
filled with the axis last and moved into place at the end (cap cells
|
|
1101
1144
|
per fiber). */
|
|
1102
1145
|
static VALUE
|
|
1103
|
-
ca_topk_buffered_positions (VALUE key, long cap, long axis, int desc)
|
|
1146
|
+
ca_topk_buffered_positions (volatile VALUE key, long cap, long axis, int desc)
|
|
1104
1147
|
{
|
|
1105
1148
|
volatile VALUE holder = 0, out;
|
|
1106
1149
|
VALUE perm[CA_RANK_MAX];
|
data/ext/carray_partition.c
CHANGED
|
@@ -141,7 +141,7 @@ VALUE
|
|
|
141
141
|
rb_ca_partition_copy_c (VALUE self, VALUE vkth, VALUE vaxis)
|
|
142
142
|
{
|
|
143
143
|
/* Mask handling (= same as partition view). */
|
|
144
|
-
VALUE target = self;
|
|
144
|
+
volatile VALUE target = self; /* cat points into it; the walk can run a GC */
|
|
145
145
|
CArray *cat;
|
|
146
146
|
TypedData_Get_Struct(target, CArray, &carray_data_type, cat);
|
|
147
147
|
if ( ca_has_mask(cat) ) {
|
data/ext/carray_random.c
CHANGED
|
@@ -791,7 +791,7 @@ static CArray *
|
|
|
791
791
|
ca_rng_cells (VALUE self, int64_t **cells)
|
|
792
792
|
{
|
|
793
793
|
CArray *ca;
|
|
794
|
-
VALUE state = rb_ivar_get(self, rb_intern("@state"));
|
|
794
|
+
volatile VALUE state = rb_ivar_get(self, rb_intern("@state"));
|
|
795
795
|
TypedData_Get_Struct(state, CArray, &carray_data_type, ca);
|
|
796
796
|
ca_attach(ca); /* window: the state is an entity, whose attach holds nothing */
|
|
797
797
|
*cells = (int64_t *) ca->ptr;
|
data/ext/carray_round.c
CHANGED
|
@@ -196,6 +196,21 @@ ca_round_entity (CArray *ca, long ndigits)
|
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
typedef struct {
|
|
200
|
+
CArray *ca;
|
|
201
|
+
long ndigits;
|
|
202
|
+
} ca_round_call_t;
|
|
203
|
+
|
|
204
|
+
/* The cells of an object array are asked in turn, and a cell that is an
|
|
205
|
+
array asks its own (ca_computing_run). */
|
|
206
|
+
static VALUE
|
|
207
|
+
ca_round_cells (VALUE arg)
|
|
208
|
+
{
|
|
209
|
+
ca_round_call_t *c = (ca_round_call_t *) arg;
|
|
210
|
+
ca_round_entity(c->ca, c->ndigits);
|
|
211
|
+
return Qnil;
|
|
212
|
+
}
|
|
213
|
+
|
|
199
214
|
/* The array to round: a boolean is rounded as its 0/1 int64 values, as
|
|
200
215
|
round without digits does. */
|
|
201
216
|
static VALUE
|
|
@@ -228,7 +243,15 @@ ca_round_copy (VALUE src, long ndigits)
|
|
|
228
243
|
if ( ndigits > 0 && ca_is_integer_type(co) ) {
|
|
229
244
|
return out;
|
|
230
245
|
}
|
|
231
|
-
|
|
246
|
+
if ( ca_is_object_type(co) ) {
|
|
247
|
+
ca_round_call_t c;
|
|
248
|
+
c.ca = co;
|
|
249
|
+
c.ndigits = ndigits;
|
|
250
|
+
ca_computing_run(1, &co, ca_round_cells, (VALUE) &c);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
ca_round_entity(co, ndigits);
|
|
254
|
+
}
|
|
232
255
|
return out;
|
|
233
256
|
}
|
|
234
257
|
|
data/ext/carray_scatter.c
CHANGED
|
@@ -266,6 +266,10 @@ ca_scatter_is_scalar (VALUE v)
|
|
|
266
266
|
} \
|
|
267
267
|
} \
|
|
268
268
|
else { \
|
|
269
|
+
if ( rb_obj_is_carray(rvals) ) { \
|
|
270
|
+
TypedData_Get_Struct(rvals, CArray, &carray_data_type, cv); \
|
|
271
|
+
ca_refuse_complex_into_real(ca, cv); \
|
|
272
|
+
} \
|
|
269
273
|
/* coerce: a store into the receiver */ \
|
|
270
274
|
rvals = rb_ca_wrap_readonly(rvals, INT2NUM(ca->data_type)); \
|
|
271
275
|
TypedData_Get_Struct(rvals, CArray, &carray_data_type, cv); \
|
data/ext/carray_segment.c
CHANGED
|
@@ -34,7 +34,7 @@ static ID id_lengths, id_offsets;
|
|
|
34
34
|
data type and masked cells, since neither names a count or a
|
|
35
35
|
position. */
|
|
36
36
|
static VALUE
|
|
37
|
-
segment_read_int64 (VALUE v, const char *name, int is_lengths,
|
|
37
|
+
segment_read_int64 (volatile VALUE v, const char *name, int is_lengths,
|
|
38
38
|
ca_size_t pad_front, CArray **out_ca, ca_size_t *out_k)
|
|
39
39
|
{
|
|
40
40
|
CArray *src, *dst;
|
data/ext/carray_slab.c
CHANGED
|
@@ -117,7 +117,7 @@ ca_slab_parse_axes (ca_slab_iter_state_t *st, VALUE axis_arg, int8_t src_ndim)
|
|
|
117
117
|
init_val : VALUE — REDUCE_FIBER initial accumulator, or Qundef
|
|
118
118
|
if not applicable. Stored as Qnil if Qundef. */
|
|
119
119
|
static void
|
|
120
|
-
slab_state_init (ca_slab_iter_state_t *st, VALUE source, int8_t form,
|
|
120
|
+
slab_state_init (ca_slab_iter_state_t *st, volatile VALUE source, int8_t form,
|
|
121
121
|
VALUE axis_arg, VALUE data_type, VALUE init_val)
|
|
122
122
|
{
|
|
123
123
|
CArray *src;
|
|
@@ -422,8 +422,9 @@ ca_slab_setup_input_slab_view (ca_slab_iter_state_t *st, CArray *src,
|
|
|
422
422
|
ca_size_t exp = src->bytes;
|
|
423
423
|
int8_t k;
|
|
424
424
|
st->own_scratch_elements = elements;
|
|
425
|
-
st->own_data_scratch = (
|
|
425
|
+
st->own_data_scratch = ca_alloc_cells_of(src->data_type, elements, src->bytes);
|
|
426
426
|
if ( has_mask ) {
|
|
427
|
+
/* cells: boolean, which the collector does not read */
|
|
427
428
|
st->own_mask_scratch = (boolean8_t *) xmalloc(elements);
|
|
428
429
|
}
|
|
429
430
|
/* Carrier wraps our own scratch. Direct field assignment of
|
|
@@ -516,6 +517,14 @@ ca_slab_advance_slab_view (ca_slab_iter_state_t *st,
|
|
|
516
517
|
CArray *src, char *p_in, boolean8_t *m_in,
|
|
517
518
|
int in_alias)
|
|
518
519
|
{
|
|
520
|
+
/* A fiber of no cells has no address, but the view and its mask must
|
|
521
|
+
still read as attached. */
|
|
522
|
+
static char no_cells;
|
|
523
|
+
if ( st->t1->slab_elements == 0 ) {
|
|
524
|
+
if ( p_in == NULL ) p_in = &no_cells;
|
|
525
|
+
if ( m_in == NULL ) m_in = (boolean8_t *) &no_cells;
|
|
526
|
+
}
|
|
527
|
+
|
|
519
528
|
if ( in_alias ) {
|
|
520
529
|
/* ALIAS — single-axis OR multi-axis contig. ptr fast path uses
|
|
521
530
|
ca_index2addr * bytes + ptr (= safe since slab is row-major
|
|
@@ -751,7 +760,7 @@ ca_slab_run_map (ca_slab_iter_state_t *st)
|
|
|
751
760
|
st->t1->slab_dims);
|
|
752
761
|
if ( st->own_data_scratch != NULL ) {
|
|
753
762
|
st->own_out_scratch =
|
|
754
|
-
(
|
|
763
|
+
ca_alloc_cells_of(st->out_data_type, st->own_scratch_elements, st->out_bytes);
|
|
755
764
|
}
|
|
756
765
|
|
|
757
766
|
/* Step 4: per-slab loop.
|
|
@@ -779,7 +788,7 @@ ca_slab_run_map (ca_slab_iter_state_t *st)
|
|
|
779
788
|
piece = ca_slab_piece(st);
|
|
780
789
|
while ( ca_iter_state_next_slab_axes(st->t1, &p_in, &m_in) &&
|
|
781
790
|
ca_iter_state_next_slab_axes(st->t1_out, &p_out, &m_out) ) {
|
|
782
|
-
VALUE result;
|
|
791
|
+
volatile VALUE result;
|
|
783
792
|
|
|
784
793
|
ca_slab_advance_slab_view(st, slab_cs, carrier_cw,
|
|
785
794
|
src, p_in, m_in, in_alias);
|
data/ext/carray_sort.c
CHANGED
|
@@ -621,7 +621,7 @@ axis2addr_body (void *user_data, void *ptr, ca_size_t n)
|
|
|
621
621
|
* by rb_ca_take_along_axis_c / rb_ca_put_along_axis in
|
|
622
622
|
* carray_order.c. */
|
|
623
623
|
VALUE
|
|
624
|
-
rb_ca_axis2addr_c (VALUE self, VALUE vindices, VALUE vaxis)
|
|
624
|
+
rb_ca_axis2addr_c (VALUE self, volatile VALUE vindices, VALUE vaxis)
|
|
625
625
|
{
|
|
626
626
|
rb_check_carray_object(vindices);
|
|
627
627
|
|
|
@@ -958,6 +958,9 @@ rb_ca_sort_copy (int argc, VALUE *argv, VALUE self)
|
|
|
958
958
|
CA_FOR_EACH_FIBER_INOUT(st_in, st_out, cat, cao, (int8_t) axis,
|
|
959
959
|
CA_KERNEL_NO_MASK, pi, po, n) {
|
|
960
960
|
(void) fiber_n_for_check;
|
|
961
|
+
if ( n == 0 ) { /* an empty array's one fiber has no buffer */
|
|
962
|
+
continue;
|
|
963
|
+
}
|
|
961
964
|
memcpy(po, pi, (size_t) n * (size_t) bytes);
|
|
962
965
|
if ( do_stable ) {
|
|
963
966
|
switch ( cat->data_type ) {
|
|
@@ -970,12 +973,12 @@ rb_ca_sort_copy (int argc, VALUE *argv, VALUE self)
|
|
|
970
973
|
case CA_INT64: ca_sort_merge_i64((int64_t *) po, (int64_t *) aux, n); break;
|
|
971
974
|
case CA_UINT64: ca_sort_merge_u64((uint64_t *) po, (uint64_t *) aux, n); break;
|
|
972
975
|
case CA_FLOAT32: {
|
|
973
|
-
ca_size_t fin =
|
|
976
|
+
ca_size_t fin = ca_partition_nan_stable_f32((float32_t *) po, n, (float32_t *) aux);
|
|
974
977
|
ca_sort_merge_f32((float32_t *) po, (float32_t *) aux, fin);
|
|
975
978
|
break;
|
|
976
979
|
}
|
|
977
980
|
case CA_FLOAT64: {
|
|
978
|
-
ca_size_t fin =
|
|
981
|
+
ca_size_t fin = ca_partition_nan_stable_f64((double *) po, n, (double *) aux);
|
|
979
982
|
ca_sort_merge_f64((double *) po, (double *) aux, fin);
|
|
980
983
|
break;
|
|
981
984
|
}
|
data/ext/carray_sort_kernel.c
CHANGED
|
@@ -446,6 +446,30 @@ struct ca_partition_nan_##SUFFIX##_eat_semicolon
|
|
|
446
446
|
DEFINE_PARTITION_NAN(float32_t, f32);
|
|
447
447
|
DEFINE_PARTITION_NAN(double, f64);
|
|
448
448
|
|
|
449
|
+
/* Stable variant for a stable value sort: the finite values, then the
|
|
450
|
+
NaNs, each in their original order. scratch holds n values, taken by
|
|
451
|
+
the caller before it opens its walks. */
|
|
452
|
+
#define DEFINE_PARTITION_NAN_STABLE(TYPE, SUFFIX) \
|
|
453
|
+
ca_size_t \
|
|
454
|
+
ca_partition_nan_stable_##SUFFIX (TYPE *a, ca_size_t n, TYPE *scratch) \
|
|
455
|
+
{ \
|
|
456
|
+
ca_size_t fin = 0, k; \
|
|
457
|
+
for ( k = 0; k < n; k++ ) { \
|
|
458
|
+
if ( !isnan(a[k]) ) scratch[fin++] = a[k]; \
|
|
459
|
+
} \
|
|
460
|
+
if ( fin == n ) return n; \
|
|
461
|
+
ca_size_t m = fin; \
|
|
462
|
+
for ( k = 0; k < n; k++ ) { \
|
|
463
|
+
if ( isnan(a[k]) ) scratch[m++] = a[k]; \
|
|
464
|
+
} \
|
|
465
|
+
memcpy(a, scratch, (size_t) n * sizeof(TYPE)); \
|
|
466
|
+
return fin; \
|
|
467
|
+
} \
|
|
468
|
+
struct ca_partition_nan_stable_##SUFFIX##_eat_semicolon
|
|
469
|
+
|
|
470
|
+
DEFINE_PARTITION_NAN_STABLE(float32_t, f32);
|
|
471
|
+
DEFINE_PARTITION_NAN_STABLE(double, f64);
|
|
472
|
+
|
|
449
473
|
/* Pair variant for argsort: separates ca_pair_<type> by
|
|
450
474
|
isnan(v.value). Returns the finite count.
|
|
451
475
|
|
data/ext/carray_struct.c
CHANGED
|
@@ -113,9 +113,15 @@ ca_struct_read_primitive_fast (const char *p, int type_code)
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/* A String is read as a decimal number, as a store into the member's
|
|
117
|
+
field view reads it. */
|
|
116
118
|
static void
|
|
117
119
|
ca_struct_write_primitive_fast (char *p, int type_code, VALUE val)
|
|
118
120
|
{
|
|
121
|
+
if ( type_code != CA_BOOLEAN && RB_TYPE_P(val, T_STRING) ) {
|
|
122
|
+
ca_decimal_string_store(val, (int8_t) type_code, p);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
119
125
|
switch (type_code) {
|
|
120
126
|
case CA_BOOLEAN: {
|
|
121
127
|
/* The values a boolean array takes: true / false / 1 / 0. */
|
|
@@ -259,7 +265,7 @@ ca_struct_write_bitfield_fast (char *p, int view_bytes,
|
|
|
259
265
|
}
|
|
260
266
|
}
|
|
261
267
|
else {
|
|
262
|
-
v = NUM2ULL(val);
|
|
268
|
+
v = NUM2ULL(ca_integer_wrap_bits(val, bits, 0));
|
|
263
269
|
}
|
|
264
270
|
uint64_t mask = (bits >= 64) ? ~(uint64_t)0
|
|
265
271
|
: ((uint64_t)1 << bits) - 1;
|
|
@@ -324,6 +330,15 @@ ca_struct_read_endian_swapped_fast (const char *p, int type_code)
|
|
|
324
330
|
static void
|
|
325
331
|
ca_struct_write_endian_swapped_fast (char *p, int type_code, VALUE val)
|
|
326
332
|
{
|
|
333
|
+
if ( RB_TYPE_P(val, T_STRING) ) {
|
|
334
|
+
char host[8];
|
|
335
|
+
ca_decimal_string_store(val, (int8_t) type_code, host);
|
|
336
|
+
switch ( ca_sizeof[type_code] ) {
|
|
337
|
+
case 2: { uint16_t v; memcpy(&v, host, 2); v = CA_BSWAP16(v); memcpy(p, &v, 2); return; }
|
|
338
|
+
case 4: { uint32_t v; memcpy(&v, host, 4); v = CA_BSWAP32(v); memcpy(p, &v, 4); return; }
|
|
339
|
+
case 8: { uint64_t v; memcpy(&v, host, 8); v = CA_BSWAP64(v); memcpy(p, &v, 8); return; }
|
|
340
|
+
}
|
|
341
|
+
}
|
|
327
342
|
switch (type_code) {
|
|
328
343
|
case CA_INT16: {
|
|
329
344
|
uint16_t v = (uint16_t) NUM2LL(ca_obj2integer_fitting(val, CA_INT16));
|
|
@@ -425,7 +440,7 @@ ca_struct_member_name (VALUE klass, VALUE name)
|
|
|
425
440
|
if ( ! RB_TYPE_P(name, T_STRING) && ! RB_TYPE_P(name, T_FIXNUM) ) {
|
|
426
441
|
rb_raise(rb_eTypeError,
|
|
427
442
|
"a struct member is named by a String or an Integer position "
|
|
428
|
-
"(got %
|
|
443
|
+
"(got %"PRIsVALUE")", rb_obj_class(name));
|
|
429
444
|
}
|
|
430
445
|
name_s = ca_struct_resolve_name(klass, name);
|
|
431
446
|
if ( NIL_P(name_s)
|
|
@@ -708,8 +723,8 @@ rb_ca_struct_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
708
723
|
VALUE unknown_inspect = rb_inspect(state.unknown_keys);
|
|
709
724
|
VALUE known_inspect = rb_inspect(members);
|
|
710
725
|
rb_raise(rb_eArgError,
|
|
711
|
-
"unknown member(s) for %
|
|
712
|
-
|
|
726
|
+
"unknown member(s) for %"PRIsVALUE": %s (known: %s)",
|
|
727
|
+
klass,
|
|
713
728
|
StringValueCStr(unknown_inspect),
|
|
714
729
|
StringValueCStr(known_inspect));
|
|
715
730
|
}
|
|
@@ -721,8 +736,8 @@ rb_ca_struct_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
721
736
|
long mems_size = RARRAY_LEN(members);
|
|
722
737
|
if (argc > mems_size) {
|
|
723
738
|
rb_raise(rb_eArgError,
|
|
724
|
-
"too many arguments for %
|
|
725
|
-
|
|
739
|
+
"too many arguments for %"PRIsVALUE".new (<%d> for <%ld>)",
|
|
740
|
+
klass, argc, mems_size);
|
|
726
741
|
}
|
|
727
742
|
for (int i = 0; i < argc; i++) {
|
|
728
743
|
VALUE name_s = rb_ary_entry(members, i);
|
data/ext/carray_test.c
CHANGED
|
@@ -201,6 +201,23 @@ rb_ca_is_type (VALUE arg, int type)
|
|
|
201
201
|
live in ca_obj_record.c; signatures stay in carray.h for cross-file
|
|
202
202
|
extern use. */
|
|
203
203
|
|
|
204
|
+
/* Whether v, an index along a length of n, names a position: a negative one
|
|
205
|
+
* counts from the end. An Integer too large for ca_size_t is out of any
|
|
206
|
+
* range; what is not an Integer is not an index. */
|
|
207
|
+
static int
|
|
208
|
+
ca_index_arg_in_range (VALUE v, ca_size_t n, const char *arg)
|
|
209
|
+
{
|
|
210
|
+
ca_size_t idx;
|
|
211
|
+
if ( RB_TYPE_P(v, T_BIGNUM) ) {
|
|
212
|
+
return 0;
|
|
213
|
+
}
|
|
214
|
+
idx = ca_integer_arg(v, arg, NULL);
|
|
215
|
+
if ( idx < 0 ) {
|
|
216
|
+
idx += n;
|
|
217
|
+
}
|
|
218
|
+
return idx >= 0 && idx < n;
|
|
219
|
+
}
|
|
220
|
+
|
|
204
221
|
/* CArray#valid_index?(*idx) -- whether self[*idx] names a cell: a negative
|
|
205
222
|
* index counts from the end of its axis, as it does at every door. The
|
|
206
223
|
* number of indices must equal ndim (raises otherwise). */
|
|
@@ -208,7 +225,6 @@ static VALUE
|
|
|
208
225
|
rb_ca_is_valid_index (int argc, VALUE *argv, VALUE self)
|
|
209
226
|
{
|
|
210
227
|
CArray *ca;
|
|
211
|
-
ca_size_t idx;
|
|
212
228
|
int i;
|
|
213
229
|
|
|
214
230
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
@@ -218,11 +234,7 @@ rb_ca_is_valid_index (int argc, VALUE *argv, VALUE self)
|
|
|
218
234
|
"invalid # of arguments (%i for %i)", argc, ca->ndim);
|
|
219
235
|
}
|
|
220
236
|
for (i=0; i<ca->ndim; i++) {
|
|
221
|
-
|
|
222
|
-
if ( idx < 0 ) {
|
|
223
|
-
idx += ca->dim[i];
|
|
224
|
-
}
|
|
225
|
-
if ( idx < 0 || idx >= ca->dim[i] ) {
|
|
237
|
+
if ( ! ca_index_arg_in_range(argv[i], ca->dim[i], "an index") ) {
|
|
226
238
|
return Qfalse;
|
|
227
239
|
}
|
|
228
240
|
}
|
|
@@ -236,30 +248,26 @@ static VALUE
|
|
|
236
248
|
rb_ca_is_valid_addr (VALUE self, VALUE raddr)
|
|
237
249
|
{
|
|
238
250
|
CArray *ca;
|
|
239
|
-
ca_size_t addr;
|
|
240
251
|
|
|
241
252
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
242
|
-
|
|
243
|
-
if ( addr < 0 ) {
|
|
244
|
-
addr += ca->elements;
|
|
245
|
-
}
|
|
246
|
-
if ( addr < 0 || addr >= ca->elements ) {
|
|
247
|
-
return Qfalse;
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
return Qtrue;
|
|
251
|
-
}
|
|
253
|
+
return ca_index_arg_in_range(raddr, ca->elements, "an address") ? Qtrue : Qfalse;
|
|
252
254
|
}
|
|
253
255
|
|
|
254
|
-
/* CArray#same_shape?(other) —
|
|
255
|
-
* Scalars compare true against any array (see ca_has_same_shape).
|
|
256
|
+
/* CArray#same_shape?(other) — whether self and other share ndim and dim[].
|
|
257
|
+
* Scalars compare true against any array (see ca_has_same_shape). Only the
|
|
258
|
+
* shape is compared, so no value is converted: other that is not a CArray
|
|
259
|
+
* takes the shape it has as an object array. */
|
|
256
260
|
static VALUE
|
|
257
261
|
rb_ca_has_same_shape (VALUE self, VALUE other)
|
|
258
262
|
{
|
|
259
263
|
CArray *ca, *cb;
|
|
260
264
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
261
|
-
|
|
262
|
-
|
|
265
|
+
if ( rb_obj_is_carray(other) ) {
|
|
266
|
+
TypedData_Get_Struct(other, CArray, &carray_data_type, cb);
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
cb = ca_wrap_readonly(other, CA_OBJECT);
|
|
270
|
+
}
|
|
263
271
|
return ca_has_same_shape(ca, cb) ? Qtrue : Qfalse;
|
|
264
272
|
}
|
|
265
273
|
|
|
@@ -276,10 +284,22 @@ eql_## type (const char *a, const char *b, ca_size_t bytes) \
|
|
|
276
284
|
|
|
277
285
|
/* == compares contents: a NaN equals a NaN (whatever its payload), as the
|
|
278
286
|
same array read back or copied holds the same NaN; -0.0 equals 0.0 as
|
|
279
|
-
values do. eql? stays bitwise.
|
|
287
|
+
values do. eql? stays bitwise. An object cell equals itself first, as
|
|
288
|
+
in Array#== and Array#eql?, so a copy of an array holding any NaN object
|
|
289
|
+
equals it. A cell holding a CArray is asked all the same, so an array
|
|
290
|
+
that holds itself is refused as cyclic. */
|
|
291
|
+
static int
|
|
292
|
+
ca_object_cells_identical (VALUE x, VALUE y)
|
|
293
|
+
{
|
|
294
|
+
return x == y && ! rb_obj_is_carray(x);
|
|
295
|
+
}
|
|
296
|
+
|
|
280
297
|
static int
|
|
281
298
|
ca_object_cells_equal (VALUE x, VALUE y)
|
|
282
299
|
{
|
|
300
|
+
if ( ca_object_cells_identical(x, y) ) {
|
|
301
|
+
return 1;
|
|
302
|
+
}
|
|
283
303
|
if ( RB_FLOAT_TYPE_P(x) && RB_FLOAT_TYPE_P(y) &&
|
|
284
304
|
isnan(RFLOAT_VALUE(x)) && isnan(RFLOAT_VALUE(y)) ) {
|
|
285
305
|
return 1;
|
|
@@ -287,6 +307,13 @@ ca_object_cells_equal (VALUE x, VALUE y)
|
|
|
287
307
|
return RTEST(rb_funcall(x, id_equal, 1, y)) ? 1 : 0;
|
|
288
308
|
}
|
|
289
309
|
|
|
310
|
+
static int
|
|
311
|
+
ca_object_cells_eql (VALUE x, VALUE y)
|
|
312
|
+
{
|
|
313
|
+
return ca_object_cells_identical(x, y)
|
|
314
|
+
|| RTEST(rb_funcall(x, id_eql, 1, y));
|
|
315
|
+
}
|
|
316
|
+
|
|
290
317
|
static int
|
|
291
318
|
eql_VALUE (const char *a, const char *b, ca_size_t bytes)
|
|
292
319
|
{
|
|
@@ -416,8 +443,7 @@ ca_compare_body (VALUE arg)
|
|
|
416
443
|
for (i=0; i<ca->elements; i++) {
|
|
417
444
|
volatile VALUE x = va[i];
|
|
418
445
|
volatile VALUE y = vb[i];
|
|
419
|
-
int eq = strict ?
|
|
420
|
-
: ca_object_cells_equal(x, y);
|
|
446
|
+
int eq = strict ? ca_object_cells_eql(x, y) : ca_object_cells_equal(x, y);
|
|
421
447
|
if ( ! eq ) {
|
|
422
448
|
flag = 0;
|
|
423
449
|
break;
|
|
@@ -459,8 +485,7 @@ ca_compare_body (VALUE arg)
|
|
|
459
485
|
if ( is_object ) {
|
|
460
486
|
volatile VALUE x = *(VALUE *) pa;
|
|
461
487
|
volatile VALUE y = *(VALUE *) pb;
|
|
462
|
-
eq = strict ?
|
|
463
|
-
: ca_object_cells_equal(x, y);
|
|
488
|
+
eq = strict ? ca_object_cells_eql(x, y) : ca_object_cells_equal(x, y);
|
|
464
489
|
}
|
|
465
490
|
else if ( strict
|
|
466
491
|
|| ca->data_type <= CA_UINT64
|
|
@@ -507,7 +532,7 @@ ca_compare_run (VALUE arg)
|
|
|
507
532
|
*
|
|
508
533
|
* The only difference is the per-element comparator:
|
|
509
534
|
* == : ca_eql[data_type] (by value: NaN equals NaN, -0.0 equals 0.0)
|
|
510
|
-
* eql?: memcmp for numeric,
|
|
535
|
+
* eql?: memcmp for numeric, ca_object_cells_eql for CA_OBJECT
|
|
511
536
|
*
|
|
512
537
|
* The unmasked-unmasked branch takes a bulk memcmp or per-cell
|
|
513
538
|
* shortcut to amortise per-element function pointer dispatch. */
|
|
@@ -659,6 +684,24 @@ rb_ca_eql (VALUE self, VALUE other)
|
|
|
659
684
|
|
|
660
685
|
#define CA_HASH_SAMPLE_BYTES 64
|
|
661
686
|
|
|
687
|
+
typedef struct {
|
|
688
|
+
st_index_t h;
|
|
689
|
+
ca_size_t n;
|
|
690
|
+
const VALUE *cells;
|
|
691
|
+
} ca_hash_cells_t;
|
|
692
|
+
|
|
693
|
+
static VALUE
|
|
694
|
+
ca_hash_cells (VALUE arg)
|
|
695
|
+
{
|
|
696
|
+
ca_hash_cells_t *hc = (ca_hash_cells_t *) arg;
|
|
697
|
+
ca_size_t i;
|
|
698
|
+
|
|
699
|
+
for (i = 0; i < hc->n; i++) {
|
|
700
|
+
hc->h = rb_hash_uint(hc->h, (st_index_t) NUM2LONG(rb_hash(hc->cells[i])));
|
|
701
|
+
}
|
|
702
|
+
return Qnil;
|
|
703
|
+
}
|
|
704
|
+
|
|
662
705
|
static st_index_t
|
|
663
706
|
ca_hash (CArray *ca)
|
|
664
707
|
{
|
|
@@ -668,19 +711,21 @@ ca_hash (CArray *ca)
|
|
|
668
711
|
ca_size_t data_len = ca_length(ca);
|
|
669
712
|
ca_size_t sample = (data_len < CA_HASH_SAMPLE_BYTES) ? data_len : CA_HASH_SAMPLE_BYTES;
|
|
670
713
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
h
|
|
674
|
-
h
|
|
675
|
-
h
|
|
714
|
+
/* Mixed in order: XOR would cancel equal fields, as a 1-D array's dim
|
|
715
|
+
and elements are. */
|
|
716
|
+
h = rb_hash_start(ca->data_type);
|
|
717
|
+
h = rb_hash_uint(h, (st_index_t) ca->ndim);
|
|
718
|
+
h = rb_hash_uint(h, (st_index_t) ca->bytes);
|
|
719
|
+
h = rb_hash_uint(h, (st_index_t) ca->elements);
|
|
720
|
+
h = rb_hash_uint(h, (st_index_t) scalar_flag);
|
|
676
721
|
if ( ca->ndim > 0 ) {
|
|
677
|
-
h
|
|
722
|
+
h = rb_hash_uint(h, rb_memhash(ca->dim, sizeof(ca_size_t) * ca->ndim));
|
|
678
723
|
}
|
|
679
724
|
|
|
680
725
|
/* ca_is_any_masked() attaches/detaches the mask internally and returns
|
|
681
726
|
only a boolean, so we never touch ca->mask->ptr here. */
|
|
682
727
|
masked_flag = ca_is_any_masked(ca) ? 1 : 0;
|
|
683
|
-
h
|
|
728
|
+
h = rb_hash_uint(h, (st_index_t) masked_flag);
|
|
684
729
|
|
|
685
730
|
if ( ! masked_flag && sample > 0 ) {
|
|
686
731
|
ca_size_t addrs[CA_HASH_SAMPLE_BYTES];
|
|
@@ -700,22 +745,23 @@ ca_hash (CArray *ca)
|
|
|
700
745
|
#hash, not the VALUE bits. The cells sit on the stack, where the
|
|
701
746
|
GC sees them while #hash runs. */
|
|
702
747
|
VALUE cells[CA_HASH_SAMPLE_BYTES / sizeof(VALUE)];
|
|
748
|
+
ca_hash_cells_t hc;
|
|
703
749
|
ca_xfer_addrs(ca, ncell, addrs, cells, CA_XFER_GET);
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
750
|
+
hc.h = h; hc.n = ncell; hc.cells = cells;
|
|
751
|
+
ca_cell_walk_run(ca_hash_cells, (VALUE) &hc);
|
|
752
|
+
h = hc.h;
|
|
707
753
|
RB_GC_GUARD(cells[0]);
|
|
708
754
|
}
|
|
709
755
|
else {
|
|
710
756
|
volatile VALUE holder;
|
|
711
757
|
char *buf = ALLOCV_N(char, holder, ncell * ca->bytes);
|
|
712
758
|
ca_xfer_addrs(ca, ncell, addrs, buf, CA_XFER_GET);
|
|
713
|
-
h
|
|
759
|
+
h = rb_hash_uint(h, rb_memhash(buf, ncell * ca->bytes));
|
|
714
760
|
ALLOCV_END(holder);
|
|
715
761
|
}
|
|
716
762
|
}
|
|
717
763
|
|
|
718
|
-
return h;
|
|
764
|
+
return rb_hash_end(h);
|
|
719
765
|
}
|
|
720
766
|
|
|
721
767
|
/* CArray#hash — Hash key value; wraps ca_hash into a Ruby Integer. */
|
data/ext/carray_time_text.c
CHANGED
|
@@ -602,6 +602,12 @@ rb_ca_s_time_ticks_from_fields (VALUE klass,
|
|
|
602
602
|
other than Z, UTC and GMT, an offset written another way) is deferred to
|
|
603
603
|
Date._strptime for that cell.
|
|
604
604
|
|
|
605
|
+
Three inputs read differently from Date._strptime. A format with both
|
|
606
|
+
a two-digit year and a four-digit year takes the four-digit year, where
|
|
607
|
+
Date._strptime adds the century to it. %Z ends at the zone's name, so
|
|
608
|
+
digits directly after it go to the next directive. A NUL in the text
|
|
609
|
+
is text, so it is left over.
|
|
610
|
+
|
|
605
611
|
Strict reading, used to find the format a column is written in, holds
|
|
606
612
|
the text to the shape of the format: %Y is four digits and %y two, %N
|
|
607
613
|
one to nine digits, the other numbers one or two digits (two when a
|