From 1b801484209bbfba55ff4681fb3880c7ddb11156 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 7 Jun 2014 08:57:55 -0700 Subject: [PATCH] Implement '#' flag. --- format.cc | 114 +++++++++++++++++++++--------------------------------- format.h | 73 ++++++++++++++++++---------------- 2 files changed, 83 insertions(+), 104 deletions(-) diff --git a/format.cc b/format.cc index 7e389de1..77fd1fd5 100644 --- a/format.cc +++ b/format.cc @@ -345,12 +345,13 @@ typename fmt::BasicWriter::CharPtr template typename fmt::BasicWriter::CharPtr - fmt::BasicWriter::PrepareFilledBuffer( - unsigned size, const AlignSpec &spec, char sign) { + fmt::BasicWriter::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::CharPtr // TODO: error if fill is not convertible to Char Char fill = static_cast(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::FormatDouble( } } +template +fmt::ULongLong fmt::BasicWriter::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 inline const typename fmt::BasicWriter::ArgInfo &fmt::BasicWriter::FormatParser::ParseArgIndex(const Char *&s) { @@ -577,26 +598,28 @@ void fmt::BasicWriter::FormatParser::CheckSign( template void fmt::BasicWriter::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::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::CharPtr unsigned total_size, std::size_t content_size, wchar_t fill); template fmt::BasicWriter::CharPtr - fmt::BasicWriter::PrepareFilledBuffer( - unsigned size, const AlignSpec &spec, char sign); + fmt::BasicWriter::PrepareFilledBuffer(unsigned num_digits, + const AlignSpec &spec, const char *prefix, unsigned prefix_size); template void fmt::BasicWriter::FormatParser::Format( BasicWriter &writer, BasicStringRef format, @@ -1213,8 +1187,8 @@ template fmt::BasicWriter::CharPtr unsigned total_size, std::size_t content_size, wchar_t fill); template fmt::BasicWriter::CharPtr - fmt::BasicWriter::PrepareFilledBuffer( - unsigned size, const AlignSpec &spec, char sign); + fmt::BasicWriter::PrepareFilledBuffer(unsigned num_digits, + const AlignSpec &spec, const char *prefix, unsigned prefix_size); template void fmt::BasicWriter::FormatParser::Format( BasicWriter &writer, BasicStringRef format, diff --git a/format.h b/format.h index 29852ccf..42b0e65f 100644 --- a/format.h +++ b/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 @@ -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 &writer, @@ -1279,78 +1285,77 @@ typename BasicWriter::CharPtr BasicWriter::FormatString( template template void BasicWriter::FormatInt(T value, const Spec &spec) { - unsigned size = 0; - char sign = 0; + unsigned prefix_size = 0; typedef typename internal::IntTraits::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: