mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 10:47:35 +02:00
Fix type safety when using custom formatters (#394)
This commit is contained in:
@ -403,72 +403,11 @@ FMT_FUNC void format_system_error(
|
|||||||
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
|
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
void internal::ArgMap<Char>::init(const format_args &args) {
|
|
||||||
if (!map_.empty())
|
|
||||||
return;
|
|
||||||
typedef internal::NamedArg<Char> NamedArg;
|
|
||||||
const NamedArg *named_arg = 0;
|
|
||||||
bool use_values =
|
|
||||||
args.type(MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
|
|
||||||
if (use_values) {
|
|
||||||
for (unsigned i = 0;/*nothing*/; ++i) {
|
|
||||||
internal::Arg::Type arg_type = args.type(i);
|
|
||||||
switch (arg_type) {
|
|
||||||
case internal::Arg::NONE:
|
|
||||||
return;
|
|
||||||
case internal::Arg::NAMED_ARG:
|
|
||||||
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
|
|
||||||
map_.push_back(Pair(named_arg->name, *named_arg));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/*nothing*/;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) {
|
|
||||||
internal::Arg::Type arg_type = args.type(i);
|
|
||||||
if (arg_type == internal::Arg::NAMED_ARG) {
|
|
||||||
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
|
|
||||||
map_.push_back(Pair(named_arg->name, *named_arg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (unsigned i = MAX_PACKED_ARGS;/*nothing*/; ++i) {
|
|
||||||
switch (args.args_[i].type) {
|
|
||||||
case internal::Arg::NONE:
|
|
||||||
return;
|
|
||||||
case internal::Arg::NAMED_ARG:
|
|
||||||
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
|
|
||||||
map_.push_back(Pair(named_arg->name, *named_arg));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/*nothing*/;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void internal::FixedBuffer<Char>::grow(std::size_t) {
|
void internal::FixedBuffer<Char>::grow(std::size_t) {
|
||||||
FMT_THROW(std::runtime_error("buffer overflow"));
|
FMT_THROW(std::runtime_error("buffer overflow"));
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC Arg internal::FormatterBase::do_get_arg(
|
|
||||||
unsigned arg_index, const char *&error) {
|
|
||||||
Arg arg = args_[arg_index];
|
|
||||||
switch (arg.type) {
|
|
||||||
case Arg::NONE:
|
|
||||||
error = "argument index out of range";
|
|
||||||
break;
|
|
||||||
case Arg::NAMED_ARG:
|
|
||||||
arg = *static_cast<const internal::Arg*>(arg.pointer);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/*nothing*/;
|
|
||||||
}
|
|
||||||
return arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_FUNC void report_system_error(
|
FMT_FUNC void report_system_error(
|
||||||
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
|
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
|
||||||
// 'fmt::' is for bcc32.
|
// 'fmt::' is for bcc32.
|
||||||
@ -505,7 +444,8 @@ template <typename Char>
|
|||||||
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format,
|
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format,
|
||||||
format_args args);
|
format_args args);
|
||||||
|
|
||||||
FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, format_args args) {
|
FMT_FUNC int vfprintf(std::FILE *f, CStringRef format,
|
||||||
|
basic_format_args<PrintfFormatter<char>> args) {
|
||||||
MemoryWriter w;
|
MemoryWriter w;
|
||||||
printf(w, format, args);
|
printf(w, format, args);
|
||||||
std::size_t size = w.size();
|
std::size_t size = w.size();
|
||||||
|
128
fmt/format.h
128
fmt/format.h
@ -1429,7 +1429,7 @@ constexpr uint64_t make_type<void>() { return 0; }
|
|||||||
enum { MAX_PACKED_ARGS = 16 };
|
enum { MAX_PACKED_ARGS = 16 };
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
template <typename ...Args>
|
template <typename Formatter, typename ...Args>
|
||||||
class format_arg_store {
|
class format_arg_store {
|
||||||
private:
|
private:
|
||||||
static const size_t NUM_ARGS = sizeof...(Args);
|
static const size_t NUM_ARGS = sizeof...(Args);
|
||||||
@ -1441,13 +1441,12 @@ class format_arg_store {
|
|||||||
// If the arguments are not packed, add one more element to mark the end.
|
// If the arguments are not packed, add one more element to mark the end.
|
||||||
std::array<value_type, NUM_ARGS + (IS_PACKED ? 0 : 1)> data_;
|
std::array<value_type, NUM_ARGS + (IS_PACKED ? 0 : 1)> data_;
|
||||||
|
|
||||||
template <typename Formatter, typename ...A>
|
template <typename ...A>
|
||||||
friend format_arg_store<A...> make_format_args(const A & ... args);
|
friend format_arg_store<Formatter, A...> make_format_args(const A & ... args);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const uint64_t TYPES = internal::make_type<Args..., void>();
|
static const uint64_t TYPES = internal::make_type<Args..., void>();
|
||||||
|
|
||||||
template <typename Formatter>
|
|
||||||
format_arg_store(const Args &... args, Formatter *)
|
format_arg_store(const Args &... args, Formatter *)
|
||||||
: data_{{internal::MakeValue<Formatter>(args)...}} {}
|
: data_{{internal::MakeValue<Formatter>(args)...}} {}
|
||||||
|
|
||||||
@ -1455,13 +1454,15 @@ class format_arg_store {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Formatter, typename ...Args>
|
template <typename Formatter, typename ...Args>
|
||||||
inline format_arg_store<Args...> make_format_args(const Args & ... args) {
|
inline format_arg_store<Formatter, Args...>
|
||||||
|
make_format_args(const Args & ... args) {
|
||||||
Formatter *f = nullptr;
|
Formatter *f = nullptr;
|
||||||
return format_arg_store<Args...>(args..., f);
|
return format_arg_store<Formatter, Args...>(args..., f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formatting arguments. */
|
/** Formatting arguments. */
|
||||||
class format_args {
|
template <typename Formatter>
|
||||||
|
class basic_format_args {
|
||||||
private:
|
private:
|
||||||
// To reduce compiled code size per formatting function call, types of first
|
// To reduce compiled code size per formatting function call, types of first
|
||||||
// MAX_PACKED_ARGS arguments are passed in the types_ field.
|
// MAX_PACKED_ARGS arguments are passed in the types_ field.
|
||||||
@ -1491,10 +1492,10 @@ class format_args {
|
|||||||
public:
|
public:
|
||||||
typedef unsigned size_type;
|
typedef unsigned size_type;
|
||||||
|
|
||||||
format_args() : types_(0) {}
|
basic_format_args() : types_(0) {}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename F, typename... Args>
|
||||||
format_args(const format_arg_store<Args...> &store)
|
basic_format_args(const format_arg_store<F, Args...> &store)
|
||||||
: types_(store.TYPES) {
|
: types_(store.TYPES) {
|
||||||
set_data(store.data());
|
set_data(store.data());
|
||||||
}
|
}
|
||||||
@ -1525,6 +1526,9 @@ class format_args {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef basic_format_args<BasicFormatter<char>> format_args;
|
||||||
|
typedef basic_format_args<BasicFormatter<wchar_t>> wformat_args;
|
||||||
|
|
||||||
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
|
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1919,7 +1923,8 @@ class ArgMap {
|
|||||||
MapType map_;
|
MapType map_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FMT_API void init(const format_args &args);
|
template <typename Formatter>
|
||||||
|
void init(const basic_format_args<Formatter> &args);
|
||||||
|
|
||||||
const internal::Arg* find(const fmt::BasicStringRef<Char> &name) const {
|
const internal::Arg* find(const fmt::BasicStringRef<Char> &name) const {
|
||||||
// The list is unsorted, so just return the first matching name.
|
// The list is unsorted, so just return the first matching name.
|
||||||
@ -1932,6 +1937,52 @@ class ArgMap {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
template <typename Formatter>
|
||||||
|
void ArgMap<Char>::init(const basic_format_args<Formatter> &args) {
|
||||||
|
if (!map_.empty())
|
||||||
|
return;
|
||||||
|
typedef internal::NamedArg<Char> NamedArg;
|
||||||
|
const NamedArg *named_arg = 0;
|
||||||
|
bool use_values =
|
||||||
|
args.type(MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
|
||||||
|
if (use_values) {
|
||||||
|
for (unsigned i = 0;/*nothing*/; ++i) {
|
||||||
|
internal::Arg::Type arg_type = args.type(i);
|
||||||
|
switch (arg_type) {
|
||||||
|
case internal::Arg::NONE:
|
||||||
|
return;
|
||||||
|
case internal::Arg::NAMED_ARG:
|
||||||
|
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
|
||||||
|
map_.push_back(Pair(named_arg->name, *named_arg));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/*nothing*/;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) {
|
||||||
|
internal::Arg::Type arg_type = args.type(i);
|
||||||
|
if (arg_type == internal::Arg::NAMED_ARG) {
|
||||||
|
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
|
||||||
|
map_.push_back(Pair(named_arg->name, *named_arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned i = MAX_PACKED_ARGS;/*nothing*/; ++i) {
|
||||||
|
switch (args.args_[i].type) {
|
||||||
|
case internal::Arg::NONE:
|
||||||
|
return;
|
||||||
|
case internal::Arg::NAMED_ARG:
|
||||||
|
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
|
||||||
|
map_.push_back(Pair(named_arg->name, *named_arg));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/*nothing*/;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Impl, typename Char>
|
template <typename Impl, typename Char>
|
||||||
class ArgFormatterBase : public ArgVisitor<Impl, void> {
|
class ArgFormatterBase : public ArgVisitor<Impl, void> {
|
||||||
private:
|
private:
|
||||||
@ -2030,21 +2081,33 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Formatter>
|
||||||
class FormatterBase {
|
class FormatterBase {
|
||||||
private:
|
private:
|
||||||
format_args args_;
|
basic_format_args<Formatter> args_;
|
||||||
int next_arg_index_;
|
int next_arg_index_;
|
||||||
|
|
||||||
// Returns the argument with specified index.
|
// Returns the argument with specified index.
|
||||||
FMT_API Arg do_get_arg(unsigned arg_index, const char *&error);
|
Arg do_get_arg(unsigned arg_index, const char *&error) {
|
||||||
|
Arg arg = args_[arg_index];
|
||||||
|
switch (arg.type) {
|
||||||
|
case Arg::NONE:
|
||||||
|
error = "argument index out of range";
|
||||||
|
break;
|
||||||
|
case Arg::NAMED_ARG:
|
||||||
|
arg = *static_cast<const internal::Arg*>(arg.pointer);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/*nothing*/;
|
||||||
|
}
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const format_args &args() const { return args_; }
|
FormatterBase(basic_format_args<Formatter> args)
|
||||||
|
: args_(args), next_arg_index_(0) {}
|
||||||
|
|
||||||
explicit FormatterBase(const format_args &args) {
|
const basic_format_args<Formatter> &args() const { return args_; }
|
||||||
args_ = args;
|
|
||||||
next_arg_index_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the next argument.
|
// Returns the next argument.
|
||||||
Arg next_arg(const char *&error) {
|
Arg next_arg(const char *&error) {
|
||||||
@ -2132,7 +2195,8 @@ class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> {
|
|||||||
|
|
||||||
/** This template formats data and writes the output to a writer. */
|
/** This template formats data and writes the output to a writer. */
|
||||||
template <typename CharType, typename ArgFormatter>
|
template <typename CharType, typename ArgFormatter>
|
||||||
class BasicFormatter : private internal::FormatterBase {
|
class BasicFormatter :
|
||||||
|
private internal::FormatterBase<BasicFormatter<CharType, ArgFormatter>> {
|
||||||
public:
|
public:
|
||||||
/** The character type for the output. */
|
/** The character type for the output. */
|
||||||
typedef CharType Char;
|
typedef CharType Char;
|
||||||
@ -2143,7 +2207,8 @@ class BasicFormatter : private internal::FormatterBase {
|
|||||||
|
|
||||||
FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter);
|
FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter);
|
||||||
|
|
||||||
using internal::FormatterBase::get_arg;
|
typedef internal::FormatterBase<BasicFormatter> Base;
|
||||||
|
using Base::get_arg;
|
||||||
|
|
||||||
// Checks if manual indexing is used and returns the argument with
|
// Checks if manual indexing is used and returns the argument with
|
||||||
// specified name.
|
// specified name.
|
||||||
@ -2163,8 +2228,8 @@ class BasicFormatter : private internal::FormatterBase {
|
|||||||
appropriate lifetimes.
|
appropriate lifetimes.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
BasicFormatter(const format_args &args, BasicWriter<Char> &w)
|
BasicFormatter(basic_format_args<BasicFormatter> args, BasicWriter<Char> &w)
|
||||||
: internal::FormatterBase(args), writer_(w) {}
|
: Base(args), writer_(w) {}
|
||||||
|
|
||||||
/** Returns a reference to the writer associated with this formatter. */
|
/** Returns a reference to the writer associated with this formatter. */
|
||||||
BasicWriter<Char> &writer() { return writer_; }
|
BasicWriter<Char> &writer() { return writer_; }
|
||||||
@ -2404,7 +2469,8 @@ class BasicWriter {
|
|||||||
return std::basic_string<Char>(&buffer_[0], buffer_.size());
|
return std::basic_string<Char>(&buffer_[0], buffer_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void vwrite(BasicCStringRef<Char> format, format_args args) {
|
void vwrite(BasicCStringRef<Char> format,
|
||||||
|
basic_format_args<BasicFormatter<Char>> args) {
|
||||||
BasicFormatter<Char>(args, *this).format(format);
|
BasicFormatter<Char>(args, *this).format(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3111,7 +3177,7 @@ inline std::string format(CStringRef format_str, const Args & ... args) {
|
|||||||
return vformat(format_str, make_format_args<BasicFormatter<char>>(args...));
|
return vformat(format_str, make_format_args<BasicFormatter<char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::wstring vformat(WCStringRef format_str, format_args args) {
|
inline std::wstring vformat(WCStringRef format_str, wformat_args args) {
|
||||||
WMemoryWriter w;
|
WMemoryWriter w;
|
||||||
w.vwrite(format_str, args);
|
w.vwrite(format_str, args);
|
||||||
return w.str();
|
return w.str();
|
||||||
@ -3348,8 +3414,8 @@ void check_sign(const Char *&s, const Arg &arg) {
|
|||||||
template <typename Char, typename AF>
|
template <typename Char, typename AF>
|
||||||
inline internal::Arg BasicFormatter<Char, AF>::get_arg(
|
inline internal::Arg BasicFormatter<Char, AF>::get_arg(
|
||||||
BasicStringRef<Char> arg_name, const char *&error) {
|
BasicStringRef<Char> arg_name, const char *&error) {
|
||||||
if (check_no_auto_index(error)) {
|
if (this->check_no_auto_index(error)) {
|
||||||
map_.init(args());
|
map_.init(this->args());
|
||||||
const internal::Arg *arg = map_.find(arg_name);
|
const internal::Arg *arg = map_.find(arg_name);
|
||||||
if (arg)
|
if (arg)
|
||||||
return *arg;
|
return *arg;
|
||||||
@ -3362,7 +3428,7 @@ template <typename Char, typename AF>
|
|||||||
inline internal::Arg BasicFormatter<Char, AF>::parse_arg_index(const Char *&s) {
|
inline internal::Arg BasicFormatter<Char, AF>::parse_arg_index(const Char *&s) {
|
||||||
const char *error = 0;
|
const char *error = 0;
|
||||||
internal::Arg arg = *s < '0' || *s > '9' ?
|
internal::Arg arg = *s < '0' || *s > '9' ?
|
||||||
next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error);
|
this->next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error);
|
||||||
if (error) {
|
if (error) {
|
||||||
FMT_THROW(format_error(
|
FMT_THROW(format_error(
|
||||||
*s != '}' && *s != ':' ? "invalid format string" : error));
|
*s != '}' && *s != ':' ? "invalid format string" : error));
|
||||||
@ -3563,18 +3629,18 @@ void BasicFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) {
|
|||||||
Char c = *s++;
|
Char c = *s++;
|
||||||
if (c != '{' && c != '}') continue;
|
if (c != '{' && c != '}') continue;
|
||||||
if (*s == c) {
|
if (*s == c) {
|
||||||
write(writer_, start, s);
|
this->write(writer_, start, s);
|
||||||
start = ++s;
|
start = ++s;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c == '}')
|
if (c == '}')
|
||||||
FMT_THROW(format_error("unmatched '}' in format string"));
|
FMT_THROW(format_error("unmatched '}' in format string"));
|
||||||
write(writer_, start, s - 1);
|
this->write(writer_, start, s - 1);
|
||||||
internal::Arg arg = internal::is_name_start(*s) ?
|
internal::Arg arg = internal::is_name_start(*s) ?
|
||||||
parse_arg_name(s) : parse_arg_index(s);
|
parse_arg_name(s) : parse_arg_index(s);
|
||||||
start = s = format(s, arg);
|
start = s = format(s, arg);
|
||||||
}
|
}
|
||||||
write(writer_, start, s);
|
this->write(writer_, start, s);
|
||||||
}
|
}
|
||||||
} // namespace fmt
|
} // namespace fmt
|
||||||
|
|
||||||
|
40
fmt/printf.h
40
fmt/printf.h
@ -262,7 +262,8 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase<Impl, Char> {
|
|||||||
|
|
||||||
/** Formats an argument of a custom (user-defined) type. */
|
/** Formats an argument of a custom (user-defined) type. */
|
||||||
void visit_custom(internal::Arg::CustomValue c) {
|
void visit_custom(internal::Arg::CustomValue c) {
|
||||||
BasicFormatter<Char> formatter(format_args(), this->writer());
|
BasicFormatter<Char> formatter(basic_format_args<BasicFormatter<Char>>(),
|
||||||
|
this->writer());
|
||||||
const Char format_str[] = {'}', 0};
|
const Char format_str[] = {'}', 0};
|
||||||
const Char *format = format_str;
|
const Char *format = format_str;
|
||||||
c.format(&formatter, c.value, &format);
|
c.format(&formatter, c.value, &format);
|
||||||
@ -281,10 +282,13 @@ class PrintfArgFormatter
|
|||||||
|
|
||||||
/** This template formats data and writes the output to a writer. */
|
/** This template formats data and writes the output to a writer. */
|
||||||
template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> >
|
template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> >
|
||||||
class PrintfFormatter : private internal::FormatterBase {
|
class PrintfFormatter :
|
||||||
|
private internal::FormatterBase<PrintfFormatter<Char, ArgFormatter>> {
|
||||||
private:
|
private:
|
||||||
BasicWriter<Char> &writer_;
|
BasicWriter<Char> &writer_;
|
||||||
|
|
||||||
|
typedef internal::FormatterBase<PrintfFormatter> Base;
|
||||||
|
|
||||||
void parse_flags(FormatSpec &spec, const Char *&s);
|
void parse_flags(FormatSpec &spec, const Char *&s);
|
||||||
|
|
||||||
// Returns the argument with specified index or, if arg_index is equal
|
// Returns the argument with specified index or, if arg_index is equal
|
||||||
@ -304,8 +308,9 @@ class PrintfFormatter : private internal::FormatterBase {
|
|||||||
appropriate lifetimes.
|
appropriate lifetimes.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
explicit PrintfFormatter(const format_args &args, BasicWriter<Char> &w)
|
explicit PrintfFormatter(basic_format_args<PrintfFormatter> args,
|
||||||
: FormatterBase(args), writer_(w) {}
|
BasicWriter<Char> &w)
|
||||||
|
: Base(args), writer_(w) {}
|
||||||
|
|
||||||
/** Formats stored arguments and writes the output to the writer. */
|
/** Formats stored arguments and writes the output to the writer. */
|
||||||
FMT_API void format(BasicCStringRef<Char> format_str);
|
FMT_API void format(BasicCStringRef<Char> format_str);
|
||||||
@ -343,7 +348,7 @@ internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s,
|
|||||||
(void)s;
|
(void)s;
|
||||||
const char *error = 0;
|
const char *error = 0;
|
||||||
internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
|
internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
|
||||||
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
|
this->next_arg(error) : Base::get_arg(arg_index - 1, error);
|
||||||
if (error)
|
if (error)
|
||||||
FMT_THROW(format_error(!*s ? "invalid format string" : error));
|
FMT_THROW(format_error(!*s ? "invalid format string" : error));
|
||||||
return arg;
|
return arg;
|
||||||
@ -391,11 +396,11 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) {
|
|||||||
Char c = *s++;
|
Char c = *s++;
|
||||||
if (c != '%') continue;
|
if (c != '%') continue;
|
||||||
if (*s == c) {
|
if (*s == c) {
|
||||||
write(writer_, start, s);
|
this->write(writer_, start, s);
|
||||||
start = ++s;
|
start = ++s;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
write(writer_, start, s - 1);
|
this->write(writer_, start, s - 1);
|
||||||
|
|
||||||
FormatSpec spec;
|
FormatSpec spec;
|
||||||
spec.align_ = ALIGN_RIGHT;
|
spec.align_ = ALIGN_RIGHT;
|
||||||
@ -480,16 +485,17 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) {
|
|||||||
// Format argument.
|
// Format argument.
|
||||||
AF(writer_, spec).visit(arg);
|
AF(writer_, spec).visit(arg);
|
||||||
}
|
}
|
||||||
write(writer_, start, s);
|
this->write(writer_, start, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format,
|
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format,
|
||||||
format_args args) {
|
basic_format_args<PrintfFormatter<Char>> args) {
|
||||||
PrintfFormatter<Char>(args, w).format(format);
|
PrintfFormatter<Char>(args, w).format(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string vsprintf(CStringRef format, format_args args) {
|
inline std::string vsprintf(CStringRef format,
|
||||||
|
basic_format_args<PrintfFormatter<char>> args) {
|
||||||
MemoryWriter w;
|
MemoryWriter w;
|
||||||
printf(w, format, args);
|
printf(w, format, args);
|
||||||
return w.str();
|
return w.str();
|
||||||
@ -509,7 +515,8 @@ inline std::string sprintf(CStringRef format_str, const Args & ... args) {
|
|||||||
return vsprintf(format_str, make_format_args<BasicFormatter<char>>(args...));
|
return vsprintf(format_str, make_format_args<BasicFormatter<char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::wstring vsprintf(WCStringRef format, format_args args) {
|
inline std::wstring vsprintf(WCStringRef format,
|
||||||
|
basic_format_args<PrintfFormatter<wchar_t>> args) {
|
||||||
WMemoryWriter w;
|
WMemoryWriter w;
|
||||||
printf(w, format, args);
|
printf(w, format, args);
|
||||||
return w.str();
|
return w.str();
|
||||||
@ -521,7 +528,8 @@ inline std::wstring sprintf(WCStringRef format_str, const Args & ... args) {
|
|||||||
return vsprintf(format_str, vargs);
|
return vsprintf(format_str, vargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_API int vfprintf(std::FILE *f, CStringRef format, format_args args);
|
FMT_API int vfprintf(std::FILE *f, CStringRef format,
|
||||||
|
basic_format_args<PrintfFormatter<char>> args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@ -534,11 +542,12 @@ FMT_API int vfprintf(std::FILE *f, CStringRef format, format_args args);
|
|||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline int fprintf(std::FILE *f, CStringRef format_str, const Args & ... args) {
|
inline int fprintf(std::FILE *f, CStringRef format_str, const Args & ... args) {
|
||||||
auto vargs = make_format_args<BasicFormatter<char>>(args...);
|
auto vargs = make_format_args<PrintfFormatter<char>>(args...);
|
||||||
return vfprintf(f, format_str, vargs);
|
return vfprintf(f, format_str, vargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int vprintf(CStringRef format, format_args args) {
|
inline int vprintf(CStringRef format,
|
||||||
|
basic_format_args<PrintfFormatter<char>> args) {
|
||||||
return vfprintf(stdout, format, args);
|
return vfprintf(stdout, format, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,7 +565,8 @@ inline int printf(CStringRef format_str, const Args & ... args) {
|
|||||||
return vprintf(format_str, make_format_args<BasicFormatter<char>>(args...));
|
return vprintf(format_str, make_format_args<BasicFormatter<char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int vfprintf(std::ostream &os, CStringRef format_str, format_args args) {
|
inline int vfprintf(std::ostream &os, CStringRef format_str,
|
||||||
|
basic_format_args<PrintfFormatter<char>> args) {
|
||||||
MemoryWriter w;
|
MemoryWriter w;
|
||||||
printf(w, format_str, args);
|
printf(w, format_str, args);
|
||||||
internal::write(os, w);
|
internal::write(os, w);
|
||||||
|
@ -45,10 +45,13 @@ class CustomPrintfArgFormatter :
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string custom_vformat(const char *format_str, fmt::format_args args) {
|
typedef fmt::BasicFormatter<char, CustomArgFormatter> CustomFormatter;
|
||||||
|
|
||||||
|
std::string custom_vformat(const char *format_str,
|
||||||
|
fmt::basic_format_args<CustomFormatter> args) {
|
||||||
fmt::MemoryWriter writer;
|
fmt::MemoryWriter writer;
|
||||||
// Pass custom argument formatter as a template arg to BasicFormatter.
|
// Pass custom argument formatter as a template arg to BasicFormatter.
|
||||||
fmt::BasicFormatter<char, CustomArgFormatter> formatter(args, writer);
|
CustomFormatter formatter(args, writer);
|
||||||
formatter.format(format_str);
|
formatter.format(format_str);
|
||||||
return writer.str();
|
return writer.str();
|
||||||
}
|
}
|
||||||
@ -59,9 +62,14 @@ std::string custom_format(const char *format_str, const Args & ... args) {
|
|||||||
return custom_vformat(format_str, va);
|
return custom_vformat(format_str, va);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string custom_vsprintf(const char* format_str, fmt::format_args args) {
|
typedef fmt::PrintfFormatter<char, CustomPrintfArgFormatter>
|
||||||
|
CustomPrintfFormatter;
|
||||||
|
|
||||||
|
std::string custom_vsprintf(
|
||||||
|
const char* format_str,
|
||||||
|
fmt::basic_format_args<CustomPrintfFormatter> args) {
|
||||||
fmt::MemoryWriter writer;
|
fmt::MemoryWriter writer;
|
||||||
fmt::PrintfFormatter<char, CustomPrintfArgFormatter> formatter(args, writer);
|
CustomPrintfFormatter formatter(args, writer);
|
||||||
formatter.format(format_str);
|
formatter.format(format_str);
|
||||||
return writer.str();
|
return writer.str();
|
||||||
}
|
}
|
||||||
|
@ -1633,16 +1633,19 @@ class MockArgFormatter :
|
|||||||
MOCK_METHOD1(visit_int, void (int value));
|
MOCK_METHOD1(visit_int, void (int value));
|
||||||
};
|
};
|
||||||
|
|
||||||
void vcustom_format(const char *format_str, fmt::format_args args) {
|
typedef fmt::BasicFormatter<char, MockArgFormatter> CustomFormatter;
|
||||||
|
|
||||||
|
void custom_vformat(const char *format_str,
|
||||||
|
fmt::basic_format_args<CustomFormatter> args) {
|
||||||
fmt::MemoryWriter writer;
|
fmt::MemoryWriter writer;
|
||||||
fmt::BasicFormatter<char, MockArgFormatter> formatter(args, writer);
|
CustomFormatter formatter(args, writer);
|
||||||
formatter.format(format_str);
|
formatter.format(format_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void custom_format(const char *format_str, const Args & ... args) {
|
void custom_format(const char *format_str, const Args & ... args) {
|
||||||
auto va = fmt::make_format_args<fmt::BasicFormatter<char>>(args...);
|
auto va = fmt::make_format_args<fmt::BasicFormatter<char>>(args...);
|
||||||
return vcustom_format(format_str, va);
|
return custom_vformat(format_str, va);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, CustomArgFormatter) {
|
TEST(FormatTest, CustomArgFormatter) {
|
||||||
|
@ -67,7 +67,7 @@ struct TestArgFormatter : fmt::BasicArgFormatter<TestArgFormatter, char> {
|
|||||||
TEST(OStreamTest, CustomArg) {
|
TEST(OStreamTest, CustomArg) {
|
||||||
fmt::MemoryWriter writer;
|
fmt::MemoryWriter writer;
|
||||||
typedef fmt::BasicFormatter<char, TestArgFormatter> Formatter;
|
typedef fmt::BasicFormatter<char, TestArgFormatter> Formatter;
|
||||||
Formatter formatter(fmt::format_args(), writer);
|
Formatter formatter(fmt::basic_format_args<Formatter>(), writer);
|
||||||
fmt::FormatSpec spec;
|
fmt::FormatSpec spec;
|
||||||
TestArgFormatter af(formatter, spec, "}");
|
TestArgFormatter af(formatter, spec, "}");
|
||||||
af.visit(fmt::internal::MakeArg<Formatter>(TestEnum()));
|
af.visit(fmt::internal::MakeArg<Formatter>(TestEnum()));
|
||||||
|
Reference in New Issue
Block a user