From bda5f9a55685f4156759a4c2abe3e4502aec4117 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 17 Oct 2018 08:55:45 -0700 Subject: [PATCH] Replace grisu2_specs with core_format_specs --- include/fmt/format-inl.h | 13 +++++---- include/fmt/format.h | 60 +++++++++++++++++----------------------- test/format-impl-test.cc | 2 +- 3 files changed, 34 insertions(+), 41 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 1257f2b0..784b417d 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -568,18 +568,18 @@ struct gen_digits_params { // Creates digit generation parameters from format specifiers for a number in // the range [pow(10, exp - 1), pow(10, exp) or 0 if exp == 1. - gen_digits_params(const grisu2_specs &specs, int exp) - : min_digits(specs.precision >= 0 ? to_unsigned(specs.precision) : 6), + gen_digits_params(const core_format_specs &specs, int exp) + : min_digits(specs.precision_ >= 0 ? to_unsigned(specs.precision_) : 6), fixed(false), upper(false), trailing_zeros(false) { - switch (specs.type) { + switch (specs.type_) { case 'G': upper = true; FMT_FALLTHROUGH case '\0': case 'g': - trailing_zeros = (specs.flags & HASH_FLAG) != 0; + trailing_zeros = (specs.flags_ & HASH_FLAG) != 0; if (-4 <= exp && exp < static_cast(min_digits) + 1) { fixed = true; - if (!specs.type && trailing_zeros && exp >= 0) + if (!specs.type_ && trailing_zeros && exp >= 0) min_digits = to_unsigned(exp) + 1; } break; @@ -667,7 +667,7 @@ FMT_FUNC void format_float(char *buffer, size_t &size, int exp, template FMT_FUNC typename std::enable_if::type - grisu2_format(Double value, buffer &buf, grisu2_specs specs) { + grisu2_format(Double value, buffer &buf, core_format_specs specs) { FMT_ASSERT(value >= 0, "value is negative"); char *buffer = buf.data(); if (value == 0) { @@ -710,6 +710,7 @@ FMT_FUNC typename std::enable_if::type size_t size = 0; if (!grisu2_gen_digits(buffer, size, hi, lo, exp, delta, one, diff, params.max_digits)) { + buf.clear(); return false; } format_float(buffer, size, cached_exp + exp, params); diff --git a/include/fmt/format.h b/include/fmt/format.h index fcdf837e..91350f3f 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -285,25 +285,6 @@ inline dummy_int _finite(...) { return dummy_int(); } inline dummy_int isnan(...) { return dummy_int(); } inline dummy_int _isnan(...) { return dummy_int(); } -inline bool use_grisu() { - return FMT_USE_GRISU && std::numeric_limits::is_iec559; -} - -struct grisu2_specs { - int precision; - char type; - uint_least8_t flags; -}; - -// Formats value using Grisu2 algorithm: -// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf -template -FMT_API typename std::enable_if::type - grisu2_format(Double value, buffer &buf, grisu2_specs); -template -inline typename std::enable_if::type - grisu2_format(Double, buffer &, grisu2_specs) { return false; } - template typename Allocator::value_type *allocate(Allocator& alloc, std::size_t n) { #if __cplusplus >= 201103L || FMT_MSC_VER >= 1700 @@ -1174,17 +1155,23 @@ struct align_spec { int precision() const { return -1; } }; -// Format specifiers. -template -class basic_format_specs : public align_spec { - public: +struct core_format_specs { int precision_; uint_least8_t flags_; char type_; +}; +// Format specifiers. +template +class basic_format_specs : public align_spec, public core_format_specs { + public: FMT_CONSTEXPR basic_format_specs( unsigned width = 0, char type = 0, wchar_t fill = ' ') - : align_spec(width, fill), precision_(-1), flags_(0), type_(type) {} + : align_spec(width, fill) { + precision_ = -1; + flags_ = 0; + type_ = type; + } FMT_CONSTEXPR bool flag(unsigned f) const { return (flags_ & f) != 0; } FMT_CONSTEXPR int precision() const { return precision_; } @@ -1203,6 +1190,19 @@ FMT_CONSTEXPR unsigned basic_parse_context::next_arg_id() { namespace internal { +inline bool use_grisu() { + return FMT_USE_GRISU && std::numeric_limits::is_iec559; +} + +// Formats value using Grisu2 algorithm: +// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf +template +FMT_API typename std::enable_if::type + grisu2_format(Double value, buffer &buf, core_format_specs); +template +inline typename std::enable_if::type + grisu2_format(Double, buffer &, core_format_specs) { return false; } + template struct format_string_traits< S, typename std::enable_if::value>::type>: @@ -2855,20 +2855,12 @@ void basic_writer::write_double(T value, const format_specs &spec) { return write_inf_or_nan(handler.upper ? "INF" : "inf"); memory_buffer buffer; - char type = static_cast(spec.type()); bool use_grisu = internal::use_grisu() && sizeof(T) <= sizeof(double) && - type != 'a' && type != 'A'; - if (use_grisu) { - auto gs = internal::grisu2_specs(); - gs.type = type; - gs.precision = spec.precision(); - gs.flags = spec.flags_; - use_grisu = internal::grisu2_format(static_cast(value), buffer, gs); - } + spec.type() != 'a' && spec.type() != 'A' && + internal::grisu2_format(static_cast(value), buffer, spec); if (!use_grisu) { format_specs normalized_spec(spec); normalized_spec.type_ = handler.type; - buffer.clear(); write_double_sprintf(value, normalized_spec, buffer); } size_t n = buffer.size(); diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index c66a587a..b20d0e19 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -105,7 +105,7 @@ TEST(FPTest, GetCachedPower) { TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) { size_t size = 0; fmt::memory_buffer buf; - grisu2_format(4.2f, buf, fmt::internal::grisu2_specs()); + grisu2_format(4.2f, buf, fmt::core_format_specs()); } template