@@ -32,7 +32,7 @@ template <typename UC> fastfloat_really_inline constexpr bool has_simd_opt() {
3232// able to optimize it well.
3333template <typename UC>
3434fastfloat_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 ;
3636}
3737
3838fastfloat_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,
232232 }
233233}
234234
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+
235268enum class parse_error {
236269 no_error,
237270 // [JSON-only] The minus sign must be followed by an integer.
@@ -347,13 +380,7 @@ parse_number_string(UC const *p, UC const *pend,
347380 UC const *before = p;
348381 // can occur at most twice without overflowing, but let it occur more, since
349382 // 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);
357384 exponent = before - p;
358385 answer.fraction = span<UC const >(before, size_t (p - before));
359386 digit_count -= exponent;
0 commit comments