diff --git a/format.cc b/format.cc index 1970d53c..a8dc94cb 100644 --- a/format.cc +++ b/format.cc @@ -304,20 +304,20 @@ class ArgConverter : public fmt::internal::ArgVisitor, void> { // Extra casts are used to silence warnings. if (is_signed) { arg_.type = Arg::INT; - arg_.int_value = static_cast(static_cast(value)); + arg_.value.int_value = static_cast(static_cast(value)); } else { arg_.type = Arg::UINT; - arg_.uint_value = static_cast( + arg_.value.uint_value = static_cast( static_cast::Type>(value)); } } else { if (is_signed) { arg_.type = Arg::LONG_LONG; - arg_.long_long_value = + arg_.value.long_long_value = static_cast::Type>(value); } else { arg_.type = Arg::ULONG_LONG; - arg_.ulong_long_value = + arg_.value.ulong_long_value = static_cast::Type>(value); } } @@ -337,7 +337,7 @@ class CharConverter : public fmt::internal::ArgVisitor { template void visit_any_int(T value) { arg_.type = Arg::CHAR; - arg_.int_value = static_cast(value); + arg_.value.int_value = static_cast(value); } }; } // namespace @@ -405,7 +405,7 @@ class PrintfArgFormatter : write_null_pointer(); } - void visit_custom(Arg::CustomValue c) { + void visit_custom(Value::CustomValue c) { BasicFormatter formatter(ArgList(), this->writer()); const Char format_str[] = {'}', 0}; const Char *format = format_str; @@ -627,7 +627,7 @@ void fmt::internal::ArgMap::init(const ArgList &args) { for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { internal::Arg::Type arg_type = args.type(i); if (arg_type == internal::Arg::NAMED_ARG) { - named_arg = static_cast(args.args_[i].pointer); + named_arg = static_cast(args.args_[i].value.pointer); map_.insert(Pair(named_arg->name, *named_arg)); } } @@ -636,7 +636,7 @@ void fmt::internal::ArgMap::init(const ArgList &args) { case internal::Arg::NONE: return; case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.args_[i].pointer); + named_arg = static_cast(args.args_[i].value.pointer); map_.insert(Pair(named_arg->name, *named_arg)); break; default: @@ -658,7 +658,7 @@ FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( error = "argument index out of range"; break; case Arg::NAMED_ARG: - arg = *static_cast(arg.pointer); + arg = *static_cast(arg.value.pointer); default: /*nothing*/; } diff --git a/format.h b/format.h index a98a1660..157e5170 100644 --- a/format.h +++ b/format.h @@ -927,7 +927,11 @@ struct Value { StringValue wstring; CustomValue custom; }; +}; +// A formatting argument. It is a POD type to allow storage in +// internal::MemoryBuffer. +struct Arg { enum Type { NONE, NAMED_ARG, // Integer types should go first, @@ -936,11 +940,8 @@ struct Value { DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, CSTRING, STRING, WSTRING, POINTER, CUSTOM }; -}; -// A formatting argument. It is a POD type to allow storage in -// internal::MemoryBuffer. -struct Arg : Value { + Value value; Type type; }; @@ -1044,7 +1045,7 @@ struct Not { enum { value = 1 }; }; // Makes an Arg object from any type. template -class MakeValue : public Arg { +class MakeValue : public Value { public: typedef typename Formatter::Char Char; @@ -1206,9 +1207,10 @@ struct NamedArg : Arg { typedef internal::MakeValue< BasicFormatter > MakeValue; template - NamedArg(BasicStringRef argname, const T &value) - : Arg(MakeValue(value)), name(argname) { - type = static_cast(MakeValue::type(value)); + NamedArg(BasicStringRef argname, const T &x) + : name(argname) { + value = MakeValue(x); + type = static_cast(MakeValue::type(x)); } }; @@ -1281,16 +1283,16 @@ class ArgVisitor { Result visit_cstring(const char *) { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_string(Arg::StringValue) { + Result visit_string(Value::StringValue) { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_wstring(Arg::StringValue) { + Result visit_wstring(Value::StringValue) { return FMT_DISPATCH(visit_unhandled_arg()); } Result visit_pointer(const void *) { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_custom(Arg::CustomValue) { + Result visit_custom(Value::CustomValue) { return FMT_DISPATCH(visit_unhandled_arg()); } @@ -1300,31 +1302,31 @@ class ArgVisitor { FMT_ASSERT(false, "invalid argument type"); return Result(); case Arg::INT: - return FMT_DISPATCH(visit_int(arg.int_value)); + return FMT_DISPATCH(visit_int(arg.value.int_value)); case Arg::UINT: - return FMT_DISPATCH(visit_uint(arg.uint_value)); + return FMT_DISPATCH(visit_uint(arg.value.uint_value)); 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: - return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); + return FMT_DISPATCH(visit_ulong_long(arg.value.ulong_long_value)); 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: - return FMT_DISPATCH(visit_char(arg.int_value)); + return FMT_DISPATCH(visit_char(arg.value.int_value)); case Arg::DOUBLE: - return FMT_DISPATCH(visit_double(arg.double_value)); + return FMT_DISPATCH(visit_double(arg.value.double_value)); 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: - return FMT_DISPATCH(visit_cstring(arg.string.value)); + return FMT_DISPATCH(visit_cstring(arg.value.string.value)); case Arg::STRING: - return FMT_DISPATCH(visit_string(arg.string)); + return FMT_DISPATCH(visit_string(arg.value.string)); case Arg::WSTRING: - return FMT_DISPATCH(visit_wstring(arg.wstring)); + return FMT_DISPATCH(visit_wstring(arg.value.wstring)); case Arg::POINTER: - return FMT_DISPATCH(visit_pointer(arg.pointer)); + return FMT_DISPATCH(visit_pointer(arg.value.pointer)); 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; if (index < MAX_PACKED_ARGS) { Arg::Type arg_type = type(index); - internal::Value &val = arg; 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; return arg; } @@ -1665,12 +1666,12 @@ class ArgFormatterBase : public ArgVisitor { void write(bool value) { const char *str_value = value ? "true" : "false"; - Arg::StringValue str = { str_value, std::strlen(str_value) }; + Value::StringValue str = { str_value, std::strlen(str_value) }; writer_.write_str(str, spec_); } void write(const char *value) { - Arg::StringValue str = {value, value != 0 ? std::strlen(value) : 0}; + Value::StringValue str = {value, value != 0 ? std::strlen(value) : 0}; writer_.write_str(str, spec_); } @@ -1726,13 +1727,13 @@ class ArgFormatterBase : public ArgVisitor { write(value); } - void visit_string(Arg::StringValue value) { + void visit_string(Value::StringValue value) { writer_.write_str(value, spec_); } using ArgVisitor::visit_wstring; - void visit_wstring(Arg::StringValue value) { + void visit_wstring(Value::StringValue value) { writer_.write_str(value, spec_); } @@ -1756,7 +1757,7 @@ class BasicArgFormatter : : ArgFormatterBase, Char>(f.writer(), s), formatter_(f), format_(fmt) {} - void visit_custom(Arg::CustomValue c) { + void visit_custom(Value::CustomValue c) { c.format(&formatter_, c.value, &format_); } }; @@ -1931,12 +1932,15 @@ inline void set_types(Value *, const Args & ...) { template inline void store_args(Value *) {} -template +template 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) - // that is assigned by set_types. - Value &value = *args; - value = MakeValue(arg); + args->value = MakeValue(arg); + store_args(args + 1, tail...); +} + +template +inline void store_args(Value *args, const T &arg, const Args & ... tail) { + *args = MakeValue(arg); store_args(args + 1, tail...); } @@ -2242,7 +2246,7 @@ class BasicWriter { CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); template - void write_str(const internal::Arg::StringValue &str, + void write_str(const internal::Value::StringValue &str, const FormatSpec &spec); // This following methods are private to disallow writing wide characters @@ -2461,7 +2465,7 @@ typename BasicWriter::CharPtr BasicWriter::write_str( template template void BasicWriter::write_str( - const internal::Arg::StringValue &s, const FormatSpec &spec) { + const internal::Value::StringValue &s, const FormatSpec &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); if (spec.type_ && spec.type_ != 's') @@ -2921,7 +2925,8 @@ void format(BasicFormatter &f, const Char *&format_str, const T &value) { BasicStringRef str(&buffer[0], format_buf.size()); typedef internal::MakeValue< BasicFormatter > MakeValue; - internal::Arg arg = MakeValue(str); + internal::Arg arg; + arg.value = MakeValue(str); arg.type = static_cast(MakeValue::type(str)); format_str = f.format(format_str, arg); } @@ -3462,7 +3467,7 @@ const Char *BasicFormatter::format( FormatSpec spec; if (*s == ':') { 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; } ++s; @@ -3542,20 +3547,20 @@ const Char *BasicFormatter::format( ULongLong value = 0; switch (width_arg.type) { case Arg::INT: - if (width_arg.int_value < 0) + if (width_arg.value.int_value < 0) FMT_THROW(FormatError("negative width")); - value = width_arg.int_value; + value = width_arg.value.int_value; break; case Arg::UINT: - value = width_arg.uint_value; + value = width_arg.value.uint_value; break; case Arg::LONG_LONG: - if (width_arg.long_long_value < 0) + if (width_arg.value.long_long_value < 0) FMT_THROW(FormatError("negative width")); - value = width_arg.long_long_value; + value = width_arg.value.long_long_value; break; case Arg::ULONG_LONG: - value = width_arg.ulong_long_value; + value = width_arg.value.ulong_long_value; break; default: FMT_THROW(FormatError("width is not integer")); @@ -3580,20 +3585,20 @@ const Char *BasicFormatter::format( ULongLong value = 0; switch (precision_arg.type) { case Arg::INT: - if (precision_arg.int_value < 0) + if (precision_arg.value.int_value < 0) FMT_THROW(FormatError("negative precision")); - value = precision_arg.int_value; + value = precision_arg.value.int_value; break; case Arg::UINT: - value = precision_arg.uint_value; + value = precision_arg.value.uint_value; break; case Arg::LONG_LONG: - if (precision_arg.long_long_value < 0) + if (precision_arg.value.long_long_value < 0) FMT_THROW(FormatError("negative precision")); - value = precision_arg.long_long_value; + value = precision_arg.value.long_long_value; break; case Arg::ULONG_LONG: - value = precision_arg.ulong_long_value; + value = precision_arg.value.ulong_long_value; break; default: FMT_THROW(FormatError("precision is not integer")); diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 9948a848..8742e78b 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -42,7 +42,7 @@ TEST(FormatTest, ArgConverter) { using fmt::internal::Arg; Arg arg = Arg(); arg.type = Arg::LONG_LONG; - arg.long_long_value = std::numeric_limits::max(); + arg.value.long_long_value = std::numeric_limits::max(); fmt::ArgConverter(arg, 'd').visit(arg); EXPECT_EQ(Arg::LONG_LONG, arg.type); } diff --git a/test/macro-test.cc b/test/macro-test.cc index 38e85858..1c096b82 100644 --- a/test/macro-test.cc +++ b/test/macro-test.cc @@ -70,7 +70,7 @@ int result; void func(const char *format, const fmt::ArgList &args) { \ result = 0; \ for (unsigned i = 0; args[i].type; ++i) \ - result += args[i].int_value; \ + result += args[i].value.int_value; \ } MAKE_TEST(test_func) @@ -101,7 +101,7 @@ struct S {}; int test_variadic(FMT_GEN(10, GET_TYPE), const fmt::ArgList &args) { \ int result = 0; \ for (unsigned i = 0; args[i].type; ++i) \ - result += args[i].int_value; \ + result += args[i].value.int_value; \ return result; } FMT_VARIADIC(int, test_variadic, diff --git a/test/util-test.cc b/test/util-test.cc index 2aa8245b..fec7b37c 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -53,6 +53,7 @@ using fmt::StringRef; using fmt::internal::Arg; +using fmt::internal::Value; using fmt::Buffer; using fmt::internal::MemoryBuffer; @@ -70,7 +71,8 @@ std::basic_ostream &operator<<(std::basic_ostream &os, Test) { template Arg make_arg(const T &value) { typedef fmt::internal::MakeValue< fmt::BasicFormatter > MakeValue; - Arg arg = MakeValue(value); + Arg arg; + arg.value = MakeValue(value); arg.type = static_cast(MakeValue::type(value)); return arg; } @@ -409,7 +411,7 @@ struct ArgInfo; #define ARG_INFO(type_code, Type, field) \ template <> \ struct ArgInfo { \ - 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); @@ -424,12 +426,12 @@ ARG_INFO(CSTRING, const char *, string.value); ARG_INFO(STRING, const char *, string.value); ARG_INFO(WSTRING, const wchar_t *, wstring.value); 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.field = value; \ - EXPECT_EQ(value, ArgInfo::get(arg)); \ + arg.value.field = x; \ + EXPECT_EQ(x, ArgInfo::get(arg)); \ } TEST(ArgTest, ArgInfo) { @@ -447,7 +449,7 @@ TEST(ArgTest, ArgInfo) { int p = 0; CHECK_ARG_INFO(POINTER, pointer, &p); Arg arg = Arg(); - arg.custom.value = &p; + arg.value.custom.value = &p; EXPECT_EQ(&p, ArgInfo::get(arg).value); } @@ -562,11 +564,11 @@ TEST(ArgTest, MakeArg) { ::Test t; Arg arg = make_arg(t); 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::BasicFormatter formatter(fmt::ArgList(), w); const char *s = "}"; - arg.custom.format(&formatter, &t, &s); + arg.value.custom.format(&formatter, &t, &s); EXPECT_EQ("test", w.str()); } @@ -585,10 +587,11 @@ void format(CustomFormatter &, const char *&s, const Test &) { TEST(UtilTest, MakeValueWithCustomFormatter) { ::Test t; - Arg arg = fmt::internal::MakeValue(t); + Arg arg; + arg.value = fmt::internal::MakeValue(t); CustomFormatter formatter; const char *s = ""; - arg.custom.format(&formatter, &t, &s); + arg.value.custom.format(&formatter, &t, &s); EXPECT_STREQ("custom_format", s); } @@ -611,10 +614,10 @@ struct TestVisitor : fmt::internal::ArgVisitor { Result visit_long_double(long double value) { return value; } Result visit_char(int value) { return static_cast(value); } Result visit_cstring(const char *s) { return s; } - Result visit_string(Arg::StringValue s) { return s.value; } - Result visit_wstring(Arg::StringValue s) { return s.value; } + Result visit_string(Value::StringValue s) { return s.value; } + Result visit_wstring(Value::StringValue s) { return s.value; } Result visit_pointer(const void *p) { return p; } - Result visit_custom(Arg::CustomValue c) { + Result visit_custom(Value::CustomValue c) { return *static_cast(c.value); } }; @@ -648,7 +651,7 @@ TEST(ArgVisitorTest, VisitAll) { ::Test t; Result result = TestVisitor().visit(make_arg(t)); 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 {