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/ca_obj_const_string.c
CHANGED
|
@@ -372,7 +372,7 @@ rb_ca_const_string_wrap_method (int argc, VALUE *argv, VALUE klass)
|
|
|
372
372
|
per-element Ruby build loop -- no `String#b` copy, no `pack`, no per-row
|
|
373
373
|
method dispatch. `renc` is the target Encoding (nil = UTF-8). */
|
|
374
374
|
static VALUE
|
|
375
|
-
rb_ca_const_string_build (VALUE klass, VALUE values, VALUE renc)
|
|
375
|
+
rb_ca_const_string_build (VALUE klass, volatile VALUE values, VALUE renc)
|
|
376
376
|
{
|
|
377
377
|
long i, n;
|
|
378
378
|
int encoding_id;
|
|
@@ -385,6 +385,8 @@ rb_ca_const_string_build (VALUE klass, VALUE values, VALUE renc)
|
|
|
385
385
|
long hint = 0;
|
|
386
386
|
|
|
387
387
|
Check_Type(values, T_ARRAY);
|
|
388
|
+
/* A to_s below can change the caller's Array; read a copy of it. */
|
|
389
|
+
values = rb_ary_dup(values);
|
|
388
390
|
n = RARRAY_LEN(values);
|
|
389
391
|
encoding_id = NIL_P(renc) ? rb_utf8_encindex() : rb_to_encoding_index(renc);
|
|
390
392
|
enc = rb_enc_from_index(encoding_id);
|
|
@@ -403,7 +405,7 @@ rb_ca_const_string_build (VALUE klass, VALUE values, VALUE renc)
|
|
|
403
405
|
pair = (int64_t *) pe->ptr;
|
|
404
406
|
|
|
405
407
|
for ( i = 0; i < n; i++ ) {
|
|
406
|
-
VALUE s = RARRAY_AREF(values, i);
|
|
408
|
+
volatile VALUE s = RARRAY_AREF(values, i);
|
|
407
409
|
if ( NIL_P(s) ) {
|
|
408
410
|
if ( ! mask ) {
|
|
409
411
|
ca_create_mask(pe);
|
|
@@ -506,6 +508,76 @@ rb_ca_const_string_to_string (VALUE self)
|
|
|
506
508
|
rb_intern("wrap"), 1, out);
|
|
507
509
|
}
|
|
508
510
|
|
|
511
|
+
/* A scan reads the (start,end) pairs and the bytes of a column. */
|
|
512
|
+
typedef struct {
|
|
513
|
+
CAConstString *ca;
|
|
514
|
+
int64_t *off;
|
|
515
|
+
boolean8_t *m;
|
|
516
|
+
const char *buf;
|
|
517
|
+
long buflen;
|
|
518
|
+
ca_size_t n;
|
|
519
|
+
} ca_const_string_scan_t;
|
|
520
|
+
|
|
521
|
+
/* What a scan's body runs with the window open. s holds one scan, or two
|
|
522
|
+
for an operation on a pair of arrays. */
|
|
523
|
+
typedef VALUE (*ca_const_string_scan_body_t) (ca_const_string_scan_t *s, void *arg);
|
|
524
|
+
|
|
525
|
+
typedef struct {
|
|
526
|
+
int32_t n;
|
|
527
|
+
ca_const_string_scan_t *s;
|
|
528
|
+
ca_const_string_scan_body_t body;
|
|
529
|
+
void *arg;
|
|
530
|
+
} ca_const_string_run_t;
|
|
531
|
+
|
|
532
|
+
static VALUE
|
|
533
|
+
ca_const_string_run_body (VALUE varg)
|
|
534
|
+
{
|
|
535
|
+
ca_const_string_run_t *r = (ca_const_string_run_t *) varg;
|
|
536
|
+
int32_t k;
|
|
537
|
+
for ( k = 0; k < r->n; k++ ) {
|
|
538
|
+
ca_const_string_scan_t *s = &r->s[k];
|
|
539
|
+
s->off = (int64_t *) s->ca->ptr;
|
|
540
|
+
s->m = s->ca->mask ? (boolean8_t *) s->ca->mask->ptr : NULL;
|
|
541
|
+
s->buf = RSTRING_PTR(s->ca->buffer);
|
|
542
|
+
s->buflen = RSTRING_LEN(s->ca->buffer);
|
|
543
|
+
s->n = s->ca->elements;
|
|
544
|
+
}
|
|
545
|
+
return r->body(r->s, r->arg);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/* Runs body(s, arg) with the offsets of the n (1 or 2) columns in cols
|
|
549
|
+
attached, s[k] scanning cols[k], and closes the window however body
|
|
550
|
+
leaves: what body allocates can fail, and body may raise. */
|
|
551
|
+
static VALUE
|
|
552
|
+
ca_const_string_scan_cols (int32_t n, const VALUE *cols,
|
|
553
|
+
ca_const_string_scan_t *s,
|
|
554
|
+
ca_const_string_scan_body_t body, void *arg)
|
|
555
|
+
{
|
|
556
|
+
ca_const_string_run_t r;
|
|
557
|
+
CArray *list[2];
|
|
558
|
+
int32_t k;
|
|
559
|
+
|
|
560
|
+
r.n = n;
|
|
561
|
+
r.s = s;
|
|
562
|
+
r.body = body;
|
|
563
|
+
r.arg = arg;
|
|
564
|
+
for ( k = 0; k < n; k++ ) {
|
|
565
|
+
TypedData_Get_Struct(cols[k], CAConstString, &catext_data_type, s[k].ca);
|
|
566
|
+
ca_update_mask((CArray *) s[k].ca);
|
|
567
|
+
list[k] = (CArray *) s[k].ca;
|
|
568
|
+
}
|
|
569
|
+
return ca_attach_window(n, list, n == 2 ? "rr" : "r",
|
|
570
|
+
ca_const_string_run_body, (VALUE) &r);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/* The scan of one column. */
|
|
574
|
+
static VALUE
|
|
575
|
+
ca_const_string_scan_run (VALUE self, ca_const_string_scan_t *s,
|
|
576
|
+
ca_const_string_scan_body_t body, void *arg)
|
|
577
|
+
{
|
|
578
|
+
return ca_const_string_scan_cols(1, &self, s, body, arg);
|
|
579
|
+
}
|
|
580
|
+
|
|
509
581
|
/* copy = compacting deep copy — the only chain-descent point in
|
|
510
582
|
CAConstString. Produces a standalone CAConstString:
|
|
511
583
|
- a fresh contiguous fixlen-16 (start,end) pair entity
|
|
@@ -515,73 +587,76 @@ rb_ca_const_string_to_string (VALUE self)
|
|
|
515
587
|
- fully detached from the original buffer / pair-source
|
|
516
588
|
Cost is O(live bytes); a near-full copy is a near-full rebuild (accepted).
|
|
517
589
|
Done at the byte level (no per-element Ruby String boxing). */
|
|
590
|
+
typedef struct {
|
|
591
|
+
volatile VALUE pairs; /* the new (start,end) pair entity */
|
|
592
|
+
volatile VALUE buffer; /* the compacted bytes */
|
|
593
|
+
} ca_const_string_copy_t;
|
|
594
|
+
|
|
595
|
+
/* Repacks each live record's bytes into a new buffer in the view's order,
|
|
596
|
+
writing the new pairs and carrying the mask. */
|
|
518
597
|
static VALUE
|
|
519
|
-
|
|
598
|
+
ca_const_string_copy_body (ca_const_string_scan_t *scan, void *arg)
|
|
520
599
|
{
|
|
521
|
-
|
|
522
|
-
|
|
600
|
+
ca_const_string_scan_t s0 = *scan, *s = &s0; /* a local copy: the writes below cannot alias it */
|
|
601
|
+
ca_const_string_copy_t *c = (ca_const_string_copy_t *) arg;
|
|
523
602
|
CArray *co;
|
|
524
|
-
ca_size_t i
|
|
525
|
-
int64_t *
|
|
526
|
-
boolean8_t *m = NULL;
|
|
527
|
-
const char *oldbuf;
|
|
528
|
-
long oldbuflen;
|
|
529
|
-
|
|
530
|
-
TypedData_Get_Struct(self, CAConstString, &catext_data_type, ca);
|
|
531
|
-
|
|
532
|
-
/* materialize logical-order (start,end) pairs + mask */
|
|
533
|
-
ca_update_mask((CArray *) ca);
|
|
534
|
-
ca_attach((CArray *) ca); /* window: detached before its one raise */
|
|
535
|
-
|
|
536
|
-
n = ca->elements;
|
|
537
|
-
src_pair = (int64_t *) ca->ptr;
|
|
538
|
-
m = ca->mask ? (boolean8_t *) ca->mask->ptr : NULL;
|
|
539
|
-
oldbuf = RSTRING_PTR(ca->buffer);
|
|
540
|
-
oldbuflen = RSTRING_LEN(ca->buffer);
|
|
603
|
+
ca_size_t i;
|
|
604
|
+
int64_t *dst_pair;
|
|
541
605
|
|
|
542
606
|
/* fresh fixlen-16 pair entity, same shape (N-D preserved) */
|
|
543
|
-
|
|
544
|
-
|
|
607
|
+
c->pairs = rb_carray_new(CA_FIXLEN, s->ca->ndim, s->ca->dim,
|
|
608
|
+
2 * sizeof(int64_t), NULL);
|
|
609
|
+
TypedData_Get_Struct(c->pairs, CArray, &carray_data_type, co);
|
|
545
610
|
dst_pair = (int64_t *) co->ptr;
|
|
546
611
|
|
|
547
612
|
/* growable compacted buffer (BINARY) */
|
|
548
|
-
|
|
549
|
-
rb_enc_associate_index(
|
|
613
|
+
c->buffer = rb_str_buf_new(s->buflen);
|
|
614
|
+
rb_enc_associate_index(c->buffer, rb_ascii8bit_encindex());
|
|
550
615
|
|
|
551
|
-
for ( i = 0; i < n; i++ ) {
|
|
616
|
+
for ( i = 0; i < s->n; i++ ) {
|
|
552
617
|
int64_t start, end, len;
|
|
553
|
-
if ( m && m[i] ) {
|
|
618
|
+
if ( s->m && s->m[i] ) {
|
|
554
619
|
dst_pair[2 * i] = 0;
|
|
555
620
|
dst_pair[2 * i + 1] = 0;
|
|
556
621
|
continue;
|
|
557
622
|
}
|
|
558
|
-
start =
|
|
559
|
-
end =
|
|
623
|
+
start = s->off[2 * i];
|
|
624
|
+
end = s->off[2 * i + 1];
|
|
560
625
|
len = end - start;
|
|
561
|
-
if ( start < 0 || len < 0 || end > (int64_t)
|
|
562
|
-
ca_detach((CArray *) ca);
|
|
626
|
+
if ( start < 0 || len < 0 || end > (int64_t) s->buflen ) {
|
|
563
627
|
rb_raise(rb_eIndexError,
|
|
564
628
|
"CAConstString#copy: record [%lld,%lld) out of buffer range",
|
|
565
629
|
(long long) start, (long long) end);
|
|
566
630
|
}
|
|
567
|
-
dst_pair[2 * i] = (int64_t) RSTRING_LEN(
|
|
568
|
-
rb_str_cat(
|
|
569
|
-
dst_pair[2 * i + 1] = (int64_t) RSTRING_LEN(
|
|
631
|
+
dst_pair[2 * i] = (int64_t) RSTRING_LEN(c->buffer);
|
|
632
|
+
rb_str_cat(c->buffer, s->buf + start, (long) len);
|
|
633
|
+
dst_pair[2 * i + 1] = (int64_t) RSTRING_LEN(c->buffer);
|
|
570
634
|
}
|
|
571
635
|
|
|
572
636
|
/* carry mask onto the new pair entity */
|
|
573
|
-
if ( m ) {
|
|
637
|
+
if ( s->m ) {
|
|
574
638
|
boolean8_t *nm;
|
|
575
639
|
ca_create_mask(co);
|
|
576
640
|
nm = (boolean8_t *) co->mask->ptr;
|
|
577
|
-
for ( i = 0; i < n; i++ ) {
|
|
578
|
-
nm[i] = m[i] ? 1 : 0;
|
|
641
|
+
for ( i = 0; i < s->n; i++ ) {
|
|
642
|
+
nm[i] = s->m[i] ? 1 : 0;
|
|
579
643
|
}
|
|
580
644
|
}
|
|
645
|
+
return Qnil;
|
|
646
|
+
}
|
|
581
647
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
648
|
+
static VALUE
|
|
649
|
+
rb_ca_const_string_copy (VALUE self)
|
|
650
|
+
{
|
|
651
|
+
ca_const_string_scan_t s;
|
|
652
|
+
ca_const_string_copy_t c;
|
|
653
|
+
volatile VALUE vout;
|
|
654
|
+
|
|
655
|
+
c.pairs = Qnil;
|
|
656
|
+
c.buffer = Qnil;
|
|
657
|
+
ca_const_string_scan_run(self, &s, ca_const_string_copy_body, &c);
|
|
658
|
+
vout = rb_ca_const_string_wrap(c.pairs, rb_str_freeze(c.buffer),
|
|
659
|
+
s.ca->encoding_id);
|
|
585
660
|
rb_ca_inherit_attr(vout, self);
|
|
586
661
|
return vout;
|
|
587
662
|
}
|
|
@@ -604,67 +679,6 @@ rb_ca_const_string_to_ca (int argc, VALUE *argv, VALUE self)
|
|
|
604
679
|
the layer where CAConstString outperforms `to_object` followed by
|
|
605
680
|
per-cell Ruby String work. */
|
|
606
681
|
|
|
607
|
-
typedef struct {
|
|
608
|
-
CAConstString *ca;
|
|
609
|
-
int64_t *off;
|
|
610
|
-
boolean8_t *m;
|
|
611
|
-
const char *buf;
|
|
612
|
-
long buflen;
|
|
613
|
-
ca_size_t n;
|
|
614
|
-
} ca_const_string_scan_t;
|
|
615
|
-
|
|
616
|
-
/* Opens the scan's window; ca_const_string_scan_end closes it. What runs
|
|
617
|
-
between them in this file reads bytes and raises only after closing. */
|
|
618
|
-
static void
|
|
619
|
-
ca_const_string_scan_begin (VALUE self, ca_const_string_scan_t *s)
|
|
620
|
-
{
|
|
621
|
-
TypedData_Get_Struct(self, CAConstString, &catext_data_type, s->ca);
|
|
622
|
-
ca_update_mask((CArray *) s->ca);
|
|
623
|
-
ca_attach((CArray *) s->ca); /* window: closed by ca_const_string_scan_end */
|
|
624
|
-
s->off = (int64_t *) s->ca->ptr;
|
|
625
|
-
s->m = s->ca->mask ? (boolean8_t *) s->ca->mask->ptr : NULL;
|
|
626
|
-
s->buf = RSTRING_PTR(s->ca->buffer);
|
|
627
|
-
s->buflen = RSTRING_LEN(s->ca->buffer);
|
|
628
|
-
s->n = s->ca->elements;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
static void
|
|
632
|
-
ca_const_string_scan_end (ca_const_string_scan_t *s)
|
|
633
|
-
{
|
|
634
|
-
ca_detach((CArray *) s->ca);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
typedef struct {
|
|
638
|
-
VALUE self;
|
|
639
|
-
ca_const_string_scan_t *s;
|
|
640
|
-
} ca_const_string_scan_arg_t;
|
|
641
|
-
|
|
642
|
-
static VALUE
|
|
643
|
-
ca_const_string_scan_begin_body (VALUE arg)
|
|
644
|
-
{
|
|
645
|
-
ca_const_string_scan_arg_t *x = (ca_const_string_scan_arg_t *) arg;
|
|
646
|
-
ca_const_string_scan_begin(x->self, x->s);
|
|
647
|
-
return Qnil;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
/* Begins the scans of two arrays, both or neither: when the second one's
|
|
651
|
-
attach raises, the first is closed before the raise goes on. */
|
|
652
|
-
static void
|
|
653
|
-
ca_const_string_scan_begin_pair (VALUE va, ca_const_string_scan_t *a,
|
|
654
|
-
VALUE vb, ca_const_string_scan_t *b)
|
|
655
|
-
{
|
|
656
|
-
ca_const_string_scan_arg_t x;
|
|
657
|
-
int tag = 0;
|
|
658
|
-
ca_const_string_scan_begin(va, a);
|
|
659
|
-
x.self = vb;
|
|
660
|
-
x.s = b;
|
|
661
|
-
/* protect: ends the first scan, which is not an array */
|
|
662
|
-
rb_protect(ca_const_string_scan_begin_body, (VALUE) &x, &tag);
|
|
663
|
-
if ( tag ) {
|
|
664
|
-
ca_const_string_scan_end(a);
|
|
665
|
-
rb_jump_tag(tag);
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
682
|
|
|
669
683
|
/* Resolve element i to its record bytes; returns 0 if masked.
|
|
670
684
|
Storage is (start,end) int64 pairs: s->off holds 2 int64 per element,
|
|
@@ -720,65 +734,72 @@ ca_const_string_memmem (const char *hay, long hlen, const char *need, long nlen)
|
|
|
720
734
|
return NULL;
|
|
721
735
|
}
|
|
722
736
|
|
|
723
|
-
/* CAConstString#byte_length → int64 CArray of per-element byte lengths. */
|
|
724
737
|
static VALUE
|
|
725
|
-
|
|
738
|
+
ca_const_string_byte_length_body (ca_const_string_scan_t *scan, void *arg)
|
|
726
739
|
{
|
|
727
|
-
ca_const_string_scan_t s;
|
|
728
|
-
VALUE vout;
|
|
740
|
+
ca_const_string_scan_t s0 = *scan, *s = &s0; /* a local copy: the writes below cannot alias it */
|
|
741
|
+
volatile VALUE vout;
|
|
729
742
|
CArray *co;
|
|
730
743
|
int64_t *op;
|
|
731
744
|
const char *p;
|
|
732
745
|
int64_t len;
|
|
733
746
|
ca_size_t i;
|
|
734
747
|
|
|
735
|
-
|
|
736
|
-
vout = rb_carray_new(CA_INT64, s.ca->ndim, s.ca->dim, 0, NULL);
|
|
748
|
+
vout = rb_carray_new(CA_INT64, s->ca->ndim, s->ca->dim, 0, NULL);
|
|
737
749
|
TypedData_Get_Struct(vout, CArray, &carray_data_type, co);
|
|
738
750
|
op = (int64_t *) co->ptr;
|
|
739
|
-
for ( i = 0; i < s
|
|
740
|
-
op[i] = ca_const_string_record(
|
|
751
|
+
for ( i = 0; i < s->n; i++ ) {
|
|
752
|
+
op[i] = ca_const_string_record(s, i, &p, &len) ? (int64_t) len : 0;
|
|
741
753
|
}
|
|
742
|
-
if ( s
|
|
754
|
+
if ( s->m ) {
|
|
743
755
|
boolean8_t *nm;
|
|
744
756
|
ca_create_mask(co);
|
|
745
757
|
nm = (boolean8_t *) co->mask->ptr;
|
|
746
|
-
for ( i = 0; i < s
|
|
747
|
-
nm[i] = s
|
|
758
|
+
for ( i = 0; i < s->n; i++ ) {
|
|
759
|
+
nm[i] = s->m[i] ? 1 : 0;
|
|
748
760
|
}
|
|
749
761
|
}
|
|
750
|
-
ca_const_string_scan_end(&s);
|
|
751
762
|
return vout;
|
|
752
763
|
}
|
|
753
764
|
|
|
765
|
+
/* CAConstString#byte_length → int64 CArray of per-element byte lengths. */
|
|
766
|
+
static VALUE
|
|
767
|
+
rb_ca_const_string_byte_length (VALUE self)
|
|
768
|
+
{
|
|
769
|
+
ca_const_string_scan_t s;
|
|
770
|
+
return ca_const_string_scan_run(self, &s,
|
|
771
|
+
ca_const_string_byte_length_body, NULL);
|
|
772
|
+
}
|
|
773
|
+
|
|
754
774
|
/* op codes for the shared predicate scan. */
|
|
755
775
|
enum { CA_TEXT_EQ, CA_TEXT_START, CA_TEXT_END, CA_TEXT_INCLUDE };
|
|
756
776
|
|
|
757
777
|
/* CAConstString#eq / start_with? / end_with? / include? — boolean mask vs a scalar
|
|
758
778
|
String query, byte-native. */
|
|
779
|
+
typedef struct {
|
|
780
|
+
const char *qp;
|
|
781
|
+
long qlen;
|
|
782
|
+
int op;
|
|
783
|
+
} ca_const_string_query_t;
|
|
784
|
+
|
|
759
785
|
static VALUE
|
|
760
|
-
|
|
786
|
+
ca_const_string_predicate_body (ca_const_string_scan_t *scan, void *arg)
|
|
761
787
|
{
|
|
762
|
-
ca_const_string_scan_t s;
|
|
763
|
-
|
|
788
|
+
ca_const_string_scan_t s0 = *scan, *s = &s0; /* a local copy: the writes below cannot alias it */
|
|
789
|
+
ca_const_string_query_t *q = (ca_const_string_query_t *) arg;
|
|
790
|
+
const char *qp = q->qp, *p;
|
|
791
|
+
long qlen = q->qlen;
|
|
792
|
+
int op = q->op;
|
|
793
|
+
volatile VALUE vout;
|
|
764
794
|
boolean8_t *out;
|
|
765
|
-
const char *qp, *p;
|
|
766
|
-
long qlen;
|
|
767
795
|
int64_t len;
|
|
768
796
|
ca_size_t i;
|
|
769
797
|
|
|
770
|
-
|
|
771
|
-
query = rb_obj_as_string(query);
|
|
772
|
-
}
|
|
773
|
-
qp = RSTRING_PTR(query);
|
|
774
|
-
qlen = RSTRING_LEN(query);
|
|
775
|
-
|
|
776
|
-
ca_const_string_scan_begin(self, &s);
|
|
777
|
-
vout = ca_const_string_bool_out(&s, &out);
|
|
798
|
+
vout = ca_const_string_bool_out(scan, &out);
|
|
778
799
|
|
|
779
|
-
for ( i = 0; i < s
|
|
800
|
+
for ( i = 0; i < s->n; i++ ) {
|
|
780
801
|
boolean8_t r = 0;
|
|
781
|
-
if ( ca_const_string_record(
|
|
802
|
+
if ( ca_const_string_record(s, i, &p, &len) ) {
|
|
782
803
|
switch ( op ) {
|
|
783
804
|
case CA_TEXT_EQ:
|
|
784
805
|
r = ( len == qlen && memcmp(p, qp, qlen) == 0 );
|
|
@@ -796,13 +817,91 @@ ca_const_string_predicate (VALUE self, VALUE query, int op)
|
|
|
796
817
|
}
|
|
797
818
|
out[i] = r;
|
|
798
819
|
}
|
|
799
|
-
ca_const_string_scan_end(&s);
|
|
800
820
|
return vout;
|
|
801
821
|
}
|
|
802
822
|
|
|
803
|
-
static VALUE
|
|
804
|
-
|
|
805
|
-
|
|
823
|
+
static VALUE
|
|
824
|
+
ca_const_string_predicate (VALUE self, VALUE query, int op)
|
|
825
|
+
{
|
|
826
|
+
ca_const_string_scan_t s;
|
|
827
|
+
ca_const_string_query_t q;
|
|
828
|
+
volatile VALUE vquery = query;
|
|
829
|
+
|
|
830
|
+
if ( TYPE(vquery) != T_STRING ) {
|
|
831
|
+
vquery = rb_obj_as_string(vquery);
|
|
832
|
+
}
|
|
833
|
+
q.qp = RSTRING_PTR(vquery);
|
|
834
|
+
q.qlen = RSTRING_LEN(vquery);
|
|
835
|
+
q.op = op;
|
|
836
|
+
{
|
|
837
|
+
VALUE out = ca_const_string_scan_run(self, &s,
|
|
838
|
+
ca_const_string_predicate_body, &q);
|
|
839
|
+
RB_GC_GUARD(vquery);
|
|
840
|
+
return out;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/* The native scans read one String. Anything else (a Regexp, several
|
|
845
|
+
prefixes, a value that is no String) is asked of the Strings themselves. */
|
|
846
|
+
static VALUE
|
|
847
|
+
ca_const_string_ask_strings (VALUE self, const char *name, int argc, VALUE *argv)
|
|
848
|
+
{
|
|
849
|
+
return rb_funcallv(rb_funcall(self, rb_intern("to_string"), 0),
|
|
850
|
+
rb_intern(name), argc, argv);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
static VALUE
|
|
854
|
+
rb_ca_const_string_start_with (int argc, VALUE *argv, VALUE self)
|
|
855
|
+
{
|
|
856
|
+
if ( argc == 1 && RB_TYPE_P(argv[0], T_STRING) ) {
|
|
857
|
+
return ca_const_string_predicate(self, argv[0], CA_TEXT_START);
|
|
858
|
+
}
|
|
859
|
+
return ca_const_string_ask_strings(self, "start_with?", argc, argv);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
static VALUE
|
|
863
|
+
rb_ca_const_string_end_with (int argc, VALUE *argv, VALUE self)
|
|
864
|
+
{
|
|
865
|
+
if ( argc == 1 && RB_TYPE_P(argv[0], T_STRING) ) {
|
|
866
|
+
return ca_const_string_predicate(self, argv[0], CA_TEXT_END);
|
|
867
|
+
}
|
|
868
|
+
return ca_const_string_ask_strings(self, "end_with?", argc, argv);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
static VALUE
|
|
872
|
+
rb_ca_const_string_include (VALUE self, VALUE q)
|
|
873
|
+
{
|
|
874
|
+
if ( RB_TYPE_P(q, T_STRING) ) {
|
|
875
|
+
return ca_const_string_predicate(self, q, CA_TEXT_INCLUDE);
|
|
876
|
+
}
|
|
877
|
+
return ca_const_string_ask_strings(self, "include?", 1, &q);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
static VALUE
|
|
881
|
+
ca_const_string_eq_pair_body (ca_const_string_scan_t *scan, void *arg)
|
|
882
|
+
{
|
|
883
|
+
ca_const_string_scan_t a0 = scan[0], b0 = scan[1], *a = &a0, *b = &b0; /* local copies: the writes below cannot alias them */
|
|
884
|
+
volatile VALUE vout;
|
|
885
|
+
boolean8_t *out;
|
|
886
|
+
/* record() leaves these unset for masked cells; short-circuit eval means
|
|
887
|
+
they are read only when both records are valid, but GCC cannot prove
|
|
888
|
+
that -- initialize to keep -Wmaybe-uninitialized quiet and defensive. */
|
|
889
|
+
const char *pa = NULL, *pb = NULL;
|
|
890
|
+
int64_t la = 0, lb = 0;
|
|
891
|
+
ca_size_t i;
|
|
892
|
+
|
|
893
|
+
if ( a->n != b->n ) {
|
|
894
|
+
rb_raise(rb_eArgError, "CAConstString#eq: element count mismatch (%lld vs %lld)",
|
|
895
|
+
(long long) a->n, (long long) b->n);
|
|
896
|
+
}
|
|
897
|
+
vout = ca_const_string_bool_out(&scan[0], &out); /* mask carried from self */
|
|
898
|
+
for ( i = 0; i < a->n; i++ ) {
|
|
899
|
+
int va = ca_const_string_record(a, i, &pa, &la);
|
|
900
|
+
int vb = ca_const_string_record(b, i, &pb, &lb);
|
|
901
|
+
out[i] = ( va && vb && la == lb && memcmp(pa, pb, la) == 0 );
|
|
902
|
+
}
|
|
903
|
+
return vout;
|
|
904
|
+
}
|
|
806
905
|
|
|
807
906
|
/* CAConstString#eq(value): value is a scalar String (broadcast) or a CAConstString
|
|
808
907
|
(element-wise). Returns a boolean CArray. */
|
|
@@ -810,32 +909,12 @@ static VALUE
|
|
|
810
909
|
rb_ca_const_string_eq (VALUE self, VALUE other)
|
|
811
910
|
{
|
|
812
911
|
if ( rb_obj_is_kind_of(other, rb_cCAConstString) ) {
|
|
813
|
-
ca_const_string_scan_t
|
|
814
|
-
VALUE
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
const char *pa = NULL, *pb = NULL;
|
|
820
|
-
int64_t la = 0, lb = 0;
|
|
821
|
-
ca_size_t i;
|
|
822
|
-
|
|
823
|
-
ca_const_string_scan_begin_pair(self, &a, other, &b);
|
|
824
|
-
if ( a.n != b.n ) {
|
|
825
|
-
ca_const_string_scan_end(&a);
|
|
826
|
-
ca_const_string_scan_end(&b);
|
|
827
|
-
rb_raise(rb_eArgError, "CAConstString#eq: element count mismatch (%lld vs %lld)",
|
|
828
|
-
(long long) a.n, (long long) b.n);
|
|
829
|
-
}
|
|
830
|
-
vout = ca_const_string_bool_out(&a, &out); /* mask carried from self */
|
|
831
|
-
for ( i = 0; i < a.n; i++ ) {
|
|
832
|
-
int va = ca_const_string_record(&a, i, &pa, &la);
|
|
833
|
-
int vb = ca_const_string_record(&b, i, &pb, &lb);
|
|
834
|
-
out[i] = ( va && vb && la == lb && memcmp(pa, pb, la) == 0 );
|
|
835
|
-
}
|
|
836
|
-
ca_const_string_scan_end(&a);
|
|
837
|
-
ca_const_string_scan_end(&b);
|
|
838
|
-
return vout;
|
|
912
|
+
ca_const_string_scan_t s[2];
|
|
913
|
+
VALUE cols[2];
|
|
914
|
+
cols[0] = self;
|
|
915
|
+
cols[1] = other;
|
|
916
|
+
return ca_const_string_scan_cols(2, cols, s,
|
|
917
|
+
ca_const_string_eq_pair_body, NULL);
|
|
839
918
|
}
|
|
840
919
|
/* Another array is compared cell by cell as Strings, where a CAString
|
|
841
920
|
reconciles it (an object array of Strings, a fixlen or a CAString). */
|
|
@@ -843,6 +922,9 @@ rb_ca_const_string_eq (VALUE self, VALUE other)
|
|
|
843
922
|
return rb_funcall(rb_ca_const_string_to_string(self), rb_intern("eq"), 1,
|
|
844
923
|
other);
|
|
845
924
|
}
|
|
925
|
+
if ( ! RB_TYPE_P(other, T_STRING) ) {
|
|
926
|
+
return ca_const_string_ask_strings(self, "eq", 1, &other);
|
|
927
|
+
}
|
|
846
928
|
return ca_const_string_predicate(self, other, CA_TEXT_EQ);
|
|
847
929
|
}
|
|
848
930
|
|
|
@@ -850,32 +932,78 @@ rb_ca_const_string_eq (VALUE self, VALUE other)
|
|
|
850
932
|
value. With no value, the number of non-masked elements, as CArray#count
|
|
851
933
|
answers. */
|
|
852
934
|
static VALUE
|
|
853
|
-
|
|
935
|
+
ca_const_string_count_body (ca_const_string_scan_t *scan, void *arg)
|
|
854
936
|
{
|
|
855
|
-
ca_const_string_scan_t s;
|
|
856
|
-
|
|
857
|
-
|
|
937
|
+
ca_const_string_scan_t s0 = *scan, *s = &s0; /* a local copy: the writes below cannot alias it */
|
|
938
|
+
ca_const_string_query_t *q = (ca_const_string_query_t *) arg;
|
|
939
|
+
const char *p;
|
|
858
940
|
int64_t len;
|
|
859
941
|
ca_size_t i, c = 0;
|
|
860
|
-
|
|
942
|
+
for ( i = 0; i < s->n; i++ ) {
|
|
943
|
+
if ( ca_const_string_record(s, i, &p, &len) && len == q->qlen &&
|
|
944
|
+
memcmp(p, q->qp, q->qlen) == 0 ) {
|
|
945
|
+
c++;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
return SIZET2NUM(c);
|
|
949
|
+
}
|
|
861
950
|
|
|
862
|
-
|
|
863
|
-
|
|
951
|
+
/* The first (non-masked) cell byte-equal to the query, as a flat index, or
|
|
952
|
+
nil when none matches. */
|
|
953
|
+
static VALUE
|
|
954
|
+
ca_const_string_search_body (ca_const_string_scan_t *scan, void *arg)
|
|
955
|
+
{
|
|
956
|
+
ca_const_string_scan_t s0 = *scan, *s = &s0; /* a local copy: the writes below cannot alias it */
|
|
957
|
+
ca_const_string_query_t *q = (ca_const_string_query_t *) arg;
|
|
958
|
+
const char *p;
|
|
959
|
+
int64_t len;
|
|
960
|
+
ca_size_t i;
|
|
961
|
+
for ( i = 0; i < s->n; i++ ) {
|
|
962
|
+
if ( ca_const_string_record(s, i, &p, &len) && len == q->qlen &&
|
|
963
|
+
memcmp(p, q->qp, (size_t) q->qlen) == 0 ) {
|
|
964
|
+
return SIZET2NUM(i);
|
|
965
|
+
}
|
|
864
966
|
}
|
|
865
|
-
|
|
866
|
-
|
|
967
|
+
return Qnil;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
/* Runs a scan that compares each cell with a query String. */
|
|
971
|
+
static VALUE
|
|
972
|
+
ca_const_string_query_run (VALUE self, VALUE query,
|
|
973
|
+
ca_const_string_scan_body_t body)
|
|
974
|
+
{
|
|
975
|
+
ca_const_string_scan_t s;
|
|
976
|
+
ca_const_string_query_t q;
|
|
977
|
+
volatile VALUE vquery = query;
|
|
978
|
+
VALUE out;
|
|
979
|
+
|
|
980
|
+
if ( TYPE(vquery) != T_STRING ) {
|
|
981
|
+
vquery = rb_obj_as_string(vquery);
|
|
867
982
|
}
|
|
868
|
-
qp = RSTRING_PTR(
|
|
869
|
-
qlen = RSTRING_LEN(
|
|
983
|
+
q.qp = RSTRING_PTR(vquery);
|
|
984
|
+
q.qlen = RSTRING_LEN(vquery);
|
|
985
|
+
q.op = CA_TEXT_EQ;
|
|
986
|
+
out = ca_const_string_scan_run(self, &s, body, &q);
|
|
987
|
+
RB_GC_GUARD(vquery);
|
|
988
|
+
return out;
|
|
989
|
+
}
|
|
870
990
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
991
|
+
static VALUE
|
|
992
|
+
rb_ca_const_string_count (int argc, VALUE *argv, VALUE self)
|
|
993
|
+
{
|
|
994
|
+
VALUE query;
|
|
995
|
+
if ( rb_keyword_given_p() ) {
|
|
996
|
+
/* axis: and the other reduction keywords: the scan below is flat */
|
|
997
|
+
return rb_funcallv_kw(rb_funcall(self, rb_intern("to_string"), 0),
|
|
998
|
+
rb_intern("count"), argc, argv, RB_PASS_KEYWORDS);
|
|
876
999
|
}
|
|
877
|
-
|
|
878
|
-
|
|
1000
|
+
if ( rb_scan_args(argc, argv, "01", &query) == 0 ) {
|
|
1001
|
+
return rb_funcall(self, rb_intern("count_not_masked"), 0);
|
|
1002
|
+
}
|
|
1003
|
+
if ( ! RB_TYPE_P(query, T_STRING) ) {
|
|
1004
|
+
return ca_const_string_ask_strings(self, "count", 1, &query);
|
|
1005
|
+
}
|
|
1006
|
+
return ca_const_string_query_run(self, query, ca_const_string_count_body);
|
|
879
1007
|
}
|
|
880
1008
|
|
|
881
1009
|
/* CAConstString#search(query) / #find_value_index(query): flat index of the
|
|
@@ -884,30 +1012,25 @@ rb_ca_const_string_count (int argc, VALUE *argv, VALUE self)
|
|
|
884
1012
|
offset entity, not the string content), so this is a native memcmp scan --
|
|
885
1013
|
the exact-lookup counterpart of the native sort / min / max below. */
|
|
886
1014
|
static VALUE
|
|
887
|
-
|
|
1015
|
+
rb_ca_const_string_find_value_index (VALUE self, VALUE query)
|
|
888
1016
|
{
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
VALUE result = Qnil;
|
|
1017
|
+
if ( ! RB_TYPE_P(query, T_STRING) ) {
|
|
1018
|
+
return Qnil;
|
|
1019
|
+
}
|
|
1020
|
+
return ca_const_string_query_run(self, query, ca_const_string_search_body);
|
|
1021
|
+
}
|
|
895
1022
|
|
|
896
|
-
|
|
897
|
-
|
|
1023
|
+
static VALUE
|
|
1024
|
+
rb_ca_const_string_search (int argc, VALUE *argv, VALUE self)
|
|
1025
|
+
{
|
|
1026
|
+
if ( rb_keyword_given_p() ) {
|
|
1027
|
+
return rb_funcallv_kw(rb_funcall(self, rb_intern("to_string"), 0),
|
|
1028
|
+
rb_intern("search"), argc, argv, RB_PASS_KEYWORDS);
|
|
898
1029
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
ca_const_string_scan_begin(self, &s);
|
|
903
|
-
for ( i = 0; i < s.n; i++ ) {
|
|
904
|
-
if ( ca_const_string_record(&s, i, &p, &len) && len == qlen && memcmp(p, qp, (size_t) qlen) == 0 ) {
|
|
905
|
-
result = SIZET2NUM(i);
|
|
906
|
-
break;
|
|
907
|
-
}
|
|
1030
|
+
if ( argc == 1 && RB_TYPE_P(argv[0], T_STRING) ) {
|
|
1031
|
+
return rb_ca_const_string_find_value_index(self, argv[0]);
|
|
908
1032
|
}
|
|
909
|
-
|
|
910
|
-
return result;
|
|
1033
|
+
return ca_const_string_ask_strings(self, "search", argc, argv);
|
|
911
1034
|
}
|
|
912
1035
|
|
|
913
1036
|
/* ------------------------------------------------------------------- */
|
|
@@ -944,18 +1067,20 @@ ca_const_string_index_cmp (const void *a, const void *b)
|
|
|
944
1067
|
return (ia > ib) - (ia < ib);
|
|
945
1068
|
}
|
|
946
1069
|
|
|
947
|
-
/*
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
ca_const_string_sort_perm (ca_const_string_scan_t *s)
|
|
1070
|
+
/* raises on masked input (matches base CArray#sort) */
|
|
1071
|
+
static void
|
|
1072
|
+
ca_const_string_refuse_masked_sort (ca_const_string_scan_t *s)
|
|
951
1073
|
{
|
|
952
|
-
ca_size_t *idx;
|
|
953
|
-
ca_size_t i;
|
|
954
1074
|
if ( s->m ) {
|
|
955
|
-
ca_const_string_scan_end(s);
|
|
956
1075
|
rb_raise(rb_eArgError, "CAConstString#sort: cannot sort an array with masked elements");
|
|
957
1076
|
}
|
|
958
|
-
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/* computes the ascending sort permutation into idx[0..n-1] */
|
|
1080
|
+
static void
|
|
1081
|
+
ca_const_string_sort_perm (ca_const_string_scan_t *s, ca_size_t *idx)
|
|
1082
|
+
{
|
|
1083
|
+
ca_size_t i;
|
|
959
1084
|
for ( i = 0; i < s->n; i++ ) idx[i] = i;
|
|
960
1085
|
ruby_qsort(idx, (size_t) s->n, sizeof(ca_size_t), ca_const_string_byte_cmp, s);
|
|
961
1086
|
/* qsort is not stable. Equal strings keep their order, as CArray's own
|
|
@@ -970,31 +1095,38 @@ ca_const_string_sort_perm (ca_const_string_scan_t *s)
|
|
|
970
1095
|
}
|
|
971
1096
|
i = j;
|
|
972
1097
|
}
|
|
973
|
-
return idx;
|
|
974
1098
|
}
|
|
975
1099
|
|
|
976
1100
|
/* CAConstString#sort_index → int64 CArray of the ascending sort permutation. */
|
|
977
1101
|
static VALUE
|
|
978
|
-
|
|
1102
|
+
ca_const_string_sort_index_body (ca_const_string_scan_t *s, void *arg)
|
|
979
1103
|
{
|
|
980
|
-
|
|
1104
|
+
volatile VALUE holder = 0; /* 0, not Qnil: ALLOCV_END reads a non-zero holder */
|
|
1105
|
+
volatile VALUE vout;
|
|
981
1106
|
ca_size_t *idx;
|
|
982
|
-
VALUE vout;
|
|
983
1107
|
CArray *co;
|
|
984
1108
|
int64_t *op;
|
|
985
1109
|
ca_size_t i;
|
|
986
1110
|
|
|
987
|
-
|
|
988
|
-
idx =
|
|
989
|
-
|
|
1111
|
+
ca_const_string_refuse_masked_sort(s);
|
|
1112
|
+
idx = ALLOCV_N(ca_size_t, holder, s->n > 0 ? s->n : 1);
|
|
1113
|
+
ca_const_string_sort_perm(s, idx);
|
|
1114
|
+
vout = rb_carray_new(CA_INT64, s->ca->ndim, s->ca->dim, 0, NULL);
|
|
990
1115
|
TypedData_Get_Struct(vout, CArray, &carray_data_type, co);
|
|
991
1116
|
op = (int64_t *) co->ptr;
|
|
992
|
-
for ( i = 0; i < s
|
|
993
|
-
|
|
994
|
-
ca_const_string_scan_end(&s);
|
|
1117
|
+
for ( i = 0; i < s->n; i++ ) op[i] = (int64_t) idx[i];
|
|
1118
|
+
ALLOCV_END(holder);
|
|
995
1119
|
return vout;
|
|
996
1120
|
}
|
|
997
1121
|
|
|
1122
|
+
static VALUE
|
|
1123
|
+
rb_ca_const_string_sort_index (VALUE self)
|
|
1124
|
+
{
|
|
1125
|
+
ca_const_string_scan_t s;
|
|
1126
|
+
return ca_const_string_scan_run(self, &s,
|
|
1127
|
+
ca_const_string_sort_index_body, NULL);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
998
1130
|
/* The ordering surface is defined in Ruby (lib/carray/const_string.rb) on
|
|
999
1131
|
top of these three: a storage cell is a byte range, so storage order is
|
|
1000
1132
|
insertion order rather than string order, and every member has to read
|
|
@@ -1008,18 +1140,18 @@ rb_ca_const_string_sort_index (VALUE self)
|
|
|
1008
1140
|
/* CAConstString#min / #max → the byte-min / byte-max element as a frozen String,
|
|
1009
1141
|
skipping masked elements; nil if empty or all masked. */
|
|
1010
1142
|
static VALUE
|
|
1011
|
-
|
|
1143
|
+
ca_const_string_extremum_body (ca_const_string_scan_t *scan, void *arg)
|
|
1012
1144
|
{
|
|
1013
|
-
ca_const_string_scan_t s;
|
|
1145
|
+
ca_const_string_scan_t s0 = *scan, *s = &s0; /* a local copy: the writes below cannot alias it */
|
|
1146
|
+
int want_max = *(int *) arg;
|
|
1014
1147
|
const char *p, *bestp = NULL;
|
|
1015
1148
|
int64_t len, bestlen = 0;
|
|
1016
1149
|
ca_size_t i;
|
|
1017
1150
|
int found = 0;
|
|
1018
1151
|
|
|
1019
|
-
|
|
1020
|
-
for ( i = 0; i < s.n; i++ ) {
|
|
1152
|
+
for ( i = 0; i < s->n; i++ ) {
|
|
1021
1153
|
int c;
|
|
1022
|
-
if ( ! ca_const_string_record(
|
|
1154
|
+
if ( ! ca_const_string_record(s, i, &p, &len) ) continue;
|
|
1023
1155
|
if ( ! found ) {
|
|
1024
1156
|
bestp = p; bestlen = len; found = 1;
|
|
1025
1157
|
continue;
|
|
@@ -1031,14 +1163,18 @@ ca_const_string_extremum (VALUE self, int want_max)
|
|
|
1031
1163
|
}
|
|
1032
1164
|
}
|
|
1033
1165
|
if ( ! found ) {
|
|
1034
|
-
ca_const_string_scan_end(&s);
|
|
1035
1166
|
return Qnil;
|
|
1036
1167
|
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1168
|
+
return rb_str_freeze(rb_enc_str_new(bestp, bestlen,
|
|
1169
|
+
rb_enc_from_index(s->ca->encoding_id)));
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
static VALUE
|
|
1173
|
+
ca_const_string_extremum (VALUE self, int want_max)
|
|
1174
|
+
{
|
|
1175
|
+
ca_const_string_scan_t s;
|
|
1176
|
+
return ca_const_string_scan_run(self, &s,
|
|
1177
|
+
ca_const_string_extremum_body, &want_max);
|
|
1042
1178
|
}
|
|
1043
1179
|
|
|
1044
1180
|
static VALUE rb_ca_const_string_min (VALUE self) { return ca_const_string_extremum(self, 0); }
|
|
@@ -1062,6 +1198,52 @@ ca_const_string_hash_bytes (const char *p, int64_t len)
|
|
|
1062
1198
|
return h;
|
|
1063
1199
|
}
|
|
1064
1200
|
|
|
1201
|
+
typedef struct {
|
|
1202
|
+
uint32_t *codes, *slot;
|
|
1203
|
+
int64_t *lev_start, *lev_len;
|
|
1204
|
+
size_t mask_bits;
|
|
1205
|
+
ca_size_t k;
|
|
1206
|
+
} ca_const_string_factorize_t;
|
|
1207
|
+
|
|
1208
|
+
/* Codes the cells by first appearance into an open-addressing table of
|
|
1209
|
+
(start, length) records. Reads bytes only. */
|
|
1210
|
+
static VALUE
|
|
1211
|
+
ca_const_string_factorize_body (ca_const_string_scan_t *scan, void *arg)
|
|
1212
|
+
{
|
|
1213
|
+
ca_const_string_scan_t s0 = *scan, *s = &s0; /* a local copy: the writes below cannot alias it */
|
|
1214
|
+
ca_const_string_factorize_t *f = (ca_const_string_factorize_t *) arg;
|
|
1215
|
+
ca_size_t i, k = f->k;
|
|
1216
|
+
for ( i = 0; i < s->n; i++ ) {
|
|
1217
|
+
const char *p;
|
|
1218
|
+
int64_t len;
|
|
1219
|
+
size_t j;
|
|
1220
|
+
if ( ! ca_const_string_record(s, i, &p, &len) ) {
|
|
1221
|
+
f->codes[i] = 0xFFFFFFFFu;
|
|
1222
|
+
continue;
|
|
1223
|
+
}
|
|
1224
|
+
j = (size_t) ca_const_string_hash_bytes(p, len) & f->mask_bits;
|
|
1225
|
+
for (;;) {
|
|
1226
|
+
uint32_t c = f->slot[j];
|
|
1227
|
+
if ( c == 0 ) {
|
|
1228
|
+
f->lev_start[k] = (int64_t) (p - s->buf);
|
|
1229
|
+
f->lev_len[k] = len;
|
|
1230
|
+
f->slot[j] = (uint32_t) (k + 1);
|
|
1231
|
+
f->codes[i] = (uint32_t) k;
|
|
1232
|
+
k++;
|
|
1233
|
+
break;
|
|
1234
|
+
}
|
|
1235
|
+
if ( f->lev_len[c - 1] == len &&
|
|
1236
|
+
memcmp(s->buf + f->lev_start[c - 1], p, (size_t) len) == 0 ) {
|
|
1237
|
+
f->codes[i] = c - 1;
|
|
1238
|
+
break;
|
|
1239
|
+
}
|
|
1240
|
+
j = (j + 1) & f->mask_bits;
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
f->k = k;
|
|
1244
|
+
return Qnil;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1065
1247
|
/* CAConstString#__factorize_appearance__ -> [codes, levels], as the CArray
|
|
1066
1248
|
method answers: codes are the narrowest unsigned type holding the k codes
|
|
1067
1249
|
and the type-max sentinel, which masked cells store; levels are the k
|
|
@@ -1100,34 +1282,17 @@ rb_ca_const_string_factorize_appearance (VALUE self)
|
|
|
1100
1282
|
lev_start = ALLOCV_N(int64_t, start_holder, n > 0 ? n : 1);
|
|
1101
1283
|
lev_len = ALLOCV_N(int64_t, len_holder, n > 0 ? n : 1);
|
|
1102
1284
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
for (;;) {
|
|
1114
|
-
uint32_t c = slot[j];
|
|
1115
|
-
if ( c == 0 ) {
|
|
1116
|
-
lev_start[k] = (int64_t) (p - s.buf);
|
|
1117
|
-
lev_len[k] = len;
|
|
1118
|
-
slot[j] = (uint32_t) (k + 1);
|
|
1119
|
-
codes[i] = (uint32_t) k;
|
|
1120
|
-
k++;
|
|
1121
|
-
break;
|
|
1122
|
-
}
|
|
1123
|
-
if ( lev_len[c - 1] == len && memcmp(s.buf + lev_start[c - 1], p, (size_t) len) == 0 ) {
|
|
1124
|
-
codes[i] = c - 1;
|
|
1125
|
-
break;
|
|
1126
|
-
}
|
|
1127
|
-
j = (j + 1) & mask_bits;
|
|
1128
|
-
}
|
|
1285
|
+
{
|
|
1286
|
+
ca_const_string_factorize_t f;
|
|
1287
|
+
f.codes = codes;
|
|
1288
|
+
f.slot = slot;
|
|
1289
|
+
f.lev_start = lev_start;
|
|
1290
|
+
f.lev_len = lev_len;
|
|
1291
|
+
f.mask_bits = mask_bits;
|
|
1292
|
+
f.k = 0;
|
|
1293
|
+
ca_const_string_scan_run(self, &s, ca_const_string_factorize_body, &f);
|
|
1294
|
+
k = f.k;
|
|
1129
1295
|
}
|
|
1130
|
-
ca_const_string_scan_end(&s);
|
|
1131
1296
|
ALLOCV_END(slot_holder);
|
|
1132
1297
|
|
|
1133
1298
|
/* The buffer is the column's frozen String, alive past the window. */
|
|
@@ -1229,15 +1394,15 @@ Init_ca_obj_const_string (void)
|
|
|
1229
1394
|
rb_define_method(rb_cCAConstString, "byte_length", rb_ca_const_string_byte_length, 0);
|
|
1230
1395
|
rb_define_method(rb_cCAConstString, "eq", rb_ca_const_string_eq, 1);
|
|
1231
1396
|
rb_define_method(rb_cCAConstString, "count", rb_ca_const_string_count, -1);
|
|
1232
|
-
rb_define_method(rb_cCAConstString, "start_with?", rb_ca_const_string_start_with, 1);
|
|
1233
|
-
rb_define_method(rb_cCAConstString, "end_with?", rb_ca_const_string_end_with, 1);
|
|
1397
|
+
rb_define_method(rb_cCAConstString, "start_with?", rb_ca_const_string_start_with, -1);
|
|
1398
|
+
rb_define_method(rb_cCAConstString, "end_with?", rb_ca_const_string_end_with, -1);
|
|
1234
1399
|
rb_define_method(rb_cCAConstString, "include?", rb_ca_const_string_include, 1);
|
|
1235
1400
|
|
|
1236
1401
|
/* native exact-lookup search: flat index of the first byte-equal element,
|
|
1237
1402
|
or nil. `search` is what str_matches consumes; find_value_index is the
|
|
1238
1403
|
*_index-named surface (both exact, mask-skipping). */
|
|
1239
|
-
rb_define_method(rb_cCAConstString, "search", rb_ca_const_string_search, 1);
|
|
1240
|
-
rb_define_method(rb_cCAConstString, "find_value_index",
|
|
1404
|
+
rb_define_method(rb_cCAConstString, "search", rb_ca_const_string_search, -1);
|
|
1405
|
+
rb_define_method(rb_cCAConstString, "find_value_index", rb_ca_const_string_find_value_index, 1);
|
|
1241
1406
|
|
|
1242
1407
|
/* Native flat sort permutation / min / max (§3.7), byte-memcmp
|
|
1243
1408
|
comparator. The public ordering surface is built on these in
|