diff --git a/format.cc b/format.cc index 1297197b..c7ee4797 100644 --- a/format.cc +++ b/format.cc @@ -820,6 +820,10 @@ void fmt::internal::PrintfFormatter::format( case Arg::LONG_DOUBLE: writer.write_double(arg.long_double_value, spec); break; + case Arg::CSTRING: + arg.string.size = 0; + writer.write_str(arg.string, spec); + break; case Arg::STRING: writer.write_str(arg.string, spec); break; diff --git a/format.h b/format.h index a1d10163..d936d63a 100644 --- a/format.h +++ b/format.h @@ -645,7 +645,7 @@ struct Arg : Value { INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, // followed by floating-point types. DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, - STRING, WSTRING, POINTER, CUSTOM + CSTRING, STRING, WSTRING, POINTER, CUSTOM }; Type type; }; @@ -689,7 +689,7 @@ public: #define FMT_MAKE_VALUE(Type, field, TYPE) \ MakeValue(Type value) { field = value; } \ - static fmt::ULongLong type(Type) { return Arg::TYPE; } + static ULongLong type(Type) { return Arg::TYPE; } FMT_MAKE_VALUE(bool, int_value, INT) FMT_MAKE_VALUE(short, int_value, INT) @@ -705,7 +705,7 @@ public: else long_long_value = value; } - static fmt::ULongLong type(long) { + static ULongLong type(long) { return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; } @@ -715,7 +715,7 @@ public: else ulong_long_value = value; } - static fmt::ULongLong type(unsigned long) { + static ULongLong type(unsigned long) { return sizeof(unsigned long) == sizeof(unsigned) ? Arg::UINT : Arg::ULONG_LONG; } @@ -732,14 +732,14 @@ public: MakeValue(wchar_t value) { int_value = internal::CharTraits::convert(value); } - static fmt::ULongLong type(wchar_t) { return Arg::CHAR; } + static ULongLong type(wchar_t) { return Arg::CHAR; } #define FMT_MAKE_STR_VALUE(Type, TYPE) \ MakeValue(Type value) { set_string(value); } \ - static fmt::ULongLong type(Type) { return Arg::TYPE; } + static ULongLong type(Type) { return Arg::TYPE; } - FMT_MAKE_STR_VALUE(char *, STRING) - FMT_MAKE_STR_VALUE(const char *, STRING) + FMT_MAKE_VALUE(char *, string.value, CSTRING) + FMT_MAKE_VALUE(const char *, string.value, CSTRING) FMT_MAKE_STR_VALUE(const std::string &, STRING) FMT_MAKE_STR_VALUE(StringRef, STRING) @@ -757,15 +757,7 @@ public: custom.format = &format_custom_arg; } template - static fmt::ULongLong type(const T &) { return Arg::CUSTOM; } - - static fmt::ULongLong type() { return 0; } - - // TODO: conditionally compile - template - static fmt::ULongLong type(const Arg &first, const Args & ... tail) { - return type(first) | (type(tail...) << 4); - } + static ULongLong type(const T &) { return Arg::CUSTOM; } }; #define FMT_DISPATCH(call) static_cast(this)->call @@ -858,6 +850,11 @@ class ArgVisitor { return FMT_DISPATCH(visit_long_double(arg.long_double_value)); case Arg::CHAR: return FMT_DISPATCH(visit_char(arg.int_value)); + case Arg::CSTRING: { + Value::StringValue str = arg.string; + str.size = 0; + return FMT_DISPATCH(visit_string(str)); + } case Arg::STRING: return FMT_DISPATCH(visit_string(arg.string)); case Arg::WSTRING: @@ -884,7 +881,7 @@ class ArgFormatter; */ class ArgList { private: - fmt::ULongLong types_; + ULongLong types_; const internal::Value *values_; public: @@ -892,7 +889,7 @@ class ArgList { enum { MAX_ARGS = 16 }; ArgList() : types_(0) {} - ArgList(fmt::ULongLong types, const internal::Value *values) + ArgList(ULongLong types, const internal::Value *values) : types_(types), values_(values) {} /** @@ -902,9 +899,9 @@ class ArgList { using internal::Arg; if (index >= MAX_ARGS) return Arg(); - fmt::ULongLong shift = index * 4; + ULongLong shift = index * 4, mask = 0xf; Arg::Type type = - static_cast((types_ & (0xfull << shift)) >> shift); + static_cast((types_ & (mask << shift)) >> shift); Arg arg; arg.type = type; if (type != Arg::NONE) { @@ -1224,6 +1221,42 @@ inline StrFormatSpec pad( # define FMT_GEN14(f) FMT_GEN13(f), f(13) # define FMT_GEN15(f) FMT_GEN14(f), f(14) +namespace internal { +inline ULongLong make_type() { return 0; } + +template +inline ULongLong make_type(const T &arg) { return MakeValue::type(arg); } + +#if FMT_USE_VARIADIC_TEMPLATES +template +inline ULongLong make_type(const Arg &first, const Args & ... tail) { + return make_type(first) | (make_type(tail...) << 4); +} +#else + +struct ArgType { + fmt::ULongLong type; + + ArgType() : type(0) {} + + template + ArgType(const T &arg) : type(make_type(arg)) {} +}; + +inline ULongLong make_type( + ArgType t0, ArgType t1, ArgType t2 = ArgType(), ArgType t3 = ArgType(), + ArgType t4 = ArgType(), ArgType t5 = ArgType(), ArgType t6 = ArgType(), + ArgType t7 = ArgType(), ArgType t8 = ArgType(), ArgType t9 = ArgType(), + ArgType t10 = ArgType(), ArgType t11 = ArgType(), ArgType t12 = ArgType(), + ArgType t13 = ArgType(), ArgType t14 = ArgType()) { + return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | + (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | + (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | + (t12.type << 48) | (t13.type << 52) | (t14.type << 56); +} +#endif +} // namespace internal + # define FMT_MAKE_TEMPLATE_ARG(n) typename T##n # define FMT_MAKE_ARG_TYPE(n) T##n # define FMT_MAKE_ARG(n) const T##n &v##n @@ -1235,12 +1268,11 @@ inline StrFormatSpec pad( # define FMT_VARIADIC_VOID(func, arg_type) \ template \ void func(arg_type arg1, const Args & ... args) { \ - using fmt::internal::MakeValue; \ const fmt::internal::Value values[ \ fmt::internal::NonZero::VALUE] = { \ - MakeValue(args)... \ + fmt::internal::MakeValue(args)... \ }; \ - func(arg1, ArgList(MakeValue::type(args...), values)); \ + func(arg1, ArgList(fmt::internal::make_type(args...), values)); \ } // Defines a variadic constructor. @@ -1252,7 +1284,7 @@ inline StrFormatSpec pad( fmt::internal::NonZero::VALUE] = { \ MakeValue(args)... \ }; \ - func(arg0, arg1, ArgList(MakeValue::type(args...), values)); \ + func(arg0, arg1, ArgList(fmt::internal::make_type(args...), values)); \ } #else @@ -1267,7 +1299,7 @@ inline StrFormatSpec pad( inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ func(arg1, fmt::ArgList( \ - fmt::internal::MakeValue::type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ } // Emulates a variadic function returning void on a pre-C++11 compiler. @@ -1283,7 +1315,7 @@ inline StrFormatSpec pad( ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ func(arg0, arg1, fmt::ArgList( \ - fmt::internal::MakeValue::type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ } // Emulates a variadic constructor on a pre-C++11 compiler. @@ -2246,7 +2278,7 @@ inline void format_decimal(char *&buffer, T value) { fmt::internal::MakeValue(args)... \ }; \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ - fmt::internal::MakeValue::type(args...), values)); \ + fmt::internal::make_type(args...), values)); \ } #else // Defines a wrapper for a function taking __VA_ARGS__ arguments @@ -2257,7 +2289,7 @@ inline void format_decimal(char *&buffer, T value) { FMT_GEN(n, FMT_MAKE_ARG)) { \ const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ - fmt::internal::MakeValue::type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ } # define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ diff --git a/test/util-test.cc b/test/util-test.cc index cf4adb90..13c5f537 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -95,6 +95,7 @@ ARG_INFO(ULONG_LONG, fmt::ULongLong, ulong_long_value); ARG_INFO(DOUBLE, double, double_value); ARG_INFO(LONG_DOUBLE, long double, long_double_value); ARG_INFO(CHAR, int, int_value); +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); @@ -115,7 +116,7 @@ TEST(ArgTest, ArgInfo) { CHECK_ARG_INFO(LONG_DOUBLE, long_double_value, 4.2); CHECK_ARG_INFO(CHAR, int_value, 'x'); const char STR[] = "abc"; - CHECK_ARG_INFO(STRING, string.value, STR); + CHECK_ARG_INFO(CSTRING, string.value, STR); const wchar_t WSTR[] = L"abc"; CHECK_ARG_INFO(WSTRING, wstring.value, WSTR); int p = 0; @@ -215,8 +216,8 @@ TEST(ArgTest, MakeArg) { // Test string. char STR[] = "test"; - EXPECT_ARG(STRING, char*, STR); - EXPECT_ARG(STRING, const char*, STR); + EXPECT_ARG(CSTRING, char*, STR); + EXPECT_ARG(CSTRING, const char*, STR); EXPECT_ARG(STRING, std::string, STR); EXPECT_ARG(STRING, fmt::StringRef, STR); @@ -289,7 +290,7 @@ TEST(ArgVisitorTest, VisitAll) { EXPECT_RESULT(LONG_DOUBLE, 4.2l); EXPECT_RESULT(CHAR, 'x'); const char STR[] = "abc"; - EXPECT_RESULT(STRING, STR); + EXPECT_RESULT(CSTRING, STR); const wchar_t WSTR[] = L"abc"; EXPECT_RESULTW(WSTRING, WSTR); const void *p = STR;