Move formatting methods to BasicFormat.
This commit is contained in:
parent
8e158d74cd
commit
de17baae2d
98
format.cc
98
format.cc
@ -137,48 +137,6 @@ void FormatDecimal(char *buffer, uint64_t value, unsigned num_digits) {
|
||||
buffer[0] = DIGITS[index];
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
int signbit(double value) {
|
||||
if (value < 0) return 1;
|
||||
if (value == value) return 0;
|
||||
int dec = 0, sign = 0;
|
||||
_ecvt(value, 0, &dec, &sign);
|
||||
return sign;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BasicFormatter::operator<<(int value) {
|
||||
unsigned abs_value = value;
|
||||
unsigned num_digits = 0;
|
||||
char *out = 0;
|
||||
if (value >= 0) {
|
||||
num_digits = CountDigits(abs_value);
|
||||
out = GrowBuffer(num_digits);
|
||||
} else {
|
||||
abs_value = 0 - abs_value;
|
||||
num_digits = CountDigits(abs_value);
|
||||
out = GrowBuffer(num_digits + 1);
|
||||
*out++ = '-';
|
||||
}
|
||||
FormatDecimal(out, abs_value, 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, StringRef message) const {
|
||||
for (int num_open_braces = num_open_braces_; *s; ++s) {
|
||||
if (*s == '{') {
|
||||
++num_open_braces;
|
||||
} else if (*s == '}') {
|
||||
if (--num_open_braces == 0)
|
||||
throw fmt::FormatError(message);
|
||||
}
|
||||
}
|
||||
throw fmt::FormatError("unmatched '{' in format");
|
||||
}
|
||||
|
||||
// Fills the padding around the content and returns the pointer to the
|
||||
// content area.
|
||||
char *FillPadding(char *buffer,
|
||||
@ -192,7 +150,18 @@ char *FillPadding(char *buffer,
|
||||
return content;
|
||||
}
|
||||
|
||||
char *Formatter::PrepareFilledBuffer(
|
||||
#ifdef _MSC_VER
|
||||
int signbit(double value) {
|
||||
if (value < 0) return 1;
|
||||
if (value == value) return 0;
|
||||
int dec = 0, sign = 0;
|
||||
_ecvt(value, 0, &dec, &sign);
|
||||
return sign;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
char *BasicFormatter::PrepareFilledBuffer(
|
||||
unsigned size, const FormatSpec &spec, char sign) {
|
||||
if (spec.width <= size) {
|
||||
char *p = GrowBuffer(size);
|
||||
@ -225,7 +194,7 @@ char *Formatter::PrepareFilledBuffer(
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Formatter::FormatInt(T value, const FormatSpec &spec) {
|
||||
void BasicFormatter::FormatInt(T value, const FormatSpec &spec) {
|
||||
unsigned size = 0;
|
||||
char sign = 0;
|
||||
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
||||
@ -289,7 +258,8 @@ void Formatter::FormatInt(T value, const FormatSpec &spec) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
|
||||
void BasicFormatter::FormatDouble(
|
||||
T value, const FormatSpec &spec, int precision) {
|
||||
// Check type.
|
||||
char type = spec.type;
|
||||
bool upper = false;
|
||||
@ -431,7 +401,7 @@ void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) {
|
||||
}
|
||||
}
|
||||
|
||||
char *Formatter::FormatString(
|
||||
char *BasicFormatter::FormatString(
|
||||
const char *s, std::size_t size, const FormatSpec &spec) {
|
||||
char *out = 0;
|
||||
if (spec.width > size) {
|
||||
@ -451,6 +421,37 @@ char *Formatter::FormatString(
|
||||
return out;
|
||||
}
|
||||
|
||||
void BasicFormatter::operator<<(int value) {
|
||||
unsigned abs_value = value;
|
||||
unsigned num_digits = 0;
|
||||
char *out = 0;
|
||||
if (value >= 0) {
|
||||
num_digits = CountDigits(abs_value);
|
||||
out = GrowBuffer(num_digits);
|
||||
} else {
|
||||
abs_value = 0 - abs_value;
|
||||
num_digits = CountDigits(abs_value);
|
||||
out = GrowBuffer(num_digits + 1);
|
||||
*out++ = '-';
|
||||
}
|
||||
FormatDecimal(out, abs_value, 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, StringRef message) const {
|
||||
for (int num_open_braces = num_open_braces_; *s; ++s) {
|
||||
if (*s == '{') {
|
||||
++num_open_braces;
|
||||
} else if (*s == '}') {
|
||||
if (--num_open_braces == 0)
|
||||
throw fmt::FormatError(message);
|
||||
}
|
||||
}
|
||||
throw fmt::FormatError("unmatched '{' in format");
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@ -465,7 +466,7 @@ unsigned Formatter::ParseUInt(const char *&s) const {
|
||||
return value;
|
||||
}
|
||||
|
||||
const Formatter::Arg &Formatter::ParseArgIndex(const char *&s) {
|
||||
inline const Formatter::Arg &Formatter::ParseArgIndex(const char *&s) {
|
||||
unsigned arg_index = 0;
|
||||
if (*s < '0' || *s > '9') {
|
||||
if (*s != '}' && *s != ':')
|
||||
@ -726,6 +727,5 @@ void Formatter::DoFormat() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
buffer_.append(start, s + 1);
|
||||
buffer_.resize(buffer_.size() - 1); // Don't count the terminating zero.
|
||||
buffer_.append(start, s);
|
||||
}
|
||||
|
124
format.h
124
format.h
@ -124,6 +124,10 @@ class ArgInserter;
|
||||
type to allow passing different types of strings in a function, for example::
|
||||
|
||||
TempFormatter<> Format(StringRef format);
|
||||
|
||||
Format("{}") << 42;
|
||||
Format(std::string("{}")) << 42;
|
||||
Format(Format("{{}}")) << 42;
|
||||
\endrst
|
||||
*/
|
||||
class StringRef {
|
||||
@ -162,13 +166,14 @@ struct FormatSpec {
|
||||
char type;
|
||||
char fill;
|
||||
|
||||
FormatSpec() : align(ALIGN_DEFAULT), flags(0), width(0), type(0), fill(' ') {}
|
||||
FormatSpec(unsigned width = 0, char type = 0, char fill = ' ')
|
||||
: align(ALIGN_DEFAULT), flags(0), width(width), type(type), fill(fill) {}
|
||||
};
|
||||
|
||||
class BasicFormatter {
|
||||
protected:
|
||||
enum { INLINE_BUFFER_SIZE = 500 };
|
||||
internal::Array<char, INLINE_BUFFER_SIZE> buffer_; // Output buffer.
|
||||
mutable internal::Array<char, INLINE_BUFFER_SIZE> buffer_; // Output buffer.
|
||||
|
||||
// Grows the buffer by n characters and returns a pointer to the newly
|
||||
// allocated area.
|
||||
@ -178,8 +183,69 @@ class BasicFormatter {
|
||||
return &buffer_[size];
|
||||
}
|
||||
|
||||
char *PrepareFilledBuffer(unsigned size, const FormatSpec &spec, char sign);
|
||||
|
||||
// Formats an integer.
|
||||
template <typename T>
|
||||
void FormatInt(T value, const FormatSpec &spec);
|
||||
|
||||
// Formats a floating point number (double or long double).
|
||||
template <typename T>
|
||||
void FormatDouble(T value, const FormatSpec &spec, int precision);
|
||||
|
||||
char *FormatString(const char *s, std::size_t size, const FormatSpec &spec);
|
||||
|
||||
public:
|
||||
/**
|
||||
\rst
|
||||
Returns the number of characters written to the output buffer.
|
||||
\endrst
|
||||
*/
|
||||
std::size_t size() const { return buffer_.size(); }
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns a pointer to the output buffer content. No terminating null
|
||||
character is appended.
|
||||
\endrst
|
||||
*/
|
||||
const char *data() const { return &buffer_[0]; }
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns a pointer to the output buffer content with terminating null
|
||||
character appended.
|
||||
\endrst
|
||||
*/
|
||||
const char *c_str() const {
|
||||
std::size_t size = buffer_.size();
|
||||
buffer_.reserve(size + 1);
|
||||
buffer_[size] = '\0';
|
||||
return &buffer_[0];
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns the content of the output buffer as an ``std::string``.
|
||||
\endrst
|
||||
*/
|
||||
std::string str() const { return std::string(&buffer_[0], buffer_.size()); }
|
||||
|
||||
void operator<<(int value);
|
||||
|
||||
void operator<<(char value) {
|
||||
*GrowBuffer(1) = value;
|
||||
}
|
||||
|
||||
void operator<<(const char *value) {
|
||||
std::size_t size = std::strlen(value);
|
||||
std::strncpy(GrowBuffer(size), value, size);
|
||||
}
|
||||
|
||||
BasicFormatter &Write(int value, const FormatSpec &spec) {
|
||||
FormatInt(value, spec);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -324,18 +390,6 @@ class Formatter : public BasicFormatter {
|
||||
|
||||
void ReportError(const char *s, StringRef message) const;
|
||||
|
||||
char *PrepareFilledBuffer(unsigned size, const FormatSpec &spec, char sign);
|
||||
|
||||
// Formats an integer.
|
||||
template <typename T>
|
||||
void FormatInt(T value, const FormatSpec &spec);
|
||||
|
||||
// Formats a floating point number (double or long double).
|
||||
template <typename T>
|
||||
void FormatDouble(T value, const FormatSpec &spec, int precision);
|
||||
|
||||
char *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 <typename T>
|
||||
void FormatCustomArg(const void *arg, const FormatSpec &spec);
|
||||
@ -360,7 +414,7 @@ class Formatter : public BasicFormatter {
|
||||
Constructs a formatter with an empty output buffer.
|
||||
\endrst
|
||||
*/
|
||||
Formatter() : format_(0) { buffer_[0] = 0; }
|
||||
Formatter() : format_(0) {}
|
||||
|
||||
/**
|
||||
\rst
|
||||
@ -370,36 +424,6 @@ class Formatter : public BasicFormatter {
|
||||
\endrst
|
||||
*/
|
||||
internal::ArgInserter operator()(StringRef format);
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns the number of characters written to the output buffer.
|
||||
\endrst
|
||||
*/
|
||||
std::size_t size() const { return buffer_.size(); }
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns a pointer to the output buffer content. No terminating null
|
||||
character is appended.
|
||||
\endrst
|
||||
*/
|
||||
const char *data() const { return &buffer_[0]; }
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns a pointer to the output buffer content with terminating null
|
||||
character appended.
|
||||
\endrst
|
||||
*/
|
||||
const char *c_str() const { return &buffer_[0]; }
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns the content of the output buffer as an ``std::string``.
|
||||
\endrst
|
||||
*/
|
||||
std::string str() const { return std::string(&buffer_[0], buffer_.size()); }
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
@ -540,9 +564,13 @@ struct NoAction {
|
||||
void operator()(const Formatter &) const {}
|
||||
};
|
||||
|
||||
// A formatter with an action performed when formatting is complete.
|
||||
// Objects of this class normally exist only as temporaries returned
|
||||
// by one of the formatting functions, thus the name.
|
||||
/**
|
||||
\rst
|
||||
A formatter with an action performed when formatting is complete.
|
||||
Objects of this class normally exist only as temporaries returned
|
||||
by one of the formatting functions which explains the name.
|
||||
\endrst
|
||||
*/
|
||||
template <typename Action = NoAction>
|
||||
class TempFormatter : public internal::ArgInserter {
|
||||
private:
|
||||
|
@ -898,7 +898,6 @@ TEST(FormatterTest, FormatStringFromSpeedTest) {
|
||||
TEST(FormatterTest, FormatterCtor) {
|
||||
Formatter format;
|
||||
EXPECT_EQ(0u, format.size());
|
||||
EXPECT_STREQ("", format.data());
|
||||
EXPECT_STREQ("", format.c_str());
|
||||
EXPECT_EQ("", format.str());
|
||||
format("part{0}") << 1;
|
||||
@ -921,6 +920,10 @@ TEST(FormatterTest, FormatterAppend) {
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatterExamples) {
|
||||
EXPECT_EQ("42", str(Format("{}") << 42));
|
||||
EXPECT_EQ("42", str(Format(std::string("{}")) << 42));
|
||||
EXPECT_EQ("42", str(Format(Format("{{}}")) << 42));
|
||||
|
||||
Formatter format;
|
||||
format("Current point:\n");
|
||||
format("({0:+f}, {1:+f})\n") << -3.14 << 3.14;
|
||||
|
Loading…
Reference in New Issue
Block a user