carray 2.0.0 → 3.0.0
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/.yardopts +5 -25
- data/CHANGELOG.md +16 -0
- data/LICENSE +1 -1
- data/NEWS.md +3 -0
- data/README.md +128 -44
- data/carray.gemspec +22 -24
- data/ext/ca_array_pool.c +91 -0
- data/ext/ca_axis_descriptor.h +186 -0
- data/ext/ca_axis_dispatch.c +924 -0
- data/ext/ca_axis_group.c +1208 -0
- data/ext/ca_bincmp_dispatch.c +76 -0
- data/ext/ca_bincmp_dispatch.h +85 -0
- data/ext/ca_binop_dispatch.c +125 -0
- data/ext/ca_binop_dispatch.h +159 -0
- data/ext/ca_categorical_iterator.c +1375 -0
- data/ext/ca_compare.c +94 -0
- data/ext/ca_compare.h +26 -0
- data/ext/ca_composite_dispatch.c +414 -0
- data/ext/ca_composite_dispatch.h +116 -0
- data/ext/ca_for_buffer.h +96 -0
- data/ext/ca_for_each_element.h +241 -0
- data/ext/ca_group_iter.c +304 -0
- data/ext/ca_iter_substrate.h +325 -0
- data/ext/ca_kernel_iterator.c +4321 -0
- data/ext/ca_kernel_iterator.h +2603 -0
- data/ext/ca_moncmp_dispatch.c +37 -0
- data/ext/ca_moncmp_dispatch.h +62 -0
- data/ext/ca_monop_dispatch.c +200 -0
- data/ext/ca_monop_dispatch.h +235 -0
- data/ext/ca_obj_array.c +355 -359
- data/ext/ca_obj_bincmp.c +809 -0
- data/ext/ca_obj_binop.c +892 -0
- data/ext/ca_obj_bitarray.c +369 -164
- data/ext/ca_obj_bitfield.c +294 -234
- data/ext/ca_obj_block.c +189 -711
- data/ext/ca_obj_byte_swap.c +766 -0
- data/ext/ca_obj_const_string.c +965 -0
- data/ext/ca_obj_face.c +670 -0
- data/ext/ca_obj_face.h +247 -0
- data/ext/ca_obj_fake.c +228 -100
- data/ext/ca_obj_farray.c +54 -441
- data/ext/ca_obj_field.c +82 -529
- data/ext/ca_obj_fixlen_string.c +306 -0
- data/ext/ca_obj_grid.c +858 -440
- data/ext/ca_obj_meld.c +1034 -0
- data/ext/ca_obj_moncmp.c +569 -0
- data/ext/ca_obj_monop.c +1111 -0
- data/ext/ca_obj_object.c +774 -298
- data/ext/ca_obj_record.c +468 -0
- data/ext/ca_obj_reduce.c +97 -82
- data/ext/ca_obj_refer.c +569 -459
- data/ext/ca_obj_remap.c +475 -0
- data/ext/ca_obj_repeat.c +92 -477
- data/ext/ca_obj_roll.c +616 -0
- data/ext/ca_obj_select.c +344 -296
- data/ext/ca_obj_select_axis.c +1296 -0
- data/ext/ca_obj_shift.c +230 -792
- data/ext/ca_obj_source.c +78 -0
- data/ext/ca_obj_stack.c +1173 -0
- data/ext/ca_obj_stride.c +2501 -0
- data/ext/ca_obj_string.c +268 -0
- data/ext/ca_obj_tile.c +614 -0
- data/ext/ca_obj_time.c +546 -0
- data/ext/ca_obj_timedelta.c +435 -0
- data/ext/ca_obj_transpose.c +62 -516
- data/ext/ca_obj_triop.c +746 -0
- data/ext/ca_obj_unbound_repeat.c +208 -241
- data/ext/ca_obj_window.c +1131 -563
- data/ext/ca_op_byte_swap.c +175 -0
- data/ext/ca_op_ipower.c +319 -0
- data/ext/ca_op_powi.h +88 -0
- data/ext/ca_sort_kernels.h +132 -0
- data/ext/ca_sweep_engine.c +430 -0
- data/ext/ca_sweep_engine.h +157 -0
- data/ext/ca_transform_common.c +228 -0
- data/ext/ca_triop_dispatch.c +55 -0
- data/ext/ca_triop_dispatch.h +62 -0
- data/ext/carray.h +795 -402
- data/ext/carray_access.c +831 -711
- data/ext/carray_attribute.c +98 -330
- data/ext/carray_bincount.c +255 -0
- data/ext/carray_broadcast.c +283 -0
- data/ext/carray_call_cfunc.c +1360 -828
- data/ext/carray_call_cfunc.h +160 -0
- data/ext/carray_cast.c +1212 -301
- data/ext/carray_cast_func.rb +81 -40
- data/ext/carray_class.c +53 -63
- data/ext/carray_config.h +28 -0
- data/ext/carray_conversion.c +350 -346
- data/ext/carray_copy.c +156 -268
- data/ext/carray_core.c +1342 -199
- data/ext/carray_count.c +312 -0
- data/ext/carray_data_type.c +43 -19
- data/ext/carray_element.c +585 -213
- data/ext/carray_factorize.c +2542 -0
- data/ext/carray_generate.c +230 -559
- data/ext/carray_histogram.c +490 -0
- data/ext/carray_hold.c +228 -0
- data/ext/carray_index_classifier.c +1035 -0
- data/ext/carray_index_classifier.h +27 -0
- data/ext/carray_internal.h +120 -0
- data/ext/carray_kernels_bincmp.c +4445 -0
- data/ext/carray_kernels_binop.c +10979 -0
- data/ext/carray_kernels_init.c +36 -0
- data/ext/carray_kernels_map.c +3466 -0
- data/ext/carray_kernels_moncmp.c +2096 -0
- data/ext/carray_kernels_monop.c +18312 -0
- data/ext/carray_kernels_reduce_aggregate.c +25836 -0
- data/ext/carray_kernels_reduce_boolean.c +329 -0
- data/ext/carray_kernels_reduce_cumulative.c +14592 -0
- data/ext/carray_kernels_reduce_extreme.c +16947 -0
- data/ext/carray_kernels_reduce_variance.c +3909 -0
- data/ext/carray_kernels_scan.c +3692 -0
- data/ext/carray_kernels_search.c +32137 -0
- data/ext/carray_kernels_sort.c +10625 -0
- data/ext/carray_kernels_triop.c +1391 -0
- data/ext/carray_lazy.c +567 -0
- data/ext/carray_loop.c +88 -200
- data/ext/carray_mask.c +848 -154
- data/ext/carray_math_kernel.h +120 -0
- data/ext/carray_mathfunc.c +10 -241
- data/ext/carray_median_percentile.c +1257 -0
- data/ext/carray_memory_view.c +1625 -0
- data/ext/carray_operator.c +1526 -318
- data/ext/carray_order.c +664 -1394
- data/ext/carray_partition.c +416 -0
- data/ext/carray_random.c +518 -0
- data/ext/carray_scatter.c +357 -0
- data/ext/carray_slab.c +1219 -0
- data/ext/carray_slab.h +84 -0
- data/ext/carray_sort.c +829 -0
- data/ext/carray_sort_kernel.c +620 -0
- data/ext/carray_struct.c +695 -0
- data/ext/carray_test.c +343 -229
- data/ext/carray_undef.c +34 -17
- data/ext/carray_utils.c +175 -74
- data/ext/extconf.rb +216 -55
- data/ext/mk_call_cfunc.rb +480 -0
- data/ext/mkkernel.rb +8842 -0
- data/ext/ruby_carray.c +202 -101
- data/ext/version.h +4 -14
- data/ext/version.rb +5 -13
- data/lib/carray/arrow_tensor.rb +401 -0
- data/lib/carray/attribute.rb +166 -0
- data/lib/carray/autoload_carray.rb +220 -0
- data/lib/carray/autoload_method_extension.rb +44 -0
- data/lib/carray/axis_group.rb +711 -0
- data/lib/carray/basics.rb +481 -0
- data/lib/carray/bincount_nd.rb +358 -0
- data/lib/carray/block_iterator.rb +604 -0
- data/lib/carray/boolean_reduce.rb +109 -0
- data/lib/carray/categorical.rb +561 -0
- data/lib/carray/categorical_iterator.rb +1062 -0
- data/lib/carray/complex.rb +150 -0
- data/lib/carray/conditional.rb +216 -0
- data/lib/carray/const_string.rb +228 -0
- data/lib/carray/construct.rb +139 -328
- data/lib/carray/core_extensions.rb +240 -0
- data/lib/carray/data_type_extension.rb +233 -0
- data/lib/carray/fixlen_string.rb +95 -0
- data/lib/carray/frame/concat.rb +132 -0
- data/lib/carray/frame/convert.rb +95 -0
- data/lib/carray/frame/csv_parser.rb +211 -0
- data/lib/carray/frame/frame.rb +649 -0
- data/lib/carray/frame/group.rb +186 -0
- data/lib/carray/frame/io.rb +164 -0
- data/lib/carray/frame/join.rb +248 -0
- data/lib/carray/frame/records.rb +99 -0
- data/lib/carray/frame/sort.rb +113 -0
- data/lib/carray/frame/verbs.rb +299 -0
- data/lib/carray/frame.rb +16 -0
- data/lib/carray/histogram.rb +512 -0
- data/lib/carray/inspect.rb +37 -20
- data/lib/carray/iterator.rb +57 -349
- data/lib/carray/lazy.rb +889 -0
- data/lib/carray/mask_gap_fill.rb +200 -0
- data/lib/carray/math.rb +78 -342
- data/lib/carray/meld_reduce.rb +289 -0
- data/lib/carray/methods/align_addr.rb +116 -0
- data/lib/carray/methods/bin.rb +128 -0
- data/lib/carray/methods/bincount.rb +87 -0
- data/lib/carray/methods/bit_string.rb +92 -0
- data/lib/carray/methods/broadcast.rb +63 -0
- data/lib/carray/methods/choose.rb +39 -0
- data/lib/carray/methods/composition.rb +280 -0
- data/lib/carray/methods/gather_nd.rb +206 -0
- data/lib/carray/methods/index.rb +39 -0
- data/lib/carray/methods/insert_block.rb +99 -0
- data/lib/carray/methods/is_in.rb +141 -0
- data/lib/carray/methods/join.rb +90 -0
- data/lib/carray/methods/locate_addr.rb +47 -0
- data/lib/carray/methods/mask_duplicates.rb +41 -0
- data/lib/carray/methods/meshgrid.rb +91 -0
- data/lib/carray/methods/mode.rb +126 -0
- data/lib/carray/methods/nunique.rb +46 -0
- data/lib/carray/methods/resize.rb +56 -0
- data/lib/carray/methods/snap.rb +156 -0
- data/lib/carray/methods/string_format.rb +57 -0
- data/lib/carray/methods/unique.rb +47 -0
- data/lib/carray/methods/value_counts.rb +71 -0
- data/lib/carray/mkmf.rb +124 -101
- data/lib/carray/runtime.rb +108 -0
- data/lib/carray/serialize.rb +478 -167
- data/lib/carray/slab_iterator.rb +292 -0
- data/lib/carray/stack.rb +291 -0
- data/lib/carray/string.rb +56 -180
- data/lib/carray/string_operation_extension.rb +289 -0
- data/lib/carray/struct.rb +335 -323
- data/lib/carray/struct_builder.rb +697 -0
- data/lib/carray/table.rb +41 -2
- data/lib/carray/time.rb +2255 -38
- data/lib/carray/window_iterator.rb +655 -0
- data/lib/carray.rb +55 -57
- metadata +163 -130
- data/Rakefile +0 -51
- data/TODO.md +0 -18
- data/ext/ca_iter_block.c +0 -257
- data/ext/ca_iter_dimension.c +0 -299
- data/ext/ca_iter_window.c +0 -214
- data/ext/ca_obj_mapping.c +0 -644
- data/ext/carray_iterator.c +0 -641
- data/ext/carray_math.rb +0 -850
- data/ext/carray_numeric.c +0 -259
- data/ext/carray_sort_addr.c +0 -254
- data/ext/carray_stat.c +0 -2100
- data/ext/carray_stat_proc.rb +0 -1999
- data/ext/mkmath.rb +0 -741
- data/ext/ruby_ccomplex.c +0 -509
- data/ext/ruby_float_func.c +0 -86
- data/lib/carray/array.rb +0 -8
- data/lib/carray/autoload/autoload_base.rb +0 -19
- data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
- data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
- data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
- data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
- data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
- data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
- data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
- data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
- data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
- data/lib/carray/autoload/autoload_gem_random.rb +0 -8
- data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
- data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
- data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
- data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
- data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
- data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
- data/lib/carray/autoload/autoload_object_link.rb +0 -1
- data/lib/carray/autoload/autoload_object_pack.rb +0 -2
- data/lib/carray/autoload.rb +0 -141
- data/lib/carray/basic.rb +0 -191
- data/lib/carray/broadcast.rb +0 -101
- data/lib/carray/compose.rb +0 -315
- data/lib/carray/convert.rb +0 -115
- data/lib/carray/info.rb +0 -110
- data/lib/carray/io/imagemagick.rb +0 -235
- data/lib/carray/mask.rb +0 -102
- data/lib/carray/math/histogram.rb +0 -177
- data/lib/carray/math/recurrence.rb +0 -93
- data/lib/carray/object/ca_obj_iterator.rb +0 -50
- data/lib/carray/object/ca_obj_link.rb +0 -50
- data/lib/carray/object/ca_obj_pack.rb +0 -99
- data/lib/carray/obsolete.rb +0 -256
- data/lib/carray/ordering.rb +0 -181
- data/lib/carray/testing.rb +0 -51
- data/lib/carray/transform.rb +0 -109
- data/misc/Methods.ja.md +0 -182
- data/misc/NOTE +0 -51
- data/spec/Classes/CABitfield_spec.rb +0 -58
- data/spec/Classes/CABlockIterator_spec.rb +0 -114
- data/spec/Classes/CABlock_spec.rb +0 -205
- data/spec/Classes/CAField_spec.rb +0 -39
- data/spec/Classes/CAGrid_spec.rb +0 -75
- data/spec/Classes/CAMap_spec.rb +0 -0
- data/spec/Classes/CAMapping_spec.rb +0 -105
- data/spec/Classes/CAObject_attribute_spec.rb +0 -33
- data/spec/Classes/CAObject_spec.rb +0 -33
- data/spec/Classes/CARefer_spec.rb +0 -93
- data/spec/Classes/CARepeat_spec.rb +0 -65
- data/spec/Classes/CASelect_spec.rb +0 -22
- data/spec/Classes/CAShift_spec.rb +0 -16
- data/spec/Classes/CAStruct_spec.rb +0 -71
- data/spec/Classes/CATranspose_spec.rb +0 -60
- data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
- data/spec/Classes/CAWindow_spec.rb +0 -54
- data/spec/Classes/CAWrap_spec.rb +0 -8
- data/spec/Classes/CArray_spec.rb +0 -184
- data/spec/Classes/CScalar_spec.rb +0 -55
- data/spec/Classes/ex1.rb +0 -46
- data/spec/Features/feature_130_spec.rb +0 -19
- data/spec/Features/feature_attributes_spec.rb +0 -280
- data/spec/Features/feature_boolean_spec.rb +0 -98
- data/spec/Features/feature_broadcast.rb +0 -116
- data/spec/Features/feature_cast_function.rb +0 -19
- data/spec/Features/feature_cast_spec.rb +0 -33
- data/spec/Features/feature_class_spec.rb +0 -84
- data/spec/Features/feature_complex_spec.rb +0 -42
- data/spec/Features/feature_composite_spec.rb +0 -124
- data/spec/Features/feature_convert_spec.rb +0 -46
- data/spec/Features/feature_copy_spec.rb +0 -123
- data/spec/Features/feature_creation_spec.rb +0 -84
- data/spec/Features/feature_element_spec.rb +0 -144
- data/spec/Features/feature_extream_spec.rb +0 -54
- data/spec/Features/feature_generate_spec.rb +0 -74
- data/spec/Features/feature_index_spec.rb +0 -69
- data/spec/Features/feature_mask_spec.rb +0 -580
- data/spec/Features/feature_math_spec.rb +0 -97
- data/spec/Features/feature_order_spec.rb +0 -146
- data/spec/Features/feature_ref_store_spec.rb +0 -209
- data/spec/Features/feature_serialization_spec.rb +0 -125
- data/spec/Features/feature_stat_spec.rb +0 -397
- data/spec/Features/feature_virtual_spec.rb +0 -48
- data/spec/Features/method_eq_spec.rb +0 -81
- data/spec/Features/method_is_nan_spec.rb +0 -12
- data/spec/Features/method_map_spec.rb +0 -54
- data/spec/Features/method_max_with.rb +0 -20
- data/spec/Features/method_min_with.rb +0 -19
- data/spec/Features/method_ne_spec.rb +0 -18
- data/spec/Features/method_project_spec.rb +0 -188
- data/spec/Features/method_ref_spec.rb +0 -27
- data/spec/Features/method_round_spec.rb +0 -11
- data/spec/Features/method_s_linspace_spec.rb +0 -48
- data/spec/Features/method_s_span_spec.rb +0 -14
- data/spec/Features/method_seq_spec.rb +0 -47
- data/spec/Features/method_sort_with.rb +0 -43
- data/spec/Features/method_sorted_with.rb +0 -29
- data/spec/Features/method_span_spec.rb +0 -42
- data/spec/Features/method_wrap_readonly_spec.rb +0 -43
- data/spec/UnitTest/test_CAVirtual.rb +0 -214
- data/spec/spec_all.rb +0 -10
- data/utils/ca_ase.rb +0 -21
- data/utils/ca_methods.rb +0 -15
- data/utils/cast_checker.rb +0 -30
- data/utils/convert_test.rb +0 -73
- data/utils/extract_yard.rb +0 -22
- data/utils/guess_shape.rb +0 -76
- data/utils/monkey_patch_methods.rb +0 -62
- data/utils/remove_resource_fork.sh +0 -5
|
@@ -0,0 +1,965 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
ca_obj_const_string.c
|
|
4
|
+
|
|
5
|
+
CAConstString — read-only variable-length UTF-8 string column
|
|
6
|
+
(Arrow string layout via Face).
|
|
7
|
+
|
|
8
|
+
A Face whose tail carries the string `buffer` + encoding. Parent
|
|
9
|
+
(storage) is a fixlen-16 entity holding one `(int64 start, int64 end)`
|
|
10
|
+
pair per element; the buffer is a frozen byte String laid out as a
|
|
11
|
+
pure concatenation of the element bytes (= Arrow values buffer, no
|
|
12
|
+
per-record length prefix). Decoding element i: read the pair from
|
|
13
|
+
`parent[i]`, then `bytes = buf + start`, `len = end - start`. Each
|
|
14
|
+
element is self-describing (carries its own byte range), so gather /
|
|
15
|
+
sort / boolean-select views over the pairs decode correctly with no
|
|
16
|
+
buffer copy.
|
|
17
|
+
|
|
18
|
+
Surface data_type = CA_FIXLEN (numeric gate): mkkernel dispatch
|
|
19
|
+
routes numeric ops to `ca_*_not_implement` -> raise, preventing a
|
|
20
|
+
silent numeric strip of a CAConstString. Storage is fixlen-16 so
|
|
21
|
+
the byte size is told truthfully; the FIXLEN surface seals off
|
|
22
|
+
only the numeric meaning.
|
|
23
|
+
|
|
24
|
+
High-duplication columns belong in CACategorical (= Arrow
|
|
25
|
+
DictionaryArray), not here: CAConstString stores every element's
|
|
26
|
+
bytes once in logical order, without offset-sharing dedup.
|
|
27
|
+
|
|
28
|
+
Sibling of ca_obj_record.c (Face + VALUE tail + custom dmark) and
|
|
29
|
+
ca_obj_time.c (int64 Face + storage_to_scalar fast path).
|
|
30
|
+
|
|
31
|
+
--------------------------------------------------------------------------- */
|
|
32
|
+
|
|
33
|
+
#include "carray.h"
|
|
34
|
+
#include "ca_obj_face.h"
|
|
35
|
+
#include <ruby/encoding.h>
|
|
36
|
+
|
|
37
|
+
/* === struct layout (identical to the CATime prefix + tail) === */
|
|
38
|
+
typedef struct {
|
|
39
|
+
/* === CAView prefix === */
|
|
40
|
+
int16_t obj_type;
|
|
41
|
+
int8_t data_type; /* CA_FIXLEN surface (numeric gate); storage is int64 */
|
|
42
|
+
int8_t ndim;
|
|
43
|
+
int32_t flags; /* CA_FLAG_IS_FACE set */
|
|
44
|
+
ca_size_t bytes; /* sizeof(int64_t) = 8 (one offset per element) */
|
|
45
|
+
ca_size_t elements;
|
|
46
|
+
ca_size_t *dim;
|
|
47
|
+
char *ptr;
|
|
48
|
+
CArray *mask;
|
|
49
|
+
char *_pool; /* framework-managed pool buffer (NULL = legacy ALLOC_N path). */
|
|
50
|
+
CArray *parent; /* fixlen-16 (start,end) pair entity (offset-source) */
|
|
51
|
+
uint32_t attach;
|
|
52
|
+
uint8_t nosync;
|
|
53
|
+
/* === Face tail === */
|
|
54
|
+
VALUE buffer; /* frozen byte String (pure concat), marked by custom dmark */
|
|
55
|
+
int encoding_id; /* rb_enc_to_index() value */
|
|
56
|
+
} CAConstString;
|
|
57
|
+
|
|
58
|
+
static size_t
|
|
59
|
+
ca_const_string_dsize (const void *ap)
|
|
60
|
+
{
|
|
61
|
+
const CAConstString *ca = (const CAConstString *) ap;
|
|
62
|
+
return sizeof(CAConstString) + ca->ndim * sizeof(ca_size_t);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Pool framework hooks: single ndim-sized tail (dim) in the _pool
|
|
66
|
+
buffer (uniform alloc / free discipline). */
|
|
67
|
+
static size_t
|
|
68
|
+
ca_const_string_pool_bytes (int8_t ndim)
|
|
69
|
+
{
|
|
70
|
+
ca_size_t n = (ndim > 0) ? ndim : 1;
|
|
71
|
+
return (size_t) n * sizeof(ca_size_t);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static void
|
|
75
|
+
ca_const_string_pool_init (void *ap, int8_t ndim)
|
|
76
|
+
{
|
|
77
|
+
CAConstString *ca = (CAConstString *) ap;
|
|
78
|
+
ca->dim = (ca_size_t *) ca->_pool;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Custom dmark: ca_mark walks the standard prefix (CA_OBJECT elements, of
|
|
82
|
+
which a CAConstString has none); we additionally mark the buffer tail VALUE.
|
|
83
|
+
parent retention is via rb_ca_set_parent ivar (= not dmark), same as
|
|
84
|
+
CARecord / CATime. */
|
|
85
|
+
static void
|
|
86
|
+
ca_const_string_mark (void *ap)
|
|
87
|
+
{
|
|
88
|
+
CAConstString *ca = (CAConstString *) ap;
|
|
89
|
+
ca_mark(ca);
|
|
90
|
+
rb_gc_mark(ca->buffer);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const rb_data_type_t catext_data_type = {
|
|
94
|
+
.parent = &caface_data_type,
|
|
95
|
+
.wrap_struct_name = "CAConstString",
|
|
96
|
+
.function = {
|
|
97
|
+
.dmark = ca_const_string_mark,
|
|
98
|
+
.dfree = ca_free,
|
|
99
|
+
.dsize = ca_const_string_dsize,
|
|
100
|
+
.dcompact = NULL
|
|
101
|
+
},
|
|
102
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
static int8_t CA_OBJ_CONST_STRING;
|
|
106
|
+
static VALUE rb_cCAConstString;
|
|
107
|
+
|
|
108
|
+
/* yard:
|
|
109
|
+
class CAConstString < CAFace # :nodoc:
|
|
110
|
+
end
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
/* ------------------------------------------------------------------- */
|
|
114
|
+
|
|
115
|
+
int
|
|
116
|
+
ca_const_string_setup (CAConstString *ca, CArray *parent, VALUE buffer, int encoding_id)
|
|
117
|
+
{
|
|
118
|
+
if ( parent->data_type != CA_FIXLEN || parent->bytes != 2 * (ca_size_t) sizeof(int64_t) ) {
|
|
119
|
+
rb_raise(rb_eTypeError,
|
|
120
|
+
"CAConstString requires a fixlen-16 (start,end) pair storage "
|
|
121
|
+
"(parent.data_type must be CA_FIXLEN with bytes == 16)");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
ca->obj_type = CA_OBJ_CONST_STRING;
|
|
125
|
+
/* FIXLEN surface auto-gates mkkernel numeric dispatch. */
|
|
126
|
+
ca->data_type = CA_FIXLEN;
|
|
127
|
+
ca->flags = CA_FLAG_IS_FACE;
|
|
128
|
+
ca->ndim = parent->ndim;
|
|
129
|
+
ca->bytes = 2 * sizeof(int64_t); /* (start,end) pair per element */
|
|
130
|
+
ca->elements = parent->elements;
|
|
131
|
+
ca->ptr = NULL;
|
|
132
|
+
ca->mask = NULL;
|
|
133
|
+
if ( ! ca->_pool ) {
|
|
134
|
+
ca->dim = ALLOC_N(ca_size_t, parent->ndim);
|
|
135
|
+
}
|
|
136
|
+
memcpy(ca->dim, parent->dim, sizeof(ca_size_t) * parent->ndim);
|
|
137
|
+
|
|
138
|
+
ca->parent = parent;
|
|
139
|
+
ca->attach = 0;
|
|
140
|
+
ca->nosync = 0;
|
|
141
|
+
|
|
142
|
+
ca->buffer = buffer;
|
|
143
|
+
ca->encoding_id = encoding_id;
|
|
144
|
+
|
|
145
|
+
if ( ca_has_mask(parent) ) {
|
|
146
|
+
ca_create_mask((CArray *) ca);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if ( ca_is_scalar(parent) ) {
|
|
150
|
+
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* CAConstString is always read-only (Invariant 4). */
|
|
154
|
+
ca_set_flag(ca, CA_FLAG_READ_ONLY);
|
|
155
|
+
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
CAConstString *
|
|
160
|
+
ca_const_string_new (CArray *parent, VALUE buffer, int encoding_id)
|
|
161
|
+
{
|
|
162
|
+
CAConstString *ca = (CAConstString *) ca_array_alloc(CA_OBJ_CONST_STRING, parent->ndim);
|
|
163
|
+
ca_const_string_setup(ca, parent, buffer, encoding_id);
|
|
164
|
+
return ca;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
static void
|
|
168
|
+
free_ca_text (void *ap)
|
|
169
|
+
{
|
|
170
|
+
CAConstString *ca = (CAConstString *) ap;
|
|
171
|
+
if ( ca != NULL ) {
|
|
172
|
+
ca_free(ca->mask);
|
|
173
|
+
if ( ca->_pool ) {
|
|
174
|
+
ca_array_free(ca); /* dim lives in _pool */
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
xfree(ca->dim);
|
|
178
|
+
xfree(ca);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* ------------------------------------------------------------------- */
|
|
184
|
+
|
|
185
|
+
static void *
|
|
186
|
+
ca_const_string_func_clone (void *ap)
|
|
187
|
+
{
|
|
188
|
+
CAConstString *ca = (CAConstString *) ap;
|
|
189
|
+
/* buffer is immutable → sharing the same VALUE reference is safe + cheap
|
|
190
|
+
(Invariant 7, MEMO §3). */
|
|
191
|
+
return ca_const_string_new(ca->parent, ca->buffer, ca->encoding_id);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
static void
|
|
195
|
+
ca_const_string_func_allocate (void *ap)
|
|
196
|
+
{
|
|
197
|
+
CAConstString *ca = (CAConstString *) ap;
|
|
198
|
+
/* alias: parent attach + alias parent->ptr (Face has identical layout) */
|
|
199
|
+
ca_attach(ca->parent);
|
|
200
|
+
ca->ptr = ca->parent->ptr;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
static void
|
|
204
|
+
ca_const_string_func_create_mask (void *ap)
|
|
205
|
+
{
|
|
206
|
+
CAConstString *ca = (CAConstString *) ap;
|
|
207
|
+
ca_update_mask(ca->parent);
|
|
208
|
+
if ( ! ca->parent->mask ) {
|
|
209
|
+
ca_create_mask(ca->parent);
|
|
210
|
+
}
|
|
211
|
+
ca->mask = (CArray *) ca_refer_new(ca->parent->mask,
|
|
212
|
+
CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
ca_operation_function_t ca_const_string_func = {
|
|
216
|
+
-1, /* CA_OBJ_CONST_STRING — filled by ca_install_obj_type */
|
|
217
|
+
CA_VIEW_ARRAY,
|
|
218
|
+
free_ca_text,
|
|
219
|
+
ca_const_string_func_clone,
|
|
220
|
+
ca_const_string_func_allocate,
|
|
221
|
+
ca_face_attach,
|
|
222
|
+
ca_face_sync,
|
|
223
|
+
ca_face_detach,
|
|
224
|
+
ca_face_fill_data,
|
|
225
|
+
ca_const_string_func_create_mask,
|
|
226
|
+
ca_face_xfer_index,
|
|
227
|
+
ca_face_xfer_addrs,
|
|
228
|
+
NULL, /* fold_stride: identity Face is not foldable */
|
|
229
|
+
ca_face_xfer_stride,
|
|
230
|
+
ca_face_xfer_all
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
/* ------------------------------------------------------------------- */
|
|
234
|
+
|
|
235
|
+
/* decode one record from the buffer given its [start,end) byte range →
|
|
236
|
+
frozen String. buffer layout: pure concatenation (Arrow values layout),
|
|
237
|
+
length = end - start. encoding from ca->encoding_id. */
|
|
238
|
+
static VALUE
|
|
239
|
+
ca_const_string_decode (CAConstString *ca, int64_t start, int64_t end)
|
|
240
|
+
{
|
|
241
|
+
const char *buf = RSTRING_PTR(ca->buffer);
|
|
242
|
+
long buflen = RSTRING_LEN(ca->buffer);
|
|
243
|
+
int64_t len = end - start;
|
|
244
|
+
VALUE s;
|
|
245
|
+
|
|
246
|
+
if ( start < 0 || len < 0 || end > (int64_t) buflen ) {
|
|
247
|
+
rb_raise(rb_eIndexError,
|
|
248
|
+
"CAConstString: record [%lld,%lld) out of buffer range (%ld bytes)",
|
|
249
|
+
(long long) start, (long long) end, buflen);
|
|
250
|
+
}
|
|
251
|
+
s = rb_enc_str_new(buf + start, (long) len,
|
|
252
|
+
rb_enc_from_index(ca->encoding_id));
|
|
253
|
+
return rb_str_freeze(s);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* storage_to_scalar in C (= skip rb_funcall on the per-cell fetch hot
|
|
257
|
+
path). Since the Face surface is CA_FIXLEN (16 bytes), fetch delivers a
|
|
258
|
+
16-byte raw String = the (start,end) int64 pair. Decode the buffer slice
|
|
259
|
+
→ frozen Ruby String (plain frozen String, no Scalar wrapper). */
|
|
260
|
+
static VALUE
|
|
261
|
+
rb_ca_const_string_storage_to_scalar (VALUE self, VALUE raw)
|
|
262
|
+
{
|
|
263
|
+
CAConstString *ca;
|
|
264
|
+
int64_t pair[2];
|
|
265
|
+
|
|
266
|
+
TypedData_Get_Struct(self, CAConstString, &catext_data_type, ca);
|
|
267
|
+
|
|
268
|
+
if ( TYPE(raw) != T_STRING || RSTRING_LEN(raw) != (long) sizeof(pair) ) {
|
|
269
|
+
rb_raise(rb_eArgError,
|
|
270
|
+
"CAConstString#storage_to_scalar: expected a %lu-byte (start,end) cell",
|
|
271
|
+
(unsigned long) sizeof(pair));
|
|
272
|
+
}
|
|
273
|
+
memcpy(pair, RSTRING_PTR(raw), sizeof(pair));
|
|
274
|
+
|
|
275
|
+
return ca_const_string_decode(ca, pair[0], pair[1]);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* ------------------------------------------------------------------- */
|
|
279
|
+
|
|
280
|
+
/* CAConstString.wrap(int64_offsets, buffer:, encoding:) — low-level Face wrap of an
|
|
281
|
+
existing fixlen-16 (start,end) pair entity + pure-concatenation buffer. */
|
|
282
|
+
static VALUE
|
|
283
|
+
rb_ca_const_string_wrap (VALUE parent_val, VALUE buffer, int encoding_id)
|
|
284
|
+
{
|
|
285
|
+
CArray *parent;
|
|
286
|
+
CAConstString *ca;
|
|
287
|
+
VALUE obj;
|
|
288
|
+
|
|
289
|
+
TypedData_Get_Struct(parent_val, CArray, &carray_data_type, parent);
|
|
290
|
+
if ( parent->data_type != CA_FIXLEN || parent->bytes != 2 * (ca_size_t) sizeof(int64_t) ) {
|
|
291
|
+
rb_raise(rb_eTypeError,
|
|
292
|
+
"CAConstString.wrap requires a fixlen-16 (start,end) pair entity "
|
|
293
|
+
"(got data_type=%d, bytes=%ld)",
|
|
294
|
+
parent->data_type, (long) parent->bytes);
|
|
295
|
+
}
|
|
296
|
+
if ( TYPE(buffer) != T_STRING ) {
|
|
297
|
+
rb_raise(rb_eTypeError, "CAConstString.wrap: buffer: must be a String");
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
ca = ca_const_string_new(parent, rb_str_freeze(buffer), encoding_id);
|
|
301
|
+
obj = TypedData_Wrap_Struct(rb_cCAConstString, &catext_data_type, ca);
|
|
302
|
+
rb_ca_set_parent(obj, parent_val); /* pin parent VALUE for GC */
|
|
303
|
+
return obj;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
static VALUE
|
|
307
|
+
rb_ca_const_string_wrap_method (int argc, VALUE *argv, VALUE klass)
|
|
308
|
+
{
|
|
309
|
+
VALUE parent_val, ropt, rbuffer = Qnil, renc = Qnil;
|
|
310
|
+
int encoding_id;
|
|
311
|
+
|
|
312
|
+
rb_scan_args(argc, argv, "1:", &parent_val, &ropt);
|
|
313
|
+
rb_scan_options(ropt, "buffer,encoding", &rbuffer, &renc);
|
|
314
|
+
if ( NIL_P(rbuffer) ) {
|
|
315
|
+
rb_raise(rb_eArgError, "CAConstString.wrap: buffer: keyword is required");
|
|
316
|
+
}
|
|
317
|
+
encoding_id = NIL_P(renc) ? rb_utf8_encindex()
|
|
318
|
+
: rb_to_encoding_index(renc);
|
|
319
|
+
|
|
320
|
+
return rb_ca_const_string_wrap(parent_val, rbuffer, encoding_id);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/* Build a CAConstString from a Ruby Array of Strings / nils in a single C
|
|
324
|
+
pass: pure-concatenation buffer (Arrow values layout) + fixlen-16
|
|
325
|
+
(start,end) pair entity, with a mask for nil elements. Replaces the
|
|
326
|
+
per-element Ruby build loop -- no `String#b` copy, no `pack`, no per-row
|
|
327
|
+
method dispatch. `renc` is the target Encoding (nil = UTF-8). */
|
|
328
|
+
static VALUE
|
|
329
|
+
rb_ca_const_string_build (VALUE klass, VALUE values, VALUE renc)
|
|
330
|
+
{
|
|
331
|
+
long i, n;
|
|
332
|
+
int encoding_id;
|
|
333
|
+
rb_encoding *enc;
|
|
334
|
+
volatile VALUE buffer, vpair;
|
|
335
|
+
CArray *pe;
|
|
336
|
+
int64_t *pair;
|
|
337
|
+
boolean8_t *mask = NULL;
|
|
338
|
+
ca_size_t dim[1];
|
|
339
|
+
long hint = 0;
|
|
340
|
+
|
|
341
|
+
Check_Type(values, T_ARRAY);
|
|
342
|
+
n = RARRAY_LEN(values);
|
|
343
|
+
encoding_id = NIL_P(renc) ? rb_utf8_encindex() : rb_to_encoding_index(renc);
|
|
344
|
+
enc = rb_enc_from_index(encoding_id);
|
|
345
|
+
|
|
346
|
+
/* size hint: sum String lengths cheaply (skip non-String coercion here) */
|
|
347
|
+
for ( i = 0; i < n; i++ ) {
|
|
348
|
+
VALUE s = RARRAY_AREF(values, i);
|
|
349
|
+
if ( RB_TYPE_P(s, T_STRING) ) hint += RSTRING_LEN(s);
|
|
350
|
+
}
|
|
351
|
+
buffer = rb_str_buf_new(hint);
|
|
352
|
+
rb_enc_associate_index(buffer, rb_ascii8bit_encindex());
|
|
353
|
+
|
|
354
|
+
dim[0] = (ca_size_t) n;
|
|
355
|
+
vpair = rb_carray_new(CA_FIXLEN, 1, dim, 2 * sizeof(int64_t), NULL);
|
|
356
|
+
TypedData_Get_Struct(vpair, CArray, &carray_data_type, pe);
|
|
357
|
+
pair = (int64_t *) pe->ptr;
|
|
358
|
+
|
|
359
|
+
for ( i = 0; i < n; i++ ) {
|
|
360
|
+
VALUE s = RARRAY_AREF(values, i);
|
|
361
|
+
if ( NIL_P(s) ) {
|
|
362
|
+
if ( ! mask ) {
|
|
363
|
+
ca_create_mask(pe);
|
|
364
|
+
mask = (boolean8_t *) pe->mask->ptr;
|
|
365
|
+
}
|
|
366
|
+
mask[i] = 1;
|
|
367
|
+
pair[2 * i] = 0;
|
|
368
|
+
pair[2 * i + 1] = 0;
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if ( ! RB_TYPE_P(s, T_STRING) ) {
|
|
372
|
+
s = rb_obj_as_string(s); /* to_s */
|
|
373
|
+
}
|
|
374
|
+
/* encoding gate: match the column encoding, or pure-ASCII passes through */
|
|
375
|
+
if ( rb_enc_get_index(s) != encoding_id && ! rb_enc_str_asciionly_p(s) ) {
|
|
376
|
+
rb_raise(rb_eArgError,
|
|
377
|
+
"CArray.const_string: element encoding %s does not match column "
|
|
378
|
+
"encoding %s (use String#encode to convert explicitly)",
|
|
379
|
+
rb_enc_name(rb_enc_get(s)), rb_enc_name(enc));
|
|
380
|
+
}
|
|
381
|
+
pair[2 * i] = (int64_t) RSTRING_LEN(buffer);
|
|
382
|
+
rb_str_cat(buffer, RSTRING_PTR(s), RSTRING_LEN(s));
|
|
383
|
+
pair[2 * i + 1] = (int64_t) RSTRING_LEN(buffer);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return rb_ca_const_string_wrap(vpair, rb_str_freeze(buffer), encoding_id);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* CAConstString#encoding → Encoding */
|
|
390
|
+
static VALUE
|
|
391
|
+
rb_ca_const_string_encoding (VALUE self)
|
|
392
|
+
{
|
|
393
|
+
CAConstString *ca;
|
|
394
|
+
TypedData_Get_Struct(self, CAConstString, &catext_data_type, ca);
|
|
395
|
+
return rb_enc_from_encoding(rb_enc_from_index(ca->encoding_id));
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/* `CAConstString#buffer` — returns the frozen internal byte buffer
|
|
399
|
+
(length-prefix format). Exposes the defining tail state for
|
|
400
|
+
introspection and the Arrow-boundary component-buffer export
|
|
401
|
+
path. */
|
|
402
|
+
static VALUE
|
|
403
|
+
rb_ca_const_string_buffer (VALUE self)
|
|
404
|
+
{
|
|
405
|
+
CAConstString *ca;
|
|
406
|
+
TypedData_Get_Struct(self, CAConstString, &catext_data_type, ca);
|
|
407
|
+
return ca->buffer;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/* ------------------------------------------------------------------- */
|
|
411
|
+
|
|
412
|
+
/* copy = compacting deep copy — the only chain-descent point in
|
|
413
|
+
CAConstString. Produces a standalone CAConstString:
|
|
414
|
+
- a fresh contiguous fixlen-16 (start,end) pair entity
|
|
415
|
+
- a fresh compacted buffer, each element's bytes repacked once in the
|
|
416
|
+
view's logical order (pure concatenation = Arrow values layout)
|
|
417
|
+
- encoding preserved, mask carried
|
|
418
|
+
- fully detached from the original buffer / pair-source
|
|
419
|
+
Cost is O(live bytes); a near-full copy is a near-full rebuild (accepted).
|
|
420
|
+
Done at the byte level (no per-element Ruby String boxing). */
|
|
421
|
+
static VALUE
|
|
422
|
+
rb_ca_const_string_copy (VALUE self)
|
|
423
|
+
{
|
|
424
|
+
volatile VALUE vout, newbuf;
|
|
425
|
+
CAConstString *ca;
|
|
426
|
+
CArray *co;
|
|
427
|
+
ca_size_t i, n;
|
|
428
|
+
int64_t *src_pair, *dst_pair;
|
|
429
|
+
boolean8_t *m = NULL;
|
|
430
|
+
const char *oldbuf;
|
|
431
|
+
long oldbuflen;
|
|
432
|
+
|
|
433
|
+
TypedData_Get_Struct(self, CAConstString, &catext_data_type, ca);
|
|
434
|
+
|
|
435
|
+
/* materialize logical-order (start,end) pairs + mask */
|
|
436
|
+
ca_attach((CArray *) ca);
|
|
437
|
+
ca_update_mask((CArray *) ca);
|
|
438
|
+
|
|
439
|
+
n = ca->elements;
|
|
440
|
+
src_pair = (int64_t *) ca->ptr;
|
|
441
|
+
m = ca->mask ? (boolean8_t *) ca->mask->ptr : NULL;
|
|
442
|
+
oldbuf = RSTRING_PTR(ca->buffer);
|
|
443
|
+
oldbuflen = RSTRING_LEN(ca->buffer);
|
|
444
|
+
|
|
445
|
+
/* fresh fixlen-16 pair entity, same shape (N-D preserved) */
|
|
446
|
+
vout = rb_carray_new(CA_FIXLEN, ca->ndim, ca->dim, 2 * sizeof(int64_t), NULL);
|
|
447
|
+
TypedData_Get_Struct(vout, CArray, &carray_data_type, co);
|
|
448
|
+
dst_pair = (int64_t *) co->ptr;
|
|
449
|
+
|
|
450
|
+
/* growable compacted buffer (BINARY) */
|
|
451
|
+
newbuf = rb_str_buf_new(oldbuflen);
|
|
452
|
+
rb_enc_associate_index(newbuf, rb_ascii8bit_encindex());
|
|
453
|
+
|
|
454
|
+
for ( i = 0; i < n; i++ ) {
|
|
455
|
+
int64_t start, end, len;
|
|
456
|
+
if ( m && m[i] ) {
|
|
457
|
+
dst_pair[2 * i] = 0;
|
|
458
|
+
dst_pair[2 * i + 1] = 0;
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
start = src_pair[2 * i];
|
|
462
|
+
end = src_pair[2 * i + 1];
|
|
463
|
+
len = end - start;
|
|
464
|
+
if ( start < 0 || len < 0 || end > (int64_t) oldbuflen ) {
|
|
465
|
+
ca_detach((CArray *) ca);
|
|
466
|
+
rb_raise(rb_eIndexError,
|
|
467
|
+
"CAConstString#copy: record [%lld,%lld) out of buffer range",
|
|
468
|
+
(long long) start, (long long) end);
|
|
469
|
+
}
|
|
470
|
+
dst_pair[2 * i] = (int64_t) RSTRING_LEN(newbuf);
|
|
471
|
+
rb_str_cat(newbuf, oldbuf + start, (long) len);
|
|
472
|
+
dst_pair[2 * i + 1] = (int64_t) RSTRING_LEN(newbuf);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/* carry mask onto the new pair entity */
|
|
476
|
+
if ( m ) {
|
|
477
|
+
boolean8_t *nm;
|
|
478
|
+
ca_create_mask(co);
|
|
479
|
+
nm = (boolean8_t *) co->mask->ptr;
|
|
480
|
+
for ( i = 0; i < n; i++ ) {
|
|
481
|
+
nm[i] = m[i] ? 1 : 0;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
ca_detach((CArray *) ca);
|
|
486
|
+
|
|
487
|
+
return rb_ca_const_string_wrap(vout, rb_str_freeze(newbuf), ca->encoding_id);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/* to_ca descends to the same compacting copy. The result is detached
|
|
491
|
+
from the source buffer by construction, so `writable: true` — a demand
|
|
492
|
+
that writes reach the source — cannot be honoured and is refused. */
|
|
493
|
+
static VALUE
|
|
494
|
+
rb_ca_const_string_to_ca (int argc, VALUE *argv, VALUE self)
|
|
495
|
+
{
|
|
496
|
+
if ( ca_to_ca_writable_arg(argc, argv) ) {
|
|
497
|
+
ca_to_ca_refuse_writable(self);
|
|
498
|
+
}
|
|
499
|
+
return rb_ca_const_string_copy(self);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/* ------------------------------------------------------------------- */
|
|
503
|
+
/* Native byte ops: compare / scan record bytes straight out of the
|
|
504
|
+
buffer, without materializing a Ruby String per element. This is
|
|
505
|
+
the layer where CAConstString outperforms `to_object` followed by
|
|
506
|
+
per-cell Ruby String work. */
|
|
507
|
+
|
|
508
|
+
typedef struct {
|
|
509
|
+
CAConstString *ca;
|
|
510
|
+
int64_t *off;
|
|
511
|
+
boolean8_t *m;
|
|
512
|
+
const char *buf;
|
|
513
|
+
long buflen;
|
|
514
|
+
ca_size_t n;
|
|
515
|
+
} ca_const_string_scan_t;
|
|
516
|
+
|
|
517
|
+
static void
|
|
518
|
+
ca_const_string_scan_begin (VALUE self, ca_const_string_scan_t *s)
|
|
519
|
+
{
|
|
520
|
+
TypedData_Get_Struct(self, CAConstString, &catext_data_type, s->ca);
|
|
521
|
+
ca_attach((CArray *) s->ca);
|
|
522
|
+
ca_update_mask((CArray *) s->ca);
|
|
523
|
+
s->off = (int64_t *) s->ca->ptr;
|
|
524
|
+
s->m = s->ca->mask ? (boolean8_t *) s->ca->mask->ptr : NULL;
|
|
525
|
+
s->buf = RSTRING_PTR(s->ca->buffer);
|
|
526
|
+
s->buflen = RSTRING_LEN(s->ca->buffer);
|
|
527
|
+
s->n = s->ca->elements;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
static void
|
|
531
|
+
ca_const_string_scan_end (ca_const_string_scan_t *s)
|
|
532
|
+
{
|
|
533
|
+
ca_detach((CArray *) s->ca);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/* Resolve element i to its record bytes; returns 0 if masked.
|
|
537
|
+
Storage is (start,end) int64 pairs: s->off holds 2 int64 per element,
|
|
538
|
+
so element i occupies s->off[2*i] (start) .. s->off[2*i+1] (end).
|
|
539
|
+
The buffer is a pure concatenation; length = end - start. */
|
|
540
|
+
static inline int
|
|
541
|
+
ca_const_string_record (ca_const_string_scan_t *s, ca_size_t i, const char **pp, int32_t *plen)
|
|
542
|
+
{
|
|
543
|
+
int64_t start, end;
|
|
544
|
+
if ( s->m && s->m[i] ) {
|
|
545
|
+
return 0;
|
|
546
|
+
}
|
|
547
|
+
start = s->off[2 * i];
|
|
548
|
+
end = s->off[2 * i + 1];
|
|
549
|
+
*pp = s->buf + start;
|
|
550
|
+
*plen = (int32_t) (end - start);
|
|
551
|
+
return 1;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/* Allocate a boolean output of the same shape; carry the input mask. */
|
|
555
|
+
static VALUE
|
|
556
|
+
ca_const_string_bool_out (ca_const_string_scan_t *s, boolean8_t **op)
|
|
557
|
+
{
|
|
558
|
+
VALUE vout;
|
|
559
|
+
CArray *co;
|
|
560
|
+
vout = rb_carray_new(CA_BOOLEAN, s->ca->ndim, s->ca->dim, 0, NULL);
|
|
561
|
+
TypedData_Get_Struct(vout, CArray, &carray_data_type, co);
|
|
562
|
+
*op = (boolean8_t *) co->ptr;
|
|
563
|
+
if ( s->m ) {
|
|
564
|
+
ca_size_t i;
|
|
565
|
+
boolean8_t *nm;
|
|
566
|
+
ca_create_mask(co);
|
|
567
|
+
nm = (boolean8_t *) co->mask->ptr;
|
|
568
|
+
for ( i = 0; i < s->n; i++ ) {
|
|
569
|
+
nm[i] = s->m[i] ? 1 : 0;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return vout;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/* memmem fallback (not in all libc). */
|
|
576
|
+
static const char *
|
|
577
|
+
ca_const_string_memmem (const char *hay, long hlen, const char *need, long nlen)
|
|
578
|
+
{
|
|
579
|
+
long i;
|
|
580
|
+
if ( nlen == 0 ) return hay;
|
|
581
|
+
if ( nlen > hlen ) return NULL;
|
|
582
|
+
for ( i = 0; i <= hlen - nlen; i++ ) {
|
|
583
|
+
if ( hay[i] == need[0] && memcmp(hay + i, need, nlen) == 0 ) {
|
|
584
|
+
return hay + i;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return NULL;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* CAConstString#byte_length → int64 CArray of per-element byte lengths. */
|
|
591
|
+
static VALUE
|
|
592
|
+
rb_ca_const_string_byte_length (VALUE self)
|
|
593
|
+
{
|
|
594
|
+
ca_const_string_scan_t s;
|
|
595
|
+
VALUE vout;
|
|
596
|
+
CArray *co;
|
|
597
|
+
int64_t *op;
|
|
598
|
+
const char *p;
|
|
599
|
+
int32_t len;
|
|
600
|
+
ca_size_t i;
|
|
601
|
+
|
|
602
|
+
ca_const_string_scan_begin(self, &s);
|
|
603
|
+
vout = rb_carray_new(CA_INT64, s.ca->ndim, s.ca->dim, 0, NULL);
|
|
604
|
+
TypedData_Get_Struct(vout, CArray, &carray_data_type, co);
|
|
605
|
+
op = (int64_t *) co->ptr;
|
|
606
|
+
for ( i = 0; i < s.n; i++ ) {
|
|
607
|
+
op[i] = ca_const_string_record(&s, i, &p, &len) ? (int64_t) len : 0;
|
|
608
|
+
}
|
|
609
|
+
if ( s.m ) {
|
|
610
|
+
boolean8_t *nm;
|
|
611
|
+
ca_create_mask(co);
|
|
612
|
+
nm = (boolean8_t *) co->mask->ptr;
|
|
613
|
+
for ( i = 0; i < s.n; i++ ) {
|
|
614
|
+
nm[i] = s.m[i] ? 1 : 0;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
ca_const_string_scan_end(&s);
|
|
618
|
+
return vout;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/* op codes for the shared predicate scan. */
|
|
622
|
+
enum { CA_TEXT_EQ, CA_TEXT_START, CA_TEXT_END, CA_TEXT_INCLUDE };
|
|
623
|
+
|
|
624
|
+
/* CAConstString#eq / start_with? / end_with? / include? — boolean mask vs a scalar
|
|
625
|
+
String query, byte-native. */
|
|
626
|
+
static VALUE
|
|
627
|
+
ca_const_string_predicate (VALUE self, VALUE query, int op)
|
|
628
|
+
{
|
|
629
|
+
ca_const_string_scan_t s;
|
|
630
|
+
VALUE vout;
|
|
631
|
+
boolean8_t *out;
|
|
632
|
+
const char *qp, *p;
|
|
633
|
+
long qlen;
|
|
634
|
+
int32_t len;
|
|
635
|
+
ca_size_t i;
|
|
636
|
+
|
|
637
|
+
if ( TYPE(query) != T_STRING ) {
|
|
638
|
+
query = rb_obj_as_string(query);
|
|
639
|
+
}
|
|
640
|
+
qp = RSTRING_PTR(query);
|
|
641
|
+
qlen = RSTRING_LEN(query);
|
|
642
|
+
|
|
643
|
+
ca_const_string_scan_begin(self, &s);
|
|
644
|
+
vout = ca_const_string_bool_out(&s, &out);
|
|
645
|
+
|
|
646
|
+
for ( i = 0; i < s.n; i++ ) {
|
|
647
|
+
boolean8_t r = 0;
|
|
648
|
+
if ( ca_const_string_record(&s, i, &p, &len) ) {
|
|
649
|
+
switch ( op ) {
|
|
650
|
+
case CA_TEXT_EQ:
|
|
651
|
+
r = ( len == qlen && memcmp(p, qp, qlen) == 0 );
|
|
652
|
+
break;
|
|
653
|
+
case CA_TEXT_START:
|
|
654
|
+
r = ( len >= qlen && memcmp(p, qp, qlen) == 0 );
|
|
655
|
+
break;
|
|
656
|
+
case CA_TEXT_END:
|
|
657
|
+
r = ( len >= qlen && memcmp(p + len - qlen, qp, qlen) == 0 );
|
|
658
|
+
break;
|
|
659
|
+
case CA_TEXT_INCLUDE:
|
|
660
|
+
r = ( ca_const_string_memmem(p, len, qp, qlen) != NULL );
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
out[i] = r;
|
|
665
|
+
}
|
|
666
|
+
ca_const_string_scan_end(&s);
|
|
667
|
+
return vout;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
static VALUE rb_ca_const_string_start_with (VALUE self, VALUE q) { return ca_const_string_predicate(self, q, CA_TEXT_START); }
|
|
671
|
+
static VALUE rb_ca_const_string_end_with (VALUE self, VALUE q) { return ca_const_string_predicate(self, q, CA_TEXT_END); }
|
|
672
|
+
static VALUE rb_ca_const_string_include (VALUE self, VALUE q) { return ca_const_string_predicate(self, q, CA_TEXT_INCLUDE); }
|
|
673
|
+
|
|
674
|
+
/* CAConstString#eq(value): value is a scalar String (broadcast) or a CAConstString
|
|
675
|
+
(element-wise). Returns a boolean CArray. */
|
|
676
|
+
static VALUE
|
|
677
|
+
rb_ca_const_string_eq (VALUE self, VALUE other)
|
|
678
|
+
{
|
|
679
|
+
if ( rb_obj_is_kind_of(other, rb_cCAConstString) ) {
|
|
680
|
+
ca_const_string_scan_t a, b;
|
|
681
|
+
VALUE vout;
|
|
682
|
+
boolean8_t *out;
|
|
683
|
+
/* record() leaves these unset for masked cells; short-circuit eval means
|
|
684
|
+
they are read only when both records are valid, but GCC cannot prove
|
|
685
|
+
that -- initialize to keep -Wmaybe-uninitialized quiet and defensive. */
|
|
686
|
+
const char *pa = NULL, *pb = NULL;
|
|
687
|
+
int32_t la = 0, lb = 0;
|
|
688
|
+
ca_size_t i;
|
|
689
|
+
|
|
690
|
+
ca_const_string_scan_begin(self, &a);
|
|
691
|
+
ca_const_string_scan_begin(other, &b);
|
|
692
|
+
if ( a.n != b.n ) {
|
|
693
|
+
ca_const_string_scan_end(&a);
|
|
694
|
+
ca_const_string_scan_end(&b);
|
|
695
|
+
rb_raise(rb_eArgError, "CAConstString#eq: element count mismatch (%lld vs %lld)",
|
|
696
|
+
(long long) a.n, (long long) b.n);
|
|
697
|
+
}
|
|
698
|
+
vout = ca_const_string_bool_out(&a, &out); /* mask carried from self */
|
|
699
|
+
for ( i = 0; i < a.n; i++ ) {
|
|
700
|
+
int va = ca_const_string_record(&a, i, &pa, &la);
|
|
701
|
+
int vb = ca_const_string_record(&b, i, &pb, &lb);
|
|
702
|
+
out[i] = ( va && vb && la == lb && memcmp(pa, pb, la) == 0 );
|
|
703
|
+
}
|
|
704
|
+
ca_const_string_scan_end(&a);
|
|
705
|
+
ca_const_string_scan_end(&b);
|
|
706
|
+
return vout;
|
|
707
|
+
}
|
|
708
|
+
return ca_const_string_predicate(self, other, CA_TEXT_EQ);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/* CAConstString#count(value): number of (non-masked) elements byte-equal to value. */
|
|
712
|
+
static VALUE
|
|
713
|
+
rb_ca_const_string_count (VALUE self, VALUE query)
|
|
714
|
+
{
|
|
715
|
+
ca_const_string_scan_t s;
|
|
716
|
+
const char *qp, *p;
|
|
717
|
+
long qlen;
|
|
718
|
+
int32_t len;
|
|
719
|
+
ca_size_t i, c = 0;
|
|
720
|
+
|
|
721
|
+
if ( TYPE(query) != T_STRING ) {
|
|
722
|
+
query = rb_obj_as_string(query);
|
|
723
|
+
}
|
|
724
|
+
qp = RSTRING_PTR(query);
|
|
725
|
+
qlen = RSTRING_LEN(query);
|
|
726
|
+
|
|
727
|
+
ca_const_string_scan_begin(self, &s);
|
|
728
|
+
for ( i = 0; i < s.n; i++ ) {
|
|
729
|
+
if ( ca_const_string_record(&s, i, &p, &len) && len == qlen && memcmp(p, qp, qlen) == 0 ) {
|
|
730
|
+
c++;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
ca_const_string_scan_end(&s);
|
|
734
|
+
return SIZET2NUM(c);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/* CAConstString#search(query) / #find_value_index(query): flat index of the
|
|
738
|
+
first (non-masked) element byte-equal to query, or nil when none matches.
|
|
739
|
+
The numeric/fixlen search kernels cannot run here (storage is the int64
|
|
740
|
+
offset entity, not the string content), so this is a native memcmp scan --
|
|
741
|
+
the exact-lookup counterpart of the native sort / min / max below. */
|
|
742
|
+
static VALUE
|
|
743
|
+
rb_ca_const_string_search (VALUE self, VALUE query)
|
|
744
|
+
{
|
|
745
|
+
ca_const_string_scan_t s;
|
|
746
|
+
const char *qp, *p;
|
|
747
|
+
long qlen;
|
|
748
|
+
int32_t len;
|
|
749
|
+
ca_size_t i;
|
|
750
|
+
VALUE result = Qnil;
|
|
751
|
+
|
|
752
|
+
if ( TYPE(query) != T_STRING ) {
|
|
753
|
+
query = rb_obj_as_string(query);
|
|
754
|
+
}
|
|
755
|
+
qp = RSTRING_PTR(query);
|
|
756
|
+
qlen = RSTRING_LEN(query);
|
|
757
|
+
|
|
758
|
+
ca_const_string_scan_begin(self, &s);
|
|
759
|
+
for ( i = 0; i < s.n; i++ ) {
|
|
760
|
+
if ( ca_const_string_record(&s, i, &p, &len) && len == qlen && memcmp(p, qp, (size_t) qlen) == 0 ) {
|
|
761
|
+
result = SIZET2NUM(i);
|
|
762
|
+
break;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
ca_const_string_scan_end(&s);
|
|
766
|
+
return result;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/* ------------------------------------------------------------------- */
|
|
770
|
+
/* Native sort / min / max. Ruby `String#<=>` is a byte comparison
|
|
771
|
+
within the same encoding, so a byte-memcmp comparator is
|
|
772
|
+
byte-for-byte faithful to `to_object.sort` with no collation
|
|
773
|
+
loss. */
|
|
774
|
+
|
|
775
|
+
/* qsort comparator context — single-threaded under the GVL (thread-safety is
|
|
776
|
+
a non-goal; see project memory), so a file-static context is safe. */
|
|
777
|
+
static ca_const_string_scan_t *ca_const_string_sort_ctx;
|
|
778
|
+
|
|
779
|
+
static int
|
|
780
|
+
ca_const_string_byte_cmp (const void *a, const void *b)
|
|
781
|
+
{
|
|
782
|
+
ca_size_t ia = *(const ca_size_t *) a;
|
|
783
|
+
ca_size_t ib = *(const ca_size_t *) b;
|
|
784
|
+
/* sort raises on masked input, so record() always sets these here; the
|
|
785
|
+
initializers keep -Wmaybe-uninitialized quiet and stay defensive. */
|
|
786
|
+
const char *pa = NULL, *pb = NULL;
|
|
787
|
+
int32_t la = 0, lb = 0;
|
|
788
|
+
int c;
|
|
789
|
+
ca_const_string_record(ca_const_string_sort_ctx, ia, &pa, &la);
|
|
790
|
+
ca_const_string_record(ca_const_string_sort_ctx, ib, &pb, &lb);
|
|
791
|
+
c = memcmp(pa, pb, (size_t) (la < lb ? la : lb));
|
|
792
|
+
if ( c != 0 ) return c;
|
|
793
|
+
return (la > lb) - (la < lb);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/* compute the ascending sort permutation; raises on masked input (matches
|
|
797
|
+
base CArray#sort). caller xfree()s the returned index array. */
|
|
798
|
+
static ca_size_t *
|
|
799
|
+
ca_const_string_sort_perm (ca_const_string_scan_t *s)
|
|
800
|
+
{
|
|
801
|
+
ca_size_t *idx;
|
|
802
|
+
ca_size_t i;
|
|
803
|
+
if ( s->m ) {
|
|
804
|
+
ca_const_string_scan_end(s);
|
|
805
|
+
rb_raise(rb_eArgError, "CAConstString#sort: cannot sort an array with masked elements");
|
|
806
|
+
}
|
|
807
|
+
idx = ALLOC_N(ca_size_t, s->n);
|
|
808
|
+
for ( i = 0; i < s->n; i++ ) idx[i] = i;
|
|
809
|
+
ca_const_string_sort_ctx = s;
|
|
810
|
+
qsort(idx, (size_t) s->n, sizeof(ca_size_t), ca_const_string_byte_cmp);
|
|
811
|
+
ca_const_string_sort_ctx = NULL;
|
|
812
|
+
return idx;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/* CAConstString#sort_index → int64 CArray of the ascending sort permutation. */
|
|
816
|
+
static VALUE
|
|
817
|
+
rb_ca_const_string_sort_index (VALUE self)
|
|
818
|
+
{
|
|
819
|
+
ca_const_string_scan_t s;
|
|
820
|
+
ca_size_t *idx;
|
|
821
|
+
VALUE vout;
|
|
822
|
+
CArray *co;
|
|
823
|
+
int64_t *op;
|
|
824
|
+
ca_size_t i;
|
|
825
|
+
|
|
826
|
+
ca_const_string_scan_begin(self, &s);
|
|
827
|
+
idx = ca_const_string_sort_perm(&s);
|
|
828
|
+
vout = rb_carray_new(CA_INT64, s.ca->ndim, s.ca->dim, 0, NULL);
|
|
829
|
+
TypedData_Get_Struct(vout, CArray, &carray_data_type, co);
|
|
830
|
+
op = (int64_t *) co->ptr;
|
|
831
|
+
for ( i = 0; i < s.n; i++ ) op[i] = (int64_t) idx[i];
|
|
832
|
+
xfree(idx);
|
|
833
|
+
ca_const_string_scan_end(&s);
|
|
834
|
+
return vout;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/* CAConstString#sort is defined in Ruby (lib/carray/const_string.rb) as `self[sort_index]`,
|
|
838
|
+
i.e. a no-copy view over the offset source (buffer + offsets shared, only
|
|
839
|
+
the gather order changes) — consistent with CArray#sort being a view. */
|
|
840
|
+
|
|
841
|
+
/* CAConstString#min / #max → the byte-min / byte-max element as a frozen String,
|
|
842
|
+
skipping masked elements; nil if empty or all masked. */
|
|
843
|
+
static VALUE
|
|
844
|
+
ca_const_string_extremum (VALUE self, int want_max)
|
|
845
|
+
{
|
|
846
|
+
ca_const_string_scan_t s;
|
|
847
|
+
const char *p, *bestp = NULL;
|
|
848
|
+
int32_t len, bestlen = 0;
|
|
849
|
+
ca_size_t i;
|
|
850
|
+
int found = 0;
|
|
851
|
+
|
|
852
|
+
ca_const_string_scan_begin(self, &s);
|
|
853
|
+
for ( i = 0; i < s.n; i++ ) {
|
|
854
|
+
int c;
|
|
855
|
+
if ( ! ca_const_string_record(&s, i, &p, &len) ) continue;
|
|
856
|
+
if ( ! found ) {
|
|
857
|
+
bestp = p; bestlen = len; found = 1;
|
|
858
|
+
continue;
|
|
859
|
+
}
|
|
860
|
+
c = memcmp(p, bestp, (size_t) (len < bestlen ? len : bestlen));
|
|
861
|
+
if ( c == 0 ) c = (len > bestlen) - (len < bestlen);
|
|
862
|
+
if ( ( want_max && c > 0 ) || ( ! want_max && c < 0 ) ) {
|
|
863
|
+
bestp = p; bestlen = len;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
if ( ! found ) {
|
|
867
|
+
ca_const_string_scan_end(&s);
|
|
868
|
+
return Qnil;
|
|
869
|
+
}
|
|
870
|
+
{
|
|
871
|
+
VALUE str = rb_enc_str_new(bestp, bestlen, rb_enc_from_index(s.ca->encoding_id));
|
|
872
|
+
ca_const_string_scan_end(&s);
|
|
873
|
+
return rb_str_freeze(str);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
static VALUE rb_ca_const_string_min (VALUE self) { return ca_const_string_extremum(self, 0); }
|
|
878
|
+
static VALUE rb_ca_const_string_max (VALUE self) { return ca_const_string_extremum(self, 1); }
|
|
879
|
+
|
|
880
|
+
/* ------------------------------------------------------------------- */
|
|
881
|
+
|
|
882
|
+
static VALUE
|
|
883
|
+
rb_ca_const_string_s_allocate (VALUE klass)
|
|
884
|
+
{
|
|
885
|
+
CAConstString *ca;
|
|
886
|
+
return TypedData_Make_Struct(klass, CAConstString, &catext_data_type, ca);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
static VALUE
|
|
890
|
+
rb_ca_const_string_initialize_copy (VALUE self, VALUE other)
|
|
891
|
+
{
|
|
892
|
+
CAConstString *ca, *cs;
|
|
893
|
+
TypedData_Get_Struct(self, CAConstString, &catext_data_type, ca);
|
|
894
|
+
TypedData_Get_Struct(other, CAConstString, &catext_data_type, cs);
|
|
895
|
+
/* T.0/T.1: shallow re-setup (shares buffer + offset-source). T.3 will
|
|
896
|
+
replace this with compacting deep copy (rebased offsets + compacted
|
|
897
|
+
buffer + detach). */
|
|
898
|
+
if ( ca_func[CA_OBJ_CONST_STRING].pool_init ) {
|
|
899
|
+
ca_array_pool_alloc(ca, CA_OBJ_CONST_STRING, cs->parent->ndim);
|
|
900
|
+
}
|
|
901
|
+
ca_const_string_setup(ca, cs->parent, cs->buffer, cs->encoding_id);
|
|
902
|
+
return self;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
void
|
|
906
|
+
Init_ca_obj_const_string (void)
|
|
907
|
+
{
|
|
908
|
+
rb_cCAConstString = rb_define_class("CAConstString", rb_cCAFace);
|
|
909
|
+
|
|
910
|
+
ca_const_string_func.struct_size = sizeof(CAConstString);
|
|
911
|
+
ca_const_string_func.pool_bytes = ca_const_string_pool_bytes;
|
|
912
|
+
ca_const_string_func.pool_init = ca_const_string_pool_init;
|
|
913
|
+
|
|
914
|
+
CA_OBJ_CONST_STRING = ca_install_obj_type(rb_cCAConstString,
|
|
915
|
+
&catext_data_type,
|
|
916
|
+
rb_cCArrayMask,
|
|
917
|
+
&carray_mask_data_type,
|
|
918
|
+
&ca_const_string_func, sizeof(ca_const_string_func));
|
|
919
|
+
rb_define_const(rb_cObject, "CA_OBJ_CONST_STRING", INT2NUM(CA_OBJ_CONST_STRING));
|
|
920
|
+
|
|
921
|
+
rb_define_alloc_func(rb_cCAConstString, rb_ca_const_string_s_allocate);
|
|
922
|
+
rb_define_method(rb_cCAConstString, "initialize_copy",
|
|
923
|
+
rb_ca_const_string_initialize_copy, 1);
|
|
924
|
+
|
|
925
|
+
rb_define_singleton_method(rb_cCAConstString, "wrap", rb_ca_const_string_wrap_method, -1);
|
|
926
|
+
rb_define_singleton_method(rb_cCAConstString, "__build__", rb_ca_const_string_build, 2);
|
|
927
|
+
rb_define_method(rb_cCAConstString, "encoding", rb_ca_const_string_encoding, 0);
|
|
928
|
+
rb_define_method(rb_cCAConstString, "buffer", rb_ca_const_string_buffer, 0);
|
|
929
|
+
rb_define_method(rb_cCAConstString, "storage_to_scalar",
|
|
930
|
+
rb_ca_const_string_storage_to_scalar, 1);
|
|
931
|
+
|
|
932
|
+
/* copy = compacting deep copy; to_ca is the same descent point. */
|
|
933
|
+
rb_define_method(rb_cCAConstString, "copy", rb_ca_const_string_copy, 0);
|
|
934
|
+
rb_define_method(rb_cCAConstString, "to_ca", rb_ca_const_string_to_ca, -1);
|
|
935
|
+
|
|
936
|
+
/* native byte ops (§3.7) */
|
|
937
|
+
rb_define_method(rb_cCAConstString, "byte_length", rb_ca_const_string_byte_length, 0);
|
|
938
|
+
rb_define_method(rb_cCAConstString, "eq", rb_ca_const_string_eq, 1);
|
|
939
|
+
rb_define_method(rb_cCAConstString, "count", rb_ca_const_string_count, 1);
|
|
940
|
+
rb_define_method(rb_cCAConstString, "start_with?", rb_ca_const_string_start_with, 1);
|
|
941
|
+
rb_define_method(rb_cCAConstString, "end_with?", rb_ca_const_string_end_with, 1);
|
|
942
|
+
rb_define_method(rb_cCAConstString, "include?", rb_ca_const_string_include, 1);
|
|
943
|
+
|
|
944
|
+
/* native exact-lookup search: flat index of the first byte-equal element,
|
|
945
|
+
or nil. `search` is what str_matches consumes; find_value_index is the
|
|
946
|
+
*_index-named surface (both exact, mask-skipping). */
|
|
947
|
+
rb_define_method(rb_cCAConstString, "search", rb_ca_const_string_search, 1);
|
|
948
|
+
rb_define_method(rb_cCAConstString, "find_value_index", rb_ca_const_string_search, 1);
|
|
949
|
+
|
|
950
|
+
/* native sort_index / min / max (§3.7), byte-memcmp comparator.
|
|
951
|
+
sort / sort_copy are defined in Ruby on top of sort_index. */
|
|
952
|
+
rb_define_method(rb_cCAConstString, "sort_index", rb_ca_const_string_sort_index, 0);
|
|
953
|
+
rb_define_method(rb_cCAConstString, "min", rb_ca_const_string_min, 0);
|
|
954
|
+
rb_define_method(rb_cCAConstString, "max", rb_ca_const_string_max, 0);
|
|
955
|
+
|
|
956
|
+
/* Y-pilot: Face-local C-level fast path for per-cell scalar fetch. */
|
|
957
|
+
ca_face_register_storage_to_scalar(CA_OBJ_CONST_STRING, rb_ca_const_string_storage_to_scalar);
|
|
958
|
+
|
|
959
|
+
/* F.S1: CAConstString's `buffer` field is per-parent (= each CAConstString holds its
|
|
960
|
+
own frozen byte String; cell offsets index into THIS instance's
|
|
961
|
+
buffer). Multi-parent CAStack lift cannot reuse list[0]'s buffer
|
|
962
|
+
without producing wrong reads for cells from other parents. Mark
|
|
963
|
+
as not-portable so CAStack rejects multi-parent CAConstString lift. */
|
|
964
|
+
ca_face_register_state_portable(CA_OBJ_CONST_STRING, 0);
|
|
965
|
+
}
|