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
data/ext/carray_cast.c
CHANGED
|
@@ -34,11 +34,573 @@
|
|
|
34
34
|
#include "ruby/memory_view.h"
|
|
35
35
|
#include "ca_monop_dispatch.h" /* CA_MONOP_CAST_BASE for as_type routing */
|
|
36
36
|
#include "ca_obj_face.h" /* ca_strip_face for write path lift */
|
|
37
|
+
#include "carray_internal.h" /* rb_ca_inherit_attr */
|
|
38
|
+
#include "ruby/util.h" /* ruby_strtod */
|
|
39
|
+
#include <math.h>
|
|
40
|
+
|
|
41
|
+
/* ------------------------------------------------------------------------
|
|
42
|
+
Reading numbers from strings
|
|
43
|
+
|
|
44
|
+
A String stored into, or converted to, an integer or float array is data,
|
|
45
|
+
not a Ruby literal, so it is read as a decimal number rather than through
|
|
46
|
+
Integer() / Float():
|
|
47
|
+
|
|
48
|
+
number [+-]? ( digit+ ( '.' digit* )? | '.' digit+ )
|
|
49
|
+
( [eE] [+-]? digit+ )?
|
|
50
|
+
float number | nan | inf | infinity (any case, optional sign)
|
|
51
|
+
|
|
52
|
+
Surrounding ASCII whitespace is ignored. "010" is ten, never octal, and
|
|
53
|
+
"0x1F" / "1_000" / "0b11" are not numbers. An integer target takes a
|
|
54
|
+
number whose value is exactly an integer ("1.0", "1e3", "2.50e1"), decided
|
|
55
|
+
from the digits rather than through a double, so a long integer is not
|
|
56
|
+
rounded; "1.5" is not an integer.
|
|
57
|
+
|
|
58
|
+
to_type makes a string that does not read, or an integer the target type
|
|
59
|
+
cannot hold, UNDEF; a store raises (ArgumentError / RangeError).
|
|
60
|
+
------------------------------------------------------------------------ */
|
|
61
|
+
|
|
62
|
+
static int ca_str_nonfinite (const char *str, double *out);
|
|
63
|
+
|
|
64
|
+
#include "ca_pow5_table.h"
|
|
65
|
+
|
|
66
|
+
/* Decimal to binary64, correctly rounded, without the C library.
|
|
67
|
+
|
|
68
|
+
A validated token is read as w * 10^q with w the first 19 significant
|
|
69
|
+
digits. Clinger's fast path answers when w and 10^q are both exact
|
|
70
|
+
doubles (one rounding). Otherwise the Eisel-Lemire method multiplies w
|
|
71
|
+
by a 128-bit approximation of 5^q (ca_pow5_table.h) and reads the
|
|
72
|
+
significand from the top of the product, declining in the rare cases
|
|
73
|
+
where the product cannot settle the rounding. A declined token, and one
|
|
74
|
+
with more than 19 significant digits, goes to ruby_strtod. */
|
|
75
|
+
|
|
76
|
+
static const double ca_exact_pow10[23] = {
|
|
77
|
+
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
|
|
78
|
+
1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
#if defined(__SIZEOF_INT128__)
|
|
82
|
+
static int
|
|
83
|
+
ca_decimal_to_double_eisel_lemire (int64_t q, uint64_t w, uint64_t *bits)
|
|
84
|
+
{
|
|
85
|
+
const uint64_t *t;
|
|
86
|
+
unsigned __int128 p;
|
|
87
|
+
uint64_t hi, lo, m;
|
|
88
|
+
int lz, upper;
|
|
89
|
+
int64_t e2;
|
|
90
|
+
|
|
91
|
+
if ( q < CA_POW5_Q_MIN ) {
|
|
92
|
+
*bits = 0;
|
|
93
|
+
return 1;
|
|
94
|
+
}
|
|
95
|
+
if ( q > CA_POW5_Q_MAX ) {
|
|
96
|
+
*bits = 0x7FFULL << 52;
|
|
97
|
+
return 1;
|
|
98
|
+
}
|
|
99
|
+
lz = __builtin_clzll(w);
|
|
100
|
+
w <<= lz;
|
|
101
|
+
t = ca_pow5_table + 2 * ( q - CA_POW5_Q_MIN );
|
|
102
|
+
p = (unsigned __int128) w * t[0];
|
|
103
|
+
hi = (uint64_t) ( p >> 64 );
|
|
104
|
+
lo = (uint64_t) p;
|
|
105
|
+
if ( ( hi & 0x1FF ) == 0x1FF ) {
|
|
106
|
+
/* The bits below the significand are all ones: the low half of the
|
|
107
|
+
table entry can carry into them. */
|
|
108
|
+
uint64_t hi2 = (uint64_t) ( ( (unsigned __int128) w * t[1] ) >> 64 );
|
|
109
|
+
lo += hi2;
|
|
110
|
+
if ( lo < hi2 ) {
|
|
111
|
+
hi++;
|
|
112
|
+
}
|
|
113
|
+
if ( ( hi & 0x1FF ) == 0x1FF && lo == UINT64_MAX && ( q < -27 || q > 55 ) ) {
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
upper = (int) ( hi >> 63 );
|
|
118
|
+
m = hi >> ( upper + 9 );
|
|
119
|
+
/* floor(q * log2(10)) + 63, then the bias. 217706 / 2^16 is log2(10)
|
|
120
|
+
closely enough for every q in the table; the floor is taken by hand,
|
|
121
|
+
since >> on a negative number is the compiler's choice. */
|
|
122
|
+
{
|
|
123
|
+
int64_t t = 217706 * q;
|
|
124
|
+
int64_t log2_10_q = ( t >= 0 ) ? t / 65536 : - ( ( - t + 65535 ) / 65536 );
|
|
125
|
+
e2 = log2_10_q + 63 + upper - lz + 1023;
|
|
126
|
+
}
|
|
127
|
+
if ( e2 <= 0 ) { /* subnormal */
|
|
128
|
+
if ( -e2 + 1 >= 64 ) {
|
|
129
|
+
*bits = 0;
|
|
130
|
+
return 1;
|
|
131
|
+
}
|
|
132
|
+
m >>= -e2 + 1;
|
|
133
|
+
m += m & 1;
|
|
134
|
+
m >>= 1;
|
|
135
|
+
e2 = ( m < ( 1ULL << 52 ) ) ? 0 : 1;
|
|
136
|
+
*bits = ( (uint64_t) e2 << 52 ) | ( m & ( ( 1ULL << 52 ) - 1 ) );
|
|
137
|
+
return 1;
|
|
138
|
+
}
|
|
139
|
+
if ( lo <= 1 && q >= -4 && q <= 23 && ( m & 3 ) == 1
|
|
140
|
+
&& ( m << ( upper + 9 ) ) == hi ) {
|
|
141
|
+
m &= ~1ULL; /* exactly halfway: to even */
|
|
142
|
+
}
|
|
143
|
+
m += m & 1;
|
|
144
|
+
m >>= 1;
|
|
145
|
+
if ( m >= ( 2ULL << 52 ) ) {
|
|
146
|
+
m = 1ULL << 52;
|
|
147
|
+
e2++;
|
|
148
|
+
}
|
|
149
|
+
m &= ~( 1ULL << 52 );
|
|
150
|
+
if ( e2 >= 0x7FF ) {
|
|
151
|
+
*bits = 0x7FFULL << 52;
|
|
152
|
+
return 1;
|
|
153
|
+
}
|
|
154
|
+
*bits = ( (uint64_t) e2 << 52 ) | m;
|
|
155
|
+
return 1;
|
|
156
|
+
}
|
|
157
|
+
#endif
|
|
158
|
+
|
|
159
|
+
/* 1 with the value at out, 0 to hand the token to ruby_strtod. */
|
|
160
|
+
static int
|
|
161
|
+
ca_decimal_token_to_double_without_strtod (const char *s, long n, double *out)
|
|
162
|
+
{
|
|
163
|
+
long i = 0;
|
|
164
|
+
int negative = 0, nd = 0, truncated = 0;
|
|
165
|
+
uint64_t w = 0;
|
|
166
|
+
int64_t q = 0, e = 0;
|
|
167
|
+
|
|
168
|
+
if ( s[i] == '+' || s[i] == '-' ) {
|
|
169
|
+
negative = ( s[i] == '-' );
|
|
170
|
+
i++;
|
|
171
|
+
}
|
|
172
|
+
for (; i < n && s[i] >= '0' && s[i] <= '9'; i++) {
|
|
173
|
+
unsigned d = (unsigned) ( s[i] - '0' );
|
|
174
|
+
if ( w == 0 && d == 0 ) continue;
|
|
175
|
+
if ( nd < 19 ) { w = w * 10 + d; nd++; }
|
|
176
|
+
else { q++; truncated |= ( d != 0 ); }
|
|
177
|
+
}
|
|
178
|
+
if ( i < n && s[i] == '.' ) {
|
|
179
|
+
for (i++; i < n && s[i] >= '0' && s[i] <= '9'; i++) {
|
|
180
|
+
unsigned d = (unsigned) ( s[i] - '0' );
|
|
181
|
+
if ( w == 0 && d == 0 ) { q--; continue; }
|
|
182
|
+
if ( nd < 19 ) { w = w * 10 + d; nd++; q--; }
|
|
183
|
+
else { truncated |= ( d != 0 ); }
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if ( i < n && ( s[i] == 'e' || s[i] == 'E' ) ) {
|
|
187
|
+
int eneg = 0;
|
|
188
|
+
i++;
|
|
189
|
+
if ( s[i] == '+' || s[i] == '-' ) {
|
|
190
|
+
eneg = ( s[i] == '-' );
|
|
191
|
+
i++;
|
|
192
|
+
}
|
|
193
|
+
for (; i < n; i++) {
|
|
194
|
+
if ( e < 100000 ) {
|
|
195
|
+
e = e * 10 + ( s[i] - '0' );
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
q += eneg ? -e : e;
|
|
199
|
+
}
|
|
200
|
+
if ( truncated ) {
|
|
201
|
+
return 0;
|
|
202
|
+
}
|
|
203
|
+
if ( w == 0 ) {
|
|
204
|
+
*out = negative ? -0.0 : 0.0;
|
|
205
|
+
return 1;
|
|
206
|
+
}
|
|
207
|
+
if ( w <= ( 1ULL << 53 ) && q >= -22 && q <= 22 ) {
|
|
208
|
+
double d = (double) w;
|
|
209
|
+
d = ( q >= 0 ) ? d * ca_exact_pow10[q] : d / ca_exact_pow10[-q];
|
|
210
|
+
*out = negative ? -d : d;
|
|
211
|
+
return 1;
|
|
212
|
+
}
|
|
213
|
+
#if defined(__SIZEOF_INT128__)
|
|
214
|
+
{
|
|
215
|
+
uint64_t bits;
|
|
216
|
+
double d;
|
|
217
|
+
if ( ! ca_decimal_to_double_eisel_lemire(q, w, &bits) ) {
|
|
218
|
+
return 0;
|
|
219
|
+
}
|
|
220
|
+
memcpy(&d, &bits, sizeof(d));
|
|
221
|
+
*out = negative ? -d : d;
|
|
222
|
+
return 1;
|
|
223
|
+
}
|
|
224
|
+
#else
|
|
225
|
+
return 0;
|
|
226
|
+
#endif
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
static double
|
|
230
|
+
ca_decimal_token_to_double (const char *s, long n, const char *buf)
|
|
231
|
+
{
|
|
232
|
+
double d;
|
|
233
|
+
if ( ca_decimal_token_to_double_without_strtod(s, n, &d) ) {
|
|
234
|
+
return d;
|
|
235
|
+
}
|
|
236
|
+
return ruby_strtod(buf, NULL);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
enum {
|
|
240
|
+
CA_DECIMAL_OK = 0,
|
|
241
|
+
CA_DECIMAL_BLANK,
|
|
242
|
+
CA_DECIMAL_UNREADABLE,
|
|
243
|
+
CA_DECIMAL_OUT_OF_RANGE
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
static int
|
|
247
|
+
ca_decimal_is_space (char c)
|
|
248
|
+
{
|
|
249
|
+
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
|
|
250
|
+
|| c == '\v' || c == '\f';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
static void
|
|
254
|
+
ca_decimal_trim (const char **str, long *len)
|
|
255
|
+
{
|
|
256
|
+
const char *s = *str;
|
|
257
|
+
long n = *len;
|
|
258
|
+
while ( n > 0 && ca_decimal_is_space(s[0]) ) {
|
|
259
|
+
s++;
|
|
260
|
+
n--;
|
|
261
|
+
}
|
|
262
|
+
while ( n > 0 && ca_decimal_is_space(s[n-1]) ) {
|
|
263
|
+
n--;
|
|
264
|
+
}
|
|
265
|
+
*str = s;
|
|
266
|
+
*len = n;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/* A decimal number whose value is exactly an integer, into a sign and a
|
|
270
|
+
magnitude. The digits are read with the decimal point moved by the
|
|
271
|
+
exponent: those left of it form the magnitude, those right of it must all
|
|
272
|
+
be zero. Returns CA_DECIMAL_OK, CA_DECIMAL_UNREADABLE, or
|
|
273
|
+
CA_DECIMAL_OUT_OF_RANGE for a magnitude beyond uint64. */
|
|
274
|
+
static int
|
|
275
|
+
ca_decimal_integer (const char *s, long n, int *negative, uint64_t *magnitude)
|
|
276
|
+
{
|
|
277
|
+
long i = 0, int_start, int_end, frac_start, frac_end;
|
|
278
|
+
long nint, total, point, exponent = 0, k;
|
|
279
|
+
int exponent_negative = 0;
|
|
280
|
+
uint64_t v = 0;
|
|
281
|
+
*negative = 0;
|
|
282
|
+
if ( i < n && ( s[i] == '+' || s[i] == '-' ) ) {
|
|
283
|
+
*negative = ( s[i] == '-' );
|
|
284
|
+
i++;
|
|
285
|
+
}
|
|
286
|
+
int_start = i;
|
|
287
|
+
while ( i < n && s[i] >= '0' && s[i] <= '9' ) {
|
|
288
|
+
i++;
|
|
289
|
+
}
|
|
290
|
+
int_end = frac_start = frac_end = i;
|
|
291
|
+
if ( i < n && s[i] == '.' ) {
|
|
292
|
+
i++;
|
|
293
|
+
frac_start = i;
|
|
294
|
+
while ( i < n && s[i] >= '0' && s[i] <= '9' ) {
|
|
295
|
+
i++;
|
|
296
|
+
}
|
|
297
|
+
frac_end = i;
|
|
298
|
+
}
|
|
299
|
+
nint = int_end - int_start;
|
|
300
|
+
total = nint + ( frac_end - frac_start );
|
|
301
|
+
if ( total == 0 ) {
|
|
302
|
+
return CA_DECIMAL_UNREADABLE;
|
|
303
|
+
}
|
|
304
|
+
if ( i < n && ( s[i] == 'e' || s[i] == 'E' ) ) {
|
|
305
|
+
long exponent_digits = 0;
|
|
306
|
+
i++;
|
|
307
|
+
if ( i < n && ( s[i] == '+' || s[i] == '-' ) ) {
|
|
308
|
+
exponent_negative = ( s[i] == '-' );
|
|
309
|
+
i++;
|
|
310
|
+
}
|
|
311
|
+
while ( i < n && s[i] >= '0' && s[i] <= '9' ) {
|
|
312
|
+
if ( exponent < 1000000 ) { /* saturate; far past any fit */
|
|
313
|
+
exponent = exponent * 10 + ( s[i] - '0' );
|
|
314
|
+
}
|
|
315
|
+
i++;
|
|
316
|
+
exponent_digits++;
|
|
317
|
+
}
|
|
318
|
+
if ( exponent_digits == 0 ) {
|
|
319
|
+
return CA_DECIMAL_UNREADABLE;
|
|
320
|
+
}
|
|
321
|
+
if ( exponent_negative ) {
|
|
322
|
+
exponent = - exponent;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if ( i != n ) {
|
|
326
|
+
return CA_DECIMAL_UNREADABLE;
|
|
327
|
+
}
|
|
328
|
+
point = nint + exponent;
|
|
329
|
+
for (k = 0; k < total; k++) {
|
|
330
|
+
char c = ( k < nint ) ? s[int_start + k] : s[frac_start + k - nint];
|
|
331
|
+
unsigned d = (unsigned) ( c - '0' );
|
|
332
|
+
if ( k >= point ) {
|
|
333
|
+
if ( d != 0 ) {
|
|
334
|
+
return CA_DECIMAL_UNREADABLE; /* a fractional part */
|
|
335
|
+
}
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
if ( v > ( UINT64_MAX - d ) / 10 ) {
|
|
339
|
+
return CA_DECIMAL_OUT_OF_RANGE;
|
|
340
|
+
}
|
|
341
|
+
v = v * 10 + d;
|
|
342
|
+
}
|
|
343
|
+
for (k = total; k < point && v != 0; k++) {
|
|
344
|
+
if ( v > UINT64_MAX / 10 ) {
|
|
345
|
+
return CA_DECIMAL_OUT_OF_RANGE;
|
|
346
|
+
}
|
|
347
|
+
v *= 10;
|
|
348
|
+
}
|
|
349
|
+
*magnitude = v;
|
|
350
|
+
return CA_DECIMAL_OK;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/* Whether s could be nan / inf / infinity: a letter after an optional sign. */
|
|
354
|
+
static int
|
|
355
|
+
ca_decimal_may_be_word (const char *s, long n)
|
|
356
|
+
{
|
|
357
|
+
long i = ( s[0] == '+' || s[0] == '-' ) ? 1 : 0;
|
|
358
|
+
return i < n && ( ( s[i] | 0x20 ) == 'n' || ( s[i] | 0x20 ) == 'i' );
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* A decimal float, written to out. With out NULL, only whether s is one. */
|
|
362
|
+
static int
|
|
363
|
+
ca_decimal_float (const char *s, long n, double *out)
|
|
364
|
+
{
|
|
365
|
+
char buf[64];
|
|
366
|
+
long i = 0, digits = 0;
|
|
367
|
+
double nonfinite;
|
|
368
|
+
if ( n == 0 ) {
|
|
369
|
+
return 0;
|
|
370
|
+
}
|
|
371
|
+
if ( n <= 9 && ca_decimal_may_be_word(s, n) ) { /* longest: "+infinity" */
|
|
372
|
+
memcpy(buf, s, n);
|
|
373
|
+
buf[n] = '\0';
|
|
374
|
+
if ( ca_str_nonfinite(buf, &nonfinite) ) {
|
|
375
|
+
if ( out ) {
|
|
376
|
+
*out = nonfinite;
|
|
377
|
+
}
|
|
378
|
+
return 1;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if ( s[i] == '+' || s[i] == '-' ) {
|
|
382
|
+
i++;
|
|
383
|
+
}
|
|
384
|
+
while ( i < n && s[i] >= '0' && s[i] <= '9' ) {
|
|
385
|
+
i++;
|
|
386
|
+
digits++;
|
|
387
|
+
}
|
|
388
|
+
if ( i < n && s[i] == '.' ) {
|
|
389
|
+
i++;
|
|
390
|
+
while ( i < n && s[i] >= '0' && s[i] <= '9' ) {
|
|
391
|
+
i++;
|
|
392
|
+
digits++;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if ( digits == 0 ) {
|
|
396
|
+
return 0;
|
|
397
|
+
}
|
|
398
|
+
if ( i < n && ( s[i] == 'e' || s[i] == 'E' ) ) {
|
|
399
|
+
long exponent_digits = 0;
|
|
400
|
+
i++;
|
|
401
|
+
if ( i < n && ( s[i] == '+' || s[i] == '-' ) ) {
|
|
402
|
+
i++;
|
|
403
|
+
}
|
|
404
|
+
while ( i < n && s[i] >= '0' && s[i] <= '9' ) {
|
|
405
|
+
i++;
|
|
406
|
+
exponent_digits++;
|
|
407
|
+
}
|
|
408
|
+
if ( exponent_digits == 0 ) {
|
|
409
|
+
return 0;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if ( i != n ) {
|
|
413
|
+
return 0;
|
|
414
|
+
}
|
|
415
|
+
if ( out == NULL ) {
|
|
416
|
+
return 1;
|
|
417
|
+
}
|
|
418
|
+
/* The token is validated, so the reader sees nothing but a decimal
|
|
419
|
+
number. */
|
|
420
|
+
if ( n < (long) sizeof(buf) ) {
|
|
421
|
+
memcpy(buf, s, n);
|
|
422
|
+
buf[n] = '\0';
|
|
423
|
+
*out = ca_decimal_token_to_double(s, n, buf);
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
volatile VALUE token = rb_str_new(s, n);
|
|
427
|
+
*out = ruby_strtod(RSTRING_PTR(token), NULL);
|
|
428
|
+
}
|
|
429
|
+
return 1;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
static int
|
|
433
|
+
ca_decimal_fits (int8_t data_type, int negative, uint64_t magnitude)
|
|
434
|
+
{
|
|
435
|
+
uint64_t positive_max, negative_max;
|
|
436
|
+
switch ( data_type ) {
|
|
437
|
+
case CA_INT8: positive_max = INT8_MAX; negative_max = (uint64_t) INT8_MAX + 1; break;
|
|
438
|
+
case CA_INT16: positive_max = INT16_MAX; negative_max = (uint64_t) INT16_MAX + 1; break;
|
|
439
|
+
case CA_INT32: positive_max = INT32_MAX; negative_max = (uint64_t) INT32_MAX + 1; break;
|
|
440
|
+
case CA_INT64: positive_max = INT64_MAX; negative_max = (uint64_t) INT64_MAX + 1; break;
|
|
441
|
+
case CA_UINT8: positive_max = UINT8_MAX; negative_max = 0; break;
|
|
442
|
+
case CA_UINT16: positive_max = UINT16_MAX; negative_max = 0; break;
|
|
443
|
+
case CA_UINT32: positive_max = UINT32_MAX; negative_max = 0; break;
|
|
444
|
+
case CA_UINT64: positive_max = UINT64_MAX; negative_max = 0; break;
|
|
445
|
+
default:
|
|
446
|
+
return 0;
|
|
447
|
+
}
|
|
448
|
+
return negative ? ( magnitude <= negative_max ) : ( magnitude <= positive_max );
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/* Store a value that ca_decimal_fits accepted. */
|
|
452
|
+
static void
|
|
453
|
+
ca_decimal_store_integer (int8_t data_type, char *ptr, ca_size_t i,
|
|
454
|
+
int negative, uint64_t magnitude)
|
|
455
|
+
{
|
|
456
|
+
int64_t v;
|
|
457
|
+
if ( negative && magnitude > 0 ) {
|
|
458
|
+
v = - (int64_t) ( magnitude - 1 ) - 1;
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
v = (int64_t) magnitude;
|
|
462
|
+
}
|
|
463
|
+
switch ( data_type ) {
|
|
464
|
+
case CA_INT8: ((int8_t *) ptr)[i] = (int8_t) v; break;
|
|
465
|
+
case CA_INT16: ((int16_t *) ptr)[i] = (int16_t) v; break;
|
|
466
|
+
case CA_INT32: ((int32_t *) ptr)[i] = (int32_t) v; break;
|
|
467
|
+
case CA_INT64: ((int64_t *) ptr)[i] = v; break;
|
|
468
|
+
case CA_UINT8: ((uint8_t *) ptr)[i] = (uint8_t) magnitude; break;
|
|
469
|
+
case CA_UINT16: ((uint16_t *) ptr)[i] = (uint16_t) magnitude; break;
|
|
470
|
+
case CA_UINT32: ((uint32_t *) ptr)[i] = (uint32_t) magnitude; break;
|
|
471
|
+
case CA_UINT64: ((uint64_t *) ptr)[i] = magnitude; break;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/* Whether v is a real number other than an Integer or a Float -- a Rational,
|
|
476
|
+
a BigDecimal -- which reads as the value it stands for. */
|
|
477
|
+
static int
|
|
478
|
+
ca_decimal_other_real (VALUE v)
|
|
479
|
+
{
|
|
480
|
+
return RTEST(rb_obj_is_kind_of(v, rb_cNumeric))
|
|
481
|
+
&& RTEST(rb_funcall(v, rb_intern("real?"), 0));
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
static VALUE
|
|
485
|
+
ca_decimal_truncate (VALUE v)
|
|
486
|
+
{
|
|
487
|
+
return rb_funcall(v, rb_intern("truncate"), 0);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/* A non-String cell as an integer: an Integer, or a Float or another real
|
|
491
|
+
number with no fractional part, that the target can hold. */
|
|
492
|
+
static int
|
|
493
|
+
ca_decimal_object_integer (VALUE v, int *negative, uint64_t *magnitude)
|
|
494
|
+
{
|
|
495
|
+
if ( ! RB_INTEGER_TYPE_P(v) && ! RB_FLOAT_TYPE_P(v) && ca_decimal_other_real(v) ) {
|
|
496
|
+
/* truncate raises for a NaN or infinite BigDecimal, which reads as
|
|
497
|
+
nothing an integer can hold. */
|
|
498
|
+
int state = 0;
|
|
499
|
+
VALUE whole = rb_protect(ca_decimal_truncate, v, &state);
|
|
500
|
+
if ( state ) {
|
|
501
|
+
rb_set_errinfo(Qnil);
|
|
502
|
+
return 0;
|
|
503
|
+
}
|
|
504
|
+
if ( ! RB_INTEGER_TYPE_P(whole) || ! RTEST(rb_equal(whole, v)) ) {
|
|
505
|
+
return 0;
|
|
506
|
+
}
|
|
507
|
+
v = whole;
|
|
508
|
+
}
|
|
509
|
+
if ( RB_INTEGER_TYPE_P(v) ) {
|
|
510
|
+
VALUE zero = INT2FIX(0);
|
|
511
|
+
*negative = RTEST(rb_funcall(v, '<', 1, zero));
|
|
512
|
+
if ( *negative ) {
|
|
513
|
+
v = rb_funcall(v, rb_intern("-@"), 0);
|
|
514
|
+
}
|
|
515
|
+
if ( RTEST(rb_funcall(v, '>', 1, ULL2NUM(UINT64_MAX))) ) {
|
|
516
|
+
return 0;
|
|
517
|
+
}
|
|
518
|
+
*magnitude = NUM2ULL(v);
|
|
519
|
+
return 1;
|
|
520
|
+
}
|
|
521
|
+
if ( RB_FLOAT_TYPE_P(v) ) {
|
|
522
|
+
double d = RFLOAT_VALUE(v);
|
|
523
|
+
if ( d != d || d != floor(d) || fabs(d) >= 18446744073709551616.0 ) {
|
|
524
|
+
return 0;
|
|
525
|
+
}
|
|
526
|
+
*negative = ( d < 0 );
|
|
527
|
+
*magnitude = (uint64_t) fabs(d);
|
|
528
|
+
return 1;
|
|
529
|
+
}
|
|
530
|
+
return 0;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/* A String as one value of data_type (an integer or float type), written
|
|
534
|
+
to out. */
|
|
535
|
+
static int
|
|
536
|
+
ca_decimal_read_bytes_as (const char *s, long n, int8_t data_type, void *out)
|
|
537
|
+
{
|
|
538
|
+
ca_decimal_trim(&s, &n);
|
|
539
|
+
if ( n == 0 ) {
|
|
540
|
+
return CA_DECIMAL_BLANK;
|
|
541
|
+
}
|
|
542
|
+
if ( data_type == CA_FLOAT32 || data_type == CA_FLOAT64 ) {
|
|
543
|
+
double d;
|
|
544
|
+
if ( ! ca_decimal_float(s, n, &d) ) {
|
|
545
|
+
return CA_DECIMAL_UNREADABLE;
|
|
546
|
+
}
|
|
547
|
+
if ( data_type == CA_FLOAT32 ) {
|
|
548
|
+
*(float32_t *) out = (float32_t) d;
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
*(float64_t *) out = d;
|
|
552
|
+
}
|
|
553
|
+
return CA_DECIMAL_OK;
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
int negative = 0;
|
|
557
|
+
uint64_t magnitude = 0;
|
|
558
|
+
int rc = ca_decimal_integer(s, n, &negative, &magnitude);
|
|
559
|
+
if ( rc != CA_DECIMAL_OK ) {
|
|
560
|
+
return rc;
|
|
561
|
+
}
|
|
562
|
+
if ( ! ca_decimal_fits(data_type, negative, magnitude) ) {
|
|
563
|
+
return CA_DECIMAL_OUT_OF_RANGE;
|
|
564
|
+
}
|
|
565
|
+
ca_decimal_store_integer(data_type, (char *) out, 0, negative, magnitude);
|
|
566
|
+
return CA_DECIMAL_OK;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
static int
|
|
571
|
+
ca_decimal_string_read (VALUE str, int8_t data_type, void *out)
|
|
572
|
+
{
|
|
573
|
+
return ca_decimal_read_bytes_as(RSTRING_PTR(str), RSTRING_LEN(str), data_type, out);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/* The to_type reader: 1 with the value at out, or 0 for a cell that
|
|
577
|
+
becomes UNDEF. */
|
|
578
|
+
int
|
|
579
|
+
ca_decimal_string_to (VALUE str, int8_t data_type, void *out)
|
|
580
|
+
{
|
|
581
|
+
return ca_decimal_string_read(str, data_type, out) == CA_DECIMAL_OK;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/* The store reader: the value at out, or a raise. */
|
|
585
|
+
void
|
|
586
|
+
ca_decimal_string_store (VALUE str, int8_t data_type, void *out)
|
|
587
|
+
{
|
|
588
|
+
switch ( ca_decimal_string_read(str, data_type, out) ) {
|
|
589
|
+
case CA_DECIMAL_OK:
|
|
590
|
+
return;
|
|
591
|
+
case CA_DECIMAL_OUT_OF_RANGE:
|
|
592
|
+
rb_raise(rb_eRangeError, "%+"PRIsVALUE" is out of range for %s",
|
|
593
|
+
str, ca_type_name[data_type]);
|
|
594
|
+
default:
|
|
595
|
+
rb_raise(rb_eArgError, "%+"PRIsVALUE" cannot be read as %s",
|
|
596
|
+
str, ca_type_name[data_type]);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
37
599
|
|
|
38
600
|
boolean8_t
|
|
39
601
|
OBJ2BOOL (VALUE v)
|
|
40
602
|
{
|
|
41
|
-
if ( v == Qfalse
|
|
603
|
+
if ( v == Qfalse ) {
|
|
42
604
|
return 0;
|
|
43
605
|
}
|
|
44
606
|
else if ( v == Qtrue ) {
|
|
@@ -99,25 +661,20 @@ OBJ2DBL (VALUE val)
|
|
|
99
661
|
switch ( TYPE(val) ) {
|
|
100
662
|
case T_FLOAT:
|
|
101
663
|
return NUM2DBL(val);
|
|
102
|
-
case T_NIL:
|
|
103
|
-
return 0.0/0.0;
|
|
104
664
|
case T_STRING: {
|
|
105
665
|
double d;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if ( ca_str_nonfinite(str, &d) ) {
|
|
109
|
-
return d;
|
|
110
|
-
}
|
|
111
|
-
return rb_cstr_to_dbl(str, 0);
|
|
666
|
+
ca_decimal_string_store(val, CA_FLOAT64, &d);
|
|
667
|
+
return d;
|
|
112
668
|
}
|
|
113
669
|
default:
|
|
114
670
|
return NUM2DBL(rb_Float(val));
|
|
115
671
|
}
|
|
116
672
|
}
|
|
117
673
|
|
|
118
|
-
/* rb_protect bodies: Kernel#Float / Kernel#Integer applied to one value
|
|
119
|
-
Used by the mask-aware object->numeric parsers
|
|
120
|
-
error is caught (and turned into a masked cell)
|
|
674
|
+
/* rb_protect bodies: Kernel#Float / Kernel#Integer applied to one value
|
|
675
|
+
that is not a String. Used by the mask-aware object->numeric parsers
|
|
676
|
+
below so a conversion error is caught (and turned into a masked cell)
|
|
677
|
+
rather than raised. */
|
|
121
678
|
static VALUE
|
|
122
679
|
ca_kernel_float (VALUE v)
|
|
123
680
|
{
|
|
@@ -130,12 +687,71 @@ ca_kernel_integer (VALUE v)
|
|
|
130
687
|
return rb_Integer(v);
|
|
131
688
|
}
|
|
132
689
|
|
|
690
|
+
/* Complex#to_s writes a part that is not finite as "NaN" or "Infinity" and
|
|
691
|
+
then marks the imaginary part with "*i" ("1.0+Infinity*i", "NaN+0i"),
|
|
692
|
+
which Complex() does not read back. Read that form as two decimal
|
|
693
|
+
numbers: the imaginary part starts at the last sign that is not the
|
|
694
|
+
first character and not an exponent's. Returns 0 when the text is not
|
|
695
|
+
of that form. */
|
|
696
|
+
static int
|
|
697
|
+
ca_str_to_cmplx_nonfinite (VALUE str, double complex *out)
|
|
698
|
+
{
|
|
699
|
+
const char *s = RSTRING_PTR(str);
|
|
700
|
+
long n = RSTRING_LEN(str), k;
|
|
701
|
+
double re, im;
|
|
702
|
+
volatile VALUE vre, vim;
|
|
703
|
+
while ( n > 0 && ( s[0] == ' ' || s[0] == '\t' ) ) { s++; n--; }
|
|
704
|
+
while ( n > 0 && ( s[n-1] == ' ' || s[n-1] == '\t' ) ) { n--; }
|
|
705
|
+
if ( n < 2 || s[n-1] != 'i' ) {
|
|
706
|
+
return 0;
|
|
707
|
+
}
|
|
708
|
+
n -= ( n >= 2 && s[n-2] == '*' ) ? 2 : 1;
|
|
709
|
+
for ( k = n - 1; k > 0; k-- ) {
|
|
710
|
+
if ( ( s[k] == '+' || s[k] == '-' ) && s[k-1] != 'e' && s[k-1] != 'E' ) {
|
|
711
|
+
break;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
if ( k <= 0 ) {
|
|
715
|
+
return 0;
|
|
716
|
+
}
|
|
717
|
+
vre = rb_str_new(s, k);
|
|
718
|
+
vim = rb_str_new(s + k, n - k);
|
|
719
|
+
if ( ! ca_decimal_string_to(vre, CA_FLOAT64, &re)
|
|
720
|
+
|| ! ca_decimal_string_to(vim, CA_FLOAT64, &im) ) {
|
|
721
|
+
return 0;
|
|
722
|
+
}
|
|
723
|
+
*out = CMPLX(re, im);
|
|
724
|
+
return 1;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/* A real is read as a decimal number; anything else goes to Complex(). */
|
|
728
|
+
double complex
|
|
729
|
+
ca_str_to_cmplx (VALUE str)
|
|
730
|
+
{
|
|
731
|
+
volatile VALUE rstr;
|
|
732
|
+
volatile VALUE c;
|
|
733
|
+
double d;
|
|
734
|
+
double complex z;
|
|
735
|
+
if ( ca_decimal_string_to(str, CA_FLOAT64, &d) ) {
|
|
736
|
+
return (double complex) d;
|
|
737
|
+
}
|
|
738
|
+
if ( ( memchr(RSTRING_PTR(str), 'N', RSTRING_LEN(str))
|
|
739
|
+
|| memchr(RSTRING_PTR(str), 'I', RSTRING_LEN(str)) )
|
|
740
|
+
&& ca_str_to_cmplx_nonfinite(str, &z) ) {
|
|
741
|
+
return z;
|
|
742
|
+
}
|
|
743
|
+
rstr = rb_funcall(str, rb_intern("strip"), 0);
|
|
744
|
+
c = rb_funcall(rb_mKernel, rb_intern("Complex"), 1, rstr);
|
|
745
|
+
return CMPLX(NUM2DBL(rb_complex_real(c)), NUM2DBL(rb_complex_imag(c)));
|
|
746
|
+
}
|
|
747
|
+
|
|
133
748
|
/* Object -> double with parse-failure signalling. Returns 1 and sets *out
|
|
134
749
|
on success; returns 0 when the cell cannot be parsed, in which case the
|
|
135
|
-
caller writes UNDEF (mask) for that cell. nil and
|
|
136
|
-
strings/objects fail; already-numeric values and
|
|
137
|
-
|
|
138
|
-
|
|
750
|
+
caller writes UNDEF (mask) for that cell. nil and unreadable
|
|
751
|
+
strings/objects fail; already-numeric values succeed, and a String is
|
|
752
|
+
read as a decimal number. This is the reading path of to_type from an
|
|
753
|
+
object array, where a cell with no number in it is a missing value; a
|
|
754
|
+
store (OBJ2DBL) raises instead. */
|
|
139
755
|
int
|
|
140
756
|
ca_obj2dbl_ok (VALUE val, double *out)
|
|
141
757
|
{
|
|
@@ -147,10 +763,7 @@ ca_obj2dbl_ok (VALUE val, double *out)
|
|
|
147
763
|
return 1;
|
|
148
764
|
}
|
|
149
765
|
if ( RB_TYPE_P(val, T_STRING) ) {
|
|
150
|
-
|
|
151
|
-
if ( ca_str_nonfinite(StringValuePtr(rstr), out) ) {
|
|
152
|
-
return 1;
|
|
153
|
-
}
|
|
766
|
+
return ca_decimal_string_to(val, CA_FLOAT64, out);
|
|
154
767
|
}
|
|
155
768
|
{
|
|
156
769
|
int state = 0;
|
|
@@ -164,98 +777,118 @@ ca_obj2dbl_ok (VALUE val, double *out)
|
|
|
164
777
|
}
|
|
165
778
|
}
|
|
166
779
|
|
|
167
|
-
/* Object ->
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
780
|
+
/* Object -> complex with parse-failure signalling: the complex sibling of
|
|
781
|
+
ca_obj2dbl_ok. A cell is read as a store reads it (a real as a decimal
|
|
782
|
+
number, the rest as Complex()); nil and a cell that does not read fail. */
|
|
783
|
+
static VALUE
|
|
784
|
+
ca_cmplx_cell_body (VALUE v)
|
|
785
|
+
{
|
|
786
|
+
double complex z = rb_carray_num2cmplx(v);
|
|
787
|
+
return rb_dbl_complex_new(creal(z), cimag(z));
|
|
788
|
+
}
|
|
789
|
+
|
|
173
790
|
int
|
|
174
|
-
|
|
791
|
+
ca_obj2cmplx_ok (VALUE val, double complex *out)
|
|
175
792
|
{
|
|
793
|
+
int state = 0;
|
|
794
|
+
volatile VALUE r;
|
|
176
795
|
if ( NIL_P(val) ) {
|
|
177
796
|
return 0;
|
|
178
797
|
}
|
|
798
|
+
r = rb_protect(ca_cmplx_cell_body, val, &state);
|
|
799
|
+
if ( state ) {
|
|
800
|
+
rb_set_errinfo(Qnil);
|
|
801
|
+
return 0;
|
|
802
|
+
}
|
|
803
|
+
*out = CMPLX(NUM2DBL(rb_complex_real(r)), NUM2DBL(rb_complex_imag(r)));
|
|
804
|
+
return 1;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/* Object -> integer with parse-failure signalling. Same contract as
|
|
808
|
+
ca_obj2dbl_ok: 1 + *out on success, 0 (mask) on failure. A String is
|
|
809
|
+
read as a decimal number ("1.5" fails, no truncation); any other object
|
|
810
|
+
goes through Integer(). nil fails. A valid Integer that overflows the
|
|
811
|
+
widest C integer still raises (a domain error, not a parse failure). */
|
|
812
|
+
static int
|
|
813
|
+
ca_obj2integer_ok (VALUE val, int8_t wide_type, void *wide, VALUE *integer)
|
|
814
|
+
{
|
|
815
|
+
int state = 0;
|
|
816
|
+
if ( NIL_P(val) ) {
|
|
817
|
+
return 0;
|
|
818
|
+
}
|
|
819
|
+
if ( RB_TYPE_P(val, T_STRING) ) {
|
|
820
|
+
return ca_decimal_string_to(val, wide_type, wide);
|
|
821
|
+
}
|
|
822
|
+
*integer = rb_protect(ca_kernel_integer, val, &state);
|
|
823
|
+
if ( state ) {
|
|
824
|
+
rb_set_errinfo(Qnil);
|
|
825
|
+
return 0;
|
|
826
|
+
}
|
|
827
|
+
return 1;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
int
|
|
831
|
+
rb_obj2long_ok (VALUE val, long *out)
|
|
832
|
+
{
|
|
833
|
+
int64_t wide;
|
|
834
|
+
VALUE integer = Qnil;
|
|
179
835
|
if ( RB_TYPE_P(val, T_FIXNUM) ) {
|
|
180
836
|
*out = NUM2LONG(val);
|
|
181
837
|
return 1;
|
|
182
838
|
}
|
|
183
|
-
{
|
|
184
|
-
|
|
185
|
-
volatile VALUE r = rb_protect(ca_kernel_integer, val, &state);
|
|
186
|
-
if ( state ) {
|
|
187
|
-
rb_set_errinfo(Qnil);
|
|
188
|
-
return 0;
|
|
189
|
-
}
|
|
190
|
-
*out = NUM2LONG(r);
|
|
191
|
-
return 1;
|
|
839
|
+
if ( ! ca_obj2integer_ok(val, CA_INT64, &wide, &integer) ) {
|
|
840
|
+
return 0;
|
|
192
841
|
}
|
|
842
|
+
*out = NIL_P(integer) ? (long) wide : NUM2LONG(integer);
|
|
843
|
+
return 1;
|
|
193
844
|
}
|
|
194
845
|
|
|
195
846
|
int
|
|
196
847
|
rb_obj2ulong_ok (VALUE val, unsigned long *out)
|
|
197
848
|
{
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
849
|
+
uint64_t wide;
|
|
850
|
+
VALUE integer = Qnil;
|
|
201
851
|
if ( RB_TYPE_P(val, T_FIXNUM) ) {
|
|
202
852
|
*out = NUM2ULONG(val);
|
|
203
853
|
return 1;
|
|
204
854
|
}
|
|
205
|
-
{
|
|
206
|
-
|
|
207
|
-
volatile VALUE r = rb_protect(ca_kernel_integer, val, &state);
|
|
208
|
-
if ( state ) {
|
|
209
|
-
rb_set_errinfo(Qnil);
|
|
210
|
-
return 0;
|
|
211
|
-
}
|
|
212
|
-
*out = NUM2ULONG(r);
|
|
213
|
-
return 1;
|
|
855
|
+
if ( ! ca_obj2integer_ok(val, CA_UINT64, &wide, &integer) ) {
|
|
856
|
+
return 0;
|
|
214
857
|
}
|
|
858
|
+
*out = NIL_P(integer) ? (unsigned long) wide : NUM2ULONG(integer);
|
|
859
|
+
return 1;
|
|
215
860
|
}
|
|
216
861
|
|
|
217
862
|
int
|
|
218
863
|
rb_obj2ll_ok (VALUE val, long long *out)
|
|
219
864
|
{
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
865
|
+
int64_t wide;
|
|
866
|
+
VALUE integer = Qnil;
|
|
223
867
|
if ( RB_TYPE_P(val, T_FIXNUM) ) {
|
|
224
868
|
*out = NUM2LL(val);
|
|
225
869
|
return 1;
|
|
226
870
|
}
|
|
227
|
-
{
|
|
228
|
-
|
|
229
|
-
volatile VALUE r = rb_protect(ca_kernel_integer, val, &state);
|
|
230
|
-
if ( state ) {
|
|
231
|
-
rb_set_errinfo(Qnil);
|
|
232
|
-
return 0;
|
|
233
|
-
}
|
|
234
|
-
*out = NUM2LL(r);
|
|
235
|
-
return 1;
|
|
871
|
+
if ( ! ca_obj2integer_ok(val, CA_INT64, &wide, &integer) ) {
|
|
872
|
+
return 0;
|
|
236
873
|
}
|
|
874
|
+
*out = NIL_P(integer) ? (long long) wide : NUM2LL(integer);
|
|
875
|
+
return 1;
|
|
237
876
|
}
|
|
238
877
|
|
|
239
878
|
int
|
|
240
879
|
rb_obj2ull_ok (VALUE val, unsigned long long *out)
|
|
241
880
|
{
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
881
|
+
uint64_t wide;
|
|
882
|
+
VALUE integer = Qnil;
|
|
245
883
|
if ( RB_TYPE_P(val, T_FIXNUM) ) {
|
|
246
884
|
*out = NUM2ULL(val);
|
|
247
885
|
return 1;
|
|
248
886
|
}
|
|
249
|
-
{
|
|
250
|
-
|
|
251
|
-
volatile VALUE r = rb_protect(ca_kernel_integer, val, &state);
|
|
252
|
-
if ( state ) {
|
|
253
|
-
rb_set_errinfo(Qnil);
|
|
254
|
-
return 0;
|
|
255
|
-
}
|
|
256
|
-
*out = rb_num2ull(r);
|
|
257
|
-
return 1;
|
|
887
|
+
if ( ! ca_obj2integer_ok(val, CA_UINT64, &wide, &integer) ) {
|
|
888
|
+
return 0;
|
|
258
889
|
}
|
|
890
|
+
*out = NIL_P(integer) ? (unsigned long long) wide : rb_num2ull(integer);
|
|
891
|
+
return 1;
|
|
259
892
|
}
|
|
260
893
|
|
|
261
894
|
long
|
|
@@ -267,8 +900,13 @@ rb_obj2long (VALUE val)
|
|
|
267
900
|
case T_BIGNUM:
|
|
268
901
|
return (long) NUM2LL(val);
|
|
269
902
|
case T_NIL:
|
|
270
|
-
rb_raise(rb_eTypeError, "
|
|
903
|
+
rb_raise(rb_eTypeError, "can't convert nil into Integer");
|
|
271
904
|
break;
|
|
905
|
+
case T_STRING: {
|
|
906
|
+
int64_t v;
|
|
907
|
+
ca_decimal_string_store(val, CA_INT64, &v);
|
|
908
|
+
return (long) v;
|
|
909
|
+
}
|
|
272
910
|
default:
|
|
273
911
|
return NUM2LONG(rb_Integer(val));
|
|
274
912
|
}
|
|
@@ -283,8 +921,13 @@ rb_obj2ulong (VALUE val)
|
|
|
283
921
|
case T_BIGNUM:
|
|
284
922
|
return (unsigned long) rb_num2ull(val);
|
|
285
923
|
case T_NIL:
|
|
286
|
-
rb_raise(rb_eTypeError, "
|
|
924
|
+
rb_raise(rb_eTypeError, "can't convert nil into Integer");
|
|
287
925
|
break;
|
|
926
|
+
case T_STRING: {
|
|
927
|
+
uint64_t v;
|
|
928
|
+
ca_decimal_string_store(val, CA_UINT64, &v);
|
|
929
|
+
return (unsigned long) v;
|
|
930
|
+
}
|
|
288
931
|
default:
|
|
289
932
|
return NUM2ULONG(rb_Integer(val));
|
|
290
933
|
}
|
|
@@ -297,8 +940,13 @@ rb_obj2ll (VALUE val)
|
|
|
297
940
|
case T_FIXNUM:
|
|
298
941
|
return NUM2LONG(val);
|
|
299
942
|
case T_NIL:
|
|
300
|
-
rb_raise(rb_eTypeError, "
|
|
943
|
+
rb_raise(rb_eTypeError, "can't convert nil into Integer");
|
|
301
944
|
break;
|
|
945
|
+
case T_STRING: {
|
|
946
|
+
int64_t v;
|
|
947
|
+
ca_decimal_string_store(val, CA_INT64, &v);
|
|
948
|
+
return (long long) v;
|
|
949
|
+
}
|
|
302
950
|
default:
|
|
303
951
|
return NUM2LL(rb_Integer(val));
|
|
304
952
|
}
|
|
@@ -311,8 +959,13 @@ rb_obj2ull (VALUE val)
|
|
|
311
959
|
case T_FIXNUM:
|
|
312
960
|
return NUM2ULONG(val);
|
|
313
961
|
case T_NIL:
|
|
314
|
-
rb_raise(rb_eTypeError, "
|
|
962
|
+
rb_raise(rb_eTypeError, "can't convert nil into Integer");
|
|
315
963
|
break;
|
|
964
|
+
case T_STRING: {
|
|
965
|
+
uint64_t v;
|
|
966
|
+
ca_decimal_string_store(val, CA_UINT64, &v);
|
|
967
|
+
return (unsigned long long) v;
|
|
968
|
+
}
|
|
316
969
|
default:
|
|
317
970
|
return rb_num2ull(rb_Integer(val));
|
|
318
971
|
}
|
|
@@ -334,7 +987,7 @@ ca_face_safe_check (CArray *ca)
|
|
|
334
987
|
static inline int8_t
|
|
335
988
|
ca_storage_type_of (CArray *ca)
|
|
336
989
|
{
|
|
337
|
-
|
|
990
|
+
if ( ca_face_safe_check(ca) ) ca = ca_strip_face(ca);
|
|
338
991
|
return ca ? ca->data_type : CA_FIXLEN;
|
|
339
992
|
}
|
|
340
993
|
|
|
@@ -433,7 +1086,7 @@ ca_val2val (int8_t data_type1, void *ptr1, int8_t data_type2, void *ptr2)
|
|
|
433
1086
|
/* Cast to CA_OBJECT for an array whose cells mean something other than their
|
|
434
1087
|
storage bytes: a data_class array (CARecord / CAStruct) or a Face (CATime,
|
|
435
1088
|
CAConstString, CACategorical, ...). Both decode per cell -- rb_ca_fetch_addr
|
|
436
|
-
goes through the data_class decode and
|
|
1089
|
+
goes through the data_class decode and CA_FACE_STORAGE_TO_ELEMENT_IF_FACE --
|
|
437
1090
|
so the object array holds the *surface* values (labels, not codes;
|
|
438
1091
|
CATime::Element, not serials; the string, not the descriptor bytes). Reading
|
|
439
1092
|
the storage instead is `.parent`, which stays available and explicit. Mask
|
|
@@ -558,6 +1211,33 @@ typedef struct {
|
|
|
558
1211
|
boolean8_t *scratch;
|
|
559
1212
|
} ca_to_type_ctx_t;
|
|
560
1213
|
|
|
1214
|
+
/* Marks in `m` the cells of a float or complex array that hold NaN (in
|
|
1215
|
+
either part). A NaN has no integer, and C leaves its conversion
|
|
1216
|
+
undefined. */
|
|
1217
|
+
static void
|
|
1218
|
+
ca_mark_nan (CArray *ca, boolean8_t *m)
|
|
1219
|
+
{
|
|
1220
|
+
ca_size_t i, n = ca->elements;
|
|
1221
|
+
switch ( ca->data_type ) {
|
|
1222
|
+
case CA_FLOAT32: { float32_t *p = (float32_t *) ca->ptr;
|
|
1223
|
+
for (i=0; i<n; i++) if ( isnan(p[i]) ) m[i] = 1;
|
|
1224
|
+
break; }
|
|
1225
|
+
case CA_FLOAT64: { float64_t *p = (float64_t *) ca->ptr;
|
|
1226
|
+
for (i=0; i<n; i++) if ( isnan(p[i]) ) m[i] = 1;
|
|
1227
|
+
break; }
|
|
1228
|
+
#ifdef HAVE_COMPLEX_H
|
|
1229
|
+
case CA_CMPLX64: { cmplx64_t *p = (cmplx64_t *) ca->ptr;
|
|
1230
|
+
for (i=0; i<n; i++) if ( isnan(crealf(p[i])) || isnan(cimagf(p[i])) ) m[i] = 1;
|
|
1231
|
+
break; }
|
|
1232
|
+
case CA_CMPLX128: { cmplx128_t *p = (cmplx128_t *) ca->ptr;
|
|
1233
|
+
for (i=0; i<n; i++) if ( isnan(creal(p[i])) || isnan(cimag(p[i])) ) m[i] = 1;
|
|
1234
|
+
break; }
|
|
1235
|
+
#endif
|
|
1236
|
+
default:
|
|
1237
|
+
break;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
|
|
561
1241
|
/* The cast proper, with `ca` attached. It can raise (a value the target
|
|
562
1242
|
type cannot hold), so it runs under rb_ensure. */
|
|
563
1243
|
static VALUE
|
|
@@ -565,11 +1245,16 @@ ca_to_type_cast (VALUE arg)
|
|
|
565
1245
|
{
|
|
566
1246
|
ca_to_type_ctx_t *c = (ca_to_type_ctx_t *) arg;
|
|
567
1247
|
CArray *ca = c->ca, *cb = c->cb;
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
1248
|
+
int to_integer = ( cb->data_type >= CA_INT8 && cb->data_type <= CA_UINT64 );
|
|
1249
|
+
int from_float = ( ca->data_type == CA_FLOAT32 || ca->data_type == CA_FLOAT64
|
|
1250
|
+
|| ca->data_type == CA_CMPLX64 || ca->data_type == CA_CMPLX128 );
|
|
1251
|
+
|
|
1252
|
+
if ( ( ca->data_type == CA_OBJECT
|
|
1253
|
+
&& ( to_integer
|
|
1254
|
+
|| cb->data_type == CA_FLOAT32 || cb->data_type == CA_FLOAT64
|
|
1255
|
+
|| cb->data_type == CA_CMPLX64 || cb->data_type == CA_CMPLX128 ) )
|
|
1256
|
+
|| ( from_float && to_integer ) ) {
|
|
1257
|
+
/* object -> int/float/complex: give the cast a mask buffer so an unparseable
|
|
573
1258
|
cell becomes UNDEF (see ext/carray_cast_func.rb). Cast into a
|
|
574
1259
|
scratch mask seeded from the source mask, then attach it to the
|
|
575
1260
|
output only if some cell ended up masked -- an all-valid cast keeps
|
|
@@ -585,6 +1270,13 @@ ca_to_type_cast (VALUE arg)
|
|
|
585
1270
|
else {
|
|
586
1271
|
memset(scratch, 0, ne);
|
|
587
1272
|
}
|
|
1273
|
+
/* float -> integer: a NaN cell becomes UNDEF, as an unparseable object
|
|
1274
|
+
cell does. A finite value outside the integer type is converted the
|
|
1275
|
+
way the machine's C converts it, which differs between machines. */
|
|
1276
|
+
if ( from_float ) {
|
|
1277
|
+
ca_mark_nan(ca, scratch);
|
|
1278
|
+
memset(cb->ptr, 0, ne * cb->bytes);
|
|
1279
|
+
}
|
|
588
1280
|
ca_cast_block_with_mask(ne, ca, ca->ptr, cb, cb->ptr, scratch);
|
|
589
1281
|
for (i=0; i<ne; i++) {
|
|
590
1282
|
if ( scratch[i] ) {
|
|
@@ -627,8 +1319,20 @@ ca_to_type_release (VALUE arg)
|
|
|
627
1319
|
data_type (a new entity owning its storage). User doc lives in
|
|
628
1320
|
yard-stubs/carray_cast.rb. */
|
|
629
1321
|
|
|
1322
|
+
static VALUE rb_ca_to_type_convert (int argc, VALUE *argv, VALUE self);
|
|
1323
|
+
|
|
1324
|
+
/* The converted array keeps self's attributes: the values are the same
|
|
1325
|
+
values in another representation. */
|
|
630
1326
|
static VALUE
|
|
631
1327
|
rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
|
|
1328
|
+
{
|
|
1329
|
+
VALUE obj = rb_ca_to_type_convert(argc, argv, self);
|
|
1330
|
+
rb_ca_inherit_attr(obj, self);
|
|
1331
|
+
return obj;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
static VALUE
|
|
1335
|
+
rb_ca_to_type_convert (int argc, VALUE *argv, VALUE self)
|
|
632
1336
|
{
|
|
633
1337
|
volatile VALUE obj, rtype = Qnil, ropt, rbytes = Qnil;
|
|
634
1338
|
CArray *ca, *cb;
|
|
@@ -657,8 +1361,8 @@ rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
|
|
|
657
1361
|
Numeric Face is not routed here -- its surface *is* its storage, so the
|
|
658
1362
|
ordinary cast below is already right. */
|
|
659
1363
|
if ( ca_is_face(ca) && ca->data_type == CA_FIXLEN ) {
|
|
660
|
-
return
|
|
661
|
-
|
|
1364
|
+
return rb_ca_to_type_convert(argc, argv,
|
|
1365
|
+
rb_ca_face_numeric_projection(self, ca));
|
|
662
1366
|
}
|
|
663
1367
|
|
|
664
1368
|
ca_update_mask(ca);
|
|
@@ -676,7 +1380,7 @@ rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
|
|
|
676
1380
|
ctx.ca = ca;
|
|
677
1381
|
ctx.cb = cb;
|
|
678
1382
|
ctx.scratch = NULL;
|
|
679
|
-
ca_attach(ca);
|
|
1383
|
+
ca_attach(ca); /* window: released by ca_to_type_release under rb_ensure */
|
|
680
1384
|
rb_ensure(ca_to_type_cast, (VALUE) &ctx, ca_to_type_release, (VALUE) &ctx);
|
|
681
1385
|
|
|
682
1386
|
/* When rtype is a data_class (e.g. CAStruct subclass), wrap the
|
|
@@ -1081,30 +1785,30 @@ rb_ca_ptr2obj (VALUE self, void *ptr)
|
|
|
1081
1785
|
}
|
|
1082
1786
|
|
|
1083
1787
|
/* Surface -> storage-domain conversion for a Face store (mirror of the
|
|
1084
|
-
|
|
1788
|
+
storage_to_element read hook). Non-Face `ca` returns `obj` unchanged, so
|
|
1085
1789
|
the non-Face store path is untouched. For a Face, the per-obj_type C
|
|
1086
1790
|
table is consulted first (fast path); if none is registered, the Ruby
|
|
1087
|
-
`
|
|
1791
|
+
`element_to_storage` method is called when defined. A Face that recognizes
|
|
1088
1792
|
`obj` returns a storage-domain value (e.g. an Integer in its unit); a bare
|
|
1089
1793
|
Integer / String falls through unchanged to the storage cast. */
|
|
1090
1794
|
VALUE
|
|
1091
|
-
|
|
1795
|
+
ca_face_element_to_storage (VALUE self, CArray *ca, VALUE obj)
|
|
1092
1796
|
{
|
|
1093
|
-
|
|
1797
|
+
ca_face_element_to_storage_fn fn;
|
|
1094
1798
|
if ( ! ca_face_safe_check(ca) || obj == CA_UNDEF ) {
|
|
1095
1799
|
return obj;
|
|
1096
1800
|
}
|
|
1097
|
-
fn =
|
|
1801
|
+
fn = ca_face_element_to_storage_table[ca->obj_type];
|
|
1098
1802
|
if ( fn != NULL ) {
|
|
1099
1803
|
return fn(self, obj);
|
|
1100
1804
|
}
|
|
1101
1805
|
else {
|
|
1102
|
-
static ID
|
|
1103
|
-
if (
|
|
1104
|
-
|
|
1806
|
+
static ID id_element_to_storage = 0;
|
|
1807
|
+
if ( id_element_to_storage == 0 ) {
|
|
1808
|
+
id_element_to_storage = rb_intern("element_to_storage");
|
|
1105
1809
|
}
|
|
1106
|
-
if ( rb_respond_to(self,
|
|
1107
|
-
return rb_funcall(self,
|
|
1810
|
+
if ( rb_respond_to(self, id_element_to_storage) ) {
|
|
1811
|
+
return rb_funcall(self, id_element_to_storage, 1, obj);
|
|
1108
1812
|
}
|
|
1109
1813
|
}
|
|
1110
1814
|
return obj;
|
|
@@ -1127,7 +1831,7 @@ rb_ca_obj2ptr (VALUE self, VALUE obj, void *ptr)
|
|
|
1127
1831
|
if ( ca_face_safe_check(ca) ) {
|
|
1128
1832
|
/* Face write hook: turn a surface value object (Scalar / Time /
|
|
1129
1833
|
DateTime) into a storage-domain value the cast below consumes. */
|
|
1130
|
-
obj =
|
|
1834
|
+
obj = ca_face_element_to_storage(self, ca, obj);
|
|
1131
1835
|
convert_type = ca_storage_type_of(ca);
|
|
1132
1836
|
}
|
|
1133
1837
|
if ( convert_type == CA_FIXLEN ) {
|
|
@@ -1149,7 +1853,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
|
|
|
1149
1853
|
if ( rb_obj_is_carray(obj) ) { /* obj == carray */
|
|
1150
1854
|
TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
|
|
1151
1855
|
if ( ca_is_readonly(ca) ) {
|
|
1152
|
-
rb_raise(rb_eRuntimeError, "can
|
|
1856
|
+
rb_raise(rb_eRuntimeError, "can not modify read-only array");
|
|
1153
1857
|
}
|
|
1154
1858
|
if ( NIL_P(rtype) ) {
|
|
1155
1859
|
data_type = ca->data_type;
|
|
@@ -1187,7 +1891,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
|
|
|
1187
1891
|
}
|
|
1188
1892
|
TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
|
|
1189
1893
|
if ( ca_is_readonly(ca) ) {
|
|
1190
|
-
rb_raise(rb_eRuntimeError, "can
|
|
1894
|
+
rb_raise(rb_eRuntimeError, "can not modify read-only array");
|
|
1191
1895
|
}
|
|
1192
1896
|
if ( NIL_P(rtype) ) {
|
|
1193
1897
|
data_type = ca->data_type;
|
|
@@ -1220,7 +1924,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
|
|
|
1220
1924
|
}
|
|
1221
1925
|
else {
|
|
1222
1926
|
volatile VALUE inspect = rb_inspect(CLASS_OF(obj));
|
|
1223
|
-
rb_raise(
|
|
1927
|
+
rb_raise(rb_eTypeError,
|
|
1224
1928
|
"given object '%s' can't be wrapped as carray",
|
|
1225
1929
|
StringValuePtr(inspect));
|
|
1226
1930
|
}
|
|
@@ -1431,6 +2135,62 @@ ca_fixlen_scalar_operand (volatile VALUE *scalar, VALUE reference)
|
|
|
1431
2135
|
return 1;
|
|
1432
2136
|
}
|
|
1433
2137
|
|
|
2138
|
+
/* Where a Ruby Integer falls against the range of integer data type `dt`:
|
|
2139
|
+
-1 below it, 1 above it, 0 inside. Anything but an Integer, and a
|
|
2140
|
+
non-integer `dt`, answer 0. */
|
|
2141
|
+
int
|
|
2142
|
+
ca_integer_range_side (VALUE v, int8_t dt)
|
|
2143
|
+
{
|
|
2144
|
+
VALUE lo, hi;
|
|
2145
|
+
if ( ! RB_INTEGER_TYPE_P(v) ) return 0;
|
|
2146
|
+
switch ( dt ) {
|
|
2147
|
+
case CA_INT8: lo = INT2FIX(INT8_MIN); hi = INT2FIX(INT8_MAX); break;
|
|
2148
|
+
case CA_UINT8: lo = INT2FIX(0); hi = INT2FIX(UINT8_MAX); break;
|
|
2149
|
+
case CA_INT16: lo = INT2FIX(INT16_MIN); hi = INT2FIX(INT16_MAX); break;
|
|
2150
|
+
case CA_UINT16: lo = INT2FIX(0); hi = INT2FIX(UINT16_MAX); break;
|
|
2151
|
+
case CA_INT32: lo = LL2NUM(INT32_MIN); hi = LL2NUM(INT32_MAX); break;
|
|
2152
|
+
case CA_UINT32: lo = INT2FIX(0); hi = ULL2NUM(UINT32_MAX); break;
|
|
2153
|
+
case CA_INT64: lo = LL2NUM(INT64_MIN); hi = LL2NUM(INT64_MAX); break;
|
|
2154
|
+
case CA_UINT64: lo = INT2FIX(0); hi = ULL2NUM(UINT64_MAX); break;
|
|
2155
|
+
default: return 0;
|
|
2156
|
+
}
|
|
2157
|
+
if ( RTEST(rb_funcall(v, rb_intern("<"), 1, lo)) ) return -1;
|
|
2158
|
+
if ( RTEST(rb_funcall(v, rb_intern(">"), 1, hi)) ) return 1;
|
|
2159
|
+
return 0;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
/* Refuses a Ruby Integer that does not fit integer data type `dt`. Taken
|
|
2163
|
+
modulo the type, 256 against a uint8 array would be 0 and compare equal
|
|
2164
|
+
to it. */
|
|
2165
|
+
void
|
|
2166
|
+
ca_check_integer_fits (VALUE v, int8_t dt)
|
|
2167
|
+
{
|
|
2168
|
+
if ( ca_integer_range_side(v, dt) != 0 ) {
|
|
2169
|
+
rb_raise(rb_eRangeError, "%"PRIsVALUE" is out of range for %s",
|
|
2170
|
+
rb_inspect(v), ca_type_name[dt]);
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
/* A Ruby Integer operand against an integer array is taken in the array's
|
|
2175
|
+
own data type, refused when it does not fit (ca_check_integer_fits).
|
|
2176
|
+
Widening instead would make the result's type depend on a scalar's
|
|
2177
|
+
value. A Float, a Face and an object array keep the coercion below. */
|
|
2178
|
+
static int
|
|
2179
|
+
ca_integer_scalar_operand (volatile VALUE *scalar, VALUE reference)
|
|
2180
|
+
{
|
|
2181
|
+
CArray *cr;
|
|
2182
|
+
if ( ! RB_INTEGER_TYPE_P(*scalar) || ! rb_obj_is_carray(reference) ) {
|
|
2183
|
+
return 0;
|
|
2184
|
+
}
|
|
2185
|
+
TypedData_Get_Struct(reference, CArray, &carray_data_type, cr);
|
|
2186
|
+
if ( ! ca_is_integer_type(cr) || ca_is_face(cr) ) {
|
|
2187
|
+
return 0;
|
|
2188
|
+
}
|
|
2189
|
+
ca_check_integer_fits(*scalar, cr->data_type);
|
|
2190
|
+
*scalar = rb_cscalar_new_with_value(cr->data_type, 0, *scalar);
|
|
2191
|
+
return 1;
|
|
2192
|
+
}
|
|
2193
|
+
|
|
1434
2194
|
/* CArray.cast(value) -- singleton entry delegating to rb_ca_cast, which
|
|
1435
2195
|
returns a CArray unchanged and coerces a Ruby value to a CScalar / CArray.
|
|
1436
2196
|
User doc lives in yard-stubs/carray_cast.rb. */
|
|
@@ -1441,6 +2201,41 @@ rb_ca_s_cast (VALUE klass, VALUE val)
|
|
|
1441
2201
|
return rb_ca_cast(val);
|
|
1442
2202
|
}
|
|
1443
2203
|
|
|
2204
|
+
/* An operator operand that exports MemoryView, as a CArray. When the object
|
|
2205
|
+
also defines to_ca, that is asked first, in the order wrap_readonly uses:
|
|
2206
|
+
the MemoryView carries only the values buffer, while to_ca can hand over
|
|
2207
|
+
what the object knows besides it (the nulls of an Arrow array as a mask,
|
|
2208
|
+
a time type as a Face). Only MemoryView producers come here, so an object
|
|
2209
|
+
with to_ca alone (a Range) is still not an operand. */
|
|
2210
|
+
static VALUE
|
|
2211
|
+
ca_operand_from_memory_view (VALUE obj)
|
|
2212
|
+
{
|
|
2213
|
+
volatile VALUE ca;
|
|
2214
|
+
if ( rb_respond_to(obj, rb_intern("to_ca")) ) {
|
|
2215
|
+
ca = rb_funcall(obj, rb_intern("to_ca"), 0);
|
|
2216
|
+
if ( ! rb_obj_is_carray(ca) ) {
|
|
2217
|
+
volatile VALUE inspect = rb_inspect(CLASS_OF(obj));
|
|
2218
|
+
rb_raise(rb_eTypeError,
|
|
2219
|
+
"%s#to_ca did not return a CArray", StringValuePtr(inspect));
|
|
2220
|
+
}
|
|
2221
|
+
return ca;
|
|
2222
|
+
}
|
|
2223
|
+
return rb_funcall(rb_cCArray, rb_intern("wrap_memory_view"), 1, obj);
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
/* The name a coercion error gives an operand: its data type, or for a Face
|
|
2227
|
+
its class. A Face reports the data type of its storage ("fixlen" for a
|
|
2228
|
+
time, a categorical, a record or a string column), which says nothing
|
|
2229
|
+
about what the operand is. */
|
|
2230
|
+
static const char *
|
|
2231
|
+
ca_coerce_operand_name (VALUE obj, CArray *ca)
|
|
2232
|
+
{
|
|
2233
|
+
if ( ca_is_face(ca) ) {
|
|
2234
|
+
return rb_obj_classname(obj);
|
|
2235
|
+
}
|
|
2236
|
+
return ca_type_name[ca->data_type];
|
|
2237
|
+
}
|
|
2238
|
+
|
|
1444
2239
|
void
|
|
1445
2240
|
rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
1446
2241
|
{
|
|
@@ -1453,11 +2248,11 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1453
2248
|
Excludes T_STRING which has its own legacy interpretation. */
|
|
1454
2249
|
if ( ! rb_obj_is_carray(*self) && TYPE(*self) != T_STRING &&
|
|
1455
2250
|
rb_memory_view_available_p(*self) ) {
|
|
1456
|
-
*self =
|
|
2251
|
+
*self = ca_operand_from_memory_view(*self);
|
|
1457
2252
|
}
|
|
1458
2253
|
if ( ! rb_obj_is_carray(*other) && TYPE(*other) != T_STRING &&
|
|
1459
2254
|
rb_memory_view_available_p(*other) ) {
|
|
1460
|
-
*other =
|
|
2255
|
+
*other = ca_operand_from_memory_view(*other);
|
|
1461
2256
|
}
|
|
1462
2257
|
|
|
1463
2258
|
if ( ! rb_obj_is_carray(*self) ) {
|
|
@@ -1477,6 +2272,9 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1477
2272
|
else if ( ca_fixlen_scalar_operand(self, *other) ) {
|
|
1478
2273
|
/* width taken from the fixlen reference; see the helper above */
|
|
1479
2274
|
}
|
|
2275
|
+
else if ( ca_integer_scalar_operand(self, *other) ) {
|
|
2276
|
+
/* the array's own integer type; see the helper above */
|
|
2277
|
+
}
|
|
1480
2278
|
else if ( rb_ca_is_float_type(*other) ) {
|
|
1481
2279
|
*self = rb_cscalar_new_with_value(CA_FLOAT64, 0, *self);
|
|
1482
2280
|
}
|
|
@@ -1508,6 +2306,9 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1508
2306
|
else if ( ca_fixlen_scalar_operand(other, *self) ) {
|
|
1509
2307
|
/* width taken from the fixlen reference; see the helper above */
|
|
1510
2308
|
}
|
|
2309
|
+
else if ( ca_integer_scalar_operand(other, *self) ) {
|
|
2310
|
+
/* the array's own integer type; see the helper above */
|
|
2311
|
+
}
|
|
1511
2312
|
else if ( rb_ca_is_float_type(*self) ) {
|
|
1512
2313
|
*other = rb_cscalar_new_with_value(CA_FLOAT64, 0, *other);
|
|
1513
2314
|
}
|
|
@@ -1577,10 +2378,10 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1577
2378
|
return;
|
|
1578
2379
|
}
|
|
1579
2380
|
|
|
1580
|
-
rb_raise(
|
|
2381
|
+
rb_raise(rb_eTypeError,
|
|
1581
2382
|
"can't coerce carray with data_types of '%s' and '%s'",
|
|
1582
|
-
|
|
1583
|
-
|
|
2383
|
+
ca_coerce_operand_name(*self, ca),
|
|
2384
|
+
ca_coerce_operand_name(*other, cb));
|
|
1584
2385
|
}
|
|
1585
2386
|
|
|
1586
2387
|
/* CArray.cast_self_or_other(self, other) — promote self and other
|
|
@@ -1681,33 +2482,129 @@ ca_promote_type (int8_t a, int8_t b)
|
|
|
1681
2482
|
/* b should be cast to a */
|
|
1682
2483
|
return a;
|
|
1683
2484
|
}
|
|
1684
|
-
rb_raise(
|
|
2485
|
+
rb_raise(rb_eCADataTypeError,
|
|
1685
2486
|
"can't promote data_types '%s' and '%s' to a common type",
|
|
1686
2487
|
ca_type_name[a], ca_type_name[b]);
|
|
1687
2488
|
}
|
|
1688
2489
|
|
|
1689
|
-
/*
|
|
1690
|
-
|
|
2490
|
+
/* The type in which values of types `a` and `b`, whose common type is `t`,
|
|
2491
|
+
are matched for equality. It is `t`, except where `t` cannot hold every
|
|
2492
|
+
value of both: an integer pair of mixed sign whose common type is
|
|
2493
|
+
unsigned (uint8 with int8 is uint8, where -1 would read as 255) moves to
|
|
2494
|
+
a signed type that holds both, or, for 64 bits, where no numeric type
|
|
2495
|
+
does, to object, whose Integers compare by value; and an integer of 32
|
|
2496
|
+
bits or more beside a float32 (or cmplx64) moves to double precision. `eq` answers the
|
|
2497
|
+
mixed-sign pair by value. */
|
|
2498
|
+
int8_t
|
|
2499
|
+
ca_value_match_type (int8_t t, int8_t a, int8_t b)
|
|
2500
|
+
{
|
|
2501
|
+
int signed_a = ( a == CA_INT8 || a == CA_INT16 || a == CA_INT32 || a == CA_INT64 );
|
|
2502
|
+
int signed_b = ( b == CA_INT8 || b == CA_INT16 || b == CA_INT32 || b == CA_INT64 );
|
|
2503
|
+
int wide_a = ( a == CA_INT32 || a == CA_UINT32 || a == CA_INT64 || a == CA_UINT64 );
|
|
2504
|
+
int wide_b = ( b == CA_INT32 || b == CA_UINT32 || b == CA_INT64 || b == CA_UINT64 );
|
|
2505
|
+
/* An integer of 32 bits or more beside a single-precision float: float32
|
|
2506
|
+
holds integers only up to 2**24 (every value of a 16-bit integer, not of
|
|
2507
|
+
a 32-bit one), so the match moves to double precision, which holds every
|
|
2508
|
+
value of a 32-bit integer and of a float32 (a 64-bit integer only up to
|
|
2509
|
+
2**53). */
|
|
2510
|
+
if ( wide_a || wide_b ) {
|
|
2511
|
+
if ( t == CA_FLOAT32 ) return CA_FLOAT64;
|
|
2512
|
+
if ( t == CA_CMPLX64 ) return CA_CMPLX128;
|
|
2513
|
+
}
|
|
2514
|
+
if ( ! signed_a && ! signed_b ) return t;
|
|
2515
|
+
switch ( t ) {
|
|
2516
|
+
case CA_UINT8: return CA_INT16;
|
|
2517
|
+
case CA_UINT16: return CA_INT32;
|
|
2518
|
+
case CA_UINT32: return CA_INT64;
|
|
2519
|
+
case CA_UINT64: return CA_OBJECT;
|
|
2520
|
+
default: return t;
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
/* ca.value_match_type(t, other_type) -- ca_value_match_type with self's
|
|
2525
|
+
data type as the first operand, for the set family and locate_addr. */
|
|
2526
|
+
static VALUE
|
|
2527
|
+
rb_ca_value_match_type (VALUE self, VALUE vt, VALUE vother)
|
|
2528
|
+
{
|
|
2529
|
+
CArray *ca;
|
|
2530
|
+
GetCArray(self, ca);
|
|
2531
|
+
return rb_ca_data_type_to_sym(ca_value_match_type(rb_ca_guess_type(vt), ca->data_type,
|
|
2532
|
+
rb_ca_guess_type(vother)));
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2535
|
+
/* A result_type argument that is a scalar: a Ruby value (Integer, Float,
|
|
2536
|
+
true, ...) or a CScalar. The operators let a scalar take the type of the
|
|
2537
|
+
array beside it, so result_type does too. */
|
|
2538
|
+
static int
|
|
2539
|
+
ca_arg_is_scalar (VALUE obj)
|
|
2540
|
+
{
|
|
2541
|
+
if ( rb_obj_is_carray(obj) ) {
|
|
2542
|
+
CArray *ca;
|
|
2543
|
+
TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
|
|
2544
|
+
return ca_is_scalar(ca);
|
|
2545
|
+
}
|
|
2546
|
+
if ( TYPE(obj) == T_SYMBOL || TYPE(obj) == T_STRING || TYPE(obj) == T_CLASS ) {
|
|
2547
|
+
return 0;
|
|
2548
|
+
}
|
|
2549
|
+
return ca_mv_probe_data_type(obj) < 0;
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
/* The type a scalar `obj` (of type `st`) and an array of type `at` share,
|
|
2553
|
+
by the rule the operators apply: a scalar of the same kind takes the
|
|
2554
|
+
array's type (0.1 beside float32 is float32, 1 beside int8 is int8); one
|
|
2555
|
+
of another kind promotes (1.5 beside int32 is float64). An Integer that
|
|
2556
|
+
does not fit the array's integer type takes the type of its value, where
|
|
2557
|
+
an operator would raise RangeError. */
|
|
2558
|
+
int8_t
|
|
2559
|
+
ca_promote_scalar_type (int8_t at, VALUE obj, int8_t st)
|
|
2560
|
+
{
|
|
2561
|
+
if ( RB_INTEGER_TYPE_P(obj) && at >= CA_INT8 && at <= CA_UINT64 ) {
|
|
2562
|
+
return ( ca_integer_range_side(obj, at) == 0 ) ? at : ca_promote_type(at, st);
|
|
2563
|
+
}
|
|
2564
|
+
if ( ca_cast_table2[st][at] >= 0 ) {
|
|
2565
|
+
return at;
|
|
2566
|
+
}
|
|
2567
|
+
return ca_promote_type(at, st);
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
/* CArray.result_type(*args) -- common data_type of the operands, by the rule
|
|
2571
|
+
the operators use. Each arg is classified by ca_arg_to_data_type: a
|
|
1691
2572
|
CArray / Symbol / String / Class gives a data_type representation, a
|
|
1692
2573
|
Numeric / bool / nil / Object gives a value whose data_type is inferred.
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
2574
|
+
The non-scalar arguments fold pairwise via ca_promote_type; a scalar then
|
|
2575
|
+
joins that type through ca_promote_scalar_type. With no non-scalar
|
|
2576
|
+
argument every argument folds by its own type. Returns a Symbol. User
|
|
2577
|
+
doc lives in yard-stubs/carray_cast.rb. */
|
|
1696
2578
|
|
|
1697
2579
|
static VALUE
|
|
1698
2580
|
rb_ca_s_result_type (int argc, VALUE *argv, VALUE klass)
|
|
1699
2581
|
{
|
|
1700
|
-
int8_t cur;
|
|
2582
|
+
int8_t cur = -1;
|
|
1701
2583
|
int i;
|
|
2584
|
+
VALUE rest, ropt;
|
|
2585
|
+
|
|
2586
|
+
/* Keywords are refused; without this a keyword Hash would be classified
|
|
2587
|
+
as one more operand and the answer would turn into object. */
|
|
2588
|
+
rb_scan_args(argc, argv, "*:", &rest, &ropt);
|
|
2589
|
+
rb_reject_options(ropt);
|
|
2590
|
+
argc = (int) RARRAY_LEN(rest);
|
|
2591
|
+
argv = RARRAY_PTR(rest);
|
|
1702
2592
|
|
|
1703
2593
|
if ( argc < 1 ) {
|
|
1704
2594
|
rb_raise(rb_eArgError, "result_type requires at least one argument");
|
|
1705
2595
|
}
|
|
1706
2596
|
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
2597
|
+
for ( i = 0; i < argc; i++ ) {
|
|
2598
|
+
if ( ! ca_arg_is_scalar(argv[i]) ) {
|
|
2599
|
+
int8_t t = ca_arg_to_data_type(argv[i]);
|
|
2600
|
+
cur = ( cur < 0 ) ? t : ca_promote_type(cur, t);
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
for ( i = 0; i < argc; i++ ) {
|
|
2604
|
+
if ( ca_arg_is_scalar(argv[i]) ) {
|
|
2605
|
+
int8_t t = ca_arg_to_data_type(argv[i]);
|
|
2606
|
+
cur = ( cur < 0 ) ? t : ca_promote_scalar_type(cur, argv[i], t);
|
|
2607
|
+
}
|
|
1711
2608
|
}
|
|
1712
2609
|
/* Return Symbol for family consistency with
|
|
1713
2610
|
CArray.value_to_data_type and ca.data_type. */
|
|
@@ -1747,9 +2644,6 @@ rb_ca_s_promote_list (int argc, VALUE *argv, VALUE klass)
|
|
|
1747
2644
|
{
|
|
1748
2645
|
VALUE list, kwargs, data_type = Qnil;
|
|
1749
2646
|
long n, i;
|
|
1750
|
-
int all_face = 1, any_face = 0, all_primitive = 1;
|
|
1751
|
-
VALUE face_class = Qnil;
|
|
1752
|
-
CArray *ref_face = NULL;
|
|
1753
2647
|
int8_t common = -1;
|
|
1754
2648
|
|
|
1755
2649
|
rb_scan_args(argc, argv, "1:", &list, &kwargs);
|
|
@@ -1768,49 +2662,26 @@ rb_ca_s_promote_list (int argc, VALUE *argv, VALUE klass)
|
|
|
1768
2662
|
if ( RB_TYPE_P(data_type, T_CLASS) || RB_TYPE_P(data_type, T_MODULE) ) {
|
|
1769
2663
|
rb_raise(rb_eArgError,
|
|
1770
2664
|
"promote_list: data_type must be a primitive Symbol "
|
|
1771
|
-
"(Class targets are not supported;
|
|
1772
|
-
"
|
|
1773
|
-
}
|
|
1774
|
-
}
|
|
1775
|
-
|
|
1776
|
-
/* Classify each element: Face / primitive CArray. Detect Face-class
|
|
1777
|
-
homogeneity as we go. */
|
|
1778
|
-
for ( i = 0; i < n; i++ ) {
|
|
1779
|
-
VALUE elem = rb_ary_entry(list, i);
|
|
1780
|
-
CArray *ca;
|
|
1781
|
-
rb_check_carray_object(elem);
|
|
1782
|
-
TypedData_Get_Struct(elem, CArray, &carray_data_type, ca);
|
|
1783
|
-
if ( ca_is_face(ca) ) {
|
|
1784
|
-
any_face = 1;
|
|
1785
|
-
all_primitive = 0;
|
|
1786
|
-
if ( NIL_P(face_class) ) {
|
|
1787
|
-
face_class = rb_obj_class(elem);
|
|
1788
|
-
ref_face = ca;
|
|
1789
|
-
} else if ( rb_obj_class(elem) != face_class ) {
|
|
1790
|
-
all_face = 0; /* will be caught after the loop */
|
|
1791
|
-
} else if ( all_face ) {
|
|
1792
|
-
if ( ! ca_face_state_compatible(rb_ary_entry(list, 0), ref_face,
|
|
1793
|
-
elem, ca) ) {
|
|
1794
|
-
rb_raise(rb_eArgError,
|
|
1795
|
-
"promote_list: Face state mismatch across elements "
|
|
1796
|
-
"(= %s instance at index %ld differs from index 0)",
|
|
1797
|
-
rb_class2name(face_class), i);
|
|
1798
|
-
}
|
|
1799
|
-
}
|
|
1800
|
-
} else {
|
|
1801
|
-
all_face = 0;
|
|
2665
|
+
"(Class targets are not supported; leave data_type out to "
|
|
2666
|
+
"keep a Face)");
|
|
1802
2667
|
}
|
|
1803
2668
|
}
|
|
1804
2669
|
|
|
1805
2670
|
/* Explicit data_type path: primitive Symbol, all elements must be
|
|
1806
2671
|
primitive. Reject if any Face in list. */
|
|
1807
2672
|
if ( ! NIL_P(data_type) ) {
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
2673
|
+
for ( i = 0; i < n; i++ ) {
|
|
2674
|
+
VALUE elem = rb_ary_entry(list, i);
|
|
2675
|
+
CArray *ca;
|
|
2676
|
+
rb_check_carray_object(elem);
|
|
2677
|
+
TypedData_Get_Struct(elem, CArray, &carray_data_type, ca);
|
|
2678
|
+
if ( ca_is_face(ca) ) {
|
|
2679
|
+
rb_raise(rb_eArgError,
|
|
2680
|
+
"promote_list: data_type %s cannot be applied to a list "
|
|
2681
|
+
"containing Face elements (= Face cannot be coerced to "
|
|
2682
|
+
"a primitive without losing identity)",
|
|
2683
|
+
RSTRING_PTR(rb_inspect(data_type)));
|
|
2684
|
+
}
|
|
1814
2685
|
}
|
|
1815
2686
|
{
|
|
1816
2687
|
VALUE out = rb_ary_new_capa(n);
|
|
@@ -1825,41 +2696,24 @@ rb_ca_s_promote_list (int argc, VALUE *argv, VALUE klass)
|
|
|
1825
2696
|
}
|
|
1826
2697
|
}
|
|
1827
2698
|
|
|
1828
|
-
/* Auto-detect path.
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
"promote_list: cannot mix Face and non-Face (or heterogeneous "
|
|
1835
|
-
"Face classes); pass a homogeneous Face list, or strip Face "
|
|
1836
|
-
"manually with .parent for the storage-level layout");
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
|
-
|
|
1840
|
-
if ( all_face ) {
|
|
1841
|
-
/* Homogeneous Face: validate portability, then pass through. */
|
|
1842
|
-
if ( n > 1 && ! ca_face_state_portable(ref_face->obj_type, face_class) ) {
|
|
1843
|
-
rb_raise(rb_eArgError,
|
|
1844
|
-
"promote_list: %s state is not portable across multiple "
|
|
1845
|
-
"elements (= per-parent storage like CAConstString's buffer); "
|
|
1846
|
-
"strip Face manually with .parent for a storage-level list",
|
|
1847
|
-
rb_class2name(face_class));
|
|
1848
|
-
}
|
|
1849
|
-
/* Return a fresh Array so callers can mutate without aliasing. */
|
|
1850
|
-
{
|
|
1851
|
-
VALUE out = rb_ary_new_capa(n);
|
|
1852
|
-
for ( i = 0; i < n; i++ ) rb_ary_push(out, rb_ary_entry(list, i));
|
|
1853
|
-
return out;
|
|
1854
|
-
}
|
|
2699
|
+
/* Auto-detect path. A list of one Face class passes through (the
|
|
2700
|
+
multi-parent constructor lifts it). */
|
|
2701
|
+
if ( ! NIL_P(ca_face_list_class(list, "promote_list")) ) {
|
|
2702
|
+
VALUE out = rb_ary_new_capa(n);
|
|
2703
|
+
for ( i = 0; i < n; i++ ) rb_ary_push(out, rb_ary_entry(list, i));
|
|
2704
|
+
return out;
|
|
1855
2705
|
}
|
|
1856
2706
|
|
|
1857
2707
|
/* All primitive: result_type to determine common data_type, then
|
|
1858
2708
|
wrap_readonly each element. */
|
|
2709
|
+
/* The arrays are joined value for value, so a list mixing signed and
|
|
2710
|
+
unsigned integers takes a type that holds both (uint8 with int8 is
|
|
2711
|
+
int16, not uint8, where -1 would read as 255): the rule equality
|
|
2712
|
+
matches such a pair by. */
|
|
1859
2713
|
common = ca_arg_to_data_type(rb_ary_entry(list, 0));
|
|
1860
2714
|
for ( i = 1; i < n; i++ ) {
|
|
1861
2715
|
int8_t next = ca_arg_to_data_type(rb_ary_entry(list, i));
|
|
1862
|
-
common = ca_promote_type(common, next);
|
|
2716
|
+
common = ca_value_match_type(ca_promote_type(common, next), common, next);
|
|
1863
2717
|
}
|
|
1864
2718
|
{
|
|
1865
2719
|
VALUE common_sym = rb_ca_data_type_to_sym(common);
|
|
@@ -1888,7 +2742,7 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
|
|
|
1888
2742
|
Excludes T_STRING which has its own legacy interpretation. */
|
|
1889
2743
|
if ( ! rb_obj_is_carray(*other) && TYPE(*other) != T_STRING &&
|
|
1890
2744
|
rb_memory_view_available_p(*other) ) {
|
|
1891
|
-
*other =
|
|
2745
|
+
*other = ca_operand_from_memory_view(*other);
|
|
1892
2746
|
}
|
|
1893
2747
|
|
|
1894
2748
|
if ( ! rb_obj_is_carray(*other) ) {
|
|
@@ -1933,10 +2787,10 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
|
|
|
1933
2787
|
return;
|
|
1934
2788
|
}
|
|
1935
2789
|
|
|
1936
|
-
rb_raise(
|
|
2790
|
+
rb_raise(rb_eTypeError,
|
|
1937
2791
|
"can't coerce carray with data_types of '%s' and '%s'",
|
|
1938
|
-
|
|
1939
|
-
|
|
2792
|
+
ca_coerce_operand_name(*self, ca),
|
|
2793
|
+
ca_coerce_operand_name(*other, cb));
|
|
1940
2794
|
}
|
|
1941
2795
|
|
|
1942
2796
|
/* CArray#cast_with(other) -- coerce self and other to a common
|
|
@@ -1951,7 +2805,7 @@ rb_ca_cast_with (VALUE self, VALUE other)
|
|
|
1951
2805
|
rb_ca_cast_self_or_other(&self, &other);
|
|
1952
2806
|
}
|
|
1953
2807
|
else {
|
|
1954
|
-
rb_raise(
|
|
2808
|
+
rb_raise(rb_eTypeError, "first argument should be a carray");
|
|
1955
2809
|
}
|
|
1956
2810
|
return rb_assoc_new(self, other);
|
|
1957
2811
|
}
|
|
@@ -2000,7 +2854,7 @@ rb_ca_clip_uint64 (VALUE self)
|
|
|
2000
2854
|
volatile VALUE vout = rb_carray_new(CA_UINT64, ca->ndim, ca->dim, 0, NULL);
|
|
2001
2855
|
CArray *out;
|
|
2002
2856
|
GetCArray(vout, out);
|
|
2003
|
-
ca_attach(src);
|
|
2857
|
+
ca_attach(src); /* window: nothing raises inside */
|
|
2004
2858
|
double *sp = (double *) src->ptr;
|
|
2005
2859
|
uint64_t *op = (uint64_t *) out->ptr;
|
|
2006
2860
|
ca_size_t n = ca->elements;
|
|
@@ -2028,16 +2882,19 @@ rb_ca_clip_uint64 (VALUE self)
|
|
|
2028
2882
|
Polymorphic cast (NOT a fresh allocator): `data` is coerced into a CArray
|
|
2029
2883
|
of the target data_type, dispatching on its Ruby class:
|
|
2030
2884
|
|
|
2031
|
-
Array
|
|
2032
|
-
CArray
|
|
2033
|
-
nil
|
|
2034
|
-
Range
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2885
|
+
Array -> shape-guessed CArray, element-wise store
|
|
2886
|
+
CArray -> copy if same data_type, else #to_type
|
|
2887
|
+
nil -> empty CArray
|
|
2888
|
+
Range -> arange; a second argument, if given, is the step
|
|
2889
|
+
Numeric -> CScalar, or #to_ca when the object answers it
|
|
2890
|
+
String -> the whitespace / `,` / `;` / `_`->UNDEF parser, which reads
|
|
2891
|
+
far more naturally in Ruby and so is the one branch that
|
|
2892
|
+
calls back out to it (CArray.__cast_string__ in
|
|
2893
|
+
carray/basics.rb, eager-loaded). It receives the data_type
|
|
2894
|
+
as a Symbol.
|
|
2895
|
+
|
|
2896
|
+
A second argument is meaningful only for Range, and a third never is;
|
|
2897
|
+
anything else is refused.
|
|
2041
2898
|
------------------------------------------------------------------------ */
|
|
2042
2899
|
|
|
2043
2900
|
static ID id_new_cast = 0, id_guess_array_shape_cast = 0, id_cast_string = 0,
|
|
@@ -2063,6 +2920,21 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
|
|
|
2063
2920
|
VALUE v = ( argc >= 1 ) ? argv[0] : Qnil;
|
|
2064
2921
|
VALUE sym = ID2SYM(ca_data_type_sym[data_type]);
|
|
2065
2922
|
|
|
2923
|
+
/* Only the Range branch below reads a second argument (the step), and
|
|
2924
|
+
nothing reads a third. The arity is -1 for the step's sake, so the count
|
|
2925
|
+
is checked here; without it `CA_INT32(0, 2)`, which looks like the shape
|
|
2926
|
+
spelling `CArray.int32(3, 3)`, casts the 0 and drops the 2. */
|
|
2927
|
+
if ( argc > 2 ) {
|
|
2928
|
+
rb_raise(rb_eArgError,
|
|
2929
|
+
"wrong number of arguments (given %d, expected 0..2)", argc);
|
|
2930
|
+
}
|
|
2931
|
+
if ( argc == 2 && ! RTEST(rb_obj_is_kind_of(v, rb_cRange)) ) {
|
|
2932
|
+
rb_raise(rb_eArgError,
|
|
2933
|
+
"a step (the second argument) is only accepted "
|
|
2934
|
+
"when the first argument is a Range (got %s)",
|
|
2935
|
+
rb_obj_classname(v));
|
|
2936
|
+
}
|
|
2937
|
+
|
|
2066
2938
|
if ( TYPE(v) == T_ARRAY ) {
|
|
2067
2939
|
volatile VALUE shape, obj;
|
|
2068
2940
|
shape = rb_funcall(rb_cCArray, id_guess_array_shape_cast, 1, v);
|
|
@@ -2083,8 +2955,9 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
|
|
|
2083
2955
|
return rb_carray_new(data_type, 1, &dim0, 0, NULL);
|
|
2084
2956
|
}
|
|
2085
2957
|
else if ( RTEST(rb_obj_is_kind_of(v, rb_cRange)) ) {
|
|
2086
|
-
/* arange: n = ((end - begin).abs / step).floor
|
|
2087
|
-
|
|
2958
|
+
/* arange: n = ((end - begin).abs / step).floor + 1, or for an excluded
|
|
2959
|
+
end ((end - begin).abs.quo(step)).ceil -- the steps that start before
|
|
2960
|
+
the end -- then seq(begin, sign * step.abs). */
|
|
2088
2961
|
volatile VALUE vbeg, vend, step, n;
|
|
2089
2962
|
int sign;
|
|
2090
2963
|
ca_size_t dn;
|
|
@@ -2094,7 +2967,7 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
|
|
|
2094
2967
|
vend = rb_funcall(v, id_end_cast, 0);
|
|
2095
2968
|
step = ( argc >= 2 ) ? argv[1] : Qnil;
|
|
2096
2969
|
if ( RTEST(step) && RTEST(rb_funcall(step, id_op_eq, 1, INT2FIX(0))) ) {
|
|
2097
|
-
rb_raise(
|
|
2970
|
+
rb_raise(rb_eArgError, "step should not be 0");
|
|
2098
2971
|
}
|
|
2099
2972
|
if ( data_type == CA_OBJECT && !RTEST(step) ) {
|
|
2100
2973
|
VALUE va = rb_funcall(v, id_to_a_cast, 0); /* CA_OBJECT(v.to_a) */
|
|
@@ -2103,9 +2976,13 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
|
|
|
2103
2976
|
if ( !RTEST(step) ) step = INT2FIX(1);
|
|
2104
2977
|
n = rb_funcall(vend, id_op_minus, 1, vbeg);
|
|
2105
2978
|
n = rb_funcall(n, id_abs_cast, 0);
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2979
|
+
if ( RTEST(rb_funcall(v, id_exclude_end_p_cast, 0)) ) {
|
|
2980
|
+
n = rb_funcall(n, rb_intern("quo"), 1, rb_funcall(step, id_abs_cast, 0));
|
|
2981
|
+
n = rb_funcall(n, rb_intern("ceil"), 0);
|
|
2982
|
+
}
|
|
2983
|
+
else {
|
|
2984
|
+
n = rb_funcall(n, id_op_div, 1, step);
|
|
2985
|
+
n = rb_funcall(n, id_floor_cast, 0);
|
|
2109
2986
|
n = rb_funcall(n, id_op_plus, 1, INT2FIX(1));
|
|
2110
2987
|
}
|
|
2111
2988
|
sign = RTEST(rb_funcall(vbeg, id_op_le, 1, vend)) ? 1 : -1;
|
|
@@ -2206,7 +3083,7 @@ rb_ca_cast_fixlen (int argc, VALUE *argv, VALUE self)
|
|
|
2206
3083
|
ca_size_t l = NUM2SIZE(rb_funcall(rb_ary_entry(v, i), id_length_cast, 0));
|
|
2207
3084
|
if ( l > maxlen ) maxlen = l;
|
|
2208
3085
|
}
|
|
2209
|
-
bytes = maxlen;
|
|
3086
|
+
bytes = ( maxlen > 0 ) ? maxlen : 1; /* all empty: one NUL byte */
|
|
2210
3087
|
} else {
|
|
2211
3088
|
bytes = NUM2SIZE(bytes_v);
|
|
2212
3089
|
}
|
|
@@ -2219,7 +3096,7 @@ rb_ca_cast_fixlen (int argc, VALUE *argv, VALUE self)
|
|
|
2219
3096
|
}
|
|
2220
3097
|
else if ( NIL_P(v) ) {
|
|
2221
3098
|
ca_size_t dim0 = 0;
|
|
2222
|
-
ca_size_t bytes = NIL_P(bytes_v) ?
|
|
3099
|
+
ca_size_t bytes = NIL_P(bytes_v) ? 1 : NUM2SIZE(bytes_v);
|
|
2223
3100
|
return rb_carray_new(CA_FIXLEN, 1, &dim0, bytes, NULL);
|
|
2224
3101
|
}
|
|
2225
3102
|
else {
|
|
@@ -2231,17 +3108,373 @@ rb_ca_cast_fixlen (int argc, VALUE *argv, VALUE self)
|
|
|
2231
3108
|
? ca : ca_cast_to_fixlen(ca, fixlen_sym, bytes_v);
|
|
2232
3109
|
}
|
|
2233
3110
|
{
|
|
2234
|
-
|
|
3111
|
+
/* No bytes: given: a String is as wide as it is (one NUL byte when
|
|
3112
|
+
empty). Anything else has no width to infer, and the fixlen
|
|
3113
|
+
check reports it. */
|
|
3114
|
+
ca_size_t bytes = 0;
|
|
3115
|
+
if ( ! NIL_P(bytes_v) ) {
|
|
3116
|
+
bytes = NUM2SIZE(bytes_v);
|
|
3117
|
+
}
|
|
3118
|
+
else if ( RB_TYPE_P(v, T_STRING) ) {
|
|
3119
|
+
bytes = ( RSTRING_LEN(v) > 0 ) ? RSTRING_LEN(v) : 1;
|
|
3120
|
+
}
|
|
2235
3121
|
return rb_cscalar_new_with_value(CA_FIXLEN, bytes, v);
|
|
2236
3122
|
}
|
|
2237
3123
|
}
|
|
2238
3124
|
}
|
|
2239
3125
|
|
|
3126
|
+
static VALUE
|
|
3127
|
+
rb_ca_read_text_as_number (int argc, VALUE *argv, VALUE self)
|
|
3128
|
+
{
|
|
3129
|
+
volatile VALUE src = self, out, vmask;
|
|
3130
|
+
VALUE rtype, report;
|
|
3131
|
+
CArray *ca, *co, *cmask;
|
|
3132
|
+
int8_t data_type;
|
|
3133
|
+
int is_float;
|
|
3134
|
+
VALUE *cells;
|
|
3135
|
+
boolean8_t *m_in, *m_out;
|
|
3136
|
+
ca_size_t i;
|
|
3137
|
+
|
|
3138
|
+
rb_scan_args(argc, argv, "11", &rtype, &report);
|
|
3139
|
+
if ( ! NIL_P(report) ) {
|
|
3140
|
+
Check_Type(report, T_ARRAY);
|
|
3141
|
+
}
|
|
3142
|
+
|
|
3143
|
+
data_type = rb_ca_guess_type(rtype);
|
|
3144
|
+
switch ( data_type ) {
|
|
3145
|
+
case CA_INT8: case CA_INT16: case CA_INT32: case CA_INT64:
|
|
3146
|
+
case CA_UINT8: case CA_UINT16: case CA_UINT32: case CA_UINT64:
|
|
3147
|
+
is_float = 0;
|
|
3148
|
+
break;
|
|
3149
|
+
case CA_FLOAT32: case CA_FLOAT64:
|
|
3150
|
+
is_float = 1;
|
|
3151
|
+
break;
|
|
3152
|
+
default:
|
|
3153
|
+
return Qnil; /* not a number type: the caller casts */
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
3157
|
+
if ( ca->data_type != CA_OBJECT ) {
|
|
3158
|
+
rb_raise(rb_eArgError, "decimal reading needs an object array");
|
|
3159
|
+
}
|
|
3160
|
+
if ( ! ca_is_entity(ca) ) {
|
|
3161
|
+
src = rb_ca_copy(src);
|
|
3162
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
3163
|
+
}
|
|
3164
|
+
|
|
3165
|
+
out = rb_carray_new(data_type, ca->ndim, ca->dim, 0, NULL);
|
|
3166
|
+
TypedData_Get_Struct(out, CArray, &carray_data_type, co);
|
|
3167
|
+
vmask = rb_carray_new(CA_BOOLEAN, ca->ndim, ca->dim, 0, NULL);
|
|
3168
|
+
|
|
3169
|
+
cells = (VALUE *) ca->ptr;
|
|
3170
|
+
m_in = ca_has_mask(ca) ? (boolean8_t *) ca->mask->ptr : NULL;
|
|
3171
|
+
TypedData_Get_Struct(vmask, CArray, &carray_data_type, cmask);
|
|
3172
|
+
m_out = (boolean8_t *) cmask->ptr;
|
|
3173
|
+
|
|
3174
|
+
for (i = 0; i < ca->elements; i++) {
|
|
3175
|
+
VALUE v = cells[i];
|
|
3176
|
+
char *cell = co->ptr + i * co->bytes;
|
|
3177
|
+
int ok = 0;
|
|
3178
|
+
int missing = ( m_in && m_in[i] ) || NIL_P(v);
|
|
3179
|
+
if ( missing ) {
|
|
3180
|
+
ok = 0;
|
|
3181
|
+
}
|
|
3182
|
+
else if ( RB_TYPE_P(v, T_STRING) ) {
|
|
3183
|
+
int rc = ca_decimal_string_read(v, data_type, cell);
|
|
3184
|
+
missing = ( rc == CA_DECIMAL_BLANK );
|
|
3185
|
+
ok = ( rc == CA_DECIMAL_OK );
|
|
3186
|
+
}
|
|
3187
|
+
else if ( is_float ) {
|
|
3188
|
+
if ( RB_FLOAT_TYPE_P(v) || RB_INTEGER_TYPE_P(v) || ca_decimal_other_real(v) ) {
|
|
3189
|
+
double d = NUM2DBL(v);
|
|
3190
|
+
if ( data_type == CA_FLOAT32 ) {
|
|
3191
|
+
*(float32_t *) cell = (float32_t) d;
|
|
3192
|
+
}
|
|
3193
|
+
else {
|
|
3194
|
+
*(float64_t *) cell = d;
|
|
3195
|
+
}
|
|
3196
|
+
ok = 1;
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
3199
|
+
else {
|
|
3200
|
+
int negative = 0;
|
|
3201
|
+
uint64_t magnitude = 0;
|
|
3202
|
+
ok = ca_decimal_object_integer(v, &negative, &magnitude)
|
|
3203
|
+
&& ca_decimal_fits(data_type, negative, magnitude);
|
|
3204
|
+
if ( ok ) {
|
|
3205
|
+
ca_decimal_store_integer(data_type, cell, 0, negative, magnitude);
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
m_out[i] = ok ? 0 : 1;
|
|
3209
|
+
if ( ! ok ) {
|
|
3210
|
+
memset(co->ptr + i * co->bytes, 0, co->bytes);
|
|
3211
|
+
if ( ! missing && ! NIL_P(report) ) {
|
|
3212
|
+
rb_ary_push(report, SIZET2NUM(i));
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
|
|
3217
|
+
ca_mask_from_bytes(co, m_out);
|
|
3218
|
+
rb_ca_inherit_attr(out, self);
|
|
3219
|
+
RB_GC_GUARD(src);
|
|
3220
|
+
RB_GC_GUARD(vmask);
|
|
3221
|
+
return out;
|
|
3222
|
+
}
|
|
3223
|
+
|
|
3224
|
+
/* The number type a column of text reads as, for CAFrame#infer_types.
|
|
3225
|
+
|
|
3226
|
+
A cell is an integer when it is digits with an optional sign and fits
|
|
3227
|
+
int64, and a float when it is any other decimal number (the grammar
|
|
3228
|
+
above, nan / inf included). A number with a leading zero ("007",
|
|
3229
|
+
"007.5") is not a number here: it is a code, kept as text. Neither is
|
|
3230
|
+
an integer too long for int64 (an identifier), which a float would
|
|
3231
|
+
round. Blank, nil and masked cells are missing and say nothing.
|
|
3232
|
+
|
|
3233
|
+
Returns :int64 when every present cell is an integer, :float64 when
|
|
3234
|
+
every present cell is a number and one is not an integer, and nil
|
|
3235
|
+
otherwise -- including when no cell is present. */
|
|
3236
|
+
|
|
3237
|
+
enum {
|
|
3238
|
+
CA_INFER_MISSING,
|
|
3239
|
+
CA_INFER_INTEGER,
|
|
3240
|
+
CA_INFER_FLOAT,
|
|
3241
|
+
CA_INFER_TEXT
|
|
3242
|
+
};
|
|
3243
|
+
|
|
3244
|
+
static int
|
|
3245
|
+
ca_infer_decimal_kind_of_bytes (const char *s, long n)
|
|
3246
|
+
{
|
|
3247
|
+
long i = 0, k;
|
|
3248
|
+
int digits_only = 1;
|
|
3249
|
+
ca_decimal_trim(&s, &n);
|
|
3250
|
+
if ( n == 0 ) {
|
|
3251
|
+
return CA_INFER_MISSING;
|
|
3252
|
+
}
|
|
3253
|
+
if ( ! ca_decimal_float(s, n, NULL) ) {
|
|
3254
|
+
return CA_INFER_TEXT;
|
|
3255
|
+
}
|
|
3256
|
+
if ( s[i] == '+' || s[i] == '-' ) {
|
|
3257
|
+
i++;
|
|
3258
|
+
}
|
|
3259
|
+
if ( i + 1 < n && s[i] == '0' && s[i+1] >= '0' && s[i+1] <= '9' ) {
|
|
3260
|
+
return CA_INFER_TEXT; /* a leading zero */
|
|
3261
|
+
}
|
|
3262
|
+
if ( i == n ) {
|
|
3263
|
+
return CA_INFER_TEXT;
|
|
3264
|
+
}
|
|
3265
|
+
for (k = i; k < n; k++) {
|
|
3266
|
+
if ( s[k] < '0' || s[k] > '9' ) {
|
|
3267
|
+
digits_only = 0;
|
|
3268
|
+
break;
|
|
3269
|
+
}
|
|
3270
|
+
}
|
|
3271
|
+
if ( digits_only ) {
|
|
3272
|
+
int negative;
|
|
3273
|
+
uint64_t magnitude;
|
|
3274
|
+
if ( ca_decimal_integer(s, n, &negative, &magnitude) == CA_DECIMAL_OK
|
|
3275
|
+
&& ca_decimal_fits(CA_INT64, negative, magnitude) ) {
|
|
3276
|
+
return CA_INFER_INTEGER;
|
|
3277
|
+
}
|
|
3278
|
+
return CA_INFER_TEXT; /* too long for int64 */
|
|
3279
|
+
}
|
|
3280
|
+
return CA_INFER_FLOAT;
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3283
|
+
static VALUE
|
|
3284
|
+
rb_ca_infer_number_type_of_text (VALUE self)
|
|
3285
|
+
{
|
|
3286
|
+
volatile VALUE src = self;
|
|
3287
|
+
CArray *ca;
|
|
3288
|
+
VALUE *cells;
|
|
3289
|
+
boolean8_t *m;
|
|
3290
|
+
ca_size_t i;
|
|
3291
|
+
int present = 0, any_float = 0;
|
|
3292
|
+
|
|
3293
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
3294
|
+
if ( ca->data_type != CA_OBJECT ) {
|
|
3295
|
+
rb_raise(rb_eArgError, "type inference needs an object array");
|
|
3296
|
+
}
|
|
3297
|
+
if ( ! ca_is_entity(ca) ) {
|
|
3298
|
+
src = rb_ca_copy(src);
|
|
3299
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
3300
|
+
}
|
|
3301
|
+
cells = (VALUE *) ca->ptr;
|
|
3302
|
+
m = ca_has_mask(ca) ? (boolean8_t *) ca->mask->ptr : NULL;
|
|
3303
|
+
|
|
3304
|
+
for (i = 0; i < ca->elements; i++) {
|
|
3305
|
+
VALUE v = cells[i];
|
|
3306
|
+
int kind;
|
|
3307
|
+
if ( ( m && m[i] ) || NIL_P(v) ) {
|
|
3308
|
+
continue;
|
|
3309
|
+
}
|
|
3310
|
+
if ( RB_TYPE_P(v, T_STRING) ) {
|
|
3311
|
+
kind = ca_infer_decimal_kind_of_bytes(RSTRING_PTR(v), RSTRING_LEN(v));
|
|
3312
|
+
}
|
|
3313
|
+
else if ( RB_FLOAT_TYPE_P(v) ) {
|
|
3314
|
+
kind = CA_INFER_FLOAT;
|
|
3315
|
+
}
|
|
3316
|
+
else if ( RB_INTEGER_TYPE_P(v) ) {
|
|
3317
|
+
int negative;
|
|
3318
|
+
uint64_t magnitude;
|
|
3319
|
+
kind = ( ca_decimal_object_integer(v, &negative, &magnitude)
|
|
3320
|
+
&& ca_decimal_fits(CA_INT64, negative, magnitude) )
|
|
3321
|
+
? CA_INFER_INTEGER : CA_INFER_TEXT;
|
|
3322
|
+
}
|
|
3323
|
+
else {
|
|
3324
|
+
kind = CA_INFER_TEXT;
|
|
3325
|
+
}
|
|
3326
|
+
if ( kind == CA_INFER_TEXT ) {
|
|
3327
|
+
RB_GC_GUARD(src);
|
|
3328
|
+
return Qnil;
|
|
3329
|
+
}
|
|
3330
|
+
if ( kind != CA_INFER_MISSING ) {
|
|
3331
|
+
present = 1;
|
|
3332
|
+
any_float |= ( kind == CA_INFER_FLOAT );
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
RB_GC_GUARD(src);
|
|
3336
|
+
if ( ! present ) {
|
|
3337
|
+
return Qnil;
|
|
3338
|
+
}
|
|
3339
|
+
return ID2SYM(rb_intern(any_float ? "float64" : "int64"));
|
|
3340
|
+
}
|
|
3341
|
+
|
|
3342
|
+
/* The same two readers over a CAConstString, from its buffer and its
|
|
3343
|
+
(start, end) byte ranges, without a String per cell. CAConstString's
|
|
3344
|
+
__infer_number_type_of_text__ / __read_text_as_number__ call them, so
|
|
3345
|
+
CAFrame#infer_types and #cast read a text column from a file this way. */
|
|
3346
|
+
|
|
3347
|
+
/* The buffer of a CAConstString and an entity of its (start, end) byte
|
|
3348
|
+
ranges, masked where a cell is missing. */
|
|
3349
|
+
static VALUE
|
|
3350
|
+
ca_const_string_buffer_and_ranges (VALUE cs, VALUE *buffer, CArray **ranges)
|
|
3351
|
+
{
|
|
3352
|
+
volatile VALUE vranges;
|
|
3353
|
+
VALUE klass = rb_const_get(rb_cObject, rb_intern("CAConstString"));
|
|
3354
|
+
if ( ! RTEST(rb_obj_is_kind_of(cs, klass)) ) {
|
|
3355
|
+
rb_raise(rb_eTypeError, "needs a CAConstString");
|
|
3356
|
+
}
|
|
3357
|
+
*buffer = rb_funcall(cs, rb_intern("buffer"), 0);
|
|
3358
|
+
vranges = rb_ca_parent(cs);
|
|
3359
|
+
TypedData_Get_Struct(vranges, CArray, &carray_data_type, *ranges);
|
|
3360
|
+
if ( ! ca_is_entity(*ranges) ) {
|
|
3361
|
+
vranges = rb_ca_copy(vranges);
|
|
3362
|
+
TypedData_Get_Struct(vranges, CArray, &carray_data_type, *ranges);
|
|
3363
|
+
}
|
|
3364
|
+
return vranges;
|
|
3365
|
+
}
|
|
3366
|
+
|
|
3367
|
+
static VALUE
|
|
3368
|
+
rb_ca_s_const_string_infer_number_type_of_text (VALUE klass, VALUE cs)
|
|
3369
|
+
{
|
|
3370
|
+
volatile VALUE src;
|
|
3371
|
+
VALUE buffer;
|
|
3372
|
+
CArray *pe;
|
|
3373
|
+
const char *buf;
|
|
3374
|
+
const int64_t *pair;
|
|
3375
|
+
boolean8_t *m;
|
|
3376
|
+
ca_size_t i;
|
|
3377
|
+
int present = 0, any_float = 0;
|
|
3378
|
+
|
|
3379
|
+
src = ca_const_string_buffer_and_ranges(cs, &buffer, &pe);
|
|
3380
|
+
buf = RSTRING_PTR(buffer);
|
|
3381
|
+
pair = (const int64_t *) pe->ptr;
|
|
3382
|
+
m = ca_has_mask(pe) ? (boolean8_t *) pe->mask->ptr : NULL;
|
|
3383
|
+
for (i = 0; i < pe->elements; i++) {
|
|
3384
|
+
int kind;
|
|
3385
|
+
if ( m && m[i] ) {
|
|
3386
|
+
continue;
|
|
3387
|
+
}
|
|
3388
|
+
kind = ca_infer_decimal_kind_of_bytes(buf + pair[2 * i], (long) ( pair[2 * i + 1] - pair[2 * i] ));
|
|
3389
|
+
if ( kind == CA_INFER_TEXT ) {
|
|
3390
|
+
RB_GC_GUARD(src);
|
|
3391
|
+
return Qnil;
|
|
3392
|
+
}
|
|
3393
|
+
if ( kind != CA_INFER_MISSING ) {
|
|
3394
|
+
present = 1;
|
|
3395
|
+
any_float |= ( kind == CA_INFER_FLOAT );
|
|
3396
|
+
}
|
|
3397
|
+
}
|
|
3398
|
+
RB_GC_GUARD(src);
|
|
3399
|
+
RB_GC_GUARD(buffer);
|
|
3400
|
+
if ( ! present ) {
|
|
3401
|
+
return Qnil;
|
|
3402
|
+
}
|
|
3403
|
+
return ID2SYM(rb_intern(any_float ? "float64" : "int64"));
|
|
3404
|
+
}
|
|
3405
|
+
|
|
3406
|
+
static VALUE
|
|
3407
|
+
rb_ca_s_const_string_read_text_as_number (VALUE klass, VALUE cs, VALUE rtype, VALUE report)
|
|
3408
|
+
{
|
|
3409
|
+
volatile VALUE src, out;
|
|
3410
|
+
VALUE buffer;
|
|
3411
|
+
CArray *pe, *co;
|
|
3412
|
+
int8_t data_type;
|
|
3413
|
+
const char *buf;
|
|
3414
|
+
const int64_t *pair;
|
|
3415
|
+
boolean8_t *m_in, *m_out = NULL;
|
|
3416
|
+
ca_size_t i;
|
|
3417
|
+
|
|
3418
|
+
if ( ! NIL_P(report) ) {
|
|
3419
|
+
Check_Type(report, T_ARRAY);
|
|
3420
|
+
}
|
|
3421
|
+
data_type = rb_ca_guess_type(rtype);
|
|
3422
|
+
switch ( data_type ) {
|
|
3423
|
+
case CA_INT8: case CA_INT16: case CA_INT32: case CA_INT64:
|
|
3424
|
+
case CA_UINT8: case CA_UINT16: case CA_UINT32: case CA_UINT64:
|
|
3425
|
+
case CA_FLOAT32: case CA_FLOAT64:
|
|
3426
|
+
break;
|
|
3427
|
+
default:
|
|
3428
|
+
return Qnil; /* not a number type: the caller casts */
|
|
3429
|
+
}
|
|
3430
|
+
src = ca_const_string_buffer_and_ranges(cs, &buffer, &pe);
|
|
3431
|
+
out = rb_carray_new(data_type, pe->ndim, pe->dim, 0, NULL);
|
|
3432
|
+
TypedData_Get_Struct(out, CArray, &carray_data_type, co);
|
|
3433
|
+
buf = RSTRING_PTR(buffer);
|
|
3434
|
+
pair = (const int64_t *) pe->ptr;
|
|
3435
|
+
m_in = ca_has_mask(pe) ? (boolean8_t *) pe->mask->ptr : NULL;
|
|
3436
|
+
|
|
3437
|
+
for (i = 0; i < pe->elements; i++) {
|
|
3438
|
+
char *cell = co->ptr + i * co->bytes;
|
|
3439
|
+
int rc = CA_DECIMAL_BLANK;
|
|
3440
|
+
if ( ! ( m_in && m_in[i] ) ) {
|
|
3441
|
+
rc = ca_decimal_read_bytes_as(buf + pair[2 * i],
|
|
3442
|
+
(long) ( pair[2 * i + 1] - pair[2 * i] ),
|
|
3443
|
+
data_type, cell);
|
|
3444
|
+
}
|
|
3445
|
+
if ( rc != CA_DECIMAL_OK ) {
|
|
3446
|
+
if ( m_out == NULL ) {
|
|
3447
|
+
ca_create_mask(co);
|
|
3448
|
+
m_out = (boolean8_t *) co->mask->ptr;
|
|
3449
|
+
}
|
|
3450
|
+
m_out[i] = 1;
|
|
3451
|
+
memset(cell, 0, co->bytes);
|
|
3452
|
+
if ( rc != CA_DECIMAL_BLANK && ! NIL_P(report) ) {
|
|
3453
|
+
rb_ary_push(report, SIZET2NUM(i));
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
RB_GC_GUARD(src);
|
|
3458
|
+
RB_GC_GUARD(buffer);
|
|
3459
|
+
return out;
|
|
3460
|
+
}
|
|
3461
|
+
|
|
2240
3462
|
void
|
|
2241
3463
|
Init_carray_cast (void)
|
|
2242
3464
|
{
|
|
2243
3465
|
/* CArray data_type conversion */
|
|
2244
3466
|
|
|
3467
|
+
/* Internal: CAFrame#infer_types asks the number type of a text column. */
|
|
3468
|
+
rb_define_method(rb_cCArray, "__infer_number_type_of_text__", rb_ca_infer_number_type_of_text, 0);
|
|
3469
|
+
|
|
3470
|
+
/* Internal: CAFrame#cast reads text cells with this grammar. With an
|
|
3471
|
+
Array as the second argument, the addresses of cells that hold
|
|
3472
|
+
something but do not read (blank, nil and masked cells are missing,
|
|
3473
|
+
not unreadable) are pushed onto it. */
|
|
3474
|
+
rb_define_method(rb_cCArray, "__read_text_as_number__", rb_ca_read_text_as_number, -1);
|
|
3475
|
+
rb_define_singleton_method(rb_cCArray, "__const_string_infer_number_type_of_text__", rb_ca_s_const_string_infer_number_type_of_text, 1);
|
|
3476
|
+
rb_define_singleton_method(rb_cCArray, "__const_string_read_text_as_number__", rb_ca_s_const_string_read_text_as_number, 3);
|
|
3477
|
+
|
|
2245
3478
|
rb_define_method(rb_cCArray, "to_type", rb_ca_to_type_internal, -1);
|
|
2246
3479
|
|
|
2247
3480
|
rb_define_method(rb_cCArray, "fixlen", rb_ca_to_fixlen, -1);
|
|
@@ -2306,6 +3539,8 @@ Init_carray_cast (void)
|
|
|
2306
3539
|
"cast_self_or_other", rb_ca_s_cast_self_or_other, 2);
|
|
2307
3540
|
rb_define_singleton_method(rb_cCArray,
|
|
2308
3541
|
"result_type", rb_ca_s_result_type, -1);
|
|
3542
|
+
rb_define_private_method(rb_cCArray,
|
|
3543
|
+
"value_match_type", rb_ca_value_match_type, 2);
|
|
2309
3544
|
|
|
2310
3545
|
rb_define_singleton_method(rb_cCArray,
|
|
2311
3546
|
"promote_list", rb_ca_s_promote_list, -1);
|