mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-31 11:17:35 +02:00
Format NaN.
This commit is contained in:
30
format.cc
30
format.cc
@@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@@ -280,17 +281,21 @@ template <typename T>
|
|||||||
void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
|
void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
|
||||||
// Check type.
|
// Check type.
|
||||||
char type = spec.type;
|
char type = spec.type;
|
||||||
|
bool upper = false;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0:
|
case 0:
|
||||||
type = 'g';
|
type = 'g';
|
||||||
break;
|
break;
|
||||||
case 'e': case 'E': case 'f': case 'g': case 'G':
|
case 'e': case 'f': case 'g':
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
// MSVC's printf doesn't support 'F'.
|
// MSVC's printf doesn't support 'F'.
|
||||||
type = 'f';
|
type = 'f';
|
||||||
#endif
|
#endif
|
||||||
|
// Fall through.
|
||||||
|
case 'E': case 'G':
|
||||||
|
upper = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ReportUnknownType(type, "double");
|
ReportUnknownType(type, "double");
|
||||||
@@ -298,12 +303,30 @@ void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char sign = 0;
|
char sign = 0;
|
||||||
if (value < 0) {
|
// Use signbit instead of value < 0 because the latter is always
|
||||||
|
// false for NaN.
|
||||||
|
if (signbit(value)) {
|
||||||
sign = '-';
|
sign = '-';
|
||||||
value = -value;
|
value = -value;
|
||||||
} else if ((spec.flags & SIGN_FLAG) != 0) {
|
} else if ((spec.flags & SIGN_FLAG) != 0) {
|
||||||
sign = (spec.flags & PLUS_FLAG) != 0 ? '+' : ' ';
|
sign = (spec.flags & PLUS_FLAG) != 0 ? '+' : ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isnan(value)) {
|
||||||
|
// Format NaN ourselves because sprintf's output is not consistent
|
||||||
|
// across platforms.
|
||||||
|
std::size_t size = 4;
|
||||||
|
const char *nan = upper ? " NAN" : " nan";
|
||||||
|
if (!sign) {
|
||||||
|
--size;
|
||||||
|
++nan;
|
||||||
|
}
|
||||||
|
char *out = FormatString(nan, size, spec);
|
||||||
|
if (sign)
|
||||||
|
*out = sign;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
size_t offset = buffer_.size();
|
size_t offset = buffer_.size();
|
||||||
unsigned width = spec.width;
|
unsigned width = spec.width;
|
||||||
if (sign) {
|
if (sign) {
|
||||||
@@ -382,7 +405,7 @@ void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Formatter::FormatString(
|
char *Formatter::FormatString(
|
||||||
const char *s, std::size_t size, const FormatSpec &spec) {
|
const char *s, std::size_t size, const FormatSpec &spec) {
|
||||||
char *out = 0;
|
char *out = 0;
|
||||||
if (spec.width > size) {
|
if (spec.width > size) {
|
||||||
@@ -399,6 +422,7 @@ void Formatter::FormatString(
|
|||||||
out = GrowBuffer(size);
|
out = GrowBuffer(size);
|
||||||
}
|
}
|
||||||
std::copy(s, s + size, out);
|
std::copy(s, s + size, out);
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses an unsigned integer advancing s to the end of the parsed input.
|
// Parses an unsigned integer advancing s to the end of the parsed input.
|
||||||
|
2
format.h
2
format.h
@@ -322,7 +322,7 @@ class Formatter : public BasicFormatter {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
void FormatDouble(T value, const FormatSpec &spec, int precision);
|
void FormatDouble(T value, const FormatSpec &spec, int precision);
|
||||||
|
|
||||||
void FormatString(const char *s, std::size_t size, const FormatSpec &spec);
|
char *FormatString(const char *s, std::size_t size, const FormatSpec &spec);
|
||||||
|
|
||||||
// Formats an argument of a custom type, such as a user-defined class.
|
// Formats an argument of a custom type, such as a user-defined class.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@@ -774,16 +774,24 @@ TEST(FormatterTest, FormatDouble) {
|
|||||||
sprintf(buffer, "%E", 392.65);
|
sprintf(buffer, "%E", 392.65);
|
||||||
EXPECT_EQ(buffer, str(Format("{0:E}") << 392.65));
|
EXPECT_EQ(buffer, str(Format("{0:E}") << 392.65));
|
||||||
EXPECT_EQ("+0000392.6", str(Format("{0:+010.4g}") << 392.65));
|
EXPECT_EQ("+0000392.6", str(Format("{0:+010.4g}") << 392.65));
|
||||||
double nan = std::numeric_limits<double>::quiet_NaN();
|
|
||||||
EXPECT_EQ("nan", str(Format("{}") << nan));
|
|
||||||
EXPECT_EQ("-nan", str(Format("{}") << -nan));
|
|
||||||
EXPECT_EQ("NAN", str(Format("{:F}") << nan));
|
|
||||||
double inf = std::numeric_limits<double>::infinity();
|
double inf = std::numeric_limits<double>::infinity();
|
||||||
EXPECT_EQ("inf", str(Format("{}") << inf));
|
EXPECT_EQ("inf", str(Format("{}") << inf));
|
||||||
EXPECT_EQ("-inf", str(Format("{}") << -inf));
|
EXPECT_EQ("-inf", str(Format("{}") << -inf));
|
||||||
EXPECT_EQ("INF", str(Format("{:F}") << inf));
|
EXPECT_EQ("INF", str(Format("{:F}") << inf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FormatterTest, FormatNaN) {
|
||||||
|
double nan = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
EXPECT_EQ("nan", str(Format("{}") << nan));
|
||||||
|
EXPECT_EQ("+nan", str(Format("{:+}") << nan));
|
||||||
|
EXPECT_EQ("-nan", str(Format("{}") << -nan));
|
||||||
|
EXPECT_EQ(" nan", str(Format("{: }") << nan));
|
||||||
|
EXPECT_EQ("NAN", str(Format("{:F}") << nan));
|
||||||
|
EXPECT_EQ("nan ", str(Format("{:<7}") << nan));
|
||||||
|
EXPECT_EQ(" nan ", str(Format("{:^7}") << nan));
|
||||||
|
EXPECT_EQ(" nan", str(Format("{:>7}") << nan));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, FormatLongDouble) {
|
TEST(FormatterTest, FormatLongDouble) {
|
||||||
EXPECT_EQ("0", str(Format("{0:}") << 0.0l));
|
EXPECT_EQ("0", str(Format("{0:}") << 0.0l));
|
||||||
EXPECT_EQ("0.000000", str(Format("{0:f}") << 0.0l));
|
EXPECT_EQ("0.000000", str(Format("{0:f}") << 0.0l));
|
||||||
|
Reference in New Issue
Block a user