@@ -32,7 +32,7 @@ template <typename UC> fastfloat_really_inline constexpr bool has_simd_opt() {
32
32
// able to optimize it well.
33
33
template <typename UC>
34
34
fastfloat_really_inline constexpr bool is_integer (UC c) noexcept {
35
- return ! (c > UC ( ' 9 ' ) || c < UC ( ' 0 ' )) ;
35
+ return static_cast < uint8_t > (c - ' 0 ' ) < 10 ;
36
36
}
37
37
38
38
fastfloat_really_inline constexpr uint64_t byteswap (uint64_t val) {
@@ -232,6 +232,39 @@ loop_parse_if_eight_digits(char const *&p, char const *const pend,
232
232
}
233
233
}
234
234
235
+ // credit @realtimechris
236
+ fastfloat_really_inline constexpr bool
237
+ parse_if_eight_digits_unrolled (const char *&string, size_t &value) {
238
+ constexpr size_t byte_mask = ~size_t (0 ) / 255ull ;
239
+ constexpr size_t msb_mask = byte_mask * 128ull ;
240
+ constexpr size_t threshold_byte_mask = byte_mask * (127ull - 9ull );
241
+ constexpr size_t mask = 0x000000FF000000FFull ;
242
+ constexpr size_t mul1 = 0x000F424000000064ull ;
243
+ constexpr size_t mul2 = 0x0000271000000001ull ;
244
+ size_t value_new = read8_to_u64 (string) - 0x3030303030303030 ;
245
+ if (!(((value_new + threshold_byte_mask) | value_new) & msb_mask)) {
246
+ value_new = (value_new * 10 ) + (value_new >> 8 );
247
+ value =
248
+ value * 100000000 +
249
+ ((((value_new & mask) * mul1) + (((value_new >> 16 ) & mask) * mul2)) >>
250
+ 32 );
251
+ string += 8 ;
252
+ return true ;
253
+ }
254
+ return false ;
255
+ }
256
+
257
+ fastfloat_really_inline constexpr void
258
+ loop_parse_if_digits (const char *&p, const char *const pend,
259
+ size_t &i) noexcept {
260
+ while (pend - p >= 8 && parse_if_eight_digits_unrolled (p, i)) {
261
+ }
262
+ while (p < pend && is_integer (*p)) {
263
+ i = i * 10 + static_cast <uint8_t >(*p - ' 0' );
264
+ ++p;
265
+ }
266
+ }
267
+
235
268
enum class parse_error {
236
269
no_error,
237
270
// [JSON-only] The minus sign must be followed by an integer.
@@ -347,13 +380,7 @@ parse_number_string(UC const *p, UC const *pend,
347
380
UC const *before = p;
348
381
// can occur at most twice without overflowing, but let it occur more, since
349
382
// for integers with many digits, digit parsing is the primary bottleneck.
350
- loop_parse_if_eight_digits (p, pend, i);
351
-
352
- while ((p != pend) && is_integer (*p)) {
353
- uint8_t digit = uint8_t (*p - UC (' 0' ));
354
- ++p;
355
- i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
356
- }
383
+ loop_parse_if_digits (p, pend, i);
357
384
exponent = before - p;
358
385
answer.fraction = span<UC const >(before, size_t (p - before));
359
386
digit_count -= exponent;
0 commit comments