Get rid of ArgVisitor
This commit is contained in:
parent
d58cc8a4a8
commit
d4084ac5b1
201
fmt/format.h
201
fmt/format.h
@ -1580,173 +1580,6 @@ typename std::result_of<Visitor(int)>::type visit(Visitor &&vis,
|
|||||||
return typename std::result_of<Visitor(int)>::type();
|
return typename std::result_of<Visitor(int)>::type();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
\rst
|
|
||||||
An argument visitor based on the `curiously recurring template pattern
|
|
||||||
<http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.
|
|
||||||
|
|
||||||
To use `~fmt::ArgVisitor` define a subclass that implements some or all of the
|
|
||||||
visit methods with the same signatures as the methods in `~fmt::ArgVisitor`,
|
|
||||||
for example, `~fmt::ArgVisitor::visit_int()`.
|
|
||||||
Pass the subclass as the *Impl* template parameter. Then calling
|
|
||||||
`~fmt::ArgVisitor::visit` for some argument will dispatch to a visit method
|
|
||||||
specific to the argument type. For example, if the argument type is
|
|
||||||
``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass
|
|
||||||
will be called. If the subclass doesn't contain a method with this signature,
|
|
||||||
then a corresponding method of `~fmt::ArgVisitor` will be called.
|
|
||||||
|
|
||||||
**Example**::
|
|
||||||
|
|
||||||
class MyArgVisitor : public fmt::ArgVisitor<MyArgVisitor, void> {
|
|
||||||
public:
|
|
||||||
void visit_int(int value) { fmt::print("{}", value); }
|
|
||||||
void visit_double(double value) { fmt::print("{}", value ); }
|
|
||||||
};
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
template <typename Impl, typename Result>
|
|
||||||
class ArgVisitor {
|
|
||||||
private:
|
|
||||||
typedef internal::Arg Arg;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void report_unhandled_arg() {}
|
|
||||||
|
|
||||||
Result visit_unhandled_arg() {
|
|
||||||
FMT_DISPATCH(report_unhandled_arg());
|
|
||||||
return Result();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits an ``int`` argument. **/
|
|
||||||
Result visit_int(int value) {
|
|
||||||
return FMT_DISPATCH(visit_any_int(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits a ``long long`` argument. **/
|
|
||||||
Result visit_long_long(LongLong value) {
|
|
||||||
return FMT_DISPATCH(visit_any_int(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits an ``unsigned`` argument. **/
|
|
||||||
Result visit_uint(unsigned value) {
|
|
||||||
return FMT_DISPATCH(visit_any_int(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits an ``unsigned long long`` argument. **/
|
|
||||||
Result visit_ulong_long(ULongLong value) {
|
|
||||||
return FMT_DISPATCH(visit_any_int(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits a ``bool`` argument. **/
|
|
||||||
Result visit_bool(bool value) {
|
|
||||||
return FMT_DISPATCH(visit_any_int(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits a ``char`` or ``wchar_t`` argument. **/
|
|
||||||
Result visit_char(int value) {
|
|
||||||
return FMT_DISPATCH(visit_any_int(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits an argument of any integral type. **/
|
|
||||||
template <typename T>
|
|
||||||
Result visit_any_int(T) {
|
|
||||||
return FMT_DISPATCH(visit_unhandled_arg());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits a ``double`` argument. **/
|
|
||||||
Result visit_double(double value) {
|
|
||||||
return FMT_DISPATCH(visit_any_double(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits a ``long double`` argument. **/
|
|
||||||
Result visit_long_double(long double value) {
|
|
||||||
return FMT_DISPATCH(visit_any_double(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits a ``double`` or ``long double`` argument. **/
|
|
||||||
template <typename T>
|
|
||||||
Result visit_any_double(T) {
|
|
||||||
return FMT_DISPATCH(visit_unhandled_arg());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits a null-terminated C string (``const char *``) argument. **/
|
|
||||||
Result visit_cstring(const char *) {
|
|
||||||
return FMT_DISPATCH(visit_unhandled_arg());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits a string argument. **/
|
|
||||||
Result visit_string(Arg::StringValue<char>) {
|
|
||||||
return FMT_DISPATCH(visit_unhandled_arg());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits a wide string argument. **/
|
|
||||||
Result visit_wstring(Arg::StringValue<wchar_t>) {
|
|
||||||
return FMT_DISPATCH(visit_unhandled_arg());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits a pointer argument. **/
|
|
||||||
Result visit_pointer(const void *) {
|
|
||||||
return FMT_DISPATCH(visit_unhandled_arg());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visits an argument of a custom (user-defined) type. **/
|
|
||||||
Result visit_custom(Arg::CustomValue) {
|
|
||||||
return FMT_DISPATCH(visit_unhandled_arg());
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(int value) {
|
|
||||||
return FMT_DISPATCH(visit_int(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(unsigned value) {
|
|
||||||
return FMT_DISPATCH(visit_uint(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(fmt::LongLong value) {
|
|
||||||
return FMT_DISPATCH(visit_long_long(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(fmt::ULongLong value) {
|
|
||||||
return FMT_DISPATCH(visit_ulong_long(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(bool value) {
|
|
||||||
return FMT_DISPATCH(visit_bool(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(wchar_t value) {
|
|
||||||
return FMT_DISPATCH(visit_char(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(double value) {
|
|
||||||
return FMT_DISPATCH(visit_double(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(long double value) {
|
|
||||||
return FMT_DISPATCH(visit_long_double(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(const char *value) {
|
|
||||||
return FMT_DISPATCH(visit_cstring(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(format_arg::StringValue<char> value) {
|
|
||||||
return FMT_DISPATCH(visit_string(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(format_arg::StringValue<wchar_t> value) {
|
|
||||||
return FMT_DISPATCH(visit_wstring(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(const void *value) {
|
|
||||||
return FMT_DISPATCH(visit_pointer(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(format_arg::CustomValue value) {
|
|
||||||
return FMT_DISPATCH(visit_custom(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Alignment {
|
enum Alignment {
|
||||||
ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC
|
ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC
|
||||||
};
|
};
|
||||||
@ -2041,7 +1874,7 @@ void ArgMap<Char>::init(const basic_format_args<Formatter> &args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Impl, typename Char>
|
template <typename Impl, typename Char>
|
||||||
class ArgFormatterBase : public ArgVisitor<Impl, void> {
|
class ArgFormatterBase {
|
||||||
private:
|
private:
|
||||||
BasicWriter<Char> &writer_;
|
BasicWriter<Char> &writer_;
|
||||||
FormatSpec &spec_;
|
FormatSpec &spec_;
|
||||||
@ -2092,16 +1925,16 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> {
|
|||||||
: writer_(w), spec_(s) {}
|
: writer_(w), spec_(s) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void visit_any_int(T value) { writer_.write_int(value, spec_); }
|
typename std::enable_if<std::is_integral<T>::value>::type
|
||||||
|
operator()(T value) { writer_.write_int(value, spec_); }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void visit_any_double(T value) { writer_.write_double(value, spec_); }
|
typename std::enable_if<std::is_floating_point<T>::value>::type
|
||||||
|
operator()(T value) { writer_.write_double(value, spec_); }
|
||||||
using ArgVisitor<Impl, void>::operator();
|
|
||||||
|
|
||||||
void operator()(bool value) {
|
void operator()(bool value) {
|
||||||
if (spec_.type_)
|
if (spec_.type_)
|
||||||
return visit_any_int(value);
|
return (*this)(value ? 1 : 0);
|
||||||
write(value);
|
write(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2222,23 +2055,7 @@ class format_context_base {
|
|||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
/**
|
/** An argument formatter. */
|
||||||
\rst
|
|
||||||
An argument formatter based on the `curiously recurring template pattern
|
|
||||||
<http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.
|
|
||||||
|
|
||||||
To use `~fmt::BasicArgFormatter` define a subclass that implements some or
|
|
||||||
all of the visit methods with the same signatures as the methods in
|
|
||||||
`~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`.
|
|
||||||
Pass the subclass as the *Impl* template parameter. When a formatting
|
|
||||||
function processes an argument, it will dispatch to a visit method
|
|
||||||
specific to the argument type. For example, if the argument type is
|
|
||||||
``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass
|
|
||||||
will be called. If the subclass doesn't contain a method with this signature,
|
|
||||||
then a corresponding method of `~fmt::BasicArgFormatter` or its superclass
|
|
||||||
will be called.
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
template <typename Impl, typename Char>
|
template <typename Impl, typename Char>
|
||||||
class BasicArgFormatter : public internal::ArgFormatterBase<Impl, Char> {
|
class BasicArgFormatter : public internal::ArgFormatterBase<Impl, Char> {
|
||||||
private:
|
private:
|
||||||
@ -2257,8 +2074,10 @@ class BasicArgFormatter : public internal::ArgFormatterBase<Impl, Char> {
|
|||||||
FormatSpec &spec)
|
FormatSpec &spec)
|
||||||
: internal::ArgFormatterBase<Impl, Char>(writer, spec), ctx_(ctx) {}
|
: internal::ArgFormatterBase<Impl, Char>(writer, spec), ctx_(ctx) {}
|
||||||
|
|
||||||
|
using internal::ArgFormatterBase<Impl, Char>::operator();
|
||||||
|
|
||||||
/** 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 operator()(internal::Arg::CustomValue c) {
|
||||||
c.format(&this->writer(), c.value, &ctx_);
|
c.format(&this->writer(), c.value, &ctx_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -21,10 +21,12 @@ class CustomArgFormatter
|
|||||||
fmt::FormatSpec &s)
|
fmt::FormatSpec &s)
|
||||||
: fmt::BasicArgFormatter<CustomArgFormatter, char>(w, ctx, s) {}
|
: fmt::BasicArgFormatter<CustomArgFormatter, char>(w, ctx, s) {}
|
||||||
|
|
||||||
void visit_double(double value) {
|
using fmt::BasicArgFormatter<CustomArgFormatter, char>::operator();
|
||||||
|
|
||||||
|
void operator()(double value) {
|
||||||
if (round(value * pow(10, spec().precision())) == 0)
|
if (round(value * pow(10, spec().precision())) == 0)
|
||||||
value = 0;
|
value = 0;
|
||||||
fmt::BasicArgFormatter<CustomArgFormatter, char>::visit_double(value);
|
fmt::BasicArgFormatter<CustomArgFormatter, char>::operator()(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1621,16 +1621,23 @@ TEST(FormatTest, Enum) {
|
|||||||
|
|
||||||
class MockArgFormatter :
|
class MockArgFormatter :
|
||||||
public fmt::internal::ArgFormatterBase<MockArgFormatter, char> {
|
public fmt::internal::ArgFormatterBase<MockArgFormatter, char> {
|
||||||
|
private:
|
||||||
|
MOCK_METHOD1(call, void (int value));
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef fmt::internal::ArgFormatterBase<MockArgFormatter, char> Base;
|
typedef fmt::internal::ArgFormatterBase<MockArgFormatter, char> Base;
|
||||||
|
|
||||||
MockArgFormatter(fmt::Writer &w, fmt::format_context &ctx,
|
MockArgFormatter(fmt::Writer &w, fmt::format_context &ctx,
|
||||||
fmt::FormatSpec &s)
|
fmt::FormatSpec &s)
|
||||||
: fmt::internal::ArgFormatterBase<MockArgFormatter, char>(w, s) {
|
: fmt::internal::ArgFormatterBase<MockArgFormatter, char>(w, s) {
|
||||||
EXPECT_CALL(*this, visit_int(42));
|
EXPECT_CALL(*this, call(42));
|
||||||
}
|
}
|
||||||
|
|
||||||
MOCK_METHOD1(visit_int, void (int value));
|
using Base::operator();
|
||||||
|
|
||||||
|
void operator()(int value) { call(value); }
|
||||||
|
|
||||||
|
void operator()(fmt::internal::Arg::CustomValue) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) {
|
void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) {
|
||||||
|
@ -605,23 +605,23 @@ struct Result {
|
|||||||
Result(const wchar_t *s) : arg(make_arg<wchar_t>(s)) {}
|
Result(const wchar_t *s) : arg(make_arg<wchar_t>(s)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TestVisitor : fmt::ArgVisitor<TestVisitor, Result> {
|
struct TestVisitor {
|
||||||
Result visit_int(int value) { return value; }
|
Result operator()(int value) { return value; }
|
||||||
Result visit_uint(unsigned value) { return value; }
|
Result operator()(unsigned value) { return value; }
|
||||||
Result visit_long_long(fmt::LongLong value) { return value; }
|
Result operator()(fmt::LongLong value) { return value; }
|
||||||
Result visit_ulong_long(fmt::ULongLong value) { return value; }
|
Result operator()(fmt::ULongLong value) { return value; }
|
||||||
Result visit_double(double value) { return value; }
|
Result operator()(double value) { return value; }
|
||||||
Result visit_long_double(long double value) { return value; }
|
Result operator()(long double value) { return value; }
|
||||||
Result visit_char(int value) { return static_cast<char>(value); }
|
Result operator()(wchar_t value) { return static_cast<char>(value); }
|
||||||
Result visit_cstring(const char *s) { return s; }
|
Result operator()(const char *s) { return s; }
|
||||||
Result visit_string(fmt::internal::Arg::StringValue<char> s) {
|
Result operator()(fmt::format_arg::StringValue<char> s) {
|
||||||
return s.value;
|
return s.value;
|
||||||
}
|
}
|
||||||
Result visit_wstring(fmt::internal::Arg::StringValue<wchar_t> s) {
|
Result operator()(fmt::format_arg::StringValue<wchar_t> s) {
|
||||||
return s.value;
|
return s.value;
|
||||||
}
|
}
|
||||||
Result visit_pointer(const void *p) { return p; }
|
Result operator()(const void *p) { return p; }
|
||||||
Result visit_custom(fmt::internal::Arg::CustomValue c) {
|
Result operator()(fmt::format_arg::CustomValue c) {
|
||||||
return *static_cast<const ::Test*>(c.value);
|
return *static_cast<const ::Test*>(c.value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -658,55 +658,6 @@ TEST(ArgVisitorTest, VisitAll) {
|
|||||||
EXPECT_EQ(&t, result.arg.custom.value);
|
EXPECT_EQ(&t, result.arg.custom.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestAnyVisitor : fmt::ArgVisitor<TestAnyVisitor, Result> {
|
|
||||||
template <typename T>
|
|
||||||
Result visit_any_int(T value) { return value; }
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Result visit_any_double(T value) { return value; }
|
|
||||||
};
|
|
||||||
|
|
||||||
#undef EXPECT_RESULT
|
|
||||||
#define EXPECT_RESULT(type_code, value) { \
|
|
||||||
Result result = visit(TestAnyVisitor(), make_arg<char>(value)); \
|
|
||||||
EXPECT_EQ(Arg::type_code, result.arg.type); \
|
|
||||||
EXPECT_EQ(value, ArgInfo<Arg::type_code>::get(result.arg)); \
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ArgVisitorTest, VisitAny) {
|
|
||||||
EXPECT_RESULT(INT, 42);
|
|
||||||
EXPECT_RESULT(UINT, 42u);
|
|
||||||
EXPECT_RESULT(LONG_LONG, 42ll);
|
|
||||||
EXPECT_RESULT(ULONG_LONG, 42ull);
|
|
||||||
EXPECT_RESULT(DOUBLE, 4.2);
|
|
||||||
EXPECT_RESULT(LONG_DOUBLE, 4.2l);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TestUnhandledVisitor :
|
|
||||||
fmt::ArgVisitor<TestUnhandledVisitor, const char *> {
|
|
||||||
const char *visit_unhandled_arg() { return "test"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
#define EXPECT_UNHANDLED(value) \
|
|
||||||
EXPECT_STREQ("test", visit(TestUnhandledVisitor(), make_arg<wchar_t>(value)));
|
|
||||||
|
|
||||||
TEST(ArgVisitorTest, VisitUnhandledArg) {
|
|
||||||
EXPECT_UNHANDLED(42);
|
|
||||||
EXPECT_UNHANDLED(42u);
|
|
||||||
EXPECT_UNHANDLED(42ll);
|
|
||||||
EXPECT_UNHANDLED(42ull);
|
|
||||||
EXPECT_UNHANDLED(4.2);
|
|
||||||
EXPECT_UNHANDLED(4.2l);
|
|
||||||
EXPECT_UNHANDLED('x');
|
|
||||||
const char STR[] = "abc";
|
|
||||||
EXPECT_UNHANDLED(STR);
|
|
||||||
const wchar_t WSTR[] = L"abc";
|
|
||||||
EXPECT_UNHANDLED(WSTR);
|
|
||||||
const void *p = STR;
|
|
||||||
EXPECT_UNHANDLED(p);
|
|
||||||
EXPECT_UNHANDLED(::Test());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ArgVisitorTest, VisitInvalidArg) {
|
TEST(ArgVisitorTest, VisitInvalidArg) {
|
||||||
Arg arg = Arg();
|
Arg arg = Arg();
|
||||||
arg.type = static_cast<Arg::Type>(Arg::NONE);
|
arg.type = static_cast<Arg::Type>(Arg::NONE);
|
||||||
|
Loading…
Reference in New Issue
Block a user