forked from fmtlib/fmt
Fix compilation errors on gcc 4.4
This commit is contained in:
@@ -167,6 +167,11 @@
|
|||||||
# define FMT_USE_EXPERIMENTAL_STRING_VIEW
|
# define FMT_USE_EXPERIMENTAL_STRING_VIEW
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// std::result_of is defined in <functional> in gcc 4.4.
|
||||||
|
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404
|
||||||
|
# include <functional>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace fmt {
|
namespace fmt {
|
||||||
|
|
||||||
// An implementation of declval for pre-C++11 compilers such as gcc 4.
|
// An implementation of declval for pre-C++11 compilers such as gcc 4.
|
||||||
@@ -302,8 +307,6 @@ class basic_buffer {
|
|||||||
std::size_t capacity_;
|
std::size_t capacity_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef const T &const_reference;
|
|
||||||
|
|
||||||
basic_buffer(T *p = FMT_NULL, std::size_t size = 0, std::size_t capacity = 0)
|
basic_buffer(T *p = FMT_NULL, std::size_t size = 0, std::size_t capacity = 0)
|
||||||
FMT_NOEXCEPT: ptr_(p), size_(size), capacity_(capacity) {}
|
FMT_NOEXCEPT: ptr_(p), size_(size), capacity_(capacity) {}
|
||||||
|
|
||||||
@@ -322,6 +325,7 @@ class basic_buffer {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
typedef T value_type;
|
typedef T value_type;
|
||||||
|
typedef const T &const_reference;
|
||||||
|
|
||||||
virtual ~basic_buffer() {}
|
virtual ~basic_buffer() {}
|
||||||
|
|
||||||
@@ -655,6 +659,16 @@ enum { MAX_PACKED_ARGS = 15 };
|
|||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
class arg_map;
|
class arg_map;
|
||||||
|
|
||||||
|
template <typename>
|
||||||
|
struct result_of;
|
||||||
|
|
||||||
|
template <typename F, typename... Args>
|
||||||
|
struct result_of<F(Args...)> {
|
||||||
|
// A workaround for gcc 4.4 that doesn't allow F to be a reference.
|
||||||
|
typedef typename std::result_of<
|
||||||
|
typename std::remove_reference<F>::type(Args...)>::type type;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// A formatting argument. It is a trivially copyable/constructible type to
|
// A formatting argument. It is a trivially copyable/constructible type to
|
||||||
@@ -669,7 +683,7 @@ class basic_arg {
|
|||||||
friend FMT_CONSTEXPR basic_arg<ContextType> internal::make_arg(const T &value);
|
friend FMT_CONSTEXPR basic_arg<ContextType> internal::make_arg(const T &value);
|
||||||
|
|
||||||
template <typename Visitor, typename Ctx>
|
template <typename Visitor, typename Ctx>
|
||||||
friend FMT_CONSTEXPR typename std::result_of<Visitor(int)>::type
|
friend FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
|
||||||
visit(Visitor &&vis, basic_arg<Ctx> arg);
|
visit(Visitor &&vis, basic_arg<Ctx> arg);
|
||||||
|
|
||||||
friend class basic_format_args<Context>;
|
friend class basic_format_args<Context>;
|
||||||
|
@@ -156,6 +156,13 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// A workaround for gcc 4.4 that doesn't support union members with ctors.
|
||||||
|
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404
|
||||||
|
# define FMT_UNION struct
|
||||||
|
#else
|
||||||
|
# define FMT_UNION union
|
||||||
|
#endif
|
||||||
|
|
||||||
// Some compilers masquerade as both MSVC and GCC-likes or otherwise support
|
// Some compilers masquerade as both MSVC and GCC-likes or otherwise support
|
||||||
// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the
|
// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the
|
||||||
// MSVC intrinsics if the clz and clzll builtins are not available.
|
// MSVC intrinsics if the clz and clzll builtins are not available.
|
||||||
@@ -225,6 +232,13 @@ FMT_CONSTEXPR auto end(const C &c) -> decltype(c.end()) { return c.end(); }
|
|||||||
template <typename T, std::size_t N>
|
template <typename T, std::size_t N>
|
||||||
FMT_CONSTEXPR T *end(T (&array)[N]) FMT_NOEXCEPT { return array + N; }
|
FMT_CONSTEXPR T *end(T (&array)[N]) FMT_NOEXCEPT { return array + N; }
|
||||||
|
|
||||||
|
// For std::result_of in gcc 4.4.
|
||||||
|
template <typename Result>
|
||||||
|
struct function {
|
||||||
|
template <typename T>
|
||||||
|
struct result { typedef Result type; };
|
||||||
|
};
|
||||||
|
|
||||||
struct dummy_int {
|
struct dummy_int {
|
||||||
int data[2];
|
int data[2];
|
||||||
operator int() const { return 0; }
|
operator int() const { return 0; }
|
||||||
@@ -1016,7 +1030,7 @@ struct monostate {};
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Visitor, typename Context>
|
template <typename Visitor, typename Context>
|
||||||
FMT_CONSTEXPR typename std::result_of<Visitor(int)>::type
|
FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
|
||||||
visit(Visitor &&vis, basic_arg<Context> arg) {
|
visit(Visitor &&vis, basic_arg<Context> arg) {
|
||||||
typedef typename Context::char_type char_type;
|
typedef typename Context::char_type char_type;
|
||||||
switch (arg.type_) {
|
switch (arg.type_) {
|
||||||
@@ -1051,7 +1065,7 @@ FMT_CONSTEXPR typename std::result_of<Visitor(int)>::type
|
|||||||
case internal::custom_type:
|
case internal::custom_type:
|
||||||
return vis(typename basic_arg<Context>::handle(arg.value_.custom));
|
return vis(typename basic_arg<Context>::handle(arg.value_.custom));
|
||||||
}
|
}
|
||||||
return typename std::result_of<Visitor(int)>::type();
|
return typename internal::result_of<Visitor(int)>::type();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum alignment {
|
enum alignment {
|
||||||
@@ -1405,33 +1419,35 @@ class arg_formatter_base {
|
|||||||
write(value);
|
write(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct char_spec_handler : internal::error_handler {
|
||||||
|
arg_formatter_base &formatter;
|
||||||
|
char_type value;
|
||||||
|
|
||||||
|
char_spec_handler(arg_formatter_base& f, char_type val)
|
||||||
|
: formatter(f), value(val) {}
|
||||||
|
|
||||||
|
void on_int() { formatter.writer_.write_int(value, formatter.specs_); }
|
||||||
|
void on_char() { formatter.write_char(value); }
|
||||||
|
};
|
||||||
|
|
||||||
void operator()(char_type value) {
|
void operator()(char_type value) {
|
||||||
struct spec_handler : internal::error_handler {
|
internal::handle_char_specs(specs_, char_spec_handler(*this, value));
|
||||||
arg_formatter_base &formatter;
|
|
||||||
char_type value;
|
|
||||||
|
|
||||||
spec_handler(arg_formatter_base& f, char_type val)
|
|
||||||
: formatter(f), value(val) {}
|
|
||||||
|
|
||||||
void on_int() { formatter.writer_.write_int(value, formatter.specs_); }
|
|
||||||
void on_char() { formatter.write_char(value); }
|
|
||||||
};
|
|
||||||
internal::handle_char_specs(specs_, spec_handler(*this, value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct cstring_spec_handler : internal::error_handler {
|
||||||
|
arg_formatter_base &formatter;
|
||||||
|
const char_type *value;
|
||||||
|
|
||||||
|
cstring_spec_handler(arg_formatter_base &f, const char_type *val)
|
||||||
|
: formatter(f), value(val) {}
|
||||||
|
|
||||||
|
void on_string() { formatter.write(value); }
|
||||||
|
void on_pointer() { formatter.write_pointer(value); }
|
||||||
|
};
|
||||||
|
|
||||||
void operator()(const char_type *value) {
|
void operator()(const char_type *value) {
|
||||||
struct spec_handler : internal::error_handler {
|
|
||||||
arg_formatter_base &formatter;
|
|
||||||
const char_type *value;
|
|
||||||
|
|
||||||
spec_handler(arg_formatter_base &f, const char_type *val)
|
|
||||||
: formatter(f), value(val) {}
|
|
||||||
|
|
||||||
void on_string() { formatter.write(value); }
|
|
||||||
void on_pointer() { formatter.write_pointer(value); }
|
|
||||||
};
|
|
||||||
internal::handle_cstring_type_spec(
|
internal::handle_cstring_type_spec(
|
||||||
specs_.type_, spec_handler(*this, value));
|
specs_.type_, cstring_spec_handler(*this, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(basic_string_view<char_type> value) {
|
void operator()(basic_string_view<char_type> value) {
|
||||||
@@ -1480,20 +1496,20 @@ FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename Context>
|
template <typename Char, typename Context>
|
||||||
class custom_formatter {
|
class custom_formatter: public function<bool> {
|
||||||
private:
|
private:
|
||||||
Context &ctx_;
|
Context &ctx_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit custom_formatter(Context &ctx): ctx_(ctx) {}
|
explicit custom_formatter(Context &ctx): ctx_(ctx) {}
|
||||||
|
|
||||||
bool operator()(typename basic_arg<Context>::handle h) {
|
bool operator()(typename basic_arg<Context>::handle h) const {
|
||||||
h.format(ctx_);
|
h.format(ctx_);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool operator()(T) { return false; }
|
bool operator()(T) const { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -1505,12 +1521,13 @@ struct is_integer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename ErrorHandler>
|
template <typename ErrorHandler>
|
||||||
class width_checker {
|
class width_checker: public function<unsigned long long> {
|
||||||
public:
|
public:
|
||||||
explicit FMT_CONSTEXPR width_checker(ErrorHandler &eh) : handler_(eh) {}
|
explicit FMT_CONSTEXPR width_checker(ErrorHandler &eh) : handler_(eh) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FMT_CONSTEXPR typename std::enable_if<
|
FMT_CONSTEXPR
|
||||||
|
typename std::enable_if<
|
||||||
is_integer<T>::value, unsigned long long>::type operator()(T value) {
|
is_integer<T>::value, unsigned long long>::type operator()(T value) {
|
||||||
if (is_negative(value))
|
if (is_negative(value))
|
||||||
handler_.on_error("negative width");
|
handler_.on_error("negative width");
|
||||||
@@ -1529,7 +1546,7 @@ class width_checker {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename ErrorHandler>
|
template <typename ErrorHandler>
|
||||||
class precision_checker {
|
class precision_checker: public function<unsigned long long> {
|
||||||
public:
|
public:
|
||||||
explicit FMT_CONSTEXPR precision_checker(ErrorHandler &eh) : handler_(eh) {}
|
explicit FMT_CONSTEXPR precision_checker(ErrorHandler &eh) : handler_(eh) {}
|
||||||
|
|
||||||
@@ -1716,7 +1733,7 @@ struct arg_ref {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Kind kind;
|
Kind kind;
|
||||||
union {
|
FMT_UNION {
|
||||||
unsigned index;
|
unsigned index;
|
||||||
basic_string_view<Char> name;
|
basic_string_view<Char> name;
|
||||||
};
|
};
|
||||||
@@ -2103,7 +2120,8 @@ void handle_dynamic_spec(
|
|||||||
|
|
||||||
/** The default argument formatter. */
|
/** The default argument formatter. */
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
class arg_formatter: public internal::arg_formatter_base<Range> {
|
class arg_formatter:
|
||||||
|
public internal::function<void>, public internal::arg_formatter_base<Range> {
|
||||||
private:
|
private:
|
||||||
typedef typename Range::value_type char_type;
|
typedef typename Range::value_type char_type;
|
||||||
typedef decltype(internal::declval<Range>().begin()) iterator;
|
typedef decltype(internal::declval<Range>().begin()) iterator;
|
||||||
@@ -2129,7 +2147,7 @@ class arg_formatter: public internal::arg_formatter_base<Range> {
|
|||||||
using base::operator();
|
using base::operator();
|
||||||
|
|
||||||
/** Formats an argument of a custom (user-defined) type. */
|
/** Formats an argument of a custom (user-defined) type. */
|
||||||
void operator()(typename basic_arg<context_type>::handle handle) {
|
void operator()(typename basic_arg<context_type>::handle handle) const {
|
||||||
handle.format(ctx_);
|
handle.format(ctx_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -2516,10 +2534,10 @@ class basic_writer {
|
|||||||
Formats *value* and writes it to the buffer.
|
Formats *value* and writes it to the buffer.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename T, typename... FormatSpecs>
|
template <typename T, typename FormatSpec, typename... FormatSpecs>
|
||||||
typename std::enable_if<std::is_integral<T>::value, void>::type
|
typename std::enable_if<std::is_integral<T>::value, void>::type
|
||||||
write(T value, FormatSpecs... specs) {
|
write(T value, FormatSpec spec, FormatSpecs... specs) {
|
||||||
format_specs s(specs...);
|
format_specs s(spec, specs...);
|
||||||
s.align_ = ALIGN_RIGHT;
|
s.align_ = ALIGN_RIGHT;
|
||||||
write_int(value, s);
|
write_int(value, s);
|
||||||
}
|
}
|
||||||
@@ -2619,48 +2637,50 @@ void basic_writer<Range>::write_str(
|
|||||||
write_str(data, size, spec);
|
write_str(data, size, spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
struct float_spec_handler {
|
||||||
|
Char type;
|
||||||
|
bool upper;
|
||||||
|
|
||||||
|
explicit float_spec_handler(Char t) : type(t), upper(false) {}
|
||||||
|
|
||||||
|
void on_general() {
|
||||||
|
if (type == 'G')
|
||||||
|
upper = true;
|
||||||
|
else
|
||||||
|
type = 'g';
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_exp() {
|
||||||
|
if (type == 'E')
|
||||||
|
upper = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_fixed() {
|
||||||
|
if (type == 'F') {
|
||||||
|
upper = true;
|
||||||
|
#if FMT_MSC_VER
|
||||||
|
// MSVC's printf doesn't support 'F'.
|
||||||
|
type = 'f';
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_hex() {
|
||||||
|
if (type == 'A')
|
||||||
|
upper = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_error() {
|
||||||
|
FMT_THROW(format_error("invalid type specifier"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
||||||
// Check type.
|
// Check type.
|
||||||
struct spec_handler {
|
float_spec_handler<char_type> handler(spec.type());
|
||||||
char_type type;
|
|
||||||
bool upper;
|
|
||||||
|
|
||||||
explicit spec_handler(char_type t) : type(t), upper(false) {}
|
|
||||||
|
|
||||||
void on_general() {
|
|
||||||
if (type == 'G')
|
|
||||||
upper = true;
|
|
||||||
else
|
|
||||||
type = 'g';
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_exp() {
|
|
||||||
if (type == 'E')
|
|
||||||
upper = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_fixed() {
|
|
||||||
if (type == 'F') {
|
|
||||||
upper = true;
|
|
||||||
#if FMT_MSC_VER
|
|
||||||
// MSVC's printf doesn't support 'F'.
|
|
||||||
type = 'f';
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_hex() {
|
|
||||||
if (type == 'A')
|
|
||||||
upper = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_error() {
|
|
||||||
FMT_THROW(format_error("invalid type specifier"));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
spec_handler handler(spec.type());
|
|
||||||
internal::handle_float_type_spec(spec.type(), handler);
|
internal::handle_float_type_spec(spec.type(), handler);
|
||||||
|
|
||||||
char sign = 0;
|
char sign = 0;
|
||||||
@@ -3049,7 +3069,17 @@ struct formatter<T, Char,
|
|||||||
// }
|
// }
|
||||||
// };
|
// };
|
||||||
template <typename Char = char>
|
template <typename Char = char>
|
||||||
struct dynamic_formatter {
|
class dynamic_formatter {
|
||||||
|
private:
|
||||||
|
struct null_handler: internal::error_handler {
|
||||||
|
void on_align(alignment) {}
|
||||||
|
void on_plus() {}
|
||||||
|
void on_minus() {}
|
||||||
|
void on_space() {}
|
||||||
|
void on_hash() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
||||||
auto it = internal::null_terminating_iterator<Char>(ctx);
|
auto it = internal::null_terminating_iterator<Char>(ctx);
|
||||||
@@ -3062,13 +3092,6 @@ struct dynamic_formatter {
|
|||||||
template <typename T, typename FormatContext>
|
template <typename T, typename FormatContext>
|
||||||
auto format(const T &val, FormatContext &ctx) -> decltype(ctx.begin()) {
|
auto format(const T &val, FormatContext &ctx) -> decltype(ctx.begin()) {
|
||||||
handle_specs(ctx);
|
handle_specs(ctx);
|
||||||
struct null_handler : internal::error_handler {
|
|
||||||
void on_align(alignment) {}
|
|
||||||
void on_plus() {}
|
|
||||||
void on_minus() {}
|
|
||||||
void on_space() {}
|
|
||||||
void on_hash() {}
|
|
||||||
};
|
|
||||||
internal::specs_checker<null_handler>
|
internal::specs_checker<null_handler>
|
||||||
checker(null_handler(), internal::get_type<FormatContext, T>::value);
|
checker(null_handler(), internal::get_type<FormatContext, T>::value);
|
||||||
checker.on_align(specs_.align());
|
checker.on_align(specs_.align());
|
||||||
@@ -3115,66 +3138,70 @@ typename basic_context<Range, Char>::format_arg
|
|||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ArgFormatter, typename Char, typename Context>
|
||||||
|
struct format_handler : internal::error_handler {
|
||||||
|
typedef internal::null_terminating_iterator<Char> iterator;
|
||||||
|
typedef typename ArgFormatter::range range;
|
||||||
|
|
||||||
|
format_handler(range r, basic_string_view<Char> str,
|
||||||
|
basic_format_args<Context> format_args)
|
||||||
|
: context(r.begin(), str, format_args) {}
|
||||||
|
|
||||||
|
void on_text(iterator begin, iterator end) {
|
||||||
|
size_t size = end - begin;
|
||||||
|
auto out = context.begin();
|
||||||
|
auto &&it = internal::reserve(out, size);
|
||||||
|
it = std::copy_n(begin, size, it);
|
||||||
|
context.advance_to(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_arg_id() { arg = context.next_arg(); }
|
||||||
|
void on_arg_id(unsigned id) {
|
||||||
|
context.parse_context().check_arg_id(id);
|
||||||
|
arg = context.get_arg(id);
|
||||||
|
}
|
||||||
|
void on_arg_id(basic_string_view<Char> id) {
|
||||||
|
arg = context.get_arg(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_replacement_field(iterator it) {
|
||||||
|
context.parse_context().advance_to(pointer_from(it));
|
||||||
|
using internal::custom_formatter;
|
||||||
|
if (visit(custom_formatter<Char, Context>(context), arg))
|
||||||
|
return;
|
||||||
|
basic_format_specs<Char> specs;
|
||||||
|
visit(ArgFormatter(context, specs), arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator on_format_specs(iterator it) {
|
||||||
|
auto& parse_ctx = context.parse_context();
|
||||||
|
parse_ctx.advance_to(pointer_from(it));
|
||||||
|
using internal::custom_formatter;
|
||||||
|
if (visit(custom_formatter<Char, Context>(context), arg))
|
||||||
|
return iterator(parse_ctx);
|
||||||
|
basic_format_specs<Char> specs;
|
||||||
|
using internal::specs_handler;
|
||||||
|
internal::specs_checker<specs_handler<Context>>
|
||||||
|
handler(specs_handler<Context>(specs, context), arg.type());
|
||||||
|
it = parse_format_specs(it, handler);
|
||||||
|
if (*it != '}')
|
||||||
|
on_error("missing '}' in format string");
|
||||||
|
parse_ctx.advance_to(pointer_from(it));
|
||||||
|
visit(ArgFormatter(context, specs), arg);
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
Context context;
|
||||||
|
basic_arg<Context> arg;
|
||||||
|
};
|
||||||
|
|
||||||
/** Formats arguments and writes the output to the buffer. */
|
/** Formats arguments and writes the output to the buffer. */
|
||||||
template <typename ArgFormatter, typename Char, typename Context>
|
template <typename ArgFormatter, typename Char, typename Context>
|
||||||
typename Context::iterator do_vformat_to(typename ArgFormatter::range out,
|
typename Context::iterator do_vformat_to(typename ArgFormatter::range out,
|
||||||
basic_string_view<Char> format_str,
|
basic_string_view<Char> format_str,
|
||||||
basic_format_args<Context> args) {
|
basic_format_args<Context> args) {
|
||||||
typedef internal::null_terminating_iterator<Char> iterator;
|
typedef internal::null_terminating_iterator<Char> iterator;
|
||||||
typedef typename ArgFormatter::range range;
|
format_handler<ArgFormatter, Char, Context> h(out, format_str, args);
|
||||||
|
|
||||||
struct handler : internal::error_handler {
|
|
||||||
handler(range r, basic_string_view<Char> str,
|
|
||||||
basic_format_args<Context> format_args)
|
|
||||||
: context(r.begin(), str, format_args) {}
|
|
||||||
|
|
||||||
void on_text(iterator begin, iterator end) {
|
|
||||||
size_t size = end - begin;
|
|
||||||
auto out = context.begin();
|
|
||||||
auto &&it = internal::reserve(out, size);
|
|
||||||
it = std::copy_n(begin, size, it);
|
|
||||||
context.advance_to(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_arg_id() { arg = context.next_arg(); }
|
|
||||||
void on_arg_id(unsigned id) {
|
|
||||||
context.parse_context().check_arg_id(id);
|
|
||||||
arg = context.get_arg(id);
|
|
||||||
}
|
|
||||||
void on_arg_id(basic_string_view<Char> id) {
|
|
||||||
arg = context.get_arg(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_replacement_field(iterator it) {
|
|
||||||
context.parse_context().advance_to(pointer_from(it));
|
|
||||||
using internal::custom_formatter;
|
|
||||||
if (visit(custom_formatter<Char, Context>(context), arg))
|
|
||||||
return;
|
|
||||||
basic_format_specs<Char> specs;
|
|
||||||
visit(ArgFormatter(context, specs), arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator on_format_specs(iterator it) {
|
|
||||||
auto& parse_ctx = context.parse_context();
|
|
||||||
parse_ctx.advance_to(pointer_from(it));
|
|
||||||
using internal::custom_formatter;
|
|
||||||
if (visit(custom_formatter<Char, Context>(context), arg))
|
|
||||||
return iterator(parse_ctx);
|
|
||||||
basic_format_specs<Char> specs;
|
|
||||||
using internal::specs_handler;
|
|
||||||
internal::specs_checker<specs_handler<Context>>
|
|
||||||
handler(specs_handler<Context>(specs, context), arg.type());
|
|
||||||
it = parse_format_specs(it, handler);
|
|
||||||
if (*it != '}')
|
|
||||||
on_error("missing '}' in format string");
|
|
||||||
parse_ctx.advance_to(pointer_from(it));
|
|
||||||
visit(ArgFormatter(context, specs), arg);
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
Context context;
|
|
||||||
basic_arg<Context> arg;
|
|
||||||
} h(out, format_str, args);
|
|
||||||
parse_format_string(iterator(format_str.begin(), format_str.end()), h);
|
parse_format_string(iterator(format_str.begin(), format_str.end()), h);
|
||||||
return h.context.begin();
|
return h.context.begin();
|
||||||
}
|
}
|
||||||
@@ -3250,7 +3277,8 @@ arg_join<It, wchar_t> join(It begin, It end, wstring_view sep) {
|
|||||||
return arg_join<It, wchar_t>(begin, end, sep);
|
return arg_join<It, wchar_t>(begin, end, sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_TRAILING_RETURN
|
// The following causes ICE in gcc 4.4.
|
||||||
|
#if FMT_USE_TRAILING_RETURN && (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 405)
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
auto join(const Range &range, string_view sep)
|
auto join(const Range &range, string_view sep)
|
||||||
-> arg_join<decltype(internal::begin(range)), char> {
|
-> arg_join<decltype(internal::begin(range)), char> {
|
||||||
|
@@ -61,8 +61,8 @@ class convert_to_int<T, Char, true> {
|
|||||||
private:
|
private:
|
||||||
template <typename U>
|
template <typename U>
|
||||||
static decltype(
|
static decltype(
|
||||||
std::declval<test_stream<Char>&>() << std::declval<U>(), std::true_type())
|
internal::declval<test_stream<Char>&>()
|
||||||
test(int);
|
<< internal::declval<U>(), std::true_type()) test(int);
|
||||||
|
|
||||||
template <typename>
|
template <typename>
|
||||||
static std::false_type test(...);
|
static std::false_type test(...);
|
||||||
|
@@ -19,7 +19,7 @@ namespace internal {
|
|||||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||||
// signed and unsigned integers.
|
// signed and unsigned integers.
|
||||||
template <bool IsSigned>
|
template <bool IsSigned>
|
||||||
struct IntChecker {
|
struct int_checker {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static bool fits_in_int(T value) {
|
static bool fits_in_int(T value) {
|
||||||
unsigned max = std::numeric_limits<int>::max();
|
unsigned max = std::numeric_limits<int>::max();
|
||||||
@@ -29,7 +29,7 @@ struct IntChecker {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct IntChecker<true> {
|
struct int_checker<true> {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static bool fits_in_int(T value) {
|
static bool fits_in_int(T value) {
|
||||||
return value >= std::numeric_limits<int>::min() &&
|
return value >= std::numeric_limits<int>::min() &&
|
||||||
@@ -38,12 +38,12 @@ struct IntChecker<true> {
|
|||||||
static bool fits_in_int(int) { return true; }
|
static bool fits_in_int(int) { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class PrintfPrecisionHandler {
|
class printf_precision_handler: public function<int> {
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<std::is_integral<T>::value, int>::type
|
typename std::enable_if<std::is_integral<T>::value, int>::type
|
||||||
operator()(T value) {
|
operator()(T value) {
|
||||||
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||||
FMT_THROW(format_error("number is too big"));
|
FMT_THROW(format_error("number is too big"));
|
||||||
return static_cast<int>(value);
|
return static_cast<int>(value);
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ class PrintfPrecisionHandler {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// An argument visitor that returns true iff arg is a zero integer.
|
// An argument visitor that returns true iff arg is a zero integer.
|
||||||
class IsZeroInt {
|
class is_zero_int: public function<bool> {
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<std::is_integral<T>::value, bool>::type
|
typename std::enable_if<std::is_integral<T>::value, bool>::type
|
||||||
@@ -77,7 +77,7 @@ struct make_unsigned_or_bool<bool> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename Context>
|
template <typename T, typename Context>
|
||||||
class ArgConverter {
|
class arg_converter: public function<void> {
|
||||||
private:
|
private:
|
||||||
typedef typename Context::char_type Char;
|
typedef typename Context::char_type Char;
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ class ArgConverter {
|
|||||||
typename Context::char_type type_;
|
typename Context::char_type type_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ArgConverter(basic_arg<Context> &arg, Char type)
|
arg_converter(basic_arg<Context> &arg, Char type)
|
||||||
: arg_(arg), type_(type) {}
|
: arg_(arg), type_(type) {}
|
||||||
|
|
||||||
void operator()(bool value) {
|
void operator()(bool value) {
|
||||||
@@ -134,19 +134,19 @@ class ArgConverter {
|
|||||||
// unsigned).
|
// unsigned).
|
||||||
template <typename T, typename Context, typename Char>
|
template <typename T, typename Context, typename Char>
|
||||||
void convert_arg(basic_arg<Context> &arg, Char type) {
|
void convert_arg(basic_arg<Context> &arg, Char type) {
|
||||||
visit(ArgConverter<T, Context>(arg, type), arg);
|
visit(arg_converter<T, Context>(arg, type), arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts an integer argument to char for printf.
|
// Converts an integer argument to char for printf.
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
class CharConverter {
|
class char_converter: public function<void> {
|
||||||
private:
|
private:
|
||||||
basic_arg<Context> &arg_;
|
basic_arg<Context> &arg_;
|
||||||
|
|
||||||
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
|
FMT_DISALLOW_COPY_AND_ASSIGN(char_converter);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CharConverter(basic_arg<Context> &arg) : arg_(arg) {}
|
explicit char_converter(basic_arg<Context> &arg) : arg_(arg) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<std::is_integral<T>::value>::type
|
typename std::enable_if<std::is_integral<T>::value>::type
|
||||||
@@ -163,16 +163,16 @@ class CharConverter {
|
|||||||
// Checks if an argument is a valid printf width specifier and sets
|
// Checks if an argument is a valid printf width specifier and sets
|
||||||
// left alignment if it is negative.
|
// left alignment if it is negative.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
class PrintfWidthHandler {
|
class printf_width_handler: public function<unsigned> {
|
||||||
private:
|
private:
|
||||||
typedef basic_format_specs<Char> format_specs;
|
typedef basic_format_specs<Char> format_specs;
|
||||||
|
|
||||||
format_specs &spec_;
|
format_specs &spec_;
|
||||||
|
|
||||||
FMT_DISALLOW_COPY_AND_ASSIGN(PrintfWidthHandler);
|
FMT_DISALLOW_COPY_AND_ASSIGN(printf_width_handler);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PrintfWidthHandler(format_specs &spec) : spec_(spec) {}
|
explicit printf_width_handler(format_specs &spec) : spec_(spec) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<std::is_integral<T>::value, unsigned>::type
|
typename std::enable_if<std::is_integral<T>::value, unsigned>::type
|
||||||
@@ -213,10 +213,11 @@ class basic_printf_context;
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
class printf_arg_formatter : public internal::arg_formatter_base<Range> {
|
class printf_arg_formatter:
|
||||||
|
public internal::function<void>, public internal::arg_formatter_base<Range> {
|
||||||
private:
|
private:
|
||||||
typedef typename Range::value_type char_type;
|
typedef typename Range::value_type char_type;
|
||||||
typedef decltype(std::declval<Range>().begin()) iterator;
|
typedef decltype(internal::declval<Range>().begin()) iterator;
|
||||||
typedef internal::arg_formatter_base<Range> base;
|
typedef internal::arg_formatter_base<Range> base;
|
||||||
typedef basic_printf_context<iterator, char_type> context_type;
|
typedef basic_printf_context<iterator, char_type> context_type;
|
||||||
|
|
||||||
@@ -417,7 +418,7 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
|
|||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
spec.width_ =
|
spec.width_ =
|
||||||
visit(internal::PrintfWidthHandler<char_type>(spec), get_arg(it));
|
visit(internal::printf_width_handler<char_type>(spec), get_arg(it));
|
||||||
}
|
}
|
||||||
return arg_index;
|
return arg_index;
|
||||||
}
|
}
|
||||||
@@ -453,14 +454,14 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
|||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
spec.precision_ =
|
spec.precision_ =
|
||||||
visit(internal::PrintfPrecisionHandler(), get_arg(it));
|
visit(internal::printf_precision_handler(), get_arg(it));
|
||||||
} else {
|
} else {
|
||||||
spec.precision_ = 0;
|
spec.precision_ = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
format_arg arg = get_arg(it, arg_index);
|
format_arg arg = get_arg(it, arg_index);
|
||||||
if (spec.flag(HASH_FLAG) && visit(internal::IsZeroInt(), arg))
|
if (spec.flag(HASH_FLAG) && visit(internal::is_zero_int(), arg))
|
||||||
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
|
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
|
||||||
if (spec.fill_ == '0') {
|
if (spec.fill_ == '0') {
|
||||||
if (arg.is_arithmetic())
|
if (arg.is_arithmetic())
|
||||||
@@ -514,7 +515,7 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
|||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
// TODO: handle wchar_t
|
// TODO: handle wchar_t
|
||||||
visit(internal::CharConverter<basic_printf_context>(arg), arg);
|
visit(internal::char_converter<basic_printf_context>(arg), arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -539,8 +540,7 @@ struct printf_context {
|
|||||||
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
|
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef basic_format_args<
|
typedef basic_format_args<printf_context<internal::buffer>::type> printf_args;
|
||||||
typename printf_context<internal::buffer>::type> printf_args;
|
|
||||||
|
|
||||||
inline std::string vsprintf(string_view format, printf_args args) {
|
inline std::string vsprintf(string_view format, printf_args args) {
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
@@ -565,7 +565,7 @@ inline std::string sprintf(string_view format_str, const Args & ... args) {
|
|||||||
|
|
||||||
inline std::wstring vsprintf(
|
inline std::wstring vsprintf(
|
||||||
wstring_view format,
|
wstring_view format,
|
||||||
basic_format_args<typename printf_context<internal::wbuffer>::type> args) {
|
basic_format_args<printf_context<internal::wbuffer>::type> args) {
|
||||||
wmemory_buffer buffer;
|
wmemory_buffer buffer;
|
||||||
printf(buffer, format, args);
|
printf(buffer, format, args);
|
||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
|
@@ -18,7 +18,7 @@ class CustomArgFormatter :
|
|||||||
public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
|
public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
|
||||||
public:
|
public:
|
||||||
typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
||||||
typedef decltype(std::declval<range>().begin()) iterator;
|
typedef decltype(fmt::internal::declval<range>().begin()) iterator;
|
||||||
typedef fmt::arg_formatter<range> base;
|
typedef fmt::arg_formatter<range> base;
|
||||||
|
|
||||||
CustomArgFormatter(fmt::basic_context<iterator, char> &ctx,
|
CustomArgFormatter(fmt::basic_context<iterator, char> &ctx,
|
||||||
|
@@ -44,7 +44,7 @@
|
|||||||
#undef max
|
#undef max
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct ValueExtractor {
|
struct ValueExtractor: fmt::internal::function<T> {
|
||||||
T operator()(T value) {
|
T operator()(T value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ struct ValueExtractor {
|
|||||||
TEST(FormatTest, ArgConverter) {
|
TEST(FormatTest, ArgConverter) {
|
||||||
long long value = std::numeric_limits<long long>::max();
|
long long value = std::numeric_limits<long long>::max();
|
||||||
auto arg = fmt::internal::make_arg<fmt::context>(value);
|
auto arg = fmt::internal::make_arg<fmt::context>(value);
|
||||||
visit(fmt::internal::ArgConverter<long long, fmt::context>(arg, 'd'), arg);
|
visit(fmt::internal::arg_converter<long long, fmt::context>(arg, 'd'), arg);
|
||||||
EXPECT_EQ(value, visit(ValueExtractor<long long>(), arg));
|
EXPECT_EQ(value, visit(ValueExtractor<long long>(), arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1205,7 +1205,9 @@ TEST(FormatterTest, FormatPointer) {
|
|||||||
EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'),
|
EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'),
|
||||||
format("{0}", reinterpret_cast<void*>(~uintptr_t())));
|
format("{0}", reinterpret_cast<void*>(~uintptr_t())));
|
||||||
EXPECT_EQ("0x1234", format("{}", fmt::ptr(reinterpret_cast<int*>(0x1234))));
|
EXPECT_EQ("0x1234", format("{}", fmt::ptr(reinterpret_cast<int*>(0x1234))));
|
||||||
EXPECT_EQ("0x0", format("{}", nullptr));
|
#if FMT_USE_NULLPTR
|
||||||
|
EXPECT_EQ("0x0", format("{}", FMT_NULL));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, FormatString) {
|
TEST(FormatterTest, FormatString) {
|
||||||
@@ -1450,7 +1452,7 @@ TEST(FormatTest, JoinArg) {
|
|||||||
EXPECT_EQ(L"(1, 2, 3)", format(L"({})", join(v1, v1 + 3, L", ")));
|
EXPECT_EQ(L"(1, 2, 3)", format(L"({})", join(v1, v1 + 3, L", ")));
|
||||||
EXPECT_EQ("1, 2, 3", format("{0:{1}}", join(v1, v1 + 3, ", "), 1));
|
EXPECT_EQ("1, 2, 3", format("{0:{1}}", join(v1, v1 + 3, ", "), 1));
|
||||||
|
|
||||||
#if FMT_HAS_GXX_CXX11
|
#if FMT_USE_TRAILING_RETURN && (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 405)
|
||||||
EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, ", ")));
|
EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, ", ")));
|
||||||
EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2, ", ")));
|
EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2, ", ")));
|
||||||
#endif
|
#endif
|
||||||
@@ -1551,7 +1553,8 @@ TEST(FormatTest, FixedEnum) {
|
|||||||
|
|
||||||
typedef fmt::back_insert_range<fmt::internal::buffer> buffer_range;
|
typedef fmt::back_insert_range<fmt::internal::buffer> buffer_range;
|
||||||
|
|
||||||
class mock_arg_formatter :
|
class mock_arg_formatter:
|
||||||
|
public fmt::internal::function<void>,
|
||||||
public fmt::internal::arg_formatter_base<buffer_range> {
|
public fmt::internal::arg_formatter_base<buffer_range> {
|
||||||
private:
|
private:
|
||||||
MOCK_METHOD1(call, void (int value));
|
MOCK_METHOD1(call, void (int value));
|
||||||
@@ -1602,8 +1605,8 @@ template <>
|
|||||||
struct formatter<variant> : dynamic_formatter<> {
|
struct formatter<variant> : dynamic_formatter<> {
|
||||||
auto format(variant value, context& ctx) -> decltype(ctx.begin()) {
|
auto format(variant value, context& ctx) -> decltype(ctx.begin()) {
|
||||||
if (value.type == variant::INT)
|
if (value.type == variant::INT)
|
||||||
return dynamic_formatter::format(42, ctx);
|
return dynamic_formatter<>::format(42, ctx);
|
||||||
return dynamic_formatter::format("foo", ctx);
|
return dynamic_formatter<>::format("foo", ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -478,12 +478,12 @@ bool operator==(custom_value<Char> lhs, custom_value<Char> rhs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
// Use a unique result type to make sure that there are no undesirable
|
||||||
struct MockVisitor {
|
// conversions.
|
||||||
// Use a unique result type to make sure that there are no undesirable
|
struct Result {};
|
||||||
// conversions.
|
|
||||||
struct Result {};
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct MockVisitor: fmt::internal::function<Result> {
|
||||||
MockVisitor() {
|
MockVisitor() {
|
||||||
ON_CALL(*this, visit(_)).WillByDefault(Return(Result()));
|
ON_CALL(*this, visit(_)).WillByDefault(Return(Result()));
|
||||||
}
|
}
|
||||||
@@ -529,8 +529,9 @@ VISIT_TYPE(float, double);
|
|||||||
fmt::visit(visitor, make_arg<fmt::basic_context<iterator, Char>>(value)); \
|
fmt::visit(visitor, make_arg<fmt::basic_context<iterator, Char>>(value)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_ARG(value) { \
|
#define CHECK_ARG(value, typename_) { \
|
||||||
typename VisitType<decltype(value)>::Type expected = value; \
|
typedef decltype(value) value_type; \
|
||||||
|
typename_ VisitType<value_type>::Type expected = value; \
|
||||||
CHECK_ARG_(char, expected, value) \
|
CHECK_ARG_(char, expected, value) \
|
||||||
CHECK_ARG_(wchar_t, expected, value) \
|
CHECK_ARG_(wchar_t, expected, value) \
|
||||||
}
|
}
|
||||||
@@ -556,9 +557,9 @@ typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
|||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(NumericArgTest, MakeAndVisit) {
|
TYPED_TEST(NumericArgTest, MakeAndVisit) {
|
||||||
CHECK_ARG(test_value<TypeParam>());
|
CHECK_ARG(test_value<TypeParam>(), typename);
|
||||||
CHECK_ARG(std::numeric_limits<TypeParam>::min());
|
CHECK_ARG(std::numeric_limits<TypeParam>::min(), typename);
|
||||||
CHECK_ARG(std::numeric_limits<TypeParam>::max());
|
CHECK_ARG(std::numeric_limits<TypeParam>::max(), typename);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(UtilTest, CharArg) {
|
TEST(UtilTest, CharArg) {
|
||||||
@@ -594,22 +595,25 @@ TEST(UtilTest, PointerArg) {
|
|||||||
const void *cp = 0;
|
const void *cp = 0;
|
||||||
CHECK_ARG_(char, cp, p);
|
CHECK_ARG_(char, cp, p);
|
||||||
CHECK_ARG_(wchar_t, cp, p);
|
CHECK_ARG_(wchar_t, cp, p);
|
||||||
CHECK_ARG(cp);
|
CHECK_ARG(cp, );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(UtilTest, CustomArg) {
|
struct check_custom {
|
||||||
::Test test;
|
Result operator()(fmt::basic_arg<fmt::context>::handle h) const {
|
||||||
typedef typename fmt::basic_arg<fmt::context>::handle handle;
|
|
||||||
typedef MockVisitor<handle> visitor;
|
|
||||||
testing::StrictMock<visitor> v;
|
|
||||||
EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke([&](handle h) {
|
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
fmt::internal::basic_buffer<char> &base = buffer;
|
fmt::internal::basic_buffer<char> &base = buffer;
|
||||||
fmt::context ctx(std::back_inserter(base), "", fmt::format_args());
|
fmt::context ctx(std::back_inserter(base), "", fmt::format_args());
|
||||||
h.format(ctx);
|
h.format(ctx);
|
||||||
EXPECT_EQ("test", std::string(buffer.data(), buffer.size()));
|
EXPECT_EQ("test", std::string(buffer.data(), buffer.size()));
|
||||||
return visitor::Result();
|
return Result();
|
||||||
}));
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(UtilTest, CustomArg) {
|
||||||
|
::Test test;
|
||||||
|
typedef MockVisitor<fmt::basic_arg<fmt::context>::handle> visitor;
|
||||||
|
testing::StrictMock<visitor> v;
|
||||||
|
EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke(check_custom()));
|
||||||
fmt::visit(v, make_arg<fmt::context>(test));
|
fmt::visit(v, make_arg<fmt::context>(test));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user