Move formatting functionality from BasicFormatter to BasicWriter & FormatPaser to simplify the implementation of standalone formatting methods.
This commit is contained in:
parent
1104e73242
commit
e78904b9b9
56
format.cc
56
format.cc
@ -359,7 +359,7 @@ void fmt::BasicWriter<Char>::FormatDouble(
|
||||
// FormatError reporting unmatched '{'. The idea is that unmatched '{'
|
||||
// should override other errors.
|
||||
template <typename Char>
|
||||
void fmt::BasicFormatter<Char>::ReportError(
|
||||
void fmt::BasicWriter<Char>::FormatParser::ReportError(
|
||||
const Char *s, StringRef message) const {
|
||||
for (int num_open_braces = num_open_braces_; *s; ++s) {
|
||||
if (*s == '{') {
|
||||
@ -375,7 +375,7 @@ void fmt::BasicFormatter<Char>::ReportError(
|
||||
// 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.
|
||||
template <typename Char>
|
||||
unsigned fmt::BasicFormatter<Char>::ParseUInt(const Char *&s) const {
|
||||
unsigned fmt::BasicWriter<Char>::FormatParser::ParseUInt(const Char *&s) const {
|
||||
assert('0' <= *s && *s <= '9');
|
||||
unsigned value = 0;
|
||||
do {
|
||||
@ -388,8 +388,8 @@ unsigned fmt::BasicFormatter<Char>::ParseUInt(const Char *&s) const {
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline const typename fmt::BasicFormatter<Char>::ArgInfo
|
||||
&fmt::BasicFormatter<Char>::ParseArgIndex(const Char *&s) {
|
||||
inline const typename fmt::BasicWriter<Char>::ArgInfo
|
||||
&fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) {
|
||||
unsigned arg_index = 0;
|
||||
if (*s < '0' || *s > '9') {
|
||||
if (*s != '}' && *s != ':')
|
||||
@ -407,32 +407,35 @@ inline const typename fmt::BasicFormatter<Char>::ArgInfo
|
||||
next_arg_index_ = -1;
|
||||
arg_index = ParseUInt(s);
|
||||
}
|
||||
if (arg_index >= args_.size())
|
||||
if (arg_index >= num_args_)
|
||||
ReportError(s, "argument index is out of range in format");
|
||||
return args_[arg_index];
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void fmt::BasicFormatter<Char>::CheckSign(const Char *&s, const ArgInfo &arg) {
|
||||
void fmt::BasicWriter<Char>::FormatParser::CheckSign(
|
||||
const Char *&s, const ArgInfo &arg) {
|
||||
char sign = static_cast<char>(*s);
|
||||
if (arg.type > LAST_NUMERIC_TYPE) {
|
||||
ReportError(s,
|
||||
Format("format specifier '{}' requires numeric argument") << sign);
|
||||
fmt::Format("format specifier '{}' requires numeric argument") << sign);
|
||||
}
|
||||
if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
|
||||
ReportError(s,
|
||||
Format("format specifier '{}' requires signed argument") << sign);
|
||||
fmt::Format("format specifier '{}' requires signed argument") << sign);
|
||||
}
|
||||
++s;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void fmt::BasicFormatter<Char>::DoFormat() {
|
||||
const Char *start = format_;
|
||||
format_ = 0;
|
||||
void fmt::BasicWriter<Char>::FormatParser::Format(
|
||||
BasicWriter<Char> &writer, BasicStringRef<Char> format,
|
||||
std::size_t num_args, const ArgInfo *args) {
|
||||
const Char *start = format.c_str();
|
||||
num_args_ = num_args;
|
||||
args_ = args;
|
||||
next_arg_index_ = 0;
|
||||
const Char *s = start;
|
||||
BasicWriter<Char> &writer = *writer_;
|
||||
while (*s) {
|
||||
Char c = *s++;
|
||||
if (c != '{' && c != '}') continue;
|
||||
@ -697,18 +700,21 @@ template fmt::BasicWriter<char>::CharPtr
|
||||
fmt::BasicWriter<char>::PrepareFilledBuffer(
|
||||
unsigned size, const AlignSpec &spec, char sign);
|
||||
|
||||
template void fmt::BasicFormatter<char>::ReportError(
|
||||
template void fmt::BasicWriter<char>::FormatParser::ReportError(
|
||||
const char *s, StringRef message) const;
|
||||
|
||||
template unsigned fmt::BasicFormatter<char>::ParseUInt(const char *&s) const;
|
||||
template unsigned fmt::BasicWriter<char>::FormatParser::ParseUInt(
|
||||
const char *&s) const;
|
||||
|
||||
template const fmt::BasicFormatter<char>::ArgInfo
|
||||
&fmt::BasicFormatter<char>::ParseArgIndex(const char *&s);
|
||||
template const fmt::BasicWriter<char>::ArgInfo
|
||||
&fmt::BasicWriter<char>::FormatParser::ParseArgIndex(const char *&s);
|
||||
|
||||
template void fmt::BasicFormatter<char>::CheckSign(
|
||||
template void fmt::BasicWriter<char>::FormatParser::CheckSign(
|
||||
const char *&s, const ArgInfo &arg);
|
||||
|
||||
template void fmt::BasicFormatter<char>::DoFormat();
|
||||
template void fmt::BasicWriter<char>::FormatParser::Format(
|
||||
BasicWriter<char> &writer, BasicStringRef<char> format,
|
||||
std::size_t num_args, const ArgInfo *args);
|
||||
|
||||
// Explicit instantiations for wchar_t.
|
||||
|
||||
@ -726,19 +732,21 @@ template fmt::BasicWriter<wchar_t>::CharPtr
|
||||
fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
|
||||
unsigned size, const AlignSpec &spec, char sign);
|
||||
|
||||
template void fmt::BasicFormatter<wchar_t>::ReportError(
|
||||
template void fmt::BasicWriter<wchar_t>::FormatParser::ReportError(
|
||||
const wchar_t *s, StringRef message) const;
|
||||
|
||||
template unsigned fmt::BasicFormatter<wchar_t>::ParseUInt(
|
||||
template unsigned fmt::BasicWriter<wchar_t>::FormatParser::ParseUInt(
|
||||
const wchar_t *&s) const;
|
||||
|
||||
template const fmt::BasicFormatter<wchar_t>::ArgInfo
|
||||
&fmt::BasicFormatter<wchar_t>::ParseArgIndex(const wchar_t *&s);
|
||||
template const fmt::BasicWriter<wchar_t>::ArgInfo
|
||||
&fmt::BasicWriter<wchar_t>::FormatParser::ParseArgIndex(const wchar_t *&s);
|
||||
|
||||
template void fmt::BasicFormatter<wchar_t>::CheckSign(
|
||||
template void fmt::BasicWriter<wchar_t>::FormatParser::CheckSign(
|
||||
const wchar_t *&s, const ArgInfo &arg);
|
||||
|
||||
template void fmt::BasicFormatter<wchar_t>::DoFormat();
|
||||
template void fmt::BasicWriter<wchar_t>::FormatParser::Format(
|
||||
BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
|
||||
std::size_t num_args, const ArgInfo *args);
|
||||
|
||||
#if _MSC_VER
|
||||
# pragma warning(pop)
|
||||
|
393
format.h
393
format.h
@ -87,6 +87,14 @@ namespace fmt {
|
||||
FMT_GCC_EXTENSION typedef long long LongLong;
|
||||
FMT_GCC_EXTENSION typedef unsigned long long ULongLong;
|
||||
|
||||
template <typename Char>
|
||||
class BasicWriter;
|
||||
|
||||
template <typename Char>
|
||||
class BasicFormatter;
|
||||
|
||||
struct FormatSpec;
|
||||
|
||||
namespace internal {
|
||||
|
||||
enum { INLINE_BUFFER_SIZE = 500 };
|
||||
@ -324,6 +332,10 @@ void FormatDecimal(Char *buffer, UInt value, unsigned num_digits) {
|
||||
buffer[1] = internal::DIGITS[index + 1];
|
||||
buffer[0] = internal::DIGITS[index];
|
||||
}
|
||||
|
||||
template <typename Char, typename T>
|
||||
void FormatCustomArg(
|
||||
BasicWriter<Char> &w, const void *arg, const FormatSpec &spec);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -607,9 +619,6 @@ inline StrFormatSpec<wchar_t> pad(
|
||||
return StrFormatSpec<wchar_t>(str, width, fill);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
class BasicFormatter;
|
||||
|
||||
/**
|
||||
\rst
|
||||
This template provides operations for formatting and writing data into
|
||||
@ -696,7 +705,176 @@ class BasicWriter {
|
||||
// Do not implement!
|
||||
void operator<<(typename internal::CharTraits<Char>::UnsupportedStrType);
|
||||
|
||||
public:
|
||||
enum Type {
|
||||
// Numeric types should go first.
|
||||
INT, UINT, LONG, ULONG, LONG_LONG, ULONG_LONG, DOUBLE, LONG_DOUBLE,
|
||||
LAST_NUMERIC_TYPE = LONG_DOUBLE,
|
||||
CHAR, STRING, WSTRING, POINTER, CUSTOM
|
||||
};
|
||||
|
||||
struct StringValue {
|
||||
const Char *value;
|
||||
std::size_t size;
|
||||
};
|
||||
|
||||
typedef void (*FormatFunc)(
|
||||
BasicWriter<Char> &w, const void *arg, const FormatSpec &spec);
|
||||
|
||||
struct CustomValue {
|
||||
const void *value;
|
||||
FormatFunc format;
|
||||
};
|
||||
|
||||
// Information about a format argument. It is a POD type to allow
|
||||
// storage in internal::Array.
|
||||
struct ArgInfo {
|
||||
Type type;
|
||||
union {
|
||||
int int_value;
|
||||
unsigned uint_value;
|
||||
double double_value;
|
||||
long long_value;
|
||||
unsigned long ulong_value;
|
||||
LongLong long_long_value;
|
||||
ULongLong ulong_long_value;
|
||||
long double long_double_value;
|
||||
const void *pointer_value;
|
||||
StringValue string;
|
||||
CustomValue custom;
|
||||
};
|
||||
};
|
||||
|
||||
// A wrapper around a format argument used to ensure that the formatting
|
||||
// is performed before the argument is destroyed. It is private so that
|
||||
// its objects are only created by automatic conversions and not by users.
|
||||
// Example:
|
||||
//
|
||||
// Format("{}") << std::string("test");
|
||||
//
|
||||
// Here an Arg object that wraps a temporary string is automatically
|
||||
// created. It triggers formatting when destroyed which makes sure that
|
||||
// the temporary string is still alive at the time of the formatting.
|
||||
class Arg : public ArgInfo {
|
||||
private:
|
||||
// This method is private to disallow formatting of arbitrary pointers.
|
||||
// If you want to output a pointer cast it to const void*. Do not implement!
|
||||
template <typename T>
|
||||
Arg(const T *value);
|
||||
|
||||
// This method is private to disallow formatting of arbitrary pointers.
|
||||
// If you want to output a pointer cast it to void*. Do not implement!
|
||||
template <typename T>
|
||||
Arg(T *value);
|
||||
|
||||
public:
|
||||
mutable BasicFormatter<Char> *formatter;
|
||||
using ArgInfo::type;
|
||||
|
||||
Arg(short value) : formatter(0) { type = INT; this->int_value = value; }
|
||||
Arg(unsigned short value)
|
||||
: formatter(0) { type = UINT; this->int_value = value; }
|
||||
Arg(int value) : formatter(0) { type = INT; this->int_value = value; }
|
||||
Arg(unsigned value)
|
||||
: formatter(0) { type = UINT; this->uint_value = value; }
|
||||
Arg(long value) : formatter(0) { type = LONG; this->long_value = value; }
|
||||
Arg(unsigned long value)
|
||||
: formatter(0) { type = ULONG; this->ulong_value = value; }
|
||||
Arg(LongLong value)
|
||||
: formatter(0) { type = LONG_LONG; this->long_long_value = value; }
|
||||
Arg(ULongLong value)
|
||||
: formatter(0) { type = ULONG_LONG; this->ulong_long_value = value; }
|
||||
Arg(float value)
|
||||
: formatter(0) { type = DOUBLE; this->double_value = value; }
|
||||
Arg(double value)
|
||||
: formatter(0) { type = DOUBLE; this->double_value = value; }
|
||||
Arg(long double value)
|
||||
: formatter(0) { type = LONG_DOUBLE; this->long_double_value = value; }
|
||||
Arg(char value) : formatter(0) { type = CHAR; this->int_value = value; }
|
||||
Arg(wchar_t value) : formatter(0) {
|
||||
type = CHAR;
|
||||
this->int_value = internal::CharTraits<Char>::ConvertChar(value);
|
||||
}
|
||||
|
||||
Arg(const Char *value) : formatter(0) {
|
||||
type = STRING;
|
||||
this->string.value = value;
|
||||
this->string.size = 0;
|
||||
}
|
||||
|
||||
Arg(Char *value) : formatter(0) {
|
||||
type = STRING;
|
||||
this->string.value = value;
|
||||
this->string.size = 0;
|
||||
}
|
||||
|
||||
Arg(const void *value) : formatter(0) {
|
||||
type = POINTER;
|
||||
this->pointer_value = value;
|
||||
}
|
||||
|
||||
Arg(void *value) : formatter(0) {
|
||||
type = POINTER;
|
||||
this->pointer_value = value;
|
||||
}
|
||||
|
||||
Arg(const std::basic_string<Char> &value) : formatter(0) {
|
||||
type = STRING;
|
||||
this->string.value = value.c_str();
|
||||
this->string.size = value.size();
|
||||
}
|
||||
|
||||
Arg(BasicStringRef<Char> value) : formatter(0) {
|
||||
type = STRING;
|
||||
this->string.value = value.c_str();
|
||||
this->string.size = value.size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Arg(const T &value) : formatter(0) {
|
||||
type = CUSTOM;
|
||||
this->custom.value = &value;
|
||||
this->custom.format = &internal::FormatCustomArg<Char, T>;
|
||||
}
|
||||
|
||||
~Arg() FMT_NOEXCEPT(false) {
|
||||
// Format is called here to make sure that a referred object is
|
||||
// still alive, for example:
|
||||
//
|
||||
// Print("{}") << std::string("test");
|
||||
//
|
||||
// Here an Arg object refers to a temporary std::string which is
|
||||
// destroyed at the end of the statement. Since the string object is
|
||||
// constructed before the Arg object, it will be destroyed after,
|
||||
// so it will be alive in the Arg's destructor where Format is called.
|
||||
// Note that the string object will not necessarily be alive when
|
||||
// the destructor of BasicFormatter is called.
|
||||
if (formatter)
|
||||
formatter->CompleteFormatting();
|
||||
}
|
||||
};
|
||||
|
||||
class FormatParser {
|
||||
private:
|
||||
std::size_t num_args_;
|
||||
const ArgInfo *args_;
|
||||
int num_open_braces_;
|
||||
int next_arg_index_;
|
||||
|
||||
void ReportError(const Char *s, StringRef message) const;
|
||||
|
||||
unsigned ParseUInt(const Char *&s) const;
|
||||
|
||||
// Parses argument index and returns an argument with this index.
|
||||
const ArgInfo &ParseArgIndex(const Char *&s);
|
||||
|
||||
void CheckSign(const Char *&s, const ArgInfo &arg);
|
||||
|
||||
public:
|
||||
void Format(BasicWriter<Char> &writer,
|
||||
BasicStringRef<Char> format, std::size_t num_args, const ArgInfo *args);
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
Returns the number of characters written to the output buffer.
|
||||
*/
|
||||
@ -752,6 +930,20 @@ class BasicWriter {
|
||||
*/
|
||||
BasicFormatter<Char> Format(StringRef format);
|
||||
|
||||
// TODO: ArgInfo should be made public for this to be usable
|
||||
inline void VFormat(BasicStringRef<Char> format,
|
||||
std::size_t num_args, const ArgInfo *args) {
|
||||
FormatParser().Format(*this, format, num_args, args);
|
||||
}
|
||||
|
||||
#if FMT_USE_VARIADIC_TEMPLATES
|
||||
template<typename... Args>
|
||||
void Format(BasicStringRef<Char> format, const Args & ... args) {
|
||||
Arg arg_array[] = {args...};
|
||||
VFormat(format, sizeof...(Args), arg_array);
|
||||
}
|
||||
#endif
|
||||
|
||||
BasicWriter &operator<<(int value) {
|
||||
return *this << IntFormatSpec<int>(value);
|
||||
}
|
||||
@ -981,162 +1173,15 @@ class BasicFormatter {
|
||||
private:
|
||||
BasicWriter<Char> *writer_;
|
||||
|
||||
enum Type {
|
||||
// Numeric types should go first.
|
||||
INT, UINT, LONG, ULONG, LONG_LONG, ULONG_LONG, DOUBLE, LONG_DOUBLE,
|
||||
LAST_NUMERIC_TYPE = LONG_DOUBLE,
|
||||
CHAR, STRING, WSTRING, POINTER, CUSTOM
|
||||
};
|
||||
|
||||
typedef void (*FormatFunc)(
|
||||
BasicWriter<Char> &w, const void *arg, const FormatSpec &spec);
|
||||
|
||||
struct StringValue {
|
||||
const Char *value;
|
||||
std::size_t size;
|
||||
};
|
||||
|
||||
struct CustomValue {
|
||||
const void *value;
|
||||
FormatFunc format;
|
||||
};
|
||||
|
||||
// Information about a format argument. It is a POD type to allow
|
||||
// storage in internal::Array.
|
||||
struct ArgInfo {
|
||||
Type type;
|
||||
union {
|
||||
int int_value;
|
||||
unsigned uint_value;
|
||||
double double_value;
|
||||
long long_value;
|
||||
unsigned long ulong_value;
|
||||
LongLong long_long_value;
|
||||
ULongLong ulong_long_value;
|
||||
long double long_double_value;
|
||||
const void *pointer_value;
|
||||
StringValue string;
|
||||
CustomValue custom;
|
||||
};
|
||||
};
|
||||
|
||||
// A wrapper around a format argument used to ensure that the formatting
|
||||
// is performed before the argument is destroyed. It is private so that
|
||||
// its objects are only created by automatic conversions and not by users.
|
||||
// Example:
|
||||
//
|
||||
// Format("{}") << std::string("test");
|
||||
//
|
||||
// Here an Arg object that wraps a temporary string is automatically
|
||||
// created. It triggers formatting when destroyed which makes sure that
|
||||
// the temporary string is still alive at the time of the formatting.
|
||||
class Arg : public ArgInfo {
|
||||
private:
|
||||
// This method is private to disallow formatting of arbitrary pointers.
|
||||
// If you want to output a pointer cast it to const void*. Do not implement!
|
||||
template <typename T>
|
||||
Arg(const T *value);
|
||||
|
||||
// This method is private to disallow formatting of arbitrary pointers.
|
||||
// If you want to output a pointer cast it to void*. Do not implement!
|
||||
template <typename T>
|
||||
Arg(T *value);
|
||||
|
||||
public:
|
||||
mutable BasicFormatter *formatter;
|
||||
using ArgInfo::type;
|
||||
|
||||
Arg(short value) : formatter(0) { type = INT; this->int_value = value; }
|
||||
Arg(unsigned short value)
|
||||
: formatter(0) { type = UINT; this->int_value = value; }
|
||||
Arg(int value) : formatter(0) { type = INT; this->int_value = value; }
|
||||
Arg(unsigned value)
|
||||
: formatter(0) { type = UINT; this->uint_value = value; }
|
||||
Arg(long value) : formatter(0) { type = LONG; this->long_value = value; }
|
||||
Arg(unsigned long value)
|
||||
: formatter(0) { type = ULONG; this->ulong_value = value; }
|
||||
Arg(LongLong value)
|
||||
: formatter(0) { type = LONG_LONG; this->long_long_value = value; }
|
||||
Arg(ULongLong value)
|
||||
: formatter(0) { type = ULONG_LONG; this->ulong_long_value = value; }
|
||||
Arg(float value)
|
||||
: formatter(0) { type = DOUBLE; this->double_value = value; }
|
||||
Arg(double value)
|
||||
: formatter(0) { type = DOUBLE; this->double_value = value; }
|
||||
Arg(long double value)
|
||||
: formatter(0) { type = LONG_DOUBLE; this->long_double_value = value; }
|
||||
Arg(char value) : formatter(0) { type = CHAR; this->int_value = value; }
|
||||
Arg(wchar_t value) : formatter(0) {
|
||||
type = CHAR;
|
||||
this->int_value = internal::CharTraits<Char>::ConvertChar(value);
|
||||
}
|
||||
|
||||
Arg(const Char *value) : formatter(0) {
|
||||
type = STRING;
|
||||
this->string.value = value;
|
||||
this->string.size = 0;
|
||||
}
|
||||
|
||||
Arg(Char *value) : formatter(0) {
|
||||
type = STRING;
|
||||
this->string.value = value;
|
||||
this->string.size = 0;
|
||||
}
|
||||
|
||||
Arg(const void *value) : formatter(0) {
|
||||
type = POINTER;
|
||||
this->pointer_value = value;
|
||||
}
|
||||
|
||||
Arg(void *value) : formatter(0) {
|
||||
type = POINTER;
|
||||
this->pointer_value = value;
|
||||
}
|
||||
|
||||
Arg(const std::basic_string<Char> &value) : formatter(0) {
|
||||
type = STRING;
|
||||
this->string.value = value.c_str();
|
||||
this->string.size = value.size();
|
||||
}
|
||||
|
||||
Arg(BasicStringRef<Char> value) : formatter(0) {
|
||||
type = STRING;
|
||||
this->string.value = value.c_str();
|
||||
this->string.size = value.size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Arg(const T &value) : formatter(0) {
|
||||
type = CUSTOM;
|
||||
this->custom.value = &value;
|
||||
this->custom.format = &internal::FormatCustomArg<Char, T>;
|
||||
}
|
||||
|
||||
~Arg() FMT_NOEXCEPT(false) {
|
||||
// Format is called here to make sure that a referred object is
|
||||
// still alive, for example:
|
||||
//
|
||||
// Print("{}") << std::string("test");
|
||||
//
|
||||
// Here an Arg object refers to a temporary std::string which is
|
||||
// destroyed at the end of the statement. Since the string object is
|
||||
// constructed before the Arg object, it will be destroyed after,
|
||||
// so it will be alive in the Arg's destructor where Format is called.
|
||||
// Note that the string object will not necessarily be alive when
|
||||
// the destructor of BasicFormatter is called.
|
||||
if (formatter)
|
||||
formatter->CompleteFormatting();
|
||||
}
|
||||
};
|
||||
typedef typename BasicWriter<Char>::ArgInfo ArgInfo;
|
||||
|
||||
enum { NUM_INLINE_ARGS = 10 };
|
||||
internal::Array<ArgInfo, NUM_INLINE_ARGS> args_; // Format arguments.
|
||||
|
||||
const Char *format_; // Format string.
|
||||
int num_open_braces_;
|
||||
int next_arg_index_;
|
||||
|
||||
friend class internal::FormatterProxy<Char>;
|
||||
friend class BasicWriter<Char>::Arg; // TODO: remove (currently used for CompleteFormatting to be accessible)
|
||||
|
||||
// Forbid copying from a temporary as in the following example:
|
||||
// fmt::Formatter<> f = Format("test"); // not allowed
|
||||
@ -1146,19 +1191,6 @@ class BasicFormatter {
|
||||
BasicFormatter(const BasicFormatter &);
|
||||
BasicFormatter& operator=(const BasicFormatter &);
|
||||
|
||||
void ReportError(const Char *s, StringRef message) const;
|
||||
|
||||
unsigned ParseUInt(const Char *&s) const;
|
||||
|
||||
// Parses argument index and returns an argument with this index.
|
||||
const ArgInfo &ParseArgIndex(const Char *&s);
|
||||
|
||||
void CheckSign(const Char *&s, const ArgInfo &arg);
|
||||
|
||||
// Parses the format string and performs the actual formatting,
|
||||
// writing the output to writer_.
|
||||
void DoFormat();
|
||||
|
||||
struct Proxy {
|
||||
BasicWriter<Char> *writer;
|
||||
const Char *format;
|
||||
@ -1175,7 +1207,9 @@ class BasicFormatter {
|
||||
|
||||
void CompleteFormatting() {
|
||||
if (!format_) return;
|
||||
DoFormat();
|
||||
const Char *format = format_;
|
||||
format_ = 0;
|
||||
writer_->VFormat(format, args_.size(), &args_[0]);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -1184,21 +1218,6 @@ class BasicFormatter {
|
||||
BasicFormatter(BasicWriter<Char> &w, const Char *format = 0)
|
||||
: writer_(&w), format_(format) {}
|
||||
|
||||
#if FMT_USE_VARIADIC_TEMPLATES
|
||||
// Constructs a formatter with variable number of arguments.
|
||||
template<typename... Args>
|
||||
BasicFormatter(
|
||||
BasicWriter<Char> &w, const Char *format, const Args & ... args)
|
||||
: writer_(&w), format_(format) {
|
||||
std::size_t num_args = sizeof...(Args);
|
||||
Arg arg_array[] = {args...};
|
||||
// TODO: use array directly instead of copying
|
||||
args_.reserve(num_args);
|
||||
for (std::size_t i = 0; i < num_args; ++i)
|
||||
args_.push_back(arg_array[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Performs formatting if the format string is non-null. The format string
|
||||
// can be null if its ownership has been transferred to another formatter.
|
||||
~BasicFormatter() {
|
||||
@ -1210,7 +1229,7 @@ class BasicFormatter {
|
||||
}
|
||||
|
||||
// Feeds an argument to a formatter.
|
||||
BasicFormatter &operator<<(const Arg &arg) {
|
||||
BasicFormatter &operator<<(const typename BasicWriter<Char>::Arg &arg) {
|
||||
arg.formatter = this;
|
||||
args_.push_back(arg);
|
||||
return *this;
|
||||
@ -1526,15 +1545,15 @@ inline Formatter<ColorWriter> PrintColored(Color c, StringRef format) {
|
||||
template<typename... Args>
|
||||
inline std::string Format(const StringRef &format, const Args & ... args) {
|
||||
Writer w;
|
||||
BasicFormatter<char> f(w, format.c_str(), args...);
|
||||
return fmt::str(f);
|
||||
w.Format(format, args...);
|
||||
return fmt::str(w);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline std::wstring Format(const WStringRef &format, const Args & ... args) {
|
||||
WWriter w;
|
||||
BasicFormatter<wchar_t> f(w, format.c_str(), args...);
|
||||
return fmt::str(f);
|
||||
w.Format(format, args...);
|
||||
return fmt::str(w);
|
||||
}
|
||||
#endif // FMT_USE_VARIADIC_TEMPLATES
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user