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];
|
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
|
// Fills the padding around the content and returns the pointer to the
|
||||||
// content area.
|
// content area.
|
||||||
char *FillPadding(char *buffer,
|
char *FillPadding(char *buffer,
|
||||||
@ -192,7 +150,18 @@ char *FillPadding(char *buffer,
|
|||||||
return content;
|
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) {
|
unsigned size, const FormatSpec &spec, char sign) {
|
||||||
if (spec.width <= size) {
|
if (spec.width <= size) {
|
||||||
char *p = GrowBuffer(size);
|
char *p = GrowBuffer(size);
|
||||||
@ -225,7 +194,7 @@ char *Formatter::PrepareFilledBuffer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Formatter::FormatInt(T value, const FormatSpec &spec) {
|
void BasicFormatter::FormatInt(T value, const FormatSpec &spec) {
|
||||||
unsigned size = 0;
|
unsigned size = 0;
|
||||||
char sign = 0;
|
char sign = 0;
|
||||||
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
||||||
@ -289,7 +258,8 @@ void Formatter::FormatInt(T value, const FormatSpec &spec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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.
|
// Check type.
|
||||||
char type = spec.type;
|
char type = spec.type;
|
||||||
bool upper = false;
|
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) {
|
const char *s, std::size_t size, const FormatSpec &spec) {
|
||||||
char *out = 0;
|
char *out = 0;
|
||||||
if (spec.width > size) {
|
if (spec.width > size) {
|
||||||
@ -451,6 +421,37 @@ char *Formatter::FormatString(
|
|||||||
return out;
|
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.
|
// 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.
|
// This function assumes that the first character of s is a digit.
|
||||||
unsigned Formatter::ParseUInt(const char *&s) const {
|
unsigned Formatter::ParseUInt(const char *&s) const {
|
||||||
@ -465,7 +466,7 @@ unsigned Formatter::ParseUInt(const char *&s) const {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Formatter::Arg &Formatter::ParseArgIndex(const char *&s) {
|
inline const Formatter::Arg &Formatter::ParseArgIndex(const char *&s) {
|
||||||
unsigned arg_index = 0;
|
unsigned arg_index = 0;
|
||||||
if (*s < '0' || *s > '9') {
|
if (*s < '0' || *s > '9') {
|
||||||
if (*s != '}' && *s != ':')
|
if (*s != '}' && *s != ':')
|
||||||
@ -726,6 +727,5 @@ void Formatter::DoFormat() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buffer_.append(start, s + 1);
|
buffer_.append(start, s);
|
||||||
buffer_.resize(buffer_.size() - 1); // Don't count the terminating zero.
|
|
||||||
}
|
}
|
||||||
|
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::
|
type to allow passing different types of strings in a function, for example::
|
||||||
|
|
||||||
TempFormatter<> Format(StringRef format);
|
TempFormatter<> Format(StringRef format);
|
||||||
|
|
||||||
|
Format("{}") << 42;
|
||||||
|
Format(std::string("{}")) << 42;
|
||||||
|
Format(Format("{{}}")) << 42;
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
class StringRef {
|
class StringRef {
|
||||||
@ -162,13 +166,14 @@ struct FormatSpec {
|
|||||||
char type;
|
char type;
|
||||||
char fill;
|
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 {
|
class BasicFormatter {
|
||||||
protected:
|
protected:
|
||||||
enum { INLINE_BUFFER_SIZE = 500 };
|
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
|
// Grows the buffer by n characters and returns a pointer to the newly
|
||||||
// allocated area.
|
// allocated area.
|
||||||
@ -178,8 +183,69 @@ class BasicFormatter {
|
|||||||
return &buffer_[size];
|
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:
|
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<<(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;
|
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.
|
// Formats an argument of a custom type, such as a user-defined class.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void FormatCustomArg(const void *arg, const FormatSpec &spec);
|
void FormatCustomArg(const void *arg, const FormatSpec &spec);
|
||||||
@ -360,7 +414,7 @@ class Formatter : public BasicFormatter {
|
|||||||
Constructs a formatter with an empty output buffer.
|
Constructs a formatter with an empty output buffer.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
Formatter() : format_(0) { buffer_[0] = 0; }
|
Formatter() : format_(0) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@ -370,36 +424,6 @@ class Formatter : public BasicFormatter {
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
internal::ArgInserter operator()(StringRef format);
|
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 {
|
namespace internal {
|
||||||
@ -540,9 +564,13 @@ struct NoAction {
|
|||||||
void operator()(const Formatter &) const {}
|
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
|
\rst
|
||||||
// by one of the formatting functions, thus the name.
|
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>
|
template <typename Action = NoAction>
|
||||||
class TempFormatter : public internal::ArgInserter {
|
class TempFormatter : public internal::ArgInserter {
|
||||||
private:
|
private:
|
||||||
|
@ -898,7 +898,6 @@ TEST(FormatterTest, FormatStringFromSpeedTest) {
|
|||||||
TEST(FormatterTest, FormatterCtor) {
|
TEST(FormatterTest, FormatterCtor) {
|
||||||
Formatter format;
|
Formatter format;
|
||||||
EXPECT_EQ(0u, format.size());
|
EXPECT_EQ(0u, format.size());
|
||||||
EXPECT_STREQ("", format.data());
|
|
||||||
EXPECT_STREQ("", format.c_str());
|
EXPECT_STREQ("", format.c_str());
|
||||||
EXPECT_EQ("", format.str());
|
EXPECT_EQ("", format.str());
|
||||||
format("part{0}") << 1;
|
format("part{0}") << 1;
|
||||||
@ -921,6 +920,10 @@ TEST(FormatterTest, FormatterAppend) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, FormatterExamples) {
|
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;
|
Formatter format;
|
||||||
format("Current point:\n");
|
format("Current point:\n");
|
||||||
format("({0:+f}, {1:+f})\n") << -3.14 << 3.14;
|
format("({0:+f}, {1:+f})\n") << -3.14 << 3.14;
|
||||||
|
Loading…
Reference in New Issue
Block a user