Move stuff out of internal::Value

This commit is contained in:
Victor Zverovich 2016-12-15 07:51:40 -08:00
parent e1ee5bf0ba
commit 6cba8fe9ba
4 changed files with 107 additions and 109 deletions

View File

@ -989,22 +989,30 @@ FMT_API void format_windows_error(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT; fmt::StringRef message) FMT_NOEXCEPT;
#endif #endif
// A formatting argument value. enum Type {
struct Value { NONE, NAMED_ARG,
// Integer types should go first,
INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR,
// followed by floating-point types.
DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
CSTRING, STRING, WSTRING, POINTER, CUSTOM
};
template <typename Char> template <typename Char>
struct StringValue { struct StringValue {
const Char *value; const Char *value;
std::size_t size; std::size_t size;
}; };
typedef void (*FormatFunc)( typedef void (*FormatFunc)(void *writer, const void *arg, void *ctx);
void *writer, const void *arg, void *ctx);
struct CustomValue { struct CustomValue {
const void *value; const void *value;
FormatFunc format; FormatFunc format;
}; };
// A formatting argument value.
struct Value {
union { union {
int int_value; int int_value;
unsigned uint_value; unsigned uint_value;
@ -1019,15 +1027,6 @@ struct Value {
StringValue<wchar_t> wstring; // TODO: Char StringValue<wchar_t> wstring; // TODO: Char
CustomValue custom; CustomValue custom;
}; };
enum Type {
NONE, NAMED_ARG,
// Integer types should go first,
INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR,
// followed by floating-point types.
DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
CSTRING, STRING, WSTRING, POINTER, CUSTOM
};
}; };
template <typename Char> template <typename Char>
@ -1042,7 +1041,7 @@ class basic_format_args;
template <typename Char> template <typename Char>
class basic_format_arg : public internal::Value { class basic_format_arg : public internal::Value {
protected: protected:
Type type_; internal::Type type_;
template <typename Visitor, typename CharType> template <typename Visitor, typename CharType>
friend typename std::result_of<Visitor(int)>::type friend typename std::result_of<Visitor(int)>::type
@ -1055,25 +1054,25 @@ class basic_format_arg : public internal::Value {
friend class internal::ArgMap; friend class internal::ArgMap;
void check_type() const { void check_type() const {
FMT_ASSERT(type_ > NAMED_ARG, "invalid argument type"); FMT_ASSERT(type_ > internal::NAMED_ARG, "invalid argument type");
} }
public: public:
explicit operator bool() const noexcept { return type_ != NONE; } explicit operator bool() const noexcept { return type_ != internal::NONE; }
bool is_integral() const { bool is_integral() const {
check_type(); check_type();
return type_ <= LAST_INTEGER_TYPE; return type_ <= internal::LAST_INTEGER_TYPE;
} }
bool is_numeric() const { bool is_numeric() const {
check_type(); check_type();
return type_ <= LAST_NUMERIC_TYPE; return type_ <= internal::LAST_NUMERIC_TYPE;
} }
bool is_pointer() const { bool is_pointer() const {
check_type(); check_type();
return type_ == POINTER; return type_ == internal::POINTER;
} }
}; };
@ -1091,35 +1090,35 @@ template <typename Visitor, typename Char>
typename std::result_of<Visitor(int)>::type typename std::result_of<Visitor(int)>::type
visit(Visitor &&vis, basic_format_arg<Char> arg) { visit(Visitor &&vis, basic_format_arg<Char> arg) {
switch (arg.type_) { switch (arg.type_) {
case format_arg::NONE: case internal::NONE:
case format_arg::NAMED_ARG: case internal::NAMED_ARG:
FMT_ASSERT(false, "invalid argument type"); FMT_ASSERT(false, "invalid argument type");
break; break;
case format_arg::INT: case internal::INT:
return vis(arg.int_value); return vis(arg.int_value);
case format_arg::UINT: case internal::UINT:
return vis(arg.uint_value); return vis(arg.uint_value);
case format_arg::LONG_LONG: case internal::LONG_LONG:
return vis(arg.long_long_value); return vis(arg.long_long_value);
case format_arg::ULONG_LONG: case internal::ULONG_LONG:
return vis(arg.ulong_long_value); return vis(arg.ulong_long_value);
case format_arg::BOOL: case internal::BOOL:
return vis(arg.int_value != 0); return vis(arg.int_value != 0);
case format_arg::CHAR: case internal::CHAR:
return vis(static_cast<Char>(arg.int_value)); return vis(static_cast<Char>(arg.int_value));
case format_arg::DOUBLE: case internal::DOUBLE:
return vis(arg.double_value); return vis(arg.double_value);
case format_arg::LONG_DOUBLE: case internal::LONG_DOUBLE:
return vis(arg.long_double_value); return vis(arg.long_double_value);
case format_arg::CSTRING: case internal::CSTRING:
return vis(arg.string.value); return vis(arg.string.value);
case format_arg::STRING: case internal::STRING:
return vis(StringRef(arg.string.value, arg.string.size)); return vis(StringRef(arg.string.value, arg.string.size));
case format_arg::WSTRING: case internal::WSTRING:
return vis(WStringRef(arg.wstring.value, arg.wstring.size)); return vis(WStringRef(arg.wstring.value, arg.wstring.size));
case format_arg::POINTER: case internal::POINTER:
return vis(arg.pointer); return vis(arg.pointer);
case format_arg::CUSTOM: case internal::CUSTOM:
return vis(arg.custom); return vis(arg.custom);
} }
return typename std::result_of<Visitor(int)>::type(); return typename std::result_of<Visitor(int)>::type();
@ -1262,76 +1261,75 @@ struct IsNamedArg : std::false_type {};
template <typename Char> template <typename Char>
struct IsNamedArg< NamedArg<Char> > : std::true_type {}; struct IsNamedArg< NamedArg<Char> > : std::true_type {};
typedef Value::Type Type;
template <typename T> template <typename T>
constexpr Type gettype() { constexpr Type gettype() {
typedef format_arg Arg; typedef format_arg Arg;
return IsNamedArg<T>::value ? return IsNamedArg<T>::value ?
Arg::NAMED_ARG : (ConvertToInt<T>::value ? Arg::INT : Arg::CUSTOM); internal::NAMED_ARG :
(ConvertToInt<T>::value ? internal::INT : internal::CUSTOM);
} }
template <> constexpr Type gettype<bool>() { return format_arg::BOOL; } template <> constexpr Type gettype<bool>() { return internal::BOOL; }
template <> constexpr Type gettype<short>() { return format_arg::INT; } template <> constexpr Type gettype<short>() { return internal::INT; }
template <> constexpr Type gettype<unsigned short>() { template <> constexpr Type gettype<unsigned short>() {
return format_arg::UINT; return internal::UINT;
} }
template <> constexpr Type gettype<int>() { return format_arg::INT; } template <> constexpr Type gettype<int>() { return internal::INT; }
template <> constexpr Type gettype<unsigned>() { return format_arg::UINT; } template <> constexpr Type gettype<unsigned>() { return internal::UINT; }
template <> constexpr Type gettype<long>() { template <> constexpr Type gettype<long>() {
return sizeof(long) == sizeof(int) ? format_arg::INT : format_arg::LONG_LONG; return sizeof(long) == sizeof(int) ? internal::INT : internal::LONG_LONG;
} }
template <> constexpr Type gettype<unsigned long>() { template <> constexpr Type gettype<unsigned long>() {
return sizeof(unsigned long) == sizeof(unsigned) ? return sizeof(unsigned long) == sizeof(unsigned) ?
format_arg::UINT : format_arg::ULONG_LONG; internal::UINT : internal::ULONG_LONG;
} }
template <> constexpr Type gettype<LongLong>() { return format_arg::LONG_LONG; } template <> constexpr Type gettype<LongLong>() { return internal::LONG_LONG; }
template <> constexpr Type gettype<ULongLong>() { template <> constexpr Type gettype<ULongLong>() {
return format_arg::ULONG_LONG; return internal::ULONG_LONG;
} }
template <> constexpr Type gettype<float>() { return format_arg::DOUBLE; } template <> constexpr Type gettype<float>() { return internal::DOUBLE; }
template <> constexpr Type gettype<double>() { return format_arg::DOUBLE; } template <> constexpr Type gettype<double>() { return internal::DOUBLE; }
template <> constexpr Type gettype<long double>() { template <> constexpr Type gettype<long double>() {
return format_arg::LONG_DOUBLE; return internal::LONG_DOUBLE;
} }
template <> constexpr Type gettype<signed char>() { return format_arg::INT; } template <> constexpr Type gettype<signed char>() { return internal::INT; }
template <> constexpr Type gettype<unsigned char>() { return format_arg::UINT; } template <> constexpr Type gettype<unsigned char>() { return internal::UINT; }
template <> constexpr Type gettype<char>() { return format_arg::CHAR; } template <> constexpr Type gettype<char>() { return internal::CHAR; }
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
template <> constexpr Type gettype<wchar_t>() { return format_arg::CHAR; } template <> constexpr Type gettype<wchar_t>() { return internal::CHAR; }
#endif #endif
template <> constexpr Type gettype<char *>() { return format_arg::CSTRING; } template <> constexpr Type gettype<char *>() { return internal::CSTRING; }
template <> constexpr Type gettype<const char *>() { template <> constexpr Type gettype<const char *>() {
return format_arg::CSTRING; return internal::CSTRING;
} }
template <> constexpr Type gettype<signed char *>() { template <> constexpr Type gettype<signed char *>() {
return format_arg::CSTRING; return internal::CSTRING;
} }
template <> constexpr Type gettype<const signed char *>() { template <> constexpr Type gettype<const signed char *>() {
return format_arg::CSTRING; return internal::CSTRING;
} }
template <> constexpr Type gettype<unsigned char *>() { template <> constexpr Type gettype<unsigned char *>() {
return format_arg::CSTRING; return internal::CSTRING;
} }
template <> constexpr Type gettype<const unsigned char *>() { template <> constexpr Type gettype<const unsigned char *>() {
return format_arg::CSTRING; return internal::CSTRING;
} }
template <> constexpr Type gettype<std::string>() { return format_arg::STRING; } template <> constexpr Type gettype<std::string>() { return internal::STRING; }
template <> constexpr Type gettype<StringRef>() { return format_arg::STRING; } template <> constexpr Type gettype<StringRef>() { return internal::STRING; }
template <> constexpr Type gettype<CStringRef>() { return format_arg::CSTRING; } template <> constexpr Type gettype<CStringRef>() { return internal::CSTRING; }
template <> constexpr Type gettype<wchar_t *>() { return format_arg::WSTRING; } template <> constexpr Type gettype<wchar_t *>() { return internal::WSTRING; }
template <> constexpr Type gettype<const wchar_t *>() { template <> constexpr Type gettype<const wchar_t *>() {
return format_arg::WSTRING; return internal::WSTRING;
} }
template <> constexpr Type gettype<std::wstring>() { template <> constexpr Type gettype<std::wstring>() {
return format_arg::WSTRING; return internal::WSTRING;
} }
template <> constexpr Type gettype<WStringRef>() { return format_arg::WSTRING; } template <> constexpr Type gettype<WStringRef>() { return internal::WSTRING; }
template <> constexpr Type gettype<void *>() { return format_arg::POINTER; } template <> constexpr Type gettype<void *>() { return internal::POINTER; }
template <> constexpr Type gettype<const void *>() { template <> constexpr Type gettype<const void *>() {
return format_arg::POINTER; return internal::POINTER;
} }
template <typename T> template <typename T>
@ -1390,7 +1388,7 @@ class MakeValue : public basic_format_arg<typename Context::char_type> {
#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ #define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \
MakeValue(Type value) { \ MakeValue(Type value) { \
static_assert(internal::type<Type>() == MakeValue::TYPE, "invalid type"); \ static_assert(internal::type<Type>() == internal::TYPE, "invalid type"); \
this->field = rhs; \ this->field = rhs; \
} }
@ -1431,14 +1429,14 @@ class MakeValue : public basic_format_arg<typename Context::char_type> {
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
typedef typename WCharHelper<wchar_t, Char>::Supported WChar; typedef typename WCharHelper<wchar_t, Char>::Supported WChar;
MakeValue(WChar value) { MakeValue(WChar value) {
static_assert(internal::type<WChar>() == MakeValue::CHAR, "invalid type"); static_assert(internal::type<WChar>() == internal::CHAR, "invalid type");
this->int_value = value; this->int_value = value;
} }
#endif #endif
#define FMT_MAKE_STR_VALUE(Type, TYPE) \ #define FMT_MAKE_STR_VALUE(Type, TYPE) \
MakeValue(Type value) { \ MakeValue(Type value) { \
static_assert(internal::type<Type>() == MakeValue::TYPE, "invalid type"); \ static_assert(internal::type<Type>() == internal::TYPE, "invalid type"); \
set_string(value); \ set_string(value); \
} }
@ -1454,7 +1452,7 @@ class MakeValue : public basic_format_arg<typename Context::char_type> {
#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \
MakeValue(typename WCharHelper<Type, Char>::Supported value) { \ MakeValue(typename WCharHelper<Type, Char>::Supported value) { \
static_assert(internal::type<Type>() == MakeValue::TYPE, "invalid type"); \ static_assert(internal::type<Type>() == internal::TYPE, "invalid type"); \
set_string(value); \ set_string(value); \
} }
@ -1470,7 +1468,7 @@ class MakeValue : public basic_format_arg<typename Context::char_type> {
MakeValue(const T &value, MakeValue(const T &value,
typename EnableIf<Not< typename EnableIf<Not<
ConvertToInt<T>::value>::value, int>::type = 0) { ConvertToInt<T>::value>::value, int>::type = 0) {
static_assert(internal::type<T>() == MakeValue::CUSTOM, "invalid type"); static_assert(internal::type<T>() == internal::CUSTOM, "invalid type");
this->custom.value = &value; this->custom.value = &value;
this->custom.format = &format_custom_arg<T>; this->custom.format = &format_custom_arg<T>;
} }
@ -1478,7 +1476,7 @@ class MakeValue : public basic_format_arg<typename Context::char_type> {
template <typename T> template <typename T>
MakeValue(const T &value, MakeValue(const T &value,
typename EnableIf<ConvertToInt<T>::value, int>::type = 0) { typename EnableIf<ConvertToInt<T>::value, int>::type = 0) {
static_assert(internal::type<T>() == MakeValue::INT, "invalid type"); static_assert(internal::type<T>() == internal::INT, "invalid type");
this->int_value = value; this->int_value = value;
} }
@ -1487,7 +1485,7 @@ class MakeValue : public basic_format_arg<typename Context::char_type> {
template <typename Char_> template <typename Char_>
MakeValue(const NamedArg<Char_> &value) { MakeValue(const NamedArg<Char_> &value) {
static_assert( static_assert(
internal::type<const NamedArg<Char_> &>() == MakeValue::NAMED_ARG, internal::type<const NamedArg<Char_> &>() == internal::NAMED_ARG,
"invalid type"); "invalid type");
this->pointer = &value; this->pointer = &value;
} }
@ -1497,7 +1495,7 @@ template <typename Context>
class MakeArg : public basic_format_arg<typename Context::char_type> { class MakeArg : public basic_format_arg<typename Context::char_type> {
public: public:
MakeArg() { MakeArg() {
this->type_ = format_arg::NONE; this->type_ = internal::NONE;
} }
template <typename T> template <typename T>
@ -1589,10 +1587,10 @@ class basic_format_args {
const format_arg *args_; const format_arg *args_;
}; };
typename format_arg::Type type(unsigned index) const { typename internal::Type type(unsigned index) const {
unsigned shift = index * 4; unsigned shift = index * 4;
uint64_t mask = 0xf; uint64_t mask = 0xf;
return static_cast<typename format_arg::Type>( return static_cast<typename internal::Type>(
(types_ & (mask << shift)) >> shift); (types_ & (mask << shift)) >> shift);
} }
@ -1603,11 +1601,11 @@ class basic_format_args {
format_arg get(size_type index) const { format_arg get(size_type index) const {
format_arg arg; format_arg arg;
bool use_values = type(internal::MAX_PACKED_ARGS - 1) == format_arg::NONE; bool use_values = type(internal::MAX_PACKED_ARGS - 1) == internal::NONE;
if (index < internal::MAX_PACKED_ARGS) { if (index < internal::MAX_PACKED_ARGS) {
typename format_arg::Type arg_type = type(index); typename internal::Type arg_type = type(index);
internal::Value &val = arg; internal::Value &val = arg;
if (arg_type != format_arg::NONE) if (arg_type != internal::NONE)
val = use_values ? values_[index] : args_[index]; val = use_values ? values_[index] : args_[index];
arg.type_ = arg_type; arg.type_ = arg_type;
return arg; return arg;
@ -1615,11 +1613,11 @@ class basic_format_args {
if (use_values) { if (use_values) {
// The index is greater than the number of arguments that can be stored // The index is greater than the number of arguments that can be stored
// in values, so return a "none" argument. // in values, so return a "none" argument.
arg.type_ = format_arg::NONE; arg.type_ = internal::NONE;
return arg; return arg;
} }
for (unsigned i = internal::MAX_PACKED_ARGS; i <= index; ++i) { for (unsigned i = internal::MAX_PACKED_ARGS; i <= index; ++i) {
if (args_[i].type_ == format_arg::NONE) if (args_[i].type_ == internal::NONE)
return args_[i]; return args_[i];
} }
return args_[index]; return args_[index];
@ -1637,7 +1635,7 @@ class basic_format_args {
/** Returns the argument at specified index. */ /** Returns the argument at specified index. */
format_arg operator[](size_type index) const { format_arg operator[](size_type index) const {
format_arg arg = get(index); format_arg arg = get(index);
return arg.type_ == format_arg::NAMED_ARG ? return arg.type_ == internal::NAMED_ARG ?
*static_cast<const format_arg*>(arg.pointer) : arg; *static_cast<const format_arg*>(arg.pointer) : arg;
} }
}; };
@ -1901,14 +1899,14 @@ void ArgMap<Char>::init(const basic_format_args<Context, Char> &args) {
typedef internal::NamedArg<Char> NamedArg; typedef internal::NamedArg<Char> NamedArg;
const NamedArg *named_arg = 0; const NamedArg *named_arg = 0;
bool use_values = bool use_values =
args.type(MAX_PACKED_ARGS - 1) == format_arg::NONE; args.type(MAX_PACKED_ARGS - 1) == internal::NONE;
if (use_values) { if (use_values) {
for (unsigned i = 0;/*nothing*/; ++i) { for (unsigned i = 0;/*nothing*/; ++i) {
format_arg::Type arg_type = args.type(i); internal::Type arg_type = args.type(i);
switch (arg_type) { switch (arg_type) {
case format_arg::NONE: case internal::NONE:
return; return;
case format_arg::NAMED_ARG: case internal::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer); named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg)); map_.push_back(Pair(named_arg->name, *named_arg));
break; break;
@ -1919,17 +1917,17 @@ void ArgMap<Char>::init(const basic_format_args<Context, Char> &args) {
return; return;
} }
for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) { for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) {
format_arg::Type arg_type = args.type(i); internal::Type arg_type = args.type(i);
if (arg_type == format_arg::NAMED_ARG) { if (arg_type == internal::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg)); map_.push_back(Pair(named_arg->name, *named_arg));
} }
} }
for (unsigned i = MAX_PACKED_ARGS; ; ++i) { for (unsigned i = MAX_PACKED_ARGS; ; ++i) {
switch (args.args_[i].type_) { switch (args.args_[i].type_) {
case format_arg::NONE: case internal::NONE:
return; return;
case format_arg::NAMED_ARG: case internal::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg)); map_.push_back(Pair(named_arg->name, *named_arg));
break; break;
@ -2136,7 +2134,7 @@ class ArgFormatter : public internal::ArgFormatterBase<Char> {
using internal::ArgFormatterBase<Char>::operator(); using internal::ArgFormatterBase<Char>::operator();
/** Formats an argument of a custom (user-defined) type. */ /** Formats an argument of a custom (user-defined) type. */
void operator()(format_arg::CustomValue c) { void operator()(internal::CustomValue c) {
c.format(&this->writer(), c.value, &ctx_); c.format(&this->writer(), c.value, &ctx_);
} }
}; };
@ -3367,7 +3365,7 @@ class CustomFormatter {
CustomFormatter(BasicWriter<Char> &writer, Context &ctx) CustomFormatter(BasicWriter<Char> &writer, Context &ctx)
: writer_(writer), ctx_(ctx) {} : writer_(writer), ctx_(ctx) {}
bool operator()(format_arg::CustomValue custom) { bool operator()(internal::CustomValue custom) {
custom.format(&writer_, custom.value, &ctx_); custom.format(&writer_, custom.value, &ctx_);
return true; return true;
} }

View File

@ -281,7 +281,7 @@ class PrintfArgFormatter : public internal::ArgFormatterBase<Char> {
} }
/** Formats an argument of a custom (user-defined) type. */ /** Formats an argument of a custom (user-defined) type. */
void operator()(format_arg::CustomValue c) { void operator()(internal::CustomValue c) {
const Char format_str[] = {'}', '\0'}; const Char format_str[] = {'}', '\0'};
auto args = basic_format_args<basic_format_context<Char>, Char>(); auto args = basic_format_args<basic_format_context<Char>, Char>();
basic_format_context<Char> ctx(format_str, args); basic_format_context<Char> ctx(format_str, args);

View File

@ -1636,7 +1636,7 @@ class MockArgFormatter : public fmt::internal::ArgFormatterBase<char> {
void operator()(int value) { call(value); } void operator()(int value) { call(value); }
void operator()(fmt::format_arg::CustomValue) {} void operator()(fmt::internal::CustomValue) {}
}; };
void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) {

View File

@ -434,7 +434,7 @@ TEST(UtilTest, MakeValueWithCustomFormatter) {
namespace fmt { namespace fmt {
namespace internal { namespace internal {
bool operator==(Value::CustomValue lhs, Value::CustomValue rhs) { bool operator==(CustomValue lhs, CustomValue rhs) {
return lhs.value == rhs.value; return lhs.value == rhs.value;
} }
} }
@ -564,10 +564,10 @@ TEST(UtilTest, PointerArg) {
TEST(UtilTest, CustomArg) { TEST(UtilTest, CustomArg) {
::Test test; ::Test test;
typedef MockVisitor<Value::CustomValue> Visitor; typedef MockVisitor<fmt::internal::CustomValue> Visitor;
testing::StrictMock<Visitor> visitor; testing::StrictMock<Visitor> visitor;
EXPECT_CALL(visitor, visit(_)).WillOnce( EXPECT_CALL(visitor, visit(_)).WillOnce(
testing::Invoke([&](Value::CustomValue custom) { testing::Invoke([&](fmt::internal::CustomValue custom) {
EXPECT_EQ(&test, custom.value); EXPECT_EQ(&test, custom.value);
fmt::MemoryWriter w; fmt::MemoryWriter w;
fmt::format_context ctx("}", fmt::format_args()); fmt::format_context ctx("}", fmt::format_args());