mirror of
https://github.com/fmtlib/fmt.git
synced 2025-01-27 15:35:18 +00:00
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 '{'
|
// FormatError reporting unmatched '{'. The idea is that unmatched '{'
|
||||||
// should override other errors.
|
// should override other errors.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void fmt::BasicFormatter<Char>::ReportError(
|
void fmt::BasicWriter<Char>::FormatParser::ReportError(
|
||||||
const Char *s, StringRef message) const {
|
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 == '{') {
|
||||||
@ -375,7 +375,7 @@ void fmt::BasicFormatter<Char>::ReportError(
|
|||||||
// 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.
|
||||||
template <typename Char>
|
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');
|
assert('0' <= *s && *s <= '9');
|
||||||
unsigned value = 0;
|
unsigned value = 0;
|
||||||
do {
|
do {
|
||||||
@ -388,8 +388,8 @@ unsigned fmt::BasicFormatter<Char>::ParseUInt(const Char *&s) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
inline const typename fmt::BasicFormatter<Char>::ArgInfo
|
inline const typename fmt::BasicWriter<Char>::ArgInfo
|
||||||
&fmt::BasicFormatter<Char>::ParseArgIndex(const Char *&s) {
|
&fmt::BasicWriter<Char>::FormatParser::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 != ':')
|
||||||
@ -407,32 +407,35 @@ inline const typename fmt::BasicFormatter<Char>::ArgInfo
|
|||||||
next_arg_index_ = -1;
|
next_arg_index_ = -1;
|
||||||
arg_index = ParseUInt(s);
|
arg_index = ParseUInt(s);
|
||||||
}
|
}
|
||||||
if (arg_index >= args_.size())
|
if (arg_index >= num_args_)
|
||||||
ReportError(s, "argument index is out of range in format");
|
ReportError(s, "argument index is out of range in format");
|
||||||
return args_[arg_index];
|
return args_[arg_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
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);
|
char sign = static_cast<char>(*s);
|
||||||
if (arg.type > LAST_NUMERIC_TYPE) {
|
if (arg.type > LAST_NUMERIC_TYPE) {
|
||||||
ReportError(s,
|
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) {
|
if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
|
||||||
ReportError(s,
|
ReportError(s,
|
||||||
Format("format specifier '{}' requires signed argument") << sign);
|
fmt::Format("format specifier '{}' requires signed argument") << sign);
|
||||||
}
|
}
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void fmt::BasicFormatter<Char>::DoFormat() {
|
void fmt::BasicWriter<Char>::FormatParser::Format(
|
||||||
const Char *start = format_;
|
BasicWriter<Char> &writer, BasicStringRef<Char> format,
|
||||||
format_ = 0;
|
std::size_t num_args, const ArgInfo *args) {
|
||||||
|
const Char *start = format.c_str();
|
||||||
|
num_args_ = num_args;
|
||||||
|
args_ = args;
|
||||||
next_arg_index_ = 0;
|
next_arg_index_ = 0;
|
||||||
const Char *s = start;
|
const Char *s = start;
|
||||||
BasicWriter<Char> &writer = *writer_;
|
|
||||||
while (*s) {
|
while (*s) {
|
||||||
Char c = *s++;
|
Char c = *s++;
|
||||||
if (c != '{' && c != '}') continue;
|
if (c != '{' && c != '}') continue;
|
||||||
@ -697,18 +700,21 @@ template fmt::BasicWriter<char>::CharPtr
|
|||||||
fmt::BasicWriter<char>::PrepareFilledBuffer(
|
fmt::BasicWriter<char>::PrepareFilledBuffer(
|
||||||
unsigned size, const AlignSpec &spec, char sign);
|
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;
|
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
|
template const fmt::BasicWriter<char>::ArgInfo
|
||||||
&fmt::BasicFormatter<char>::ParseArgIndex(const char *&s);
|
&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);
|
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.
|
// Explicit instantiations for wchar_t.
|
||||||
|
|
||||||
@ -726,19 +732,21 @@ template fmt::BasicWriter<wchar_t>::CharPtr
|
|||||||
fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
|
fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
|
||||||
unsigned size, const AlignSpec &spec, char sign);
|
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;
|
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;
|
const wchar_t *&s) const;
|
||||||
|
|
||||||
template const fmt::BasicFormatter<wchar_t>::ArgInfo
|
template const fmt::BasicWriter<wchar_t>::ArgInfo
|
||||||
&fmt::BasicFormatter<wchar_t>::ParseArgIndex(const wchar_t *&s);
|
&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);
|
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
|
#if _MSC_VER
|
||||||
# pragma warning(pop)
|
# 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 long long LongLong;
|
||||||
FMT_GCC_EXTENSION typedef unsigned long long ULongLong;
|
FMT_GCC_EXTENSION typedef unsigned long long ULongLong;
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
class BasicWriter;
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
class BasicFormatter;
|
||||||
|
|
||||||
|
struct FormatSpec;
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
enum { INLINE_BUFFER_SIZE = 500 };
|
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[1] = internal::DIGITS[index + 1];
|
||||||
buffer[0] = internal::DIGITS[index];
|
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);
|
return StrFormatSpec<wchar_t>(str, width, fill);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
class BasicFormatter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
This template provides operations for formatting and writing data into
|
This template provides operations for formatting and writing data into
|
||||||
@ -696,7 +705,176 @@ class BasicWriter {
|
|||||||
// Do not implement!
|
// Do not implement!
|
||||||
void operator<<(typename internal::CharTraits<Char>::UnsupportedStrType);
|
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.
|
Returns the number of characters written to the output buffer.
|
||||||
*/
|
*/
|
||||||
@ -752,6 +930,20 @@ class BasicWriter {
|
|||||||
*/
|
*/
|
||||||
BasicFormatter<Char> Format(StringRef format);
|
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) {
|
BasicWriter &operator<<(int value) {
|
||||||
return *this << IntFormatSpec<int>(value);
|
return *this << IntFormatSpec<int>(value);
|
||||||
}
|
}
|
||||||
@ -981,162 +1173,15 @@ class BasicFormatter {
|
|||||||
private:
|
private:
|
||||||
BasicWriter<Char> *writer_;
|
BasicWriter<Char> *writer_;
|
||||||
|
|
||||||
enum Type {
|
typedef typename BasicWriter<Char>::ArgInfo ArgInfo;
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { NUM_INLINE_ARGS = 10 };
|
enum { NUM_INLINE_ARGS = 10 };
|
||||||
internal::Array<ArgInfo, NUM_INLINE_ARGS> args_; // Format arguments.
|
internal::Array<ArgInfo, NUM_INLINE_ARGS> args_; // Format arguments.
|
||||||
|
|
||||||
const Char *format_; // Format string.
|
const Char *format_; // Format string.
|
||||||
int num_open_braces_;
|
|
||||||
int next_arg_index_;
|
|
||||||
|
|
||||||
friend class internal::FormatterProxy<Char>;
|
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:
|
// Forbid copying from a temporary as in the following example:
|
||||||
// fmt::Formatter<> f = Format("test"); // not allowed
|
// fmt::Formatter<> f = Format("test"); // not allowed
|
||||||
@ -1146,19 +1191,6 @@ class BasicFormatter {
|
|||||||
BasicFormatter(const BasicFormatter &);
|
BasicFormatter(const BasicFormatter &);
|
||||||
BasicFormatter& operator=(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 {
|
struct Proxy {
|
||||||
BasicWriter<Char> *writer;
|
BasicWriter<Char> *writer;
|
||||||
const Char *format;
|
const Char *format;
|
||||||
@ -1175,7 +1207,9 @@ class BasicFormatter {
|
|||||||
|
|
||||||
void CompleteFormatting() {
|
void CompleteFormatting() {
|
||||||
if (!format_) return;
|
if (!format_) return;
|
||||||
DoFormat();
|
const Char *format = format_;
|
||||||
|
format_ = 0;
|
||||||
|
writer_->VFormat(format, args_.size(), &args_[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -1184,21 +1218,6 @@ class BasicFormatter {
|
|||||||
BasicFormatter(BasicWriter<Char> &w, const Char *format = 0)
|
BasicFormatter(BasicWriter<Char> &w, const Char *format = 0)
|
||||||
: writer_(&w), format_(format) {}
|
: 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
|
// Performs formatting if the format string is non-null. The format string
|
||||||
// can be null if its ownership has been transferred to another formatter.
|
// can be null if its ownership has been transferred to another formatter.
|
||||||
~BasicFormatter() {
|
~BasicFormatter() {
|
||||||
@ -1210,7 +1229,7 @@ class BasicFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Feeds an argument to a formatter.
|
// Feeds an argument to a formatter.
|
||||||
BasicFormatter &operator<<(const Arg &arg) {
|
BasicFormatter &operator<<(const typename BasicWriter<Char>::Arg &arg) {
|
||||||
arg.formatter = this;
|
arg.formatter = this;
|
||||||
args_.push_back(arg);
|
args_.push_back(arg);
|
||||||
return *this;
|
return *this;
|
||||||
@ -1526,15 +1545,15 @@ inline Formatter<ColorWriter> PrintColored(Color c, StringRef format) {
|
|||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline std::string Format(const StringRef &format, const Args & ... args) {
|
inline std::string Format(const StringRef &format, const Args & ... args) {
|
||||||
Writer w;
|
Writer w;
|
||||||
BasicFormatter<char> f(w, format.c_str(), args...);
|
w.Format(format, args...);
|
||||||
return fmt::str(f);
|
return fmt::str(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline std::wstring Format(const WStringRef &format, const Args & ... args) {
|
inline std::wstring Format(const WStringRef &format, const Args & ... args) {
|
||||||
WWriter w;
|
WWriter w;
|
||||||
BasicFormatter<wchar_t> f(w, format.c_str(), args...);
|
w.Format(format, args...);
|
||||||
return fmt::str(f);
|
return fmt::str(w);
|
||||||
}
|
}
|
||||||
#endif // FMT_USE_VARIADIC_TEMPLATES
|
#endif // FMT_USE_VARIADIC_TEMPLATES
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user