Implement minus flag.

This commit is contained in:
Victor Zverovich 2012-12-25 13:25:14 -08:00
parent d96337914f
commit 0a138ad865
3 changed files with 65 additions and 36 deletions

View File

@ -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.

View File

@ -117,6 +117,33 @@ void Array<T, SIZE>::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

View File

@ -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<void*>(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));