Line data Source code
1 : #ifndef FASTFLOAT_ASCII_NUMBER_H
2 : #define FASTFLOAT_ASCII_NUMBER_H
3 :
4 : #include <cctype>
5 : #include <cstdint>
6 : #include <cstring>
7 : #include <iterator>
8 : #include <type_traits>
9 :
10 : #include "float_common.h"
11 :
12 : #ifdef FASTFLOAT_SSE2
13 : #include <emmintrin.h>
14 : #endif
15 :
16 : #ifdef FASTFLOAT_NEON
17 : #include <arm_neon.h>
18 : #endif
19 :
20 : namespace fast_float {
21 :
22 : template <typename UC>
23 : fastfloat_really_inline constexpr bool has_simd_opt() {
24 : #ifdef FASTFLOAT_HAS_SIMD
25 0 : return std::is_same<UC, char16_t>::value;
26 : #else
27 : return false;
28 : #endif
29 : }
30 :
31 : // Next function can be micro-optimized, but compilers are entirely
32 : // able to optimize it well.
33 : template <typename UC>
34 : fastfloat_really_inline constexpr bool is_integer(UC c) noexcept {
35 41267700 : return !(c > UC('9') || c < UC('0'));
36 : }
37 :
38 : fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
39 : return (val & 0xFF00000000000000) >> 56
40 : | (val & 0x00FF000000000000) >> 40
41 : | (val & 0x0000FF0000000000) >> 24
42 : | (val & 0x000000FF00000000) >> 8
43 : | (val & 0x00000000FF000000) << 8
44 : | (val & 0x0000000000FF0000) << 24
45 : | (val & 0x000000000000FF00) << 40
46 : | (val & 0x00000000000000FF) << 56;
47 : }
48 :
49 : // Read 8 UC into a u64. Truncates UC if not char.
50 : template <typename UC>
51 : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
52 : uint64_t read8_to_u64(const UC *chars) {
53 1128290 : if (cpp20_and_in_constexpr() || !std::is_same<UC, char>::value) {
54 0 : uint64_t val = 0;
55 0 : for(int i = 0; i < 8; ++i) {
56 0 : val |= uint64_t(uint8_t(*chars)) << (i*8);
57 0 : ++chars;
58 : }
59 0 : return val;
60 : }
61 : uint64_t val;
62 1128290 : ::memcpy(&val, chars, sizeof(uint64_t));
63 : #if FASTFLOAT_IS_BIG_ENDIAN == 1
64 : // Need to read as-if the number was in little-endian order.
65 : val = byteswap(val);
66 : #endif
67 1128290 : return val;
68 : }
69 :
70 : #ifdef FASTFLOAT_SSE2
71 :
72 : fastfloat_really_inline
73 : uint64_t simd_read8_to_u64(const __m128i data) {
74 : FASTFLOAT_SIMD_DISABLE_WARNINGS
75 : const __m128i packed = _mm_packus_epi16(data, data);
76 : #ifdef FASTFLOAT_64BIT
77 : return uint64_t(_mm_cvtsi128_si64(packed));
78 : #else
79 : uint64_t value;
80 : // Visual Studio + older versions of GCC don't support _mm_storeu_si64
81 : _mm_storel_epi64(reinterpret_cast<__m128i*>(&value), packed);
82 : return value;
83 : #endif
84 : FASTFLOAT_SIMD_RESTORE_WARNINGS
85 : }
86 :
87 : fastfloat_really_inline
88 : uint64_t simd_read8_to_u64(const char16_t* chars) {
89 : FASTFLOAT_SIMD_DISABLE_WARNINGS
90 : return simd_read8_to_u64(_mm_loadu_si128(reinterpret_cast<const __m128i*>(chars)));
91 : FASTFLOAT_SIMD_RESTORE_WARNINGS
92 : }
93 :
94 : #elif defined(FASTFLOAT_NEON)
95 :
96 :
97 : fastfloat_really_inline
98 : uint64_t simd_read8_to_u64(const uint16x8_t data) {
99 : FASTFLOAT_SIMD_DISABLE_WARNINGS
100 : uint8x8_t utf8_packed = vmovn_u16(data);
101 : return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0);
102 : FASTFLOAT_SIMD_RESTORE_WARNINGS
103 : }
104 :
105 : fastfloat_really_inline
106 : uint64_t simd_read8_to_u64(const char16_t* chars) {
107 : FASTFLOAT_SIMD_DISABLE_WARNINGS
108 : return simd_read8_to_u64(vld1q_u16(reinterpret_cast<const uint16_t*>(chars)));
109 : FASTFLOAT_SIMD_RESTORE_WARNINGS
110 : }
111 :
112 : #endif // FASTFLOAT_SSE2
113 :
114 : // MSVC SFINAE is broken pre-VS2017
115 : #if defined(_MSC_VER) && _MSC_VER <= 1900
116 : template <typename UC>
117 : #else
118 : template <typename UC, FASTFLOAT_ENABLE_IF(!has_simd_opt<UC>())>
119 : #endif
120 : // dummy for compile
121 0 : uint64_t simd_read8_to_u64(UC const*) {
122 0 : return 0;
123 : }
124 :
125 :
126 : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
127 : void write_u64(uint8_t *chars, uint64_t val) {
128 : if (cpp20_and_in_constexpr()) {
129 : for(int i = 0; i < 8; ++i) {
130 : *chars = uint8_t(val);
131 : val >>= 8;
132 : ++chars;
133 : }
134 : return;
135 : }
136 : #if FASTFLOAT_IS_BIG_ENDIAN == 1
137 : // Need to read as-if the number was in little-endian order.
138 : val = byteswap(val);
139 : #endif
140 : ::memcpy(chars, &val, sizeof(uint64_t));
141 : }
142 :
143 : // credit @aqrit
144 : fastfloat_really_inline FASTFLOAT_CONSTEXPR14
145 : uint32_t parse_eight_digits_unrolled(uint64_t val) {
146 549944 : const uint64_t mask = 0x000000FF000000FF;
147 549944 : const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
148 549944 : const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
149 549944 : val -= 0x3030303030303030;
150 549944 : val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
151 549944 : val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
152 0 : return uint32_t(val);
153 : }
154 :
155 :
156 : // Call this if chars are definitely 8 digits.
157 : template <typename UC>
158 : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
159 : uint32_t parse_eight_digits_unrolled(UC const * chars) noexcept {
160 0 : if (cpp20_and_in_constexpr() || !has_simd_opt<UC>()) {
161 0 : return parse_eight_digits_unrolled(read8_to_u64(chars)); // truncation okay
162 : }
163 0 : return parse_eight_digits_unrolled(simd_read8_to_u64(chars));
164 : }
165 :
166 :
167 : // credit @aqrit
168 : fastfloat_really_inline constexpr bool is_made_of_eight_digits_fast(uint64_t val) noexcept {
169 578350 : return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) &
170 578350 : 0x8080808080808080));
171 : }
172 :
173 :
174 : #ifdef FASTFLOAT_HAS_SIMD
175 :
176 : // Call this if chars might not be 8 digits.
177 : // Using this style (instead of is_made_of_eight_digits_fast() then parse_eight_digits_unrolled())
178 : // ensures we don't load SIMD registers twice.
179 : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
180 : bool simd_parse_if_eight_digits_unrolled(const char16_t* chars, uint64_t& i) noexcept {
181 : if (cpp20_and_in_constexpr()) {
182 : return false;
183 : }
184 : #ifdef FASTFLOAT_SSE2
185 : FASTFLOAT_SIMD_DISABLE_WARNINGS
186 : const __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i*>(chars));
187 :
188 : // (x - '0') <= 9
189 : // http://0x80.pl/articles/simd-parsing-int-sequences.html
190 : const __m128i t0 = _mm_add_epi16(data, _mm_set1_epi16(32720));
191 : const __m128i t1 = _mm_cmpgt_epi16(t0, _mm_set1_epi16(-32759));
192 :
193 : if (_mm_movemask_epi8(t1) == 0) {
194 : i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data));
195 : return true;
196 : }
197 : else return false;
198 : FASTFLOAT_SIMD_RESTORE_WARNINGS
199 : #elif defined(FASTFLOAT_NEON)
200 : FASTFLOAT_SIMD_DISABLE_WARNINGS
201 : const uint16x8_t data = vld1q_u16(reinterpret_cast<const uint16_t*>(chars));
202 :
203 : // (x - '0') <= 9
204 : // http://0x80.pl/articles/simd-parsing-int-sequences.html
205 : const uint16x8_t t0 = vsubq_u16(data, vmovq_n_u16('0'));
206 : const uint16x8_t mask = vcltq_u16(t0, vmovq_n_u16('9' - '0' + 1));
207 :
208 : if (vminvq_u16(mask) == 0xFFFF) {
209 : i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data));
210 : return true;
211 : }
212 : else return false;
213 : FASTFLOAT_SIMD_RESTORE_WARNINGS
214 : #else
215 : (void)chars; (void)i;
216 : return false;
217 : #endif // FASTFLOAT_SSE2
218 : }
219 :
220 : #endif // FASTFLOAT_HAS_SIMD
221 :
222 : // MSVC SFINAE is broken pre-VS2017
223 : #if defined(_MSC_VER) && _MSC_VER <= 1900
224 : template <typename UC>
225 : #else
226 : template <typename UC, FASTFLOAT_ENABLE_IF(!has_simd_opt<UC>())>
227 : #endif
228 : // dummy for compile
229 : bool simd_parse_if_eight_digits_unrolled(UC const*, uint64_t&) {
230 : return 0;
231 : }
232 :
233 :
234 : template <typename UC, FASTFLOAT_ENABLE_IF(!std::is_same<UC, char>::value)>
235 : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
236 : void loop_parse_if_eight_digits(const UC*& p, const UC* const pend, uint64_t& i) {
237 : if (!has_simd_opt<UC>()) {
238 : return;
239 : }
240 : while ((std::distance(p, pend) >= 8) && simd_parse_if_eight_digits_unrolled(p, i)) { // in rare cases, this will overflow, but that's ok
241 : p += 8;
242 : }
243 : }
244 :
245 : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
246 : void loop_parse_if_eight_digits(const char*& p, const char* const pend, uint64_t& i) {
247 : // optimizes better than parse_if_eight_digits_unrolled() for UC = char.
248 8021700 : while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(read8_to_u64(p))) {
249 1099890 : i = i * 100000000 + parse_eight_digits_unrolled(read8_to_u64(p)); // in rare cases, this will overflow, but that's ok
250 549944 : p += 8;
251 : }
252 6315050 : }
253 :
254 : template <typename UC>
255 : struct parsed_number_string_t {
256 : int64_t exponent{0};
257 : uint64_t mantissa{0};
258 : UC const * lastmatch{nullptr};
259 : bool negative{false};
260 : bool valid{false};
261 : bool too_many_digits{false};
262 : // contains the range of the significant digits
263 : span<const UC> integer{}; // non-nullable
264 : span<const UC> fraction{}; // nullable
265 : };
266 :
267 : using byte_span = span<const char>;
268 : using parsed_number_string = parsed_number_string_t<char>;
269 :
270 : // Assuming that you use no more than 19 digits, this will
271 : // parse an ASCII string.
272 : template <typename UC>
273 : fastfloat_really_inline FASTFLOAT_CONSTEXPR20
274 : parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, parse_options_t<UC> options) noexcept {
275 7423270 : chars_format const fmt = options.format;
276 7423270 : UC const decimal_point = options.decimal_point;
277 :
278 7423270 : parsed_number_string_t<UC> answer;
279 7423270 : answer.valid = false;
280 7423270 : answer.too_many_digits = false;
281 7423270 : answer.negative = (*p == UC('-'));
282 : #ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
283 : if ((*p == UC('-')) || (!(fmt & FASTFLOAT_JSONFMT) && *p == UC('+'))) {
284 : #else
285 7423270 : if (*p == UC('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
286 : #endif
287 2968940 : ++p;
288 2968940 : if (p == pend) {
289 232 : return answer;
290 : }
291 2968710 : if (fmt & FASTFLOAT_JSONFMT) {
292 0 : if (!is_integer(*p)) { // a sign must be followed by an integer
293 0 : return answer;
294 : }
295 : } else {
296 5937430 : if (!is_integer(*p) && (*p != decimal_point)) { // a sign must be followed by an integer or the dot
297 0 : return answer;
298 : }
299 : }
300 : }
301 7423040 : UC const * const start_digits = p;
302 :
303 7423040 : uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
304 :
305 57612800 : while ((p != pend) && is_integer(*p)) {
306 : // a multiplication by 10 is cheaper than an arbitrary integer
307 : // multiplication
308 21936800 : i = 10 * i +
309 21936800 : uint64_t(*p - UC('0')); // might overflow, we will handle the overflow later
310 21936800 : ++p;
311 : }
312 7423040 : UC const * const end_of_integer_part = p;
313 7423040 : int64_t digit_count = int64_t(end_of_integer_part - start_digits);
314 7423040 : answer.integer = span<const UC>(start_digits, size_t(digit_count));
315 7423040 : if (fmt & FASTFLOAT_JSONFMT) {
316 : // at least 1 digit in integer part, without leading zeros
317 0 : if (digit_count == 0 || (start_digits[0] == UC('0') && digit_count > 1)) {
318 0 : return answer;
319 : }
320 : }
321 :
322 7423040 : int64_t exponent = 0;
323 7423040 : const bool has_decimal_point = (p != pend) && (*p == decimal_point);
324 7423040 : if (has_decimal_point) {
325 6315050 : ++p;
326 6315050 : UC const * before = p;
327 : // can occur at most twice without overflowing, but let it occur more, since
328 : // for integers with many digits, digit parsing is the primary bottleneck.
329 : loop_parse_if_eight_digits(p, pend, i);
330 :
331 26137800 : while ((p != pend) && is_integer(*p)) {
332 9891440 : uint8_t digit = uint8_t(*p - UC('0'));
333 9891440 : ++p;
334 9891440 : i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
335 : }
336 6315050 : exponent = before - p;
337 6315050 : answer.fraction = span<const UC>(before, size_t(p - before));
338 6315050 : digit_count -= exponent;
339 : }
340 7423040 : if (fmt & FASTFLOAT_JSONFMT) {
341 : // at least 1 digit in fractional part
342 0 : if (has_decimal_point && exponent == 0) {
343 0 : return answer;
344 : }
345 : }
346 7423040 : else if (digit_count == 0) { // we must have encountered at least one integer!
347 387 : return answer;
348 : }
349 7422650 : int64_t exp_number = 0; // explicit exponential part
350 7422650 : if ( ((fmt & chars_format::scientific) &&
351 7422650 : (p != pend) &&
352 40711 : ((UC('e') == *p) || (UC('E') == *p)))
353 7382550 : ||
354 7382550 : ((fmt & FASTFLOAT_FORTRANFMT) &&
355 0 : (p != pend) &&
356 0 : ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || (UC('D') == *p)))) {
357 40103 : UC const * location_of_e = p;
358 40103 : if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) || (UC('D') == *p)) {
359 40103 : ++p;
360 : }
361 40103 : bool neg_exp = false;
362 40103 : if ((p != pend) && (UC('-') == *p)) {
363 8409 : neg_exp = true;
364 8409 : ++p;
365 31694 : } else if ((p != pend) && (UC('+') == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
366 31492 : ++p;
367 : }
368 80203 : if ((p == pend) || !is_integer(*p)) {
369 3 : if(!(fmt & chars_format::fixed)) {
370 : // We are in error.
371 0 : return answer;
372 : }
373 : // Otherwise, we will be ignoring the 'e'.
374 3 : p = location_of_e;
375 : } else {
376 189168 : while ((p != pend) && is_integer(*p)) {
377 74534 : uint8_t digit = uint8_t(*p - UC('0'));
378 74534 : if (exp_number < 0x10000000) {
379 74534 : exp_number = 10 * exp_number + digit;
380 : }
381 74534 : ++p;
382 : }
383 40100 : if(neg_exp) { exp_number = - exp_number; }
384 40100 : exponent += exp_number;
385 40103 : }
386 : } else {
387 : // If it scientific and not fixed, we have to bail out.
388 7382550 : if((fmt & chars_format::scientific) && !(fmt & chars_format::fixed)) { return answer; }
389 : }
390 7422650 : answer.lastmatch = p;
391 7422650 : answer.valid = true;
392 :
393 : // If we frequently had to deal with long strings of digits,
394 : // we could extend our code by using a 128-bit integer instead
395 : // of a 64-bit integer. However, this is uncommon.
396 : //
397 : // We can deal with up to 19 digits.
398 7422650 : if (digit_count > 19) { // this is uncommon
399 : // It is possible that the integer had an overflow.
400 : // We have to handle the case where we have 0.0000somenumber.
401 : // We need to be mindful of the case where we only have zeroes...
402 : // E.g., 0.000000000...000.
403 63420 : UC const * start = start_digits;
404 70193 : while ((start != pend) && (*start == UC('0') || *start == decimal_point)) {
405 6773 : if(*start == UC('0')) { digit_count --; }
406 6773 : start++;
407 : }
408 :
409 63420 : if (digit_count > 19) {
410 62516 : answer.too_many_digits = true;
411 : // Let us start again, this time, avoiding overflows.
412 : // We don't need to check if is_integer, since we use the
413 : // pre-tokenized spans from above.
414 62516 : i = 0;
415 62516 : p = answer.integer.ptr;
416 62516 : UC const* int_end = p + answer.integer.len();
417 62516 : const uint64_t minimal_nineteen_digit_integer{ 1000000000000000000 };
418 471114 : while ((i < minimal_nineteen_digit_integer) && (p != int_end)) {
419 408598 : i = i * 10 + uint64_t(*p - UC('0'));
420 408598 : ++p;
421 : }
422 62516 : if (i >= minimal_nineteen_digit_integer) { // We have a big integers
423 0 : exponent = end_of_integer_part - p + exp_number;
424 : }
425 : else { // We have a value with a fractional component.
426 62516 : p = answer.fraction.ptr;
427 62516 : UC const* frac_end = p + answer.fraction.len();
428 841724 : while ((i < minimal_nineteen_digit_integer) && (p != frac_end)) {
429 779208 : i = i * 10 + uint64_t(*p - UC('0'));
430 779208 : ++p;
431 : }
432 62516 : exponent = answer.fraction.ptr - p + exp_number;
433 : }
434 : // We have now corrected both exponent and i, to a truncated value
435 : }
436 : }
437 7422650 : answer.exponent = exponent;
438 7422650 : answer.mantissa = i;
439 7422650 : return answer;
440 : }
441 :
442 : } // namespace fast_float
443 :
444 : #endif
|