From 3e1f70fe02b29daa79860248b029e19c46a45e2f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 20 Nov 2019 12:20:17 -0800 Subject: [PATCH] Merge write_fp into write --- include/fmt/format-inl.h | 2 +- include/fmt/format.h | 173 +++++++++++++++++---------------------- include/fmt/printf.h | 2 +- test/locale-test.cc | 7 -- 4 files changed, 75 insertions(+), 109 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 53559ee1..e662d0e3 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -1,4 +1,4 @@ -// Formatting library for C++ +// Formatting library for C++ - implementation // // Copyright (c) 2012 - 2016, Victor Zverovich // All rights reserved. diff --git a/include/fmt/format.h b/include/fmt/format.h index 152deee6..3d90387e 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1690,7 +1690,6 @@ template class basic_writer { }; public: - /** Constructs a ``basic_writer`` object. */ explicit basic_writer(Range out, internal::locale_ref loc = internal::locale_ref()) : out_(out.begin()), locale_(loc) {} @@ -1743,29 +1742,79 @@ template class basic_writer { int_writer(*this, value, spec)); } - void write(float value, const format_specs& specs = format_specs()) { - write_fp(value, specs); + template ::value)> + void write(T value, const format_specs& specs = {}) { + auto sign = specs.sign; + if (std::signbit(value)) { // value < 0 is false for NaN so use signbit. + sign = sign::minus; + value = -value; + } else if (sign == sign::minus) { + sign = sign::none; + } + + float_spec fspec = parse_float_type_spec(specs.type); + if (!std::isfinite(value)) { + const char* str = std::isinf(value) ? (fspec.upper ? "INF" : "inf") + : (fspec.upper ? "NAN" : "nan"); + return write_padded(specs, inf_or_nan_writer{sign, fspec.percent, str}); + } + + if (fspec.percent) value *= 100; + + memory_buffer buffer; + int exp = 0; + int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6; + int num_digits = + fspec.format == float_format::exp ? precision + 1 : precision; + unsigned options = 0; + if (fspec.format == float_format::fixed) options |= grisu_options::fixed; + if (const_check(sizeof(value) == sizeof(float))) + options |= grisu_options::binary32; + bool use_grisu = internal::use_grisu() && + (specs.type != 'a' && specs.type != 'A') && + grisu_format(static_cast(value), buffer, + num_digits, options, exp); + char* decimal_point_pos = nullptr; + if (!use_grisu) decimal_point_pos = sprintf_format(value, buffer, specs); + + if (fspec.percent) { + buffer.push_back('%'); + --exp; // Adjust decimal place position. + } + format_specs as = specs; + if (specs.align == align::numeric) { + if (sign) { + auto&& it = reserve(1); + *it++ = static_cast(data::signs[sign]); + sign = sign::none; + if (as.width) --as.width; + } + as.align = align::right; + } else if (specs.align == align::none) { + as.align = align::right; + } + char_type point = fspec.locale ? decimal_point(locale_) + : static_cast('.'); + if (use_grisu) { + auto params = gen_digits_params(); + params.sign = sign; + params.format = fspec.format; + params.num_digits = num_digits; + params.trailing_zeros = + (precision != 0 && + (!specs.type || fspec.format == float_format::fixed || + fspec.format == float_format::exp)) || + specs.alt; + params.upper = fspec.upper; + num_digits = static_cast(buffer.size()); + write_padded(as, grisu_writer(buffer.data(), num_digits, exp, + params, point)); + } else { + write_padded(as, double_writer{sign, buffer, decimal_point_pos, point}); + } } - void write(double value, const format_specs& specs = format_specs()) { - write_fp(value, specs); - } - - /** - \rst - Formats *value* using the general format for floating-point numbers - (``'g'``) and writes it to the buffer. - \endrst - */ - void write(long double value, const format_specs& specs = format_specs()) { - write_fp(value, specs); - } - - // Formats a floating-point number (float, double, or long double). - template ()> - void write_fp(T value, const format_specs& specs); - - /** Writes a character to the buffer. */ + // Writes a character to the buffer. void write(char value) { auto&& it = reserve(1); *it++ = value; @@ -1777,11 +1826,7 @@ template class basic_writer { *it++ = value; } - /** - \rst - Writes *value* to the buffer. - \endrst - */ + // Writes value to the buffer. void write(string_view value) { auto&& it = reserve(value.size()); it = internal::copy_str(value.begin(), value.end(), it); @@ -1820,78 +1865,6 @@ template class basic_writer { } }; -template -template -void basic_writer::write_fp(T value, const format_specs& specs) { - auto sign = specs.sign; - if (std::signbit(value)) { // value < 0 is false for NaN so use signbit. - sign = sign::minus; - value = -value; - } else if (sign == sign::minus) { - sign = sign::none; - } - - float_spec fspec = parse_float_type_spec(specs.type); - if (!std::isfinite(value)) { - const char* str = std::isinf(value) ? (fspec.upper ? "INF" : "inf") - : (fspec.upper ? "NAN" : "nan"); - return write_padded(specs, inf_or_nan_writer{sign, fspec.percent, str}); - } - - if (fspec.percent) value *= 100; - - memory_buffer buffer; - int exp = 0; - int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6; - int num_digits = - fspec.format == float_format::exp ? precision + 1 : precision; - unsigned options = 0; - if (fspec.format == float_format::fixed) options |= grisu_options::fixed; - if (const_check(sizeof(value) == sizeof(float))) - options |= grisu_options::binary32; - bool use_grisu = USE_GRISU && (specs.type != 'a' && specs.type != 'A') && - grisu_format(static_cast(value), buffer, num_digits, - options, exp); - char* decimal_point_pos = nullptr; - if (!use_grisu) decimal_point_pos = sprintf_format(value, buffer, specs); - - if (fspec.percent) { - buffer.push_back('%'); - --exp; // Adjust decimal place position. - } - format_specs as = specs; - if (specs.align == align::numeric) { - if (sign) { - auto&& it = reserve(1); - *it++ = static_cast(data::signs[sign]); - sign = sign::none; - if (as.width) --as.width; - } - as.align = align::right; - } else if (specs.align == align::none) { - as.align = align::right; - } - char_type point = fspec.locale ? decimal_point(locale_) - : static_cast('.'); - if (use_grisu) { - auto params = gen_digits_params(); - params.sign = sign; - params.format = fspec.format; - params.num_digits = num_digits; - params.trailing_zeros = - (precision != 0 && - (!specs.type || fspec.format == float_format::fixed || - fspec.format == float_format::exp)) || - specs.alt; - params.upper = fspec.upper; - num_digits = static_cast(buffer.size()); - write_padded(as, grisu_writer(buffer.data(), num_digits, exp, - params, point)); - } else { - write_padded(as, double_writer{sign, buffer, decimal_point_pos, point}); - } -} - using writer = basic_writer>; template struct is_integral : std::is_integral {}; @@ -1983,7 +1956,7 @@ class arg_formatter_base { template ::value)> iterator operator()(T value) { - writer_.write_fp(value, specs_ ? *specs_ : format_specs()); + writer_.write(value, specs_ ? *specs_ : format_specs()); return out(); } diff --git a/include/fmt/printf.h b/include/fmt/printf.h index 17a20afb..cdbb65e6 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -1,4 +1,4 @@ -// Formatting library for C++ +// Formatting library for C++ - legacy printf implementation // // Copyright (c) 2012 - 2016, Victor Zverovich // All rights reserved. diff --git a/test/locale-test.cc b/test/locale-test.cc index d1922328..a064ecda 100644 --- a/test/locale-test.cc +++ b/test/locale-test.cc @@ -42,13 +42,6 @@ template struct small_grouping : std::numpunct { TEST(LocaleTest, DoubleDecimalPoint) { std::locale loc(std::locale(), new numpunct()); EXPECT_EQ("1?23", fmt::format(loc, "{:n}", 1.23)); - // Test with Grisu disabled. - fmt::memory_buffer buf; - fmt::internal::writer w(buf, fmt::internal::locale_ref(loc)); - auto specs = fmt::format_specs(); - specs.type = 'n'; - w.write_fp(1.23, specs); - EXPECT_EQ(fmt::to_string(buf), "1?23"); } TEST(LocaleTest, Format) {