diff --git a/include/fmt/core.h b/include/fmt/core.h index 9c90e6398d473..03a47557d1ee0 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -1099,7 +1099,7 @@ FMT_CONSTEXPR void basic_format_parse_context::check_dynamic_spec( FMT_EXPORT template class basic_format_arg; FMT_EXPORT template class basic_format_args; -FMT_EXPORT template class format_arg_store; +FMT_EXPORT template class format_arg_store_impl; FMT_EXPORT template class dynamic_format_arg_store; // A formatter for objects of type T. @@ -1192,33 +1192,6 @@ template struct named_arg_info { int id; }; -template -struct arg_data { - // args_[0].named_args points to named_args_ to avoid bloating format_args. - // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. - T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)]; - named_arg_info named_args_[NUM_NAMED_ARGS]; - - template - arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {} - arg_data(const arg_data& other) = delete; - auto args() const -> const T* { return args_ + 1; } - auto named_args() -> named_arg_info* { return named_args_; } -}; - -template -struct arg_data { - // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. - T args_[NUM_ARGS != 0 ? NUM_ARGS : +1]; - - template - FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {} - FMT_CONSTEXPR FMT_INLINE auto args() const -> const T* { return args_; } - FMT_CONSTEXPR FMT_INLINE auto named_args() -> std::nullptr_t { - return nullptr; - } -}; - template inline void init_named_args(named_arg_info*, int, int) {} @@ -1638,8 +1611,7 @@ template class basic_format_arg { using char_type = typename Context::char_type; - template - friend struct detail::arg_data; + template friend class format_arg_store_impl; basic_format_arg(const detail::named_arg_info* args, size_t size) : value_(args, size) {} @@ -1792,11 +1764,11 @@ template class basic_format_args { Constructs a `basic_format_args` object from `~fmt::format_arg_store`. \endrst */ - template + template constexpr FMT_INLINE basic_format_args( - const format_arg_store& store) - : basic_format_args(format_arg_store::desc, - store.data_.args()) {} + const format_arg_store_impl& store) + : basic_format_args(format_arg_store_impl::desc, + store.args()) {} /** \rst @@ -1926,8 +1898,8 @@ using is_formattable = bool_constant -class format_arg_store +template +class format_arg_store_impl #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 // Workaround a GCC template argument substitution bug. : public basic_format_args @@ -1935,38 +1907,81 @@ class format_arg_store { private: static const size_t num_args = sizeof...(Args); - static constexpr size_t num_named_args = detail::count_named_args(); static const bool is_packed = num_args <= detail::max_packed_args; + using char_type = typename Context::char_type; using value_type = conditional_t, basic_format_arg>; - detail::arg_data - data_; + // args_[0].named_args points to named_args_ to avoid bloating format_args. + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + value_type args_[1 + (num_args != 0 ? num_args : +1)]; + detail::named_arg_info named_args_[NUM_NAMED_ARGS]; - friend class basic_format_args; + public: + template + FMT_CONSTEXPR FMT_INLINE format_arg_store_impl(T&... args) + : +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + basic_format_args(*this), +#endif + args_{value_type(named_args_, NUM_NAMED_ARGS), + detail::make_arg(args)...} { + detail::init_named_args(named_args_, 0, 0, args...); + } static constexpr unsigned long long desc = (is_packed ? detail::encode_types() : detail::is_unpacked_bit | num_args) | - (num_named_args != 0 + (NUM_NAMED_ARGS != 0 ? static_cast(detail::has_named_args_bit) : 0); + FMT_CONSTEXPR FMT_INLINE auto args() const -> const value_type* { + return args_ + 1; + } +}; + +template +class format_arg_store_impl +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + // Workaround a GCC template argument substitution bug. + : public basic_format_args +#endif +{ + private: + static const size_t num_args = sizeof...(Args); + static const bool is_packed = num_args <= detail::max_packed_args; + + using value_type = conditional_t, + basic_format_arg>; + + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + value_type args_[num_args != 0 ? num_args : +1]; + public: template - FMT_CONSTEXPR FMT_INLINE format_arg_store(T&... args) + FMT_CONSTEXPR FMT_INLINE format_arg_store_impl(T&... args) : #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 basic_format_args(*this), #endif - data_{detail::make_arg(args)...} { - if (detail::const_check(num_named_args != 0)) - detail::init_named_args(data_.named_args(), 0, 0, args...); + args_{detail::make_arg(args)...} { + } + + static constexpr unsigned long long desc = + (is_packed ? detail::encode_types() + : detail::is_unpacked_bit | num_args); + + FMT_CONSTEXPR FMT_INLINE auto args() const -> const value_type* { + return args_; } }; +template +using format_arg_store = + format_arg_store_impl(), T...>; + /** \rst Constructs a `~fmt::format_arg_store` object that contains references to @@ -1976,9 +1991,10 @@ class format_arg_store \endrst */ // Arguments are taken by lvalue references to avoid some lifetime issues. -template +template ()> constexpr auto make_format_args(T&... args) - -> format_arg_store...> { + -> format_arg_store_impl...> { return {args...}; } @@ -2302,9 +2318,10 @@ enum class state { start, align, sign, hash, zero, width, precision, locale }; // Parses standard format specifiers. template -FMT_CONSTEXPR FMT_INLINE auto parse_format_specs( - const Char* begin, const Char* end, dynamic_format_specs& specs, - basic_format_parse_context& ctx, type arg_type) -> const Char* { +FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end, + dynamic_format_specs& specs, + basic_format_parse_context& ctx, + type arg_type) -> const Char* { auto c = '\0'; if (end - begin > 1) { auto next = to_ascii(begin[1]); @@ -2742,6 +2759,7 @@ struct formatter FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* { + if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin(); auto type = detail::type_constant::value; auto end = detail::parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, type);