From 99e2052669e9aa2fff5b6b0c243d10f8a357e2d0 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 8 Jan 2024 20:40:03 -0800 Subject: [PATCH] Improve arg storage --- include/fmt/core.h | 113 ++++++++++++++++++++++++-------------------- include/fmt/xchar.h | 4 +- test/printf-test.cc | 2 +- test/xchar-test.cc | 3 +- 4 files changed, 67 insertions(+), 55 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index 322fd99db60c9..7555b4cae69eb 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -139,6 +139,13 @@ FMT_END_NAMESPACE_STD # endif #endif +// Workaround broken [[deprecated]] in the Intel compiler and NVCC. +#if defined(__INTEL_COMPILER) || defined(__NVCC__) +# define FMT_DEPRECATED_ALIAS +#else +# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED +#endif + // Check if relaxed C++14 constexpr is supported. // GCC doesn't allow throw in constexpr until version 6 (bug 67371). #ifndef FMT_USE_CONSTEXPR @@ -1099,7 +1106,8 @@ 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_impl; +FMT_EXPORT template +struct format_arg_store_impl; FMT_EXPORT template class dynamic_format_arg_store; // A formatter for objects of type T. @@ -1611,7 +1619,8 @@ template class basic_format_arg { using char_type = typename Context::char_type; - template friend class format_arg_store_impl; + template + friend struct format_arg_store_impl; basic_format_arg(const detail::named_arg_info* args, size_t size) : value_(args, size) {} @@ -1758,19 +1767,19 @@ template class basic_format_args { Constructs a `basic_format_args` object from `~fmt::format_arg_store`. \endrst */ - template + template constexpr basic_format_args( - const format_arg_store_impl& store) - : desc_(format_arg_store_impl::desc), - values_(store.args()) {} + const format_arg_store_impl& + store) + : desc_(DESC), values_(store.args()) {} - template detail::max_packed_args)> + template detail::max_packed_args)> constexpr basic_format_args( - const format_arg_store_impl& store) - : desc_(format_arg_store_impl::desc), - args_(store.args()) {} + const format_arg_store_impl& + store) + : desc_(DESC), args_(store.args()) {} /** \rst @@ -1900,72 +1909,48 @@ using is_formattable = bool_constant -class format_arg_store_impl { - private: - static const size_t num_args = sizeof...(Args); - static const bool is_packed = num_args <= detail::max_packed_args; +template +struct format_arg_store_impl { + 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>; - // args_[0].named_args points to named_args_ to avoid bloating format_args. + // 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]; + value_type args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)]; + detail::named_arg_info named_args[NUM_NAMED_ARGS]; - public: template FMT_CONSTEXPR FMT_INLINE format_arg_store_impl(T&... args) - : args_{value_type(named_args_, NUM_NAMED_ARGS), + : args_{value_type(named_args, NUM_NAMED_ARGS), detail::make_arg(args)...} { - detail::init_named_args(named_args_, 0, 0, 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 - ? static_cast(detail::has_named_args_bit) - : 0); - FMT_CONSTEXPR FMT_INLINE auto args() const -> const value_type* { return args_ + 1; } }; // A specialization of format_arg_store_impl without named arguments. -template -class format_arg_store_impl { - private: - static const size_t num_args = sizeof...(Args); - static const bool is_packed = num_args <= detail::max_packed_args; +template +struct format_arg_store_impl { + 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_impl(T&... args) - : args_{detail::make_arg(args)...} {} - - static constexpr unsigned long long desc = - (is_packed ? detail::encode_types() - : detail::is_unpacked_bit | num_args); + value_type args_[NUM_ARGS != 0 ? NUM_ARGS : +1]; FMT_CONSTEXPR FMT_INLINE auto args() const -> const value_type* { return args_; } }; -template -using format_arg_store = - format_arg_store_impl(), T...>; - /** \rst Constructs an object that stores references to arguments and can be implicitly @@ -1978,12 +1963,38 @@ using format_arg_store = // auto args = make_format_args(std::string()); // Use format_arg_store_impl instead of format_arg_store for shorter symbols. template ()> + size_t NUM_ARGS = sizeof...(T), + size_t NUM_NAMED_ARGS = detail::count_named_args(), + unsigned long long DESC = (NUM_ARGS <= detail::max_packed_args + ? detail::encode_types() + : detail::is_unpacked_bit | NUM_ARGS), + FMT_ENABLE_IF(NUM_NAMED_ARGS == 0)> +constexpr auto make_format_args(T&... args) + -> format_arg_store_impl { + return { + detail::make_arg(args)...}; +} + +template (), + unsigned long long DESC = + (NUM_ARGS <= detail::max_packed_args + ? detail::encode_types() + : detail::is_unpacked_bit | NUM_ARGS) | + (NUM_NAMED_ARGS != 0 + ? static_cast(detail::has_named_args_bit) + : 0), + FMT_ENABLE_IF(NUM_NAMED_ARGS != 0)> constexpr auto make_format_args(T&... args) - -> format_arg_store_impl...> { + -> format_arg_store_impl { return {args...}; } +template +using format_arg_store FMT_DEPRECATED_ALIAS = + decltype(make_format_args(std::declval()...)); + /** \rst Returns a named argument to be used in a formatting function. diff --git a/include/fmt/xchar.h b/include/fmt/xchar.h index 3beead4244459..68e81659e0d41 100644 --- a/include/fmt/xchar.h +++ b/include/fmt/xchar.h @@ -87,9 +87,9 @@ template <> struct is_char : std::true_type {}; template <> struct is_char : std::true_type {}; template -constexpr auto make_wformat_args(const T&... args) +constexpr auto make_wformat_args(T&... args) -> format_arg_store { - return {args...}; + return make_format_args(args...); } inline namespace literals { diff --git a/test/printf-test.cc b/test/printf-test.cc index 63d5b437ab100..c96811c8f3ee8 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -529,7 +529,7 @@ TEST(printf_test, wide_string) { TEST(printf_test, vprintf) { int n = 42; - auto store = fmt::format_arg_store(n); + auto store = fmt::make_format_args(n); auto args = fmt::basic_format_args(store); EXPECT_EQ(fmt::vsprintf(fmt::string_view("%d"), args), "42"); EXPECT_WRITE(stdout, fmt::vfprintf(stdout, fmt::string_view("%d"), args), diff --git a/test/xchar-test.cc b/test/xchar-test.cc index c5482dc13eb89..8ecfebe4289b1 100644 --- a/test/xchar-test.cc +++ b/test/xchar-test.cc @@ -194,7 +194,8 @@ TEST(xchar_test, format_to) { } TEST(xchar_test, vformat_to) { - auto args = fmt::make_wformat_args(42); + int n = 42; + auto args = fmt::make_wformat_args(n); auto w = std::wstring(); fmt::vformat_to(std::back_inserter(w), L"{}", args); EXPECT_EQ(L"42", w);