accept(): skip digits without computing their value

accept() needs the value of a number only for a float whose exponent may
reach the largest value. skip_digits() finds the end of the digits without
the multiply-adds of accumulate_digits(), and once an 8-byte word fails the
digit test, the remaining loop needs no bounds check: a non-digit is in
that word. The value is computed afterwards for the rare floats that need
it.

accept() of canada.json: -16 % on Apple M1, -22 % with GCC 15 and -21 %
with Clang 21 on x86-64; files with many numbers -9 to -15 %.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-11-06 12:16:38 +01:00
1 parent 2eb9aae537
commit 788b12213b
4 files changed
+103 -4

No files matched your search

@@ -646,7 +646,9 @@ done:
}
else if (i < avail && data[i] >= '1' && data[i] <= '9')
{
i = accumulate_digits(data, i, avail, w);
// accept() needs the value only for a float with a large exponent,
// which computes it below; its handler ignores the values
i = keep_values() ? accumulate_digits(data, i, avail, w) : skip_digits(data, i, avail);
}
else
{
@@ -664,7 +666,7 @@ done:
return false;
}
const std::size_t fraction_begin = i;
i = accumulate_digits(data, i, avail, w);
i = keep_values() ? accumulate_digits(data, i, avail, w) : skip_digits(data, i, avail);
fraction_digits = i - fraction_begin;
digit_count += fraction_digits;
}
@@ -753,6 +755,16 @@ done:
{
return report(sax->number_float(value, number_text(data, data + i)));
}
if (!keep_values())
{
// the digits were skipped: their value now
s.w = 0;
const std::size_t integer_end = accumulate_digits(data, integer_begin, avail, s.w);
if (dot_index != std::string::npos)
{
static_cast<void>(accumulate_digits(data, integer_end + 1, avail, s.w));
}
}
value = decimal_to_float<number_float_t>(s);
}
else