Compose Arg instead of inheriting from Value

This commit is contained in:
Dean Moldovan 2015-10-19 01:18:32 +02:00
parent 5c76d107cb
commit 8a9ad00ab3
5 changed files with 87 additions and 79 deletions

View File

@ -304,20 +304,20 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
// Extra casts are used to silence warnings. // Extra casts are used to silence warnings.
if (is_signed) { if (is_signed) {
arg_.type = Arg::INT; arg_.type = Arg::INT;
arg_.int_value = static_cast<int>(static_cast<T>(value)); arg_.value.int_value = static_cast<int>(static_cast<T>(value));
} else { } else {
arg_.type = Arg::UINT; arg_.type = Arg::UINT;
arg_.uint_value = static_cast<unsigned>( arg_.value.uint_value = static_cast<unsigned>(
static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value)); static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
} }
} else { } else {
if (is_signed) { if (is_signed) {
arg_.type = Arg::LONG_LONG; arg_.type = Arg::LONG_LONG;
arg_.long_long_value = arg_.value.long_long_value =
static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value); static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
} else { } else {
arg_.type = Arg::ULONG_LONG; arg_.type = Arg::ULONG_LONG;
arg_.ulong_long_value = arg_.value.ulong_long_value =
static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value); static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
} }
} }
@ -337,7 +337,7 @@ class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
template <typename T> template <typename T>
void visit_any_int(T value) { void visit_any_int(T value) {
arg_.type = Arg::CHAR; arg_.type = Arg::CHAR;
arg_.int_value = static_cast<char>(value); arg_.value.int_value = static_cast<char>(value);
} }
}; };
} // namespace } // namespace
@ -405,7 +405,7 @@ class PrintfArgFormatter :
write_null_pointer(); write_null_pointer();
} }
void visit_custom(Arg::CustomValue c) { void visit_custom(Value::CustomValue c) {
BasicFormatter<Char> formatter(ArgList(), this->writer()); BasicFormatter<Char> formatter(ArgList(), this->writer());
const Char format_str[] = {'}', 0}; const Char format_str[] = {'}', 0};
const Char *format = format_str; const Char *format = format_str;
@ -627,7 +627,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
internal::Arg::Type arg_type = args.type(i); internal::Arg::Type arg_type = args.type(i);
if (arg_type == internal::Arg::NAMED_ARG) { if (arg_type == internal::Arg::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); named_arg = static_cast<const NamedArg*>(args.args_[i].value.pointer);
map_.insert(Pair(named_arg->name, *named_arg)); map_.insert(Pair(named_arg->name, *named_arg));
} }
} }
@ -636,7 +636,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
case internal::Arg::NONE: case internal::Arg::NONE:
return; return;
case internal::Arg::NAMED_ARG: case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); named_arg = static_cast<const NamedArg*>(args.args_[i].value.pointer);
map_.insert(Pair(named_arg->name, *named_arg)); map_.insert(Pair(named_arg->name, *named_arg));
break; break;
default: default:
@ -658,7 +658,7 @@ FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
error = "argument index out of range"; error = "argument index out of range";
break; break;
case Arg::NAMED_ARG: case Arg::NAMED_ARG:
arg = *static_cast<const internal::Arg*>(arg.pointer); arg = *static_cast<const internal::Arg*>(arg.value.pointer);
default: default:
/*nothing*/; /*nothing*/;
} }

109
format.h
View File

@ -927,7 +927,11 @@ struct Value {
StringValue<wchar_t> wstring; StringValue<wchar_t> wstring;
CustomValue custom; CustomValue custom;
}; };
};
// A formatting argument. It is a POD type to allow storage in
// internal::MemoryBuffer.
struct Arg {
enum Type { enum Type {
NONE, NAMED_ARG, NONE, NAMED_ARG,
// Integer types should go first, // Integer types should go first,
@ -936,11 +940,8 @@ struct Value {
DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
CSTRING, STRING, WSTRING, POINTER, CUSTOM CSTRING, STRING, WSTRING, POINTER, CUSTOM
}; };
};
// A formatting argument. It is a POD type to allow storage in Value value;
// internal::MemoryBuffer.
struct Arg : Value {
Type type; Type type;
}; };
@ -1044,7 +1045,7 @@ struct Not<false> { enum { value = 1 }; };
// Makes an Arg object from any type. // Makes an Arg object from any type.
template <typename Formatter> template <typename Formatter>
class MakeValue : public Arg { class MakeValue : public Value {
public: public:
typedef typename Formatter::Char Char; typedef typename Formatter::Char Char;
@ -1206,9 +1207,10 @@ struct NamedArg : Arg {
typedef internal::MakeValue< BasicFormatter<Char> > MakeValue; typedef internal::MakeValue< BasicFormatter<Char> > MakeValue;
template <typename T> template <typename T>
NamedArg(BasicStringRef<Char> argname, const T &value) NamedArg(BasicStringRef<Char> argname, const T &x)
: Arg(MakeValue(value)), name(argname) { : name(argname) {
type = static_cast<Arg::Type>(MakeValue::type(value)); value = MakeValue(x);
type = static_cast<Arg::Type>(MakeValue::type(x));
} }
}; };
@ -1281,16 +1283,16 @@ class ArgVisitor {
Result visit_cstring(const char *) { Result visit_cstring(const char *) {
return FMT_DISPATCH(visit_unhandled_arg()); return FMT_DISPATCH(visit_unhandled_arg());
} }
Result visit_string(Arg::StringValue<char>) { Result visit_string(Value::StringValue<char>) {
return FMT_DISPATCH(visit_unhandled_arg()); return FMT_DISPATCH(visit_unhandled_arg());
} }
Result visit_wstring(Arg::StringValue<wchar_t>) { Result visit_wstring(Value::StringValue<wchar_t>) {
return FMT_DISPATCH(visit_unhandled_arg()); return FMT_DISPATCH(visit_unhandled_arg());
} }
Result visit_pointer(const void *) { Result visit_pointer(const void *) {
return FMT_DISPATCH(visit_unhandled_arg()); return FMT_DISPATCH(visit_unhandled_arg());
} }
Result visit_custom(Arg::CustomValue) { Result visit_custom(Value::CustomValue) {
return FMT_DISPATCH(visit_unhandled_arg()); return FMT_DISPATCH(visit_unhandled_arg());
} }
@ -1300,31 +1302,31 @@ class ArgVisitor {
FMT_ASSERT(false, "invalid argument type"); FMT_ASSERT(false, "invalid argument type");
return Result(); return Result();
case Arg::INT: case Arg::INT:
return FMT_DISPATCH(visit_int(arg.int_value)); return FMT_DISPATCH(visit_int(arg.value.int_value));
case Arg::UINT: case Arg::UINT:
return FMT_DISPATCH(visit_uint(arg.uint_value)); return FMT_DISPATCH(visit_uint(arg.value.uint_value));
case Arg::LONG_LONG: case Arg::LONG_LONG:
return FMT_DISPATCH(visit_long_long(arg.long_long_value)); return FMT_DISPATCH(visit_long_long(arg.value.long_long_value));
case Arg::ULONG_LONG: case Arg::ULONG_LONG:
return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); return FMT_DISPATCH(visit_ulong_long(arg.value.ulong_long_value));
case Arg::BOOL: case Arg::BOOL:
return FMT_DISPATCH(visit_bool(arg.int_value != 0)); return FMT_DISPATCH(visit_bool(arg.value.int_value != 0));
case Arg::CHAR: case Arg::CHAR:
return FMT_DISPATCH(visit_char(arg.int_value)); return FMT_DISPATCH(visit_char(arg.value.int_value));
case Arg::DOUBLE: case Arg::DOUBLE:
return FMT_DISPATCH(visit_double(arg.double_value)); return FMT_DISPATCH(visit_double(arg.value.double_value));
case Arg::LONG_DOUBLE: case Arg::LONG_DOUBLE:
return FMT_DISPATCH(visit_long_double(arg.long_double_value)); return FMT_DISPATCH(visit_long_double(arg.value.long_double_value));
case Arg::CSTRING: case Arg::CSTRING:
return FMT_DISPATCH(visit_cstring(arg.string.value)); return FMT_DISPATCH(visit_cstring(arg.value.string.value));
case Arg::STRING: case Arg::STRING:
return FMT_DISPATCH(visit_string(arg.string)); return FMT_DISPATCH(visit_string(arg.value.string));
case Arg::WSTRING: case Arg::WSTRING:
return FMT_DISPATCH(visit_wstring(arg.wstring)); return FMT_DISPATCH(visit_wstring(arg.value.wstring));
case Arg::POINTER: case Arg::POINTER:
return FMT_DISPATCH(visit_pointer(arg.pointer)); return FMT_DISPATCH(visit_pointer(arg.value.pointer));
case Arg::CUSTOM: case Arg::CUSTOM:
return FMT_DISPATCH(visit_custom(arg.custom)); return FMT_DISPATCH(visit_custom(arg.value.custom));
} }
} }
}; };
@ -1385,9 +1387,8 @@ class ArgList {
bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE; bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE;
if (index < MAX_PACKED_ARGS) { if (index < MAX_PACKED_ARGS) {
Arg::Type arg_type = type(index); Arg::Type arg_type = type(index);
internal::Value &val = arg;
if (arg_type != Arg::NONE) if (arg_type != Arg::NONE)
val = use_values ? values_[index] : args_[index]; arg.value = use_values ? values_[index] : args_[index].value;
arg.type = arg_type; arg.type = arg_type;
return arg; return arg;
} }
@ -1665,12 +1666,12 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> {
void write(bool value) { void write(bool value) {
const char *str_value = value ? "true" : "false"; const char *str_value = value ? "true" : "false";
Arg::StringValue<char> str = { str_value, std::strlen(str_value) }; Value::StringValue<char> str = { str_value, std::strlen(str_value) };
writer_.write_str(str, spec_); writer_.write_str(str, spec_);
} }
void write(const char *value) { void write(const char *value) {
Arg::StringValue<char> str = {value, value != 0 ? std::strlen(value) : 0}; Value::StringValue<char> str = {value, value != 0 ? std::strlen(value) : 0};
writer_.write_str(str, spec_); writer_.write_str(str, spec_);
} }
@ -1726,13 +1727,13 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> {
write(value); write(value);
} }
void visit_string(Arg::StringValue<char> value) { void visit_string(Value::StringValue<char> value) {
writer_.write_str(value, spec_); writer_.write_str(value, spec_);
} }
using ArgVisitor<Impl, void>::visit_wstring; using ArgVisitor<Impl, void>::visit_wstring;
void visit_wstring(Arg::StringValue<Char> value) { void visit_wstring(Value::StringValue<Char> value) {
writer_.write_str(value, spec_); writer_.write_str(value, spec_);
} }
@ -1756,7 +1757,7 @@ class BasicArgFormatter :
: ArgFormatterBase<BasicArgFormatter<Char>, Char>(f.writer(), s), : ArgFormatterBase<BasicArgFormatter<Char>, Char>(f.writer(), s),
formatter_(f), format_(fmt) {} formatter_(f), format_(fmt) {}
void visit_custom(Arg::CustomValue c) { void visit_custom(Value::CustomValue c) {
c.format(&formatter_, c.value, &format_); c.format(&formatter_, c.value, &format_);
} }
}; };
@ -1931,12 +1932,15 @@ inline void set_types(Value *, const Args & ...) {
template <typename Formatter, typename Value> template <typename Formatter, typename Value>
inline void store_args(Value *) {} inline void store_args(Value *) {}
template <typename Formatter, typename Arg, typename T, typename... Args> template <typename Formatter, typename T, typename... Args>
inline void store_args(Arg *args, const T &arg, const Args & ... tail) { inline void store_args(Arg *args, const T &arg, const Args & ... tail) {
// Assign only the Value subobject of Arg and don't overwrite type (if any) args->value = MakeValue<Formatter>(arg);
// that is assigned by set_types. store_args<Formatter>(args + 1, tail...);
Value &value = *args; }
value = MakeValue<Formatter>(arg);
template <typename Formatter, typename T, typename... Args>
inline void store_args(Value *args, const T &arg, const Args & ... tail) {
*args = MakeValue<Formatter>(arg);
store_args<Formatter>(args + 1, tail...); store_args<Formatter>(args + 1, tail...);
} }
@ -2242,7 +2246,7 @@ class BasicWriter {
CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec);
template <typename StrChar> template <typename StrChar>
void write_str(const internal::Arg::StringValue<StrChar> &str, void write_str(const internal::Value::StringValue<StrChar> &str,
const FormatSpec &spec); const FormatSpec &spec);
// This following methods are private to disallow writing wide characters // This following methods are private to disallow writing wide characters
@ -2461,7 +2465,7 @@ typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(
template <typename Char> template <typename Char>
template <typename StrChar> template <typename StrChar>
void BasicWriter<Char>::write_str( void BasicWriter<Char>::write_str(
const internal::Arg::StringValue<StrChar> &s, const FormatSpec &spec) { const internal::Value::StringValue<StrChar> &s, const FormatSpec &spec) {
// Check if StrChar is convertible to Char. // Check if StrChar is convertible to Char.
internal::CharTraits<Char>::convert(StrChar()); internal::CharTraits<Char>::convert(StrChar());
if (spec.type_ && spec.type_ != 's') if (spec.type_ && spec.type_ != 's')
@ -2921,7 +2925,8 @@ void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) {
BasicStringRef<Char> str(&buffer[0], format_buf.size()); BasicStringRef<Char> str(&buffer[0], format_buf.size());
typedef internal::MakeValue< BasicFormatter<Char> > MakeValue; typedef internal::MakeValue< BasicFormatter<Char> > MakeValue;
internal::Arg arg = MakeValue(str); internal::Arg arg;
arg.value = MakeValue(str);
arg.type = static_cast<internal::Arg::Type>(MakeValue::type(str)); arg.type = static_cast<internal::Arg::Type>(MakeValue::type(str));
format_str = f.format(format_str, arg); format_str = f.format(format_str, arg);
} }
@ -3462,7 +3467,7 @@ const Char *BasicFormatter<Char>::format(
FormatSpec spec; FormatSpec spec;
if (*s == ':') { if (*s == ':') {
if (arg.type == Arg::CUSTOM) { if (arg.type == Arg::CUSTOM) {
arg.custom.format(this, arg.custom.value, &s); arg.value.custom.format(this, arg.value.custom.value, &s);
return s; return s;
} }
++s; ++s;
@ -3542,20 +3547,20 @@ const Char *BasicFormatter<Char>::format(
ULongLong value = 0; ULongLong value = 0;
switch (width_arg.type) { switch (width_arg.type) {
case Arg::INT: case Arg::INT:
if (width_arg.int_value < 0) if (width_arg.value.int_value < 0)
FMT_THROW(FormatError("negative width")); FMT_THROW(FormatError("negative width"));
value = width_arg.int_value; value = width_arg.value.int_value;
break; break;
case Arg::UINT: case Arg::UINT:
value = width_arg.uint_value; value = width_arg.value.uint_value;
break; break;
case Arg::LONG_LONG: case Arg::LONG_LONG:
if (width_arg.long_long_value < 0) if (width_arg.value.long_long_value < 0)
FMT_THROW(FormatError("negative width")); FMT_THROW(FormatError("negative width"));
value = width_arg.long_long_value; value = width_arg.value.long_long_value;
break; break;
case Arg::ULONG_LONG: case Arg::ULONG_LONG:
value = width_arg.ulong_long_value; value = width_arg.value.ulong_long_value;
break; break;
default: default:
FMT_THROW(FormatError("width is not integer")); FMT_THROW(FormatError("width is not integer"));
@ -3580,20 +3585,20 @@ const Char *BasicFormatter<Char>::format(
ULongLong value = 0; ULongLong value = 0;
switch (precision_arg.type) { switch (precision_arg.type) {
case Arg::INT: case Arg::INT:
if (precision_arg.int_value < 0) if (precision_arg.value.int_value < 0)
FMT_THROW(FormatError("negative precision")); FMT_THROW(FormatError("negative precision"));
value = precision_arg.int_value; value = precision_arg.value.int_value;
break; break;
case Arg::UINT: case Arg::UINT:
value = precision_arg.uint_value; value = precision_arg.value.uint_value;
break; break;
case Arg::LONG_LONG: case Arg::LONG_LONG:
if (precision_arg.long_long_value < 0) if (precision_arg.value.long_long_value < 0)
FMT_THROW(FormatError("negative precision")); FMT_THROW(FormatError("negative precision"));
value = precision_arg.long_long_value; value = precision_arg.value.long_long_value;
break; break;
case Arg::ULONG_LONG: case Arg::ULONG_LONG:
value = precision_arg.ulong_long_value; value = precision_arg.value.ulong_long_value;
break; break;
default: default:
FMT_THROW(FormatError("precision is not integer")); FMT_THROW(FormatError("precision is not integer"));

View File

@ -42,7 +42,7 @@ TEST(FormatTest, ArgConverter) {
using fmt::internal::Arg; using fmt::internal::Arg;
Arg arg = Arg(); Arg arg = Arg();
arg.type = Arg::LONG_LONG; arg.type = Arg::LONG_LONG;
arg.long_long_value = std::numeric_limits<fmt::LongLong>::max(); arg.value.long_long_value = std::numeric_limits<fmt::LongLong>::max();
fmt::ArgConverter<fmt::LongLong>(arg, 'd').visit(arg); fmt::ArgConverter<fmt::LongLong>(arg, 'd').visit(arg);
EXPECT_EQ(Arg::LONG_LONG, arg.type); EXPECT_EQ(Arg::LONG_LONG, arg.type);
} }

View File

@ -70,7 +70,7 @@ int result;
void func(const char *format, const fmt::ArgList &args) { \ void func(const char *format, const fmt::ArgList &args) { \
result = 0; \ result = 0; \
for (unsigned i = 0; args[i].type; ++i) \ for (unsigned i = 0; args[i].type; ++i) \
result += args[i].int_value; \ result += args[i].value.int_value; \
} }
MAKE_TEST(test_func) MAKE_TEST(test_func)
@ -101,7 +101,7 @@ struct S {};
int test_variadic(FMT_GEN(10, GET_TYPE), const fmt::ArgList &args) { \ int test_variadic(FMT_GEN(10, GET_TYPE), const fmt::ArgList &args) { \
int result = 0; \ int result = 0; \
for (unsigned i = 0; args[i].type; ++i) \ for (unsigned i = 0; args[i].type; ++i) \
result += args[i].int_value; \ result += args[i].value.int_value; \
return result; return result;
} }
FMT_VARIADIC(int, test_variadic, FMT_VARIADIC(int, test_variadic,

View File

@ -53,6 +53,7 @@
using fmt::StringRef; using fmt::StringRef;
using fmt::internal::Arg; using fmt::internal::Arg;
using fmt::internal::Value;
using fmt::Buffer; using fmt::Buffer;
using fmt::internal::MemoryBuffer; using fmt::internal::MemoryBuffer;
@ -70,7 +71,8 @@ std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &os, Test) {
template <typename Char, typename T> template <typename Char, typename T>
Arg make_arg(const T &value) { Arg make_arg(const T &value) {
typedef fmt::internal::MakeValue< fmt::BasicFormatter<Char> > MakeValue; typedef fmt::internal::MakeValue< fmt::BasicFormatter<Char> > MakeValue;
Arg arg = MakeValue(value); Arg arg;
arg.value = MakeValue(value);
arg.type = static_cast<Arg::Type>(MakeValue::type(value)); arg.type = static_cast<Arg::Type>(MakeValue::type(value));
return arg; return arg;
} }
@ -409,7 +411,7 @@ struct ArgInfo;
#define ARG_INFO(type_code, Type, field) \ #define ARG_INFO(type_code, Type, field) \
template <> \ template <> \
struct ArgInfo<Arg::type_code> { \ struct ArgInfo<Arg::type_code> { \
static Type get(const Arg &arg) { return arg.field; } \ static Type get(const Arg &arg) { return arg.value.field; } \
}; };
ARG_INFO(INT, int, int_value); ARG_INFO(INT, int, int_value);
@ -424,12 +426,12 @@ ARG_INFO(CSTRING, const char *, string.value);
ARG_INFO(STRING, const char *, string.value); ARG_INFO(STRING, const char *, string.value);
ARG_INFO(WSTRING, const wchar_t *, wstring.value); ARG_INFO(WSTRING, const wchar_t *, wstring.value);
ARG_INFO(POINTER, const void *, pointer); ARG_INFO(POINTER, const void *, pointer);
ARG_INFO(CUSTOM, Arg::CustomValue, custom); ARG_INFO(CUSTOM, Value::CustomValue, custom);
#define CHECK_ARG_INFO(Type, field, value) { \ #define CHECK_ARG_INFO(Type, field, x) { \
Arg arg = Arg(); \ Arg arg = Arg(); \
arg.field = value; \ arg.value.field = x; \
EXPECT_EQ(value, ArgInfo<Arg::Type>::get(arg)); \ EXPECT_EQ(x, ArgInfo<Arg::Type>::get(arg)); \
} }
TEST(ArgTest, ArgInfo) { TEST(ArgTest, ArgInfo) {
@ -447,7 +449,7 @@ TEST(ArgTest, ArgInfo) {
int p = 0; int p = 0;
CHECK_ARG_INFO(POINTER, pointer, &p); CHECK_ARG_INFO(POINTER, pointer, &p);
Arg arg = Arg(); Arg arg = Arg();
arg.custom.value = &p; arg.value.custom.value = &p;
EXPECT_EQ(&p, ArgInfo<Arg::CUSTOM>::get(arg).value); EXPECT_EQ(&p, ArgInfo<Arg::CUSTOM>::get(arg).value);
} }
@ -562,11 +564,11 @@ TEST(ArgTest, MakeArg) {
::Test t; ::Test t;
Arg arg = make_arg<char>(t); Arg arg = make_arg<char>(t);
EXPECT_EQ(fmt::internal::Arg::CUSTOM, arg.type); EXPECT_EQ(fmt::internal::Arg::CUSTOM, arg.type);
EXPECT_EQ(&t, arg.custom.value); EXPECT_EQ(&t, arg.value.custom.value);
fmt::MemoryWriter w; fmt::MemoryWriter w;
fmt::BasicFormatter<char> formatter(fmt::ArgList(), w); fmt::BasicFormatter<char> formatter(fmt::ArgList(), w);
const char *s = "}"; const char *s = "}";
arg.custom.format(&formatter, &t, &s); arg.value.custom.format(&formatter, &t, &s);
EXPECT_EQ("test", w.str()); EXPECT_EQ("test", w.str());
} }
@ -585,10 +587,11 @@ void format(CustomFormatter &, const char *&s, const Test &) {
TEST(UtilTest, MakeValueWithCustomFormatter) { TEST(UtilTest, MakeValueWithCustomFormatter) {
::Test t; ::Test t;
Arg arg = fmt::internal::MakeValue<CustomFormatter>(t); Arg arg;
arg.value = fmt::internal::MakeValue<CustomFormatter>(t);
CustomFormatter formatter; CustomFormatter formatter;
const char *s = ""; const char *s = "";
arg.custom.format(&formatter, &t, &s); arg.value.custom.format(&formatter, &t, &s);
EXPECT_STREQ("custom_format", s); EXPECT_STREQ("custom_format", s);
} }
@ -611,10 +614,10 @@ struct TestVisitor : fmt::internal::ArgVisitor<TestVisitor, Result> {
Result visit_long_double(long double value) { return value; } Result visit_long_double(long double value) { return value; }
Result visit_char(int value) { return static_cast<char>(value); } Result visit_char(int value) { return static_cast<char>(value); }
Result visit_cstring(const char *s) { return s; } Result visit_cstring(const char *s) { return s; }
Result visit_string(Arg::StringValue<char> s) { return s.value; } Result visit_string(Value::StringValue<char> s) { return s.value; }
Result visit_wstring(Arg::StringValue<wchar_t> s) { return s.value; } Result visit_wstring(Value::StringValue<wchar_t> s) { return s.value; }
Result visit_pointer(const void *p) { return p; } Result visit_pointer(const void *p) { return p; }
Result visit_custom(Arg::CustomValue c) { Result visit_custom(Value::CustomValue c) {
return *static_cast<const ::Test*>(c.value); return *static_cast<const ::Test*>(c.value);
} }
}; };
@ -648,7 +651,7 @@ TEST(ArgVisitorTest, VisitAll) {
::Test t; ::Test t;
Result result = TestVisitor().visit(make_arg<char>(t)); Result result = TestVisitor().visit(make_arg<char>(t));
EXPECT_EQ(Arg::CUSTOM, result.arg.type); EXPECT_EQ(Arg::CUSTOM, result.arg.type);
EXPECT_EQ(&t, result.arg.custom.value); EXPECT_EQ(&t, result.arg.value.custom.value);
} }
struct TestAnyVisitor : fmt::internal::ArgVisitor<TestAnyVisitor, Result> { struct TestAnyVisitor : fmt::internal::ArgVisitor<TestAnyVisitor, Result> {