qr_reader-native 0.0.1
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 +7 -0
- data/LICENSE-mruby.txt +22 -0
- data/LICENSE-spinel.txt +19 -0
- data/LICENSE.txt +21 -0
- data/README.md +61 -0
- data/ext/qr_reader_native/SPINEL_VERSION +1 -0
- data/ext/qr_reader_native/extconf.rb +8 -0
- data/ext/qr_reader_native/mruby/error.h +13 -0
- data/ext/qr_reader_native/mruby/internal.h +145 -0
- data/ext/qr_reader_native/mruby/string.h +22 -0
- data/ext/qr_reader_native/mruby.h +93 -0
- data/ext/qr_reader_native/mruby_shim.h +118 -0
- data/ext/qr_reader_native/qr_reader_native.c +13513 -0
- data/ext/qr_reader_native/qr_reader_native.h +29 -0
- data/ext/qr_reader_native/qr_reader_native_ext.c +598 -0
- data/ext/qr_reader_native/re_cased.h +71 -0
- data/ext/qr_reader_native/re_compile.c +5784 -0
- data/ext/qr_reader_native/re_ctype.h +3540 -0
- data/ext/qr_reader_native/re_exec.c +2190 -0
- data/ext/qr_reader_native/re_internal.h +671 -0
- data/ext/qr_reader_native/re_prop.h +4629 -0
- data/ext/qr_reader_native/re_spinel.c +363 -0
- data/ext/qr_reader_native/re_spinel.h +22 -0
- data/ext/qr_reader_native/re_spinel_utf8.inc +97 -0
- data/ext/qr_reader_native/re_utf8.c +156 -0
- data/ext/qr_reader_native/sp_alloc.c +1447 -0
- data/ext/qr_reader_native/sp_alloc.h +1196 -0
- data/ext/qr_reader_native/sp_argf.h +33 -0
- data/ext/qr_reader_native/sp_array.c +1052 -0
- data/ext/qr_reader_native/sp_array.h +456 -0
- data/ext/qr_reader_native/sp_bigint.c +5826 -0
- data/ext/qr_reader_native/sp_bigint.h +117 -0
- data/ext/qr_reader_native/sp_cold.c +5259 -0
- data/ext/qr_reader_native/sp_compat.h +402 -0
- data/ext/qr_reader_native/sp_core.c +818 -0
- data/ext/qr_reader_native/sp_core.h +56 -0
- data/ext/qr_reader_native/sp_crypto.c +877 -0
- data/ext/qr_reader_native/sp_crypto.h +169 -0
- data/ext/qr_reader_native/sp_dtoa.c +1533 -0
- data/ext/qr_reader_native/sp_dtoa.h +29 -0
- data/ext/qr_reader_native/sp_encoding_names.h +172 -0
- data/ext/qr_reader_native/sp_enum.h +86 -0
- data/ext/qr_reader_native/sp_exc.c +1185 -0
- data/ext/qr_reader_native/sp_exc.h +186 -0
- data/ext/qr_reader_native/sp_exc_ctx.h +56 -0
- data/ext/qr_reader_native/sp_fiber.c +889 -0
- data/ext/qr_reader_native/sp_fiber.h +162 -0
- data/ext/qr_reader_native/sp_fiber_ctx.h +84 -0
- data/ext/qr_reader_native/sp_format.c +695 -0
- data/ext/qr_reader_native/sp_format.h +83 -0
- data/ext/qr_reader_native/sp_gc.c +1793 -0
- data/ext/qr_reader_native/sp_gc.h +762 -0
- data/ext/qr_reader_native/sp_hash.c +131 -0
- data/ext/qr_reader_native/sp_hash.h +131 -0
- data/ext/qr_reader_native/sp_inspect.c +215 -0
- data/ext/qr_reader_native/sp_inspect.h +128 -0
- data/ext/qr_reader_native/sp_io.c +1676 -0
- data/ext/qr_reader_native/sp_io.h +272 -0
- data/ext/qr_reader_native/sp_iobuffer.c +1014 -0
- data/ext/qr_reader_native/sp_iobuffer.h +167 -0
- data/ext/qr_reader_native/sp_marshal.c +487 -0
- data/ext/qr_reader_native/sp_marshal.h +60 -0
- data/ext/qr_reader_native/sp_net.c +1029 -0
- data/ext/qr_reader_native/sp_net.h +205 -0
- data/ext/qr_reader_native/sp_pack.c +1254 -0
- data/ext/qr_reader_native/sp_poly_cold.c +1220 -0
- data/ext/qr_reader_native/sp_proc.c +410 -0
- data/ext/qr_reader_native/sp_proc.h +327 -0
- data/ext/qr_reader_native/sp_process.c +547 -0
- data/ext/qr_reader_native/sp_process_status.c +211 -0
- data/ext/qr_reader_native/sp_process_status.h +66 -0
- data/ext/qr_reader_native/sp_random.c +287 -0
- data/ext/qr_reader_native/sp_random.h +52 -0
- data/ext/qr_reader_native/sp_range.h +144 -0
- data/ext/qr_reader_native/sp_re.c +1379 -0
- data/ext/qr_reader_native/sp_re.h +186 -0
- data/ext/qr_reader_native/sp_re_names.h +59 -0
- data/ext/qr_reader_native/sp_sched.c +4044 -0
- data/ext/qr_reader_native/sp_sched.h +295 -0
- data/ext/qr_reader_native/sp_slab.c +1507 -0
- data/ext/qr_reader_native/sp_str.c +1462 -0
- data/ext/qr_reader_native/sp_str.h +306 -0
- data/ext/qr_reader_native/sp_str_crypt.c +23 -0
- data/ext/qr_reader_native/sp_string.c +92 -0
- data/ext/qr_reader_native/sp_string.h +253 -0
- data/ext/qr_reader_native/sp_system.c +78 -0
- data/ext/qr_reader_native/sp_system.h +18 -0
- data/ext/qr_reader_native/sp_time.c +860 -0
- data/ext/qr_reader_native/sp_time.h +100 -0
- data/ext/qr_reader_native/sp_types.h +292 -0
- data/ext/qr_reader_native/spinel_rt.h +19017 -0
- data/ext/qr_reader_native/unicase.c +399 -0
- data/ext/qr_reader_native/unicase.h +901 -0
- data/lib/qr_reader/native.rb +6 -0
- metadata +153 -0
|
@@ -0,0 +1,818 @@
|
|
|
1
|
+
/* sp_core.c -- runtime helpers split out of spinel_rt.h into
|
|
2
|
+
* libspinel_rt.a. See sp_core.h for the rationale. */
|
|
3
|
+
#include "sp_core.h"
|
|
4
|
+
#include <float.h>
|
|
5
|
+
#include <limits.h>
|
|
6
|
+
#include <string.h>
|
|
7
|
+
#include "sp_alloc.h" /* sp_str_byte_len: embedded-NUL detection in Integer()/Float() */
|
|
8
|
+
#include "sp_dtoa.h" /* sp_read_float: locale-independent String#to_f / Float() */
|
|
9
|
+
#include <stdlib.h>
|
|
10
|
+
#include <ctype.h>
|
|
11
|
+
#include <errno.h>
|
|
12
|
+
#include <locale.h>
|
|
13
|
+
/* macOS keeps the *_l / locale_t surface in <xlocale.h>; glibc exposes it from
|
|
14
|
+
<locale.h> under POSIX.1-2008. Guarded so a platform with neither is not a
|
|
15
|
+
build error either. (#3370) */
|
|
16
|
+
#if defined(__has_include)
|
|
17
|
+
# if __has_include(<xlocale.h>)
|
|
18
|
+
# include <xlocale.h>
|
|
19
|
+
# endif
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
/* Must match sp_types.h: sp_int is pointer-width (int64 on 64-bit,
|
|
23
|
+
int32 on 32-bit) so this TU's helper ABI agrees with the generated TU. */
|
|
24
|
+
typedef intptr_t sp_int;
|
|
25
|
+
typedef double sp_float;
|
|
26
|
+
/* 10^p fits sp_int only up to this exponent (p>= it collapses to 0):
|
|
27
|
+
10^19 > INT64_MAX, 10^10 > INT32_MAX. */
|
|
28
|
+
#if INTPTR_MAX == INT32_MAX
|
|
29
|
+
#define SP_INT_POW10_LIMIT 10
|
|
30
|
+
#else
|
|
31
|
+
#define SP_INT_POW10_LIMIT 19
|
|
32
|
+
#endif
|
|
33
|
+
|
|
34
|
+
/* Defined in the generated translation unit (spinel_rt.h); referenced
|
|
35
|
+
here and resolved at link time. */
|
|
36
|
+
SP_NORETURN void sp_raise_cls(const char *cls, const char *msg);
|
|
37
|
+
const char *sp_sprintf(const char *fmt, ...);
|
|
38
|
+
|
|
39
|
+
/* CRuby's `String#to_i` accepts a leading sign, then digits with
|
|
40
|
+
`_` between consecutive digits, and stops at the first non-digit
|
|
41
|
+
(returning what it has so far rather than raising). `"1_2_3asdf"`
|
|
42
|
+
-> 123. spinel previously emitted `(sp_int)atoll(s)` which stops
|
|
43
|
+
at the first `_`, returning 1 instead. Issue #619. */
|
|
44
|
+
sp_int sp_str_to_i_cruby(const char *s) {SP_GC_ROOT_STR(s);
|
|
45
|
+
if (!s) return 0;
|
|
46
|
+
const char *p = s;
|
|
47
|
+
while (isspace((unsigned char)*p)) p++;
|
|
48
|
+
int neg = 0;
|
|
49
|
+
if (*p == '+') p++;
|
|
50
|
+
else if (*p == '-') { neg = 1; p++; }
|
|
51
|
+
sp_int v = 0;
|
|
52
|
+
int any = 0;
|
|
53
|
+
while (*p) {
|
|
54
|
+
if (*p >= '0' && *p <= '9') {
|
|
55
|
+
/* Accumulate the signed value: the magnitude of INTPTR_MIN does not
|
|
56
|
+
fit sp_int, even though the negative value does. Signed-overflow
|
|
57
|
+
on `v * 10 + digit` is undefined behavior;
|
|
58
|
+
detect via sp_ckd_*_iptr (sp_compat.h). CRuby promotes to Bignum
|
|
59
|
+
on overflow but spinel's int model is int64-only -- raise
|
|
60
|
+
RangeError instead of silently saturating, so a user-side
|
|
61
|
+
`rescue` can react. */
|
|
62
|
+
sp_int t, digit = (sp_int)(*p - '0');
|
|
63
|
+
if (neg) digit = -digit;
|
|
64
|
+
if (sp_ckd_mul_iptr(v, 10, &t) ||
|
|
65
|
+
sp_ckd_add_iptr(t, digit, &v)) {
|
|
66
|
+
sp_raise_cls("RangeError", sp_sprintf("integer overflow parsing \"%s\"", s));
|
|
67
|
+
}
|
|
68
|
+
any = 1;
|
|
69
|
+
p++;
|
|
70
|
+
}
|
|
71
|
+
else if (*p == '_' && any && p[1] >= '0' && p[1] <= '9') {
|
|
72
|
+
p++;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!any) return 0;
|
|
79
|
+
return v;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* `String#to_f`: parse a leading float, tolerating `_` between digits as a
|
|
83
|
+
separator (CRuby's `"1_000.5".to_f == 1000.5`), returning 0.0 when no
|
|
84
|
+
number leads. Underscores are stripped into a small scratch buffer before
|
|
85
|
+
strtod so the C parser (which stops at `_`) sees clean digits. */
|
|
86
|
+
double sp_str_to_f_cruby(const char *s) {
|
|
87
|
+
if (!s) return 0.0;
|
|
88
|
+
const char *p = s;
|
|
89
|
+
while (isspace((unsigned char)*p)) p++;
|
|
90
|
+
/* copy the leading numeric run, dropping `_` that sit between two digits */
|
|
91
|
+
char buf[512];
|
|
92
|
+
size_t n = 0;
|
|
93
|
+
if (*p == '+' || *p == '-') { if (n < sizeof buf - 1) buf[n++] = *p; p++; }
|
|
94
|
+
for (; *p && n < sizeof buf - 1; p++) {
|
|
95
|
+
if ((*p >= '0' && *p <= '9') || *p == '.' || *p == 'e' || *p == 'E' ||
|
|
96
|
+
*p == '+' || *p == '-') {
|
|
97
|
+
buf[n++] = *p;
|
|
98
|
+
}
|
|
99
|
+
else if (*p == '_' && n > 0 &&
|
|
100
|
+
((buf[n-1] >= '0' && buf[n-1] <= '9')) &&
|
|
101
|
+
(p[1] >= '0' && p[1] <= '9')) {
|
|
102
|
+
/* separator between digits: skip it */
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
buf[n] = 0;
|
|
109
|
+
double d = 0.0;
|
|
110
|
+
sp_read_float(buf, NULL, &d); /* locale-independent parse */
|
|
111
|
+
return d;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Digit value of `c` in bases up to 36, or -1. */
|
|
115
|
+
static int sp_digit36(int c) {
|
|
116
|
+
if (c >= '0' && c <= '9') return c - '0';
|
|
117
|
+
if (c >= 'a' && c <= 'z') return c - 'a' + 10;
|
|
118
|
+
if (c >= 'A' && c <= 'Z') return c - 'A' + 10;
|
|
119
|
+
return -1;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Skips leading whitespace and sign, resolves base 0 from the prefix
|
|
123
|
+
(0x -> 16, 0b -> 2, 0/0o -> 8, 0d -> 10, otherwise 10), and skips a
|
|
124
|
+
prefix matching the base. Per CRuby, only base 0 enables prefix-based
|
|
125
|
+
dispatch -- explicit bases just *accept* the matching prefix. A leading
|
|
126
|
+
0 followed by anything but a prefix letter is octal whatever comes next,
|
|
127
|
+
so "08" stops at the 8 (Integer() refuses it) rather than reading 8. */
|
|
128
|
+
static const char *sp_int_head(const char *p, sp_int *base, int *neg) {
|
|
129
|
+
while (isspace((unsigned char)*p)) p++;
|
|
130
|
+
*neg = 0;
|
|
131
|
+
if (*p == '+') p++;
|
|
132
|
+
else if (*p == '-') { *neg = 1; p++; }
|
|
133
|
+
if (*base == 0) {
|
|
134
|
+
*base = 10;
|
|
135
|
+
if (*p == '0') {
|
|
136
|
+
char n = p[1];
|
|
137
|
+
if (n == 'x' || n == 'X') *base = 16;
|
|
138
|
+
else if (n == 'b' || n == 'B') *base = 2;
|
|
139
|
+
else if (n == 'o' || n == 'O') *base = 8;
|
|
140
|
+
else if (n != 0 && n != 'd' && n != 'D') *base = 8;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (*p == '0' && p[1] != 0) {
|
|
144
|
+
char n = p[1];
|
|
145
|
+
if ((*base == 16) && (n == 'x' || n == 'X')) p += 2;
|
|
146
|
+
else if ((*base == 2) && (n == 'b' || n == 'B')) p += 2;
|
|
147
|
+
else if ((*base == 8) && (n == 'o' || n == 'O')) p += 2;
|
|
148
|
+
/* base 10 accepts the explicit decimal prefix too (#3719) */
|
|
149
|
+
else if ((*base == 10) && (n == 'd' || n == 'D')) p += 2;
|
|
150
|
+
}
|
|
151
|
+
return p;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* Accumulates digits of `base` into *v, consuming `_` only between
|
|
155
|
+
digits; *any is set once a digit is read. Returns the stop position,
|
|
156
|
+
or NULL on sp_int overflow. */
|
|
157
|
+
static const char *sp_int_scan(const char *p, sp_int base, sp_int *v, int *any) {
|
|
158
|
+
*v = 0;
|
|
159
|
+
*any = 0;
|
|
160
|
+
for (;; p++) {
|
|
161
|
+
int d = sp_digit36((unsigned char)*p);
|
|
162
|
+
if (d < 0 || d >= (int)base) {
|
|
163
|
+
if (*p == '_' && *any) {
|
|
164
|
+
int n = sp_digit36((unsigned char)p[1]);
|
|
165
|
+
if (n >= 0 && n < (int)base) continue;
|
|
166
|
+
}
|
|
167
|
+
return p;
|
|
168
|
+
}
|
|
169
|
+
sp_int t;
|
|
170
|
+
if (sp_ckd_mul_iptr(*v, base, &t) ||
|
|
171
|
+
sp_ckd_add_iptr(t, (sp_int)d, v)) return NULL;
|
|
172
|
+
*any = 1;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/* The promote-mode parsers (sp_str_to_i_promote, spinel_rt.h) read the
|
|
177
|
+
same text as the sp_int ones below, and take a Bignum where the sp_int
|
|
178
|
+
scan overflows. Whether it does, for `s` in `base` (0 resolves from the
|
|
179
|
+
prefix): */
|
|
180
|
+
int sp_str_int_overflows(const char *s, intptr_t base) {
|
|
181
|
+
if (!s) return 0;
|
|
182
|
+
int neg, any;
|
|
183
|
+
sp_int v, b = base;
|
|
184
|
+
const char *p = sp_int_head(s, &b, &neg);
|
|
185
|
+
if (b < 2 || b > 36) return 0;
|
|
186
|
+
return sp_int_scan(p, b, &v, &any) == NULL;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* ...and the digits as the Bignum parser wants them: a '-' for a negative
|
|
190
|
+
value, then the digits without their `_` separators. *base comes back
|
|
191
|
+
resolved, *rest just past the last digit. A malloc'd string. */
|
|
192
|
+
char *sp_int_digits_dup(const char *s, intptr_t *base, const char **rest) {
|
|
193
|
+
int neg, any = 0;
|
|
194
|
+
sp_int b = *base;
|
|
195
|
+
const char *p = sp_int_head(s, &b, &neg);
|
|
196
|
+
size_t k = 0;
|
|
197
|
+
char *out = (char *)malloc(strlen(p) + 2);
|
|
198
|
+
if (!out) return NULL;
|
|
199
|
+
if (neg) out[k++] = '-';
|
|
200
|
+
for (;; p++) {
|
|
201
|
+
int d = sp_digit36((unsigned char)*p);
|
|
202
|
+
if (d < 0 || d >= (int)b) {
|
|
203
|
+
if (*p == '_' && any) {
|
|
204
|
+
int n = sp_digit36((unsigned char)p[1]);
|
|
205
|
+
if (n >= 0 && n < (int)b) continue;
|
|
206
|
+
}
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
out[k++] = *p;
|
|
210
|
+
any = 1;
|
|
211
|
+
}
|
|
212
|
+
out[k] = 0;
|
|
213
|
+
*base = b;
|
|
214
|
+
if (rest) *rest = p;
|
|
215
|
+
return out;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/* `String#to_i(base)` with a non-decimal base. Accepts bases 2..36
|
|
219
|
+
like MRI; `_` is allowed between digits the same way as base 10.
|
|
220
|
+
Stops at the first invalid digit and returns what's parsed so
|
|
221
|
+
far. Base 0 auto-detects from the prefix. Issue #883. */
|
|
222
|
+
sp_int sp_str_to_i_base(const char *s, sp_int base) {SP_GC_ROOT_STR(s);
|
|
223
|
+
if (!s) return 0;
|
|
224
|
+
/* CRuby rejects a radix outside 2..36 rather than falling back to 10 */
|
|
225
|
+
if (base != 0 && (base < 2 || base > 36))
|
|
226
|
+
sp_raise_cls("ArgumentError", sp_sprintf("invalid radix %lld", (long long)base));
|
|
227
|
+
int neg, any;
|
|
228
|
+
sp_int v;
|
|
229
|
+
const char *p = sp_int_head(s, &base, &neg);
|
|
230
|
+
if (!sp_int_scan(p, base, &v, &any))
|
|
231
|
+
sp_raise_cls("RangeError", sp_sprintf("integer overflow parsing \"%s\"", s));
|
|
232
|
+
if (!any) return 0;
|
|
233
|
+
return neg ? -v : v;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* CRuby's `Integer(s)` raises ArgumentError for unparseable input
|
|
237
|
+
(empty string, leading/trailing junk, all-whitespace). The bare
|
|
238
|
+
`(sp_int)strtoll(s, NULL, 10)` spinel previously emitted silently
|
|
239
|
+
returned 0 instead, which made `Integer(s) rescue 0` always take
|
|
240
|
+
the main branch. This helper matches CRuby semantics: skips
|
|
241
|
+
leading/trailing whitespace, requires at least one valid digit,
|
|
242
|
+
rejects trailing junk. Accepts an optional leading `+` / `-`. */
|
|
243
|
+
sp_int sp_str_to_i_strict(const char *s) {SP_GC_ROOT_STR(s);
|
|
244
|
+
if (!s) sp_raise_cls("ArgumentError", "invalid value for Integer(): nil");
|
|
245
|
+
/* an embedded NUL makes the Ruby string longer than its C prefix: CRuby
|
|
246
|
+
rejects it, a C-string scan would silently parse the prefix. */
|
|
247
|
+
if (strlen(s) != sp_str_byte_len(s))
|
|
248
|
+
sp_raise_cls("ArgumentError", sp_sprintf("invalid value for Integer(): \"%s\"", s));
|
|
249
|
+
/* Delegate to the base-aware parser with auto-detection: unlike a bare
|
|
250
|
+
strtoll it handles digit-separating underscores ("1_000") and CRuby's
|
|
251
|
+
prefix bases ("0x1A", "0b101", and leading-0 octal "077" -> 63). */
|
|
252
|
+
return sp_str_to_i_strict_base(s, 0);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* `Integer(s, base)` with explicit base. Bases 2..36, MRI-compatible
|
|
256
|
+
prefix recognition (0x / 0b / 0o when the base matches). Raises
|
|
257
|
+
ArgumentError on invalid input or unsupported base. Issue #887. */
|
|
258
|
+
/* The shared body. `lenient` is Kernel#Integer's `exception: false`: every
|
|
259
|
+
rejection answers nil (SP_INT_NIL) instead of raising (#3718). */
|
|
260
|
+
static sp_int sp_str_to_i_base_impl(const char *s, sp_int base, int lenient) {SP_GC_ROOT_STR(s);
|
|
261
|
+
#define SP_INT_REJECT(cls, msg) do { if (lenient) return SP_INT_NIL; sp_raise_cls(cls, msg); } while (0)
|
|
262
|
+
if (!s) SP_INT_REJECT("ArgumentError", "invalid value for Integer(): nil");
|
|
263
|
+
/* an embedded NUL makes the Ruby string longer than its C prefix: CRuby
|
|
264
|
+
rejects it, a C-string scan would silently parse the prefix. */
|
|
265
|
+
if (strlen(s) != sp_str_byte_len(s))
|
|
266
|
+
SP_INT_REJECT("ArgumentError", sp_sprintf("invalid value for Integer(): \"%s\"", s));
|
|
267
|
+
int neg, any;
|
|
268
|
+
sp_int v;
|
|
269
|
+
const char *p = sp_int_head(s, &base, &neg);
|
|
270
|
+
if (base < 2 || base > 36) SP_INT_REJECT("ArgumentError", sp_sprintf("invalid radix %lld", (long long)base));
|
|
271
|
+
if (*p == '\0') SP_INT_REJECT("ArgumentError", sp_sprintf("invalid value for Integer(): \"%s\"", s));
|
|
272
|
+
p = sp_int_scan(p, base, &v, &any);
|
|
273
|
+
if (!p) SP_INT_REJECT("RangeError", sp_sprintf("integer overflow parsing \"%s\"", s));
|
|
274
|
+
if (!any) SP_INT_REJECT("ArgumentError", sp_sprintf("invalid value for Integer(): \"%s\"", s));
|
|
275
|
+
while (isspace((unsigned char)*p)) p++;
|
|
276
|
+
if (*p != '\0') SP_INT_REJECT("ArgumentError", sp_sprintf("invalid value for Integer(): \"%s\"", s));
|
|
277
|
+
return neg ? -v : v;
|
|
278
|
+
#undef SP_INT_REJECT
|
|
279
|
+
}
|
|
280
|
+
sp_int sp_str_to_i_strict_base(const char *s, sp_int base) {
|
|
281
|
+
return sp_str_to_i_base_impl(s, base, 0);
|
|
282
|
+
}
|
|
283
|
+
/* Kernel#Integer(s[, base], exception: false) */
|
|
284
|
+
sp_int sp_str_to_i_lenient_base(const char *s, sp_int base) {
|
|
285
|
+
return sp_str_to_i_base_impl(s, base, 1);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/* The decimal text Float() accepts once its underscores are stripped: an
|
|
289
|
+
optional sign, digits, an optional '.' that may have no digit after it
|
|
290
|
+
("5.", "1.e5"; at least one digit in all), and an optional exponent that
|
|
291
|
+
has a digit of its own. Nothing may follow, so a second point is refused. */
|
|
292
|
+
static int sp_float_text_shape_ok(const char *p) {
|
|
293
|
+
int nd = 0;
|
|
294
|
+
if (*p == '+' || *p == '-') p++;
|
|
295
|
+
while (isdigit((unsigned char)*p)) { p++; nd++; }
|
|
296
|
+
if (*p == '.') { p++; while (isdigit((unsigned char)*p)) { p++; nd++; } }
|
|
297
|
+
if (!nd) return 0;
|
|
298
|
+
if (*p == 'e' || *p == 'E') {
|
|
299
|
+
p++;
|
|
300
|
+
if (*p == '+' || *p == '-') p++;
|
|
301
|
+
if (!isdigit((unsigned char)*p)) return 0;
|
|
302
|
+
while (isdigit((unsigned char)*p)) p++;
|
|
303
|
+
}
|
|
304
|
+
return *p == '\0';
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/* Kernel#Float() raises ArgumentError on unparseable input. strtod
|
|
308
|
+
on its own would silently return 0.0 for "abc" or empty input;
|
|
309
|
+
match MRI semantics by validating at-least-one-digit + no-trailing-
|
|
310
|
+
junk. Whitespace flanking is fine. Issue #888. */
|
|
311
|
+
static sp_float sp_str_to_f_impl(const char *s, int lenient) {SP_GC_ROOT_STR(s);
|
|
312
|
+
if (!s) { if (lenient) return sp_float_nil(); sp_raise_cls("ArgumentError", "invalid value for Float(): nil"); }
|
|
313
|
+
/* embedded NUL: the Ruby string extends past its C prefix -- reject rather
|
|
314
|
+
than silently parsing the prefix ("1\\0" is not a float in CRuby). */
|
|
315
|
+
size_t blen = sp_str_byte_len(s);
|
|
316
|
+
if (strlen(s) != blen) goto bad0;
|
|
317
|
+
{
|
|
318
|
+
/* Clean into a buffer, enforcing CRuby's shape rules that strtod is looser
|
|
319
|
+
about: an '_' only BETWEEN two digits of the active base (stripped);
|
|
320
|
+
a hex literal is integral (hex digits only after 0x); at least one real
|
|
321
|
+
digit must appear (rejects "inf"/"nan", which strtod would parse). A
|
|
322
|
+
decimal literal's own shape is checked below once it is copied. */
|
|
323
|
+
size_t n = strlen(s);
|
|
324
|
+
char sbuf[256];
|
|
325
|
+
char *buf = n < sizeof sbuf ? sbuf : (char *)malloc(n + 1);
|
|
326
|
+
if (!buf) { perror("malloc"); exit(1); }
|
|
327
|
+
size_t o = 0;
|
|
328
|
+
int hex = 0, sawdigit = 0, sawp = 0, sawdot = 0;
|
|
329
|
+
const char *q = s;
|
|
330
|
+
while (isspace((unsigned char)*q)) q++;
|
|
331
|
+
const char *start = q;
|
|
332
|
+
if (*q == '+' || *q == '-') buf[o++] = *q++;
|
|
333
|
+
if (q[0] == '0' && (q[1] == 'x' || q[1] == 'X')) { hex = 1; buf[o++] = *q++; buf[o++] = *q++; }
|
|
334
|
+
for (; *q && !isspace((unsigned char)*q); q++) {
|
|
335
|
+
char ch = *q;
|
|
336
|
+
if (ch == '_') {
|
|
337
|
+
int pd = q > start && (hex ? isxdigit((unsigned char)q[-1]) : isdigit((unsigned char)q[-1]));
|
|
338
|
+
int nd = hex ? isxdigit((unsigned char)q[1]) : isdigit((unsigned char)q[1]);
|
|
339
|
+
if (!(pd && nd)) goto bad;
|
|
340
|
+
continue; /* a valid digit separator: strip */
|
|
341
|
+
}
|
|
342
|
+
if (hex) {
|
|
343
|
+
/* hex FLOATS are valid Float() input: 0x1p4 / 0x1.8p-1 (hex digits,
|
|
344
|
+
an optional single point before the mandatory p-exponent, then
|
|
345
|
+
decimal exponent digits with an optional sign) */
|
|
346
|
+
/* sawp/sawdot flags, NOT strchr(buf, ...): buf is not yet
|
|
347
|
+
NUL-terminated inside this loop, so strchr read past the written
|
|
348
|
+
prefix into uninitialized stack (a stray 'p' there failed valid
|
|
349
|
+
inputs like "0xa" depending on the caller's stack residue) */
|
|
350
|
+
if (ch == 'p' || ch == 'P') {
|
|
351
|
+
if (!sawdigit || sawp) goto bad;
|
|
352
|
+
sawp = 1;
|
|
353
|
+
buf[o++] = ch;
|
|
354
|
+
if (q[1] == '+' || q[1] == '-') { buf[o++] = q[1]; q++; }
|
|
355
|
+
if (!isdigit((unsigned char)q[1])) goto bad;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
if (sawp) {
|
|
359
|
+
if (!isdigit((unsigned char)ch)) goto bad;
|
|
360
|
+
buf[o++] = ch;
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
if (ch == '.') {
|
|
364
|
+
if (sawdot || !isxdigit((unsigned char)q[1])) goto bad;
|
|
365
|
+
sawdot = 1;
|
|
366
|
+
buf[o++] = ch;
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
if (!isxdigit((unsigned char)ch)) goto bad;
|
|
370
|
+
sawdigit = 1;
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
if (isdigit((unsigned char)ch)) sawdigit = 1;
|
|
374
|
+
}
|
|
375
|
+
buf[o++] = ch;
|
|
376
|
+
}
|
|
377
|
+
while (isspace((unsigned char)*q)) q++;
|
|
378
|
+
if (*q || !sawdigit) goto bad; /* junk after spaces / no digits */
|
|
379
|
+
buf[o] = '\0';
|
|
380
|
+
/* sp_read_float below stops at the first character it cannot use and
|
|
381
|
+
succeeds, so text after a valid prefix ("1.0foo", "1e", "0b10") has to
|
|
382
|
+
be refused here: digits, an optional fraction, then an optional exponent
|
|
383
|
+
with at least one digit of its own. A hex literal was validated above. */
|
|
384
|
+
if (!hex && !sp_float_text_shape_ok(buf)) goto bad;
|
|
385
|
+
{
|
|
386
|
+
char *endptr;
|
|
387
|
+
double v = 0.0;
|
|
388
|
+
/* A hex literal (0x...) is validated integral above and has no decimal
|
|
389
|
+
point, so strtod (which parses hex floats) is safe and locale-neutral;
|
|
390
|
+
a decimal literal uses the locale-independent sp_read_float. The shape
|
|
391
|
+
was already validated, so a short read is malformed input. */
|
|
392
|
+
if (hex) {
|
|
393
|
+
v = strtod(buf, &endptr);
|
|
394
|
+
if (endptr == buf || *endptr != '\0') goto bad;
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
/* The buffer is already a complete, validated float literal (a digit
|
|
398
|
+
appeared, no trailing junk), so sp_read_float's success is enough;
|
|
399
|
+
its endp is left at the start for all-zero input, so don't gate on
|
|
400
|
+
it consuming the buffer. */
|
|
401
|
+
if (!sp_read_float(buf, &endptr, &v)) goto bad;
|
|
402
|
+
}
|
|
403
|
+
if (buf != sbuf) free(buf);
|
|
404
|
+
return (sp_float)v;
|
|
405
|
+
}
|
|
406
|
+
bad:
|
|
407
|
+
if (buf != sbuf) free(buf);
|
|
408
|
+
}
|
|
409
|
+
bad0:
|
|
410
|
+
/* Kernel#Float(s, exception: false) answers nil for everything this rejects */
|
|
411
|
+
if (lenient) return sp_float_nil();
|
|
412
|
+
sp_raise_cls("ArgumentError", sp_sprintf("invalid value for Float(): \"%s\"", s));
|
|
413
|
+
return 0.0; /* unreachable */
|
|
414
|
+
}
|
|
415
|
+
sp_float sp_str_to_f_strict(const char *s) { return sp_str_to_f_impl(s, 0); }
|
|
416
|
+
sp_float sp_str_to_f_lenient(const char *s) { return sp_str_to_f_impl(s, 1); }
|
|
417
|
+
|
|
418
|
+
/* Kernel#sprintf's float directives (%f/%e/%g/%a with width/flags) are emitted
|
|
419
|
+
by faithfully delegating to libc snprintf, which is locale-sensitive for the
|
|
420
|
+
decimal point. Run that one call under a pinned "C" locale so the output
|
|
421
|
+
always uses '.', matching Ruby, regardless of the process locale. The number
|
|
422
|
+
primitives (Float#to_s / to_f) are locale-free via fp_uscale; this is only
|
|
423
|
+
for the printf-compatible field/flag machinery libc handles best. */
|
|
424
|
+
int sp_snprintf_c_float(char *buf, size_t size, const char *fmt, double v) {
|
|
425
|
+
#if defined(_WIN32)
|
|
426
|
+
/* the UCRT's %a keeps every trailing zero of the mantissa ("0x1.0000000000000p+0");
|
|
427
|
+
MinGW-w64's own C99 printf trims as glibc does */
|
|
428
|
+
if (strpbrk(fmt, "aA")) return __mingw_snprintf(buf, size, fmt, v);
|
|
429
|
+
#endif
|
|
430
|
+
static locale_t sp_c_loc = (locale_t)0;
|
|
431
|
+
if (!sp_c_loc) sp_c_loc = newlocale(LC_ALL_MASK, "C", (locale_t)0);
|
|
432
|
+
if (sp_c_loc) {
|
|
433
|
+
locale_t old = uselocale(sp_c_loc);
|
|
434
|
+
int n = snprintf(buf, size, fmt, v);
|
|
435
|
+
uselocale(old);
|
|
436
|
+
return n;
|
|
437
|
+
}
|
|
438
|
+
return snprintf(buf, size, fmt, v);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/* Ruby's float conversions go through its BSD__dtoa (missing/dtoa.c), whose
|
|
442
|
+
fast path generates the digits in double arithmetic and, unlike David
|
|
443
|
+
Gay's original, settles a remainder within its error bound of one half as
|
|
444
|
+
a tie, to even: `format("%.2f", 2.675)` answers 2.68 where C's printf
|
|
445
|
+
answers 2.67 (2.675 is stored as 2.67499999999999982), and
|
|
446
|
+
`format("%.2f", 0.69 / 6)` (0.11499999999999999112) answers 0.12 (#7270).
|
|
447
|
+
The fast path is run here as dtoa runs it (mode 3 for %f with the
|
|
448
|
+
precision as decimals, mode 2 for %e/%g as significant digits), and the
|
|
449
|
+
digits it settles on are rebuilt into the double libc then lays out. Where
|
|
450
|
+
dtoa leaves the fast path for its exact arithmetic (more than 14 digits, a
|
|
451
|
+
cut before the first digit, a denormal), the exact binary value is
|
|
452
|
+
rounded, which is what libc does. *keep_zeros is set when dtoa answers its
|
|
453
|
+
digits untrimmed: a tie settled to even whose exact value lies above the
|
|
454
|
+
half keeps its trailing zeros, which %g then prints (`format("%.5g",
|
|
455
|
+
7.91905000000000001)` is 7.9190). */
|
|
456
|
+
static double sp_float_round_ruby(double v, int mode, int ndigits, int *keep_zeros) {
|
|
457
|
+
static const double tens[] = {
|
|
458
|
+
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14,
|
|
459
|
+
1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 };
|
|
460
|
+
static const double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
|
|
461
|
+
if (!isfinite(v) || v == 0.0) return v;
|
|
462
|
+
union { double f; uint64_t u; } x, d2, e;
|
|
463
|
+
double d = v < 0 ? -v : v;
|
|
464
|
+
x.f = d;
|
|
465
|
+
int bexp = (int)((x.u >> 52) & 0x7ff);
|
|
466
|
+
if (bexp == 0) return v;
|
|
467
|
+
/* k: dtoa's estimate of floor(log10(d)), exact when it can check it */
|
|
468
|
+
d2.u = (x.u & 0x000fffffffffffffULL) | 0x3ff0000000000000ULL;
|
|
469
|
+
int i = bexp - 1023;
|
|
470
|
+
double dsl = (d2.f - 1.5) * 0.289529654602168 + 0.1760912590558 + i * 0.301029995663981;
|
|
471
|
+
int k = (int)dsl;
|
|
472
|
+
if (dsl < 0. && dsl != k) k--;
|
|
473
|
+
int k_check = 1;
|
|
474
|
+
if (k >= 0 && k <= 22) {
|
|
475
|
+
if (d < tens[k]) k--;
|
|
476
|
+
k_check = 0;
|
|
477
|
+
}
|
|
478
|
+
int ilim, ilim1;
|
|
479
|
+
if (mode == 2) {
|
|
480
|
+
if (ndigits <= 0) ndigits = 1;
|
|
481
|
+
ilim = ilim1 = ndigits;
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
ilim = ndigits + k + 1;
|
|
485
|
+
ilim1 = ilim - 1;
|
|
486
|
+
}
|
|
487
|
+
if (ilim <= 0 || ilim > 14) return v;
|
|
488
|
+
int ieps = 2;
|
|
489
|
+
if (k > 0) {
|
|
490
|
+
double ds = tens[k & 0xf];
|
|
491
|
+
int j = k >> 4;
|
|
492
|
+
if (j & 0x10) { j &= 0xf; d /= bigtens[4]; ieps++; }
|
|
493
|
+
for (int n = 0; j; j >>= 1, n++)
|
|
494
|
+
if (j & 1) { ieps++; ds *= bigtens[n]; }
|
|
495
|
+
d /= ds;
|
|
496
|
+
}
|
|
497
|
+
else if (k < 0) {
|
|
498
|
+
int j1 = -k;
|
|
499
|
+
d *= tens[j1 & 0xf];
|
|
500
|
+
for (int j = j1 >> 4, n = 0; j; j >>= 1, n++)
|
|
501
|
+
if (j & 1) { ieps++; d *= bigtens[n]; }
|
|
502
|
+
}
|
|
503
|
+
if (k_check && d < 1.) {
|
|
504
|
+
if (ilim1 <= 0) return v;
|
|
505
|
+
ilim = ilim1; k--; d *= 10.; ieps++;
|
|
506
|
+
}
|
|
507
|
+
e.f = ieps * d + 7.;
|
|
508
|
+
e.u -= (uint64_t)52 << 52;
|
|
509
|
+
double eps = e.f * tens[ilim - 1];
|
|
510
|
+
char s[24];
|
|
511
|
+
int n = 0;
|
|
512
|
+
for (int t = 1;; t++, d *= 10.) {
|
|
513
|
+
long L = (long)d;
|
|
514
|
+
if (!(d -= L)) ilim = t;
|
|
515
|
+
s[n++] = (char)('0' + L);
|
|
516
|
+
if (t == ilim) {
|
|
517
|
+
if (d > 0.5 + eps) goto bump_up;
|
|
518
|
+
if (d < 0.5 - eps) break;
|
|
519
|
+
/* within the error bound of a half: a tie, to even */
|
|
520
|
+
if ((s[n - 1] - '0') & 1) goto bump_up;
|
|
521
|
+
/* dtoa redoes these digits exactly and keeps them whatever the exact
|
|
522
|
+
remainder; above an exact half it does not trim their zeros */
|
|
523
|
+
/* an integer below 1e15 is redone by dtoa's small-integer loop, which
|
|
524
|
+
stops at the last kept digit without trimming */
|
|
525
|
+
if (keep_zeros && x.f == floor(x.f) && k <= 14) *keep_zeros = 1;
|
|
526
|
+
else if (keep_zeros && n < 20) {
|
|
527
|
+
char ex[900];
|
|
528
|
+
snprintf(ex, sizeof ex, "%.800e", v < 0 ? -v : v);
|
|
529
|
+
int dpos = n; /* digit after the kept ones, in ex's mantissa */
|
|
530
|
+
const char *q = ex; int seen = 0;
|
|
531
|
+
while (*q && *q != 'e') {
|
|
532
|
+
if (*q >= '0' && *q <= '9') {
|
|
533
|
+
if (seen == dpos) break;
|
|
534
|
+
seen++;
|
|
535
|
+
}
|
|
536
|
+
q++;
|
|
537
|
+
}
|
|
538
|
+
if (*q >= '0' && *q <= '9') {
|
|
539
|
+
int above = *q > '5';
|
|
540
|
+
if (*q == '5') for (const char *t = q + 1; *t && *t != 'e'; t++) if (*t != '0') { above = 1; break; }
|
|
541
|
+
*keep_zeros = above;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
break;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
goto rebuild;
|
|
548
|
+
bump_up:
|
|
549
|
+
while (n > 0 && s[n - 1] == '9') n--;
|
|
550
|
+
if (n == 0) { s[n++] = '1'; k++; }
|
|
551
|
+
else s[n - 1]++;
|
|
552
|
+
rebuild:
|
|
553
|
+
s[n] = 0;
|
|
554
|
+
char buf[64];
|
|
555
|
+
snprintf(buf, sizeof buf, "0.%se%d", s, k + 1);
|
|
556
|
+
char *end = NULL;
|
|
557
|
+
double r = 0;
|
|
558
|
+
if (!sp_read_float(buf, &end, &r) || !isfinite(r)) return v;
|
|
559
|
+
return v < 0 ? -r : r;
|
|
560
|
+
}
|
|
561
|
+
/* sprintf's float directives: the C-locale delegation above, with Ruby's
|
|
562
|
+
rounding. The conversion decides how many significant digits survive --
|
|
563
|
+
%f counts them from the decimal point, %e from the first digit, %g is a
|
|
564
|
+
significant-digit count of its own. A `*` precision takes an argument this
|
|
565
|
+
call does not receive, so such a format is left to libc. */
|
|
566
|
+
int sp_snprintf_ruby_float(char *buf, size_t size, const char *fmt, double v) {
|
|
567
|
+
size_t n = fmt ? strlen(fmt) : 0;
|
|
568
|
+
char conv = n ? fmt[n - 1] : 0;
|
|
569
|
+
if ((conv == 'f' || conv == 'e' || conv == 'E' || conv == 'g' || conv == 'G') &&
|
|
570
|
+
!strchr(fmt, '*') && isfinite(v) && v != 0.0) {
|
|
571
|
+
const char *dot = strchr(fmt, '.');
|
|
572
|
+
int prec = 6; /* C's default for all five */
|
|
573
|
+
if (dot) {
|
|
574
|
+
prec = 0;
|
|
575
|
+
for (const char *q = dot + 1; *q >= '0' && *q <= '9'; q++) prec = prec * 10 + (*q - '0');
|
|
576
|
+
}
|
|
577
|
+
int keep_zeros = 0;
|
|
578
|
+
if (conv == 'f') v = sp_float_round_ruby(v, 3, prec, NULL);
|
|
579
|
+
else if (conv == 'e' || conv == 'E') v = sp_float_round_ruby(v, 2, prec + 1, NULL);
|
|
580
|
+
else {
|
|
581
|
+
v = sp_float_round_ruby(v, 2, prec, &keep_zeros);
|
|
582
|
+
/* %g with dtoa's digits untrimmed: the alternate form keeps the zeros;
|
|
583
|
+
a point it adds with no digit after it is not Ruby's */
|
|
584
|
+
if (keep_zeros && !strchr(fmt, '#') && n + 2 < 48) {
|
|
585
|
+
/* the flags and the width are laid out here, around the digits */
|
|
586
|
+
const char *f = fmt + 1;
|
|
587
|
+
int minus = 0, zero = 0, plus = 0, space = 0, width = 0;
|
|
588
|
+
for (;; f++) {
|
|
589
|
+
if (*f == '-') minus = 1;
|
|
590
|
+
else if (*f == '0') zero = 1;
|
|
591
|
+
else if (*f == '+') plus = 1;
|
|
592
|
+
else if (*f == ' ') space = 1;
|
|
593
|
+
else break;
|
|
594
|
+
}
|
|
595
|
+
while (*f >= '0' && *f <= '9' && width < 10000) width = width * 10 + (*f++ - '0');
|
|
596
|
+
if (width > 1000) return sp_snprintf_c_float(buf, size, fmt, v);
|
|
597
|
+
char af[64], body[512];
|
|
598
|
+
snprintf(af, sizeof af, "%%%s%s#%s", plus ? "+" : "", space ? " " : "", f);
|
|
599
|
+
int w = sp_snprintf_c_float(body, sizeof body, af, v);
|
|
600
|
+
if (w < 0 || (size_t)w >= sizeof body) return sp_snprintf_c_float(buf, size, fmt, v);
|
|
601
|
+
char *pt = strchr(body, '.');
|
|
602
|
+
if (pt && (pt[1] < '0' || pt[1] > '9')) { memmove(pt, pt + 1, strlen(pt + 1) + 1); w--; }
|
|
603
|
+
int pad = width > w ? width - w : 0;
|
|
604
|
+
char out[1100]; int o = 0;
|
|
605
|
+
const char *b0 = body;
|
|
606
|
+
if (!minus && zero && pad) {
|
|
607
|
+
if (*b0 == '-' || *b0 == '+' || *b0 == ' ') out[o++] = *b0++;
|
|
608
|
+
while (pad-- > 0) out[o++] = '0';
|
|
609
|
+
}
|
|
610
|
+
else if (!minus) while (pad-- > 0) out[o++] = ' ';
|
|
611
|
+
while (*b0) out[o++] = *b0++;
|
|
612
|
+
if (minus) while (pad-- > 0) out[o++] = ' ';
|
|
613
|
+
out[o] = 0;
|
|
614
|
+
if (size) { size_t c = (size_t)o < size - 1 ? (size_t)o : size - 1; memcpy(buf, out, c); buf[c] = 0; }
|
|
615
|
+
return o;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
return sp_snprintf_c_float(buf, size, fmt, v);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/* Cold integer-math and String#oct helpers, moved out of spinel_rt.h
|
|
623
|
+
* so they're compiled once into libspinel_rt.a rather than re-parsed
|
|
624
|
+
* in every generated translation unit. Leaf functions: arithmetic +
|
|
625
|
+
* libc + sp_raise_cls only. */
|
|
626
|
+
sp_int sp_gcd(sp_int a,sp_int b){if(a<0)a=-a;if(b<0)b=-b;while(b){sp_int t=b;b=a%b;a=t;}return a;}
|
|
627
|
+
sp_int sp_lcm(sp_int a,sp_int b){if(a==0||b==0)return 0;sp_int g=sp_gcd(a,b);if(a<0)a=-a;if(b<0)b=-b;return (a/g)*b;}
|
|
628
|
+
sp_int sp_powmod(sp_int base,sp_int exp,sp_int mod){if(exp<0)sp_raise_cls("RangeError","Integer#pow() 1st argument cannot be negative when 2nd argument specified");if(mod==0)sp_raise_cls("ZeroDivisionError","divided by 0");sp_int r=1;sp_int m=mod<0?-mod:mod;if(m==1){r=0;}
|
|
629
|
+
else{base=base%m;if(base<0)base+=m;while(exp>0){if(exp%2==1)r=r*base%m;exp=exp/2;base=base*base%m;}}if(mod<0&&r>0)r-=m;return r;}
|
|
630
|
+
sp_int sp_ceildiv(sp_int a,sp_int b){if(b==0)sp_raise_cls("ZeroDivisionError","divided by 0");if(b==-1)return -a;sp_int q=a/b;if(a%b!=0&&((a^b)>=0))q++;return q;}
|
|
631
|
+
sp_int sp_int_clamp(sp_int v,sp_int lo,sp_int hi){return v<lo?lo:v>hi?hi:v;}
|
|
632
|
+
sp_float sp_float_clamp(sp_float v,sp_float lo,sp_float hi){return v<lo?lo:v>hi?hi:v;}
|
|
633
|
+
/* Integer square root via Newton's method -- exact for the full
|
|
634
|
+
sp_int range. CRuby raises Math::DomainError on negative input
|
|
635
|
+
(flattened runtime name "Math::DomainError"). The seed is n/2, not
|
|
636
|
+
(n+1)/2: at n == INTPTR_MAX the latter overflows (signed UB), and
|
|
637
|
+
n/2 is a valid Newton seed for all n >= 2. */
|
|
638
|
+
sp_int sp_int_sqrt(sp_int n){if(n<0)sp_raise_cls("Math::DomainError","Numerical argument is out of domain - \"isqrt\"");if(n<2)return n;sp_int x=n,y=n/2;while(y<x){x=y;y=(x+n/x)/2;}return x;}
|
|
639
|
+
/* Integer#round/ceil/floor/truncate at 10^(-ndigits). Pure integer
|
|
640
|
+
arithmetic (no double precision loss above 2^53). 10^p fits sp_int
|
|
641
|
+
only for p<=18; p>=19 collapses to 0. Round-up multiply is overflow-
|
|
642
|
+
guarded and falls back to the truncated value. */
|
|
643
|
+
sp_int sp_ipow10(sp_int p){sp_int f=1;sp_int i=0;while(i<p){f*=10;i++;}return f;}
|
|
644
|
+
void sp_int_round_check_ndigits(sp_int nd) {
|
|
645
|
+
if (nd > INT_MAX || nd < INT_MIN)
|
|
646
|
+
sp_raise_cls("RangeError", sp_sprintf("integer %lld too %s to convert to 'int'",
|
|
647
|
+
(long long)nd, nd < 0 ? "small" : "big"));
|
|
648
|
+
}
|
|
649
|
+
sp_int sp_int_round(sp_int v,sp_int nd){sp_int_round_check_ndigits(nd);if(nd>=0)return v;sp_int p=-nd;if(p>=SP_INT_POW10_LIMIT)return 0;sp_int f=sp_ipow10(p);sp_int q=v/f,r=v%f,half=f/2;if(v>=0){if(r>=half&&q<INTPTR_MAX/f)return(q+1)*f;return q*f;}if(-r>=half&&q>INTPTR_MIN/f)return(q-1)*f;return q*f;}
|
|
650
|
+
sp_int sp_int_ceil(sp_int v,sp_int nd){if(nd>=0)return v;sp_int p=-nd;if(p>=SP_INT_POW10_LIMIT)return 0;sp_int f=sp_ipow10(p);sp_int q=v/f,r=v%f;if(r!=0&&v>0&&q<INTPTR_MAX/f)return(q+1)*f;return q*f;}
|
|
651
|
+
sp_int sp_int_floor(sp_int v,sp_int nd){if(nd>=0)return v;sp_int p=-nd;if(p>=SP_INT_POW10_LIMIT)return 0;sp_int f=sp_ipow10(p);sp_int q=v/f,r=v%f;if(r!=0&&v<0&&q>INTPTR_MIN/f)return(q-1)*f;return q*f;}
|
|
652
|
+
sp_int sp_int_truncate(sp_int v,sp_int nd){if(nd>=0)return v;sp_int p=-nd;if(p>=SP_INT_POW10_LIMIT)return 0;sp_int f=sp_ipow10(p);return(v/f)*f;}
|
|
653
|
+
/* String#oct: prefix auto-detection (0x=hex, 0b=bin, 0o/0=oct, else
|
|
654
|
+
base-8). Matches CRuby. */
|
|
655
|
+
/* String#oct: lenient Integer(str, 8)-style parse. Skips leading whitespace,
|
|
656
|
+
accepts an optional sign, an optional base prefix (0x/0b/0o/0d, or a leading
|
|
657
|
+
0 = octal), and single `_` separators between digits. Stops at the first
|
|
658
|
+
character not valid in the selected base (a leading/doubled underscore ends
|
|
659
|
+
parsing too); an unparseable string is 0. A value past sp_int raises
|
|
660
|
+
RangeError, like the sibling Integer() parsers. */
|
|
661
|
+
sp_int sp_str_oct(const char*s){SP_GC_ROOT_STR(s);
|
|
662
|
+
if(!s)return 0;
|
|
663
|
+
const char*p=s;
|
|
664
|
+
while(isspace((unsigned char)*p))p++;
|
|
665
|
+
int sign=1;
|
|
666
|
+
if(*p=='+')p++;
|
|
667
|
+
else if(*p=='-'){sign=-1;p++;}
|
|
668
|
+
int base=8;
|
|
669
|
+
if(p[0]=='0'){
|
|
670
|
+
char c=p[1];
|
|
671
|
+
if(c=='x'||c=='X'){base=16;p+=2;}
|
|
672
|
+
else if(c=='b'||c=='B'){base=2;p+=2;}
|
|
673
|
+
else if(c=='o'||c=='O'){base=8;p+=2;}
|
|
674
|
+
else if(c=='d'||c=='D'){base=10;p+=2;}
|
|
675
|
+
/* a bare leading 0 is octal; keep p on the 0 (a valid octal digit) */
|
|
676
|
+
}
|
|
677
|
+
sp_int val=0; int any=0, prev_us=0;
|
|
678
|
+
for(;;){
|
|
679
|
+
char c=*p; int d;
|
|
680
|
+
if(c>='0'&&c<='9')d=c-'0';
|
|
681
|
+
else if(c>='a'&&c<='z')d=c-'a'+10;
|
|
682
|
+
else if(c>='A'&&c<='Z')d=c-'A'+10;
|
|
683
|
+
else if(c=='_'){ if(!any||prev_us)break; prev_us=1; p++; continue; }
|
|
684
|
+
else break;
|
|
685
|
+
if(d>=base)break;
|
|
686
|
+
sp_int t;
|
|
687
|
+
if(sp_ckd_mul_iptr(val,(sp_int)base,&t)||
|
|
688
|
+
sp_ckd_add_iptr(t,(sp_int)d,&val))
|
|
689
|
+
sp_raise_cls("RangeError",sp_sprintf("integer overflow parsing \"%s\"",s));
|
|
690
|
+
any=1; prev_us=0; p++;
|
|
691
|
+
}
|
|
692
|
+
return sign*val;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/* Float#round(n) and its siblings at a positive digit count. Scaling by 10**n
|
|
696
|
+
and rounding the product reads the product's OWN representation error as
|
|
697
|
+
part of the value: 64.781995 * 1e5 is 6478199.4999999991, so the digit that
|
|
698
|
+
should round up rounds down and the answer comes out a decimal short. CRuby
|
|
699
|
+
compensates by asking whether the next step up is still <= the input, which
|
|
700
|
+
is what makes 64.781995.round(5) answer 64.782 rather than 64.78199. The
|
|
701
|
+
floor/ceil forms compensate the same way, from the other side.
|
|
702
|
+
nd <= 0 answers an Integer and is the caller's own path; this is the Float
|
|
703
|
+
half. (#3983) */
|
|
704
|
+
/* Float#round / #floor / #ceil / #truncate at a POSITIVE digit count, laid
|
|
705
|
+
out as CRuby lays it out (numeric.c: flo_round, rb_float_floor,
|
|
706
|
+
rb_float_ceil). Scaling by a power of ten and rounding the product reads the
|
|
707
|
+
product's OWN representation error as part of the value -- 64.781995 * 1e5
|
|
708
|
+
is 6478199.4999999991, so the digit that should round up rounds down and the
|
|
709
|
+
answer comes out a decimal short (#3983). Each form compensates differently,
|
|
710
|
+
and the asymmetry is deliberate:
|
|
711
|
+
round compensates on both sides, which is what makes 2.675.round(2)
|
|
712
|
+
answer 2.68 rather than the exact value's 2.67;
|
|
713
|
+
floor compensates upward only;
|
|
714
|
+
ceil takes the scaled product as it stands.
|
|
715
|
+
The two guards decide whether the digit being asked for is inside the
|
|
716
|
+
double's reach at all: past it the value is unchanged, short of it the value
|
|
717
|
+
rounds away to zero. A digit count a power of ten cannot represent exactly
|
|
718
|
+
(>= DBL_DIG) goes through the decimal conversion, which is exact, in place
|
|
719
|
+
of CRuby's rational arithmetic. */
|
|
720
|
+
/* The round family past DBL_DIG digits, decided on the value's own decimal
|
|
721
|
+
expansion rather than on a scaled product. The cut digit and what follows it
|
|
722
|
+
settle the tie the same way CRuby's rational arithmetic does, which the
|
|
723
|
+
library conversion alone cannot: it breaks exact ties to even, and Ruby's
|
|
724
|
+
default breaks them away from zero. */
|
|
725
|
+
static double sp_prec_decimal_round(double x, intptr_t nd, int op) {
|
|
726
|
+
char buf[512];
|
|
727
|
+
int extra = 25;
|
|
728
|
+
snprintf(buf, sizeof buf, "%.*f", (int)nd + extra, x);
|
|
729
|
+
char *dot = strchr(buf, '.');
|
|
730
|
+
if (!dot) return x;
|
|
731
|
+
char *cut = dot + 1 + (int)nd; /* the first digit past the cut */
|
|
732
|
+
char cutd = *cut;
|
|
733
|
+
int tail_nonzero = 0;
|
|
734
|
+
for (char *q = cut + 1; *q; q++) if (*q != '0') { tail_nonzero = 1; break; }
|
|
735
|
+
*cut = '\0'; /* the truncation toward zero */
|
|
736
|
+
double r = strtod(buf, NULL);
|
|
737
|
+
int away;
|
|
738
|
+
if (cutd > '5') away = 1;
|
|
739
|
+
else if (cutd < '5') away = 0;
|
|
740
|
+
else if (tail_nonzero) away = 1;
|
|
741
|
+
else if (op == SP_PREC_HALF_DOWN) away = 0;
|
|
742
|
+
else if (op == SP_PREC_HALF_EVEN) {
|
|
743
|
+
char last = cut[-1];
|
|
744
|
+
away = (last >= '0' && last <= '9') ? ((last - '0') % 2 != 0) : 0;
|
|
745
|
+
}
|
|
746
|
+
else away = 1; /* the default: ties leave zero behind */
|
|
747
|
+
if (!away) return r;
|
|
748
|
+
double step = 1.0 / pow(10, (double)nd);
|
|
749
|
+
snprintf(buf, sizeof buf, "%.*f", (int)nd, x < 0.0 ? r - step : r + step);
|
|
750
|
+
return strtod(buf, NULL);
|
|
751
|
+
}
|
|
752
|
+
static int sp_prec_overflow(intptr_t nd, int binexp) {
|
|
753
|
+
return nd >= (DBL_DIG + 2) - (binexp > 0 ? binexp / 4 : binexp / 3 - 1);
|
|
754
|
+
}
|
|
755
|
+
static int sp_prec_underflow(intptr_t nd, int binexp) {
|
|
756
|
+
return nd < -(binexp > 0 ? binexp / 3 + 1 : binexp / 4);
|
|
757
|
+
}
|
|
758
|
+
double sp_float_prec_op(double x, intptr_t nd, int op) {
|
|
759
|
+
if (x == 0.0 || !isfinite(x) || nd <= 0) return x;
|
|
760
|
+
if (op == SP_PREC_TRUNC) return sp_float_prec_op(x, nd, signbit(x) ? SP_PREC_CEIL : SP_PREC_FLOOR);
|
|
761
|
+
int binexp = 0;
|
|
762
|
+
frexp(x, &binexp);
|
|
763
|
+
if (sp_prec_overflow(nd, binexp)) return x;
|
|
764
|
+
if (sp_prec_underflow(nd, binexp)) {
|
|
765
|
+
/* round leaves zero whatever the sign; floor keeps a negative value's own
|
|
766
|
+
first decimal step, and ceil keeps a positive one's */
|
|
767
|
+
if (op == SP_PREC_FLOOR && x < 0.0) { /* fall through to the arithmetic */ }
|
|
768
|
+
else if (op == SP_PREC_CEIL && x > 0.0) { /* likewise */ }
|
|
769
|
+
else return 0.0;
|
|
770
|
+
}
|
|
771
|
+
/* Past DBL_DIG digits a power of ten is no longer exact, so the scaled form
|
|
772
|
+
reads its own error as part of the value; CRuby rounds those by rational.
|
|
773
|
+
The decimal conversion is the same exact answer. floor and ceil keep the
|
|
774
|
+
scaled form -- that is what CRuby answers for them. */
|
|
775
|
+
if (nd >= DBL_DIG && op != SP_PREC_FLOOR && op != SP_PREC_CEIL) return sp_prec_decimal_round(x, nd, op);
|
|
776
|
+
double s = pow(10, (double)nd);
|
|
777
|
+
double xs = x * s;
|
|
778
|
+
if (!isfinite(s) || !isfinite(xs)) return x;
|
|
779
|
+
double f;
|
|
780
|
+
switch (op) {
|
|
781
|
+
case SP_PREC_FLOOR: {
|
|
782
|
+
f = floor(xs);
|
|
783
|
+
double res = (f + 1) / s;
|
|
784
|
+
return res > x ? f / s : res;
|
|
785
|
+
}
|
|
786
|
+
case SP_PREC_CEIL:
|
|
787
|
+
return ceil(xs) / s;
|
|
788
|
+
case SP_PREC_HALF_EVEN: {
|
|
789
|
+
/* the tie is decided on the fractional part alone, so the integral part
|
|
790
|
+
is split off first and only rejoined at the end */
|
|
791
|
+
double u, v, us, vs, ff, d, uf;
|
|
792
|
+
v = modf(x, &u);
|
|
793
|
+
us = u * s; vs = v * s;
|
|
794
|
+
if (x > 0.0) {
|
|
795
|
+
ff = floor(vs); uf = us + ff; d = vs - ff;
|
|
796
|
+
if (d > 0.5) d = 1.0;
|
|
797
|
+
else if (d == 0.5 || (uf + 0.5) / s <= x) d = fmod(uf, 2.0);
|
|
798
|
+
else d = 0.0;
|
|
799
|
+
return (us + ff + d) / s;
|
|
800
|
+
}
|
|
801
|
+
ff = ceil(vs); uf = us + ff; d = ff - vs;
|
|
802
|
+
if (d > 0.5) d = 1.0;
|
|
803
|
+
else if (d == 0.5 || (uf - 0.5) / s >= x) d = fmod(-uf, 2.0);
|
|
804
|
+
else d = 0.0;
|
|
805
|
+
return (us + ff - d) / s;
|
|
806
|
+
}
|
|
807
|
+
case SP_PREC_HALF_DOWN:
|
|
808
|
+
f = round(xs);
|
|
809
|
+
if (x > 0) { if ((f - 0.5) / s >= x) f -= 1; }
|
|
810
|
+
else { if ((f + 0.5) / s <= x) f += 1; }
|
|
811
|
+
return f / s;
|
|
812
|
+
default:
|
|
813
|
+
f = round(xs);
|
|
814
|
+
if (x > 0) { if ((f + 0.5) / s <= x) f += 1; }
|
|
815
|
+
else { if ((f - 0.5) / s >= x) f -= 1; }
|
|
816
|
+
return f / s;
|
|
817
|
+
}
|
|
818
|
+
}
|