carray 3.0.1 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/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
|
|
@@ -548,19 +1201,142 @@ rb_ca_object_to_data_class (VALUE self, VALUE rtype, ca_size_t bytes)
|
|
|
548
1201
|
rb_ca_store_addr(obj, i, rb_funcall(rval, id_encode, 0));
|
|
549
1202
|
}
|
|
550
1203
|
}
|
|
551
|
-
|
|
552
|
-
return obj;
|
|
1204
|
+
|
|
1205
|
+
return obj;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
typedef struct {
|
|
1209
|
+
CArray *ca;
|
|
1210
|
+
CArray *cb;
|
|
1211
|
+
boolean8_t *scratch;
|
|
1212
|
+
} ca_to_type_ctx_t;
|
|
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
|
+
|
|
1241
|
+
/* The cast proper, with `ca` attached. It can raise (a value the target
|
|
1242
|
+
type cannot hold), so it runs under rb_ensure. */
|
|
1243
|
+
static VALUE
|
|
1244
|
+
ca_to_type_cast (VALUE arg)
|
|
1245
|
+
{
|
|
1246
|
+
ca_to_type_ctx_t *c = (ca_to_type_ctx_t *) arg;
|
|
1247
|
+
CArray *ca = c->ca, *cb = c->cb;
|
|
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
|
|
1258
|
+
cell becomes UNDEF (see ext/carray_cast_func.rb). Cast into a
|
|
1259
|
+
scratch mask seeded from the source mask, then attach it to the
|
|
1260
|
+
output only if some cell ended up masked -- an all-valid cast keeps
|
|
1261
|
+
the mask-less result the legacy path produced. */
|
|
1262
|
+
ca_size_t ne = cb->elements;
|
|
1263
|
+
ca_size_t i;
|
|
1264
|
+
boolean8_t any = 0;
|
|
1265
|
+
boolean8_t *scratch;
|
|
1266
|
+
c->scratch = scratch = ALLOC_N(boolean8_t, ne > 0 ? ne : 1);
|
|
1267
|
+
if ( cb->mask ) {
|
|
1268
|
+
memcpy(scratch, cb->mask->ptr, ne); /* copy of source mask */
|
|
1269
|
+
}
|
|
1270
|
+
else {
|
|
1271
|
+
memset(scratch, 0, ne);
|
|
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
|
+
}
|
|
1280
|
+
ca_cast_block_with_mask(ne, ca, ca->ptr, cb, cb->ptr, scratch);
|
|
1281
|
+
for (i=0; i<ne; i++) {
|
|
1282
|
+
if ( scratch[i] ) {
|
|
1283
|
+
any = 1;
|
|
1284
|
+
break;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
if ( any ) {
|
|
1288
|
+
if ( ! cb->mask ) {
|
|
1289
|
+
ca_create_mask(cb);
|
|
1290
|
+
}
|
|
1291
|
+
memcpy(cb->mask->ptr, scratch, ne);
|
|
1292
|
+
}
|
|
1293
|
+
xfree(scratch);
|
|
1294
|
+
c->scratch = NULL;
|
|
1295
|
+
}
|
|
1296
|
+
else if ( ca_has_mask(ca) ) {
|
|
1297
|
+
ca_cast_block_with_mask(cb->elements, ca, ca->ptr, cb, cb->ptr,
|
|
1298
|
+
(boolean8_t*)ca->mask->ptr);
|
|
1299
|
+
}
|
|
1300
|
+
else {
|
|
1301
|
+
ca_cast_block(cb->elements, ca, ca->ptr, cb, cb->ptr);
|
|
1302
|
+
}
|
|
1303
|
+
return Qnil;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
static VALUE
|
|
1307
|
+
ca_to_type_release (VALUE arg)
|
|
1308
|
+
{
|
|
1309
|
+
ca_to_type_ctx_t *c = (ca_to_type_ctx_t *) arg;
|
|
1310
|
+
if ( c->scratch ) {
|
|
1311
|
+
xfree(c->scratch);
|
|
1312
|
+
c->scratch = NULL;
|
|
1313
|
+
}
|
|
1314
|
+
ca_detach(c->ca);
|
|
1315
|
+
return Qnil;
|
|
553
1316
|
}
|
|
554
1317
|
|
|
555
1318
|
/* CArray#to_type(data_type, bytes:) -- eager copy of self converted to
|
|
556
1319
|
data_type (a new entity owning its storage). User doc lives in
|
|
557
1320
|
yard-stubs/carray_cast.rb. */
|
|
558
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. */
|
|
559
1326
|
static VALUE
|
|
560
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)
|
|
561
1336
|
{
|
|
562
1337
|
volatile VALUE obj, rtype = Qnil, ropt, rbytes = Qnil;
|
|
563
1338
|
CArray *ca, *cb;
|
|
1339
|
+
ca_to_type_ctx_t ctx;
|
|
564
1340
|
int8_t data_type;
|
|
565
1341
|
ca_size_t bytes;
|
|
566
1342
|
|
|
@@ -585,8 +1361,8 @@ rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
|
|
|
585
1361
|
Numeric Face is not routed here -- its surface *is* its storage, so the
|
|
586
1362
|
ordinary cast below is already right. */
|
|
587
1363
|
if ( ca_is_face(ca) && ca->data_type == CA_FIXLEN ) {
|
|
588
|
-
return
|
|
589
|
-
|
|
1364
|
+
return rb_ca_to_type_convert(argc, argv,
|
|
1365
|
+
rb_ca_face_numeric_projection(self, ca));
|
|
590
1366
|
}
|
|
591
1367
|
|
|
592
1368
|
ca_update_mask(ca);
|
|
@@ -601,48 +1377,11 @@ rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
|
|
|
601
1377
|
|
|
602
1378
|
TypedData_Get_Struct(obj, CArray, &carray_data_type, cb);
|
|
603
1379
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
cell becomes UNDEF (see ext/carray_cast_func.rb). Cast into a
|
|
610
|
-
scratch mask seeded from the source mask, then attach it to the
|
|
611
|
-
output only if some cell ended up masked -- an all-valid cast keeps
|
|
612
|
-
the mask-less result the legacy path produced. */
|
|
613
|
-
ca_size_t ne = cb->elements;
|
|
614
|
-
ca_size_t i;
|
|
615
|
-
boolean8_t any = 0;
|
|
616
|
-
boolean8_t *scratch = ALLOC_N(boolean8_t, ne > 0 ? ne : 1);
|
|
617
|
-
if ( cb->mask ) {
|
|
618
|
-
memcpy(scratch, cb->mask->ptr, ne); /* copy of source mask */
|
|
619
|
-
}
|
|
620
|
-
else {
|
|
621
|
-
memset(scratch, 0, ne);
|
|
622
|
-
}
|
|
623
|
-
ca_cast_block_with_mask(ne, ca, ca->ptr, cb, cb->ptr, scratch);
|
|
624
|
-
for (i=0; i<ne; i++) {
|
|
625
|
-
if ( scratch[i] ) {
|
|
626
|
-
any = 1;
|
|
627
|
-
break;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
if ( any ) {
|
|
631
|
-
if ( ! cb->mask ) {
|
|
632
|
-
ca_create_mask(cb);
|
|
633
|
-
}
|
|
634
|
-
memcpy(cb->mask->ptr, scratch, ne);
|
|
635
|
-
}
|
|
636
|
-
xfree(scratch);
|
|
637
|
-
}
|
|
638
|
-
else if ( ca_has_mask(ca) ) {
|
|
639
|
-
ca_cast_block_with_mask(cb->elements, ca, ca->ptr, cb, cb->ptr,
|
|
640
|
-
(boolean8_t*)ca->mask->ptr);
|
|
641
|
-
}
|
|
642
|
-
else {
|
|
643
|
-
ca_cast_block(cb->elements, ca, ca->ptr, cb, cb->ptr);
|
|
644
|
-
}
|
|
645
|
-
ca_detach(ca);
|
|
1380
|
+
ctx.ca = ca;
|
|
1381
|
+
ctx.cb = cb;
|
|
1382
|
+
ctx.scratch = NULL;
|
|
1383
|
+
ca_attach(ca); /* window: released by ca_to_type_release under rb_ensure */
|
|
1384
|
+
rb_ensure(ca_to_type_cast, (VALUE) &ctx, ca_to_type_release, (VALUE) &ctx);
|
|
646
1385
|
|
|
647
1386
|
/* When rtype is a data_class (e.g. CAStruct subclass), wrap the
|
|
648
1387
|
result in CARecord so the cast output carries data_class. */
|
|
@@ -1046,30 +1785,30 @@ rb_ca_ptr2obj (VALUE self, void *ptr)
|
|
|
1046
1785
|
}
|
|
1047
1786
|
|
|
1048
1787
|
/* Surface -> storage-domain conversion for a Face store (mirror of the
|
|
1049
|
-
|
|
1788
|
+
storage_to_element read hook). Non-Face `ca` returns `obj` unchanged, so
|
|
1050
1789
|
the non-Face store path is untouched. For a Face, the per-obj_type C
|
|
1051
1790
|
table is consulted first (fast path); if none is registered, the Ruby
|
|
1052
|
-
`
|
|
1791
|
+
`element_to_storage` method is called when defined. A Face that recognizes
|
|
1053
1792
|
`obj` returns a storage-domain value (e.g. an Integer in its unit); a bare
|
|
1054
1793
|
Integer / String falls through unchanged to the storage cast. */
|
|
1055
1794
|
VALUE
|
|
1056
|
-
|
|
1795
|
+
ca_face_element_to_storage (VALUE self, CArray *ca, VALUE obj)
|
|
1057
1796
|
{
|
|
1058
|
-
|
|
1797
|
+
ca_face_element_to_storage_fn fn;
|
|
1059
1798
|
if ( ! ca_face_safe_check(ca) || obj == CA_UNDEF ) {
|
|
1060
1799
|
return obj;
|
|
1061
1800
|
}
|
|
1062
|
-
fn =
|
|
1801
|
+
fn = ca_face_element_to_storage_table[ca->obj_type];
|
|
1063
1802
|
if ( fn != NULL ) {
|
|
1064
1803
|
return fn(self, obj);
|
|
1065
1804
|
}
|
|
1066
1805
|
else {
|
|
1067
|
-
static ID
|
|
1068
|
-
if (
|
|
1069
|
-
|
|
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");
|
|
1070
1809
|
}
|
|
1071
|
-
if ( rb_respond_to(self,
|
|
1072
|
-
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);
|
|
1073
1812
|
}
|
|
1074
1813
|
}
|
|
1075
1814
|
return obj;
|
|
@@ -1092,7 +1831,7 @@ rb_ca_obj2ptr (VALUE self, VALUE obj, void *ptr)
|
|
|
1092
1831
|
if ( ca_face_safe_check(ca) ) {
|
|
1093
1832
|
/* Face write hook: turn a surface value object (Scalar / Time /
|
|
1094
1833
|
DateTime) into a storage-domain value the cast below consumes. */
|
|
1095
|
-
obj =
|
|
1834
|
+
obj = ca_face_element_to_storage(self, ca, obj);
|
|
1096
1835
|
convert_type = ca_storage_type_of(ca);
|
|
1097
1836
|
}
|
|
1098
1837
|
if ( convert_type == CA_FIXLEN ) {
|
|
@@ -1114,7 +1853,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
|
|
|
1114
1853
|
if ( rb_obj_is_carray(obj) ) { /* obj == carray */
|
|
1115
1854
|
TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
|
|
1116
1855
|
if ( ca_is_readonly(ca) ) {
|
|
1117
|
-
rb_raise(rb_eRuntimeError, "can
|
|
1856
|
+
rb_raise(rb_eRuntimeError, "can not modify read-only array");
|
|
1118
1857
|
}
|
|
1119
1858
|
if ( NIL_P(rtype) ) {
|
|
1120
1859
|
data_type = ca->data_type;
|
|
@@ -1152,7 +1891,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
|
|
|
1152
1891
|
}
|
|
1153
1892
|
TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
|
|
1154
1893
|
if ( ca_is_readonly(ca) ) {
|
|
1155
|
-
rb_raise(rb_eRuntimeError, "can
|
|
1894
|
+
rb_raise(rb_eRuntimeError, "can not modify read-only array");
|
|
1156
1895
|
}
|
|
1157
1896
|
if ( NIL_P(rtype) ) {
|
|
1158
1897
|
data_type = ca->data_type;
|
|
@@ -1185,7 +1924,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
|
|
|
1185
1924
|
}
|
|
1186
1925
|
else {
|
|
1187
1926
|
volatile VALUE inspect = rb_inspect(CLASS_OF(obj));
|
|
1188
|
-
rb_raise(
|
|
1927
|
+
rb_raise(rb_eTypeError,
|
|
1189
1928
|
"given object '%s' can't be wrapped as carray",
|
|
1190
1929
|
StringValuePtr(inspect));
|
|
1191
1930
|
}
|
|
@@ -1366,6 +2105,92 @@ rb_ca_cast (volatile VALUE self)
|
|
|
1366
2105
|
return obj;
|
|
1367
2106
|
}
|
|
1368
2107
|
|
|
2108
|
+
/* A String operand against a fixlen array is a value of that array's cell
|
|
2109
|
+
width. ca_value_to_data_type answers CA_OBJECT for a String, so without
|
|
2110
|
+
this the operand became an object scalar and the comparison ran down the
|
|
2111
|
+
object lane -- an rb_funcall of String#== per cell, against the cell's
|
|
2112
|
+
NUL-padded text. A fixlen array pads a short String on write
|
|
2113
|
+
(`a[i] = "be"` stores "be\0\0\0"), so that answered that an array does
|
|
2114
|
+
not equal the string it was written from, and did it 30x slower than the
|
|
2115
|
+
memcmp lane the fixlen comparison bodies are there to provide.
|
|
2116
|
+
|
|
2117
|
+
Two fixlen *arrays* of different widths keep the variable-width byte
|
|
2118
|
+
string semantics those bodies implement (min-width memcmp with a length
|
|
2119
|
+
tiebreak); this is only about a scalar standing in for a cell. */
|
|
2120
|
+
static int
|
|
2121
|
+
ca_fixlen_scalar_operand (volatile VALUE *scalar, VALUE reference)
|
|
2122
|
+
{
|
|
2123
|
+
CArray *cr;
|
|
2124
|
+
/* A String is the only operand that means a cell value here. A Regexp
|
|
2125
|
+
(match) or any other object keeps its own coercion: those are asking
|
|
2126
|
+
something about the bytes, not standing in for them. */
|
|
2127
|
+
if ( ! RB_TYPE_P(*scalar, T_STRING) || ! rb_obj_is_carray(reference) ) {
|
|
2128
|
+
return 0;
|
|
2129
|
+
}
|
|
2130
|
+
TypedData_Get_Struct(reference, CArray, &carray_data_type, cr);
|
|
2131
|
+
if ( cr->data_type != CA_FIXLEN ) {
|
|
2132
|
+
return 0;
|
|
2133
|
+
}
|
|
2134
|
+
*scalar = rb_cscalar_new_with_value(CA_FIXLEN, cr->bytes, *scalar);
|
|
2135
|
+
return 1;
|
|
2136
|
+
}
|
|
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
|
+
|
|
1369
2194
|
/* CArray.cast(value) -- singleton entry delegating to rb_ca_cast, which
|
|
1370
2195
|
returns a CArray unchanged and coerces a Ruby value to a CScalar / CArray.
|
|
1371
2196
|
User doc lives in yard-stubs/carray_cast.rb. */
|
|
@@ -1376,6 +2201,41 @@ rb_ca_s_cast (VALUE klass, VALUE val)
|
|
|
1376
2201
|
return rb_ca_cast(val);
|
|
1377
2202
|
}
|
|
1378
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
|
+
|
|
1379
2239
|
void
|
|
1380
2240
|
rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
1381
2241
|
{
|
|
@@ -1388,11 +2248,11 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1388
2248
|
Excludes T_STRING which has its own legacy interpretation. */
|
|
1389
2249
|
if ( ! rb_obj_is_carray(*self) && TYPE(*self) != T_STRING &&
|
|
1390
2250
|
rb_memory_view_available_p(*self) ) {
|
|
1391
|
-
*self =
|
|
2251
|
+
*self = ca_operand_from_memory_view(*self);
|
|
1392
2252
|
}
|
|
1393
2253
|
if ( ! rb_obj_is_carray(*other) && TYPE(*other) != T_STRING &&
|
|
1394
2254
|
rb_memory_view_available_p(*other) ) {
|
|
1395
|
-
*other =
|
|
2255
|
+
*other = ca_operand_from_memory_view(*other);
|
|
1396
2256
|
}
|
|
1397
2257
|
|
|
1398
2258
|
if ( ! rb_obj_is_carray(*self) ) {
|
|
@@ -1409,6 +2269,12 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1409
2269
|
*self = rb_cscalar_new_with_value(CA_CMPLX128, 0, *self);
|
|
1410
2270
|
}
|
|
1411
2271
|
#endif
|
|
2272
|
+
else if ( ca_fixlen_scalar_operand(self, *other) ) {
|
|
2273
|
+
/* width taken from the fixlen reference; see the helper above */
|
|
2274
|
+
}
|
|
2275
|
+
else if ( ca_integer_scalar_operand(self, *other) ) {
|
|
2276
|
+
/* the array's own integer type; see the helper above */
|
|
2277
|
+
}
|
|
1412
2278
|
else if ( rb_ca_is_float_type(*other) ) {
|
|
1413
2279
|
*self = rb_cscalar_new_with_value(CA_FLOAT64, 0, *self);
|
|
1414
2280
|
}
|
|
@@ -1437,6 +2303,12 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1437
2303
|
*other = rb_cscalar_new_with_value(CA_CMPLX128, 0, *other);
|
|
1438
2304
|
}
|
|
1439
2305
|
#endif
|
|
2306
|
+
else if ( ca_fixlen_scalar_operand(other, *self) ) {
|
|
2307
|
+
/* width taken from the fixlen reference; see the helper above */
|
|
2308
|
+
}
|
|
2309
|
+
else if ( ca_integer_scalar_operand(other, *self) ) {
|
|
2310
|
+
/* the array's own integer type; see the helper above */
|
|
2311
|
+
}
|
|
1440
2312
|
else if ( rb_ca_is_float_type(*self) ) {
|
|
1441
2313
|
*other = rb_cscalar_new_with_value(CA_FLOAT64, 0, *other);
|
|
1442
2314
|
}
|
|
@@ -1506,10 +2378,10 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1506
2378
|
return;
|
|
1507
2379
|
}
|
|
1508
2380
|
|
|
1509
|
-
rb_raise(
|
|
2381
|
+
rb_raise(rb_eTypeError,
|
|
1510
2382
|
"can't coerce carray with data_types of '%s' and '%s'",
|
|
1511
|
-
|
|
1512
|
-
|
|
2383
|
+
ca_coerce_operand_name(*self, ca),
|
|
2384
|
+
ca_coerce_operand_name(*other, cb));
|
|
1513
2385
|
}
|
|
1514
2386
|
|
|
1515
2387
|
/* CArray.cast_self_or_other(self, other) — promote self and other
|
|
@@ -1610,33 +2482,129 @@ ca_promote_type (int8_t a, int8_t b)
|
|
|
1610
2482
|
/* b should be cast to a */
|
|
1611
2483
|
return a;
|
|
1612
2484
|
}
|
|
1613
|
-
rb_raise(
|
|
2485
|
+
rb_raise(rb_eCADataTypeError,
|
|
1614
2486
|
"can't promote data_types '%s' and '%s' to a common type",
|
|
1615
2487
|
ca_type_name[a], ca_type_name[b]);
|
|
1616
2488
|
}
|
|
1617
2489
|
|
|
1618
|
-
/*
|
|
1619
|
-
|
|
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
|
|
1620
2572
|
CArray / Symbol / String / Class gives a data_type representation, a
|
|
1621
2573
|
Numeric / bool / nil / Object gives a value whose data_type is inferred.
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
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. */
|
|
1625
2578
|
|
|
1626
2579
|
static VALUE
|
|
1627
2580
|
rb_ca_s_result_type (int argc, VALUE *argv, VALUE klass)
|
|
1628
2581
|
{
|
|
1629
|
-
int8_t cur;
|
|
2582
|
+
int8_t cur = -1;
|
|
1630
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);
|
|
1631
2592
|
|
|
1632
2593
|
if ( argc < 1 ) {
|
|
1633
2594
|
rb_raise(rb_eArgError, "result_type requires at least one argument");
|
|
1634
2595
|
}
|
|
1635
2596
|
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
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
|
+
}
|
|
1640
2608
|
}
|
|
1641
2609
|
/* Return Symbol for family consistency with
|
|
1642
2610
|
CArray.value_to_data_type and ca.data_type. */
|
|
@@ -1676,9 +2644,6 @@ rb_ca_s_promote_list (int argc, VALUE *argv, VALUE klass)
|
|
|
1676
2644
|
{
|
|
1677
2645
|
VALUE list, kwargs, data_type = Qnil;
|
|
1678
2646
|
long n, i;
|
|
1679
|
-
int all_face = 1, any_face = 0, all_primitive = 1;
|
|
1680
|
-
VALUE face_class = Qnil;
|
|
1681
|
-
CArray *ref_face = NULL;
|
|
1682
2647
|
int8_t common = -1;
|
|
1683
2648
|
|
|
1684
2649
|
rb_scan_args(argc, argv, "1:", &list, &kwargs);
|
|
@@ -1697,49 +2662,26 @@ rb_ca_s_promote_list (int argc, VALUE *argv, VALUE klass)
|
|
|
1697
2662
|
if ( RB_TYPE_P(data_type, T_CLASS) || RB_TYPE_P(data_type, T_MODULE) ) {
|
|
1698
2663
|
rb_raise(rb_eArgError,
|
|
1699
2664
|
"promote_list: data_type must be a primitive Symbol "
|
|
1700
|
-
"(Class targets are not supported;
|
|
1701
|
-
"
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
|
-
/* Classify each element: Face / primitive CArray. Detect Face-class
|
|
1706
|
-
homogeneity as we go. */
|
|
1707
|
-
for ( i = 0; i < n; i++ ) {
|
|
1708
|
-
VALUE elem = rb_ary_entry(list, i);
|
|
1709
|
-
CArray *ca;
|
|
1710
|
-
rb_check_carray_object(elem);
|
|
1711
|
-
TypedData_Get_Struct(elem, CArray, &carray_data_type, ca);
|
|
1712
|
-
if ( ca_is_face(ca) ) {
|
|
1713
|
-
any_face = 1;
|
|
1714
|
-
all_primitive = 0;
|
|
1715
|
-
if ( NIL_P(face_class) ) {
|
|
1716
|
-
face_class = rb_obj_class(elem);
|
|
1717
|
-
ref_face = ca;
|
|
1718
|
-
} else if ( rb_obj_class(elem) != face_class ) {
|
|
1719
|
-
all_face = 0; /* will be caught after the loop */
|
|
1720
|
-
} else if ( all_face ) {
|
|
1721
|
-
if ( ! ca_face_state_compatible(rb_ary_entry(list, 0), ref_face,
|
|
1722
|
-
elem, ca) ) {
|
|
1723
|
-
rb_raise(rb_eArgError,
|
|
1724
|
-
"promote_list: Face state mismatch across elements "
|
|
1725
|
-
"(= %s instance at index %ld differs from index 0)",
|
|
1726
|
-
rb_class2name(face_class), i);
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
} else {
|
|
1730
|
-
all_face = 0;
|
|
2665
|
+
"(Class targets are not supported; leave data_type out to "
|
|
2666
|
+
"keep a Face)");
|
|
1731
2667
|
}
|
|
1732
2668
|
}
|
|
1733
2669
|
|
|
1734
2670
|
/* Explicit data_type path: primitive Symbol, all elements must be
|
|
1735
2671
|
primitive. Reject if any Face in list. */
|
|
1736
2672
|
if ( ! NIL_P(data_type) ) {
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
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
|
+
}
|
|
1743
2685
|
}
|
|
1744
2686
|
{
|
|
1745
2687
|
VALUE out = rb_ary_new_capa(n);
|
|
@@ -1754,41 +2696,24 @@ rb_ca_s_promote_list (int argc, VALUE *argv, VALUE klass)
|
|
|
1754
2696
|
}
|
|
1755
2697
|
}
|
|
1756
2698
|
|
|
1757
|
-
/* Auto-detect path.
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
"promote_list: cannot mix Face and non-Face (or heterogeneous "
|
|
1764
|
-
"Face classes); pass a homogeneous Face list, or strip Face "
|
|
1765
|
-
"manually with .parent for the storage-level layout");
|
|
1766
|
-
}
|
|
1767
|
-
}
|
|
1768
|
-
|
|
1769
|
-
if ( all_face ) {
|
|
1770
|
-
/* Homogeneous Face: validate portability, then pass through. */
|
|
1771
|
-
if ( n > 1 && ! ca_face_state_portable(ref_face->obj_type, face_class) ) {
|
|
1772
|
-
rb_raise(rb_eArgError,
|
|
1773
|
-
"promote_list: %s state is not portable across multiple "
|
|
1774
|
-
"elements (= per-parent storage like CAConstString's buffer); "
|
|
1775
|
-
"strip Face manually with .parent for a storage-level list",
|
|
1776
|
-
rb_class2name(face_class));
|
|
1777
|
-
}
|
|
1778
|
-
/* Return a fresh Array so callers can mutate without aliasing. */
|
|
1779
|
-
{
|
|
1780
|
-
VALUE out = rb_ary_new_capa(n);
|
|
1781
|
-
for ( i = 0; i < n; i++ ) rb_ary_push(out, rb_ary_entry(list, i));
|
|
1782
|
-
return out;
|
|
1783
|
-
}
|
|
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;
|
|
1784
2705
|
}
|
|
1785
2706
|
|
|
1786
2707
|
/* All primitive: result_type to determine common data_type, then
|
|
1787
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. */
|
|
1788
2713
|
common = ca_arg_to_data_type(rb_ary_entry(list, 0));
|
|
1789
2714
|
for ( i = 1; i < n; i++ ) {
|
|
1790
2715
|
int8_t next = ca_arg_to_data_type(rb_ary_entry(list, i));
|
|
1791
|
-
common = ca_promote_type(common, next);
|
|
2716
|
+
common = ca_value_match_type(ca_promote_type(common, next), common, next);
|
|
1792
2717
|
}
|
|
1793
2718
|
{
|
|
1794
2719
|
VALUE common_sym = rb_ca_data_type_to_sym(common);
|
|
@@ -1817,13 +2742,16 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
|
|
|
1817
2742
|
Excludes T_STRING which has its own legacy interpretation. */
|
|
1818
2743
|
if ( ! rb_obj_is_carray(*other) && TYPE(*other) != T_STRING &&
|
|
1819
2744
|
rb_memory_view_available_p(*other) ) {
|
|
1820
|
-
*other =
|
|
2745
|
+
*other = ca_operand_from_memory_view(*other);
|
|
1821
2746
|
}
|
|
1822
2747
|
|
|
1823
2748
|
if ( ! rb_obj_is_carray(*other) ) {
|
|
1824
2749
|
if ( rb_ca_is_object_type(*self) ) {
|
|
1825
2750
|
*other = rb_cscalar_new_with_value(CA_OBJECT, 0, *other);
|
|
1826
2751
|
}
|
|
2752
|
+
else if ( ca_fixlen_scalar_operand(other, *self) ) {
|
|
2753
|
+
return; /* already the receiver's data_type and width */
|
|
2754
|
+
}
|
|
1827
2755
|
else if ( rb_ca_is_float_type(*self) ) {
|
|
1828
2756
|
*other = rb_cscalar_new_with_value(CA_FLOAT64, 0, *other);
|
|
1829
2757
|
}
|
|
@@ -1859,10 +2787,10 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
|
|
|
1859
2787
|
return;
|
|
1860
2788
|
}
|
|
1861
2789
|
|
|
1862
|
-
rb_raise(
|
|
2790
|
+
rb_raise(rb_eTypeError,
|
|
1863
2791
|
"can't coerce carray with data_types of '%s' and '%s'",
|
|
1864
|
-
|
|
1865
|
-
|
|
2792
|
+
ca_coerce_operand_name(*self, ca),
|
|
2793
|
+
ca_coerce_operand_name(*other, cb));
|
|
1866
2794
|
}
|
|
1867
2795
|
|
|
1868
2796
|
/* CArray#cast_with(other) -- coerce self and other to a common
|
|
@@ -1877,7 +2805,7 @@ rb_ca_cast_with (VALUE self, VALUE other)
|
|
|
1877
2805
|
rb_ca_cast_self_or_other(&self, &other);
|
|
1878
2806
|
}
|
|
1879
2807
|
else {
|
|
1880
|
-
rb_raise(
|
|
2808
|
+
rb_raise(rb_eTypeError, "first argument should be a carray");
|
|
1881
2809
|
}
|
|
1882
2810
|
return rb_assoc_new(self, other);
|
|
1883
2811
|
}
|
|
@@ -1926,7 +2854,7 @@ rb_ca_clip_uint64 (VALUE self)
|
|
|
1926
2854
|
volatile VALUE vout = rb_carray_new(CA_UINT64, ca->ndim, ca->dim, 0, NULL);
|
|
1927
2855
|
CArray *out;
|
|
1928
2856
|
GetCArray(vout, out);
|
|
1929
|
-
ca_attach(src);
|
|
2857
|
+
ca_attach(src); /* window: nothing raises inside */
|
|
1930
2858
|
double *sp = (double *) src->ptr;
|
|
1931
2859
|
uint64_t *op = (uint64_t *) out->ptr;
|
|
1932
2860
|
ca_size_t n = ca->elements;
|
|
@@ -1954,16 +2882,19 @@ rb_ca_clip_uint64 (VALUE self)
|
|
|
1954
2882
|
Polymorphic cast (NOT a fresh allocator): `data` is coerced into a CArray
|
|
1955
2883
|
of the target data_type, dispatching on its Ruby class:
|
|
1956
2884
|
|
|
1957
|
-
Array
|
|
1958
|
-
CArray
|
|
1959
|
-
nil
|
|
1960
|
-
Range
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
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.
|
|
1967
2898
|
------------------------------------------------------------------------ */
|
|
1968
2899
|
|
|
1969
2900
|
static ID id_new_cast = 0, id_guess_array_shape_cast = 0, id_cast_string = 0,
|
|
@@ -1989,6 +2920,21 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
|
|
|
1989
2920
|
VALUE v = ( argc >= 1 ) ? argv[0] : Qnil;
|
|
1990
2921
|
VALUE sym = ID2SYM(ca_data_type_sym[data_type]);
|
|
1991
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
|
+
|
|
1992
2938
|
if ( TYPE(v) == T_ARRAY ) {
|
|
1993
2939
|
volatile VALUE shape, obj;
|
|
1994
2940
|
shape = rb_funcall(rb_cCArray, id_guess_array_shape_cast, 1, v);
|
|
@@ -2009,8 +2955,9 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
|
|
|
2009
2955
|
return rb_carray_new(data_type, 1, &dim0, 0, NULL);
|
|
2010
2956
|
}
|
|
2011
2957
|
else if ( RTEST(rb_obj_is_kind_of(v, rb_cRange)) ) {
|
|
2012
|
-
/* arange: n = ((end - begin).abs / step).floor
|
|
2013
|
-
|
|
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). */
|
|
2014
2961
|
volatile VALUE vbeg, vend, step, n;
|
|
2015
2962
|
int sign;
|
|
2016
2963
|
ca_size_t dn;
|
|
@@ -2020,7 +2967,7 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
|
|
|
2020
2967
|
vend = rb_funcall(v, id_end_cast, 0);
|
|
2021
2968
|
step = ( argc >= 2 ) ? argv[1] : Qnil;
|
|
2022
2969
|
if ( RTEST(step) && RTEST(rb_funcall(step, id_op_eq, 1, INT2FIX(0))) ) {
|
|
2023
|
-
rb_raise(
|
|
2970
|
+
rb_raise(rb_eArgError, "step should not be 0");
|
|
2024
2971
|
}
|
|
2025
2972
|
if ( data_type == CA_OBJECT && !RTEST(step) ) {
|
|
2026
2973
|
VALUE va = rb_funcall(v, id_to_a_cast, 0); /* CA_OBJECT(v.to_a) */
|
|
@@ -2029,9 +2976,13 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
|
|
|
2029
2976
|
if ( !RTEST(step) ) step = INT2FIX(1);
|
|
2030
2977
|
n = rb_funcall(vend, id_op_minus, 1, vbeg);
|
|
2031
2978
|
n = rb_funcall(n, id_abs_cast, 0);
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
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);
|
|
2035
2986
|
n = rb_funcall(n, id_op_plus, 1, INT2FIX(1));
|
|
2036
2987
|
}
|
|
2037
2988
|
sign = RTEST(rb_funcall(vbeg, id_op_le, 1, vend)) ? 1 : -1;
|
|
@@ -2132,7 +3083,7 @@ rb_ca_cast_fixlen (int argc, VALUE *argv, VALUE self)
|
|
|
2132
3083
|
ca_size_t l = NUM2SIZE(rb_funcall(rb_ary_entry(v, i), id_length_cast, 0));
|
|
2133
3084
|
if ( l > maxlen ) maxlen = l;
|
|
2134
3085
|
}
|
|
2135
|
-
bytes = maxlen;
|
|
3086
|
+
bytes = ( maxlen > 0 ) ? maxlen : 1; /* all empty: one NUL byte */
|
|
2136
3087
|
} else {
|
|
2137
3088
|
bytes = NUM2SIZE(bytes_v);
|
|
2138
3089
|
}
|
|
@@ -2145,7 +3096,7 @@ rb_ca_cast_fixlen (int argc, VALUE *argv, VALUE self)
|
|
|
2145
3096
|
}
|
|
2146
3097
|
else if ( NIL_P(v) ) {
|
|
2147
3098
|
ca_size_t dim0 = 0;
|
|
2148
|
-
ca_size_t bytes = NIL_P(bytes_v) ?
|
|
3099
|
+
ca_size_t bytes = NIL_P(bytes_v) ? 1 : NUM2SIZE(bytes_v);
|
|
2149
3100
|
return rb_carray_new(CA_FIXLEN, 1, &dim0, bytes, NULL);
|
|
2150
3101
|
}
|
|
2151
3102
|
else {
|
|
@@ -2157,17 +3108,373 @@ rb_ca_cast_fixlen (int argc, VALUE *argv, VALUE self)
|
|
|
2157
3108
|
? ca : ca_cast_to_fixlen(ca, fixlen_sym, bytes_v);
|
|
2158
3109
|
}
|
|
2159
3110
|
{
|
|
2160
|
-
|
|
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
|
+
}
|
|
2161
3121
|
return rb_cscalar_new_with_value(CA_FIXLEN, bytes, v);
|
|
2162
3122
|
}
|
|
2163
3123
|
}
|
|
2164
3124
|
}
|
|
2165
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
|
+
|
|
2166
3462
|
void
|
|
2167
3463
|
Init_carray_cast (void)
|
|
2168
3464
|
{
|
|
2169
3465
|
/* CArray data_type conversion */
|
|
2170
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
|
+
|
|
2171
3478
|
rb_define_method(rb_cCArray, "to_type", rb_ca_to_type_internal, -1);
|
|
2172
3479
|
|
|
2173
3480
|
rb_define_method(rb_cCArray, "fixlen", rb_ca_to_fixlen, -1);
|
|
@@ -2232,6 +3539,8 @@ Init_carray_cast (void)
|
|
|
2232
3539
|
"cast_self_or_other", rb_ca_s_cast_self_or_other, 2);
|
|
2233
3540
|
rb_define_singleton_method(rb_cCArray,
|
|
2234
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);
|
|
2235
3544
|
|
|
2236
3545
|
rb_define_singleton_method(rb_cCArray,
|
|
2237
3546
|
"promote_list", rb_ca_s_promote_list, -1);
|