diff --git a/fmt/format.cc b/fmt/format.cc index 3e2a6eec..92479615 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -458,7 +458,7 @@ template struct internal::BasicData; template void internal::FixedBuffer::grow(std::size_t); -template void internal::ArgMap::init(const format_args &args); +template void internal::ArgMap::init(const format_args &args); template void printf_context::format(Writer &writer); @@ -472,9 +472,11 @@ template int internal::CharTraits::format_float( // Explicit instantiations for wchar_t. +template class basic_format_context; + template void internal::FixedBuffer::grow(std::size_t); -template void internal::ArgMap::init(const wformat_args &args); +template void internal::ArgMap::init(const wformat_args &args); template void printf_context::format(WWriter &writer); diff --git a/fmt/format.h b/fmt/format.h index 723e5395..3f9de274 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -230,10 +230,9 @@ typedef __int64 intmax_t; # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) #endif -// Some compilers masquerade as both MSVC and GCC-likes or -// otherwise support __builtin_clz and __builtin_clzll, so -// only define FMT_BUILTIN_CLZ using the MSVC intrinsics -// if the clz and clzll builtins are not available. +// Some compilers masquerade as both MSVC and GCC-likes or otherwise support +// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the +// MSVC intrinsics if the clz and clzll builtins are not available. #if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) # include // _BitScanReverse, _BitScanReverse64 @@ -371,7 +370,7 @@ class BasicWriter; typedef BasicWriter Writer; typedef BasicWriter WWriter; -template +template class basic_format_arg; template @@ -1331,11 +1330,11 @@ class MakeValue : public Value { } }; -template +template class ArgMap; template -basic_format_arg make_arg(const T &value); +basic_format_arg make_arg(const T &value); } // namespace internal struct monostate {}; @@ -1345,25 +1344,25 @@ class basic_format_args; // A formatting argument. It is a trivially copyable/constructible type to // allow storage in internal::MemoryBuffer. -template +template class basic_format_arg { private: + typedef typename Context::char_type Char; + internal::Value value_; internal::Type type_; - template - friend basic_format_arg - internal::make_arg(const T &value); + template + friend basic_format_arg internal::make_arg(const T &value); - template + template friend typename std::result_of::type - visit(Visitor &&vis, basic_format_arg arg); + visit(Visitor &&vis, basic_format_arg arg); - template + template friend class basic_format_args; - template - friend class internal::ArgMap; + friend class internal::ArgMap; public: basic_format_arg() : type_(internal::NONE) {} @@ -1385,8 +1384,8 @@ class basic_format_arg { } }; -typedef basic_format_arg format_arg; -typedef basic_format_arg wformat_arg; +typedef basic_format_arg format_arg; +typedef basic_format_arg wformat_arg; /** \rst @@ -1395,9 +1394,10 @@ typedef basic_format_arg wformat_arg; ``vis(value)`` will be called with the value of type ``double``. \endrst */ -template +template typename std::result_of::type - visit(Visitor &&vis, basic_format_arg arg) { + visit(Visitor &&vis, basic_format_arg arg) { + typedef typename Context::char_type Char; switch (arg.type_) { case internal::NONE: return vis(monostate()); @@ -1438,8 +1438,8 @@ typename std::result_of::type namespace internal { template -basic_format_arg make_arg(const T &value) { - basic_format_arg arg; +basic_format_arg make_arg(const T &value) { + basic_format_arg arg; arg.type_ = internal::type(); arg.value_ = internal::MakeValue(value); return arg; @@ -1489,14 +1489,15 @@ void format_value(BasicWriter &, const T &, Formatter &, const Char *) { "an overload of format_arg."); } -template -struct NamedArg : basic_format_arg { +template +struct NamedArg : basic_format_arg { + typedef typename Context::char_type Char; + BasicStringRef name; template NamedArg(BasicStringRef argname, const T &value) - : basic_format_arg(make_arg< basic_format_context >(value)), - name(argname) {} + : basic_format_arg(make_arg(value)), name(argname) {} }; class RuntimeError : public std::runtime_error { @@ -1524,8 +1525,7 @@ inline typename std::enable_if< } template -inline typename std::enable_if< - !IS_PACKED, basic_format_arg>::type +inline typename std::enable_if>::type make_arg(const T& value) { return make_arg(value); } @@ -1542,7 +1542,7 @@ class format_arg_store { typedef typename Context::char_type char_type; typedef typename std::conditional, basic_format_arg>::type value_type; + internal::Value, basic_format_arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. typedef std::array Array; @@ -1574,7 +1574,7 @@ template class basic_format_args { public: typedef unsigned size_type; - typedef basic_format_arg format_arg; + typedef basic_format_arg format_arg; private: // To reduce compiled code size per formatting function call, types of first @@ -1597,7 +1597,7 @@ class basic_format_args { (types_ & (mask << shift)) >> shift); } - friend class internal::ArgMap; + friend class internal::ArgMap; void set_data(const internal::Value *values) { values_ = values; } void set_data(const format_arg *args) { args_ = args; } @@ -1869,20 +1869,20 @@ inline StrFormatSpec pad( namespace internal { -template +template class ArgMap { private: + typedef typename Context::char_type Char; typedef std::vector< - std::pair, basic_format_arg > > MapType; + std::pair, basic_format_arg > > MapType; typedef typename MapType::value_type Pair; MapType map_; public: - template void init(const basic_format_args &args); - const basic_format_arg + const basic_format_arg *find(const fmt::BasicStringRef &name) const { // The list is unsorted, so just return the first matching name. for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); @@ -1894,12 +1894,11 @@ class ArgMap { } }; -template template -void ArgMap::init(const basic_format_args &args) { +void ArgMap::init(const basic_format_args &args) { if (!map_.empty()) return; - typedef internal::NamedArg NamedArg; + typedef internal::NamedArg NamedArg; const NamedArg *named_arg = 0; bool use_values = args.type(MAX_PACKED_ARGS - 1) == internal::NONE; @@ -2072,7 +2071,7 @@ class format_context_base { int next_arg_index_; protected: - typedef basic_format_arg format_arg; + typedef basic_format_arg format_arg; format_context_base(const Char *format_str, basic_format_args args) @@ -2149,24 +2148,25 @@ class ArgFormatter : public internal::ArgFormatterBase { template class basic_format_context : public internal::format_context_base> { + public: + /** The character type for the output. */ + typedef Char char_type; + private: - internal::ArgMap map_; + internal::ArgMap> map_; FMT_DISALLOW_COPY_AND_ASSIGN(basic_format_context); typedef internal::format_context_base> Base; - using typename Base::format_arg; + typedef typename Base::format_arg format_arg; using Base::get_arg; // Checks if manual indexing is used and returns the argument with // specified name. - basic_format_arg get_arg(BasicStringRef name, const char *&error); + format_arg get_arg(BasicStringRef name, const char *&error); public: - /** The character type for the output. */ - typedef Char char_type; - /** \rst Constructs a ``basic_format_context`` object. References to the arguments are @@ -2178,7 +2178,7 @@ class basic_format_context : : Base(format_str, args) {} // Parses argument id and returns corresponding argument. - basic_format_arg parse_arg_id(); + format_arg parse_arg_id(); using Base::ptr; }; @@ -3274,21 +3274,23 @@ inline void format_decimal(char *&buffer, T value) { \endrst */ template -inline internal::NamedArg arg(StringRef name, const T &arg) { - return internal::NamedArg(name, arg); +inline internal::NamedArg arg(StringRef name, const T &arg) { + return internal::NamedArg(name, arg); } template -inline internal::NamedArg arg(WStringRef name, const T &arg) { - return internal::NamedArg(name, arg); +inline internal::NamedArg arg(WStringRef name, const T &arg) { + return internal::NamedArg(name, arg); } // The following two functions are deleted intentionally to disable // nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. -template -void arg(StringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; -template -void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; +template +void arg(StringRef, const internal::NamedArg&) + FMT_DELETED_OR_UNDEFINED; +template +void arg(WStringRef, const internal::NamedArg&) + FMT_DELETED_OR_UNDEFINED; } #if FMT_GCC_VERSION @@ -3351,8 +3353,8 @@ struct IsUnsigned { } }; -template -void check_sign(const Char *&s, const basic_format_arg &arg) { +template +void check_sign(const Char *&s, const basic_format_arg &arg) { char sign = static_cast(*s); require_numeric_argument(arg, sign); if (visit(IsUnsigned(), arg)) { @@ -3425,25 +3427,27 @@ struct PrecisionHandler { } // namespace internal template -inline basic_format_arg basic_format_context::get_arg( +inline typename basic_format_context::format_arg + basic_format_context::get_arg( BasicStringRef name, const char *&error) { if (this->check_no_auto_index(error)) { map_.init(this->args()); - const basic_format_arg *arg = map_.find(name); - if (arg) + if (const format_arg *arg = map_.find(name)) return *arg; error = "argument not found"; } - return basic_format_arg(); + return format_arg(); } template -inline basic_format_arg basic_format_context::parse_arg_id() { +inline typename basic_format_context::format_arg + basic_format_context::parse_arg_id() { const Char *&s = this->ptr(); if (!internal::is_name_start(*s)) { const char *error = 0; - basic_format_arg arg = *s < '0' || *s > '9' ? - this->next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); + format_arg arg = *s < '0' || *s > '9' ? + this->next_arg(error) : + get_arg(internal::parse_nonnegative_int(s), error); if (error) { FMT_THROW(format_error( *s != '}' && *s != ':' ? "invalid format string" : error)); @@ -3456,8 +3460,7 @@ inline basic_format_arg basic_format_context::parse_arg_id() { c = *++s; } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); const char *error = 0; - basic_format_arg arg = - get_arg(BasicStringRef(start, s - start), error); + format_arg arg = get_arg(BasicStringRef(start, s - start), error); if (error) FMT_THROW(format_error(error)); return arg; @@ -3465,7 +3468,7 @@ inline basic_format_arg basic_format_context::parse_arg_id() { // Formats a single argument. template -void do_format_arg(BasicWriter &writer, const basic_format_arg &arg, +void do_format_arg(BasicWriter &writer, basic_format_arg arg, Context &ctx) { const Char *&s = ctx.ptr(); FormatSpec spec; @@ -3643,7 +3646,7 @@ struct UdlArg { const Char *str; template - NamedArg operator=(T &&value) const { + NamedArg> operator=(T &&value) const { return {str, std::forward(value)}; } }; diff --git a/fmt/printf.h b/fmt/printf.h index 92d50ef4..13b82afd 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -80,14 +80,16 @@ struct is_same { enum { value = 1 }; }; -template +template class ArgConverter { private: - basic_format_arg &arg_; - Char type_; + typedef typename Context::char_type Char; + + basic_format_arg &arg_; + typename Context::char_type type_; public: - ArgConverter(basic_format_arg &arg, Char type) + ArgConverter(basic_format_arg &arg, Char type) : arg_(arg), type_(type) {} void operator()(bool value) { @@ -105,11 +107,11 @@ class ArgConverter { if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { - arg_ = internal::make_arg( + arg_ = internal::make_arg( static_cast(static_cast(value))); } else { typedef typename internal::MakeUnsigned::Type Unsigned; - arg_ = internal::make_arg( + arg_ = internal::make_arg( static_cast(static_cast(value))); } } else { @@ -117,10 +119,9 @@ class ArgConverter { // glibc's printf doesn't sign extend arguments of smaller types: // std::printf("%lld", -42); // prints "4294967254" // but we don't have to do the same because it's a UB. - arg_ = internal::make_arg( - static_cast(value)); + arg_ = internal::make_arg(static_cast(value)); } else { - arg_ = internal::make_arg( + arg_ = internal::make_arg( static_cast::Type>(value)); } } @@ -137,32 +138,30 @@ class ArgConverter { // If T is void, the argument is converted to corresponding signed or unsigned // type depending on the type specifier: 'd' and 'i' - signed, other - // unsigned). -template -void convert_arg(basic_format_arg &arg, Char type) { - visit(ArgConverter(arg, type), arg); +template +void convert_arg(basic_format_arg &arg, Char type) { + visit(ArgConverter(arg, type), arg); } // Converts an integer argument to char for printf. -template +template class CharConverter { private: - basic_format_arg &arg_; + basic_format_arg &arg_; FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); public: - explicit CharConverter(basic_format_arg &arg) : arg_(arg) {} + explicit CharConverter(basic_format_arg &arg) : arg_(arg) {} template typename std::enable_if::value>::type operator()(T value) { - arg_ = - internal::make_arg>(static_cast(value)); + arg_ = internal::make_arg(static_cast(value)); } template - typename std::enable_if::value>::type - operator()(T value) { + typename std::enable_if::value>::type operator()(T) { // No coversion needed for non-integral types. } }; @@ -301,12 +300,13 @@ class printf_context : private: typedef internal::format_context_base Base; + typedef typename Base::format_arg format_arg; void parse_flags(FormatSpec &spec, const Char *&s); // Returns the argument with specified index or, if arg_index is equal // to the maximum unsigned value, the next argument. - basic_format_arg get_arg( + format_arg get_arg( const Char *s, unsigned arg_index = (std::numeric_limits::max)()); @@ -356,12 +356,11 @@ void printf_context::parse_flags(FormatSpec &spec, const Char *&s) { } template -basic_format_arg printf_context::get_arg( +typename printf_context::format_arg printf_context::get_arg( const Char *s, unsigned arg_index) { (void)s; const char *error = 0; - basic_format_arg arg = - arg_index == std::numeric_limits::max() ? + format_arg arg = arg_index == std::numeric_limits::max() ? this->next_arg(error) : Base::get_arg(arg_index - 1, error); if (error) FMT_THROW(format_error(!*s ? "invalid format string" : error)); @@ -433,7 +432,7 @@ void printf_context::format(BasicWriter &writer) { } } - basic_format_arg arg = get_arg(s, arg_index); + format_arg arg = get_arg(s, arg_index); if (spec.flag(HASH_FLAG) && visit(internal::IsZeroInt(), arg)) spec.flags_ &= ~internal::to_unsigned(HASH_FLAG); if (spec.fill_ == '0') { @@ -488,7 +487,7 @@ void printf_context::format(BasicWriter &writer) { break; case 'c': // TODO: handle wchar_t - visit(internal::CharConverter(arg), arg); + visit(internal::CharConverter>(arg), arg); break; } } diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 8a0afb02..40ee0a8a 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -58,7 +58,8 @@ TEST(FormatTest, ArgConverter) { using fmt::format_arg; fmt::LongLong value = std::numeric_limits::max(); format_arg arg = fmt::internal::make_arg(value); - visit(fmt::internal::ArgConverter(arg, 'd'), arg); + visit(fmt::internal::ArgConverter< + fmt::LongLong, fmt::format_context>(arg, 'd'), arg); EXPECT_EQ(value, visit(ValueExtractor(), arg)); } diff --git a/test/util-test.cc b/test/util-test.cc index 0e276d52..73d3ca8a 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -73,9 +73,9 @@ void format_value(fmt::BasicWriter &w, Test, w << "test"; } -template -basic_format_arg make_arg(const T &value) { - return fmt::internal::make_arg< fmt::basic_format_context >(value); +template +basic_format_arg make_arg(const T &value) { + return fmt::internal::make_arg(value); } } // namespace @@ -487,7 +487,7 @@ VISIT_TYPE(float, double); #define CHECK_ARG_(Char, expected, value) { \ testing::StrictMock> visitor; \ EXPECT_CALL(visitor, visit(expected)); \ - fmt::visit(visitor, make_arg(value)); \ + fmt::visit(visitor, make_arg>(value)); \ } #define CHECK_ARG(value) { \ @@ -575,7 +575,7 @@ TEST(UtilTest, CustomArg) { EXPECT_EQ("test", w.str()); return Visitor::Result(); })); - fmt::visit(visitor, make_arg(test)); + fmt::visit(visitor, make_arg(test)); } TEST(ArgVisitorTest, VisitInvalidArg) {