Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore zero-padding for non-finite floating points #2310

Merged
merged 5 commits into from
May 27, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -1584,13 +1584,17 @@ FMT_CONSTEXPR OutputIt write(OutputIt out, const Char* s,

template <typename Char, typename OutputIt>
OutputIt write_nonfinite(OutputIt out, bool isinf,
const basic_format_specs<Char>& specs,
basic_format_specs<Char> specs,
const float_specs& fspecs) {
auto str =
isinf ? (fspecs.upper ? "INF" : "inf") : (fspecs.upper ? "NAN" : "nan");
constexpr size_t str_size = 3;
auto sign = fspecs.sign;
auto size = str_size + (sign ? 1 : 0);
// replace '0'-padding with space for non-finite values
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: please make this a proper sentence:

// Replace '0'-padding with space for non-finite values.

const bool is_zero_fill =
specs.fill.size() == 1 && *specs.fill.data() == static_cast<Char>('0');
if (is_zero_fill) specs.fill[0] = static_cast<Char>(' ');
return write_padded(out, specs, size, [=](reserve_iterator<OutputIt> it) {
if (sign) *it++ = static_cast<Char>(data::signs[sign]);
return copy_str<Char>(str, str + str_size, it);
Expand Down
18 changes: 16 additions & 2 deletions test/format-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1272,9 +1272,16 @@ TEST(format_test, format_nan) {
double nan = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ("nan", fmt::format("{}", nan));
EXPECT_EQ("+nan", fmt::format("{:+}", nan));
if (std::signbit(-nan))
EXPECT_EQ(" +nan", fmt::format("{:+06}", nan));
// '0'-fill option sets alignment to numeric overwriting any user-provided
// alignment
EXPECT_EQ(" +nan", fmt::format("{:^+06}", nan));
EXPECT_EQ(" +nan", fmt::format("{:<+06}", nan));
EXPECT_EQ(" +nan", fmt::format("{:>+06}", nan));
if (std::signbit(-nan)) {
EXPECT_EQ("-nan", fmt::format("{}", -nan));
else
EXPECT_EQ(" -nan", fmt::format("{:+06}", -nan));
} else
fmt::print("Warning: compiler doesn't handle negative NaN correctly");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: please wrap the else statement in {} for consistency with if:

} else {
  fmt::print("Warning: compiler doesn't handle negative NaN correctly");
}

EXPECT_EQ(" nan", fmt::format("{: }", nan));
EXPECT_EQ("NAN", fmt::format("{:F}", nan));
Expand All @@ -1288,6 +1295,13 @@ TEST(format_test, format_infinity) {
EXPECT_EQ("inf", fmt::format("{}", inf));
EXPECT_EQ("+inf", fmt::format("{:+}", inf));
EXPECT_EQ("-inf", fmt::format("{}", -inf));
EXPECT_EQ(" +inf", fmt::format("{:+06}", inf));
EXPECT_EQ(" -inf", fmt::format("{:+06}", -inf));
// '0'-fill option sets alignment to numeric overwriting any user-provided
// alignment
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the desired behavior? Currently we lose the originally provided alignment because it seems to get replaced by align::numeric when using 0-padding.

Copy link
Contributor

@vitaut vitaut May 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we should preserve the original alignment. I think it can be dome by changing

specs_.align = align::numeric;

to something like

if (specs_.align == align::none) specs_.align = align::numeric; 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that works!

EXPECT_EQ(" +inf", fmt::format("{:^+06}", inf));
EXPECT_EQ(" +inf", fmt::format("{:<+06}", inf));
EXPECT_EQ(" +inf", fmt::format("{:>+06}", inf));
EXPECT_EQ(" inf", fmt::format("{: }", inf));
EXPECT_EQ("INF", fmt::format("{:F}", inf));
EXPECT_EQ("inf ", fmt::format("{:<7}", inf));
Expand Down