Skip to content

Commit e1bc8fc

Browse files
committed
* cleanup and slightly optimize slower path.
1 parent b69cd82 commit e1bc8fc

1 file changed

Lines changed: 23 additions & 26 deletions

File tree

include/fast_float/ascii_number.h

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ loop_parse_if_digits(char const *&p, char const *const pend, uint64_t &i) {
240240
while (std::distance(p, pend) >= sizeof(uint64_t)) {
241241
auto const val = read_chars_to_unsigned<uint64_t>(p);
242242
if (is_made_of_eight_digits_fast(val)) {
243-
i = i * 100000000/*10 ^ sizeof(uint64_t)*/ +
243+
i = i * 100000000 /*10 ^ sizeof(uint64_t)*/ +
244244
parse_eight_digits_unrolled(val); // may overflow, that's ok
245245
p += sizeof(uint64_t);
246246
} else {
@@ -253,7 +253,7 @@ loop_parse_if_digits(char const *&p, char const *const pend, uint64_t &i) {
253253
if (std::distance(p, pend) >= sizeof(uint32_t)) {
254254
auto const val = read_chars_to_unsigned<uint32_t>(p);
255255
if (is_made_of_four_digits_fast(val)) {
256-
i = i * 10000/*10 ^ sizeof(uint32_t)*/ +
256+
i = i * 10000 /*10 ^ sizeof(uint32_t)*/ +
257257
parse_four_digits_unrolled(val); // may overflow, that's ok
258258
p += sizeof(uint32_t);
259259
}
@@ -300,6 +300,7 @@ template <typename UC> struct parsed_number_string_t {
300300
using byte_span = span<char const>;
301301
using parsed_number_string = parsed_number_string_t<char>;
302302

303+
// Helper for error creating
303304
template <typename UC>
304305
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC>
305306
report_parse_error(parsed_number_string_t<UC> &answer, UC const *p,
@@ -325,29 +326,29 @@ parse_number_string(UC const *p, UC const *pend,
325326
parse_options_t<UC> const options,
326327
bool store_spans = true) noexcept {
327328
parsed_number_string_t<UC> answer{};
328-
// so dereference without checks
329-
FASTFLOAT_ASSUME(p < pend);
329+
FASTFLOAT_ASSUME(p < pend); // so dereference without checks
330330
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
331331
answer.negative = (*p == UC('-'));
332-
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
333332
if (answer.negative ||
333+
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
334334
((chars_format_t(options.format & chars_format::allow_leading_plus)) &&
335335
(!basic_json_fmt && *p == UC('+')))) {
336336
++p;
337337
if (p == pend) {
338338
return report_parse_error<UC>(
339339
answer, p, parse_error::missing_integer_or_dot_after_sign);
340340
}
341+
341342
FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
342-
// a sign must be followed by an integer
343343
if (!is_integer(*p)) {
344+
// a sign must be followed by an integer
344345
return report_parse_error<UC>(answer, p,
345346
parse_error::missing_integer_after_sign);
346347
}
347348
}
348349
else {
349-
// a sign must be followed by an integer or the dot
350350
if (!is_integer(*p) && (*p != options.decimal_point)) {
351+
// a sign must be followed by an integer or the dot
351352
return report_parse_error<UC>(
352353
answer, p, parse_error::missing_integer_or_dot_after_sign);
353354
}
@@ -359,7 +360,8 @@ parse_number_string(UC const *p, UC const *pend,
359360
// Straight-line unroll of the integer-part scan: most integer parts are
360361
// 1-5 digits, so peeling the first iterations eliminates the loop back-edge
361362
// for the common case. Semantics are identical to the original `while` loop:
362-
// i = 10*i + digit, advancing p.
363+
// i = 10*i + digit, advancing p: a multiplication by 10 is cheaper than an
364+
// arbitrary integer multiplication. might overflow, handled later
363365
if ((p != pend) && is_integer(*p)) {
364366
answer.mantissa = static_cast<fast_float::am_mant_t>(*p - UC('0'));
365367
++p;
@@ -384,12 +386,9 @@ parse_number_string(UC const *p, UC const *pend,
384386
static_cast<fast_float::am_mant_t>(*p - UC('0')));
385387
++p;
386388
while ((p != pend) && is_integer(*p)) {
387-
// a multiplication by 10 is cheaper than an arbitrary integer
388-
// multiplication
389389
answer.mantissa = static_cast<fast_float::am_mant_t>(
390390
answer.mantissa * 10 +
391-
static_cast<fast_float::am_mant_t>(
392-
*p - UC('0'))); // might overflow, handled later
391+
static_cast<fast_float::am_mant_t>(*p - UC('0')));
393392
++p;
394393
}
395394
}
@@ -426,11 +425,10 @@ parse_number_string(UC const *p, UC const *pend,
426425
loop_parse_if_digits(p, pend, answer.mantissa);
427426

428427
while ((p != pend) && is_integer(*p)) {
429-
auto const digit = uint8_t(*p - UC('0'));
430-
++p;
431428
answer.mantissa = static_cast<fast_float::am_mant_t>(
432429
answer.mantissa * 10 +
433-
digit); // in rare cases, this will overflow, but that's ok
430+
static_cast<fast_float::am_mant_t>(*p - UC('0')));
431+
++p;
434432
}
435433
answer.exponent = static_cast<am_pow_t>(before - p);
436434
if fastfloat_unlikely (store_spans) {
@@ -532,19 +530,19 @@ parse_number_string(UC const *p, UC const *pend,
532530
// of a 64-bit integer. However, this is uncommon.
533531
//
534532
// We can deal with up to 19 digits.
535-
if fastfloat_unlikely (digit_count > 19) { // this is uncommon
533+
if fastfloat_unlikely (digit_count > 19) {
536534
// It is possible that the integer had an overflow.
537535
// We have to handle the case where we have 0.0000somenumber.
538536
// We need to be mindful of the case where we only have zeroes...
539537
// E.g., 0.000000000...000.
540538
auto const *start = start_digits;
541-
while ((start != pend) &&
542-
(*start == UC('0') || *start == options.decimal_point)) {
539+
do {
543540
if (*start == UC('0')) {
544541
--digit_count;
542+
} else if (*start != options.decimal_point) {
543+
break;
545544
}
546-
++start;
547-
}
545+
} while (++start != pend);
548546

549547
// We have to check if number has more than 19 significant digits.
550548
if (digit_count > 19) {
@@ -553,20 +551,19 @@ parse_number_string(UC const *p, UC const *pend,
553551
// store_spans is false we didn't materialize them, so just flag
554552
// too_many_digits; the caller re-parses with store_spans=true to obtain
555553
// the corrected mantissa/exponent before taking the slow path.
556-
if fastfloat_unlikely (store_spans) {
554+
if (store_spans) {
557555
// Let us start again, this time, avoiding overflows.
558556
// We don't need to call if is_integer, since we use the
559557
// pre-tokenized spans from above.
560558
answer.mantissa = 0;
561559
p = answer.integer.ptr;
562560
UC const *int_end = p + answer.integer.len();
563561
constexpr am_mant_t minimal_nineteen_digit_integer{1000000000000000000};
564-
while ((p != int_end) &&
565-
(answer.mantissa < minimal_nineteen_digit_integer)) {
562+
do {
566563
answer.mantissa =
567564
answer.mantissa * 10 + static_cast<am_mant_t>(*p - UC('0'));
568-
++p;
569-
}
565+
} while ((++p != int_end) &&
566+
(answer.mantissa < minimal_nineteen_digit_integer));
570567
if (answer.mantissa >= minimal_nineteen_digit_integer) {
571568
// We have a big integers, so skip the fraction part completely.
572569
answer.exponent = am_pow_t(end_of_integer_part - p) + exp_number;
@@ -797,7 +794,7 @@ parse_int_string(UC const *p, UC const *pend, T &value,
797794
// and a single threshold separates wrapped from non-wrapped values. A
798795
// leading digit above dmax always overflows; below dmax always fits.
799796
uint64_t const ms = min_safe_u64(options.base);
800-
uint64_t const dmax = (std::numeric_limits<uint64_t>::max)() / ms;
797+
uint64_t const dmax = std::numeric_limits<uint64_t>::max() / ms;
801798
uint64_t const lead = ch_to_digit(*start_digits);
802799
if (lead > dmax || (lead == dmax && i < dmax * ms)) {
803800
answer.ec = std::errc::result_out_of_range;

0 commit comments

Comments
 (0)