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> template <typename Char>
typename fmt::BasicWriter<Char>::CharPtr typename fmt::BasicWriter<Char>::CharPtr
fmt::BasicWriter<Char>::PrepareFilledBuffer( fmt::BasicWriter<Char>::PrepareFilledBuffer(unsigned num_digits,
unsigned size, const AlignSpec &spec, char sign) { const AlignSpec &spec, const char *prefix, unsigned prefix_size) {
unsigned size = prefix_size + num_digits;
unsigned width = spec.width(); unsigned width = spec.width();
if (width <= size) { if (width <= size) {
CharPtr p = GrowBuffer(size); CharPtr p = GrowBuffer(size);
*p = sign; std::copy(prefix, prefix + prefix_size, p);
return p + size - 1; return p + size - 1;
} }
CharPtr p = GrowBuffer(width); CharPtr p = GrowBuffer(width);
@ -359,21 +360,21 @@ typename fmt::BasicWriter<Char>::CharPtr
// TODO: error if fill is not convertible to Char // TODO: error if fill is not convertible to Char
Char fill = static_cast<Char>(spec.fill()); Char fill = static_cast<Char>(spec.fill());
if (align == ALIGN_LEFT) { if (align == ALIGN_LEFT) {
*p = sign; std::copy(prefix, prefix + prefix_size, p);
p += size; p += size;
std::fill(p, end, fill); std::fill(p, end, fill);
} else if (align == ALIGN_CENTER) { } else if (align == ALIGN_CENTER) {
p = FillPadding(p, width, size, fill); p = FillPadding(p, width, size, fill);
*p = sign; std::copy(prefix, prefix + prefix_size, p);
p += size; p += size;
} else { } else {
if (align == ALIGN_NUMERIC) { if (align == ALIGN_NUMERIC) {
if (sign) { if (prefix_size != 0) {
*p++ = sign; p = std::copy(prefix, prefix + prefix_size, p);
--size; size -= prefix_size;
} }
} else { } else {
*(end - size) = sign; std::copy(prefix, prefix + prefix_size, end - size);
} }
std::fill(p, end - size, fill); std::fill(p, end - size, fill);
p = end; 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> template <typename Char>
inline const typename fmt::BasicWriter<Char>::ArgInfo inline const typename fmt::BasicWriter<Char>::ArgInfo
&fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) { &fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) {
@ -577,26 +598,28 @@ void fmt::BasicWriter<Char>::FormatParser::CheckSign(
template <typename Char> template <typename Char>
void fmt::BasicWriter<Char>::PrintfParser::ParseFlags( void fmt::BasicWriter<Char>::PrintfParser::ParseFlags(
FormatSpec &spec, const Char *&s) { FormatSpec &spec, const Char *&s, const ArgInfo &arg) {
// TODO: parse optional flags
for (;;) { for (;;) {
switch (*s) { switch (*s++) {
case '-': case '-':
++s;
spec.align_ = ALIGN_LEFT; spec.align_ = ALIGN_LEFT;
break; break;
case '+': case '+':
// TODO
++s;
spec.flags_ |= SIGN_FLAG | PLUS_FLAG; spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
break; break;
case '0': case '0':
spec.fill_ = '0'; spec.fill_ = '0';
break;
case ' ': case ' ':
spec.flags_ |= SIGN_FLAG;
break;
case '#': case '#':
++s; // TODO: handle floating-point args
if (GetIntValue(arg) != 0)
spec.flags_ |= HASH_FLAG;
break; break;
default: default:
--s;
return; return;
} }
} }
@ -682,58 +705,9 @@ void fmt::BasicWriter<Char>::PrintfParser::Format(
switch (spec.width_) { switch (spec.width_) {
case UINT_MAX: { case UINT_MAX: {
spec.width_ = 0; 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 (*s == '#') {
if (arg.type > LAST_NUMERIC_TYPE) if (arg.type > LAST_NUMERIC_TYPE)
ReportError(s, "format specifier '#' requires numeric argument"); 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); unsigned total_size, std::size_t content_size, wchar_t fill);
template fmt::BasicWriter<char>::CharPtr template fmt::BasicWriter<char>::CharPtr
fmt::BasicWriter<char>::PrepareFilledBuffer( fmt::BasicWriter<char>::PrepareFilledBuffer(unsigned num_digits,
unsigned size, const AlignSpec &spec, char sign); const AlignSpec &spec, const char *prefix, unsigned prefix_size);
template void fmt::BasicWriter<char>::FormatParser::Format( template void fmt::BasicWriter<char>::FormatParser::Format(
BasicWriter<char> &writer, BasicStringRef<char> 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); unsigned total_size, std::size_t content_size, wchar_t fill);
template fmt::BasicWriter<wchar_t>::CharPtr template fmt::BasicWriter<wchar_t>::CharPtr
fmt::BasicWriter<wchar_t>::PrepareFilledBuffer( fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(unsigned num_digits,
unsigned size, const AlignSpec &spec, char sign); const AlignSpec &spec, const char *prefix, unsigned prefix_size);
template void fmt::BasicWriter<wchar_t>::FormatParser::Format( template void fmt::BasicWriter<wchar_t>::FormatParser::Format(
BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format, BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,

View File

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