carray 3.0.2 → 3.0.4
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 +568 -0
- data/README.md +6 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +220 -0
- data/ext/ca_axis_group.c +201 -123
- data/ext/ca_binop_dispatch.c +46 -52
- data/ext/ca_binop_dispatch.h +1 -1
- data/ext/ca_categorical_iterator.c +249 -183
- data/ext/ca_compare.c +7 -12
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +38 -23
- data/ext/ca_kernel_iterator.c +1765 -2076
- data/ext/ca_kernel_iterator.h +584 -566
- data/ext/ca_monop_dispatch.c +86 -63
- data/ext/ca_monop_dispatch.h +5 -0
- data/ext/ca_obj_array.c +223 -56
- data/ext/ca_obj_bincmp.c +172 -138
- data/ext/ca_obj_binop.c +116 -230
- data/ext/ca_obj_bitarray.c +40 -26
- data/ext/ca_obj_bitfield.c +100 -68
- data/ext/ca_obj_block.c +19 -9
- data/ext/ca_obj_byte_swap.c +45 -46
- data/ext/ca_obj_const_string.c +269 -44
- data/ext/ca_obj_face.c +612 -89
- data/ext/ca_obj_face.h +111 -47
- data/ext/ca_obj_fake.c +36 -79
- data/ext/ca_obj_farray.c +7 -3
- data/ext/ca_obj_field.c +33 -8
- data/ext/ca_obj_fixlen_string.c +23 -24
- data/ext/ca_obj_grid.c +541 -210
- data/ext/ca_obj_meld.c +331 -111
- data/ext/ca_obj_moncmp.c +80 -65
- data/ext/ca_obj_monop.c +177 -149
- data/ext/ca_obj_object.c +664 -248
- data/ext/ca_obj_record.c +63 -23
- data/ext/ca_obj_reduce.c +18 -16
- data/ext/ca_obj_refer.c +140 -58
- data/ext/ca_obj_remap.c +85 -24
- data/ext/ca_obj_repeat.c +24 -9
- data/ext/ca_obj_roll.c +121 -16
- data/ext/ca_obj_select.c +61 -58
- data/ext/ca_obj_select_axis.c +73 -107
- data/ext/ca_obj_shift.c +32 -102
- data/ext/ca_obj_stack.c +372 -122
- data/ext/ca_obj_stride.c +348 -140
- data/ext/ca_obj_string.c +88 -22
- data/ext/ca_obj_tile.c +38 -21
- data/ext/ca_obj_time.c +45 -31
- data/ext/ca_obj_timedelta.c +43 -29
- data/ext/ca_obj_transpose.c +17 -6
- data/ext/ca_obj_triop.c +125 -141
- data/ext/ca_obj_window.c +330 -44
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +104 -81
- data/ext/ca_sweep_engine.h +7 -20
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +542 -0
- data/ext/carray.h +241 -92
- data/ext/carray_access.c +608 -276
- data/ext/carray_address_basis.c +494 -97
- data/ext/carray_attribute.c +129 -4
- data/ext/carray_bincount.c +39 -7
- data/ext/carray_broadcast.c +56 -19
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_call_cfunc.c +108 -28
- data/ext/carray_cast.c +1576 -223
- data/ext/carray_cast_func.rb +77 -24
- data/ext/carray_class.c +4 -3
- data/ext/carray_conversion.c +208 -75
- data/ext/carray_copy.c +82 -24
- data/ext/carray_core.c +646 -162
- data/ext/carray_count.c +171 -88
- data/ext/carray_element.c +94 -60
- data/ext/carray_factorize.c +670 -324
- data/ext/carray_generate.c +260 -83
- data/ext/carray_histogram.c +209 -106
- data/ext/carray_hold.c +14 -16
- data/ext/carray_index_classifier.c +422 -243
- data/ext/carray_internal.h +692 -3
- data/ext/carray_kernels_bincmp.c +7 -0
- data/ext/carray_kernels_binop.c +487 -120
- data/ext/carray_kernels_init.c +653 -50
- data/ext/carray_kernels_moncmp.c +15 -8
- data/ext/carray_kernels_monop.c +99 -43
- data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
- data/ext/carray_kernels_reduce_boolean.c +112 -36
- data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
- data/ext/carray_kernels_reduce_extreme.c +3032 -2892
- data/ext/carray_kernels_reduce_variance.c +439 -500
- data/ext/carray_kernels_scan.c +1097 -488
- data/ext/carray_kernels_search.c +3787 -2176
- data/ext/carray_kernels_sort.c +1200 -920
- data/ext/carray_kernels_triop.c +479 -7
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +967 -153
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +910 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +299 -100
- data/ext/carray_memory_view.c +872 -758
- data/ext/carray_operator.c +1171 -364
- data/ext/carray_order.c +505 -133
- data/ext/carray_partition.c +112 -65
- data/ext/carray_random.c +327 -239
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +346 -78
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +249 -86
- data/ext/carray_sort.c +224 -227
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +118 -39
- data/ext/carray_test.c +193 -69
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +579 -113
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +19 -4
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1202 -1014
- data/ext/ruby_carray.c +17 -5
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +160 -17
- data/lib/carray/autoload_carray.rb +23 -27
- data/lib/carray/autoload_method_extension.rb +20 -5
- data/lib/carray/axis_group.rb +360 -63
- data/lib/carray/basics.rb +162 -28
- data/lib/carray/bincount_nd.rb +18 -2
- data/lib/carray/block_iterator.rb +231 -58
- data/lib/carray/boolean_reduce.rb +34 -42
- data/lib/carray/categorical.rb +242 -52
- data/lib/carray/categorical_iterator.rb +437 -827
- data/lib/carray/complex.rb +41 -34
- data/lib/carray/conditional.rb +150 -14
- data/lib/carray/const_string.rb +59 -4
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +7 -1
- data/lib/carray/frame/column_verbs.rb +70 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +82 -7
- data/lib/carray/frame/csv_parser.rb +688 -87
- data/lib/carray/frame/describe.rb +80 -0
- data/lib/carray/frame/frame.rb +369 -45
- data/lib/carray/frame/group.rb +631 -90
- data/lib/carray/frame/io.rb +506 -79
- data/lib/carray/frame/join.rb +411 -62
- data/lib/carray/frame/records.rb +116 -19
- data/lib/carray/frame/reshape.rb +455 -0
- data/lib/carray/frame/sort.rb +30 -18
- data/lib/carray/frame/verbs.rb +868 -61
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +4 -0
- data/lib/carray/fuse_source.rb +118 -2
- data/lib/carray/fusion.rb +257 -42
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +54 -13
- data/lib/carray/iterator.rb +99 -9
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +216 -193
- data/lib/carray/mask_gap_fill.rb +112 -92
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +52 -21
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +18 -2
- data/lib/carray/methods/bit_string.rb +15 -4
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +18 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +25 -5
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +140 -10
- data/lib/carray/methods/join.rb +2 -7
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +182 -45
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +65 -17
- data/lib/carray/segment_iterator.rb +1221 -0
- data/lib/carray/serialize.rb +214 -30
- data/lib/carray/slab_iterator.rb +101 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +12 -4
- data/lib/carray/struct.rb +137 -58
- data/lib/carray/struct_builder.rb +124 -17
- data/lib/carray/time.rb +1222 -186
- data/lib/carray/window_iterator.rb +242 -81
- data/lib/carray.rb +9 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +5 -1
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +5 -4
- data/yard-stubs/ca_obj_roll.rb +2 -3
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +9 -5
- data/yard-stubs/carray_access.rb +11 -5
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +88 -43
- data/yard-stubs/carray_conversion.rb +15 -2
- data/yard-stubs/carray_copy.rb +12 -5
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +60 -12
- data/yard-stubs/carray_math.rb +52 -14
- data/yard-stubs/carray_median_percentile.rb +15 -8
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +61 -29
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +21 -9
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +10 -2
- data/yard-stubs/carray_sort.rb +49 -8
- data/yard-stubs/carray_test.rb +15 -3
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -5
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_kernels_map.c +0 -3467
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_cast.c
CHANGED
|
@@ -34,11 +34,574 @@
|
|
|
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
|
+
/* protect: a BigDecimal that is not finite reads as no integer; nothing is held */
|
|
500
|
+
VALUE whole = rb_protect(ca_decimal_truncate, v, &state);
|
|
501
|
+
if ( state ) {
|
|
502
|
+
rb_set_errinfo(Qnil);
|
|
503
|
+
return 0;
|
|
504
|
+
}
|
|
505
|
+
if ( ! RB_INTEGER_TYPE_P(whole) || ! RTEST(rb_equal(whole, v)) ) {
|
|
506
|
+
return 0;
|
|
507
|
+
}
|
|
508
|
+
v = whole;
|
|
509
|
+
}
|
|
510
|
+
if ( RB_INTEGER_TYPE_P(v) ) {
|
|
511
|
+
VALUE zero = INT2FIX(0);
|
|
512
|
+
*negative = RTEST(rb_funcall(v, '<', 1, zero));
|
|
513
|
+
if ( *negative ) {
|
|
514
|
+
v = rb_funcall(v, rb_intern("-@"), 0);
|
|
515
|
+
}
|
|
516
|
+
if ( RTEST(rb_funcall(v, '>', 1, ULL2NUM(UINT64_MAX))) ) {
|
|
517
|
+
return 0;
|
|
518
|
+
}
|
|
519
|
+
*magnitude = NUM2ULL(v);
|
|
520
|
+
return 1;
|
|
521
|
+
}
|
|
522
|
+
if ( RB_FLOAT_TYPE_P(v) ) {
|
|
523
|
+
double d = RFLOAT_VALUE(v);
|
|
524
|
+
if ( d != d || d != floor(d) || fabs(d) >= 18446744073709551616.0 ) {
|
|
525
|
+
return 0;
|
|
526
|
+
}
|
|
527
|
+
*negative = ( d < 0 );
|
|
528
|
+
*magnitude = (uint64_t) fabs(d);
|
|
529
|
+
return 1;
|
|
530
|
+
}
|
|
531
|
+
return 0;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/* A String as one value of data_type (an integer or float type), written
|
|
535
|
+
to out. */
|
|
536
|
+
static int
|
|
537
|
+
ca_decimal_read_bytes_as (const char *s, long n, int8_t data_type, void *out)
|
|
538
|
+
{
|
|
539
|
+
ca_decimal_trim(&s, &n);
|
|
540
|
+
if ( n == 0 ) {
|
|
541
|
+
return CA_DECIMAL_BLANK;
|
|
542
|
+
}
|
|
543
|
+
if ( data_type == CA_FLOAT32 || data_type == CA_FLOAT64 ) {
|
|
544
|
+
double d;
|
|
545
|
+
if ( ! ca_decimal_float(s, n, &d) ) {
|
|
546
|
+
return CA_DECIMAL_UNREADABLE;
|
|
547
|
+
}
|
|
548
|
+
if ( data_type == CA_FLOAT32 ) {
|
|
549
|
+
*(float32_t *) out = (float32_t) d;
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
*(float64_t *) out = d;
|
|
553
|
+
}
|
|
554
|
+
return CA_DECIMAL_OK;
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
int negative = 0;
|
|
558
|
+
uint64_t magnitude = 0;
|
|
559
|
+
int rc = ca_decimal_integer(s, n, &negative, &magnitude);
|
|
560
|
+
if ( rc != CA_DECIMAL_OK ) {
|
|
561
|
+
return rc;
|
|
562
|
+
}
|
|
563
|
+
if ( ! ca_decimal_fits(data_type, negative, magnitude) ) {
|
|
564
|
+
return CA_DECIMAL_OUT_OF_RANGE;
|
|
565
|
+
}
|
|
566
|
+
ca_decimal_store_integer(data_type, (char *) out, 0, negative, magnitude);
|
|
567
|
+
return CA_DECIMAL_OK;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
static int
|
|
572
|
+
ca_decimal_string_read (VALUE str, int8_t data_type, void *out)
|
|
573
|
+
{
|
|
574
|
+
return ca_decimal_read_bytes_as(RSTRING_PTR(str), RSTRING_LEN(str), data_type, out);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/* The to_type reader: 1 with the value at out, or 0 for a cell that
|
|
578
|
+
becomes UNDEF. */
|
|
579
|
+
int
|
|
580
|
+
ca_decimal_string_to (VALUE str, int8_t data_type, void *out)
|
|
581
|
+
{
|
|
582
|
+
return ca_decimal_string_read(str, data_type, out) == CA_DECIMAL_OK;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/* The store reader: the value at out, or a raise. */
|
|
586
|
+
void
|
|
587
|
+
ca_decimal_string_store (VALUE str, int8_t data_type, void *out)
|
|
588
|
+
{
|
|
589
|
+
switch ( ca_decimal_string_read(str, data_type, out) ) {
|
|
590
|
+
case CA_DECIMAL_OK:
|
|
591
|
+
return;
|
|
592
|
+
case CA_DECIMAL_OUT_OF_RANGE:
|
|
593
|
+
rb_raise(rb_eRangeError, "%s: %+"PRIsVALUE" is out of range for %s",
|
|
594
|
+
ca_calling_method_name(), str, ca_type_name[data_type]);
|
|
595
|
+
default:
|
|
596
|
+
rb_raise(rb_eArgError, "%s: %+"PRIsVALUE" cannot be read as %s",
|
|
597
|
+
ca_calling_method_name(), str, ca_type_name[data_type]);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
37
600
|
|
|
38
601
|
boolean8_t
|
|
39
602
|
OBJ2BOOL (VALUE v)
|
|
40
603
|
{
|
|
41
|
-
if ( v == Qfalse
|
|
604
|
+
if ( v == Qfalse ) {
|
|
42
605
|
return 0;
|
|
43
606
|
}
|
|
44
607
|
else if ( v == Qtrue ) {
|
|
@@ -99,25 +662,20 @@ OBJ2DBL (VALUE val)
|
|
|
99
662
|
switch ( TYPE(val) ) {
|
|
100
663
|
case T_FLOAT:
|
|
101
664
|
return NUM2DBL(val);
|
|
102
|
-
case T_NIL:
|
|
103
|
-
return 0.0/0.0;
|
|
104
665
|
case T_STRING: {
|
|
105
666
|
double d;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if ( ca_str_nonfinite(str, &d) ) {
|
|
109
|
-
return d;
|
|
110
|
-
}
|
|
111
|
-
return rb_cstr_to_dbl(str, 0);
|
|
667
|
+
ca_decimal_string_store(val, CA_FLOAT64, &d);
|
|
668
|
+
return d;
|
|
112
669
|
}
|
|
113
670
|
default:
|
|
114
671
|
return NUM2DBL(rb_Float(val));
|
|
115
672
|
}
|
|
116
673
|
}
|
|
117
674
|
|
|
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)
|
|
675
|
+
/* rb_protect bodies: Kernel#Float / Kernel#Integer applied to one value
|
|
676
|
+
that is not a String. Used by the mask-aware object->numeric parsers
|
|
677
|
+
below so a conversion error is caught (and turned into a masked cell)
|
|
678
|
+
rather than raised. */
|
|
121
679
|
static VALUE
|
|
122
680
|
ca_kernel_float (VALUE v)
|
|
123
681
|
{
|
|
@@ -130,12 +688,71 @@ ca_kernel_integer (VALUE v)
|
|
|
130
688
|
return rb_Integer(v);
|
|
131
689
|
}
|
|
132
690
|
|
|
691
|
+
/* Complex#to_s writes a part that is not finite as "NaN" or "Infinity" and
|
|
692
|
+
then marks the imaginary part with "*i" ("1.0+Infinity*i", "NaN+0i"),
|
|
693
|
+
which Complex() does not read back. Read that form as two decimal
|
|
694
|
+
numbers: the imaginary part starts at the last sign that is not the
|
|
695
|
+
first character and not an exponent's. Returns 0 when the text is not
|
|
696
|
+
of that form. */
|
|
697
|
+
static int
|
|
698
|
+
ca_str_to_cmplx_nonfinite (VALUE str, double complex *out)
|
|
699
|
+
{
|
|
700
|
+
const char *s = RSTRING_PTR(str);
|
|
701
|
+
long n = RSTRING_LEN(str), k;
|
|
702
|
+
double re, im;
|
|
703
|
+
volatile VALUE vre, vim;
|
|
704
|
+
while ( n > 0 && ( s[0] == ' ' || s[0] == '\t' ) ) { s++; n--; }
|
|
705
|
+
while ( n > 0 && ( s[n-1] == ' ' || s[n-1] == '\t' ) ) { n--; }
|
|
706
|
+
if ( n < 2 || s[n-1] != 'i' ) {
|
|
707
|
+
return 0;
|
|
708
|
+
}
|
|
709
|
+
n -= ( n >= 2 && s[n-2] == '*' ) ? 2 : 1;
|
|
710
|
+
for ( k = n - 1; k > 0; k-- ) {
|
|
711
|
+
if ( ( s[k] == '+' || s[k] == '-' ) && s[k-1] != 'e' && s[k-1] != 'E' ) {
|
|
712
|
+
break;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
if ( k <= 0 ) {
|
|
716
|
+
return 0;
|
|
717
|
+
}
|
|
718
|
+
vre = rb_str_new(s, k);
|
|
719
|
+
vim = rb_str_new(s + k, n - k);
|
|
720
|
+
if ( ! ca_decimal_string_to(vre, CA_FLOAT64, &re)
|
|
721
|
+
|| ! ca_decimal_string_to(vim, CA_FLOAT64, &im) ) {
|
|
722
|
+
return 0;
|
|
723
|
+
}
|
|
724
|
+
*out = CMPLX(re, im);
|
|
725
|
+
return 1;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/* A real is read as a decimal number; anything else goes to Complex(). */
|
|
729
|
+
double complex
|
|
730
|
+
ca_str_to_cmplx (VALUE str)
|
|
731
|
+
{
|
|
732
|
+
volatile VALUE rstr;
|
|
733
|
+
volatile VALUE c;
|
|
734
|
+
double d;
|
|
735
|
+
double complex z;
|
|
736
|
+
if ( ca_decimal_string_to(str, CA_FLOAT64, &d) ) {
|
|
737
|
+
return (double complex) d;
|
|
738
|
+
}
|
|
739
|
+
if ( ( memchr(RSTRING_PTR(str), 'N', RSTRING_LEN(str))
|
|
740
|
+
|| memchr(RSTRING_PTR(str), 'I', RSTRING_LEN(str)) )
|
|
741
|
+
&& ca_str_to_cmplx_nonfinite(str, &z) ) {
|
|
742
|
+
return z;
|
|
743
|
+
}
|
|
744
|
+
rstr = rb_funcall(str, rb_intern("strip"), 0);
|
|
745
|
+
c = rb_funcall(rb_mKernel, rb_intern("Complex"), 1, rstr);
|
|
746
|
+
return CMPLX(NUM2DBL(rb_complex_real(c)), NUM2DBL(rb_complex_imag(c)));
|
|
747
|
+
}
|
|
748
|
+
|
|
133
749
|
/* Object -> double with parse-failure signalling. Returns 1 and sets *out
|
|
134
750
|
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
|
-
|
|
751
|
+
caller writes UNDEF (mask) for that cell. nil and unreadable
|
|
752
|
+
strings/objects fail; already-numeric values succeed, and a String is
|
|
753
|
+
read as a decimal number. This is the reading path of to_type from an
|
|
754
|
+
object array, where a cell with no number in it is a missing value; a
|
|
755
|
+
store (OBJ2DBL) raises instead. */
|
|
139
756
|
int
|
|
140
757
|
ca_obj2dbl_ok (VALUE val, double *out)
|
|
141
758
|
{
|
|
@@ -147,13 +764,11 @@ ca_obj2dbl_ok (VALUE val, double *out)
|
|
|
147
764
|
return 1;
|
|
148
765
|
}
|
|
149
766
|
if ( RB_TYPE_P(val, T_STRING) ) {
|
|
150
|
-
|
|
151
|
-
if ( ca_str_nonfinite(StringValuePtr(rstr), out) ) {
|
|
152
|
-
return 1;
|
|
153
|
-
}
|
|
767
|
+
return ca_decimal_string_to(val, CA_FLOAT64, out);
|
|
154
768
|
}
|
|
155
769
|
{
|
|
156
770
|
int state = 0;
|
|
771
|
+
/* protect: converts the caller's value and reports failure; nothing is held */
|
|
157
772
|
volatile VALUE r = rb_protect(ca_kernel_float, val, &state);
|
|
158
773
|
if ( state ) {
|
|
159
774
|
rb_set_errinfo(Qnil);
|
|
@@ -164,98 +779,120 @@ ca_obj2dbl_ok (VALUE val, double *out)
|
|
|
164
779
|
}
|
|
165
780
|
}
|
|
166
781
|
|
|
167
|
-
/* Object ->
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
782
|
+
/* Object -> complex with parse-failure signalling: the complex sibling of
|
|
783
|
+
ca_obj2dbl_ok. A cell is read as a store reads it (a real as a decimal
|
|
784
|
+
number, the rest as Complex()); nil and a cell that does not read fail. */
|
|
785
|
+
static VALUE
|
|
786
|
+
ca_cmplx_cell_body (VALUE v)
|
|
787
|
+
{
|
|
788
|
+
double complex z = rb_carray_num2cmplx(v);
|
|
789
|
+
return rb_dbl_complex_new(creal(z), cimag(z));
|
|
790
|
+
}
|
|
791
|
+
|
|
173
792
|
int
|
|
174
|
-
|
|
793
|
+
ca_obj2cmplx_ok (VALUE val, double complex *out)
|
|
794
|
+
{
|
|
795
|
+
int state = 0;
|
|
796
|
+
volatile VALUE r;
|
|
797
|
+
if ( NIL_P(val) ) {
|
|
798
|
+
return 0;
|
|
799
|
+
}
|
|
800
|
+
/* protect: converts the caller's value and reports failure; nothing is held */
|
|
801
|
+
r = rb_protect(ca_cmplx_cell_body, val, &state);
|
|
802
|
+
if ( state ) {
|
|
803
|
+
rb_set_errinfo(Qnil);
|
|
804
|
+
return 0;
|
|
805
|
+
}
|
|
806
|
+
*out = CMPLX(NUM2DBL(rb_complex_real(r)), NUM2DBL(rb_complex_imag(r)));
|
|
807
|
+
return 1;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/* Object -> integer with parse-failure signalling. Same contract as
|
|
811
|
+
ca_obj2dbl_ok: 1 + *out on success, 0 (mask) on failure. A String is
|
|
812
|
+
read as a decimal number ("1.5" fails, no truncation); any other object
|
|
813
|
+
goes through Integer(). nil fails. A valid Integer that overflows the
|
|
814
|
+
widest C integer still raises (a domain error, not a parse failure). */
|
|
815
|
+
static int
|
|
816
|
+
ca_obj2integer_ok (VALUE val, int8_t wide_type, void *wide, VALUE *integer)
|
|
175
817
|
{
|
|
818
|
+
int state = 0;
|
|
176
819
|
if ( NIL_P(val) ) {
|
|
177
820
|
return 0;
|
|
178
821
|
}
|
|
822
|
+
if ( RB_TYPE_P(val, T_STRING) ) {
|
|
823
|
+
return ca_decimal_string_to(val, wide_type, wide);
|
|
824
|
+
}
|
|
825
|
+
/* protect: converts the caller's value and reports failure; nothing is held */
|
|
826
|
+
*integer = rb_protect(ca_kernel_integer, val, &state);
|
|
827
|
+
if ( state ) {
|
|
828
|
+
rb_set_errinfo(Qnil);
|
|
829
|
+
return 0;
|
|
830
|
+
}
|
|
831
|
+
return 1;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
int
|
|
835
|
+
rb_obj2long_ok (VALUE val, long *out)
|
|
836
|
+
{
|
|
837
|
+
int64_t wide;
|
|
838
|
+
VALUE integer = Qnil;
|
|
179
839
|
if ( RB_TYPE_P(val, T_FIXNUM) ) {
|
|
180
840
|
*out = NUM2LONG(val);
|
|
181
841
|
return 1;
|
|
182
842
|
}
|
|
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;
|
|
843
|
+
if ( ! ca_obj2integer_ok(val, CA_INT64, &wide, &integer) ) {
|
|
844
|
+
return 0;
|
|
192
845
|
}
|
|
846
|
+
*out = NIL_P(integer) ? (long) wide : NUM2LONG(integer);
|
|
847
|
+
return 1;
|
|
193
848
|
}
|
|
194
849
|
|
|
195
850
|
int
|
|
196
851
|
rb_obj2ulong_ok (VALUE val, unsigned long *out)
|
|
197
852
|
{
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
853
|
+
uint64_t wide;
|
|
854
|
+
VALUE integer = Qnil;
|
|
201
855
|
if ( RB_TYPE_P(val, T_FIXNUM) ) {
|
|
202
856
|
*out = NUM2ULONG(val);
|
|
203
857
|
return 1;
|
|
204
858
|
}
|
|
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;
|
|
859
|
+
if ( ! ca_obj2integer_ok(val, CA_UINT64, &wide, &integer) ) {
|
|
860
|
+
return 0;
|
|
214
861
|
}
|
|
862
|
+
*out = NIL_P(integer) ? (unsigned long) wide : NUM2ULONG(integer);
|
|
863
|
+
return 1;
|
|
215
864
|
}
|
|
216
865
|
|
|
217
866
|
int
|
|
218
867
|
rb_obj2ll_ok (VALUE val, long long *out)
|
|
219
868
|
{
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
869
|
+
int64_t wide;
|
|
870
|
+
VALUE integer = Qnil;
|
|
223
871
|
if ( RB_TYPE_P(val, T_FIXNUM) ) {
|
|
224
872
|
*out = NUM2LL(val);
|
|
225
873
|
return 1;
|
|
226
874
|
}
|
|
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;
|
|
875
|
+
if ( ! ca_obj2integer_ok(val, CA_INT64, &wide, &integer) ) {
|
|
876
|
+
return 0;
|
|
236
877
|
}
|
|
878
|
+
*out = NIL_P(integer) ? (long long) wide : NUM2LL(integer);
|
|
879
|
+
return 1;
|
|
237
880
|
}
|
|
238
881
|
|
|
239
882
|
int
|
|
240
883
|
rb_obj2ull_ok (VALUE val, unsigned long long *out)
|
|
241
884
|
{
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
885
|
+
uint64_t wide;
|
|
886
|
+
VALUE integer = Qnil;
|
|
245
887
|
if ( RB_TYPE_P(val, T_FIXNUM) ) {
|
|
246
888
|
*out = NUM2ULL(val);
|
|
247
889
|
return 1;
|
|
248
890
|
}
|
|
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;
|
|
891
|
+
if ( ! ca_obj2integer_ok(val, CA_UINT64, &wide, &integer) ) {
|
|
892
|
+
return 0;
|
|
258
893
|
}
|
|
894
|
+
*out = NIL_P(integer) ? (unsigned long long) wide : rb_num2ull(integer);
|
|
895
|
+
return 1;
|
|
259
896
|
}
|
|
260
897
|
|
|
261
898
|
long
|
|
@@ -267,8 +904,13 @@ rb_obj2long (VALUE val)
|
|
|
267
904
|
case T_BIGNUM:
|
|
268
905
|
return (long) NUM2LL(val);
|
|
269
906
|
case T_NIL:
|
|
270
|
-
rb_raise(rb_eTypeError, "
|
|
907
|
+
rb_raise(rb_eTypeError, "can't convert nil into Integer");
|
|
271
908
|
break;
|
|
909
|
+
case T_STRING: {
|
|
910
|
+
int64_t v;
|
|
911
|
+
ca_decimal_string_store(val, CA_INT64, &v);
|
|
912
|
+
return (long) v;
|
|
913
|
+
}
|
|
272
914
|
default:
|
|
273
915
|
return NUM2LONG(rb_Integer(val));
|
|
274
916
|
}
|
|
@@ -283,8 +925,13 @@ rb_obj2ulong (VALUE val)
|
|
|
283
925
|
case T_BIGNUM:
|
|
284
926
|
return (unsigned long) rb_num2ull(val);
|
|
285
927
|
case T_NIL:
|
|
286
|
-
rb_raise(rb_eTypeError, "
|
|
928
|
+
rb_raise(rb_eTypeError, "can't convert nil into Integer");
|
|
287
929
|
break;
|
|
930
|
+
case T_STRING: {
|
|
931
|
+
uint64_t v;
|
|
932
|
+
ca_decimal_string_store(val, CA_UINT64, &v);
|
|
933
|
+
return (unsigned long) v;
|
|
934
|
+
}
|
|
288
935
|
default:
|
|
289
936
|
return NUM2ULONG(rb_Integer(val));
|
|
290
937
|
}
|
|
@@ -297,8 +944,13 @@ rb_obj2ll (VALUE val)
|
|
|
297
944
|
case T_FIXNUM:
|
|
298
945
|
return NUM2LONG(val);
|
|
299
946
|
case T_NIL:
|
|
300
|
-
rb_raise(rb_eTypeError, "
|
|
947
|
+
rb_raise(rb_eTypeError, "can't convert nil into Integer");
|
|
301
948
|
break;
|
|
949
|
+
case T_STRING: {
|
|
950
|
+
int64_t v;
|
|
951
|
+
ca_decimal_string_store(val, CA_INT64, &v);
|
|
952
|
+
return (long long) v;
|
|
953
|
+
}
|
|
302
954
|
default:
|
|
303
955
|
return NUM2LL(rb_Integer(val));
|
|
304
956
|
}
|
|
@@ -311,8 +963,13 @@ rb_obj2ull (VALUE val)
|
|
|
311
963
|
case T_FIXNUM:
|
|
312
964
|
return NUM2ULONG(val);
|
|
313
965
|
case T_NIL:
|
|
314
|
-
rb_raise(rb_eTypeError, "
|
|
966
|
+
rb_raise(rb_eTypeError, "can't convert nil into Integer");
|
|
315
967
|
break;
|
|
968
|
+
case T_STRING: {
|
|
969
|
+
uint64_t v;
|
|
970
|
+
ca_decimal_string_store(val, CA_UINT64, &v);
|
|
971
|
+
return (unsigned long long) v;
|
|
972
|
+
}
|
|
316
973
|
default:
|
|
317
974
|
return rb_num2ull(rb_Integer(val));
|
|
318
975
|
}
|
|
@@ -334,7 +991,7 @@ ca_face_safe_check (CArray *ca)
|
|
|
334
991
|
static inline int8_t
|
|
335
992
|
ca_storage_type_of (CArray *ca)
|
|
336
993
|
{
|
|
337
|
-
|
|
994
|
+
if ( ca_face_safe_check(ca) ) ca = ca_strip_face(ca);
|
|
338
995
|
return ca ? ca->data_type : CA_FIXLEN;
|
|
339
996
|
}
|
|
340
997
|
|
|
@@ -399,7 +1056,7 @@ ca_ptr2val (void *ap1, void *ptr1, int8_t data_type, void *ptr2)
|
|
|
399
1056
|
{
|
|
400
1057
|
CArray *ca1 = (CArray *)ap1;
|
|
401
1058
|
static CArray dummy;
|
|
402
|
-
|
|
1059
|
+
CA_CHECK_DATA_TYPE_GIVEN(data_type);
|
|
403
1060
|
dummy.data_type = data_type;
|
|
404
1061
|
ca_cast_func_table[ca1->data_type][data_type](1, ca1, ptr1, &dummy, ptr2, NULL);
|
|
405
1062
|
return;
|
|
@@ -410,7 +1067,7 @@ ca_val2ptr (int8_t data_type, void *ptr1, void *ap2, void *ptr2)
|
|
|
410
1067
|
{
|
|
411
1068
|
CArray *ca2 = (CArray *)ap2;
|
|
412
1069
|
static CArray dummy;
|
|
413
|
-
|
|
1070
|
+
CA_CHECK_DATA_TYPE_GIVEN(data_type);
|
|
414
1071
|
dummy.data_type = data_type;
|
|
415
1072
|
ca_cast_func_table[data_type][ca2->data_type](1, &dummy, ptr1, ca2, ptr2, NULL);
|
|
416
1073
|
return;
|
|
@@ -420,8 +1077,8 @@ void
|
|
|
420
1077
|
ca_val2val (int8_t data_type1, void *ptr1, int8_t data_type2, void *ptr2)
|
|
421
1078
|
{
|
|
422
1079
|
static CArray dummy1, dummy2;
|
|
423
|
-
|
|
424
|
-
|
|
1080
|
+
CA_CHECK_DATA_TYPE_GIVEN(data_type1);
|
|
1081
|
+
CA_CHECK_DATA_TYPE_GIVEN(data_type2);
|
|
425
1082
|
dummy1.data_type = data_type1;
|
|
426
1083
|
dummy2.data_type = data_type2;
|
|
427
1084
|
ca_cast_func_table[data_type1][data_type2](1, &dummy1, ptr1, &dummy2, ptr2, NULL);
|
|
@@ -433,7 +1090,7 @@ ca_val2val (int8_t data_type1, void *ptr1, int8_t data_type2, void *ptr2)
|
|
|
433
1090
|
/* Cast to CA_OBJECT for an array whose cells mean something other than their
|
|
434
1091
|
storage bytes: a data_class array (CARecord / CAStruct) or a Face (CATime,
|
|
435
1092
|
CAConstString, CACategorical, ...). Both decode per cell -- rb_ca_fetch_addr
|
|
436
|
-
goes through the data_class decode and
|
|
1093
|
+
goes through the data_class decode and CA_FACE_STORAGE_TO_ELEMENT_IF_FACE --
|
|
437
1094
|
so the object array holds the *surface* values (labels, not codes;
|
|
438
1095
|
CATime::Element, not serials; the string, not the descriptor bytes). Reading
|
|
439
1096
|
the storage instead is `.parent`, which stays available and explicit. Mask
|
|
@@ -558,6 +1215,33 @@ typedef struct {
|
|
|
558
1215
|
boolean8_t *scratch;
|
|
559
1216
|
} ca_to_type_ctx_t;
|
|
560
1217
|
|
|
1218
|
+
/* Marks in `m` the cells of a float or complex array that hold NaN (in
|
|
1219
|
+
either part). A NaN has no integer, and C leaves its conversion
|
|
1220
|
+
undefined. */
|
|
1221
|
+
static void
|
|
1222
|
+
ca_mark_nan (CArray *ca, boolean8_t *m)
|
|
1223
|
+
{
|
|
1224
|
+
ca_size_t i, n = ca->elements;
|
|
1225
|
+
switch ( ca->data_type ) {
|
|
1226
|
+
case CA_FLOAT32: { float32_t *p = (float32_t *) ca->ptr;
|
|
1227
|
+
for (i=0; i<n; i++) if ( isnan(p[i]) ) m[i] = 1;
|
|
1228
|
+
break; }
|
|
1229
|
+
case CA_FLOAT64: { float64_t *p = (float64_t *) ca->ptr;
|
|
1230
|
+
for (i=0; i<n; i++) if ( isnan(p[i]) ) m[i] = 1;
|
|
1231
|
+
break; }
|
|
1232
|
+
#ifdef HAVE_COMPLEX_H
|
|
1233
|
+
case CA_CMPLX64: { cmplx64_t *p = (cmplx64_t *) ca->ptr;
|
|
1234
|
+
for (i=0; i<n; i++) if ( isnan(crealf(p[i])) || isnan(cimagf(p[i])) ) m[i] = 1;
|
|
1235
|
+
break; }
|
|
1236
|
+
case CA_CMPLX128: { cmplx128_t *p = (cmplx128_t *) ca->ptr;
|
|
1237
|
+
for (i=0; i<n; i++) if ( isnan(creal(p[i])) || isnan(cimag(p[i])) ) m[i] = 1;
|
|
1238
|
+
break; }
|
|
1239
|
+
#endif
|
|
1240
|
+
default:
|
|
1241
|
+
break;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
|
|
561
1245
|
/* The cast proper, with `ca` attached. It can raise (a value the target
|
|
562
1246
|
type cannot hold), so it runs under rb_ensure. */
|
|
563
1247
|
static VALUE
|
|
@@ -565,11 +1249,16 @@ ca_to_type_cast (VALUE arg)
|
|
|
565
1249
|
{
|
|
566
1250
|
ca_to_type_ctx_t *c = (ca_to_type_ctx_t *) arg;
|
|
567
1251
|
CArray *ca = c->ca, *cb = c->cb;
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
1252
|
+
int to_integer = ( cb->data_type >= CA_INT8 && cb->data_type <= CA_UINT64 );
|
|
1253
|
+
int from_float = ( ca->data_type == CA_FLOAT32 || ca->data_type == CA_FLOAT64
|
|
1254
|
+
|| ca->data_type == CA_CMPLX64 || ca->data_type == CA_CMPLX128 );
|
|
1255
|
+
|
|
1256
|
+
if ( ( ca->data_type == CA_OBJECT
|
|
1257
|
+
&& ( to_integer
|
|
1258
|
+
|| cb->data_type == CA_FLOAT32 || cb->data_type == CA_FLOAT64
|
|
1259
|
+
|| cb->data_type == CA_CMPLX64 || cb->data_type == CA_CMPLX128 ) )
|
|
1260
|
+
|| ( from_float && to_integer ) ) {
|
|
1261
|
+
/* object -> int/float/complex: give the cast a mask buffer so an unparseable
|
|
573
1262
|
cell becomes UNDEF (see ext/carray_cast_func.rb). Cast into a
|
|
574
1263
|
scratch mask seeded from the source mask, then attach it to the
|
|
575
1264
|
output only if some cell ended up masked -- an all-valid cast keeps
|
|
@@ -585,6 +1274,13 @@ ca_to_type_cast (VALUE arg)
|
|
|
585
1274
|
else {
|
|
586
1275
|
memset(scratch, 0, ne);
|
|
587
1276
|
}
|
|
1277
|
+
/* float -> integer: a NaN cell becomes UNDEF, as an unparseable object
|
|
1278
|
+
cell does. A finite value outside the integer type is converted the
|
|
1279
|
+
way the machine's C converts it, which differs between machines. */
|
|
1280
|
+
if ( from_float ) {
|
|
1281
|
+
ca_mark_nan(ca, scratch);
|
|
1282
|
+
memset(cb->ptr, 0, ne * cb->bytes);
|
|
1283
|
+
}
|
|
588
1284
|
ca_cast_block_with_mask(ne, ca, ca->ptr, cb, cb->ptr, scratch);
|
|
589
1285
|
for (i=0; i<ne; i++) {
|
|
590
1286
|
if ( scratch[i] ) {
|
|
@@ -627,8 +1323,20 @@ ca_to_type_release (VALUE arg)
|
|
|
627
1323
|
data_type (a new entity owning its storage). User doc lives in
|
|
628
1324
|
yard-stubs/carray_cast.rb. */
|
|
629
1325
|
|
|
1326
|
+
static VALUE rb_ca_to_type_convert (int argc, VALUE *argv, VALUE self);
|
|
1327
|
+
|
|
1328
|
+
/* The converted array keeps self's attributes: the values are the same
|
|
1329
|
+
values in another representation. */
|
|
630
1330
|
static VALUE
|
|
631
1331
|
rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
|
|
1332
|
+
{
|
|
1333
|
+
VALUE obj = rb_ca_to_type_convert(argc, argv, self);
|
|
1334
|
+
rb_ca_inherit_attr(obj, self);
|
|
1335
|
+
return obj;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
static VALUE
|
|
1339
|
+
rb_ca_to_type_convert (int argc, VALUE *argv, VALUE self)
|
|
632
1340
|
{
|
|
633
1341
|
volatile VALUE obj, rtype = Qnil, ropt, rbytes = Qnil;
|
|
634
1342
|
CArray *ca, *cb;
|
|
@@ -657,8 +1365,8 @@ rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
|
|
|
657
1365
|
Numeric Face is not routed here -- its surface *is* its storage, so the
|
|
658
1366
|
ordinary cast below is already right. */
|
|
659
1367
|
if ( ca_is_face(ca) && ca->data_type == CA_FIXLEN ) {
|
|
660
|
-
return
|
|
661
|
-
|
|
1368
|
+
return rb_ca_to_type_convert(argc, argv,
|
|
1369
|
+
rb_ca_face_numeric_projection(self, ca));
|
|
662
1370
|
}
|
|
663
1371
|
|
|
664
1372
|
ca_update_mask(ca);
|
|
@@ -676,7 +1384,7 @@ rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
|
|
|
676
1384
|
ctx.ca = ca;
|
|
677
1385
|
ctx.cb = cb;
|
|
678
1386
|
ctx.scratch = NULL;
|
|
679
|
-
ca_attach(ca);
|
|
1387
|
+
ca_attach(ca); /* window: released by ca_to_type_release under rb_ensure */
|
|
680
1388
|
rb_ensure(ca_to_type_cast, (VALUE) &ctx, ca_to_type_release, (VALUE) &ctx);
|
|
681
1389
|
|
|
682
1390
|
/* When rtype is a data_class (e.g. CAStruct subclass), wrap the
|
|
@@ -1063,8 +1771,11 @@ rb_ca_ptr2ptr (VALUE ra1, void *ptr1, VALUE ra2, void *ptr2)
|
|
|
1063
1771
|
}
|
|
1064
1772
|
|
|
1065
1773
|
|
|
1774
|
+
/* A cell's bytes as the value of self's data type before the last two
|
|
1775
|
+
steps of ca[i]: a boolean is 0 or 1 and a Face cell is its storage
|
|
1776
|
+
value. The element readers call this, check the mask, then decode. */
|
|
1066
1777
|
VALUE
|
|
1067
|
-
|
|
1778
|
+
rb_ca_ptr2obj_storage (VALUE self, void *ptr)
|
|
1068
1779
|
{
|
|
1069
1780
|
volatile VALUE obj;
|
|
1070
1781
|
static CArray dummy;
|
|
@@ -1080,31 +1791,45 @@ rb_ca_ptr2obj (VALUE self, void *ptr)
|
|
|
1080
1791
|
}
|
|
1081
1792
|
}
|
|
1082
1793
|
|
|
1794
|
+
VALUE
|
|
1795
|
+
rb_ca_ptr2obj (VALUE self, void *ptr)
|
|
1796
|
+
{
|
|
1797
|
+
CArray *ca;
|
|
1798
|
+
VALUE obj = rb_ca_ptr2obj_storage(self, ptr);
|
|
1799
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1800
|
+
CA_FACE_STORAGE_TO_ELEMENT_IF_FACE(obj, self, ca);
|
|
1801
|
+
if ( ca->data_type == CA_BOOLEAN &&
|
|
1802
|
+
( obj == INT2FIX(0) || obj == INT2FIX(1) ) ) {
|
|
1803
|
+
obj = ( obj == INT2FIX(1) ) ? Qtrue : Qfalse;
|
|
1804
|
+
}
|
|
1805
|
+
return obj;
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1083
1808
|
/* Surface -> storage-domain conversion for a Face store (mirror of the
|
|
1084
|
-
|
|
1809
|
+
storage_to_element read hook). Non-Face `ca` returns `obj` unchanged, so
|
|
1085
1810
|
the non-Face store path is untouched. For a Face, the per-obj_type C
|
|
1086
1811
|
table is consulted first (fast path); if none is registered, the Ruby
|
|
1087
|
-
`
|
|
1812
|
+
`element_to_storage` method is called when defined. A Face that recognizes
|
|
1088
1813
|
`obj` returns a storage-domain value (e.g. an Integer in its unit); a bare
|
|
1089
1814
|
Integer / String falls through unchanged to the storage cast. */
|
|
1090
1815
|
VALUE
|
|
1091
|
-
|
|
1816
|
+
ca_face_element_to_storage (VALUE self, CArray *ca, VALUE obj)
|
|
1092
1817
|
{
|
|
1093
|
-
|
|
1818
|
+
ca_face_element_to_storage_fn fn;
|
|
1094
1819
|
if ( ! ca_face_safe_check(ca) || obj == CA_UNDEF ) {
|
|
1095
1820
|
return obj;
|
|
1096
1821
|
}
|
|
1097
|
-
fn =
|
|
1822
|
+
fn = ca_face_element_to_storage_table[ca->obj_type];
|
|
1098
1823
|
if ( fn != NULL ) {
|
|
1099
1824
|
return fn(self, obj);
|
|
1100
1825
|
}
|
|
1101
1826
|
else {
|
|
1102
|
-
static ID
|
|
1103
|
-
if (
|
|
1104
|
-
|
|
1827
|
+
static ID id_element_to_storage = 0;
|
|
1828
|
+
if ( id_element_to_storage == 0 ) {
|
|
1829
|
+
id_element_to_storage = rb_intern("element_to_storage");
|
|
1105
1830
|
}
|
|
1106
|
-
if ( rb_respond_to(self,
|
|
1107
|
-
return rb_funcall(self,
|
|
1831
|
+
if ( rb_respond_to(self, id_element_to_storage) ) {
|
|
1832
|
+
return rb_funcall(self, id_element_to_storage, 1, obj);
|
|
1108
1833
|
}
|
|
1109
1834
|
}
|
|
1110
1835
|
return obj;
|
|
@@ -1127,7 +1852,7 @@ rb_ca_obj2ptr (VALUE self, VALUE obj, void *ptr)
|
|
|
1127
1852
|
if ( ca_face_safe_check(ca) ) {
|
|
1128
1853
|
/* Face write hook: turn a surface value object (Scalar / Time /
|
|
1129
1854
|
DateTime) into a storage-domain value the cast below consumes. */
|
|
1130
|
-
obj =
|
|
1855
|
+
obj = ca_face_element_to_storage(self, ca, obj);
|
|
1131
1856
|
convert_type = ca_storage_type_of(ca);
|
|
1132
1857
|
}
|
|
1133
1858
|
if ( convert_type == CA_FIXLEN ) {
|
|
@@ -1149,7 +1874,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
|
|
|
1149
1874
|
if ( rb_obj_is_carray(obj) ) { /* obj == carray */
|
|
1150
1875
|
TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
|
|
1151
1876
|
if ( ca_is_readonly(ca) ) {
|
|
1152
|
-
|
|
1877
|
+
ca_refuse_read_only();
|
|
1153
1878
|
}
|
|
1154
1879
|
if ( NIL_P(rtype) ) {
|
|
1155
1880
|
data_type = ca->data_type;
|
|
@@ -1187,7 +1912,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
|
|
|
1187
1912
|
}
|
|
1188
1913
|
TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
|
|
1189
1914
|
if ( ca_is_readonly(ca) ) {
|
|
1190
|
-
|
|
1915
|
+
ca_refuse_read_only();
|
|
1191
1916
|
}
|
|
1192
1917
|
if ( NIL_P(rtype) ) {
|
|
1193
1918
|
data_type = ca->data_type;
|
|
@@ -1201,12 +1926,9 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
|
|
|
1201
1926
|
}
|
|
1202
1927
|
}
|
|
1203
1928
|
else if ( rb_memory_view_available_p(obj) ) { /* MemoryView producer */
|
|
1204
|
-
obj =
|
|
1929
|
+
obj = ca_mv_wrap(obj, Qnil, rb_cCAWrap, -1,
|
|
1930
|
+
NIL_P(rtype) ? -1 : rb_ca_guess_type(rtype), 1);
|
|
1205
1931
|
TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
|
|
1206
|
-
if ( ca_is_readonly(ca) ) {
|
|
1207
|
-
rb_raise(rb_eRuntimeError,
|
|
1208
|
-
"MemoryView source is read-only; can't wrap as writable");
|
|
1209
|
-
}
|
|
1210
1932
|
if ( NIL_P(rtype) ) {
|
|
1211
1933
|
data_type = ca->data_type;
|
|
1212
1934
|
}
|
|
@@ -1220,7 +1942,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
|
|
|
1220
1942
|
}
|
|
1221
1943
|
else {
|
|
1222
1944
|
volatile VALUE inspect = rb_inspect(CLASS_OF(obj));
|
|
1223
|
-
rb_raise(
|
|
1945
|
+
rb_raise(rb_eTypeError,
|
|
1224
1946
|
"given object '%s' can't be wrapped as carray",
|
|
1225
1947
|
StringValuePtr(inspect));
|
|
1226
1948
|
}
|
|
@@ -1325,7 +2047,8 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
|
|
|
1325
2047
|
}
|
|
1326
2048
|
}
|
|
1327
2049
|
else if ( rb_memory_view_available_p(obj) ) { /* MemoryView producer */
|
|
1328
|
-
obj =
|
|
2050
|
+
obj = ca_mv_wrap(obj, Qnil, rb_cCAWrap, -1,
|
|
2051
|
+
NIL_P(rtype) ? -1 : rb_ca_guess_type(rtype), 0);
|
|
1329
2052
|
TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
|
|
1330
2053
|
if ( NIL_P(rtype) ) {
|
|
1331
2054
|
data_type = ca->data_type;
|
|
@@ -1431,6 +2154,92 @@ ca_fixlen_scalar_operand (volatile VALUE *scalar, VALUE reference)
|
|
|
1431
2154
|
return 1;
|
|
1432
2155
|
}
|
|
1433
2156
|
|
|
2157
|
+
/* Where a Ruby Integer falls against the range of integer data type `dt`:
|
|
2158
|
+
-1 below it, 1 above it, 0 inside. Anything but an Integer, and a
|
|
2159
|
+
non-integer `dt`, answer 0. */
|
|
2160
|
+
int
|
|
2161
|
+
ca_integer_range_side (VALUE v, int8_t dt)
|
|
2162
|
+
{
|
|
2163
|
+
VALUE lo, hi;
|
|
2164
|
+
if ( ! RB_INTEGER_TYPE_P(v) ) return 0;
|
|
2165
|
+
switch ( dt ) {
|
|
2166
|
+
case CA_INT8: lo = INT2FIX(INT8_MIN); hi = INT2FIX(INT8_MAX); break;
|
|
2167
|
+
case CA_UINT8: lo = INT2FIX(0); hi = INT2FIX(UINT8_MAX); break;
|
|
2168
|
+
case CA_INT16: lo = INT2FIX(INT16_MIN); hi = INT2FIX(INT16_MAX); break;
|
|
2169
|
+
case CA_UINT16: lo = INT2FIX(0); hi = INT2FIX(UINT16_MAX); break;
|
|
2170
|
+
case CA_INT32: lo = LL2NUM(INT32_MIN); hi = LL2NUM(INT32_MAX); break;
|
|
2171
|
+
case CA_UINT32: lo = INT2FIX(0); hi = ULL2NUM(UINT32_MAX); break;
|
|
2172
|
+
case CA_INT64: lo = LL2NUM(INT64_MIN); hi = LL2NUM(INT64_MAX); break;
|
|
2173
|
+
case CA_UINT64: lo = INT2FIX(0); hi = ULL2NUM(UINT64_MAX); break;
|
|
2174
|
+
default: return 0;
|
|
2175
|
+
}
|
|
2176
|
+
if ( RTEST(rb_funcall(v, rb_intern("<"), 1, lo)) ) return -1;
|
|
2177
|
+
if ( RTEST(rb_funcall(v, rb_intern(">"), 1, hi)) ) return 1;
|
|
2178
|
+
return 0;
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
/* Refuses a Ruby Integer that does not fit integer data type `dt`. Taken
|
|
2182
|
+
modulo the type, 256 against a uint8 array would be 0 and compare equal
|
|
2183
|
+
to it. */
|
|
2184
|
+
void
|
|
2185
|
+
ca_check_integer_fits (VALUE v, int8_t dt)
|
|
2186
|
+
{
|
|
2187
|
+
if ( ca_integer_range_side(v, dt) != 0 ) {
|
|
2188
|
+
rb_raise(rb_eRangeError, "%"PRIsVALUE" is out of range for %s",
|
|
2189
|
+
rb_inspect(v), ca_type_name[dt]);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
/* The store reader for an integer cell: the value as an Integer, refused
|
|
2194
|
+
when it does not fit the cell's type, as an operator refuses it. A
|
|
2195
|
+
store raises where an array cast (to_type) keeps the C conversion. A
|
|
2196
|
+
non-Integer goes through Integer() (1.5 is 1; nil and NaN raise). */
|
|
2197
|
+
VALUE
|
|
2198
|
+
ca_obj2integer_fitting (VALUE v, int8_t data_type)
|
|
2199
|
+
{
|
|
2200
|
+
VALUE integer = RB_INTEGER_TYPE_P(v) ? v : rb_Integer(v);
|
|
2201
|
+
if ( FIXNUM_P(integer) ) {
|
|
2202
|
+
long x = FIX2LONG(integer);
|
|
2203
|
+
int fits;
|
|
2204
|
+
switch ( data_type ) {
|
|
2205
|
+
case CA_INT8: fits = ( x >= INT8_MIN && x <= INT8_MAX ); break;
|
|
2206
|
+
case CA_UINT8: fits = ( x >= 0 && x <= UINT8_MAX ); break;
|
|
2207
|
+
case CA_INT16: fits = ( x >= INT16_MIN && x <= INT16_MAX ); break;
|
|
2208
|
+
case CA_UINT16: fits = ( x >= 0 && x <= UINT16_MAX ); break;
|
|
2209
|
+
case CA_INT32: fits = ( x >= INT32_MIN && x <= INT32_MAX ); break;
|
|
2210
|
+
case CA_UINT32: fits = ( x >= 0 && (unsigned long) x <= UINT32_MAX ); break;
|
|
2211
|
+
case CA_INT64: fits = 1; break;
|
|
2212
|
+
case CA_UINT64: fits = ( x >= 0 ); break;
|
|
2213
|
+
default: fits = 1; break;
|
|
2214
|
+
}
|
|
2215
|
+
if ( fits ) {
|
|
2216
|
+
return integer;
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
ca_check_integer_fits(integer, data_type);
|
|
2220
|
+
return integer;
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
/* A Ruby Integer operand against an integer array is taken in the array's
|
|
2224
|
+
own data type, refused when it does not fit (ca_check_integer_fits).
|
|
2225
|
+
Widening instead would make the result's type depend on a scalar's
|
|
2226
|
+
value. A Float, a Face and an object array keep the coercion below. */
|
|
2227
|
+
static int
|
|
2228
|
+
ca_integer_scalar_operand (volatile VALUE *scalar, VALUE reference)
|
|
2229
|
+
{
|
|
2230
|
+
CArray *cr;
|
|
2231
|
+
if ( ! RB_INTEGER_TYPE_P(*scalar) || ! rb_obj_is_carray(reference) ) {
|
|
2232
|
+
return 0;
|
|
2233
|
+
}
|
|
2234
|
+
TypedData_Get_Struct(reference, CArray, &carray_data_type, cr);
|
|
2235
|
+
if ( ! ca_is_integer_type(cr) || ca_is_face(cr) ) {
|
|
2236
|
+
return 0;
|
|
2237
|
+
}
|
|
2238
|
+
ca_check_integer_fits(*scalar, cr->data_type);
|
|
2239
|
+
*scalar = rb_cscalar_new_with_value(cr->data_type, 0, *scalar);
|
|
2240
|
+
return 1;
|
|
2241
|
+
}
|
|
2242
|
+
|
|
1434
2243
|
/* CArray.cast(value) -- singleton entry delegating to rb_ca_cast, which
|
|
1435
2244
|
returns a CArray unchanged and coerces a Ruby value to a CScalar / CArray.
|
|
1436
2245
|
User doc lives in yard-stubs/carray_cast.rb. */
|
|
@@ -1441,6 +2250,41 @@ rb_ca_s_cast (VALUE klass, VALUE val)
|
|
|
1441
2250
|
return rb_ca_cast(val);
|
|
1442
2251
|
}
|
|
1443
2252
|
|
|
2253
|
+
/* An operator operand that exports MemoryView, as a CArray. When the object
|
|
2254
|
+
also defines to_ca, that is asked first, in the order wrap_readonly uses:
|
|
2255
|
+
the MemoryView carries only the values buffer, while to_ca can hand over
|
|
2256
|
+
what the object knows besides it (the nulls of an Arrow array as a mask,
|
|
2257
|
+
a time type as a Face). Only MemoryView producers come here, so an object
|
|
2258
|
+
with to_ca alone (a Range) is still not an operand. */
|
|
2259
|
+
static VALUE
|
|
2260
|
+
ca_operand_from_memory_view (VALUE obj)
|
|
2261
|
+
{
|
|
2262
|
+
volatile VALUE ca;
|
|
2263
|
+
if ( rb_respond_to(obj, rb_intern("to_ca")) ) {
|
|
2264
|
+
ca = rb_funcall(obj, rb_intern("to_ca"), 0);
|
|
2265
|
+
if ( ! rb_obj_is_carray(ca) ) {
|
|
2266
|
+
volatile VALUE inspect = rb_inspect(CLASS_OF(obj));
|
|
2267
|
+
rb_raise(rb_eTypeError,
|
|
2268
|
+
"%s#to_ca did not return a CArray", StringValuePtr(inspect));
|
|
2269
|
+
}
|
|
2270
|
+
return ca;
|
|
2271
|
+
}
|
|
2272
|
+
return rb_funcall(rb_cCArray, rb_intern("wrap_memory_view"), 1, obj);
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
/* The name a coercion error gives an operand: its data type, or for a Face
|
|
2276
|
+
its class. A Face reports the data type of its storage ("fixlen" for a
|
|
2277
|
+
time, a categorical, a record or a string column), which says nothing
|
|
2278
|
+
about what the operand is. */
|
|
2279
|
+
static const char *
|
|
2280
|
+
ca_coerce_operand_name (VALUE obj, CArray *ca)
|
|
2281
|
+
{
|
|
2282
|
+
if ( ca_is_face(ca) ) {
|
|
2283
|
+
return rb_obj_classname(obj);
|
|
2284
|
+
}
|
|
2285
|
+
return ca_type_name[ca->data_type];
|
|
2286
|
+
}
|
|
2287
|
+
|
|
1444
2288
|
void
|
|
1445
2289
|
rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
1446
2290
|
{
|
|
@@ -1453,11 +2297,11 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1453
2297
|
Excludes T_STRING which has its own legacy interpretation. */
|
|
1454
2298
|
if ( ! rb_obj_is_carray(*self) && TYPE(*self) != T_STRING &&
|
|
1455
2299
|
rb_memory_view_available_p(*self) ) {
|
|
1456
|
-
*self =
|
|
2300
|
+
*self = ca_operand_from_memory_view(*self);
|
|
1457
2301
|
}
|
|
1458
2302
|
if ( ! rb_obj_is_carray(*other) && TYPE(*other) != T_STRING &&
|
|
1459
2303
|
rb_memory_view_available_p(*other) ) {
|
|
1460
|
-
*other =
|
|
2304
|
+
*other = ca_operand_from_memory_view(*other);
|
|
1461
2305
|
}
|
|
1462
2306
|
|
|
1463
2307
|
if ( ! rb_obj_is_carray(*self) ) {
|
|
@@ -1477,6 +2321,9 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1477
2321
|
else if ( ca_fixlen_scalar_operand(self, *other) ) {
|
|
1478
2322
|
/* width taken from the fixlen reference; see the helper above */
|
|
1479
2323
|
}
|
|
2324
|
+
else if ( ca_integer_scalar_operand(self, *other) ) {
|
|
2325
|
+
/* the array's own integer type; see the helper above */
|
|
2326
|
+
}
|
|
1480
2327
|
else if ( rb_ca_is_float_type(*other) ) {
|
|
1481
2328
|
*self = rb_cscalar_new_with_value(CA_FLOAT64, 0, *self);
|
|
1482
2329
|
}
|
|
@@ -1508,6 +2355,9 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1508
2355
|
else if ( ca_fixlen_scalar_operand(other, *self) ) {
|
|
1509
2356
|
/* width taken from the fixlen reference; see the helper above */
|
|
1510
2357
|
}
|
|
2358
|
+
else if ( ca_integer_scalar_operand(other, *self) ) {
|
|
2359
|
+
/* the array's own integer type; see the helper above */
|
|
2360
|
+
}
|
|
1511
2361
|
else if ( rb_ca_is_float_type(*self) ) {
|
|
1512
2362
|
*other = rb_cscalar_new_with_value(CA_FLOAT64, 0, *other);
|
|
1513
2363
|
}
|
|
@@ -1577,10 +2427,10 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
1577
2427
|
return;
|
|
1578
2428
|
}
|
|
1579
2429
|
|
|
1580
|
-
rb_raise(
|
|
2430
|
+
rb_raise(rb_eTypeError,
|
|
1581
2431
|
"can't coerce carray with data_types of '%s' and '%s'",
|
|
1582
|
-
|
|
1583
|
-
|
|
2432
|
+
ca_coerce_operand_name(*self, ca),
|
|
2433
|
+
ca_coerce_operand_name(*other, cb));
|
|
1584
2434
|
}
|
|
1585
2435
|
|
|
1586
2436
|
/* CArray.cast_self_or_other(self, other) — promote self and other
|
|
@@ -1624,7 +2474,7 @@ ca_arg_to_data_type (VALUE obj)
|
|
|
1624
2474
|
else {
|
|
1625
2475
|
data_type = ca_value_to_data_type(obj);
|
|
1626
2476
|
}
|
|
1627
|
-
|
|
2477
|
+
CA_CHECK_DATA_TYPE_GIVEN(data_type);
|
|
1628
2478
|
if ( ! ca_valid[data_type] ) {
|
|
1629
2479
|
rb_raise(rb_eArgError,
|
|
1630
2480
|
"data type '%s' is not valid in this build",
|
|
@@ -1664,6 +2514,9 @@ int8_t
|
|
|
1664
2514
|
ca_promote_type (int8_t a, int8_t b)
|
|
1665
2515
|
{
|
|
1666
2516
|
int test;
|
|
2517
|
+
if ( a <= CA_NONE || a >= CA_NTYPE || b <= CA_NONE || b >= CA_NTYPE ) {
|
|
2518
|
+
rb_raise(rb_eArgError, "invalid data_type id (%i, %i)", (int) a, (int) b);
|
|
2519
|
+
}
|
|
1667
2520
|
if ( a == b ) {
|
|
1668
2521
|
return a;
|
|
1669
2522
|
}
|
|
@@ -1681,34 +2534,185 @@ ca_promote_type (int8_t a, int8_t b)
|
|
|
1681
2534
|
/* b should be cast to a */
|
|
1682
2535
|
return a;
|
|
1683
2536
|
}
|
|
1684
|
-
rb_raise(
|
|
2537
|
+
rb_raise(rb_eCADataTypeError,
|
|
1685
2538
|
"can't promote data_types '%s' and '%s' to a common type",
|
|
1686
2539
|
ca_type_name[a], ca_type_name[b]);
|
|
1687
2540
|
}
|
|
1688
2541
|
|
|
1689
|
-
/*
|
|
1690
|
-
|
|
2542
|
+
/* The type in which values of types `a` and `b`, whose common type is `t`,
|
|
2543
|
+
are matched for equality. It is `t`, except where `t` cannot hold every
|
|
2544
|
+
value of both: an integer pair of mixed sign whose common type is
|
|
2545
|
+
unsigned (uint8 with int8 is uint8, where -1 would read as 255) moves to
|
|
2546
|
+
a signed type that holds both, or, for 64 bits, where no numeric type
|
|
2547
|
+
does, to object, whose Integers compare by value; and an integer of 32
|
|
2548
|
+
bits or more beside a float32 (or cmplx64) moves to double precision. `eq` answers the
|
|
2549
|
+
mixed-sign pair by value. */
|
|
2550
|
+
int8_t
|
|
2551
|
+
ca_value_match_type (int8_t t, int8_t a, int8_t b)
|
|
2552
|
+
{
|
|
2553
|
+
int signed_a = ( a == CA_INT8 || a == CA_INT16 || a == CA_INT32 || a == CA_INT64 );
|
|
2554
|
+
int signed_b = ( b == CA_INT8 || b == CA_INT16 || b == CA_INT32 || b == CA_INT64 );
|
|
2555
|
+
int wide_a = ( a == CA_INT32 || a == CA_UINT32 || a == CA_INT64 || a == CA_UINT64 );
|
|
2556
|
+
int wide_b = ( b == CA_INT32 || b == CA_UINT32 || b == CA_INT64 || b == CA_UINT64 );
|
|
2557
|
+
/* An integer of 32 bits or more beside a single-precision float: float32
|
|
2558
|
+
holds integers only up to 2**24 (every value of a 16-bit integer, not of
|
|
2559
|
+
a 32-bit one), so the match moves to double precision, which holds every
|
|
2560
|
+
value of a 32-bit integer and of a float32 (a 64-bit integer only up to
|
|
2561
|
+
2**53). */
|
|
2562
|
+
if ( wide_a || wide_b ) {
|
|
2563
|
+
if ( t == CA_FLOAT32 ) return CA_FLOAT64;
|
|
2564
|
+
if ( t == CA_CMPLX64 ) return CA_CMPLX128;
|
|
2565
|
+
}
|
|
2566
|
+
if ( ! signed_a && ! signed_b ) return t;
|
|
2567
|
+
switch ( t ) {
|
|
2568
|
+
case CA_UINT8: return CA_INT16;
|
|
2569
|
+
case CA_UINT16: return CA_INT32;
|
|
2570
|
+
case CA_UINT32: return CA_INT64;
|
|
2571
|
+
case CA_UINT64: return CA_OBJECT;
|
|
2572
|
+
default: return t;
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
/* The type a value query and a reference of type `ref` are compared in,
|
|
2577
|
+
by equality or order, as `eq` compares them: the reference is read
|
|
2578
|
+
through a view of that type, so the query is never cut to the
|
|
2579
|
+
reference's type (3.9 does not match 3, -1 does not read as 255).
|
|
2580
|
+
A Float query takes the type the operators give it beside the
|
|
2581
|
+
reference; an Integer query keeps the reference's type when it fits and
|
|
2582
|
+
otherwise the type its value needs, where it matches nothing; a CArray
|
|
2583
|
+
query takes the type the two arrays match in (the common type, widened
|
|
2584
|
+
by ca_value_match_type). Beside a reference that is not a number, a
|
|
2585
|
+
scalar query keeps the reference's type. */
|
|
2586
|
+
int8_t
|
|
2587
|
+
ca_query_match_type (int8_t ref, VALUE query)
|
|
2588
|
+
{
|
|
2589
|
+
int ref_int = ( ref >= CA_INT8 && ref <= CA_UINT64 );
|
|
2590
|
+
int ref_float = ( ref == CA_FLOAT32 || ref == CA_FLOAT64 );
|
|
2591
|
+
if ( rb_obj_is_carray(query) ) {
|
|
2592
|
+
CArray *q;
|
|
2593
|
+
TypedData_Get_Struct(query, CArray, &carray_data_type, q);
|
|
2594
|
+
return ca_value_match_type(ca_promote_type(ref, q->data_type), ref,
|
|
2595
|
+
q->data_type);
|
|
2596
|
+
}
|
|
2597
|
+
if ( ! ref_int && ! ref_float && ref != CA_BOOLEAN ) {
|
|
2598
|
+
return ref;
|
|
2599
|
+
}
|
|
2600
|
+
if ( RB_FLOAT_TYPE_P(query) ) {
|
|
2601
|
+
return ca_promote_scalar_type(ref, query, CA_FLOAT64);
|
|
2602
|
+
}
|
|
2603
|
+
if ( RB_INTEGER_TYPE_P(query) ) {
|
|
2604
|
+
return ref_int ? ca_promote_scalar_type(ref, query, CA_INT64) : ref;
|
|
2605
|
+
}
|
|
2606
|
+
return ref;
|
|
2607
|
+
}
|
|
2608
|
+
|
|
2609
|
+
/* ca.query_match_type(query) -- ca_query_match_type with self as the
|
|
2610
|
+
reference, for the set family and locate_addr. */
|
|
2611
|
+
static VALUE
|
|
2612
|
+
rb_ca_query_match_type (VALUE self, VALUE query)
|
|
2613
|
+
{
|
|
2614
|
+
CArray *ca;
|
|
2615
|
+
GetCArray(self, ca);
|
|
2616
|
+
return rb_ca_data_type_to_sym(ca_query_match_type(ca->data_type, query));
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
/* ca.value_match_type(t, other_type) -- ca_value_match_type with self's
|
|
2620
|
+
data type as the first operand, for the set family and locate_addr. */
|
|
2621
|
+
static VALUE
|
|
2622
|
+
rb_ca_value_match_type (VALUE self, VALUE vt, VALUE vother)
|
|
2623
|
+
{
|
|
2624
|
+
CArray *ca;
|
|
2625
|
+
GetCArray(self, ca);
|
|
2626
|
+
return rb_ca_data_type_to_sym(ca_value_match_type(rb_ca_guess_type(vt), ca->data_type,
|
|
2627
|
+
rb_ca_guess_type(vother)));
|
|
2628
|
+
}
|
|
2629
|
+
|
|
2630
|
+
/* A result_type argument that is a scalar: a Ruby value (Integer, Float,
|
|
2631
|
+
true, ...) or a CScalar. The operators let a scalar take the type of the
|
|
2632
|
+
array beside it, so result_type does too. */
|
|
2633
|
+
static int
|
|
2634
|
+
ca_arg_is_scalar (VALUE obj)
|
|
2635
|
+
{
|
|
2636
|
+
if ( rb_obj_is_carray(obj) ) {
|
|
2637
|
+
CArray *ca;
|
|
2638
|
+
TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
|
|
2639
|
+
return ca_is_scalar(ca);
|
|
2640
|
+
}
|
|
2641
|
+
if ( TYPE(obj) == T_SYMBOL || TYPE(obj) == T_STRING || TYPE(obj) == T_CLASS ) {
|
|
2642
|
+
return 0;
|
|
2643
|
+
}
|
|
2644
|
+
return ca_mv_probe_data_type(obj) < 0;
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
/* The type a scalar `obj` (of type `st`) and an array of type `at` share,
|
|
2648
|
+
by the rule the operators apply: a scalar of the same kind takes the
|
|
2649
|
+
array's type (0.1 beside float32 is float32, 1 beside int8 is int8); one
|
|
2650
|
+
of another kind promotes (1.5 beside int32 is float64). An Integer that
|
|
2651
|
+
does not fit the array's integer type takes a type that holds it and the
|
|
2652
|
+
array's values (int64, or object where no integer type does), where an
|
|
2653
|
+
operator would raise RangeError. */
|
|
2654
|
+
int8_t
|
|
2655
|
+
ca_promote_scalar_type (int8_t at, VALUE obj, int8_t st)
|
|
2656
|
+
{
|
|
2657
|
+
if ( RB_INTEGER_TYPE_P(obj) && at >= CA_INT8 && at <= CA_UINT64 ) {
|
|
2658
|
+
int8_t vt;
|
|
2659
|
+
if ( ca_integer_range_side(obj, at) == 0 ) {
|
|
2660
|
+
return at;
|
|
2661
|
+
}
|
|
2662
|
+
/* The type the value needs, widened so that the array's values are
|
|
2663
|
+
kept beside it (a uint64 array and -1 meet in object). */
|
|
2664
|
+
vt = ( ca_integer_range_side(obj, CA_INT64) == 0 ) ? CA_INT64
|
|
2665
|
+
: ( ca_integer_range_side(obj, CA_UINT64) == 0 ) ? CA_UINT64
|
|
2666
|
+
: CA_OBJECT;
|
|
2667
|
+
return ca_value_match_type(ca_promote_type(at, vt), at, vt);
|
|
2668
|
+
}
|
|
2669
|
+
if ( ca_cast_table2[st][at] >= 0 ) {
|
|
2670
|
+
return at;
|
|
2671
|
+
}
|
|
2672
|
+
return ca_promote_type(at, st);
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
/* CArray.result_type(*args) -- common data_type of the operands, by the rule
|
|
2676
|
+
the operators use. Each arg is classified by ca_arg_to_data_type: a
|
|
1691
2677
|
CArray / Symbol / String / Class gives a data_type representation, a
|
|
1692
2678
|
Numeric / bool / nil / Object gives a value whose data_type is inferred.
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
2679
|
+
The non-scalar arguments fold pairwise via ca_promote_type; a scalar then
|
|
2680
|
+
joins that type through ca_promote_scalar_type. With no non-scalar
|
|
2681
|
+
argument every argument folds by its own type. Returns a Symbol. User
|
|
2682
|
+
doc lives in yard-stubs/carray_cast.rb. */
|
|
1696
2683
|
|
|
1697
2684
|
static VALUE
|
|
1698
2685
|
rb_ca_s_result_type (int argc, VALUE *argv, VALUE klass)
|
|
1699
2686
|
{
|
|
1700
|
-
int8_t cur;
|
|
2687
|
+
int8_t cur = -1;
|
|
1701
2688
|
int i;
|
|
2689
|
+
VALUE rest, ropt;
|
|
2690
|
+
|
|
2691
|
+
/* Keywords are refused; without this a keyword Hash would be classified
|
|
2692
|
+
as one more operand and the answer would turn into object. */
|
|
2693
|
+
rb_scan_args(argc, argv, "*:", &rest, &ropt);
|
|
2694
|
+
rb_reject_options(ropt);
|
|
2695
|
+
argc = (int) RARRAY_LEN(rest);
|
|
2696
|
+
argv = RARRAY_PTR(rest);
|
|
1702
2697
|
|
|
1703
2698
|
if ( argc < 1 ) {
|
|
1704
2699
|
rb_raise(rb_eArgError, "result_type requires at least one argument");
|
|
1705
2700
|
}
|
|
1706
2701
|
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
2702
|
+
for ( i = 0; i < argc; i++ ) {
|
|
2703
|
+
if ( ! ca_arg_is_scalar(argv[i]) ) {
|
|
2704
|
+
int8_t t = ca_arg_to_data_type(argv[i]);
|
|
2705
|
+
cur = ( cur < 0 ) ? t : ca_promote_type(cur, t);
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
for ( i = 0; i < argc; i++ ) {
|
|
2709
|
+
if ( ca_arg_is_scalar(argv[i]) ) {
|
|
2710
|
+
int8_t t = ca_arg_to_data_type(argv[i]);
|
|
2711
|
+
cur = ( cur < 0 ) ? t : ca_promote_scalar_type(cur, argv[i], t);
|
|
2712
|
+
}
|
|
1711
2713
|
}
|
|
2714
|
+
/* argv points into rest, and classifying an argument can allocate */
|
|
2715
|
+
RB_GC_GUARD(rest);
|
|
1712
2716
|
/* Return Symbol for family consistency with
|
|
1713
2717
|
CArray.value_to_data_type and ca.data_type. */
|
|
1714
2718
|
return rb_ca_data_type_to_sym(cur);
|
|
@@ -1747,9 +2751,6 @@ rb_ca_s_promote_list (int argc, VALUE *argv, VALUE klass)
|
|
|
1747
2751
|
{
|
|
1748
2752
|
VALUE list, kwargs, data_type = Qnil;
|
|
1749
2753
|
long n, i;
|
|
1750
|
-
int all_face = 1, any_face = 0, all_primitive = 1;
|
|
1751
|
-
VALUE face_class = Qnil;
|
|
1752
|
-
CArray *ref_face = NULL;
|
|
1753
2754
|
int8_t common = -1;
|
|
1754
2755
|
|
|
1755
2756
|
rb_scan_args(argc, argv, "1:", &list, &kwargs);
|
|
@@ -1768,49 +2769,26 @@ rb_ca_s_promote_list (int argc, VALUE *argv, VALUE klass)
|
|
|
1768
2769
|
if ( RB_TYPE_P(data_type, T_CLASS) || RB_TYPE_P(data_type, T_MODULE) ) {
|
|
1769
2770
|
rb_raise(rb_eArgError,
|
|
1770
2771
|
"promote_list: data_type must be a primitive Symbol "
|
|
1771
|
-
"(Class targets are not supported;
|
|
1772
|
-
"
|
|
1773
|
-
}
|
|
1774
|
-
}
|
|
1775
|
-
|
|
1776
|
-
/* Classify each element: Face / primitive CArray. Detect Face-class
|
|
1777
|
-
homogeneity as we go. */
|
|
1778
|
-
for ( i = 0; i < n; i++ ) {
|
|
1779
|
-
VALUE elem = rb_ary_entry(list, i);
|
|
1780
|
-
CArray *ca;
|
|
1781
|
-
rb_check_carray_object(elem);
|
|
1782
|
-
TypedData_Get_Struct(elem, CArray, &carray_data_type, ca);
|
|
1783
|
-
if ( ca_is_face(ca) ) {
|
|
1784
|
-
any_face = 1;
|
|
1785
|
-
all_primitive = 0;
|
|
1786
|
-
if ( NIL_P(face_class) ) {
|
|
1787
|
-
face_class = rb_obj_class(elem);
|
|
1788
|
-
ref_face = ca;
|
|
1789
|
-
} else if ( rb_obj_class(elem) != face_class ) {
|
|
1790
|
-
all_face = 0; /* will be caught after the loop */
|
|
1791
|
-
} else if ( all_face ) {
|
|
1792
|
-
if ( ! ca_face_state_compatible(rb_ary_entry(list, 0), ref_face,
|
|
1793
|
-
elem, ca) ) {
|
|
1794
|
-
rb_raise(rb_eArgError,
|
|
1795
|
-
"promote_list: Face state mismatch across elements "
|
|
1796
|
-
"(= %s instance at index %ld differs from index 0)",
|
|
1797
|
-
rb_class2name(face_class), i);
|
|
1798
|
-
}
|
|
1799
|
-
}
|
|
1800
|
-
} else {
|
|
1801
|
-
all_face = 0;
|
|
2772
|
+
"(Class targets are not supported; leave data_type out to "
|
|
2773
|
+
"keep a Face)");
|
|
1802
2774
|
}
|
|
1803
2775
|
}
|
|
1804
2776
|
|
|
1805
2777
|
/* Explicit data_type path: primitive Symbol, all elements must be
|
|
1806
2778
|
primitive. Reject if any Face in list. */
|
|
1807
2779
|
if ( ! NIL_P(data_type) ) {
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
2780
|
+
for ( i = 0; i < n; i++ ) {
|
|
2781
|
+
VALUE elem = rb_ary_entry(list, i);
|
|
2782
|
+
CArray *ca;
|
|
2783
|
+
rb_check_carray_object(elem);
|
|
2784
|
+
TypedData_Get_Struct(elem, CArray, &carray_data_type, ca);
|
|
2785
|
+
if ( ca_is_face(ca) ) {
|
|
2786
|
+
rb_raise(rb_eArgError,
|
|
2787
|
+
"promote_list: data_type %s cannot be applied to a list "
|
|
2788
|
+
"containing Face elements (= Face cannot be coerced to "
|
|
2789
|
+
"a primitive without losing identity)",
|
|
2790
|
+
RSTRING_PTR(rb_inspect(data_type)));
|
|
2791
|
+
}
|
|
1814
2792
|
}
|
|
1815
2793
|
{
|
|
1816
2794
|
VALUE out = rb_ary_new_capa(n);
|
|
@@ -1825,41 +2803,24 @@ rb_ca_s_promote_list (int argc, VALUE *argv, VALUE klass)
|
|
|
1825
2803
|
}
|
|
1826
2804
|
}
|
|
1827
2805
|
|
|
1828
|
-
/* Auto-detect path.
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
"promote_list: cannot mix Face and non-Face (or heterogeneous "
|
|
1835
|
-
"Face classes); pass a homogeneous Face list, or strip Face "
|
|
1836
|
-
"manually with .parent for the storage-level layout");
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
|
-
|
|
1840
|
-
if ( all_face ) {
|
|
1841
|
-
/* Homogeneous Face: validate portability, then pass through. */
|
|
1842
|
-
if ( n > 1 && ! ca_face_state_portable(ref_face->obj_type, face_class) ) {
|
|
1843
|
-
rb_raise(rb_eArgError,
|
|
1844
|
-
"promote_list: %s state is not portable across multiple "
|
|
1845
|
-
"elements (= per-parent storage like CAConstString's buffer); "
|
|
1846
|
-
"strip Face manually with .parent for a storage-level list",
|
|
1847
|
-
rb_class2name(face_class));
|
|
1848
|
-
}
|
|
1849
|
-
/* Return a fresh Array so callers can mutate without aliasing. */
|
|
1850
|
-
{
|
|
1851
|
-
VALUE out = rb_ary_new_capa(n);
|
|
1852
|
-
for ( i = 0; i < n; i++ ) rb_ary_push(out, rb_ary_entry(list, i));
|
|
1853
|
-
return out;
|
|
1854
|
-
}
|
|
2806
|
+
/* Auto-detect path. A list of one Face class passes through (the
|
|
2807
|
+
multi-parent constructor lifts it). */
|
|
2808
|
+
if ( ! NIL_P(ca_face_list_class(list, "promote_list")) ) {
|
|
2809
|
+
VALUE out = rb_ary_new_capa(n);
|
|
2810
|
+
for ( i = 0; i < n; i++ ) rb_ary_push(out, rb_ary_entry(list, i));
|
|
2811
|
+
return out;
|
|
1855
2812
|
}
|
|
1856
2813
|
|
|
1857
2814
|
/* All primitive: result_type to determine common data_type, then
|
|
1858
2815
|
wrap_readonly each element. */
|
|
2816
|
+
/* The arrays are joined value for value, so a list mixing signed and
|
|
2817
|
+
unsigned integers takes a type that holds both (uint8 with int8 is
|
|
2818
|
+
int16, not uint8, where -1 would read as 255): the rule equality
|
|
2819
|
+
matches such a pair by. */
|
|
1859
2820
|
common = ca_arg_to_data_type(rb_ary_entry(list, 0));
|
|
1860
2821
|
for ( i = 1; i < n; i++ ) {
|
|
1861
2822
|
int8_t next = ca_arg_to_data_type(rb_ary_entry(list, i));
|
|
1862
|
-
common = ca_promote_type(common, next);
|
|
2823
|
+
common = ca_value_match_type(ca_promote_type(common, next), common, next);
|
|
1863
2824
|
}
|
|
1864
2825
|
{
|
|
1865
2826
|
VALUE common_sym = rb_ca_data_type_to_sym(common);
|
|
@@ -1888,7 +2849,7 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
|
|
|
1888
2849
|
Excludes T_STRING which has its own legacy interpretation. */
|
|
1889
2850
|
if ( ! rb_obj_is_carray(*other) && TYPE(*other) != T_STRING &&
|
|
1890
2851
|
rb_memory_view_available_p(*other) ) {
|
|
1891
|
-
*other =
|
|
2852
|
+
*other = ca_operand_from_memory_view(*other);
|
|
1892
2853
|
}
|
|
1893
2854
|
|
|
1894
2855
|
if ( ! rb_obj_is_carray(*other) ) {
|
|
@@ -1933,10 +2894,10 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
|
|
|
1933
2894
|
return;
|
|
1934
2895
|
}
|
|
1935
2896
|
|
|
1936
|
-
rb_raise(
|
|
2897
|
+
rb_raise(rb_eTypeError,
|
|
1937
2898
|
"can't coerce carray with data_types of '%s' and '%s'",
|
|
1938
|
-
|
|
1939
|
-
|
|
2899
|
+
ca_coerce_operand_name(*self, ca),
|
|
2900
|
+
ca_coerce_operand_name(*other, cb));
|
|
1940
2901
|
}
|
|
1941
2902
|
|
|
1942
2903
|
/* CArray#cast_with(other) -- coerce self and other to a common
|
|
@@ -1951,7 +2912,7 @@ rb_ca_cast_with (VALUE self, VALUE other)
|
|
|
1951
2912
|
rb_ca_cast_self_or_other(&self, &other);
|
|
1952
2913
|
}
|
|
1953
2914
|
else {
|
|
1954
|
-
rb_raise(
|
|
2915
|
+
rb_raise(rb_eTypeError, "first argument should be a carray");
|
|
1955
2916
|
}
|
|
1956
2917
|
return rb_assoc_new(self, other);
|
|
1957
2918
|
}
|
|
@@ -2000,19 +2961,28 @@ rb_ca_clip_uint64 (VALUE self)
|
|
|
2000
2961
|
volatile VALUE vout = rb_carray_new(CA_UINT64, ca->ndim, ca->dim, 0, NULL);
|
|
2001
2962
|
CArray *out;
|
|
2002
2963
|
GetCArray(vout, out);
|
|
2003
|
-
ca_attach(src);
|
|
2964
|
+
ca_attach(src); /* window: nothing raises inside */
|
|
2004
2965
|
double *sp = (double *) src->ptr;
|
|
2005
2966
|
uint64_t *op = (uint64_t *) out->ptr;
|
|
2006
2967
|
ca_size_t n = ca->elements;
|
|
2007
2968
|
const double LIMIT = 18446744073709551616.0; /* 2^64, exact in f64 */
|
|
2969
|
+
boolean8_t *m = ca_has_mask(src) ? (boolean8_t *) src->mask->ptr : NULL; /* attached with src */
|
|
2970
|
+
int found_nan = 0;
|
|
2008
2971
|
for ( ca_size_t i = 0; i < n; i++ ) {
|
|
2009
2972
|
double v = sp[i];
|
|
2010
|
-
if ( v != v )
|
|
2973
|
+
if ( v != v ) { /* NaN has no integer: refused below */
|
|
2974
|
+
op[i] = 0;
|
|
2975
|
+
if ( ! m || ! m[i] ) found_nan = 1;
|
|
2976
|
+
}
|
|
2011
2977
|
else if ( v >= LIMIT ) op[i] = UINT64_MAX;
|
|
2012
2978
|
else if ( v <= 0.0 ) op[i] = 0;
|
|
2013
2979
|
else op[i] = (uint64_t) v;
|
|
2014
2980
|
}
|
|
2015
2981
|
ca_detach(src);
|
|
2982
|
+
if ( found_nan ) {
|
|
2983
|
+
rb_raise(rb_eFloatDomainError, "%s: NaN cannot be converted to uint64",
|
|
2984
|
+
ca_calling_method_name());
|
|
2985
|
+
}
|
|
2016
2986
|
if ( ca_has_mask(ca) ) {
|
|
2017
2987
|
ca_copy_mask(out, ca);
|
|
2018
2988
|
}
|
|
@@ -2028,16 +2998,19 @@ rb_ca_clip_uint64 (VALUE self)
|
|
|
2028
2998
|
Polymorphic cast (NOT a fresh allocator): `data` is coerced into a CArray
|
|
2029
2999
|
of the target data_type, dispatching on its Ruby class:
|
|
2030
3000
|
|
|
2031
|
-
Array
|
|
2032
|
-
CArray
|
|
2033
|
-
nil
|
|
2034
|
-
Range
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
3001
|
+
Array -> shape-guessed CArray, element-wise store
|
|
3002
|
+
CArray -> copy if same data_type, else #to_type
|
|
3003
|
+
nil -> empty CArray
|
|
3004
|
+
Range -> arange; a second argument, if given, is the step
|
|
3005
|
+
Numeric -> CScalar, or #to_ca when the object answers it
|
|
3006
|
+
String -> the whitespace / `,` / `;` / `_`->UNDEF parser, which reads
|
|
3007
|
+
far more naturally in Ruby and so is the one branch that
|
|
3008
|
+
calls back out to it (CArray.cast_string in
|
|
3009
|
+
carray/basics.rb, eager-loaded). It receives the data_type
|
|
3010
|
+
as a Symbol.
|
|
3011
|
+
|
|
3012
|
+
A second argument is meaningful only for Range, and a third never is;
|
|
3013
|
+
anything else is refused.
|
|
2041
3014
|
------------------------------------------------------------------------ */
|
|
2042
3015
|
|
|
2043
3016
|
static ID id_new_cast = 0, id_guess_array_shape_cast = 0, id_cast_string = 0,
|
|
@@ -2063,6 +3036,21 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
|
|
|
2063
3036
|
VALUE v = ( argc >= 1 ) ? argv[0] : Qnil;
|
|
2064
3037
|
VALUE sym = ID2SYM(ca_data_type_sym[data_type]);
|
|
2065
3038
|
|
|
3039
|
+
/* Only the Range branch below reads a second argument (the step), and
|
|
3040
|
+
nothing reads a third. The arity is -1 for the step's sake, so the count
|
|
3041
|
+
is checked here; without it `CA_INT32(0, 2)`, which looks like the shape
|
|
3042
|
+
spelling `CArray.int32(3, 3)`, casts the 0 and drops the 2. */
|
|
3043
|
+
if ( argc > 2 ) {
|
|
3044
|
+
rb_raise(rb_eArgError,
|
|
3045
|
+
"wrong number of arguments (given %d, expected 0..2)", argc);
|
|
3046
|
+
}
|
|
3047
|
+
if ( argc == 2 && ! RTEST(rb_obj_is_kind_of(v, rb_cRange)) ) {
|
|
3048
|
+
rb_raise(rb_eArgError,
|
|
3049
|
+
"a step (the second argument) is only accepted "
|
|
3050
|
+
"when the first argument is a Range (got %s)",
|
|
3051
|
+
rb_obj_classname(v));
|
|
3052
|
+
}
|
|
3053
|
+
|
|
2066
3054
|
if ( TYPE(v) == T_ARRAY ) {
|
|
2067
3055
|
volatile VALUE shape, obj;
|
|
2068
3056
|
shape = rb_funcall(rb_cCArray, id_guess_array_shape_cast, 1, v);
|
|
@@ -2083,8 +3071,9 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
|
|
|
2083
3071
|
return rb_carray_new(data_type, 1, &dim0, 0, NULL);
|
|
2084
3072
|
}
|
|
2085
3073
|
else if ( RTEST(rb_obj_is_kind_of(v, rb_cRange)) ) {
|
|
2086
|
-
/* arange: n = ((end - begin).abs / step).floor
|
|
2087
|
-
|
|
3074
|
+
/* arange: n = ((end - begin).abs / step).floor + 1, or for an excluded
|
|
3075
|
+
end ((end - begin).abs.quo(step)).ceil -- the steps that start before
|
|
3076
|
+
the end -- then seq(begin, sign * step.abs). */
|
|
2088
3077
|
volatile VALUE vbeg, vend, step, n;
|
|
2089
3078
|
int sign;
|
|
2090
3079
|
ca_size_t dn;
|
|
@@ -2094,7 +3083,7 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
|
|
|
2094
3083
|
vend = rb_funcall(v, id_end_cast, 0);
|
|
2095
3084
|
step = ( argc >= 2 ) ? argv[1] : Qnil;
|
|
2096
3085
|
if ( RTEST(step) && RTEST(rb_funcall(step, id_op_eq, 1, INT2FIX(0))) ) {
|
|
2097
|
-
rb_raise(
|
|
3086
|
+
rb_raise(rb_eArgError, "step should not be 0");
|
|
2098
3087
|
}
|
|
2099
3088
|
if ( data_type == CA_OBJECT && !RTEST(step) ) {
|
|
2100
3089
|
VALUE va = rb_funcall(v, id_to_a_cast, 0); /* CA_OBJECT(v.to_a) */
|
|
@@ -2103,9 +3092,13 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
|
|
|
2103
3092
|
if ( !RTEST(step) ) step = INT2FIX(1);
|
|
2104
3093
|
n = rb_funcall(vend, id_op_minus, 1, vbeg);
|
|
2105
3094
|
n = rb_funcall(n, id_abs_cast, 0);
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
3095
|
+
if ( RTEST(rb_funcall(v, id_exclude_end_p_cast, 0)) ) {
|
|
3096
|
+
n = rb_funcall(n, rb_intern("quo"), 1, rb_funcall(step, id_abs_cast, 0));
|
|
3097
|
+
n = rb_funcall(n, rb_intern("ceil"), 0);
|
|
3098
|
+
}
|
|
3099
|
+
else {
|
|
3100
|
+
n = rb_funcall(n, id_op_div, 1, step);
|
|
3101
|
+
n = rb_funcall(n, id_floor_cast, 0);
|
|
2109
3102
|
n = rb_funcall(n, id_op_plus, 1, INT2FIX(1));
|
|
2110
3103
|
}
|
|
2111
3104
|
sign = RTEST(rb_funcall(vbeg, id_op_le, 1, vend)) ? 1 : -1;
|
|
@@ -2206,7 +3199,7 @@ rb_ca_cast_fixlen (int argc, VALUE *argv, VALUE self)
|
|
|
2206
3199
|
ca_size_t l = NUM2SIZE(rb_funcall(rb_ary_entry(v, i), id_length_cast, 0));
|
|
2207
3200
|
if ( l > maxlen ) maxlen = l;
|
|
2208
3201
|
}
|
|
2209
|
-
bytes = maxlen;
|
|
3202
|
+
bytes = ( maxlen > 0 ) ? maxlen : 1; /* all empty: one NUL byte */
|
|
2210
3203
|
} else {
|
|
2211
3204
|
bytes = NUM2SIZE(bytes_v);
|
|
2212
3205
|
}
|
|
@@ -2219,7 +3212,7 @@ rb_ca_cast_fixlen (int argc, VALUE *argv, VALUE self)
|
|
|
2219
3212
|
}
|
|
2220
3213
|
else if ( NIL_P(v) ) {
|
|
2221
3214
|
ca_size_t dim0 = 0;
|
|
2222
|
-
ca_size_t bytes = NIL_P(bytes_v) ?
|
|
3215
|
+
ca_size_t bytes = NIL_P(bytes_v) ? 1 : NUM2SIZE(bytes_v);
|
|
2223
3216
|
return rb_carray_new(CA_FIXLEN, 1, &dim0, bytes, NULL);
|
|
2224
3217
|
}
|
|
2225
3218
|
else {
|
|
@@ -2231,17 +3224,373 @@ rb_ca_cast_fixlen (int argc, VALUE *argv, VALUE self)
|
|
|
2231
3224
|
? ca : ca_cast_to_fixlen(ca, fixlen_sym, bytes_v);
|
|
2232
3225
|
}
|
|
2233
3226
|
{
|
|
2234
|
-
|
|
3227
|
+
/* No bytes: given: a String is as wide as it is (one NUL byte when
|
|
3228
|
+
empty). Anything else has no width to infer, and the fixlen
|
|
3229
|
+
check reports it. */
|
|
3230
|
+
ca_size_t bytes = 0;
|
|
3231
|
+
if ( ! NIL_P(bytes_v) ) {
|
|
3232
|
+
bytes = NUM2SIZE(bytes_v);
|
|
3233
|
+
}
|
|
3234
|
+
else if ( RB_TYPE_P(v, T_STRING) ) {
|
|
3235
|
+
bytes = ( RSTRING_LEN(v) > 0 ) ? RSTRING_LEN(v) : 1;
|
|
3236
|
+
}
|
|
2235
3237
|
return rb_cscalar_new_with_value(CA_FIXLEN, bytes, v);
|
|
2236
3238
|
}
|
|
2237
3239
|
}
|
|
2238
3240
|
}
|
|
2239
3241
|
|
|
3242
|
+
static VALUE
|
|
3243
|
+
rb_ca_read_text_as_number (int argc, VALUE *argv, VALUE self)
|
|
3244
|
+
{
|
|
3245
|
+
volatile VALUE src = self, out, vmask;
|
|
3246
|
+
VALUE rtype, report;
|
|
3247
|
+
CArray *ca, *co, *cmask;
|
|
3248
|
+
int8_t data_type;
|
|
3249
|
+
int is_float;
|
|
3250
|
+
VALUE *cells;
|
|
3251
|
+
boolean8_t *m_in, *m_out;
|
|
3252
|
+
ca_size_t i;
|
|
3253
|
+
|
|
3254
|
+
rb_scan_args(argc, argv, "11", &rtype, &report);
|
|
3255
|
+
if ( ! NIL_P(report) ) {
|
|
3256
|
+
Check_Type(report, T_ARRAY);
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
data_type = rb_ca_guess_type(rtype);
|
|
3260
|
+
switch ( data_type ) {
|
|
3261
|
+
case CA_INT8: case CA_INT16: case CA_INT32: case CA_INT64:
|
|
3262
|
+
case CA_UINT8: case CA_UINT16: case CA_UINT32: case CA_UINT64:
|
|
3263
|
+
is_float = 0;
|
|
3264
|
+
break;
|
|
3265
|
+
case CA_FLOAT32: case CA_FLOAT64:
|
|
3266
|
+
is_float = 1;
|
|
3267
|
+
break;
|
|
3268
|
+
default:
|
|
3269
|
+
return Qnil; /* not a number type: the caller casts */
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3272
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
3273
|
+
if ( ca->data_type != CA_OBJECT ) {
|
|
3274
|
+
rb_raise(rb_eArgError, "decimal reading needs an object array");
|
|
3275
|
+
}
|
|
3276
|
+
if ( ! ca_is_entity(ca) ) {
|
|
3277
|
+
src = rb_ca_copy(src);
|
|
3278
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
3279
|
+
}
|
|
3280
|
+
|
|
3281
|
+
out = rb_carray_new(data_type, ca->ndim, ca->dim, 0, NULL);
|
|
3282
|
+
TypedData_Get_Struct(out, CArray, &carray_data_type, co);
|
|
3283
|
+
vmask = rb_carray_new(CA_BOOLEAN, ca->ndim, ca->dim, 0, NULL);
|
|
3284
|
+
|
|
3285
|
+
cells = (VALUE *) ca->ptr;
|
|
3286
|
+
m_in = ca_has_mask(ca) ? (boolean8_t *) ca->mask->ptr : NULL;
|
|
3287
|
+
TypedData_Get_Struct(vmask, CArray, &carray_data_type, cmask);
|
|
3288
|
+
m_out = (boolean8_t *) cmask->ptr;
|
|
3289
|
+
|
|
3290
|
+
for (i = 0; i < ca->elements; i++) {
|
|
3291
|
+
VALUE v = cells[i];
|
|
3292
|
+
char *cell = co->ptr + i * co->bytes;
|
|
3293
|
+
int ok = 0;
|
|
3294
|
+
int missing = ( m_in && m_in[i] ) || NIL_P(v);
|
|
3295
|
+
if ( missing ) {
|
|
3296
|
+
ok = 0;
|
|
3297
|
+
}
|
|
3298
|
+
else if ( RB_TYPE_P(v, T_STRING) ) {
|
|
3299
|
+
int rc = ca_decimal_string_read(v, data_type, cell);
|
|
3300
|
+
missing = ( rc == CA_DECIMAL_BLANK );
|
|
3301
|
+
ok = ( rc == CA_DECIMAL_OK );
|
|
3302
|
+
}
|
|
3303
|
+
else if ( is_float ) {
|
|
3304
|
+
if ( RB_FLOAT_TYPE_P(v) || RB_INTEGER_TYPE_P(v) || ca_decimal_other_real(v) ) {
|
|
3305
|
+
double d = NUM2DBL(v);
|
|
3306
|
+
if ( data_type == CA_FLOAT32 ) {
|
|
3307
|
+
*(float32_t *) cell = (float32_t) d;
|
|
3308
|
+
}
|
|
3309
|
+
else {
|
|
3310
|
+
*(float64_t *) cell = d;
|
|
3311
|
+
}
|
|
3312
|
+
ok = 1;
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
else {
|
|
3316
|
+
int negative = 0;
|
|
3317
|
+
uint64_t magnitude = 0;
|
|
3318
|
+
ok = ca_decimal_object_integer(v, &negative, &magnitude)
|
|
3319
|
+
&& ca_decimal_fits(data_type, negative, magnitude);
|
|
3320
|
+
if ( ok ) {
|
|
3321
|
+
ca_decimal_store_integer(data_type, cell, 0, negative, magnitude);
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
m_out[i] = ok ? 0 : 1;
|
|
3325
|
+
if ( ! ok ) {
|
|
3326
|
+
memset(co->ptr + i * co->bytes, 0, co->bytes);
|
|
3327
|
+
if ( ! missing && ! NIL_P(report) ) {
|
|
3328
|
+
rb_ary_push(report, SIZET2NUM(i));
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
}
|
|
3332
|
+
|
|
3333
|
+
ca_mask_from_bytes(co, m_out);
|
|
3334
|
+
rb_ca_inherit_attr(out, self);
|
|
3335
|
+
RB_GC_GUARD(src);
|
|
3336
|
+
RB_GC_GUARD(vmask);
|
|
3337
|
+
return out;
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3340
|
+
/* The number type a column of text reads as, for CAFrame#infer_types.
|
|
3341
|
+
|
|
3342
|
+
A cell is an integer when it is digits with an optional sign and fits
|
|
3343
|
+
int64, and a float when it is any other decimal number (the grammar
|
|
3344
|
+
above, nan / inf included). A number with a leading zero ("007",
|
|
3345
|
+
"007.5") is not a number here: it is a code, kept as text. Neither is
|
|
3346
|
+
an integer too long for int64 (an identifier), which a float would
|
|
3347
|
+
round. Blank, nil and masked cells are missing and say nothing.
|
|
3348
|
+
|
|
3349
|
+
Returns :int64 when every present cell is an integer, :float64 when
|
|
3350
|
+
every present cell is a number and one is not an integer, and nil
|
|
3351
|
+
otherwise -- including when no cell is present. */
|
|
3352
|
+
|
|
3353
|
+
enum {
|
|
3354
|
+
CA_INFER_MISSING,
|
|
3355
|
+
CA_INFER_INTEGER,
|
|
3356
|
+
CA_INFER_FLOAT,
|
|
3357
|
+
CA_INFER_TEXT
|
|
3358
|
+
};
|
|
3359
|
+
|
|
3360
|
+
static int
|
|
3361
|
+
ca_infer_decimal_kind_of_bytes (const char *s, long n)
|
|
3362
|
+
{
|
|
3363
|
+
long i = 0, k;
|
|
3364
|
+
int digits_only = 1;
|
|
3365
|
+
ca_decimal_trim(&s, &n);
|
|
3366
|
+
if ( n == 0 ) {
|
|
3367
|
+
return CA_INFER_MISSING;
|
|
3368
|
+
}
|
|
3369
|
+
if ( ! ca_decimal_float(s, n, NULL) ) {
|
|
3370
|
+
return CA_INFER_TEXT;
|
|
3371
|
+
}
|
|
3372
|
+
if ( s[i] == '+' || s[i] == '-' ) {
|
|
3373
|
+
i++;
|
|
3374
|
+
}
|
|
3375
|
+
if ( i + 1 < n && s[i] == '0' && s[i+1] >= '0' && s[i+1] <= '9' ) {
|
|
3376
|
+
return CA_INFER_TEXT; /* a leading zero */
|
|
3377
|
+
}
|
|
3378
|
+
if ( i == n ) {
|
|
3379
|
+
return CA_INFER_TEXT;
|
|
3380
|
+
}
|
|
3381
|
+
for (k = i; k < n; k++) {
|
|
3382
|
+
if ( s[k] < '0' || s[k] > '9' ) {
|
|
3383
|
+
digits_only = 0;
|
|
3384
|
+
break;
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
if ( digits_only ) {
|
|
3388
|
+
int negative;
|
|
3389
|
+
uint64_t magnitude;
|
|
3390
|
+
if ( ca_decimal_integer(s, n, &negative, &magnitude) == CA_DECIMAL_OK
|
|
3391
|
+
&& ca_decimal_fits(CA_INT64, negative, magnitude) ) {
|
|
3392
|
+
return CA_INFER_INTEGER;
|
|
3393
|
+
}
|
|
3394
|
+
return CA_INFER_TEXT; /* too long for int64 */
|
|
3395
|
+
}
|
|
3396
|
+
return CA_INFER_FLOAT;
|
|
3397
|
+
}
|
|
3398
|
+
|
|
3399
|
+
static VALUE
|
|
3400
|
+
rb_ca_infer_number_type_of_text (VALUE self)
|
|
3401
|
+
{
|
|
3402
|
+
volatile VALUE src = self;
|
|
3403
|
+
CArray *ca;
|
|
3404
|
+
VALUE *cells;
|
|
3405
|
+
boolean8_t *m;
|
|
3406
|
+
ca_size_t i;
|
|
3407
|
+
int present = 0, any_float = 0;
|
|
3408
|
+
|
|
3409
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
3410
|
+
if ( ca->data_type != CA_OBJECT ) {
|
|
3411
|
+
rb_raise(rb_eArgError, "type inference needs an object array");
|
|
3412
|
+
}
|
|
3413
|
+
if ( ! ca_is_entity(ca) ) {
|
|
3414
|
+
src = rb_ca_copy(src);
|
|
3415
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
3416
|
+
}
|
|
3417
|
+
cells = (VALUE *) ca->ptr;
|
|
3418
|
+
m = ca_has_mask(ca) ? (boolean8_t *) ca->mask->ptr : NULL;
|
|
3419
|
+
|
|
3420
|
+
for (i = 0; i < ca->elements; i++) {
|
|
3421
|
+
VALUE v = cells[i];
|
|
3422
|
+
int kind;
|
|
3423
|
+
if ( ( m && m[i] ) || NIL_P(v) ) {
|
|
3424
|
+
continue;
|
|
3425
|
+
}
|
|
3426
|
+
if ( RB_TYPE_P(v, T_STRING) ) {
|
|
3427
|
+
kind = ca_infer_decimal_kind_of_bytes(RSTRING_PTR(v), RSTRING_LEN(v));
|
|
3428
|
+
}
|
|
3429
|
+
else if ( RB_FLOAT_TYPE_P(v) ) {
|
|
3430
|
+
kind = CA_INFER_FLOAT;
|
|
3431
|
+
}
|
|
3432
|
+
else if ( RB_INTEGER_TYPE_P(v) ) {
|
|
3433
|
+
int negative;
|
|
3434
|
+
uint64_t magnitude;
|
|
3435
|
+
kind = ( ca_decimal_object_integer(v, &negative, &magnitude)
|
|
3436
|
+
&& ca_decimal_fits(CA_INT64, negative, magnitude) )
|
|
3437
|
+
? CA_INFER_INTEGER : CA_INFER_TEXT;
|
|
3438
|
+
}
|
|
3439
|
+
else {
|
|
3440
|
+
kind = CA_INFER_TEXT;
|
|
3441
|
+
}
|
|
3442
|
+
if ( kind == CA_INFER_TEXT ) {
|
|
3443
|
+
RB_GC_GUARD(src);
|
|
3444
|
+
return Qnil;
|
|
3445
|
+
}
|
|
3446
|
+
if ( kind != CA_INFER_MISSING ) {
|
|
3447
|
+
present = 1;
|
|
3448
|
+
any_float |= ( kind == CA_INFER_FLOAT );
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3451
|
+
RB_GC_GUARD(src);
|
|
3452
|
+
if ( ! present ) {
|
|
3453
|
+
return Qnil;
|
|
3454
|
+
}
|
|
3455
|
+
return ID2SYM(rb_intern(any_float ? "float64" : "int64"));
|
|
3456
|
+
}
|
|
3457
|
+
|
|
3458
|
+
/* The same two readers over a CAConstString, from its buffer and its
|
|
3459
|
+
(start, end) byte ranges, without a String per cell. CAConstString's
|
|
3460
|
+
__infer_number_type_of_text__ / __read_text_as_number__ call them, so
|
|
3461
|
+
CAFrame#infer_types and #cast read a text column from a file this way. */
|
|
3462
|
+
|
|
3463
|
+
/* The buffer of a CAConstString and an entity of its (start, end) byte
|
|
3464
|
+
ranges, masked where a cell is missing. */
|
|
3465
|
+
static VALUE
|
|
3466
|
+
ca_const_string_buffer_and_ranges (VALUE cs, VALUE *buffer, CArray **ranges)
|
|
3467
|
+
{
|
|
3468
|
+
volatile VALUE vranges;
|
|
3469
|
+
VALUE klass = rb_const_get(rb_cObject, rb_intern("CAConstString"));
|
|
3470
|
+
if ( ! RTEST(rb_obj_is_kind_of(cs, klass)) ) {
|
|
3471
|
+
rb_raise(rb_eTypeError, "needs a CAConstString");
|
|
3472
|
+
}
|
|
3473
|
+
*buffer = rb_funcall(cs, rb_intern("buffer"), 0);
|
|
3474
|
+
vranges = rb_ca_parent(cs);
|
|
3475
|
+
TypedData_Get_Struct(vranges, CArray, &carray_data_type, *ranges);
|
|
3476
|
+
if ( ! ca_is_entity(*ranges) ) {
|
|
3477
|
+
vranges = rb_ca_copy(vranges);
|
|
3478
|
+
TypedData_Get_Struct(vranges, CArray, &carray_data_type, *ranges);
|
|
3479
|
+
}
|
|
3480
|
+
return vranges;
|
|
3481
|
+
}
|
|
3482
|
+
|
|
3483
|
+
static VALUE
|
|
3484
|
+
rb_ca_s_const_string_infer_number_type_of_text (VALUE klass, VALUE cs)
|
|
3485
|
+
{
|
|
3486
|
+
volatile VALUE src;
|
|
3487
|
+
VALUE buffer;
|
|
3488
|
+
CArray *pe;
|
|
3489
|
+
const char *buf;
|
|
3490
|
+
const int64_t *pair;
|
|
3491
|
+
boolean8_t *m;
|
|
3492
|
+
ca_size_t i;
|
|
3493
|
+
int present = 0, any_float = 0;
|
|
3494
|
+
|
|
3495
|
+
src = ca_const_string_buffer_and_ranges(cs, &buffer, &pe);
|
|
3496
|
+
buf = RSTRING_PTR(buffer);
|
|
3497
|
+
pair = (const int64_t *) pe->ptr;
|
|
3498
|
+
m = ca_has_mask(pe) ? (boolean8_t *) pe->mask->ptr : NULL;
|
|
3499
|
+
for (i = 0; i < pe->elements; i++) {
|
|
3500
|
+
int kind;
|
|
3501
|
+
if ( m && m[i] ) {
|
|
3502
|
+
continue;
|
|
3503
|
+
}
|
|
3504
|
+
kind = ca_infer_decimal_kind_of_bytes(buf + pair[2 * i], (long) ( pair[2 * i + 1] - pair[2 * i] ));
|
|
3505
|
+
if ( kind == CA_INFER_TEXT ) {
|
|
3506
|
+
RB_GC_GUARD(src);
|
|
3507
|
+
return Qnil;
|
|
3508
|
+
}
|
|
3509
|
+
if ( kind != CA_INFER_MISSING ) {
|
|
3510
|
+
present = 1;
|
|
3511
|
+
any_float |= ( kind == CA_INFER_FLOAT );
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
RB_GC_GUARD(src);
|
|
3515
|
+
RB_GC_GUARD(buffer);
|
|
3516
|
+
if ( ! present ) {
|
|
3517
|
+
return Qnil;
|
|
3518
|
+
}
|
|
3519
|
+
return ID2SYM(rb_intern(any_float ? "float64" : "int64"));
|
|
3520
|
+
}
|
|
3521
|
+
|
|
3522
|
+
static VALUE
|
|
3523
|
+
rb_ca_s_const_string_read_text_as_number (VALUE klass, VALUE cs, VALUE rtype, VALUE report)
|
|
3524
|
+
{
|
|
3525
|
+
volatile VALUE src, out;
|
|
3526
|
+
VALUE buffer;
|
|
3527
|
+
CArray *pe, *co;
|
|
3528
|
+
int8_t data_type;
|
|
3529
|
+
const char *buf;
|
|
3530
|
+
const int64_t *pair;
|
|
3531
|
+
boolean8_t *m_in, *m_out = NULL;
|
|
3532
|
+
ca_size_t i;
|
|
3533
|
+
|
|
3534
|
+
if ( ! NIL_P(report) ) {
|
|
3535
|
+
Check_Type(report, T_ARRAY);
|
|
3536
|
+
}
|
|
3537
|
+
data_type = rb_ca_guess_type(rtype);
|
|
3538
|
+
switch ( data_type ) {
|
|
3539
|
+
case CA_INT8: case CA_INT16: case CA_INT32: case CA_INT64:
|
|
3540
|
+
case CA_UINT8: case CA_UINT16: case CA_UINT32: case CA_UINT64:
|
|
3541
|
+
case CA_FLOAT32: case CA_FLOAT64:
|
|
3542
|
+
break;
|
|
3543
|
+
default:
|
|
3544
|
+
return Qnil; /* not a number type: the caller casts */
|
|
3545
|
+
}
|
|
3546
|
+
src = ca_const_string_buffer_and_ranges(cs, &buffer, &pe);
|
|
3547
|
+
out = rb_carray_new(data_type, pe->ndim, pe->dim, 0, NULL);
|
|
3548
|
+
TypedData_Get_Struct(out, CArray, &carray_data_type, co);
|
|
3549
|
+
buf = RSTRING_PTR(buffer);
|
|
3550
|
+
pair = (const int64_t *) pe->ptr;
|
|
3551
|
+
m_in = ca_has_mask(pe) ? (boolean8_t *) pe->mask->ptr : NULL;
|
|
3552
|
+
|
|
3553
|
+
for (i = 0; i < pe->elements; i++) {
|
|
3554
|
+
char *cell = co->ptr + i * co->bytes;
|
|
3555
|
+
int rc = CA_DECIMAL_BLANK;
|
|
3556
|
+
if ( ! ( m_in && m_in[i] ) ) {
|
|
3557
|
+
rc = ca_decimal_read_bytes_as(buf + pair[2 * i],
|
|
3558
|
+
(long) ( pair[2 * i + 1] - pair[2 * i] ),
|
|
3559
|
+
data_type, cell);
|
|
3560
|
+
}
|
|
3561
|
+
if ( rc != CA_DECIMAL_OK ) {
|
|
3562
|
+
if ( m_out == NULL ) {
|
|
3563
|
+
ca_create_mask(co);
|
|
3564
|
+
m_out = (boolean8_t *) co->mask->ptr;
|
|
3565
|
+
}
|
|
3566
|
+
m_out[i] = 1;
|
|
3567
|
+
memset(cell, 0, co->bytes);
|
|
3568
|
+
if ( rc != CA_DECIMAL_BLANK && ! NIL_P(report) ) {
|
|
3569
|
+
rb_ary_push(report, SIZET2NUM(i));
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
}
|
|
3573
|
+
RB_GC_GUARD(src);
|
|
3574
|
+
RB_GC_GUARD(buffer);
|
|
3575
|
+
return out;
|
|
3576
|
+
}
|
|
3577
|
+
|
|
2240
3578
|
void
|
|
2241
3579
|
Init_carray_cast (void)
|
|
2242
3580
|
{
|
|
2243
3581
|
/* CArray data_type conversion */
|
|
2244
3582
|
|
|
3583
|
+
/* Internal: CAFrame#infer_types asks the number type of a text column. */
|
|
3584
|
+
rb_define_method(rb_cCArray, "__infer_number_type_of_text__", rb_ca_infer_number_type_of_text, 0);
|
|
3585
|
+
|
|
3586
|
+
/* Internal: CAFrame#cast reads text cells with this grammar. With an
|
|
3587
|
+
Array as the second argument, the addresses of cells that hold
|
|
3588
|
+
something but do not read (blank, nil and masked cells are missing,
|
|
3589
|
+
not unreadable) are pushed onto it. */
|
|
3590
|
+
rb_define_method(rb_cCArray, "__read_text_as_number__", rb_ca_read_text_as_number, -1);
|
|
3591
|
+
rb_define_singleton_method(rb_cCArray, "__const_string_infer_number_type_of_text__", rb_ca_s_const_string_infer_number_type_of_text, 1);
|
|
3592
|
+
rb_define_singleton_method(rb_cCArray, "__const_string_read_text_as_number__", rb_ca_s_const_string_read_text_as_number, 3);
|
|
3593
|
+
|
|
2245
3594
|
rb_define_method(rb_cCArray, "to_type", rb_ca_to_type_internal, -1);
|
|
2246
3595
|
|
|
2247
3596
|
rb_define_method(rb_cCArray, "fixlen", rb_ca_to_fixlen, -1);
|
|
@@ -2306,6 +3655,10 @@ Init_carray_cast (void)
|
|
|
2306
3655
|
"cast_self_or_other", rb_ca_s_cast_self_or_other, 2);
|
|
2307
3656
|
rb_define_singleton_method(rb_cCArray,
|
|
2308
3657
|
"result_type", rb_ca_s_result_type, -1);
|
|
3658
|
+
rb_define_private_method(rb_cCArray,
|
|
3659
|
+
"value_match_type", rb_ca_value_match_type, 2);
|
|
3660
|
+
rb_define_private_method(rb_cCArray,
|
|
3661
|
+
"query_match_type", rb_ca_query_match_type, 1);
|
|
2309
3662
|
|
|
2310
3663
|
rb_define_singleton_method(rb_cCArray,
|
|
2311
3664
|
"promote_list", rb_ca_s_promote_list, -1);
|
|
@@ -2319,7 +3672,7 @@ Init_carray_cast (void)
|
|
|
2319
3672
|
classes registered in ext/carray_data_type.c. */
|
|
2320
3673
|
id_new_cast = rb_intern("new");
|
|
2321
3674
|
id_guess_array_shape_cast = rb_intern("guess_array_shape");
|
|
2322
|
-
id_cast_string = rb_intern("
|
|
3675
|
+
id_cast_string = rb_intern("cast_string");
|
|
2323
3676
|
id_to_ca_cast = rb_intern("to_ca");
|
|
2324
3677
|
id_length_cast = rb_intern("length");
|
|
2325
3678
|
id_begin_cast = rb_intern("begin");
|