Implement '#' flag.
This commit is contained in:
parent
bf790d2819
commit
1b80148420
114
format.cc
114
format.cc
@ -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,
|
||||
|
73
format.h
73
format.h
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user