From add164f6b3f5deb800443b87ba812fb19ad7cd5b Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 3 Aug 2025 10:13:13 -0700 Subject: [PATCH] Optimize the default FP formatting --- include/fmt/format.h | 58 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index f1fb2ccd..25153a4d 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -519,6 +519,11 @@ template constexpr auto to_pointer(OutputIt, size_t) -> T* { return nullptr; } +template FMT_CONSTEXPR auto to_pointer(T*& ptr, size_t n) -> T* { + T* begin = ptr; + ptr += n; + return begin; +} template FMT_CONSTEXPR20 auto to_pointer(basic_appender it, size_t n) -> T* { buffer& buf = get_container(it); @@ -1615,6 +1620,15 @@ constexpr auto convert_float(T value) -> convert_float_result { return static_cast>(value); } +template +auto select(T true_value, F) -> T { + return true_value; +} +template +auto select(T, F false_value) -> F { + return false_value; +} + template FMT_CONSTEXPR FMT_NOINLINE auto fill(OutputIt it, size_t n, const basic_specs& specs) -> OutputIt { @@ -3455,25 +3469,53 @@ FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { return write_nonfinite(out, std::isnan(value), {}, s); auto dec = dragonbox::to_decimal(static_cast>(value)); - int significand_size = count_digits(dec.significand); - int exp = dec.exponent + significand_size - 1; - if (use_fixed(exp, detail::exp_upper())) { + auto significand = dec.significand; + int significand_size = count_digits(significand); + int exponent = dec.exponent + significand_size - 1; + if (use_fixed(exponent, detail::exp_upper())) { return write_fixed>( out, dec, significand_size, Char('.'), {}, s); } // Write value in the exponential format. + const char* prefix = "e+"; + int abs_exponent = exponent; + if (exponent < 0) { + abs_exponent = -exponent; + prefix = "e-"; + } auto has_decimal_point = significand_size != 1; - size_t size = - to_unsigned((s != sign::none ? 1 : 0) + significand_size + - (has_decimal_point ? 1 : 0) + compute_exp_size(exp)); + size_t size = std::is_pointer::value + ? 0u + : to_unsigned((s != sign::none ? 1 : 0) + significand_size + + (has_decimal_point ? 1 : 0) + + (abs_exponent >= 100 ? 5 : 4)); + if (auto ptr = to_pointer(out, size)) { + if (s != sign::none) *ptr++ = Char('-'); + if (has_decimal_point) { + auto begin = ptr; + ptr = format_decimal(ptr, significand, significand_size + 1); + *begin = begin[1]; + begin[1] = '.'; + } else { + *ptr++ = static_cast('0' + significand); + } + memcpy(ptr, prefix, 2); + ptr += 2; + if (abs_exponent >= 100) { + *ptr++ = static_cast('0' + abs_exponent / 100); + abs_exponent %= 100; + } + write2digits(ptr, static_cast(abs_exponent)); + return select::value>(ptr + 2, out); + } auto it = reserve(out, size); if (s != sign::none) *it++ = Char('-'); // Insert a decimal point after the first digit and add an exponent. - it = write_significand(it, dec.significand, significand_size, 1, + it = write_significand(it, significand, significand_size, 1, has_decimal_point ? Char('.') : Char()); *it++ = Char('e'); - it = write_exponent(exp, it); + it = write_exponent(exponent, it); return base_iterator(out, it); }