carray 3.0.1 → 3.0.3
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 +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -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/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_sweep_engine.h
CHANGED
|
@@ -5,15 +5,14 @@
|
|
|
5
5
|
* Established in PROPOSAL_L0_AUTHOR_SURFACE L0.1 (2026-06-11). Extracts
|
|
6
6
|
* the xfer_all-aware lifecycle template previously duplicated 7-times in
|
|
7
7
|
* ext/carray_call_cfunc.c (= one body per arity 1..7) into a single shared
|
|
8
|
-
* helper
|
|
9
|
-
* family (L0.2a) and the WHOLE_BUFFER family (L0.2c).
|
|
8
|
+
* helper, also used by the chunked slab family (ca_call_cslab_*).
|
|
10
9
|
*
|
|
11
10
|
* Lifecycle template:
|
|
12
11
|
* (1) per-operand acquire
|
|
13
12
|
* OUTPUT (fsync=='1') -> ca_attach + use ca->ptr (sync on release)
|
|
14
13
|
* INPUT (fsync=='0') alias-able -> ca_attach + use ca->ptr
|
|
15
14
|
* INPUT (fsync=='0') non-alias -> xmalloc + ca_xfer_all(GET)
|
|
16
|
-
* (2)
|
|
15
|
+
* (2) operand pairing (scalar collapse; arrays must agree in shape)
|
|
17
16
|
* (3) mask OR across INPUT operands -> m0 (xmalloc, NULL if none)
|
|
18
17
|
* (4) mask propagate to OUTPUT operands (overwrite output->mask)
|
|
19
18
|
* (5) caller runs the per-cell loop using base[] + stride[]
|
|
@@ -64,15 +63,10 @@ typedef struct ca_sweep_state {
|
|
|
64
63
|
boolean8_t *m0;
|
|
65
64
|
ca_size_t n_kernel;
|
|
66
65
|
const char *src_label;
|
|
67
|
-
/* no_mask: if non-zero, ca_sweep_acquire raises when any INPUT operand has
|
|
68
|
-
* a mask. Used by the NO_MASK macro forms (CA_FOR_EACH_ELEMENT etc.) to
|
|
69
|
-
* implement Q3=(ii) runtime error policy. Default 0 (= masked INPUT OK,
|
|
70
|
-
* m0 built as usual). Caller sets before calling ca_sweep_acquire. */
|
|
71
|
-
int no_mask;
|
|
72
66
|
|
|
73
67
|
/* === chunked path fields (L0.1 chunk, PROPOSAL_L0_AUTHOR_SURFACE) === */
|
|
74
68
|
/* Used by ca_sweep_acquire_chunked / ca_sweep_next_chunk / ca_sweep_release_chunked
|
|
75
|
-
* (= the
|
|
69
|
+
* (= the chunked slab family, ca_call_cslab_*). Unused by the whole-materialise path
|
|
76
70
|
* (ca_sweep_acquire / ca_sweep_release) — cfunc and other whole-buffer callers
|
|
77
71
|
* leave these zero. */
|
|
78
72
|
char **base_orig; /* per-op original ptr (= ca->ptr for
|
|
@@ -84,14 +78,20 @@ typedef struct ca_sweep_state {
|
|
|
84
78
|
ca_size_t chunk_n_max; /* max chunk size from ca_chunk_compute_n */
|
|
85
79
|
ca_size_t inner; /* product of dims except outermost (= row
|
|
86
80
|
size in elements for outer-axis chunking) */
|
|
87
|
-
int chunked_state; /* 0=pre-init, 1=active, 2=done
|
|
81
|
+
int chunked_state; /* 0=pre-init, 1=active, 2=done,
|
|
82
|
+
3=aborted (a read raised; resources
|
|
83
|
+
already given back) */
|
|
88
84
|
boolean8_t *mask_scratch; /* chunk-sized staging for the per-chunk
|
|
89
85
|
mask OR; NULL when no INPUT is masked */
|
|
90
86
|
} ca_sweep_state_t;
|
|
91
87
|
|
|
92
|
-
/* Validate fsync length, acquire per-op
|
|
93
|
-
*
|
|
94
|
-
* length
|
|
88
|
+
/* Validate fsync length, pair the operands (shape), acquire per-op
|
|
89
|
+
* buffers, build mask m0, propagate mask to OUTPUTs. May raise: refusals
|
|
90
|
+
* (fsync length, shape mismatch) before
|
|
91
|
+
* anything is held, and a raising operand read after -- in which case
|
|
92
|
+
* everything acquired so far is detached / freed before the raise
|
|
93
|
+
* propagates, so the caller must not call release. The chunked path
|
|
94
|
+
* does the same for acquire_chunked and each ca_sweep_next_chunk. */
|
|
95
95
|
void ca_sweep_acquire (ca_sweep_state_t *st);
|
|
96
96
|
|
|
97
97
|
/* Reverse-order release: sync OUTPUTs, detach attached / xfree owned_buf,
|
|
@@ -99,13 +99,22 @@ void ca_sweep_acquire (ca_sweep_state_t *st);
|
|
|
99
99
|
* state without re-initializing the caller-owned arrays. */
|
|
100
100
|
void ca_sweep_release (ca_sweep_state_t *st);
|
|
101
101
|
|
|
102
|
-
/*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
/* Run walk(arg) -- the caller's loop over the acquired state -- and then
|
|
103
|
+
* release. If walk raises (a callback refusing a value), everything the
|
|
104
|
+
* engine holds is detached / freed without syncing before the raise
|
|
105
|
+
* propagates. Use in place of calling ca_sweep_release /
|
|
106
|
+
* ca_sweep_release_chunked yourself whenever the loop can raise. The
|
|
107
|
+
* chunked walk calls ca_sweep_next_chunk itself. */
|
|
108
|
+
void ca_sweep_run (ca_sweep_state_t *st, VALUE (*walk)(VALUE), VALUE arg);
|
|
109
|
+
void ca_sweep_run_chunked (ca_sweep_state_t *st, VALUE (*walk)(VALUE), VALUE arg);
|
|
107
110
|
|
|
108
|
-
/*
|
|
111
|
+
/* Shape pairing shared with rb_ca_template_n: non-zero when a and b have
|
|
112
|
+
* the same ndim and dims; the refusal raises ArgumentError naming both
|
|
113
|
+
* shapes. */
|
|
114
|
+
int ca_sweep_same_shape (CArray *a, CArray *b);
|
|
115
|
+
NORETURN(void ca_sweep_refuse_shapes (CArray *a, CArray *b));
|
|
116
|
+
|
|
117
|
+
/* ===== Chunked path API (ca_call_cslab_*) =====
|
|
109
118
|
*
|
|
110
119
|
* Unlike ca_sweep_acquire / ca_sweep_release (= whole-buffer materialise used
|
|
111
120
|
* by cfunc), the chunked path keeps INPUT memory peak bounded to chunk
|
|
@@ -113,7 +122,7 @@ void ca_sweep_check_same_shape (CArray *ca_in, CArray *ca_out,
|
|
|
113
122
|
* memory peak guarantee: shrinking views materialise into chunk scratch
|
|
114
123
|
* sized to inner-axis multiples, not full operand size.
|
|
115
124
|
*
|
|
116
|
-
* Usage shape
|
|
125
|
+
* Usage shape:
|
|
117
126
|
* ca_sweep_acquire_chunked(&st);
|
|
118
127
|
* while (ca_sweep_next_chunk(&st)) {
|
|
119
128
|
* for (k = 0; k < st.chunk_n; k++) {
|
|
@@ -141,9 +150,8 @@ void ca_sweep_check_same_shape (CArray *ca_in, CArray *ca_out,
|
|
|
141
150
|
* indexed within the chunk, NOT by the flat cell index. (This differs
|
|
142
151
|
* from the whole-buffer path, where m0 spans n_kernel.)
|
|
143
152
|
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* masks when the chunk finishes -- at the top of the following
|
|
153
|
+
* The chunk's m0 is flushed into the OUTPUT operands' masks when the
|
|
154
|
+
* chunk finishes -- at the top of the following
|
|
147
155
|
* ca_sweep_next_chunk, and once more in ca_sweep_release_chunked for
|
|
148
156
|
* the last chunk -- so the OUTPUT masks are created up front in
|
|
149
157
|
* acquire_chunked rather than propagated in one go at release.
|
data/ext/ca_triop_dispatch.c
CHANGED
|
@@ -27,6 +27,7 @@ ca_triop_kernel_lookup_vvv (uint16_t op_id, int8_t common_dt)
|
|
|
27
27
|
case CA_TRIOP_FMA: return ca_triop_fma [common_dt];
|
|
28
28
|
case CA_TRIOP_FMS: return ca_triop_fms [common_dt];
|
|
29
29
|
case CA_TRIOP_CLIP: return ca_triop_clip [common_dt];
|
|
30
|
+
case CA_TRIOP_SELECT: return ca_triop_select [common_dt];
|
|
30
31
|
default: return NULL;
|
|
31
32
|
}
|
|
32
33
|
}
|
|
@@ -38,7 +39,9 @@ ca_triop_kernel_lookup_vvv (uint16_t op_id, int8_t common_dt)
|
|
|
38
39
|
int8_t
|
|
39
40
|
ca_lazy_promote_triop (uint16_t op_id, int8_t dt1, int8_t dt2, int8_t dt3)
|
|
40
41
|
{
|
|
41
|
-
(
|
|
42
|
+
if ( op_id == CA_TRIOP_SELECT ) {
|
|
43
|
+
return (int8_t) ca_promote_type(dt2, dt3);
|
|
44
|
+
}
|
|
42
45
|
return (int8_t) ca_promote_type(ca_promote_type(dt1, dt2), dt3);
|
|
43
46
|
}
|
|
44
47
|
|
data/ext/ca_triop_dispatch.h
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
runs (cast-before invariant, mirrors CABinOp). Output data_type is
|
|
12
12
|
always the common data_type (preserve).
|
|
13
13
|
|
|
14
|
-
Scope: fma / fms / clip (see ext/mkkernel.rb
|
|
14
|
+
Scope: fma / fms / clip / select (see ext/mkkernel.rb).
|
|
15
15
|
None of the currently-defined triops trap on integer zero divisor.
|
|
16
16
|
|
|
17
17
|
---------------------------------------------------------------------------- */
|
|
@@ -29,6 +29,7 @@ enum {
|
|
|
29
29
|
CA_TRIOP_FMA = 0, /* a * b + c (single-rounding on float) */
|
|
30
30
|
CA_TRIOP_FMS = 1, /* a * b - c (single-rounding on float) */
|
|
31
31
|
CA_TRIOP_CLIP = 2, /* min(max(a, lo), hi), NaN-preserving */
|
|
32
|
+
CA_TRIOP_SELECT = 3, /* a ? b : c (lazy then_else) */
|
|
32
33
|
|
|
33
34
|
CA_TRIOP_COUNT
|
|
34
35
|
};
|
|
@@ -40,6 +41,7 @@ enum {
|
|
|
40
41
|
extern ca_triop_func_t ca_triop_fma [CA_NTYPE];
|
|
41
42
|
extern ca_triop_func_t ca_triop_fms [CA_NTYPE];
|
|
42
43
|
extern ca_triop_func_t ca_triop_clip [CA_NTYPE];
|
|
44
|
+
extern ca_triop_func_t ca_triop_select [CA_NTYPE];
|
|
43
45
|
|
|
44
46
|
/* ------------------------------------------------------------------- */
|
|
45
47
|
/* Dispatch API */
|
|
@@ -49,7 +51,8 @@ extern ca_triop_func_t ca_triop_clip [CA_NTYPE];
|
|
|
49
51
|
not implemented at the requested data_type. */
|
|
50
52
|
ca_triop_func_t ca_triop_kernel_lookup_vvv (uint16_t op_id, int8_t common_dt);
|
|
51
53
|
|
|
52
|
-
/* 3-way promotion: common data_type of (dt1, dt2, dt3).
|
|
54
|
+
/* 3-way promotion: common data_type of (dt1, dt2, dt3). For select it is
|
|
55
|
+
that of the two branches (dt2, dt3); the condition is converted to it. */
|
|
53
56
|
int8_t ca_lazy_promote_triop (uint16_t op_id, int8_t dt1, int8_t dt2, int8_t dt3);
|
|
54
57
|
|
|
55
58
|
/* Each operand's cast-target data_type (= common data_type for all three,
|
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
/* CSV body reader for CAFrame.from_csv.
|
|
2
|
+
|
|
3
|
+
CArray.__csv_read_body_as_string_cells__(text, sep, quote, ncol, keep)
|
|
4
|
+
-> [ncol, cells, records]
|
|
5
|
+
reads every record of text into one flat Array of nrow * ncol cells, row
|
|
6
|
+
after row: a String for a field, UNDEF for a missing one (an unquoted
|
|
7
|
+
empty field, or a cell a short row never reached). keep, when not nil,
|
|
8
|
+
is the ascending Array of the indexes of the columns to read: a row then
|
|
9
|
+
has a cell for each of them only, and the fields of the others are passed
|
|
10
|
+
over without being copied out of the text. records counts the
|
|
11
|
+
records read, blank lines included, as the Ruby tokenizer numbers them.
|
|
12
|
+
With ncol 0 the column count is the first record's, as for a file with no
|
|
13
|
+
header; a later record that is longer is then one this reader declines.
|
|
14
|
+
|
|
15
|
+
CArray.__csv_read_body_as_const_string_columns__(text, sep, quote, ncol, keep)
|
|
16
|
+
-> [ncol, buffer, [pairs, ...], records]
|
|
17
|
+
reads the same records into one fixlen-16 (start, end) pair entity per
|
|
18
|
+
column read, the layout CAConstString.wrap takes, with missing cells masked.
|
|
19
|
+
The pairs index buffer, which is text itself when no field held a doubled
|
|
20
|
+
quote, and text followed by those fields' unescaped bytes otherwise, so
|
|
21
|
+
the cells are not copied out of the text.
|
|
22
|
+
|
|
23
|
+
Both follow the rules of the Ruby tokenizer in
|
|
24
|
+
lib/carray/frame/csv_parser.rb, which stays the reference: a quoted field
|
|
25
|
+
may hold the separator, doubled quotes and line breaks; a line that is
|
|
26
|
+
empty, or only spaces and tabs with no separator, is not a row unless the
|
|
27
|
+
file has one column. They answer nil, for the Ruby tokenizer to read the
|
|
28
|
+
text and say what is wrong, when the text is not UTF-8 or US-ASCII or has
|
|
29
|
+
an invalid byte, when a record is malformed or longer than ncol, and when
|
|
30
|
+
keep names no column or one past the last. */
|
|
31
|
+
|
|
32
|
+
#include "carray.h"
|
|
33
|
+
#include "carray_internal.h"
|
|
34
|
+
#include "ruby/encoding.h"
|
|
35
|
+
|
|
36
|
+
static int
|
|
37
|
+
ca_csv_at (const char *s, long n, long p, const char *t, long tlen)
|
|
38
|
+
{
|
|
39
|
+
return p + tlen <= n && memcmp(s + p, t, tlen) == 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* The end of the line content that starts at p: the position of its "\n",
|
|
43
|
+
or n; *next is where the following line starts. A "\r" before the "\n",
|
|
44
|
+
or at the end of the text, is not content. */
|
|
45
|
+
static long
|
|
46
|
+
ca_csv_line_end (const char *s, long n, long p, long *next)
|
|
47
|
+
{
|
|
48
|
+
const char *nl = memchr(s + p, '\n', n - p);
|
|
49
|
+
long e = nl ? nl - s : n;
|
|
50
|
+
*next = nl ? e + 1 : n;
|
|
51
|
+
if ( e > p && s[e - 1] == '\r' ) {
|
|
52
|
+
e -= 1;
|
|
53
|
+
}
|
|
54
|
+
return e;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* A growing list of (start, end) pairs. A pair at or past the length of
|
|
58
|
+
the text indexes the unescaped tail; a missing cell is (-1, -1). */
|
|
59
|
+
typedef struct {
|
|
60
|
+
int64_t *v;
|
|
61
|
+
long len, cap; /* in pairs */
|
|
62
|
+
} ca_csv_cell_ranges;
|
|
63
|
+
|
|
64
|
+
static void
|
|
65
|
+
ca_csv_push_cell_range (ca_csv_cell_ranges *a, int64_t start, int64_t end)
|
|
66
|
+
{
|
|
67
|
+
if ( a->len == a->cap ) {
|
|
68
|
+
a->cap = a->cap ? 2 * a->cap : 4096;
|
|
69
|
+
REALLOC_N(a->v, int64_t, 2 * a->cap);
|
|
70
|
+
}
|
|
71
|
+
a->v[2 * a->len] = start;
|
|
72
|
+
a->v[2 * a->len + 1] = end;
|
|
73
|
+
a->len++;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
typedef struct {
|
|
77
|
+
ca_csv_cell_ranges cells; /* row after row */
|
|
78
|
+
ca_csv_cell_ranges pending; /* blank lines before the first record */
|
|
79
|
+
VALUE tail; /* unescaped quoted fields, or Qnil */
|
|
80
|
+
VALUE keep; /* the indexes of the columns to read, or Qnil */
|
|
81
|
+
char *kept; /* keep as a byte per column, 1 for one read;
|
|
82
|
+
NULL for every column, or before ncol is known */
|
|
83
|
+
long ncol;
|
|
84
|
+
long width; /* the cells of a row: those of the columns read */
|
|
85
|
+
long records;
|
|
86
|
+
} ca_csv_walk_t;
|
|
87
|
+
|
|
88
|
+
/* Set w->kept and w->width from w->keep for w->ncol columns. Returns 0 when
|
|
89
|
+
keep names no column or one past the last. */
|
|
90
|
+
static int
|
|
91
|
+
ca_csv_set_kept_columns (ca_csv_walk_t *w)
|
|
92
|
+
{
|
|
93
|
+
long i;
|
|
94
|
+
w->kept = ALLOC_N(char, w->ncol);
|
|
95
|
+
memset(w->kept, 0, w->ncol);
|
|
96
|
+
for (i = 0; i < RARRAY_LEN(w->keep); i++) {
|
|
97
|
+
long j = NUM2LONG(rb_ary_entry(w->keep, i));
|
|
98
|
+
if ( j < 0 || j >= w->ncol ) {
|
|
99
|
+
return 0;
|
|
100
|
+
}
|
|
101
|
+
if ( ! w->kept[j] ) {
|
|
102
|
+
w->kept[j] = 1;
|
|
103
|
+
w->width++;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return w->width > 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Read every record of s into w. Returns 0 when the text is one this
|
|
110
|
+
reader declines (see the header comment). The cell ranges it grows are
|
|
111
|
+
the caller's to free, whether it returns or raises. */
|
|
112
|
+
static int
|
|
113
|
+
ca_csv_walk_records (const char *s, long n, const char *sp, long slen,
|
|
114
|
+
const char *qp, long qlen, ca_csv_walk_t *w)
|
|
115
|
+
{
|
|
116
|
+
long ncol = w->ncol, p = 0;
|
|
117
|
+
|
|
118
|
+
if ( ! NIL_P(w->keep) && ncol > 0 && ! ca_csv_set_kept_columns(w) ) {
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
while ( p < n ) {
|
|
122
|
+
long next, e = ca_csv_line_end(s, n, p, &next), k, fields = 0;
|
|
123
|
+
int blank = 1;
|
|
124
|
+
|
|
125
|
+
w->records += 1;
|
|
126
|
+
|
|
127
|
+
/* A blank line: empty, or only spaces and tabs with no separator. */
|
|
128
|
+
for (k = p; k < e; k++) {
|
|
129
|
+
if ( s[k] != ' ' && s[k] != '\t' ) {
|
|
130
|
+
blank = 0;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if ( blank ) {
|
|
135
|
+
for (k = p; k + slen <= e; k++) {
|
|
136
|
+
if ( memcmp(s + k, sp, slen) == 0 ) {
|
|
137
|
+
blank = 0;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if ( blank ) {
|
|
143
|
+
int64_t a = e > p ? p : -1, b = e > p ? e : -1;
|
|
144
|
+
if ( ncol == 1 ) {
|
|
145
|
+
if ( w->kept == NULL || w->kept[0] ) {
|
|
146
|
+
ca_csv_push_cell_range(&w->cells, a, b);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else if ( ncol == 0 ) {
|
|
150
|
+
/* Before the first record the column count is not known: keep the
|
|
151
|
+
line, a row if that record turns out to have one column. */
|
|
152
|
+
ca_csv_push_cell_range(&w->pending, a, b);
|
|
153
|
+
}
|
|
154
|
+
p = next;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
for (;;) {
|
|
159
|
+
int64_t a = -1, b = -1;
|
|
160
|
+
/* The field of a column not read is passed over, its text not
|
|
161
|
+
unescaped. */
|
|
162
|
+
int read = w->kept == NULL || ( fields < ncol && w->kept[fields] );
|
|
163
|
+
if ( ca_csv_at(s, n, p, qp, qlen) ) {
|
|
164
|
+
/* A quoted field, which may run onto later lines. */
|
|
165
|
+
long q = p + qlen, start = q, tail0 = -1;
|
|
166
|
+
for (;;) {
|
|
167
|
+
const char *hit = NULL;
|
|
168
|
+
long r = q;
|
|
169
|
+
while ( r + qlen <= n ) {
|
|
170
|
+
const char *c = memchr(s + r, qp[0], n - r);
|
|
171
|
+
if ( c == NULL ) {
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
r = c - s;
|
|
175
|
+
if ( ca_csv_at(s, n, r, qp, qlen) ) {
|
|
176
|
+
hit = c;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
r++;
|
|
180
|
+
}
|
|
181
|
+
if ( hit == NULL ) {
|
|
182
|
+
return 0; /* unterminated */
|
|
183
|
+
}
|
|
184
|
+
if ( ca_csv_at(s, n, r + qlen, qp, qlen) ) {
|
|
185
|
+
/* a doubled quote is a literal one */
|
|
186
|
+
if ( ! read ) {
|
|
187
|
+
q = r + 2 * qlen;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if ( NIL_P(w->tail) ) {
|
|
191
|
+
w->tail = rb_str_buf_new(256);
|
|
192
|
+
}
|
|
193
|
+
if ( tail0 < 0 ) {
|
|
194
|
+
tail0 = RSTRING_LEN(w->tail);
|
|
195
|
+
rb_str_cat(w->tail, s + start, r + qlen - start);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
rb_str_cat(w->tail, s + q, r + qlen - q);
|
|
199
|
+
}
|
|
200
|
+
q = r + 2 * qlen;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if ( tail0 < 0 ) {
|
|
204
|
+
a = start;
|
|
205
|
+
b = r;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
rb_str_cat(w->tail, s + q, r - q);
|
|
209
|
+
a = n + tail0;
|
|
210
|
+
b = n + RSTRING_LEN(w->tail);
|
|
211
|
+
}
|
|
212
|
+
p = r + qlen;
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
e = ca_csv_line_end(s, n, p, &next);
|
|
216
|
+
if ( p != e && ! ca_csv_at(s, n, p, sp, slen) ) {
|
|
217
|
+
return 0; /* text after the closing quote */
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
long r = p;
|
|
222
|
+
if ( slen == 1 && qlen == 1 ) {
|
|
223
|
+
const char sc = sp[0], qc = qp[0];
|
|
224
|
+
while ( r < e && s[r] != sc ) {
|
|
225
|
+
if ( s[r] == qc ) {
|
|
226
|
+
return 0; /* a quote in an unquoted field */
|
|
227
|
+
}
|
|
228
|
+
r++;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
while ( r < e && ! ca_csv_at(s, n, r, sp, slen) ) {
|
|
233
|
+
if ( ca_csv_at(s, n, r, qp, qlen) ) {
|
|
234
|
+
return 0; /* a quote in an unquoted field */
|
|
235
|
+
}
|
|
236
|
+
r++;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
a = r > p ? p : -1;
|
|
240
|
+
b = r > p ? r : -1;
|
|
241
|
+
p = r;
|
|
242
|
+
}
|
|
243
|
+
if ( ++fields > ncol && ncol > 0 ) {
|
|
244
|
+
return 0; /* a row too long */
|
|
245
|
+
}
|
|
246
|
+
if ( read ) {
|
|
247
|
+
ca_csv_push_cell_range(&w->cells, a, b);
|
|
248
|
+
}
|
|
249
|
+
if ( p < e && ca_csv_at(s, n, p, sp, slen) ) {
|
|
250
|
+
p += slen;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
if ( ncol == 0 ) {
|
|
256
|
+
/* The first record sets the column count; the blank lines before it
|
|
257
|
+
are rows of a one-column file and nothing otherwise. */
|
|
258
|
+
ncol = fields;
|
|
259
|
+
if ( ! NIL_P(w->keep) ) {
|
|
260
|
+
/* Its fields were all read, the columns being unknown until now:
|
|
261
|
+
keep those of the columns read. */
|
|
262
|
+
long j, k = 0;
|
|
263
|
+
w->ncol = ncol;
|
|
264
|
+
if ( ! ca_csv_set_kept_columns(w) ) {
|
|
265
|
+
return 0;
|
|
266
|
+
}
|
|
267
|
+
for (j = 0; j < ncol; j++) {
|
|
268
|
+
if ( w->kept[j] ) {
|
|
269
|
+
w->cells.v[2 * k] = w->cells.v[2 * j];
|
|
270
|
+
w->cells.v[2 * k + 1] = w->cells.v[2 * j + 1];
|
|
271
|
+
k++;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
w->cells.len = k;
|
|
275
|
+
}
|
|
276
|
+
if ( ncol == 1 && w->pending.len > 0 ) {
|
|
277
|
+
long i;
|
|
278
|
+
for (i = 0; i < w->cells.len; i++) {
|
|
279
|
+
ca_csv_push_cell_range(&w->pending, w->cells.v[2 * i], w->cells.v[2 * i + 1]);
|
|
280
|
+
}
|
|
281
|
+
{ ca_csv_cell_ranges t = w->cells; w->cells = w->pending; w->pending = t; }
|
|
282
|
+
w->pending.len = 0;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
for (; fields < ncol; fields++) {
|
|
286
|
+
if ( w->kept == NULL || w->kept[fields] ) {
|
|
287
|
+
ca_csv_push_cell_range(&w->cells, -1, -1);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
p = next;
|
|
291
|
+
}
|
|
292
|
+
w->ncol = ncol;
|
|
293
|
+
if ( NIL_P(w->keep) ) {
|
|
294
|
+
w->width = ncol;
|
|
295
|
+
}
|
|
296
|
+
return ncol > 0; /* 0: no record */
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/* The arguments both readers take, checked; 0 for text they decline. */
|
|
300
|
+
static int
|
|
301
|
+
ca_csv_check_reader_args (VALUE text, VALUE vsep, VALUE vquote, VALUE vncol,
|
|
302
|
+
VALUE keep, long *ncol)
|
|
303
|
+
{
|
|
304
|
+
rb_encoding *enc;
|
|
305
|
+
Check_Type(text, T_STRING);
|
|
306
|
+
Check_Type(vsep, T_STRING);
|
|
307
|
+
Check_Type(vquote, T_STRING);
|
|
308
|
+
if ( ! NIL_P(keep) ) {
|
|
309
|
+
Check_Type(keep, T_ARRAY);
|
|
310
|
+
}
|
|
311
|
+
*ncol = NUM2LONG(vncol);
|
|
312
|
+
enc = rb_enc_get(text);
|
|
313
|
+
if ( ( enc != rb_utf8_encoding() && enc != rb_usascii_encoding() )
|
|
314
|
+
|| rb_enc_str_coderange(text) == ENC_CODERANGE_BROKEN || *ncol < 0 ) {
|
|
315
|
+
return 0;
|
|
316
|
+
}
|
|
317
|
+
return RSTRING_LEN(vsep) >= 1 && RSTRING_LEN(vquote) >= 1;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/* What a reader makes of the walked records: the Ruby value it answers. */
|
|
321
|
+
typedef VALUE (*ca_csv_build_result) (VALUE text, ca_csv_walk_t *w);
|
|
322
|
+
|
|
323
|
+
typedef struct {
|
|
324
|
+
VALUE text, vsep, vquote, vncol;
|
|
325
|
+
ca_csv_walk_t w;
|
|
326
|
+
ca_csv_build_result build;
|
|
327
|
+
} ca_csv_read_body_context;
|
|
328
|
+
|
|
329
|
+
static VALUE
|
|
330
|
+
ca_csv_read_body_walk_and_build (VALUE varg)
|
|
331
|
+
{
|
|
332
|
+
ca_csv_read_body_context *c = (ca_csv_read_body_context *) varg;
|
|
333
|
+
if ( ! ca_csv_check_reader_args(c->text, c->vsep, c->vquote, c->vncol, c->w.keep,
|
|
334
|
+
&c->w.ncol) ) {
|
|
335
|
+
return Qnil;
|
|
336
|
+
}
|
|
337
|
+
if ( ! ca_csv_walk_records(RSTRING_PTR(c->text), RSTRING_LEN(c->text),
|
|
338
|
+
RSTRING_PTR(c->vsep), RSTRING_LEN(c->vsep),
|
|
339
|
+
RSTRING_PTR(c->vquote), RSTRING_LEN(c->vquote), &c->w) ) {
|
|
340
|
+
return Qnil;
|
|
341
|
+
}
|
|
342
|
+
return c->build(c->text, &c->w);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
static VALUE
|
|
346
|
+
ca_csv_read_body_free_cell_ranges (VALUE varg)
|
|
347
|
+
{
|
|
348
|
+
ca_csv_read_body_context *c = (ca_csv_read_body_context *) varg;
|
|
349
|
+
xfree(c->w.cells.v);
|
|
350
|
+
xfree(c->w.pending.v);
|
|
351
|
+
xfree(c->w.kept);
|
|
352
|
+
return Qnil;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/* Walk the records of text and build the answer from them, with the cell
|
|
356
|
+
ranges freed however that ends: the walk and the build both allocate,
|
|
357
|
+
and so may raise. */
|
|
358
|
+
static VALUE
|
|
359
|
+
ca_csv_read_body (VALUE text, VALUE vsep, VALUE vquote, VALUE vncol, VALUE keep,
|
|
360
|
+
ca_csv_build_result build)
|
|
361
|
+
{
|
|
362
|
+
ca_csv_read_body_context c = {
|
|
363
|
+
text, vsep, vquote, vncol,
|
|
364
|
+
{ { NULL, 0, 0 }, { NULL, 0, 0 }, Qnil, keep, NULL, 0, 0, 0 }, build
|
|
365
|
+
};
|
|
366
|
+
VALUE out = rb_ensure(ca_csv_read_body_walk_and_build, (VALUE) &c,
|
|
367
|
+
ca_csv_read_body_free_cell_ranges, (VALUE) &c);
|
|
368
|
+
RB_GC_GUARD(c.w.tail);
|
|
369
|
+
return out;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
static VALUE
|
|
373
|
+
ca_csv_build_string_cells (VALUE text, ca_csv_walk_t *w)
|
|
374
|
+
{
|
|
375
|
+
volatile VALUE out;
|
|
376
|
+
rb_encoding *enc = rb_enc_get(text);
|
|
377
|
+
const char *s = RSTRING_PTR(text);
|
|
378
|
+
long n = RSTRING_LEN(text), i;
|
|
379
|
+
|
|
380
|
+
out = rb_ary_new_capa(w->cells.len);
|
|
381
|
+
for (i = 0; i < w->cells.len; i++) {
|
|
382
|
+
int64_t a = w->cells.v[2 * i], b = w->cells.v[2 * i + 1];
|
|
383
|
+
VALUE cell;
|
|
384
|
+
if ( a < 0 ) {
|
|
385
|
+
cell = CA_UNDEF;
|
|
386
|
+
}
|
|
387
|
+
else if ( a < n ) {
|
|
388
|
+
cell = rb_enc_str_new(s + a, b - a, enc);
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
cell = rb_enc_str_new(RSTRING_PTR(w->tail) + (a - n), b - a, enc);
|
|
392
|
+
}
|
|
393
|
+
rb_ary_push(out, cell);
|
|
394
|
+
}
|
|
395
|
+
return rb_ary_new3(3, LONG2NUM(w->ncol), out, LONG2NUM(w->records));
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
static VALUE
|
|
399
|
+
ca_csv_build_const_string_columns (VALUE text, ca_csv_walk_t *w)
|
|
400
|
+
{
|
|
401
|
+
volatile VALUE buffer, cols;
|
|
402
|
+
ca_size_t dim[1];
|
|
403
|
+
long nrow, i, j;
|
|
404
|
+
|
|
405
|
+
if ( NIL_P(w->tail) ) {
|
|
406
|
+
buffer = text;
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
buffer = rb_str_buf_new(RSTRING_LEN(text) + RSTRING_LEN(w->tail));
|
|
410
|
+
rb_str_cat(buffer, RSTRING_PTR(text), RSTRING_LEN(text));
|
|
411
|
+
rb_str_cat(buffer, RSTRING_PTR(w->tail), RSTRING_LEN(w->tail));
|
|
412
|
+
rb_enc_copy(buffer, text);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
nrow = w->cells.len / w->width;
|
|
416
|
+
dim[0] = (ca_size_t) nrow;
|
|
417
|
+
cols = rb_ary_new_capa(w->width);
|
|
418
|
+
for (j = 0; j < w->width; j++) {
|
|
419
|
+
CArray *pe;
|
|
420
|
+
int64_t *range;
|
|
421
|
+
boolean8_t *m = NULL;
|
|
422
|
+
VALUE col = rb_carray_new(CA_FIXLEN, 1, dim, 2 * sizeof(int64_t), NULL);
|
|
423
|
+
rb_ary_push(cols, col);
|
|
424
|
+
TypedData_Get_Struct(col, CArray, &carray_data_type, pe);
|
|
425
|
+
range = (int64_t *) pe->ptr;
|
|
426
|
+
for (i = 0; i < nrow; i++) {
|
|
427
|
+
int64_t a = w->cells.v[2 * (i * w->width + j)];
|
|
428
|
+
int64_t b = w->cells.v[2 * (i * w->width + j) + 1];
|
|
429
|
+
if ( a < 0 ) {
|
|
430
|
+
if ( m == NULL ) {
|
|
431
|
+
ca_create_mask(pe);
|
|
432
|
+
m = (boolean8_t *) pe->mask->ptr;
|
|
433
|
+
}
|
|
434
|
+
m[i] = 1;
|
|
435
|
+
a = b = 0;
|
|
436
|
+
}
|
|
437
|
+
range[2 * i] = a;
|
|
438
|
+
range[2 * i + 1] = b;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return rb_ary_new3(4, LONG2NUM(w->ncol), buffer, cols, LONG2NUM(w->records));
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
static VALUE
|
|
445
|
+
rb_ca_s_csv_read_body_as_string_cells (VALUE klass, VALUE text, VALUE vsep, VALUE vquote,
|
|
446
|
+
VALUE vncol, VALUE keep)
|
|
447
|
+
{
|
|
448
|
+
return ca_csv_read_body(text, vsep, vquote, vncol, keep, ca_csv_build_string_cells);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
static VALUE
|
|
452
|
+
rb_ca_s_csv_read_body_as_const_string_columns (VALUE klass, VALUE text, VALUE vsep, VALUE vquote,
|
|
453
|
+
VALUE vncol, VALUE keep)
|
|
454
|
+
{
|
|
455
|
+
return ca_csv_read_body(text, vsep, vquote, vncol, keep, ca_csv_build_const_string_columns);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
void
|
|
459
|
+
Init_caframe_csv_reader (void)
|
|
460
|
+
{
|
|
461
|
+
rb_define_singleton_method(rb_cCArray, "__csv_read_body_as_string_cells__", rb_ca_s_csv_read_body_as_string_cells, 5);
|
|
462
|
+
rb_define_singleton_method(rb_cCArray, "__csv_read_body_as_const_string_columns__", rb_ca_s_csv_read_body_as_const_string_columns, 5);
|
|
463
|
+
}
|