From 73f31a8bcc6b41dda70156ce3d8987f6f639b55c Mon Sep 17 00:00:00 2001 From: gawain Date: Sun, 3 Mar 2019 20:47:37 +0100 Subject: [PATCH] Updates for formatting output as a percentage. * Added percentage sign if needed when dumping nan and infinity. * Added unit tests. * Used clang-format for changed source files. --- include/fmt/format-inl.h | 7 +++---- include/fmt/format.h | 30 +++++++++++++++++++----------- test/format-test.cc | 9 +++++++++ 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 7ca73d12..61e4790a 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -539,8 +539,7 @@ struct fixed_stop { void on_exp(int exp) { if (!fixed) return; exp += exp10; - if (exp >= 0) - precision += exp; + if (exp >= 0) precision += exp; } bool operator()(char*, int& size, uint64_t remainder, uint64_t divisor, @@ -660,9 +659,9 @@ void sprintf_format(Double value, internal::buffer& buf, char type = spec.type; if (type == '%') { - type = 'f'; + type = 'f'; } else if (type == 0) { - type = 'g'; + type = 'g'; } #if FMT_MSC_VER if (type == 'F') { diff --git a/include/fmt/format.h b/include/fmt/format.h index c4e5958d..3b9f097d 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -2646,10 +2646,12 @@ template class basic_writer { struct inf_or_nan_writer { char sign; + bool as_percentage; const char* str; size_t size() const { - return static_cast(INF_SIZE + (sign ? 1 : 0)); + return static_cast(INF_SIZE + (sign ? 1 : 0) + + (as_percentage ? 1 : 0)); } size_t width() const { return size(); } @@ -2657,6 +2659,7 @@ template class basic_writer { if (sign) *it++ = static_cast(sign); it = internal::copy_str( str, str + static_cast(INF_SIZE), it); + if (as_percentage) *it++ = static_cast('%'); } }; @@ -2832,8 +2835,8 @@ struct float_spec_handler { } void on_percent() { - fixed = true; - as_percentage = true; + fixed = true; + as_percentage = true; } void on_hex() { @@ -2864,17 +2867,22 @@ void basic_writer::write_double(T value, const format_specs& spec) { basic_writer& writer; format_specs spec; char sign; + bool as_percentage; void operator()(const char* str) const { - writer.write_padded(spec, inf_or_nan_writer{sign, str}); + writer.write_padded(spec, inf_or_nan_writer{sign, as_percentage, str}); } - } write_inf_or_nan = {*this, spec, sign}; + } write_inf_or_nan = {*this, spec, sign, handler.as_percentage}; // Format NaN and ininity ourselves because sprintf's output is not consistent // across platforms. - if (internal::fputil::isnotanumber(value)) - return write_inf_or_nan(handler.upper ? "NAN" : "nan"); - if (internal::fputil::isinfinity(value)) - return write_inf_or_nan(handler.upper ? "INF" : "inf"); + if (internal::fputil::isnotanumber(value)) { + write_inf_or_nan(handler.upper ? "NAN" : "nan"); + return; + } + if (internal::fputil::isinfinity(value)) { + write_inf_or_nan(handler.upper ? "INF" : "inf"); + return; + } memory_buffer buffer; int exp = 0; @@ -2889,8 +2897,8 @@ void basic_writer::write_double(T value, const format_specs& spec) { if (!use_grisu) internal::sprintf_format(value, buffer, spec); if (handler.as_percentage) { - buffer.push_back('%'); - --exp; // Adjust decimal place position. + buffer.push_back('%'); + --exp; // Adjust decimal place position. } align_spec as = spec; if (spec.align() == ALIGN_NUMERIC) { diff --git a/test/format-test.cc b/test/format-test.cc index 45c3432e..51ce763b 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1207,6 +1207,8 @@ TEST(FormatterTest, Precision) { "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:.2f}", 42ull), format_error, "precision not allowed for this argument type"); + EXPECT_THROW_MSG(format("{0:.2%}", 42), format_error, + "precision not allowed for this argument type"); EXPECT_THROW_MSG(format("{0:3.0}", 'x'), format_error, "precision not allowed for this argument type"); EXPECT_EQ("1.2", format("{0:.2}", 1.2345)); @@ -1440,6 +1442,7 @@ TEST(FormatterTest, FormatConvertibleToLongLong) { TEST(FormatterTest, FormatFloat) { EXPECT_EQ("392.500000", format("{0:f}", 392.5f)); + EXPECT_EQ("12.500000%", format("{0:%}", 0.125f)); } TEST(FormatterTest, FormatDouble) { @@ -1452,6 +1455,8 @@ TEST(FormatterTest, FormatDouble) { EXPECT_EQ("392.65", format("{:G}", 392.65)); EXPECT_EQ("392.650000", format("{:f}", 392.65)); EXPECT_EQ("392.650000", format("{:F}", 392.65)); + EXPECT_EQ("12.500000%", format("{:%}", 0.125)); + EXPECT_EQ("12.34%", format("{:.2%}", 0.1234432)); char buffer[BUFFER_SIZE]; safe_sprintf(buffer, "%e", 392.65); EXPECT_EQ(buffer, format("{0:e}", 392.65)); @@ -1473,6 +1478,7 @@ TEST(FormatterTest, FormatNaN) { EXPECT_EQ("nan ", format("{:<7}", nan)); EXPECT_EQ(" nan ", format("{:^7}", nan)); EXPECT_EQ(" nan", format("{:>7}", nan)); + EXPECT_EQ("nan%", format("{:%}", nan)); } TEST(FormatterTest, FormatInfinity) { @@ -1485,6 +1491,7 @@ TEST(FormatterTest, FormatInfinity) { EXPECT_EQ("inf ", format("{:<7}", inf)); EXPECT_EQ(" inf ", format("{:^7}", inf)); EXPECT_EQ(" inf", format("{:>7}", inf)); + EXPECT_EQ("inf%", format("{:%}", inf)); } TEST(FormatterTest, FormatLongDouble) { @@ -1495,6 +1502,8 @@ TEST(FormatterTest, FormatLongDouble) { EXPECT_EQ("392.65", format("{0:G}", 392.65l)); EXPECT_EQ("392.650000", format("{0:f}", 392.65l)); EXPECT_EQ("392.650000", format("{0:F}", 392.65l)); + EXPECT_EQ("12.500000%", format("{:%}", 0.125l)); + EXPECT_EQ("12.34%", format("{:.2%}", 0.1234432l)); char buffer[BUFFER_SIZE]; safe_sprintf(buffer, "%Le", 392.65l); EXPECT_EQ(buffer, format("{0:e}", 392.65l));