carray 3.0.2 → 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 +304 -0
- data/README.md +3 -4
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +225 -0
- data/ext/ca_axis_group.c +177 -99
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +66 -71
- 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 +663 -214
- data/ext/ca_kernel_iterator.h +231 -167
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +132 -22
- 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 +1 -0
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +96 -25
- data/ext/ca_obj_face.c +406 -64
- data/ext/ca_obj_face.h +92 -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 +21 -21
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +189 -107
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +543 -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 +47 -49
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -118
- data/ext/ca_obj_stride.c +195 -34
- data/ext/ca_obj_string.c +17 -18
- 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 +149 -27
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +102 -79
- data/ext/ca_sweep_engine.h +7 -20
- 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 +70 -27
- data/ext/carray_access.c +455 -211
- data/ext/carray_address_basis.c +177 -36
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +46 -14
- data/ext/carray_call_cfunc.c +0 -28
- data/ext/carray_cast.c +1444 -209
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +32 -11
- data/ext/carray_core.c +514 -122
- data/ext/carray_count.c +140 -87
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +569 -277
- 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 +385 -3
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +682 -316
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +221 -76
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1089 -359
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +273 -239
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +170 -70
- data/ext/carray_sort.c +215 -218
- 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 +0 -2
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1076 -846
- data/ext/ruby_carray.c +7 -1
- 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 +19 -0
- data/lib/carray/autoload_method_extension.rb +6 -0
- data/lib/carray/axis_group.rb +174 -26
- data/lib/carray/basics.rb +91 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +118 -48
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +94 -26
- data/lib/carray/categorical_iterator.rb +333 -826
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +46 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +589 -82
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +124 -25
- data/lib/carray/frame/group.rb +189 -63
- data/lib/carray/frame/io.rb +412 -72
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +37 -16
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +715 -48
- 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 +29 -11
- data/lib/carray/iterator.rb +14 -2
- data/lib/carray/lazy.rb +54 -30
- data/lib/carray/mask_gap_fill.rb +66 -52
- 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/factorize.rb +2 -2
- 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 +117 -4
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +177 -36
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/record_order.rb +208 -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 +51 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +4 -3
- 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 +517 -103
- data/lib/carray/window_iterator.rb +127 -72
- data/lib/carray.rb +2 -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_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 +1 -2
- data/yard-stubs/carray_access.rb +5 -4
- data/yard-stubs/carray_broadcast.rb +1 -1
- 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 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +25 -13
- data/yard-stubs/carray_median_percentile.rb +10 -6
- data/yard-stubs/carray_order.rb +34 -13
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +2 -1
- data/yard-stubs/carray_sort.rb +43 -3
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +11 -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 -26005
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14862
- data/ext/carray_kernels_reduce_extreme.c +0 -17494
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32218
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
|
@@ -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
|
+
}
|
data/ext/carray.h
CHANGED
|
@@ -716,6 +716,12 @@ typedef struct {
|
|
|
716
716
|
0 = outer-axis stack (legacy default).
|
|
717
717
|
parent_ndim = K innermost (= old merge at=-1).
|
|
718
718
|
Set by ca_stack_setup_with_axis / preserved on clone. */
|
|
719
|
+
CArray **mask_standins; /* NULL, or ALLOC_N(CArray*, n_parents) once the mask is
|
|
720
|
+
built: the all-false masks standing in for parents that
|
|
721
|
+
have none (owned, freed with the view) */
|
|
722
|
+
CArray *mask_owner; /* on the mask of a CAStack: that CAStack, whose stand-ins
|
|
723
|
+
this mask reads until they give way to the parents'
|
|
724
|
+
own masks (ca_multi_parent_mask_refresh); else NULL */
|
|
719
725
|
} CAStack;
|
|
720
726
|
|
|
721
727
|
/* CAMeld (ragged concatenate view along an existing axis). Unlike CAStack
|
|
@@ -749,6 +755,8 @@ typedef struct {
|
|
|
749
755
|
ca_size_t *seg_offset; /* ALLOC_N(ca_size_t, K+1); prefix sum along meld_axis.
|
|
750
756
|
seg_offset[0]=0, seg_offset[k+1]=seg_offset[k]+parents[k]->dim[meld_axis],
|
|
751
757
|
seg_offset[K]=dim[meld_axis]. */
|
|
758
|
+
CArray **mask_standins; /* as CAStack's: stand-in masks this view owns, or NULL */
|
|
759
|
+
CArray *mask_owner; /* as CAStack's */
|
|
752
760
|
} CAMeld;
|
|
753
761
|
|
|
754
762
|
/* Multi-parent view layout convention (CA_FLAG_MULTI_PARENTS). A view that
|
|
@@ -786,9 +794,14 @@ typedef struct {
|
|
|
786
794
|
VALUE self;
|
|
787
795
|
} CAObject; /* 48 + 4*(ndim) (bytes) */
|
|
788
796
|
|
|
789
|
-
/*
|
|
790
|
-
CAObjectMask is an internal class
|
|
791
|
-
|
|
797
|
+
/*
|
|
798
|
+
CAObjectMask is an internal class used only as the mask array of a
|
|
799
|
+
CAObject. Its bits live in the CAObject's mask hooks (mask_copy_data,
|
|
800
|
+
mask_fetch_addr, ...) when it has them, and in `cache` -- the mask
|
|
801
|
+
buffer of the CAObject's internal data array -- always. Like the mask
|
|
802
|
+
of any view it is cold at rest: ptr is NULL, and every read and write
|
|
803
|
+
goes through its slots to the hooks. An attach publishes the cache in
|
|
804
|
+
ptr, and `holds` counts the attaches not yet detached.
|
|
792
805
|
*/
|
|
793
806
|
|
|
794
807
|
typedef struct {
|
|
@@ -807,6 +820,8 @@ typedef struct {
|
|
|
807
820
|
ext/ca_array_pool.c. */
|
|
808
821
|
/* -------------*/
|
|
809
822
|
VALUE array;
|
|
823
|
+
char *cache;
|
|
824
|
+
long holds;
|
|
810
825
|
} CAObjectMask;
|
|
811
826
|
|
|
812
827
|
/* CARepeat (Phase R migration): structurally identical to CAStride.
|
|
@@ -862,7 +877,7 @@ int8_t ca_promote_type (int8_t a, int8_t b);
|
|
|
862
877
|
/* Infer a data_type code from a Ruby *value* (literal Numeric, true/false,
|
|
863
878
|
Complex, etc.) — distinct from rb_ca_guess_type which interprets the
|
|
864
879
|
object as a data_type *representation* (e.g. T_FIXNUM as a data_type code).
|
|
865
|
-
Used by
|
|
880
|
+
Used by rb_ca_cast_self_or_other.
|
|
866
881
|
CArray is not accepted (callers should use ca->data_type directly). */
|
|
867
882
|
int8_t ca_value_to_data_type (VALUE obj);
|
|
868
883
|
|
|
@@ -985,21 +1000,21 @@ extern VALUE rb_cCArrayObject;
|
|
|
985
1000
|
#define CA_CHECK_DATA_TYPE(data_type) \
|
|
986
1001
|
do { \
|
|
987
1002
|
if ( data_type <= CA_NONE || data_type >= CA_NTYPE ) { \
|
|
988
|
-
rb_raise(
|
|
1003
|
+
rb_raise(rb_eArgError, "invalid data_type id %i", data_type); \
|
|
989
1004
|
} \
|
|
990
1005
|
if ( ! ca_valid[data_type] ) { \
|
|
991
|
-
rb_raise(
|
|
1006
|
+
rb_raise(rb_eCADataTypeError, "data_type %s is disabled", ca_type_name[data_type]); \
|
|
992
1007
|
} \
|
|
993
1008
|
} while (0)
|
|
994
1009
|
|
|
995
1010
|
#define CA_CHECK_DATA_TYPE_NUMERIC(data_type) \
|
|
996
1011
|
if ( data_type <= CA_NONE || data_type >= CA_NTYPE || !ca_valid[data_type] || data_type == CA_FIXLEN || data_type == CA_OBJECT ) { \
|
|
997
|
-
rb_raise(
|
|
1012
|
+
rb_raise(rb_eCADataTypeError, "invalid numeric data type"); \
|
|
998
1013
|
}
|
|
999
1014
|
|
|
1000
1015
|
#define CA_CHECK_RANK(ndim) \
|
|
1001
1016
|
if ( ndim <= 0 || ndim > CA_RANK_MAX ) { \
|
|
1002
|
-
rb_raise(
|
|
1017
|
+
rb_raise(rb_eArgError, "invalid ndim"); \
|
|
1003
1018
|
}
|
|
1004
1019
|
|
|
1005
1020
|
#define CA_CHECK_DIM(ndim, dim) \
|
|
@@ -1007,44 +1022,46 @@ extern VALUE rb_cCArrayObject;
|
|
|
1007
1022
|
int8_t i_; \
|
|
1008
1023
|
for (i_=0; i_<ndim; i_++) { \
|
|
1009
1024
|
if ( dim[i_] < 0 ) { \
|
|
1010
|
-
rb_raise(
|
|
1025
|
+
rb_raise(rb_eArgError, "negative size dimension at %i-dim", i_); \
|
|
1011
1026
|
} \
|
|
1012
1027
|
} \
|
|
1013
1028
|
}
|
|
1014
1029
|
|
|
1030
|
+
/* A fixlen cell is at least one byte wide. A zero-width cell has one
|
|
1031
|
+
possible value, and a strided view of it cannot say which cell is which:
|
|
1032
|
+
its byte strides are all zero. */
|
|
1015
1033
|
#define CA_CHECK_BYTES(data_type, bytes) \
|
|
1016
1034
|
if ( data_type == CA_FIXLEN ) { \
|
|
1017
|
-
if ( bytes
|
|
1018
|
-
rb_raise(
|
|
1035
|
+
if ( bytes <= 0 ) { \
|
|
1036
|
+
rb_raise(rb_eArgError, \
|
|
1037
|
+
"invalid bytes (a fixlen needs bytes: of 1 or more)"); \
|
|
1019
1038
|
} \
|
|
1020
1039
|
} \
|
|
1021
1040
|
else { \
|
|
1022
1041
|
bytes = ca_sizeof[data_type]; \
|
|
1023
1042
|
if ( bytes <= 0 ) { \
|
|
1024
|
-
rb_raise(
|
|
1043
|
+
rb_raise(rb_eArgError, "invalid bytes"); \
|
|
1025
1044
|
} \
|
|
1026
1045
|
}
|
|
1027
1046
|
|
|
1047
|
+
/* An index into `n` places, counted from the end when negative, outside of
|
|
1048
|
+
which IndexError is raised naming the method the user called, `what` the
|
|
1049
|
+
index is ("index", "address") and the value given. */
|
|
1050
|
+
NORETURN(void ca_index_out_of_range (ca_size_t idx, ca_size_t n, const char *what));
|
|
1051
|
+
|
|
1052
|
+
/* Normalise `index` in place against `dim` (a negative one counts from the
|
|
1053
|
+
end) and raise through ca_index_out_of_range when it falls outside. */
|
|
1028
1054
|
#define CA_CHECK_INDEX(index, dim) \
|
|
1029
1055
|
do { \
|
|
1030
|
-
|
|
1031
|
-
|
|
1056
|
+
ca_size_t ca_check_index_given_ = (index); \
|
|
1057
|
+
if ( (index) < 0 ) { \
|
|
1058
|
+
(index) += (dim); \
|
|
1032
1059
|
} \
|
|
1033
|
-
if ( index < 0 || index >= (dim) ) { \
|
|
1034
|
-
|
|
1060
|
+
if ( (index) < 0 || (index) >= (dim) ) { \
|
|
1061
|
+
ca_index_out_of_range(ca_check_index_given_, (dim), "index"); \
|
|
1035
1062
|
} \
|
|
1036
1063
|
} while (0)
|
|
1037
1064
|
|
|
1038
|
-
#define CA_CHECK_BOUND(ca, idx) \
|
|
1039
|
-
{ \
|
|
1040
|
-
int8_t i; \
|
|
1041
|
-
for (i=0; i<ca->ndim; i++) { \
|
|
1042
|
-
if ( idx[i] < 0 || idx[i] >= ca->dim[i] ) { \
|
|
1043
|
-
rb_raise(rb_eRuntimeError, "index out of range at %i-dim ( %i <=> 0..%i )", i, idx[i], ca->dim[i]-1); \
|
|
1044
|
-
} \
|
|
1045
|
-
} \
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
1065
|
/* -------------------------------------------------------------------- */
|
|
1049
1066
|
|
|
1050
1067
|
/* complex <-> Ruby Complex conversion
|
|
@@ -1070,6 +1087,10 @@ extern VALUE rb_cCArrayObject;
|
|
|
1070
1087
|
# endif
|
|
1071
1088
|
#endif
|
|
1072
1089
|
|
|
1090
|
+
/* A string as a complex cell: a real number read as Float() reads it
|
|
1091
|
+
(nan / inf included), else as Complex() does; anything else raises. */
|
|
1092
|
+
double complex ca_str_to_cmplx (VALUE str);
|
|
1093
|
+
|
|
1073
1094
|
static inline double complex
|
|
1074
1095
|
rb_carray_num2cmplx (VALUE num)
|
|
1075
1096
|
{
|
|
@@ -1079,6 +1100,12 @@ rb_carray_num2cmplx (VALUE num)
|
|
|
1079
1100
|
if ( RB_FLOAT_TYPE_P(num) || RB_INTEGER_TYPE_P(num) ) {
|
|
1080
1101
|
return (double complex) NUM2DBL(num);
|
|
1081
1102
|
}
|
|
1103
|
+
if ( RB_TYPE_P(num, T_STRING) ) {
|
|
1104
|
+
return ca_str_to_cmplx(num);
|
|
1105
|
+
}
|
|
1106
|
+
if ( NIL_P(num) ) {
|
|
1107
|
+
rb_raise(rb_eTypeError, "can't convert nil into Complex");
|
|
1108
|
+
}
|
|
1082
1109
|
if ( rb_respond_to(num, rb_intern("to_c")) ) {
|
|
1083
1110
|
VALUE c = rb_funcall(num, rb_intern("to_c"), 0);
|
|
1084
1111
|
return CMPLX(NUM2DBL(rb_complex_real(c)), NUM2DBL(rb_complex_imag(c)));
|
|
@@ -1125,6 +1152,7 @@ double OBJ2DBL (VALUE v);
|
|
|
1125
1152
|
object->int/float cast loop so an unparseable cell becomes UNDEF instead
|
|
1126
1153
|
of a silent 0.0 (float) or a raise (int). See ext/carray_cast.c. */
|
|
1127
1154
|
int ca_obj2dbl_ok (VALUE v, double *out);
|
|
1155
|
+
int ca_obj2cmplx_ok (VALUE v, double complex *out);
|
|
1128
1156
|
int rb_obj2long_ok (VALUE v, long *out);
|
|
1129
1157
|
int rb_obj2ulong_ok (VALUE v, unsigned long *out);
|
|
1130
1158
|
int rb_obj2ll_ok (VALUE v, long long *out);
|
|
@@ -1293,6 +1321,10 @@ VALUE rb_ca_farray (VALUE self);
|
|
|
1293
1321
|
|
|
1294
1322
|
/* --- ca_obj_stride.c --- */
|
|
1295
1323
|
|
|
1324
|
+
/* ca_stride_setup with ca == NULL runs its checks and returns 0 without
|
|
1325
|
+
writing. ca_stride_new calls it that way before it allocates, so a
|
|
1326
|
+
rejected argument leaves no struct behind; a subclass constructor can
|
|
1327
|
+
do the same through its own setup function. */
|
|
1296
1328
|
int ca_stride_setup (CAStride *ca, int8_t obj_type, CArray *parent,
|
|
1297
1329
|
int8_t data_type, ca_size_t bytes,
|
|
1298
1330
|
int8_t ndim, ca_size_t *dim,
|
|
@@ -1459,6 +1491,7 @@ int ca_is_object_type (void *ap);
|
|
|
1459
1491
|
|
|
1460
1492
|
void ca_check_type (void *ap, int8_t data_type);
|
|
1461
1493
|
#define ca_check_data_type(ap, data_type) ca_check_type(ap, data_type)
|
|
1494
|
+
void ca_check_uninitialized (void *ap); /* initialize / initialize_copy entry */
|
|
1462
1495
|
void ca_check_ndim (void *ap, int ndim);
|
|
1463
1496
|
void ca_check_shape (void *ap, int ndim, ca_size_t *dim);
|
|
1464
1497
|
void ca_check_same_data_type (void *ap1, void *ap2);
|
|
@@ -1474,7 +1507,7 @@ int ca_is_valid_index (void *ap, ca_size_t *idx);
|
|
|
1474
1507
|
|
|
1475
1508
|
/* API : allocate, attach, update, sync, detach */
|
|
1476
1509
|
|
|
1477
|
-
/* Attach lifecycle contract (R1-
|
|
1510
|
+
/* Attach lifecycle contract (R1-R6). Ownership-based, and NOT transitive.
|
|
1478
1511
|
This block is the canonical statement of the contract; the other documents
|
|
1479
1512
|
copy it. guides/devel/04_attach_lifecycle.md discusses it at length.
|
|
1480
1513
|
|
|
@@ -1493,6 +1526,14 @@ int ca_is_valid_index (void *ap, ca_size_t *idx);
|
|
|
1493
1526
|
R5 (traffic) Attach hands you a buffer, not a live array. Use x->ptr;
|
|
1494
1527
|
a view derived from x composes past the buffer to the
|
|
1495
1528
|
root.
|
|
1529
|
+
R6 (raising) ca_allocate and ca_attach that raise have taken
|
|
1530
|
+
nothing; ca_allocate_n and ca_attach_n take all of
|
|
1531
|
+
their arrays or none. Close a window with
|
|
1532
|
+
ca_sync_detach, which detaches even when the sync
|
|
1533
|
+
raises -- ca_sync then ca_detach leaves the window open
|
|
1534
|
+
on a raise. Anything between that can raise (Ruby
|
|
1535
|
+
called from inside the window) needs an ensure of its
|
|
1536
|
+
own.
|
|
1496
1537
|
*/
|
|
1497
1538
|
|
|
1498
1539
|
void ca_allocate (void *ap);
|
|
@@ -1500,6 +1541,7 @@ void ca_attach (void *ca);
|
|
|
1500
1541
|
void ca_update (void *ca);
|
|
1501
1542
|
void ca_sync (void *ca);
|
|
1502
1543
|
void ca_detach (void *ca);
|
|
1544
|
+
void ca_sync_detach (void *ca);
|
|
1503
1545
|
|
|
1504
1546
|
void ca_allocate_n (int n, ...);
|
|
1505
1547
|
void ca_attach_n (int n, ...);
|
|
@@ -1672,6 +1714,7 @@ void ca_parse_range_without_check (VALUE arg, ca_size_t size,
|
|
|
1672
1714
|
ca_size_t *offset, ca_size_t *count, ca_size_t *step);
|
|
1673
1715
|
|
|
1674
1716
|
int ca_equal (void *ap, void *bp);
|
|
1717
|
+
int ca_eql_storage (void *ap, void *bp);
|
|
1675
1718
|
void ca_zerodiv(void) __attribute__((noreturn));
|
|
1676
1719
|
/* ca_rand removed in 3.0; use rb_random_real/rb_random_ulong_limited instead */
|
|
1677
1720
|
ca_size_t ca_bounds_normalize_index (int8_t bounds, ca_size_t size0, ca_size_t k);
|