mirror of
https://github.com/fmtlib/fmt.git
synced 2025-03-14 13:20:51 +00:00
Parse alignment.
This commit is contained in:
parent
a0d685c710
commit
64236894ce
76
format.cc
76
format.cc
@ -52,6 +52,11 @@ namespace {
|
||||
// Flags.
|
||||
enum { PLUS_FLAG = 1, ZERO_FLAG = 2, HEX_PREFIX_FLAG = 4 };
|
||||
|
||||
// Alignment.
|
||||
enum Alignment {
|
||||
ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC
|
||||
};
|
||||
|
||||
void ReportUnknownType(char code, const char *type) {
|
||||
if (std::isprint(static_cast<unsigned char>(code))) {
|
||||
throw fmt::FormatError(
|
||||
@ -104,7 +109,7 @@ void Formatter::ReportError(const char *s, const std::string &message) const {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Formatter::FormatInt(T value, const FormatSpec &spec) {
|
||||
void Formatter::FormatInt(T value, FormatSpec spec) {
|
||||
unsigned size = 0;
|
||||
char sign = 0;
|
||||
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
||||
@ -117,7 +122,7 @@ void Formatter::FormatInt(T value, const FormatSpec &spec) {
|
||||
sign = '+';
|
||||
++size;
|
||||
}
|
||||
size_t start = buffer_.size();
|
||||
size_t offset = buffer_.size();
|
||||
char *p = 0;
|
||||
switch (spec.type) {
|
||||
case 0: case 'd': {
|
||||
@ -173,11 +178,13 @@ void Formatter::FormatInt(T value, const FormatSpec &spec) {
|
||||
}
|
||||
if (sign) {
|
||||
if ((spec.flags & ZERO_FLAG) != 0)
|
||||
buffer_[start++] = sign;
|
||||
buffer_[offset++] = sign;
|
||||
else
|
||||
*p-- = sign;
|
||||
}
|
||||
std::fill(&buffer_[start], p + 1, spec.fill);
|
||||
char *start = &buffer_[offset];
|
||||
if (start != p)
|
||||
std::fill(start, p + 1, spec.fill);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -238,8 +245,10 @@ void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
|
||||
snprintf(start, size, format, width, precision, value);
|
||||
}
|
||||
if (n >= 0 && offset + n < buffer_.capacity()) {
|
||||
while (*start == ' ')
|
||||
*start++ = spec.fill;
|
||||
if (spec.fill != ' ') {
|
||||
while (*start == ' ')
|
||||
*start++ = spec.fill;
|
||||
}
|
||||
GrowBuffer(n);
|
||||
return;
|
||||
}
|
||||
@ -289,21 +298,41 @@ void Formatter::DoFormat() {
|
||||
|
||||
const Arg &arg = ParseArgIndex(s);
|
||||
|
||||
FormatSpec spec = {};
|
||||
spec.fill = ' ';
|
||||
FormatSpec spec;
|
||||
int precision = -1;
|
||||
if (*s == ':') {
|
||||
++s;
|
||||
|
||||
// Parse fill and alignment.
|
||||
if (char c = *s) {
|
||||
switch (s[1]) {
|
||||
case '<': case '>': case '=': case '^':
|
||||
if (c != '{' && c != '}') {
|
||||
s += 2;
|
||||
spec.fill = c;
|
||||
const char *p = s + 1;
|
||||
Alignment align = ALIGN_DEFAULT;
|
||||
do {
|
||||
switch (*p) {
|
||||
case '<':
|
||||
align = ALIGN_LEFT;
|
||||
break;
|
||||
case '>':
|
||||
align = ALIGN_RIGHT;
|
||||
break;
|
||||
case '=':
|
||||
align = ALIGN_NUMERIC;
|
||||
break;
|
||||
case '^':
|
||||
align = ALIGN_CENTER;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (align != ALIGN_DEFAULT) {
|
||||
if (p != s && c != '{' && c != '}') {
|
||||
s += 2;
|
||||
spec.fill = c;
|
||||
} else ++s;
|
||||
break;
|
||||
}
|
||||
} while (--p >= s);
|
||||
}
|
||||
|
||||
// Parse sign.
|
||||
if (*s == '+') {
|
||||
++s;
|
||||
if (arg.type > LAST_NUMERIC_TYPE)
|
||||
@ -314,16 +343,17 @@ void Formatter::DoFormat() {
|
||||
}
|
||||
spec.flags |= PLUS_FLAG;
|
||||
}
|
||||
if (*s == '0') {
|
||||
++s;
|
||||
if (arg.type > LAST_NUMERIC_TYPE)
|
||||
ReportError(s, "format specifier '0' requires numeric argument");
|
||||
spec.flags |= ZERO_FLAG;
|
||||
spec.fill = '0';
|
||||
}
|
||||
|
||||
// Parse width.
|
||||
// Parse width and zero flag.
|
||||
if ('0' <= *s && *s <= '9') {
|
||||
if (*s == '0') {
|
||||
if (arg.type > LAST_NUMERIC_TYPE)
|
||||
ReportError(s, "format specifier '0' requires numeric argument");
|
||||
spec.flags |= ZERO_FLAG;
|
||||
spec.fill = '0';
|
||||
}
|
||||
// Zero may be parsed again as a part of the width, but it is simpler
|
||||
// and more efficient than checking if the next char is a digit.
|
||||
unsigned value = ParseUInt(s);
|
||||
if (value > INT_MAX)
|
||||
ReportError(s, "number is too big in format");
|
||||
|
4
format.h
4
format.h
@ -128,6 +128,8 @@ struct FormatSpec {
|
||||
unsigned width;
|
||||
char type;
|
||||
char fill;
|
||||
|
||||
FormatSpec() : flags(0), width(0), type(0), fill(' ') {}
|
||||
};
|
||||
|
||||
// Formatter provides string formatting functionality similar to Python's
|
||||
@ -266,7 +268,7 @@ class Formatter {
|
||||
|
||||
// Formats an integer.
|
||||
template <typename T>
|
||||
void FormatInt(T value, const FormatSpec &spec);
|
||||
void FormatInt(T value, FormatSpec spec);
|
||||
|
||||
// Formats a floating point number (double or long double).
|
||||
template <typename T>
|
||||
|
@ -257,6 +257,22 @@ TEST(FormatterTest, EmptySpecs) {
|
||||
EXPECT_EQ("42", str(Format("{0:}") << 42));
|
||||
}
|
||||
|
||||
TEST(FormatterTest, Align) {
|
||||
// TODO
|
||||
EXPECT_EQ(" 42", str(Format("{0:>4}") << 42));
|
||||
EXPECT_EQ(" -42", str(Format("{0:>5}") << -42));
|
||||
EXPECT_EQ(" 42", str(Format("{0:>5}") << 42u));
|
||||
EXPECT_EQ(" -42", str(Format("{0:>5}") << -42l));
|
||||
EXPECT_EQ(" 42", str(Format("{0:>5}") << 42ul));
|
||||
EXPECT_EQ(" -42", str(Format("{0:>5}") << -42.0));
|
||||
EXPECT_EQ(" -42", str(Format("{0:>5}") << -42.0l));
|
||||
EXPECT_EQ("c ", str(Format("{0:<5}") << 'c'));
|
||||
EXPECT_EQ("abc ", str(Format("{0:<5}") << "abc"));
|
||||
EXPECT_EQ(" 0xface",
|
||||
str(Format("{0:>8}") << reinterpret_cast<void*>(0xface)));
|
||||
EXPECT_EQ("def ", str(Format("{0:<5}") << TestString("def")));
|
||||
}
|
||||
|
||||
TEST(FormatterTest, Fill) {
|
||||
EXPECT_EQ("**42", str(Format("{0:*>4}") << 42));
|
||||
EXPECT_EQ("**-42", str(Format("{0:*>5}") << -42));
|
||||
@ -644,8 +660,7 @@ TEST(FormatterTest, FormatString) {
|
||||
|
||||
TEST(FormatterTest, Write) {
|
||||
Formatter format;
|
||||
fmt::FormatSpec spec = {};
|
||||
spec.fill = ' ';
|
||||
fmt::FormatSpec spec;
|
||||
spec.width = 2;
|
||||
format.Write("12", spec);
|
||||
EXPECT_EQ("12", format.str());
|
||||
@ -660,8 +675,7 @@ TEST(FormatterTest, Write) {
|
||||
TEST(ArgFormatterTest, Write) {
|
||||
Formatter formatter;
|
||||
fmt::ArgFormatter format(formatter);
|
||||
fmt::FormatSpec spec = {};
|
||||
spec.fill = ' ';
|
||||
fmt::FormatSpec spec;
|
||||
spec.width = 2;
|
||||
format.Write("12", spec);
|
||||
EXPECT_EQ("12", formatter.str());
|
||||
|
Loading…
x
Reference in New Issue
Block a user