diff --git a/format.cc b/format.cc index 3afccf26..c8df0511 100644 --- a/format.cc +++ b/format.cc @@ -119,15 +119,15 @@ char *Formatter::PrepareFilledBuffer( *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; + if (spec.align == ALIGN_NUMERIC) { + if (sign) { + *p++ = sign; + --size; + } + } else { + *(end - size) = sign; + } std::fill(p, end - size, spec.fill); p = end; } @@ -270,6 +270,21 @@ void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) { } } +void Formatter::FormatString( + const char *s, std::size_t size, const FormatSpec &spec) { + char *out = 0; + if (spec.width > size) { + out = GrowBuffer(spec.width); + if (spec.align == ALIGN_RIGHT) + out = std::fill_n(out, spec.width - size, spec.fill); + else + std::fill_n(out + size, spec.width - size, spec.fill); + } else { + out = GrowBuffer(size); + } + std::copy(s, s + size, out); +} + // Parses an unsigned integer advancing s to the end of the parsed input. // This function assumes that the first character of s is a digit. unsigned Formatter::ParseUInt(const char *&s) const { @@ -455,10 +470,17 @@ void Formatter::DoFormat() { case CHAR: { if (spec.type && spec.type != 'c') ReportUnknownType(spec.type, "char"); - char *out = GrowBuffer(std::max(spec.width, 1u)); - *out++ = arg.int_value; - if (spec.width > 1) - std::fill_n(out, spec.width - 1, spec.fill); + char *out = 0; + if (spec.width > 1) { + out = GrowBuffer(spec.width); + if (spec.align == ALIGN_RIGHT) + out = std::fill_n(out, spec.width - 1, spec.fill); + else + std::fill_n(out + 1, spec.width - 1, spec.fill); + } else { + out = GrowBuffer(1); + } + *out = arg.int_value; break; } case STRING: { @@ -472,10 +494,7 @@ void Formatter::DoFormat() { if (*str) size = std::strlen(str); } - char *out = GrowBuffer(std::max(spec.width, size)); - out = std::copy(str, str + size, out); - if (spec.width > size) - std::fill_n(out, spec.width - size, spec.fill); + FormatString(str, size, spec); break; } case POINTER: @@ -498,10 +517,3 @@ void Formatter::DoFormat() { buffer_.append(start, s + 1); buffer_.resize(buffer_.size() - 1); // Don't count the terminating zero. } - -void Formatter::Write(const std::string &s, const FormatSpec &spec) { - char *out = GrowBuffer(std::max(spec.width, s.size())); - std::copy(s.begin(), s.end(), out); - if (spec.width > s.size()) - std::fill_n(out + s.size(), spec.width - s.size(), spec.fill); -} diff --git a/format.h b/format.h index d0520eee..096481bc 100644 --- a/format.h +++ b/format.h @@ -281,6 +281,8 @@ class Formatter { template void FormatDouble(T value, const FormatSpec &spec, int precision); + void FormatString(const char *s, std::size_t size, const FormatSpec &spec); + // Formats an argument of a custom type, such as a user-defined class. template void FormatCustomArg(const void *arg, const FormatSpec &spec); @@ -323,10 +325,6 @@ class Formatter { const char *c_str() const { return &buffer_[0]; } std::string str() const { return std::string(&buffer_[0], buffer_.size()); } - - // Writes a string to the output buffer padding with spaces if - // necessary to achieve the desired width. - void Write(const std::string &s, const FormatSpec &spec); }; // A reference to a string. It can be constructed from a C string, @@ -464,7 +462,7 @@ class ArgFormatter { explicit ArgFormatter(Formatter &f) : formatter_(f) {} void Write(const std::string &s, const FormatSpec &spec) { - formatter_.Write(s, spec); + formatter_.FormatString(s.data(), s.size(), spec); } }; diff --git a/format_test.cc b/format_test.cc index a3f48a1a..b9d7333c 100644 --- a/format_test.cc +++ b/format_test.cc @@ -276,6 +276,23 @@ TEST(FormatterTest, LeftAlign) { EXPECT_EQ("def ", str(Format("{0:<5}") << TestString("def"))); } +TEST(FormatterTest, RightAlign) { + 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(0xface))); + EXPECT_EQ(" def", str(Format("{0:>5}") << TestString("def"))); +} + TEST(FormatterTest, Fill) { EXPECT_EQ("**42", str(Format("{0:*>4}") << 42)); EXPECT_EQ("**-42", str(Format("{0:*>5}") << -42)); @@ -662,20 +679,6 @@ TEST(FormatterTest, FormatString) { EXPECT_EQ("test", str(Format("{0}") << std::string("test"))); } -TEST(FormatterTest, Write) { - Formatter format; - fmt::FormatSpec spec; - spec.width = 2; - format.Write("12", spec); - EXPECT_EQ("12", format.str()); - spec.width = 4; - format.Write("34", spec); - EXPECT_EQ("1234 ", format.str()); - spec.width = 0; - format.Write("56", spec); - EXPECT_EQ("1234 56", format.str()); -} - TEST(ArgFormatterTest, Write) { Formatter formatter; fmt::ArgFormatter format(formatter);