TempFormatter -> Formatter. Complete refactoring.
This commit is contained in:
parent
50cf5e17a7
commit
ca171307f3
230
format.h
230
format.h
@ -237,7 +237,7 @@ class FormatterProxy;
|
|||||||
or as a result of a formatting operation. It is most useful as a parameter
|
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::
|
type to allow passing different types of strings in a function, for example::
|
||||||
|
|
||||||
TempFormatter<> Format(StringRef format);
|
Formatter<> Format(StringRef format);
|
||||||
|
|
||||||
Format("{}") << 42;
|
Format("{}") << 42;
|
||||||
Format(std::string("{}")) << 42;
|
Format(std::string("{}")) << 42;
|
||||||
@ -432,25 +432,17 @@ DEFINE_INT_FORMATTERS(long)
|
|||||||
DEFINE_INT_FORMATTERS(unsigned)
|
DEFINE_INT_FORMATTERS(unsigned)
|
||||||
DEFINE_INT_FORMATTERS(unsigned long)
|
DEFINE_INT_FORMATTERS(unsigned long)
|
||||||
|
|
||||||
template <typename Action>
|
template <typename Char>
|
||||||
class BasicFormatter;
|
class BasicFormatter;
|
||||||
|
|
||||||
template <typename Action, typename Char>
|
|
||||||
class TempFormatter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
A formatting action that does nothing.
|
|
||||||
*/
|
|
||||||
class NoAction {
|
|
||||||
public:
|
|
||||||
/** Does nothing. */
|
|
||||||
template <typename Char>
|
|
||||||
void operator()(const BasicFormatter<Char> &) const {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
class BasicWriter {
|
class BasicWriter {
|
||||||
protected:
|
private:
|
||||||
|
enum { INLINE_BUFFER_SIZE = 500 };
|
||||||
|
mutable internal::Array<Char, INLINE_BUFFER_SIZE> buffer_; // Output buffer.
|
||||||
|
|
||||||
|
friend class BasicFormatter<Char>;
|
||||||
|
|
||||||
#if _SECURE_SCL
|
#if _SECURE_SCL
|
||||||
typedef stdext::checked_array_iterator<Char*> CharPtr;
|
typedef stdext::checked_array_iterator<Char*> CharPtr;
|
||||||
static Char *GetBase(CharPtr p) { return p.base(); }
|
static Char *GetBase(CharPtr p) { return p.base(); }
|
||||||
@ -459,17 +451,12 @@ class BasicWriter {
|
|||||||
static Char *GetBase(Char *p) { return p; }
|
static Char *GetBase(Char *p) { return p; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
|
||||||
static void FormatDecimal(
|
static void FormatDecimal(
|
||||||
CharPtr buffer, uint64_t value, unsigned num_digits);
|
CharPtr buffer, uint64_t value, unsigned num_digits);
|
||||||
|
|
||||||
protected:
|
|
||||||
static CharPtr FillPadding(CharPtr buffer,
|
static CharPtr FillPadding(CharPtr buffer,
|
||||||
unsigned total_size, std::size_t content_size, char fill);
|
unsigned total_size, std::size_t content_size, char fill);
|
||||||
|
|
||||||
enum { INLINE_BUFFER_SIZE = 500 };
|
|
||||||
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.
|
||||||
CharPtr GrowBuffer(std::size_t n) {
|
CharPtr GrowBuffer(std::size_t n) {
|
||||||
@ -560,12 +547,10 @@ private:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
Formats a string appending the output to the internal buffer.
|
Formats a string appending the output to the internal buffer.
|
||||||
Arguments are accepted through the returned `TempFormatter` object
|
Arguments are accepted through the returned `BasicFormatter` object
|
||||||
using inserter operator `<<`.
|
using inserter operator `<<`.
|
||||||
*/
|
*/
|
||||||
TempFormatter<NoAction, Char> Format(StringRef format) {
|
BasicFormatter<Char> Format(StringRef format);
|
||||||
return TempFormatter<NoAction, Char>(format);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clear() {
|
void Clear() {
|
||||||
buffer_.clear();
|
buffer_.clear();
|
||||||
@ -881,6 +866,11 @@ BasicWriter<Char> &BasicWriter<Char>::operator<<(
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
BasicFormatter<Char> BasicWriter<Char>::Format(StringRef format) {
|
||||||
|
return BasicFormatter<Char>(*this, format.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
typedef BasicWriter<char> Writer;
|
typedef BasicWriter<char> Writer;
|
||||||
typedef BasicWriter<wchar_t> WWriter;
|
typedef BasicWriter<wchar_t> WWriter;
|
||||||
|
|
||||||
@ -907,6 +897,7 @@ void FormatCustomArg(
|
|||||||
functionality similar to Python's `str.format
|
functionality similar to Python's `str.format
|
||||||
<http://docs.python.org/3/library/stdtypes.html#str.format>`__.
|
<http://docs.python.org/3/library/stdtypes.html#str.format>`__.
|
||||||
The output is stored in a memory buffer that grows dynamically.
|
The output is stored in a memory buffer that grows dynamically.
|
||||||
|
The class provides operator<< for feeding formatting arguments.
|
||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
|
|
||||||
@ -923,11 +914,16 @@ void FormatCustomArg(
|
|||||||
(-3.140000, +3.140000)
|
(-3.140000, +3.140000)
|
||||||
|
|
||||||
The buffer can be accessed using :meth:`data` or :meth:`c_str`.
|
The buffer can be accessed using :meth:`data` or :meth:`c_str`.
|
||||||
|
|
||||||
|
Objects of this class normally exists only as temporaries returned
|
||||||
|
by one of the formatting functions.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
class BasicFormatter : public BasicWriter<Char> {
|
class BasicFormatter {
|
||||||
private:
|
private:
|
||||||
|
BasicWriter<Char> *writer_;
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
// Numeric types should go first.
|
// Numeric types should go first.
|
||||||
INT, UINT, LONG, ULONG, DOUBLE, LONG_DOUBLE,
|
INT, UINT, LONG, ULONG, DOUBLE, LONG_DOUBLE,
|
||||||
@ -1026,7 +1022,7 @@ class BasicFormatter : public BasicWriter<Char> {
|
|||||||
// constructed before the Arg object, it will be destroyed after,
|
// constructed before the Arg object, it will be destroyed after,
|
||||||
// so it will be alive in the Arg's destructor where Format is called.
|
// 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
|
// Note that the string object will not necessarily be alive when
|
||||||
// the destructor of TempFormatter is called.
|
// the destructor of BasicFormatter is called.
|
||||||
if (formatter)
|
if (formatter)
|
||||||
formatter->CompleteFormatting();
|
formatter->CompleteFormatting();
|
||||||
}
|
}
|
||||||
@ -1039,11 +1035,12 @@ class BasicFormatter : public BasicWriter<Char> {
|
|||||||
int num_open_braces_;
|
int num_open_braces_;
|
||||||
int next_arg_index_;
|
int next_arg_index_;
|
||||||
|
|
||||||
template <typename Action, typename CharT>
|
|
||||||
friend class TempFormatter; // TODO
|
|
||||||
|
|
||||||
friend class internal::FormatterProxy<Char>;
|
friend class internal::FormatterProxy<Char>;
|
||||||
|
|
||||||
|
// Forbid copying other than from a temporary. Do not implement.
|
||||||
|
BasicFormatter(BasicFormatter &);
|
||||||
|
BasicFormatter& operator=(const BasicFormatter &);
|
||||||
|
|
||||||
void Add(const Arg &arg) {
|
void Add(const Arg &arg) {
|
||||||
args_.push_back(&arg);
|
args_.push_back(&arg);
|
||||||
}
|
}
|
||||||
@ -1059,6 +1056,20 @@ class BasicFormatter : public BasicWriter<Char> {
|
|||||||
|
|
||||||
void DoFormat();
|
void DoFormat();
|
||||||
|
|
||||||
|
struct Proxy {
|
||||||
|
BasicWriter<Char> *writer;
|
||||||
|
const Char *format;
|
||||||
|
|
||||||
|
Proxy(BasicWriter<Char> *w, const Char *fmt) : writer(w), format(fmt) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const Char *TakeFormatString() {
|
||||||
|
const Char *format = this->format_;
|
||||||
|
this->format_ = 0;
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
void CompleteFormatting() {
|
void CompleteFormatting() {
|
||||||
if (!format_) return;
|
if (!format_) return;
|
||||||
DoFormat();
|
DoFormat();
|
||||||
@ -1068,11 +1079,40 @@ class BasicFormatter : public BasicWriter<Char> {
|
|||||||
/**
|
/**
|
||||||
Constructs a formatter with an empty output buffer.
|
Constructs a formatter with an empty output buffer.
|
||||||
*/
|
*/
|
||||||
BasicFormatter(const Char *format = 0) : format_(format) {}
|
BasicFormatter(BasicWriter<Char> &w, const Char *format = 0)
|
||||||
};
|
: writer_(&w), format_(format) {}
|
||||||
|
|
||||||
typedef BasicFormatter<char> Formatter;
|
~BasicFormatter() {
|
||||||
typedef BasicFormatter<wchar_t> WFormatter;
|
CompleteFormatting();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Constructs a formatter from a proxy object.
|
||||||
|
*/
|
||||||
|
BasicFormatter(const Proxy &p) : BasicFormatter<Char>(*p.writer, p.format) {}
|
||||||
|
|
||||||
|
operator Proxy() {
|
||||||
|
const Char *format = format_;
|
||||||
|
format_ = 0;
|
||||||
|
return Proxy(writer_, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feeds an argument to a formatter.
|
||||||
|
BasicFormatter &operator<<(const Arg &arg) {
|
||||||
|
arg.formatter = this;
|
||||||
|
Add(arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator internal::FormatterProxy<Char>() {
|
||||||
|
return internal::FormatterProxy<Char>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator StringRef() {
|
||||||
|
CompleteFormatting();
|
||||||
|
return StringRef(writer_->c_str(), writer_->size());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
inline std::basic_string<Char> str(const BasicWriter<Char> &f) {
|
inline std::basic_string<Char> str(const BasicWriter<Char> &f) {
|
||||||
@ -1098,19 +1138,11 @@ class FormatterProxy {
|
|||||||
public:
|
public:
|
||||||
explicit FormatterProxy(BasicFormatter<Char> *f) : formatter_(f) {}
|
explicit FormatterProxy(BasicFormatter<Char> *f) : formatter_(f) {}
|
||||||
|
|
||||||
BasicFormatter<Char> *Format() {
|
BasicWriter<Char> *Format() {
|
||||||
formatter_->CompleteFormatting();
|
formatter_->CompleteFormatting();
|
||||||
return formatter_;
|
return formatter_->writer_;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is a transient object that normally exists only as a temporary
|
|
||||||
// returned by one of the formatting functions. It stores a reference
|
|
||||||
// to a formatter and provides operator<< that feeds arguments to the
|
|
||||||
// formatter.
|
|
||||||
template <typename Char>
|
|
||||||
class ArgInserter {
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1128,27 +1160,34 @@ inline const char *c_str(internal::FormatterProxy<char> p) {
|
|||||||
return p.Format()->c_str();
|
return p.Format()->c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
A formatting action that does nothing.
|
||||||
|
*/
|
||||||
|
class NoAction {
|
||||||
|
public:
|
||||||
|
/** Does nothing. */
|
||||||
|
template <typename Char>
|
||||||
|
void operator()(const BasicWriter<Char> &) const {}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A formatter with an action performed when formatting is complete.
|
A formatter with an action performed when formatting is complete.
|
||||||
Objects of this class normally exist only as temporaries returned
|
Objects of this class normally exist only as temporaries returned
|
||||||
by one of the formatting functions which explains the name.
|
by one of the formatting functions.
|
||||||
*/
|
*/
|
||||||
template <typename Action = NoAction, typename Char = char>
|
template <typename Action = NoAction, typename Char = char>
|
||||||
class TempFormatter {
|
class Formatter : private Action, public BasicFormatter<Char> {
|
||||||
private:
|
private:
|
||||||
friend class fmt::BasicFormatter<Char>;
|
friend class fmt::BasicFormatter<Char>;
|
||||||
friend class fmt::StringRef;
|
friend class fmt::StringRef;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BasicFormatter<Char> formatter_;
|
BasicWriter<Char> writer_;
|
||||||
Action action_;
|
|
||||||
bool inactive_;
|
bool inactive_;
|
||||||
|
|
||||||
// Forbid copying other than from a temporary. Do not implement.
|
// Forbid copying other than from a temporary. Do not implement.
|
||||||
TempFormatter(TempFormatter &);
|
Formatter(Formatter &);
|
||||||
|
Formatter& operator=(const Formatter &);
|
||||||
// Do not implement.
|
|
||||||
TempFormatter& operator=(const TempFormatter &);
|
|
||||||
|
|
||||||
struct Proxy {
|
struct Proxy {
|
||||||
const char *format;
|
const char *format;
|
||||||
@ -1160,55 +1199,42 @@ private:
|
|||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Constructs a temporary formatter with a format string and an action.
|
Constructs a formatter with a format string and an action.
|
||||||
The action should be an unary function object that takes a const
|
The action should be an unary function object that takes a const
|
||||||
reference to :cpp:class:`fmt::BasicFormatter` as an argument.
|
reference to :cpp:class:`fmt::BasicFormatter` as an argument.
|
||||||
See :cpp:class:`fmt::NoAction` and :cpp:class:`fmt::Write` for
|
See :cpp:class:`fmt::NoAction` and :cpp:class:`fmt::Write` for
|
||||||
examples of action classes.
|
examples of action classes.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
explicit TempFormatter(StringRef format, Action a = Action())
|
explicit Formatter(StringRef format, Action a = Action())
|
||||||
: formatter_(format.c_str()), action_(a), inactive_(false) {
|
: Action(a), BasicFormatter<Char>(writer_, format.c_str()),
|
||||||
|
inactive_(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Constructs a temporary formatter from a proxy object.
|
Constructs a formatter from a proxy object.
|
||||||
*/
|
*/
|
||||||
TempFormatter(const Proxy &p)
|
Formatter(const Proxy &p)
|
||||||
: formatter_(p.format), action_(p.action), inactive_(false) {}
|
: Action(p.action), BasicFormatter<Char>(writer_, p.format),
|
||||||
|
inactive_(false) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Performs the actual formatting, invokes the action and destroys the object.
|
Performs the actual formatting, invokes the action and destroys the object.
|
||||||
*/
|
*/
|
||||||
~TempFormatter() FMT_NOEXCEPT(false) {
|
~Formatter() FMT_NOEXCEPT(false) {
|
||||||
if (!inactive_) {
|
if (!inactive_) {
|
||||||
formatter_.CompleteFormatting();
|
this->CompleteFormatting();
|
||||||
action_(formatter_);
|
(*this)(writer_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Converts a temporary formatter into a proxy object.
|
Converts the formatter into a proxy object.
|
||||||
*/
|
*/
|
||||||
operator Proxy() {
|
operator Proxy() {
|
||||||
inactive_ = true;
|
inactive_ = true;
|
||||||
return Proxy(formatter_.format_, action_);
|
return Proxy(this->TakeFormatString(), *this);
|
||||||
}
|
|
||||||
|
|
||||||
// Feeds an argument to a formatter.
|
|
||||||
TempFormatter &operator<<(const typename BasicFormatter<Char>::Arg &arg) {
|
|
||||||
arg.formatter = &formatter_;
|
|
||||||
formatter_.Add(arg);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator internal::FormatterProxy<Char>() {
|
|
||||||
return internal::FormatterProxy<Char>(&formatter_);
|
|
||||||
}
|
|
||||||
|
|
||||||
operator StringRef() {
|
|
||||||
formatter_.CompleteFormatting();
|
|
||||||
return StringRef(formatter_.c_str(), formatter_.size());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1229,22 +1255,22 @@ private:
|
|||||||
See also `Format String Syntax`_.
|
See also `Format String Syntax`_.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
inline TempFormatter<> Format(StringRef format) {
|
inline Formatter<> Format(StringRef format) {
|
||||||
return TempFormatter<>(format);
|
return Formatter<>(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A formatting action that writes formatted output to stdout.
|
// A formatting action that writes formatted output to stdout.
|
||||||
struct Write {
|
struct Write {
|
||||||
void operator()(const BasicFormatter<char> &f) const {
|
void operator()(const BasicWriter<char> &w) const {
|
||||||
std::fwrite(f.data(), 1, f.size(), stdout);
|
std::fwrite(w.data(), 1, w.size(), stdout);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Formats a string and prints it to stdout.
|
// Formats a string and prints it to stdout.
|
||||||
// Example:
|
// Example:
|
||||||
// Print("Elapsed time: {0:.2f} seconds") << 1.23;
|
// Print("Elapsed time: {0:.2f} seconds") << 1.23;
|
||||||
inline TempFormatter<Write> Print(StringRef format) {
|
inline Formatter<Write> Print(StringRef format) {
|
||||||
return TempFormatter<Write>(format);
|
return Formatter<Write>(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Throws Exception(message) if format contains '}', otherwise throws
|
// Throws Exception(message) if format contains '}', otherwise throws
|
||||||
@ -1322,18 +1348,20 @@ void BasicFormatter<Char>::DoFormat() {
|
|||||||
format_ = 0;
|
format_ = 0;
|
||||||
next_arg_index_ = 0;
|
next_arg_index_ = 0;
|
||||||
const Char *s = start;
|
const Char *s = start;
|
||||||
|
typedef internal::Array<Char, BasicWriter<Char>::INLINE_BUFFER_SIZE> Buffer;
|
||||||
|
Writer &writer = *writer_;
|
||||||
while (*s) {
|
while (*s) {
|
||||||
char c = *s++;
|
char c = *s++;
|
||||||
if (c != '{' && c != '}') continue;
|
if (c != '{' && c != '}') continue;
|
||||||
if (*s == c) {
|
if (*s == c) {
|
||||||
this->buffer_.append(start, s);
|
writer.buffer_.append(start, s);
|
||||||
start = ++s;
|
start = ++s;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c == '}')
|
if (c == '}')
|
||||||
throw FormatError("unmatched '}' in format");
|
throw FormatError("unmatched '}' in format");
|
||||||
num_open_braces_= 1;
|
num_open_braces_= 1;
|
||||||
this->buffer_.append(start, s - 1);
|
writer.buffer_.append(start, s - 1);
|
||||||
|
|
||||||
const Arg &arg = ParseArgIndex(s);
|
const Arg &arg = ParseArgIndex(s);
|
||||||
|
|
||||||
@ -1475,22 +1503,22 @@ void BasicFormatter<Char>::DoFormat() {
|
|||||||
// Format argument.
|
// Format argument.
|
||||||
switch (arg.type) {
|
switch (arg.type) {
|
||||||
case INT:
|
case INT:
|
||||||
this->FormatInt(arg.int_value, spec);
|
writer.FormatInt(arg.int_value, spec);
|
||||||
break;
|
break;
|
||||||
case UINT:
|
case UINT:
|
||||||
this->FormatInt(arg.uint_value, spec);
|
writer.FormatInt(arg.uint_value, spec);
|
||||||
break;
|
break;
|
||||||
case LONG:
|
case LONG:
|
||||||
this->FormatInt(arg.long_value, spec);
|
writer.FormatInt(arg.long_value, spec);
|
||||||
break;
|
break;
|
||||||
case ULONG:
|
case ULONG:
|
||||||
this->FormatInt(arg.ulong_value, spec);
|
writer.FormatInt(arg.ulong_value, spec);
|
||||||
break;
|
break;
|
||||||
case DOUBLE:
|
case DOUBLE:
|
||||||
this->FormatDouble(arg.double_value, spec, precision);
|
writer.FormatDouble(arg.double_value, spec, precision);
|
||||||
break;
|
break;
|
||||||
case LONG_DOUBLE:
|
case LONG_DOUBLE:
|
||||||
this->FormatDouble(arg.long_double_value, spec, precision);
|
writer.FormatDouble(arg.long_double_value, spec, precision);
|
||||||
break;
|
break;
|
||||||
case CHAR: {
|
case CHAR: {
|
||||||
if (spec.type_ && spec.type_ != 'c')
|
if (spec.type_ && spec.type_ != 'c')
|
||||||
@ -1498,17 +1526,17 @@ void BasicFormatter<Char>::DoFormat() {
|
|||||||
typedef typename BasicWriter<Char>::CharPtr CharPtr;
|
typedef typename BasicWriter<Char>::CharPtr CharPtr;
|
||||||
CharPtr out = CharPtr();
|
CharPtr out = CharPtr();
|
||||||
if (spec.width_ > 1) {
|
if (spec.width_ > 1) {
|
||||||
out = this->GrowBuffer(spec.width_);
|
out = writer.GrowBuffer(spec.width_);
|
||||||
if (spec.align_ == ALIGN_RIGHT) {
|
if (spec.align_ == ALIGN_RIGHT) {
|
||||||
std::fill_n(out, spec.width_ - 1, spec.fill_);
|
std::fill_n(out, spec.width_ - 1, spec.fill_);
|
||||||
out += spec.width_ - 1;
|
out += spec.width_ - 1;
|
||||||
} else if (spec.align_ == ALIGN_CENTER) {
|
} else if (spec.align_ == ALIGN_CENTER) {
|
||||||
out = this->FillPadding(out, spec.width_, 1, spec.fill_);
|
out = writer.FillPadding(out, spec.width_, 1, spec.fill_);
|
||||||
} else {
|
} else {
|
||||||
std::fill_n(out + 1, spec.width_ - 1, spec.fill_);
|
std::fill_n(out + 1, spec.width_ - 1, spec.fill_);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out = this->GrowBuffer(1);
|
out = writer.GrowBuffer(1);
|
||||||
}
|
}
|
||||||
*out = arg.int_value;
|
*out = arg.int_value;
|
||||||
break;
|
break;
|
||||||
@ -1524,7 +1552,7 @@ void BasicFormatter<Char>::DoFormat() {
|
|||||||
if (*str)
|
if (*str)
|
||||||
size = std::strlen(str);
|
size = std::strlen(str);
|
||||||
}
|
}
|
||||||
this->FormatString(str, size, spec);
|
writer.FormatString(str, size, spec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case POINTER:
|
case POINTER:
|
||||||
@ -1532,19 +1560,19 @@ void BasicFormatter<Char>::DoFormat() {
|
|||||||
internal::ReportUnknownType(spec.type_, "pointer");
|
internal::ReportUnknownType(spec.type_, "pointer");
|
||||||
spec.flags_= HASH_FLAG;
|
spec.flags_= HASH_FLAG;
|
||||||
spec.type_ = 'x';
|
spec.type_ = 'x';
|
||||||
this->FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
|
writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
|
||||||
break;
|
break;
|
||||||
case CUSTOM:
|
case CUSTOM:
|
||||||
if (spec.type_)
|
if (spec.type_)
|
||||||
internal::ReportUnknownType(spec.type_, "object");
|
internal::ReportUnknownType(spec.type_, "object");
|
||||||
arg.custom.format(*this, arg.custom.value, spec);
|
arg.custom.format(writer, arg.custom.value, spec);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->buffer_.append(start, s);
|
writer.buffer_.append(start, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ using std::size_t;
|
|||||||
|
|
||||||
using fmt::internal::Array;
|
using fmt::internal::Array;
|
||||||
using fmt::BasicWriter;
|
using fmt::BasicWriter;
|
||||||
using fmt::Formatter;
|
|
||||||
using fmt::Format;
|
using fmt::Format;
|
||||||
using fmt::FormatError;
|
using fmt::FormatError;
|
||||||
using fmt::StringRef;
|
using fmt::StringRef;
|
||||||
@ -214,6 +213,13 @@ TEST(ArrayTest, Append) {
|
|||||||
EXPECT_EQ(15u, array.capacity());
|
EXPECT_EQ(15u, array.capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(WriterTest, WriterCtor) {
|
||||||
|
Writer w;
|
||||||
|
EXPECT_EQ(0u, w.size());
|
||||||
|
EXPECT_STREQ("", w.c_str());
|
||||||
|
EXPECT_EQ("", w.str());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(WriterTest, WriteInt) {
|
TEST(WriterTest, WriteInt) {
|
||||||
EXPECT_EQ("42", str(Writer() << 42));
|
EXPECT_EQ("42", str(Writer() << 42));
|
||||||
EXPECT_EQ("-42", str(Writer() << -42));
|
EXPECT_EQ("-42", str(Writer() << -42));
|
||||||
@ -325,6 +331,20 @@ TEST(WriterTest, NoConflictWithIOManip) {
|
|||||||
EXPECT_EQ("12", str(Writer() << oct(012)));
|
EXPECT_EQ("12", str(Writer() << oct(012)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(WriterTest, Format) {
|
||||||
|
Writer w;
|
||||||
|
w.Format("part{0}") << 1;
|
||||||
|
EXPECT_EQ(strlen("part1"), w.size());
|
||||||
|
EXPECT_STREQ("part1", w.c_str());
|
||||||
|
EXPECT_STREQ("part1", w.data());
|
||||||
|
EXPECT_EQ("part1", w.str());
|
||||||
|
w.Format("part{0}") << 2;
|
||||||
|
EXPECT_EQ(strlen("part1part2"), w.size());
|
||||||
|
EXPECT_STREQ("part1part2", w.c_str());
|
||||||
|
EXPECT_STREQ("part1part2", w.data());
|
||||||
|
EXPECT_EQ("part1part2", w.str());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(WriterTest, WWriter) {
|
TEST(WriterTest, WWriter) {
|
||||||
EXPECT_EQ(L"cafe", str(fmt::WWriter() << fmt::hex(0xcafe)));
|
EXPECT_EQ(L"cafe", str(fmt::WWriter() << fmt::hex(0xcafe)));
|
||||||
}
|
}
|
||||||
@ -1015,31 +1035,13 @@ TEST(FormatterTest, FormatStringFromSpeedTest) {
|
|||||||
<< reinterpret_cast<void*>(1000) << 'X'));
|
<< reinterpret_cast<void*>(1000) << 'X'));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(WriterTest, WriterCtor) {
|
TEST(FormatterTest, StringAccess) {
|
||||||
Writer w;
|
Writer w;
|
||||||
EXPECT_EQ(0u, w.size());
|
EXPECT_EQ("1", str(w.Format("{0}") << 1));
|
||||||
EXPECT_STREQ("", w.c_str());
|
EXPECT_STREQ("12", c_str(w.Format("{0}") << 2));
|
||||||
EXPECT_EQ("", w.str());
|
|
||||||
w.Format("part{0}") << 1;
|
|
||||||
w.Format("part{0}") << 2;
|
|
||||||
EXPECT_EQ("part1part2", w.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*TEST(FormatterTest, FormatterAppend) {
|
TEST(FormatterTest, FormatExamples) {
|
||||||
Formatter format;
|
|
||||||
format("part{0}") << 1;
|
|
||||||
EXPECT_EQ(strlen("part1"), format.size());
|
|
||||||
EXPECT_STREQ("part1", format.c_str());
|
|
||||||
EXPECT_STREQ("part1", format.data());
|
|
||||||
EXPECT_EQ("part1", format.str());
|
|
||||||
format("part{0}") << 2;
|
|
||||||
EXPECT_EQ(strlen("part1part2"), format.size());
|
|
||||||
EXPECT_STREQ("part1part2", format.c_str());
|
|
||||||
EXPECT_STREQ("part1part2", format.data());
|
|
||||||
EXPECT_EQ("part1part2", format.str());
|
|
||||||
}*/
|
|
||||||
|
|
||||||
TEST(FormatTest, FormatExamples) {
|
|
||||||
using fmt::hex;
|
using fmt::hex;
|
||||||
EXPECT_EQ("0000cafe", str(BasicWriter<char>() << pad(hex(0xcafe), 8, '0')));
|
EXPECT_EQ("0000cafe", str(BasicWriter<char>() << pad(hex(0xcafe), 8, '0')));
|
||||||
|
|
||||||
@ -1050,31 +1052,23 @@ TEST(FormatTest, FormatExamples) {
|
|||||||
EXPECT_EQ("42", str(Format(std::string("{}")) << 42));
|
EXPECT_EQ("42", str(Format(std::string("{}")) << 42));
|
||||||
EXPECT_EQ("42", str(Format(Format("{{}}")) << 42));
|
EXPECT_EQ("42", str(Format(Format("{{}}")) << 42));
|
||||||
|
|
||||||
// TODO
|
Writer writer;
|
||||||
/*Formatter format;
|
writer.Format("Current point:\n");
|
||||||
format("Current point:\n");
|
writer.Format("({0:+f}, {1:+f})\n") << -3.14 << 3.14;
|
||||||
format("({0:+f}, {1:+f})\n") << -3.14 << 3.14;
|
EXPECT_EQ("Current point:\n(-3.140000, +3.140000)\n", writer.str());
|
||||||
EXPECT_EQ("Current point:\n(-3.140000, +3.140000)\n", format.str());
|
|
||||||
|
|
||||||
{
|
{
|
||||||
fmt::Formatter format;
|
fmt::Writer writer;
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
format("{0}") << i;
|
writer.Format("{}") << i;
|
||||||
std::string s = format.str(); // s == 0123456789
|
std::string s = writer.str(); // s == 0123456789
|
||||||
EXPECT_EQ("0123456789", s);
|
EXPECT_EQ("0123456789", s);
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
/*TEST(FormatterTest, ArgInserter) {
|
|
||||||
Formatter format;
|
|
||||||
EXPECT_EQ("1", str(format("{0}") << 1));
|
|
||||||
EXPECT_STREQ("12", c_str(format("{0}") << 2));
|
|
||||||
}*/
|
|
||||||
|
|
||||||
TEST(FormatterTest, StrNamespace) {
|
TEST(FormatterTest, StrNamespace) {
|
||||||
fmt::str(Format(""));
|
str(Format(""));
|
||||||
fmt::c_str(Format(""));
|
c_str(Format(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, ExceptionInNestedFormat) {
|
TEST(FormatterTest, ExceptionInNestedFormat) {
|
||||||
@ -1101,7 +1095,7 @@ struct CountCalls {
|
|||||||
|
|
||||||
CountCalls(int &num_calls) : num_calls(num_calls) {}
|
CountCalls(int &num_calls) : num_calls(num_calls) {}
|
||||||
|
|
||||||
void operator()(const Formatter &) const {
|
void operator()(const Writer &) const {
|
||||||
++num_calls;
|
++num_calls;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1109,7 +1103,7 @@ struct CountCalls {
|
|||||||
TEST(TempFormatterTest, Action) {
|
TEST(TempFormatterTest, Action) {
|
||||||
int num_calls = 0;
|
int num_calls = 0;
|
||||||
{
|
{
|
||||||
fmt::TempFormatter<CountCalls> af("test", CountCalls(num_calls));
|
fmt::Formatter<CountCalls> af("test", CountCalls(num_calls));
|
||||||
EXPECT_EQ(0, num_calls);
|
EXPECT_EQ(0, num_calls);
|
||||||
}
|
}
|
||||||
EXPECT_EQ(1, num_calls);
|
EXPECT_EQ(1, num_calls);
|
||||||
@ -1118,7 +1112,7 @@ TEST(TempFormatterTest, Action) {
|
|||||||
TEST(TempFormatterTest, ActionNotCalledOnError) {
|
TEST(TempFormatterTest, ActionNotCalledOnError) {
|
||||||
int num_calls = 0;
|
int num_calls = 0;
|
||||||
{
|
{
|
||||||
typedef fmt::TempFormatter<CountCalls> TestFormatter;
|
typedef fmt::Formatter<CountCalls> TestFormatter;
|
||||||
EXPECT_THROW(TestFormatter af("{0", CountCalls(num_calls)), FormatError);
|
EXPECT_THROW(TestFormatter af("{0", CountCalls(num_calls)), FormatError);
|
||||||
}
|
}
|
||||||
EXPECT_EQ(0, num_calls);
|
EXPECT_EQ(0, num_calls);
|
||||||
@ -1131,8 +1125,8 @@ TEST(TempFormatterTest, ActionNotCalledOnError) {
|
|||||||
TEST(TempFormatterTest, ArgLifetime) {
|
TEST(TempFormatterTest, ArgLifetime) {
|
||||||
// The following code is for testing purposes only. It is a definite abuse
|
// The following code is for testing purposes only. It is a definite abuse
|
||||||
// of the API and shouldn't be used in real applications.
|
// of the API and shouldn't be used in real applications.
|
||||||
const fmt::TempFormatter<> &af = fmt::Format("{0}");
|
const fmt::Formatter<> &af = fmt::Format("{0}");
|
||||||
const_cast<fmt::TempFormatter<>&>(af) << std::string("test");
|
const_cast<fmt::Formatter<>&>(af) << std::string("test");
|
||||||
// String object passed as an argument to TempFormatter has
|
// String object passed as an argument to TempFormatter has
|
||||||
// been destroyed, but ArgInserter dtor hasn't been called yet.
|
// been destroyed, but ArgInserter dtor hasn't been called yet.
|
||||||
// But that's OK since the Arg's dtor takes care of this and
|
// But that's OK since the Arg's dtor takes care of this and
|
||||||
@ -1146,13 +1140,13 @@ TEST(TempFormatterTest, ConvertToStringRef) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct PrintError {
|
struct PrintError {
|
||||||
void operator()(const fmt::Formatter &f) const {
|
void operator()(const fmt::Writer &w) const {
|
||||||
std::cerr << "Error: " << f.str() << std::endl;
|
std::cerr << "Error: " << w.str() << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fmt::TempFormatter<PrintError> ReportError(const char *format) {
|
fmt::Formatter<PrintError> ReportError(const char *format) {
|
||||||
return fmt::TempFormatter<PrintError>(format);
|
return fmt::Formatter<PrintError>(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TempFormatterTest, Examples) {
|
TEST(TempFormatterTest, Examples) {
|
||||||
|
Loading…
Reference in New Issue
Block a user