Implement '#' flag.

This commit is contained in:
Victor Zverovich 2012-12-25 18:19:51 -08:00
parent 3f73987a62
commit 73f13eeb5b
2 changed files with 51 additions and 5 deletions

View File

@ -55,7 +55,7 @@ using fmt::StringRef;
namespace { namespace {
// Flags. // Flags.
enum { SIGN_FLAG = 1, PLUS_FLAG = 2, HEX_PREFIX_FLAG = 4 }; enum { SIGN_FLAG = 1, PLUS_FLAG = 2, HASH_FLAG = 4 };
void ReportUnknownType(char code, const char *type) { void ReportUnknownType(char code, const char *type) {
if (std::isprint(static_cast<unsigned char>(code))) { if (std::isprint(static_cast<unsigned char>(code))) {
@ -236,7 +236,7 @@ void Formatter::FormatInt(T value, const FormatSpec &spec) {
} }
case 'x': case 'X': { case 'x': case 'X': {
UnsignedType n = abs_value; UnsignedType n = abs_value;
bool print_prefix = (spec.flags & HEX_PREFIX_FLAG) != 0; bool print_prefix = (spec.flags & HASH_FLAG) != 0;
if (print_prefix) size += 2; if (print_prefix) size += 2;
do { do {
++size; ++size;
@ -250,12 +250,14 @@ void Formatter::FormatInt(T value, const FormatSpec &spec) {
} while ((n >>= 4) != 0); } while ((n >>= 4) != 0);
if (print_prefix) { if (print_prefix) {
*p-- = spec.type; *p-- = spec.type;
*p-- = '0'; *p = '0';
} }
break; break;
} }
case 'o': { case 'o': {
UnsignedType n = abs_value; UnsignedType n = abs_value;
bool print_prefix = (spec.flags & HASH_FLAG) != 0;
if (print_prefix) ++size;
do { do {
++size; ++size;
} while ((n >>= 3) != 0); } while ((n >>= 3) != 0);
@ -264,6 +266,8 @@ void Formatter::FormatInt(T value, const FormatSpec &spec) {
do { do {
*p-- = '0' + (n & 7); *p-- = '0' + (n & 7);
} while ((n >>= 3) != 0); } while ((n >>= 3) != 0);
if (print_prefix)
*p = '0';
break; break;
} }
default: default:
@ -310,11 +314,13 @@ void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
} }
// Build format string. // Build format string.
enum { MAX_FORMAT_SIZE = 10}; // longest format: %+0*.*Lg enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
char format[MAX_FORMAT_SIZE]; char format[MAX_FORMAT_SIZE];
char *format_ptr = format; char *format_ptr = format;
*format_ptr++ = '%'; *format_ptr++ = '%';
unsigned width_for_sprintf = width; unsigned width_for_sprintf = width;
if ((spec.flags & HASH_FLAG) != 0)
*format_ptr++ = '#';
if (spec.align == ALIGN_CENTER) { if (spec.align == ALIGN_CENTER) {
width_for_sprintf = 0; width_for_sprintf = 0;
} else { } else {
@ -503,6 +509,13 @@ void Formatter::DoFormat() {
break; break;
} }
if (*s == '#') {
if (arg.type > LAST_NUMERIC_TYPE)
ReportError(s, "format specifier '#' requires numeric argument");
spec.flags |= HASH_FLAG;
++s;
}
// Parse width and zero flag. // Parse width and zero flag.
if ('0' <= *s && *s <= '9') { if ('0' <= *s && *s <= '9') {
if (*s == '0') { if (*s == '0') {
@ -634,7 +647,7 @@ void Formatter::DoFormat() {
case POINTER: case POINTER:
if (spec.type && spec.type != 'p') if (spec.type && spec.type != 'p')
ReportUnknownType(spec.type, "pointer"); ReportUnknownType(spec.type, "pointer");
spec.flags = HEX_PREFIX_FLAG; spec.flags = HASH_FLAG;
spec.type = 'x'; spec.type = 'x';
FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec); FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
break; break;

View File

@ -425,6 +425,39 @@ TEST(FormatterTest, SpaceSign) {
FormatError, "format specifier ' ' requires numeric argument"); FormatError, "format specifier ' ' requires numeric argument");
} }
TEST(FormatterTest, HashFlag) {
// TODO
EXPECT_EQ("42", str(Format("{0:#}") << 42));
EXPECT_EQ("-42", str(Format("{0:#}") << -42));
EXPECT_EQ("0x42", str(Format("{0:#x}") << 0x42));
EXPECT_EQ("-0x42", str(Format("{0:#x}") << -0x42));
EXPECT_EQ("042", str(Format("{0:#o}") << 042));
EXPECT_EQ("-042", str(Format("{0:#o}") << -042));
EXPECT_EQ("42", str(Format("{0:#}") << 42u));
EXPECT_EQ("0x42", str(Format("{0:#x}") << 0x42u));
EXPECT_EQ("042", str(Format("{0:#o}") << 042u));
EXPECT_EQ("-42", str(Format("{0:#}") << -42l));
EXPECT_EQ("0x42", str(Format("{0:#x}") << 0x42l));
EXPECT_EQ("-0x42", str(Format("{0:#x}") << -0x42l));
EXPECT_EQ("042", str(Format("{0:#o}") << 042l));
EXPECT_EQ("-042", str(Format("{0:#o}") << -042l));
EXPECT_EQ("42", str(Format("{0:#}") << 42ul));
EXPECT_EQ("0x42", str(Format("{0:#x}") << 0x42ul));
EXPECT_EQ("042", str(Format("{0:#o}") << 042ul));
EXPECT_EQ("-42.0000", str(Format("{0:#}") << -42.0));
EXPECT_EQ("-42.0000", str(Format("{0:#}") << -42.0l));
EXPECT_THROW_MSG(Format("{0:#") << 'c',
FormatError, "unmatched '{' in format");
EXPECT_THROW_MSG(Format("{0:#}") << 'c',
FormatError, "format specifier '#' requires numeric argument");
EXPECT_THROW_MSG(Format("{0:#}") << "abc",
FormatError, "format specifier '#' requires numeric argument");
EXPECT_THROW_MSG(Format("{0:#}") << reinterpret_cast<void*>(0x42),
FormatError, "format specifier '#' requires numeric argument");
EXPECT_THROW_MSG(Format("{0:#}") << TestString(),
FormatError, "format specifier '#' requires numeric argument");
}
TEST(FormatterTest, ZeroFlag) { TEST(FormatterTest, ZeroFlag) {
EXPECT_EQ("42", str(Format("{0:0}") << 42)); EXPECT_EQ("42", str(Format("{0:0}") << 42));
EXPECT_EQ("-0042", str(Format("{0:05}") << -42)); EXPECT_EQ("-0042", str(Format("{0:05}") << -42));