Implement minus flag.
This commit is contained in:
parent
d96337914f
commit
0a138ad865
20
format.cc
20
format.cc
@ -137,7 +137,7 @@ void FormatDecimal(char *buffer, uint64_t value, unsigned num_digits) {
|
|||||||
// Throws Exception(message) if format contains '}', otherwise throws
|
// Throws Exception(message) if format contains '}', otherwise throws
|
||||||
// FormatError reporting unmatched '{'. The idea is that unmatched '{'
|
// FormatError reporting unmatched '{'. The idea is that unmatched '{'
|
||||||
// should override other errors.
|
// 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) {
|
for (int num_open_braces = num_open_braces_; *s; ++s) {
|
||||||
if (*s == '{') {
|
if (*s == '{') {
|
||||||
++num_open_braces;
|
++num_open_braces;
|
||||||
@ -459,15 +459,21 @@ void Formatter::DoFormat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse sign.
|
// Parse sign.
|
||||||
if (*s == '+') {
|
switch (*s) {
|
||||||
++s;
|
case '+':
|
||||||
if (arg.type > LAST_NUMERIC_TYPE)
|
spec.flags |= PLUS_FLAG;
|
||||||
ReportError(s, "format specifier '+' requires numeric argument");
|
// 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) {
|
if (arg.type == UINT || arg.type == ULONG) {
|
||||||
ReportError(s,
|
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.
|
// Parse width and zero flag.
|
||||||
|
56
format.h
56
format.h
@ -117,6 +117,33 @@ void Array<T, SIZE>::append(const T *begin, const T *end) {
|
|||||||
class ArgInserter;
|
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 {
|
class FormatError : public std::runtime_error {
|
||||||
public:
|
public:
|
||||||
explicit FormatError(const std::string &message)
|
explicit FormatError(const std::string &message)
|
||||||
@ -269,7 +296,7 @@ class Formatter {
|
|||||||
args_.push_back(&arg);
|
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);
|
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()); }
|
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 {
|
namespace internal {
|
||||||
|
|
||||||
// This is a transient object that normally exists only as a temporary
|
// This is a transient object that normally exists only as a temporary
|
||||||
|
@ -356,7 +356,7 @@ TEST(FormatterTest, Fill) {
|
|||||||
EXPECT_EQ("def**", str(Format("{0:*<5}") << TestString("def")));
|
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));
|
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");
|
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) {
|
TEST(FormatterTest, ZeroFlag) {
|
||||||
EXPECT_EQ("42", str(Format("{0:0}") << 42));
|
EXPECT_EQ("42", str(Format("{0:0}") << 42));
|
||||||
EXPECT_EQ("-0042", str(Format("{0:05}") << -42));
|
EXPECT_EQ("-0042", str(Format("{0:05}") << -42));
|
||||||
|
Loading…
Reference in New Issue
Block a user