From 0a138ad86500c42cab37f72848fc87b585c98cd2 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 25 Dec 2012 13:25:14 -0800 Subject: [PATCH] Implement minus flag. --- format.cc | 20 +++++++++++------- format.h | 56 +++++++++++++++++++++++++------------------------- format_test.cc | 25 +++++++++++++++++++++- 3 files changed, 65 insertions(+), 36 deletions(-) diff --git a/format.cc b/format.cc index 77a18b70..6bdceaa0 100644 --- a/format.cc +++ b/format.cc @@ -137,7 +137,7 @@ void FormatDecimal(char *buffer, uint64_t value, unsigned num_digits) { // Throws Exception(message) if format contains '}', otherwise throws // FormatError reporting unmatched '{'. The idea is that unmatched '{' // should override other errors. -void Formatter::ReportError(const char *s, const std::string &message) const { +void Formatter::ReportError(const char *s, StringRef message) const { for (int num_open_braces = num_open_braces_; *s; ++s) { if (*s == '{') { ++num_open_braces; @@ -459,15 +459,21 @@ void Formatter::DoFormat() { } // Parse sign. - if (*s == '+') { - ++s; - if (arg.type > LAST_NUMERIC_TYPE) - ReportError(s, "format specifier '+' requires numeric argument"); + switch (*s) { + case '+': + spec.flags |= PLUS_FLAG; + // Fall through. + case '-': + if (arg.type > LAST_NUMERIC_TYPE) { + ReportError(s, + Format("format specifier '{0}' requires numeric argument") << *s); + } if (arg.type == UINT || arg.type == ULONG) { ReportError(s, - "format specifier '+' requires signed argument"); + Format("format specifier '{0}' requires signed argument") << *s); } - spec.flags |= PLUS_FLAG; + ++s; + break; } // Parse width and zero flag. diff --git a/format.h b/format.h index e5ba3dee..307a7ea8 100644 --- a/format.h +++ b/format.h @@ -117,6 +117,33 @@ void Array::append(const T *begin, const T *end) { class ArgInserter; } +// A reference to a string. It can be constructed from a C string, +// std::string or as a result of a formatting operation. It is most useful +// as a parameter type to allow passing different types of strings in a +// function, for example: +// void SetName(StringRef s) { +// std::string name = s; +// ... +// } +class StringRef { + private: + const char *data_; + mutable std::size_t size_; + + public: + StringRef(const char *s, std::size_t size = 0) : data_(s), size_(size) {} + StringRef(const std::string &s) : data_(s.c_str()), size_(s.size()) {} + + operator std::string() const { return std::string(data_, size()); } + + const char *c_str() const { return data_; } + + std::size_t size() const { + if (size_ == 0) size_ = std::strlen(data_); + return size_; + } +}; + class FormatError : public std::runtime_error { public: explicit FormatError(const std::string &message) @@ -269,7 +296,7 @@ class Formatter { args_.push_back(&arg); } - void ReportError(const char *s, const std::string &message) const; + void ReportError(const char *s, StringRef message) const; char *PrepareFilledBuffer(unsigned size, const FormatSpec &spec, char sign); @@ -325,33 +352,6 @@ class Formatter { std::string str() const { return std::string(&buffer_[0], buffer_.size()); } }; -// A reference to a string. It can be constructed from a C string, -// std::string or as a result of a formatting operation. It is most useful -// as a parameter type to allow passing different types of strings in a -// function, for example: -// void SetName(StringRef s) { -// std::string name = s; -// ... -// } -class StringRef { - private: - const char *data_; - mutable std::size_t size_; - - public: - StringRef(const char *s, std::size_t size = 0) : data_(s), size_(size) {} - StringRef(const std::string &s) : data_(s.c_str()), size_(s.size()) {} - - operator std::string() const { return std::string(data_, size()); } - - const char *c_str() const { return data_; } - - std::size_t size() const { - if (size_ == 0) size_ = std::strlen(data_); - return size_; - } -}; - namespace internal { // This is a transient object that normally exists only as a temporary diff --git a/format_test.cc b/format_test.cc index 8bf8edd9..d352791a 100644 --- a/format_test.cc +++ b/format_test.cc @@ -356,7 +356,7 @@ TEST(FormatterTest, Fill) { EXPECT_EQ("def**", str(Format("{0:*<5}") << TestString("def"))); } -TEST(FormatterTest, PlusFlag) { +TEST(FormatterTest, PlusSign) { EXPECT_EQ("+42", str(Format("{0:+}") << 42)); EXPECT_EQ("-42", str(Format("{0:+}") << -42)); EXPECT_EQ("+42", str(Format("{0:+}") << 42)); @@ -379,6 +379,29 @@ TEST(FormatterTest, PlusFlag) { FormatError, "format specifier '+' requires numeric argument"); } +TEST(FormatterTest, MinusSign) { + EXPECT_EQ("42", str(Format("{0:-}") << 42)); + EXPECT_EQ("-42", str(Format("{0:-}") << -42)); + EXPECT_EQ("42", str(Format("{0:-}") << 42)); + EXPECT_THROW_MSG(Format("{0:-}") << 42u, + FormatError, "format specifier '-' requires signed argument"); + EXPECT_EQ("42", str(Format("{0:-}") << 42l)); + EXPECT_THROW_MSG(Format("{0:-}") << 42ul, + FormatError, "format specifier '-' requires signed argument"); + EXPECT_EQ("42", str(Format("{0:-}") << 42.0)); + EXPECT_EQ("42", str(Format("{0:-}") << 42.0l)); + EXPECT_THROW_MSG(Format("{0:-") << 'c', + FormatError, "unmatched '{' in format"); + EXPECT_THROW_MSG(Format("{0:-}") << 'c', + FormatError, "format specifier '-' requires numeric argument"); + EXPECT_THROW_MSG(Format("{0:-}") << "abc", + FormatError, "format specifier '-' requires numeric argument"); + EXPECT_THROW_MSG(Format("{0:-}") << reinterpret_cast(0x42), + FormatError, "format specifier '-' requires numeric argument"); + EXPECT_THROW_MSG(Format("{0:-}") << TestString(), + FormatError, "format specifier '-' requires numeric argument"); +} + TEST(FormatterTest, ZeroFlag) { EXPECT_EQ("42", str(Format("{0:0}") << 42)); EXPECT_EQ("-0042", str(Format("{0:05}") << -42));