mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-26 12:10:06 +00:00
Implement left alignment.
This commit is contained in:
parent
c5f4ecb25a
commit
be6e54de36
73
format.cc
73
format.cc
@ -53,12 +53,7 @@ using fmt::FormatSpec;
|
||||
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
|
||||
};
|
||||
enum { PLUS_FLAG = 1, HEX_PREFIX_FLAG = 2 };
|
||||
|
||||
void ReportUnknownType(char code, const char *type) {
|
||||
if (std::isprint(static_cast<unsigned char>(code))) {
|
||||
@ -111,6 +106,34 @@ void Formatter::ReportError(const char *s, const std::string &message) const {
|
||||
throw fmt::FormatError("unmatched '{' in format");
|
||||
}
|
||||
|
||||
char *Formatter::PrepareFilledBuffer(
|
||||
unsigned size, FormatSpec spec, char sign) {
|
||||
if (spec.width <= size) {
|
||||
char *p = GrowBuffer(size);
|
||||
*p = sign;
|
||||
return p + size - 1;
|
||||
}
|
||||
char *p = GrowBuffer(spec.width);
|
||||
char *end = p + spec.width;
|
||||
if (spec.align == ALIGN_LEFT) {
|
||||
*p = sign;
|
||||
p += size;
|
||||
std::fill(p, end, spec.fill);
|
||||
} else if (spec.align == ALIGN_NUMERIC) {
|
||||
if (sign) {
|
||||
*p++ = sign;
|
||||
--size;
|
||||
}
|
||||
std::fill(p, end - size, spec.fill);
|
||||
p = end;
|
||||
} else {
|
||||
*(end - size) = sign;
|
||||
std::fill(p, end - size, spec.fill);
|
||||
p = end;
|
||||
}
|
||||
return p - 1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Formatter::FormatInt(T value, FormatSpec spec) {
|
||||
unsigned size = 0;
|
||||
@ -125,16 +148,13 @@ void Formatter::FormatInt(T value, FormatSpec spec) {
|
||||
sign = '+';
|
||||
++size;
|
||||
}
|
||||
size_t start = buffer_.size();
|
||||
char *p = 0;
|
||||
switch (spec.type) {
|
||||
case 0: case 'd': {
|
||||
UnsignedType n = abs_value;
|
||||
do {
|
||||
++size;
|
||||
} while ((n /= 10) != 0);
|
||||
unsigned width = std::max(spec.width, size);
|
||||
p = GrowBuffer(width) + width - 1;
|
||||
char *p = PrepareFilledBuffer(size, spec, sign);
|
||||
n = abs_value;
|
||||
do {
|
||||
*p-- = '0' + (n % 10);
|
||||
@ -148,8 +168,7 @@ void Formatter::FormatInt(T value, FormatSpec spec) {
|
||||
do {
|
||||
++size;
|
||||
} while ((n >>= 4) != 0);
|
||||
unsigned width = std::max(spec.width, size);
|
||||
p = GrowBuffer(width) + width - 1;
|
||||
char *p = PrepareFilledBuffer(size, spec, sign);
|
||||
n = abs_value;
|
||||
const char *digits = spec.type == 'x' ?
|
||||
"0123456789abcdef" : "0123456789ABCDEF";
|
||||
@ -167,8 +186,7 @@ void Formatter::FormatInt(T value, FormatSpec spec) {
|
||||
do {
|
||||
++size;
|
||||
} while ((n >>= 3) != 0);
|
||||
unsigned width = std::max(spec.width, size);
|
||||
p = GrowBuffer(width) + width - 1;
|
||||
char *p = PrepareFilledBuffer(size, spec, sign);
|
||||
n = abs_value;
|
||||
do {
|
||||
*p-- = '0' + (n & 7);
|
||||
@ -179,13 +197,6 @@ void Formatter::FormatInt(T value, FormatSpec spec) {
|
||||
ReportUnknownType(spec.type, "integer");
|
||||
break;
|
||||
}
|
||||
if (sign) {
|
||||
if ((spec.flags & ZERO_FLAG) != 0)
|
||||
buffer_[start++] = sign;
|
||||
else
|
||||
*p-- = sign;
|
||||
}
|
||||
std::fill(&buffer_[start], p + 1, spec.fill);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -210,14 +221,16 @@ void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
|
||||
}
|
||||
|
||||
// Build format string.
|
||||
enum { MAX_FORMAT_SIZE = 9}; // longest format: %+0*.*Lg
|
||||
enum { MAX_FORMAT_SIZE = 10}; // longest format: %+0*.*Lg
|
||||
char format[MAX_FORMAT_SIZE];
|
||||
char *format_ptr = format;
|
||||
unsigned width = spec.width;
|
||||
*format_ptr++ = '%';
|
||||
if ((spec.flags & PLUS_FLAG) != 0)
|
||||
*format_ptr++ = '+';
|
||||
if ((spec.flags & ZERO_FLAG) != 0)
|
||||
if (spec.align == ALIGN_LEFT)
|
||||
*format_ptr++ = '-';
|
||||
else if (spec.align == ALIGN_NUMERIC)
|
||||
*format_ptr++ = '0';
|
||||
if (width != 0)
|
||||
*format_ptr++ = '*';
|
||||
@ -307,23 +320,23 @@ void Formatter::DoFormat() {
|
||||
// Parse fill and alignment.
|
||||
if (char c = *s) {
|
||||
const char *p = s + 1;
|
||||
Alignment align = ALIGN_DEFAULT;
|
||||
spec.align = ALIGN_DEFAULT;
|
||||
do {
|
||||
switch (*p) {
|
||||
case '<':
|
||||
align = ALIGN_LEFT;
|
||||
spec.align = ALIGN_LEFT;
|
||||
break;
|
||||
case '>':
|
||||
align = ALIGN_RIGHT;
|
||||
spec.align = ALIGN_RIGHT;
|
||||
break;
|
||||
case '=':
|
||||
align = ALIGN_NUMERIC;
|
||||
spec.align = ALIGN_NUMERIC;
|
||||
break;
|
||||
case '^':
|
||||
align = ALIGN_CENTER;
|
||||
spec.align = ALIGN_CENTER;
|
||||
break;
|
||||
}
|
||||
if (align != ALIGN_DEFAULT) {
|
||||
if (spec.align != ALIGN_DEFAULT) {
|
||||
if (p != s && c != '{' && c != '}') {
|
||||
s += 2;
|
||||
spec.fill = c;
|
||||
@ -350,7 +363,7 @@ void Formatter::DoFormat() {
|
||||
if (*s == '0') {
|
||||
if (arg.type > LAST_NUMERIC_TYPE)
|
||||
ReportError(s, "format specifier '0' requires numeric argument");
|
||||
spec.flags |= ZERO_FLAG;
|
||||
spec.align = ALIGN_NUMERIC;
|
||||
spec.fill = '0';
|
||||
}
|
||||
// Zero may be parsed again as a part of the width, but it is simpler
|
||||
|
9
format.h
9
format.h
@ -123,13 +123,18 @@ class FormatError : public std::runtime_error {
|
||||
: std::runtime_error(message) {}
|
||||
};
|
||||
|
||||
enum Alignment {
|
||||
ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC
|
||||
};
|
||||
|
||||
struct FormatSpec {
|
||||
Alignment align;
|
||||
unsigned flags;
|
||||
unsigned width;
|
||||
char type;
|
||||
char fill;
|
||||
|
||||
FormatSpec() : flags(0), width(0), type(0), fill(' ') {}
|
||||
FormatSpec() : align(ALIGN_DEFAULT), flags(0), width(0), type(0), fill(' ') {}
|
||||
};
|
||||
|
||||
// Formatter provides string formatting functionality similar to Python's
|
||||
@ -266,6 +271,8 @@ class Formatter {
|
||||
|
||||
void ReportError(const char *s, const std::string &message) const;
|
||||
|
||||
char *PrepareFilledBuffer(unsigned size, FormatSpec spec, char sign);
|
||||
|
||||
// Formats an integer.
|
||||
template <typename T>
|
||||
void FormatInt(T value, FormatSpec spec);
|
||||
|
@ -259,19 +259,20 @@ 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));
|
||||
TEST(FormatterTest, LeftAlign) {
|
||||
EXPECT_EQ("42 ", str(Format("{0:<4}") << 42));
|
||||
EXPECT_EQ("42 ", str(Format("{0:<4o}") << 042));
|
||||
EXPECT_EQ("42 ", str(Format("{0:<4x}") << 0x42));
|
||||
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("0xface ",
|
||||
str(Format("{0:<8}") << reinterpret_cast<void*>(0xface)));
|
||||
EXPECT_EQ("def ", str(Format("{0:<5}") << TestString("def")));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user