Implement '#' flag.

This commit is contained in:
Victor Zverovich 2014-06-07 08:57:55 -07:00
parent bf790d2819
commit 1b80148420
2 changed files with 83 additions and 104 deletions

114
format.cc
View File

@ -345,12 +345,13 @@ typename fmt::BasicWriter<Char>::CharPtr
template <typename Char>
typename fmt::BasicWriter<Char>::CharPtr
fmt::BasicWriter<Char>::PrepareFilledBuffer(
unsigned size, const AlignSpec &spec, char sign) {
fmt::BasicWriter<Char>::PrepareFilledBuffer(unsigned num_digits,
const AlignSpec &spec, const char *prefix, unsigned prefix_size) {
unsigned size = prefix_size + num_digits;
unsigned width = spec.width();
if (width <= size) {
CharPtr p = GrowBuffer(size);
*p = sign;
std::copy(prefix, prefix + prefix_size, p);
return p + size - 1;
}
CharPtr p = GrowBuffer(width);
@ -359,21 +360,21 @@ typename fmt::BasicWriter<Char>::CharPtr
// TODO: error if fill is not convertible to Char
Char fill = static_cast<Char>(spec.fill());
if (align == ALIGN_LEFT) {
*p = sign;
std::copy(prefix, prefix + prefix_size, p);
p += size;
std::fill(p, end, fill);
} else if (align == ALIGN_CENTER) {
p = FillPadding(p, width, size, fill);
*p = sign;
std::copy(prefix, prefix + prefix_size, p);
p += size;
} else {
if (align == ALIGN_NUMERIC) {
if (sign) {
*p++ = sign;
--size;
if (prefix_size != 0) {
p = std::copy(prefix, prefix + prefix_size, p);
size -= prefix_size;
}
} else {
*(end - size) = sign;
std::copy(prefix, prefix + prefix_size, end - size);
}
std::fill(p, end - size, fill);
p = end;
@ -532,6 +533,26 @@ void fmt::BasicWriter<Char>::FormatDouble(
}
}
template <typename Char>
fmt::ULongLong fmt::BasicWriter<Char>::GetIntValue(const ArgInfo &arg) {
switch (arg.type) {
case INT:
return arg.int_value;
case UINT:
return arg.uint_value;
case LONG:
return arg.long_value;
case ULONG:
return arg.ulong_value;
case LONG_LONG:
return arg.long_long_value;
case ULONG_LONG:
return arg.ulong_long_value;
default:
return -1;
}
}
template <typename Char>
inline const typename fmt::BasicWriter<Char>::ArgInfo
&fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) {
@ -577,26 +598,28 @@ void fmt::BasicWriter<Char>::FormatParser::CheckSign(
template <typename Char>
void fmt::BasicWriter<Char>::PrintfParser::ParseFlags(
FormatSpec &spec, const Char *&s) {
// TODO: parse optional flags
FormatSpec &spec, const Char *&s, const ArgInfo &arg) {
for (;;) {
switch (*s) {
switch (*s++) {
case '-':
++s;
spec.align_ = ALIGN_LEFT;
break;
case '+':
// TODO
++s;
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
break;
case '0':
spec.fill_ = '0';
break;
case ' ':
spec.flags_ |= SIGN_FLAG;
break;
case '#':
++s;
// TODO: handle floating-point args
if (GetIntValue(arg) != 0)
spec.flags_ |= HASH_FLAG;
break;
default:
--s;
return;
}
}
@ -682,58 +705,9 @@ void fmt::BasicWriter<Char>::PrintfParser::Format(
switch (spec.width_) {
case UINT_MAX: {
spec.width_ = 0;
ParseFlags(spec, s);
ParseFlags(spec, s, *arg);
/*
// Parse fill and alignment.
if (Char c = *s) {
const Char *p = s + 1;
spec.align_ = ALIGN_DEFAULT;
do {
switch (*p) {
case '<':
spec.align_ = ALIGN_LEFT;
break;
case '>':
spec.align_ = ALIGN_RIGHT;
break;
case '=':
spec.align_ = ALIGN_NUMERIC;
break;
case '^':
spec.align_ = ALIGN_CENTER;
break;
}
if (spec.align_ != ALIGN_DEFAULT) {
if (p != s) {
if (c == '}') break;
if (c == '{')
ReportError(s, "invalid fill character '{'");
s += 2;
spec.fill_ = c;
} else ++s;
if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
ReportError(s, "format specifier '=' requires numeric argument");
break;
}
} while (--p >= s);
}
// Parse sign.
switch (*s) {
case '+':
CheckSign(s, arg);
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
break;
case '-':
CheckSign(s, arg);
break;
case ' ':
CheckSign(s, arg);
spec.flags_ |= SIGN_FLAG;
break;
}
if (*s == '#') {
if (arg.type > LAST_NUMERIC_TYPE)
ReportError(s, "format specifier '#' requires numeric argument");
@ -1195,8 +1169,8 @@ template fmt::BasicWriter<char>::CharPtr
unsigned total_size, std::size_t content_size, wchar_t fill);
template fmt::BasicWriter<char>::CharPtr
fmt::BasicWriter<char>::PrepareFilledBuffer(
unsigned size, const AlignSpec &spec, char sign);
fmt::BasicWriter<char>::PrepareFilledBuffer(unsigned num_digits,
const AlignSpec &spec, const char *prefix, unsigned prefix_size);
template void fmt::BasicWriter<char>::FormatParser::Format(
BasicWriter<char> &writer, BasicStringRef<char> format,
@ -1213,8 +1187,8 @@ template fmt::BasicWriter<wchar_t>::CharPtr
unsigned total_size, std::size_t content_size, wchar_t fill);
template fmt::BasicWriter<wchar_t>::CharPtr
fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
unsigned size, const AlignSpec &spec, char sign);
fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(unsigned num_digits,
const AlignSpec &spec, const char *prefix, unsigned prefix_size);
template void fmt::BasicWriter<wchar_t>::FormatParser::Format(
BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,

View File

@ -847,13 +847,17 @@ class BasicWriter {
return internal::CheckPtr(&buffer_[size], n);
}
CharPtr PrepareFilledBuffer(unsigned size, const EmptySpec &, char sign) {
// Prepare a buffer for integer formatting.
CharPtr PrepareFilledBuffer(unsigned num_digits,
const EmptySpec &, const char *prefix, unsigned prefix_size) {
unsigned size = prefix_size + num_digits;
CharPtr p = GrowBuffer(size);
*p = sign;
std::copy(prefix, prefix + prefix_size, p);
return p + size - 1;
}
CharPtr PrepareFilledBuffer(unsigned size, const AlignSpec &spec, char sign);
CharPtr PrepareFilledBuffer(unsigned num_digits,
const AlignSpec &spec, const char *prefix, unsigned prefix_size);
// Formats an integer.
template <typename T, typename Spec>
@ -915,6 +919,8 @@ class BasicWriter {
static const ArgInfo DUMMY_ARG;
static ULongLong GetIntValue(const ArgInfo &arg);
// An argument action that does nothing.
struct NullArgAction {
void operator()() const {}
@ -1033,7 +1039,7 @@ class BasicWriter {
const ArgInfo *args_;
int next_arg_index_;
void ParseFlags(FormatSpec &spec, const Char *&s);
void ParseFlags(FormatSpec &spec, const Char *&s, const ArgInfo &arg);
public:
void Format(BasicWriter<Char> &writer,
@ -1279,78 +1285,77 @@ typename BasicWriter<Char>::CharPtr BasicWriter<Char>::FormatString(
template <typename Char>
template <typename T, typename Spec>
void BasicWriter<Char>::FormatInt(T value, const Spec &spec) {
unsigned size = 0;
char sign = 0;
unsigned prefix_size = 0;
typedef typename internal::IntTraits<T>::MainType UnsignedType;
UnsignedType abs_value = value;
char prefix[4] = "";
if (internal::IsNegative(value)) {
sign = '-';
++size;
prefix[0] = '-';
++prefix_size;
abs_value = 0 - abs_value;
} else if (spec.sign_flag()) {
sign = spec.plus_flag() ? '+' : ' ';
++size;
prefix[0] = spec.plus_flag() ? '+' : ' ';
++prefix_size;
}
switch (spec.type()) {
case 0: case 'd': {
unsigned num_digits = internal::CountDigits(abs_value);
CharPtr p =
PrepareFilledBuffer(size + num_digits, spec, sign) + 1 - num_digits;
CharPtr p = PrepareFilledBuffer(
num_digits, spec, prefix, prefix_size) + 1 - num_digits;
internal::FormatDecimal(GetBase(p), abs_value, num_digits);
break;
}
case 'x': case 'X': {
UnsignedType n = abs_value;
bool print_prefix = spec.hash_flag();
if (print_prefix) size += 2;
if (spec.hash_flag()) {
prefix[prefix_size++] = '0';
prefix[prefix_size++] = spec.type();
}
unsigned num_digits = 0;
do {
++size;
++num_digits;
} while ((n >>= 4) != 0);
Char *p = GetBase(PrepareFilledBuffer(size, spec, sign));
Char *p = GetBase(PrepareFilledBuffer(
num_digits, spec, prefix, prefix_size));
n = abs_value;
const char *digits = spec.type() == 'x' ?
"0123456789abcdef" : "0123456789ABCDEF";
do {
*p-- = digits[n & 0xf];
} while ((n >>= 4) != 0);
if (print_prefix) {
*p-- = spec.type();
*p = '0';
}
break;
}
case 'b': case 'B': {
UnsignedType n = abs_value;
bool print_prefix = spec.hash_flag();
if (print_prefix) size += 2;
if (spec.hash_flag()) {
prefix[prefix_size++] = '0';
prefix[prefix_size++] = spec.type();
}
unsigned num_digits = 0;
do {
++size;
++num_digits;
} while ((n >>= 1) != 0);
Char *p = GetBase(PrepareFilledBuffer(size, spec, sign));
Char *p = GetBase(PrepareFilledBuffer(num_digits, spec, prefix, prefix_size));
n = abs_value;
do {
*p-- = '0' + (n & 1);
} while ((n >>= 1) != 0);
if (print_prefix) {
*p-- = spec.type();
*p = '0';
}
break;
}
case 'o': {
UnsignedType n = abs_value;
bool print_prefix = spec.hash_flag();
if (print_prefix) ++size;
if (spec.hash_flag())
prefix[prefix_size++] = '0';
unsigned num_digits = 0;
do {
++size;
++num_digits;
} while ((n >>= 3) != 0);
Char *p = GetBase(PrepareFilledBuffer(size, spec, sign));
Char *p = GetBase(PrepareFilledBuffer(
num_digits, spec, prefix, prefix_size));
n = abs_value;
do {
*p-- = '0' + (n & 7);
} while ((n >>= 3) != 0);
if (print_prefix)
*p = '0';
break;
}
default: