carray 3.0.1 → 3.0.2
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 +520 -0
- data/README.md +2 -2
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +33 -4
- data/ext/ca_axis_group.c +202 -96
- data/ext/ca_categorical_iterator.c +108 -54
- data/ext/ca_kernel_iterator.c +317 -51
- data/ext/ca_kernel_iterator.h +142 -35
- data/ext/ca_obj_array.c +62 -20
- data/ext/ca_obj_block.c +4 -4
- data/ext/ca_obj_const_string.c +85 -26
- data/ext/ca_obj_face.c +24 -0
- data/ext/ca_obj_face.h +15 -0
- data/ext/ca_obj_fixlen_string.c +18 -5
- data/ext/ca_obj_meld.c +123 -25
- data/ext/ca_obj_object.c +8 -0
- data/ext/ca_obj_select.c +49 -34
- data/ext/ca_obj_stack.c +3 -8
- data/ext/ca_obj_stride.c +72 -1
- data/ext/ca_obj_string.c +8 -4
- data/ext/ca_obj_window.c +8 -2
- data/ext/ca_op_ipower.c +1 -2
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sweep_engine.c +307 -143
- data/ext/ca_sweep_engine.h +26 -5
- data/ext/carray.h +21 -2
- data/ext/carray_access.c +32 -20
- data/ext/carray_address_basis.c +590 -0
- data/ext/carray_broadcast.c +3 -3
- data/ext/carray_call_cfunc.c +667 -483
- data/ext/carray_cast.c +115 -41
- data/ext/carray_copy.c +55 -30
- data/ext/carray_core.c +83 -3
- data/ext/carray_count.c +9 -10
- data/ext/carray_factorize.c +46 -25
- data/ext/carray_internal.h +17 -0
- data/ext/carray_kernels_reduce_aggregate.c +168 -0
- data/ext/carray_kernels_reduce_cumulative.c +270 -1
- data/ext/carray_kernels_reduce_extreme.c +554 -8
- data/ext/carray_kernels_scan.c +4 -4
- data/ext/carray_kernels_search.c +94 -14
- data/ext/carray_loop.c +7 -1
- data/ext/carray_mask.c +23 -8
- data/ext/carray_median_percentile.c +55 -0
- data/ext/carray_operator.c +4 -4
- data/ext/carray_order.c +1 -1
- data/ext/carray_random.c +384 -40
- data/ext/carray_slab.c +13 -0
- data/ext/carray_sort.c +20 -22
- data/ext/mk_call_cfunc.rb +103 -116
- data/ext/mkkernel.rb +297 -29
- data/ext/ruby_carray.c +10 -1
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +5 -3
- data/lib/carray/autoload_method_extension.rb +12 -0
- data/lib/carray/axis_group.rb +77 -0
- data/lib/carray/basics.rb +4 -0
- data/lib/carray/block_iterator.rb +92 -16
- data/lib/carray/categorical.rb +150 -33
- data/lib/carray/categorical_iterator.rb +207 -80
- data/lib/carray/const_string.rb +131 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/csv_parser.rb +11 -4
- data/lib/carray/frame/frame.rb +81 -10
- data/lib/carray/frame/group.rb +36 -3
- data/lib/carray/frame/io.rb +67 -15
- data/lib/carray/frame/records.rb +18 -4
- data/lib/carray/frame/verbs.rb +14 -11
- data/lib/carray/inspect.rb +42 -9
- data/lib/carray/iterator.rb +143 -0
- data/lib/carray/lazy.rb +0 -37
- data/lib/carray/mask_gap_fill.rb +3 -1
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/is_in.rb +13 -2
- data/lib/carray/methods/locate_addr.rb +75 -2
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +110 -0
- data/lib/carray/methods/unique.rb +41 -1
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/slab_iterator.rb +58 -13
- data/lib/carray/string_operation_extension.rb +5 -1
- data/lib/carray/time.rb +18 -2
- data/lib/carray/window_iterator.rb +142 -20
- data/lib/carray.rb +2 -0
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_window.rb +10 -2
- data/yard-stubs/carray_access.rb +1 -1
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_core.rb +0 -80
- data/yard-stubs/carray_count.rb +7 -2
- data/yard-stubs/carray_lazy.rb +205 -0
- data/yard-stubs/carray_math.rb +1486 -3
- data/yard-stubs/carray_median_percentile.rb +16 -2
- data/yard-stubs/carray_order.rb +9 -69
- data/yard-stubs/carray_slab.rb +9 -7
- data/yard-stubs/carray_sort.rb +7 -5
- metadata +9 -1
data/ext/ca_kernel_iterator.h
CHANGED
|
@@ -528,7 +528,24 @@ int ca_iter_state_init_l2 (ca_iter_state *st,
|
|
|
528
528
|
source carries a mask (= ca_has_mask(src)), or NULL otherwise.
|
|
529
529
|
The mask layout matches the value layout (= same iteration order
|
|
530
530
|
and same n). Step 6+: kernels use the CA_FOR_EACH_UNMASKED macro
|
|
531
|
-
family (carray.h) to skip masked cells.
|
|
531
|
+
family (carray.h) to skip masked cells.
|
|
532
|
+
|
|
533
|
+
The mask is an input. What it points at is a copy taken when the
|
|
534
|
+
walk began, so writing through it changes nothing -- not even under
|
|
535
|
+
CA_KERNEL_WRITE, where the value half of the same yield is often a
|
|
536
|
+
live alias. It also cannot express the thing an author would most
|
|
537
|
+
want it for: an unmasked source yields NULL, so there is nowhere to
|
|
538
|
+
record that a cell has become undefined. A kernel authors its
|
|
539
|
+
output mask on its own output array instead:
|
|
540
|
+
|
|
541
|
+
if ( op_mask == NULL ) {
|
|
542
|
+
ca_create_mask(co);
|
|
543
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
544
|
+
}
|
|
545
|
+
op_mask[out_i] = 1;
|
|
546
|
+
|
|
547
|
+
which is what every kernel in carray does (carray_hold.c, and the
|
|
548
|
+
reduction kernels mkkernel emits). */
|
|
532
549
|
int ca_iter_state_next_slab (ca_iter_state *st,
|
|
533
550
|
char **out_ptr,
|
|
534
551
|
boolean8_t **out_mask,
|
|
@@ -603,6 +620,13 @@ void ca_iter_state_sync_slab (ca_iter_state *st);
|
|
|
603
620
|
exactly once after a successful init (either level). */
|
|
604
621
|
void ca_iter_state_finish (ca_iter_state *st);
|
|
605
622
|
|
|
623
|
+
/* Raise unless rc is CA_ITER_OK. The block macros call this on the value
|
|
624
|
+
ca_iter_state_init_l1 / _l2 returned, so an author who never looks at a
|
|
625
|
+
return code still hears about a request the iterator would not serve.
|
|
626
|
+
Returns rc when there is nothing to report, so it composes inside the
|
|
627
|
+
macros' comma expressions. */
|
|
628
|
+
int ca_iter_check_init (int rc);
|
|
629
|
+
|
|
606
630
|
/* ---- Phase C C.3: kernel author block macros ------------------------
|
|
607
631
|
(PROPOSAL_CAPSTONE_PHASE_C.md D3.1 (A) do/while/for + D3.2 (C) 2 kinds)
|
|
608
632
|
|
|
@@ -617,17 +641,24 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
617
641
|
surrounding scope.
|
|
618
642
|
- `flags` arg propagates to init_l2 (= CA_KERNEL_WRITE supported).
|
|
619
643
|
`sync_slab` is called automatically after each iteration; it's a
|
|
620
|
-
no-op when WRITE flag is absent.
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
644
|
+
no-op when WRITE flag is absent. The mask cursor is an input even
|
|
645
|
+
under WRITE -- see ca_iter_state_next_slab above for why, and for
|
|
646
|
+
where an output mask is written instead.
|
|
647
|
+
- Init failure (ca_iter_state_init_l2 returns CA_ITER_ERR_*) raises:
|
|
648
|
+
the macro passes the code to ca_iter_check_init, which reports what
|
|
649
|
+
the iterator declined to do. The body does not run and finish is
|
|
650
|
+
not reached, which is safe because a failed init allocates nothing.
|
|
651
|
+
Kernels that want to handle a refusal rather than propagate it
|
|
652
|
+
should drop down to the raw API and read the code themselves.
|
|
626
653
|
- `break;` from inside the body exits the loop AND triggers finish
|
|
627
654
|
correctly (= outer for's "increment" clause runs once on natural
|
|
628
655
|
exit; `break` from the inner while breaks both). `return` inside
|
|
629
656
|
the body LEAKS resources (scratch_ptr, parent attach) — drop to
|
|
630
|
-
raw API if early return is needed.
|
|
657
|
+
raw API if early return is needed. A body that raises leaks the
|
|
658
|
+
same way: the engine releases what it holds when the walk itself
|
|
659
|
+
raises (a gather or a write-back through the source's slots), but
|
|
660
|
+
the body runs in the caller's frame, where it has no hold on it.
|
|
661
|
+
An object-lane body calling back into Ruby is the case to watch.
|
|
631
662
|
- Macros are not statement-equivalent (= they expand to nested for
|
|
632
663
|
constructs). Don't follow them with `else` etc. */
|
|
633
664
|
|
|
@@ -760,8 +791,9 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
760
791
|
always-constant argument). CA_SLAB_AXES is still FROZEN, because
|
|
761
792
|
raw-API kernels pass it to ca_iter_state_init_l2 directly. */
|
|
762
793
|
#define CA_FOR_EACH_SLAB(st, ca, axes, naxes, flags, p, m) \
|
|
763
|
-
for ( int __caf_init = (
|
|
764
|
-
|
|
794
|
+
for ( int __caf_init = (ca_iter_check_init( \
|
|
795
|
+
ca_iter_state_init_l2(&(st), (ca), CA_SLAB_AXES, \
|
|
796
|
+
(axes), (naxes), (flags))), \
|
|
765
797
|
1); \
|
|
766
798
|
__caf_init; \
|
|
767
799
|
__caf_init = 0, ca_iter_state_finish(&(st)) ) \
|
|
@@ -777,16 +809,18 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
777
809
|
Shape mismatch between ca_in / ca_out is NOT validated by the macro
|
|
778
810
|
— caller responsibility (= typically output is `rb_ca_template_with_type`
|
|
779
811
|
of input, guaranteeing same shape). Init failure on either iter
|
|
780
|
-
|
|
812
|
+
raises — see CA_FOR_EACH_SLAB above. */
|
|
781
813
|
/* Policy fixed to CA_SLAB_AXES internally — see CA_FOR_EACH_SLAB above. */
|
|
782
814
|
#define CA_FOR_EACH_SLAB_INOUT(st_in, st_out, ca_in, ca_out, \
|
|
783
815
|
axes, naxes, \
|
|
784
816
|
p_in, p_out, m_in, m_out) \
|
|
785
817
|
for ( int __cafi_init = ( \
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
818
|
+
ca_iter_check_init( \
|
|
819
|
+
ca_iter_state_init_l2(&(st_in), (ca_in), CA_SLAB_AXES, \
|
|
820
|
+
(axes), (naxes), 0)), \
|
|
821
|
+
ca_iter_check_init( \
|
|
822
|
+
ca_iter_state_init_l2(&(st_out), (ca_out), CA_SLAB_AXES, \
|
|
823
|
+
(axes), (naxes), CA_KERNEL_WRITE)), \
|
|
790
824
|
1); \
|
|
791
825
|
__cafi_init; \
|
|
792
826
|
__cafi_init = 0, \
|
|
@@ -827,9 +861,10 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
827
861
|
|
|
828
862
|
#define CA_FOR_EACH_FIBER(st, ca, axis, flags, p, n) \
|
|
829
863
|
for ( int __cff_init = ( \
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
864
|
+
ca_iter_check_init( \
|
|
865
|
+
ca_iter_state_init_l2(&(st), (ca), CA_SLAB_AXES, \
|
|
866
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
867
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
833
868
|
(n) = (st).slab_dims[0], \
|
|
834
869
|
1); \
|
|
835
870
|
__cff_init; \
|
|
@@ -839,9 +874,10 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
839
874
|
|
|
840
875
|
#define CA_FOR_EACH_FIBER_MASKED(st, ca, axis, flags, p, n, m) \
|
|
841
876
|
for ( int __cffm_init = ( \
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
877
|
+
ca_iter_check_init( \
|
|
878
|
+
ca_iter_state_init_l2(&(st), (ca), CA_SLAB_AXES, \
|
|
879
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
880
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
845
881
|
(n) = (st).slab_dims[0], \
|
|
846
882
|
1); \
|
|
847
883
|
__cffm_init; \
|
|
@@ -864,13 +900,15 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
864
900
|
#define CA_FOR_EACH_FIBER_INOUT(st_in, st_out, ca_in, ca_out, axis, \
|
|
865
901
|
flags, p_in, p_out, n) \
|
|
866
902
|
for ( int __cffi_init = ( \
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
903
|
+
ca_iter_check_init( \
|
|
904
|
+
ca_iter_state_init_l2(&(st_in), (ca_in), CA_SLAB_AXES, \
|
|
905
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
906
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
907
|
+
ca_iter_check_init( \
|
|
908
|
+
ca_iter_state_init_l2(&(st_out), (ca_out), CA_SLAB_AXES, \
|
|
909
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
910
|
+
((flags) | CA_KERNEL_FIBER_CONTIG \
|
|
911
|
+
| CA_KERNEL_WRITE))), \
|
|
874
912
|
(n) = (st_in).slab_dims[0], \
|
|
875
913
|
1); \
|
|
876
914
|
__cffi_init; \
|
|
@@ -888,13 +926,15 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
888
926
|
#define CA_FOR_EACH_FIBER_INOUT_MASKED(st_in, st_out, ca_in, ca_out, axis, \
|
|
889
927
|
flags, p_in, p_out, n, m) \
|
|
890
928
|
for ( int __cffim_init = ( \
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
929
|
+
ca_iter_check_init( \
|
|
930
|
+
ca_iter_state_init_l2(&(st_in), (ca_in), CA_SLAB_AXES, \
|
|
931
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
932
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
933
|
+
ca_iter_check_init( \
|
|
934
|
+
ca_iter_state_init_l2(&(st_out), (ca_out), CA_SLAB_AXES, \
|
|
935
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
936
|
+
((flags) | CA_KERNEL_FIBER_CONTIG \
|
|
937
|
+
| CA_KERNEL_WRITE))), \
|
|
898
938
|
(n) = (st_in).slab_dims[0], \
|
|
899
939
|
1); \
|
|
900
940
|
__cffim_init; \
|
|
@@ -909,6 +949,73 @@ void ca_iter_state_finish (ca_iter_state *st);
|
|
|
909
949
|
ca_iter_state_sync_slab(&(st_in)), \
|
|
910
950
|
ca_iter_state_sync_slab(&(st_out)) )
|
|
911
951
|
|
|
952
|
+
/* PAIR forms: two sources read together along the same axis.
|
|
953
|
+
|
|
954
|
+
The INOUT forms cover input + output. These cover input + input, which
|
|
955
|
+
is what a routine taking two vectors of the same length wants -- a
|
|
956
|
+
correlation, a dot product, a distance. Neither state gets
|
|
957
|
+
CA_KERNEL_WRITE, and `flags` must not carry it: use the INOUT forms to
|
|
958
|
+
write.
|
|
959
|
+
|
|
960
|
+
Both fibers are contig-delivered, so the pair may be handed straight to
|
|
961
|
+
a C routine that walks it itself. The MASKED form yields BOTH mask
|
|
962
|
+
cursors: which cells a pair of fibers may be used at is a question about
|
|
963
|
+
both of them, and the INOUT forms answer only about the input.
|
|
964
|
+
|
|
965
|
+
Shape agreement is guarded the way the INOUT forms guard it (ndim,
|
|
966
|
+
elements, fiber length), and the body is skipped on mismatch. The two
|
|
967
|
+
sources may be the same array. */
|
|
968
|
+
|
|
969
|
+
#define CA_FOR_EACH_FIBER_PAIR(st_a, st_b, ca_a, ca_b, axis, \
|
|
970
|
+
flags, p_a, p_b, n) \
|
|
971
|
+
for ( int __cffp_init = ( \
|
|
972
|
+
ca_iter_check_init( \
|
|
973
|
+
ca_iter_state_init_l2(&(st_a), (ca_a), CA_SLAB_AXES, \
|
|
974
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
975
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
976
|
+
ca_iter_check_init( \
|
|
977
|
+
ca_iter_state_init_l2(&(st_b), (ca_b), CA_SLAB_AXES, \
|
|
978
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
979
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
980
|
+
(n) = (st_a).slab_dims[0], \
|
|
981
|
+
1); \
|
|
982
|
+
__cffp_init; \
|
|
983
|
+
__cffp_init = 0, \
|
|
984
|
+
ca_iter_state_finish(&(st_a)), \
|
|
985
|
+
ca_iter_state_finish(&(st_b)) ) \
|
|
986
|
+
for ( ; (st_a).src->ndim == (st_b).src->ndim \
|
|
987
|
+
&& (st_a).src->elements == (st_b).src->elements \
|
|
988
|
+
&& (st_a).slab_dims[0] == (st_b).slab_dims[0] \
|
|
989
|
+
&& ca_iter_state_next_slab_axes(&(st_a), &(p_a), NULL) \
|
|
990
|
+
&& ca_iter_state_next_slab_axes(&(st_b), &(p_b), NULL); \
|
|
991
|
+
ca_iter_state_sync_slab(&(st_a)), \
|
|
992
|
+
ca_iter_state_sync_slab(&(st_b)) )
|
|
993
|
+
|
|
994
|
+
#define CA_FOR_EACH_FIBER_PAIR_MASKED(st_a, st_b, ca_a, ca_b, axis, \
|
|
995
|
+
flags, p_a, p_b, n, m_a, m_b) \
|
|
996
|
+
for ( int __cffpm_init = ( \
|
|
997
|
+
ca_iter_check_init( \
|
|
998
|
+
ca_iter_state_init_l2(&(st_a), (ca_a), CA_SLAB_AXES, \
|
|
999
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
1000
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
1001
|
+
ca_iter_check_init( \
|
|
1002
|
+
ca_iter_state_init_l2(&(st_b), (ca_b), CA_SLAB_AXES, \
|
|
1003
|
+
(int8_t[]){(int8_t)(axis)}, 1, \
|
|
1004
|
+
(flags) | CA_KERNEL_FIBER_CONTIG)), \
|
|
1005
|
+
(n) = (st_a).slab_dims[0], \
|
|
1006
|
+
1); \
|
|
1007
|
+
__cffpm_init; \
|
|
1008
|
+
__cffpm_init = 0, \
|
|
1009
|
+
ca_iter_state_finish(&(st_a)), \
|
|
1010
|
+
ca_iter_state_finish(&(st_b)) ) \
|
|
1011
|
+
for ( ; (st_a).src->ndim == (st_b).src->ndim \
|
|
1012
|
+
&& (st_a).src->elements == (st_b).src->elements \
|
|
1013
|
+
&& (st_a).slab_dims[0] == (st_b).slab_dims[0] \
|
|
1014
|
+
&& ca_iter_state_next_slab_axes(&(st_a), &(p_a), &(m_a)) \
|
|
1015
|
+
&& ca_iter_state_next_slab_axes(&(st_b), &(p_b), &(m_b)); \
|
|
1016
|
+
ca_iter_state_sync_slab(&(st_a)), \
|
|
1017
|
+
ca_iter_state_sync_slab(&(st_b)) )
|
|
1018
|
+
|
|
912
1019
|
/* ---- Phase D: per-data_type reduction macro suite ----------------------- */
|
|
913
1020
|
|
|
914
1021
|
/* CA_SLAB_REDUCE_T(T, ...): generic per-data_type slab reduction. T is the
|
data/ext/ca_obj_array.c
CHANGED
|
@@ -825,26 +825,17 @@ rb_ca_s_allocate (VALUE klass)
|
|
|
825
825
|
return TypedData_Make_Struct(klass, CArray, &carray_data_type, ca);
|
|
826
826
|
}
|
|
827
827
|
|
|
828
|
-
/*
|
|
828
|
+
/* Reads the (data_type, dim, bytes: nil) argument list that CArray.new
|
|
829
|
+
and CArray.__empty__ share. The two differ only in whether the buffer
|
|
830
|
+
is filled, so the rule for reading their arguments -- the optional
|
|
831
|
+
bytes for a fixlen, the refusal of a Class, the guess of the data type,
|
|
832
|
+
the demand that dim be an Array -- is written once here. */
|
|
829
833
|
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
The byte size of each element for the fixed length data type
|
|
834
|
-
(<code>data_type == CA_FIXLEN</code>) is specified optional argument
|
|
835
|
-
<i>bytes</i>. Otherwise, this optional argument has no
|
|
836
|
-
effect. If the block is given, the new CArray
|
|
837
|
-
object will be initialized by the value returned from the block.
|
|
838
|
-
*/
|
|
839
|
-
|
|
840
|
-
static VALUE
|
|
841
|
-
rb_ca_initialize (int argc, VALUE *argv, VALUE self)
|
|
834
|
+
static void
|
|
835
|
+
ca_scan_construct_args (int argc, VALUE *argv, int8_t *data_type,
|
|
836
|
+
ca_size_t *bytes, int8_t *ndim, ca_size_t *dim)
|
|
842
837
|
{
|
|
843
838
|
volatile VALUE rtype, rdim, ropt, rbytes = Qnil;
|
|
844
|
-
CArray *ca;
|
|
845
|
-
int8_t data_type, ndim;
|
|
846
|
-
ca_size_t dim[CA_RANK_MAX];
|
|
847
|
-
ca_size_t bytes;
|
|
848
839
|
int8_t i;
|
|
849
840
|
|
|
850
841
|
rb_scan_args(argc, argv, "21", (VALUE *)&rtype, (VALUE *) &rdim, (VALUE *) &ropt);
|
|
@@ -863,13 +854,36 @@ rb_ca_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
863
854
|
rtype, rtype, rtype);
|
|
864
855
|
}
|
|
865
856
|
|
|
866
|
-
rb_ca_guess_type_and_bytes(rtype, rbytes,
|
|
857
|
+
rb_ca_guess_type_and_bytes(rtype, rbytes, data_type, bytes);
|
|
867
858
|
|
|
868
859
|
Check_Type(rdim, T_ARRAY);
|
|
869
|
-
ndim = RARRAY_LEN(rdim);
|
|
870
|
-
for (i=0; i
|
|
860
|
+
*ndim = RARRAY_LEN(rdim);
|
|
861
|
+
for (i=0; i<*ndim; i++) {
|
|
871
862
|
dim[i] = NUM2SIZE(rb_ary_entry(rdim, i));
|
|
872
863
|
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/* @overload initialize(data_type, dim, bytes=0) { ... }
|
|
867
|
+
|
|
868
|
+
Constructs a new CArray object of <i>data_type</i>, which has the
|
|
869
|
+
ndim and the dimensions specified by an <code>Array</code> of
|
|
870
|
+
<code>Integer</code> or an argument list of <code>Integer</code>.
|
|
871
|
+
The byte size of each element for the fixed length data type
|
|
872
|
+
(<code>data_type == CA_FIXLEN</code>) is specified optional argument
|
|
873
|
+
<i>bytes</i>. Otherwise, this optional argument has no
|
|
874
|
+
effect. If the block is given, the new CArray
|
|
875
|
+
object will be initialized by the value returned from the block.
|
|
876
|
+
*/
|
|
877
|
+
|
|
878
|
+
static VALUE
|
|
879
|
+
rb_ca_initialize (int argc, VALUE *argv, VALUE self)
|
|
880
|
+
{
|
|
881
|
+
CArray *ca;
|
|
882
|
+
int8_t data_type, ndim;
|
|
883
|
+
ca_size_t dim[CA_RANK_MAX];
|
|
884
|
+
ca_size_t bytes;
|
|
885
|
+
|
|
886
|
+
ca_scan_construct_args(argc, argv, &data_type, &bytes, &ndim, dim);
|
|
873
887
|
|
|
874
888
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
875
889
|
if ( ca_func[CA_OBJ_ARRAY].pool_init ) {
|
|
@@ -1438,6 +1452,33 @@ rb_ca_s_alloc_uninit (VALUE klass, VALUE rtype, VALUE rshape)
|
|
|
1438
1452
|
return rb_carray_new(data_type, ndim, dim, bytes, NULL);
|
|
1439
1453
|
}
|
|
1440
1454
|
|
|
1455
|
+
/* Internal primitive behind CArray.empty(data_type, dim, bytes: nil) in
|
|
1456
|
+
lib/carray/construct.rb, which also routes the compatibility spelling
|
|
1457
|
+
CArray.empty(*shape). It is CArray.new with the fill left out: the
|
|
1458
|
+
arguments are read by the same function, and the buffer comes from
|
|
1459
|
+
rb_carray_new (= no MEMZERO) rather than rb_carray_new_safe. A block
|
|
1460
|
+
is refused -- filling is what CArray.new is for. CA_OBJECT still
|
|
1461
|
+
falls through to the zero-VALUE init inside carray_setup_i (= required
|
|
1462
|
+
for GC), so any data_type is safe to ask for. */
|
|
1463
|
+
|
|
1464
|
+
static VALUE
|
|
1465
|
+
rb_ca_s_empty (int argc, VALUE *argv, VALUE klass)
|
|
1466
|
+
{
|
|
1467
|
+
int8_t data_type, ndim;
|
|
1468
|
+
ca_size_t dim[CA_RANK_MAX];
|
|
1469
|
+
ca_size_t bytes;
|
|
1470
|
+
|
|
1471
|
+
if ( rb_block_given_p() ) {
|
|
1472
|
+
rb_raise(rb_eArgError,
|
|
1473
|
+
"CArray.empty does not take a block "
|
|
1474
|
+
"(its contents are left undefined); use CArray.new to fill.");
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
ca_scan_construct_args(argc, argv, &data_type, &bytes, &ndim, dim);
|
|
1478
|
+
|
|
1479
|
+
return rb_carray_new(data_type, ndim, dim, bytes, NULL);
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1441
1482
|
void
|
|
1442
1483
|
Init_ca_obj_array (void)
|
|
1443
1484
|
{
|
|
@@ -1449,6 +1490,7 @@ Init_ca_obj_array (void)
|
|
|
1449
1490
|
rb_define_method(rb_cCArray, "initialize", rb_ca_initialize, -1);
|
|
1450
1491
|
rb_define_singleton_method(rb_cCArray, "__alloc_uninit__",
|
|
1451
1492
|
rb_ca_s_alloc_uninit, 2);
|
|
1493
|
+
rb_define_singleton_method(rb_cCArray, "__empty__", rb_ca_s_empty, -1);
|
|
1452
1494
|
|
|
1453
1495
|
rb_define_singleton_method(rb_cCArray, "fixlen", rb_ca_s_fixlen, -1);
|
|
1454
1496
|
rb_define_singleton_method(rb_cCArray, "boolean", rb_ca_s_boolean, -1);
|
data/ext/ca_obj_block.c
CHANGED
|
@@ -269,8 +269,10 @@ rb_cb_initialize_copy (VALUE self, VALUE other)
|
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
/* Per-axis accessor macro: defines a method that returns the named
|
|
272
|
-
CABlock tail array (size0 / start / step
|
|
273
|
-
`offset` is a single Integer and uses its own accessor below.
|
|
272
|
+
CABlock tail array (size0 / start / step) as a Ruby Array.
|
|
273
|
+
`offset` is a single Integer and uses its own accessor below.
|
|
274
|
+
`count` has no accessor: it is what `shape` already answers, and the
|
|
275
|
+
name belongs to CArray#count. */
|
|
274
276
|
#define rb_cb_get_attr_ary(name) \
|
|
275
277
|
rb_cb_ ## name (VALUE self) \
|
|
276
278
|
{ \
|
|
@@ -288,7 +290,6 @@ rb_cb_ ## name (VALUE self) \
|
|
|
288
290
|
static VALUE rb_cb_get_attr_ary(size0)
|
|
289
291
|
static VALUE rb_cb_get_attr_ary(start)
|
|
290
292
|
static VALUE rb_cb_get_attr_ary(step)
|
|
291
|
-
static VALUE rb_cb_get_attr_ary(count)
|
|
292
293
|
|
|
293
294
|
static VALUE
|
|
294
295
|
rb_cb_offset (VALUE self)
|
|
@@ -376,7 +377,6 @@ Init_ca_obj_block (void)
|
|
|
376
377
|
rb_define_method(rb_cCABlock, "size0", rb_cb_size0, 0);
|
|
377
378
|
rb_define_method(rb_cCABlock, "start", rb_cb_start, 0);
|
|
378
379
|
rb_define_method(rb_cCABlock, "step", rb_cb_step, 0);
|
|
379
|
-
rb_define_method(rb_cCABlock, "count", rb_cb_count, 0);
|
|
380
380
|
rb_define_method(rb_cCABlock, "offset", rb_cb_offset, 0);
|
|
381
381
|
|
|
382
382
|
rb_define_method(rb_cCABlock, "idx2addr0", rb_cb_idx2addr0, -1);
|
data/ext/ca_obj_const_string.c
CHANGED
|
@@ -38,10 +38,10 @@
|
|
|
38
38
|
typedef struct {
|
|
39
39
|
/* === CAView prefix === */
|
|
40
40
|
int16_t obj_type;
|
|
41
|
-
int8_t data_type; /* CA_FIXLEN surface (numeric gate); storage is
|
|
41
|
+
int8_t data_type; /* CA_FIXLEN surface (numeric gate); storage is fixlen-16 */
|
|
42
42
|
int8_t ndim;
|
|
43
43
|
int32_t flags; /* CA_FLAG_IS_FACE set */
|
|
44
|
-
ca_size_t bytes; /* sizeof(int64_t) =
|
|
44
|
+
ca_size_t bytes; /* 2 * sizeof(int64_t) = 16 (one (start,end) pair per element) */
|
|
45
45
|
ca_size_t elements;
|
|
46
46
|
ca_size_t *dim;
|
|
47
47
|
char *ptr;
|
|
@@ -299,6 +299,54 @@ rb_ca_const_string_wrap (VALUE parent_val, VALUE buffer, int encoding_id)
|
|
|
299
299
|
rb_raise(rb_eTypeError, "CAConstString.wrap: buffer: must be a String");
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
+
/* This is the one door through which already-built offsets enter, so it
|
|
303
|
+
validates rather than assumes. Everything downstream -- the per-cell
|
|
304
|
+
decode, the native byte scans, the sort comparator -- reads `buf + start`
|
|
305
|
+
for `end - start` bytes on the strength of these pairs; an out-of-range
|
|
306
|
+
one is an out-of-bounds read of the heap, not a wrong answer. Refuse it
|
|
307
|
+
here, while the input is still in the caller's hands, rather than letting
|
|
308
|
+
it surface as an IndexError from a decode or as a crash from a scan.
|
|
309
|
+
|
|
310
|
+
A masked cell is exempt: its bytes may be anything at all, that being the
|
|
311
|
+
CArray mask contract, and no reader dereferences them (the scan skips on
|
|
312
|
+
the mask before touching an offset; `.value`, the explicit strip, raises
|
|
313
|
+
from the decode). */
|
|
314
|
+
{
|
|
315
|
+
ca_size_t i, n;
|
|
316
|
+
int64_t *pair;
|
|
317
|
+
boolean8_t *m;
|
|
318
|
+
|
|
319
|
+
ca_attach(parent);
|
|
320
|
+
ca_update_mask(parent);
|
|
321
|
+
n = parent->elements;
|
|
322
|
+
pair = (int64_t *) parent->ptr;
|
|
323
|
+
m = parent->mask ? (boolean8_t *) parent->mask->ptr : NULL;
|
|
324
|
+
for ( i = 0; i < n; i++ ) {
|
|
325
|
+
int64_t start = pair[2 * i], end = pair[2 * i + 1];
|
|
326
|
+
if ( m && m[i] ) {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if ( start < 0 || end < start || end > (int64_t) RSTRING_LEN(buffer) ) {
|
|
330
|
+
ca_detach(parent);
|
|
331
|
+
rb_raise(rb_eArgError,
|
|
332
|
+
"CAConstString.wrap: element %lld has range [%lld,%lld), "
|
|
333
|
+
"outside the %ld-byte buffer",
|
|
334
|
+
(long long) i, (long long) start, (long long) end,
|
|
335
|
+
(long) RSTRING_LEN(buffer));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
ca_detach(parent);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* Take ownership of the offsets, the way CACategorical.from_codes takes
|
|
342
|
+
ownership of its codes. Without this the Face is read-only but its
|
|
343
|
+
storage is not, so `cs.parent[i] = <anything>` walks straight past the
|
|
344
|
+
check above and back into an out-of-bounds read. The flag rather than
|
|
345
|
+
#freeze, for the reason from_codes gives: freeze would propagate through
|
|
346
|
+
views and Faces. A caller that wants to keep a mutable entity of its own
|
|
347
|
+
passes `.copy`. */
|
|
348
|
+
ca_set_flag(parent, CA_FLAG_READ_ONLY);
|
|
349
|
+
|
|
302
350
|
ca = ca_const_string_new(parent, rb_str_freeze(buffer), encoding_id);
|
|
303
351
|
obj = TypedData_Wrap_Struct(rb_cCAConstString, &catext_data_type, ca);
|
|
304
352
|
rb_ca_set_parent(obj, parent_val); /* pin parent VALUE for GC */
|
|
@@ -397,10 +445,13 @@ rb_ca_const_string_encoding (VALUE self)
|
|
|
397
445
|
return rb_enc_from_encoding(rb_enc_from_index(ca->encoding_id));
|
|
398
446
|
}
|
|
399
447
|
|
|
400
|
-
/* `CAConstString#buffer` — returns the frozen internal byte buffer
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
path.
|
|
448
|
+
/* `CAConstString#buffer` — returns the frozen internal byte buffer: a pure
|
|
449
|
+
concatenation of the element bytes, with no per-record length prefix (=
|
|
450
|
+
the Arrow values buffer). Exposes the defining tail state for
|
|
451
|
+
introspection and the Arrow-boundary component-buffer export path. The
|
|
452
|
+
ranges that index it live in the storage, one (start,end) int64 pair per
|
|
453
|
+
element; `wrap` is where a hand-built pair array is checked against a
|
|
454
|
+
buffer. */
|
|
404
455
|
static VALUE
|
|
405
456
|
rb_ca_const_string_buffer (VALUE self)
|
|
406
457
|
{
|
|
@@ -540,7 +591,7 @@ ca_const_string_scan_end (ca_const_string_scan_t *s)
|
|
|
540
591
|
so element i occupies s->off[2*i] (start) .. s->off[2*i+1] (end).
|
|
541
592
|
The buffer is a pure concatenation; length = end - start. */
|
|
542
593
|
static inline int
|
|
543
|
-
ca_const_string_record (ca_const_string_scan_t *s, ca_size_t i, const char **pp,
|
|
594
|
+
ca_const_string_record (ca_const_string_scan_t *s, ca_size_t i, const char **pp, int64_t *plen)
|
|
544
595
|
{
|
|
545
596
|
int64_t start, end;
|
|
546
597
|
if ( s->m && s->m[i] ) {
|
|
@@ -549,7 +600,7 @@ ca_const_string_record (ca_const_string_scan_t *s, ca_size_t i, const char **pp,
|
|
|
549
600
|
start = s->off[2 * i];
|
|
550
601
|
end = s->off[2 * i + 1];
|
|
551
602
|
*pp = s->buf + start;
|
|
552
|
-
*plen = (
|
|
603
|
+
*plen = (int64_t) (end - start);
|
|
553
604
|
return 1;
|
|
554
605
|
}
|
|
555
606
|
|
|
@@ -598,7 +649,7 @@ rb_ca_const_string_byte_length (VALUE self)
|
|
|
598
649
|
CArray *co;
|
|
599
650
|
int64_t *op;
|
|
600
651
|
const char *p;
|
|
601
|
-
|
|
652
|
+
int64_t len;
|
|
602
653
|
ca_size_t i;
|
|
603
654
|
|
|
604
655
|
ca_const_string_scan_begin(self, &s);
|
|
@@ -633,7 +684,7 @@ ca_const_string_predicate (VALUE self, VALUE query, int op)
|
|
|
633
684
|
boolean8_t *out;
|
|
634
685
|
const char *qp, *p;
|
|
635
686
|
long qlen;
|
|
636
|
-
|
|
687
|
+
int64_t len;
|
|
637
688
|
ca_size_t i;
|
|
638
689
|
|
|
639
690
|
if ( TYPE(query) != T_STRING ) {
|
|
@@ -686,7 +737,7 @@ rb_ca_const_string_eq (VALUE self, VALUE other)
|
|
|
686
737
|
they are read only when both records are valid, but GCC cannot prove
|
|
687
738
|
that -- initialize to keep -Wmaybe-uninitialized quiet and defensive. */
|
|
688
739
|
const char *pa = NULL, *pb = NULL;
|
|
689
|
-
|
|
740
|
+
int64_t la = 0, lb = 0;
|
|
690
741
|
ca_size_t i;
|
|
691
742
|
|
|
692
743
|
ca_const_string_scan_begin(self, &a);
|
|
@@ -717,7 +768,7 @@ rb_ca_const_string_count (VALUE self, VALUE query)
|
|
|
717
768
|
ca_const_string_scan_t s;
|
|
718
769
|
const char *qp, *p;
|
|
719
770
|
long qlen;
|
|
720
|
-
|
|
771
|
+
int64_t len;
|
|
721
772
|
ca_size_t i, c = 0;
|
|
722
773
|
|
|
723
774
|
if ( TYPE(query) != T_STRING ) {
|
|
@@ -747,7 +798,7 @@ rb_ca_const_string_search (VALUE self, VALUE query)
|
|
|
747
798
|
ca_const_string_scan_t s;
|
|
748
799
|
const char *qp, *p;
|
|
749
800
|
long qlen;
|
|
750
|
-
|
|
801
|
+
int64_t len;
|
|
751
802
|
ca_size_t i;
|
|
752
803
|
VALUE result = Qnil;
|
|
753
804
|
|
|
@@ -786,7 +837,7 @@ ca_const_string_byte_cmp (const void *a, const void *b)
|
|
|
786
837
|
/* sort raises on masked input, so record() always sets these here; the
|
|
787
838
|
initializers keep -Wmaybe-uninitialized quiet and stay defensive. */
|
|
788
839
|
const char *pa = NULL, *pb = NULL;
|
|
789
|
-
|
|
840
|
+
int64_t la = 0, lb = 0;
|
|
790
841
|
int c;
|
|
791
842
|
ca_const_string_record(ca_const_string_sort_ctx, ia, &pa, &la);
|
|
792
843
|
ca_const_string_record(ca_const_string_sort_ctx, ib, &pb, &lb);
|
|
@@ -836,9 +887,15 @@ rb_ca_const_string_sort_index (VALUE self)
|
|
|
836
887
|
return vout;
|
|
837
888
|
}
|
|
838
889
|
|
|
839
|
-
/*
|
|
840
|
-
|
|
841
|
-
|
|
890
|
+
/* The ordering surface is defined in Ruby (lib/carray/const_string.rb) on
|
|
891
|
+
top of these three: a storage cell is a byte range, so storage order is
|
|
892
|
+
insertion order rather than string order, and every member has to read
|
|
893
|
+
the bytes. What is native here is the flat form, which is the common one
|
|
894
|
+
for a string column and which a byte scan does an order of magnitude
|
|
895
|
+
faster than decoding a Ruby String per cell; the per-axis forms go
|
|
896
|
+
through #to_string. These are spelled as internals because the public
|
|
897
|
+
names carry CArray's meanings: what the permutation below answers is
|
|
898
|
+
sort_addr (view-flat addresses in sorted order), not sort_index. */
|
|
842
899
|
|
|
843
900
|
/* CAConstString#min / #max → the byte-min / byte-max element as a frozen String,
|
|
844
901
|
skipping masked elements; nil if empty or all masked. */
|
|
@@ -847,7 +904,7 @@ ca_const_string_extremum (VALUE self, int want_max)
|
|
|
847
904
|
{
|
|
848
905
|
ca_const_string_scan_t s;
|
|
849
906
|
const char *p, *bestp = NULL;
|
|
850
|
-
|
|
907
|
+
int64_t len, bestlen = 0;
|
|
851
908
|
ca_size_t i;
|
|
852
909
|
int found = 0;
|
|
853
910
|
|
|
@@ -894,9 +951,9 @@ rb_ca_const_string_initialize_copy (VALUE self, VALUE other)
|
|
|
894
951
|
CAConstString *ca, *cs;
|
|
895
952
|
TypedData_Get_Struct(self, CAConstString, &catext_data_type, ca);
|
|
896
953
|
TypedData_Get_Struct(other, CAConstString, &catext_data_type, cs);
|
|
897
|
-
/*
|
|
898
|
-
|
|
899
|
-
buffer
|
|
954
|
+
/* Shallow re-setup: shares the buffer and the offset source, which is the
|
|
955
|
+
documented `dup` semantics for a view. `copy` is the compacting deep
|
|
956
|
+
copy (rebased offsets, compacted buffer, detached). */
|
|
900
957
|
if ( ca_func[CA_OBJ_CONST_STRING].pool_init ) {
|
|
901
958
|
ca_array_pool_alloc(ca, CA_OBJ_CONST_STRING, cs->parent->ndim);
|
|
902
959
|
}
|
|
@@ -949,11 +1006,13 @@ Init_ca_obj_const_string (void)
|
|
|
949
1006
|
rb_define_method(rb_cCAConstString, "search", rb_ca_const_string_search, 1);
|
|
950
1007
|
rb_define_method(rb_cCAConstString, "find_value_index", rb_ca_const_string_search, 1);
|
|
951
1008
|
|
|
952
|
-
/*
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
rb_define_method(rb_cCAConstString, "
|
|
956
|
-
|
|
1009
|
+
/* Native flat sort permutation / min / max (§3.7), byte-memcmp
|
|
1010
|
+
comparator. The public ordering surface is built on these in
|
|
1011
|
+
lib/carray/const_string.rb; see the comment above their definitions. */
|
|
1012
|
+
rb_define_method(rb_cCAConstString, "__sort_addr_bytes__",
|
|
1013
|
+
rb_ca_const_string_sort_index, 0);
|
|
1014
|
+
rb_define_method(rb_cCAConstString, "__min_bytes__", rb_ca_const_string_min, 0);
|
|
1015
|
+
rb_define_method(rb_cCAConstString, "__max_bytes__", rb_ca_const_string_max, 0);
|
|
957
1016
|
|
|
958
1017
|
/* Y-pilot: Face-local C-level fast path for per-cell scalar fetch. */
|
|
959
1018
|
ca_face_register_storage_to_scalar(CA_OBJ_CONST_STRING, rb_ca_const_string_storage_to_scalar);
|
data/ext/ca_obj_face.c
CHANGED
|
@@ -595,6 +595,30 @@ ca_face_class_has_portable_method (VALUE klass)
|
|
|
595
595
|
return ( owner != rb_singleton_class(rb_cCArray) ) ? 1 : 0;
|
|
596
596
|
}
|
|
597
597
|
|
|
598
|
+
VALUE
|
|
599
|
+
ca_face_operand_descend (VALUE operand, const char *name)
|
|
600
|
+
{
|
|
601
|
+
CArray *op;
|
|
602
|
+
if ( ! RTEST(rb_obj_is_carray(operand)) ) {
|
|
603
|
+
return operand;
|
|
604
|
+
}
|
|
605
|
+
TypedData_Get_Struct(operand, CArray, &carray_data_type, op);
|
|
606
|
+
if ( ! ca_is_face(op) ) {
|
|
607
|
+
return operand;
|
|
608
|
+
}
|
|
609
|
+
if ( ca_test_flag(op, CA_FLAG_FACE_COMPARABLE_STORAGE) ) {
|
|
610
|
+
return rb_ca_strip_face_value(operand);
|
|
611
|
+
}
|
|
612
|
+
rb_raise(rb_eArgError,
|
|
613
|
+
"%s: cannot take a %s operand: its storage is not its surface "
|
|
614
|
+
"(a cell encodes the value rather than being it), so comparing "
|
|
615
|
+
"the storage would compare the encoding. Convert the operand to "
|
|
616
|
+
"the receiver's space first -- #to_string for a string Face -- "
|
|
617
|
+
"or pass .parent on both sides to work in storage space",
|
|
618
|
+
name, rb_obj_classname(operand));
|
|
619
|
+
return Qnil; /* not reached */
|
|
620
|
+
}
|
|
621
|
+
|
|
598
622
|
int
|
|
599
623
|
ca_face_state_portable (int obj_type, VALUE klass)
|
|
600
624
|
{
|