diff --git a/include/fmt/core.h b/include/fmt/core.h index 0bc74fdf..fae0e063 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -1288,7 +1288,7 @@ inline format_arg_store make_format_args( return {args...}; } -template class dynamic_format_arg_store; +template class dynamic_format_arg_store; /** \rst @@ -1367,8 +1367,7 @@ template class basic_format_args { `~fmt::dynamic_format_arg_store`. \endrst */ - template - basic_format_args(const dynamic_format_arg_store& store) + basic_format_args(const dynamic_format_arg_store& store) : types_(store.get_types()) { set_data(store.data_.data()); } diff --git a/include/fmt/dyn-args.h b/include/fmt/dyn-args.h index 7f0293c7..20a4e2ab 100644 --- a/include/fmt/dyn-args.h +++ b/include/fmt/dyn-args.h @@ -6,6 +6,7 @@ #include #include +#include #include #include "core.h" @@ -59,10 +60,37 @@ template struct need_dyn_copy { template using need_dyn_copy_t = typename need_dyn_copy::type; -template -const T& get(const StorageValue& v) { - return v; -} +class dyn_arg_storage { + struct dyn_arg_node_base { + virtual ~dyn_arg_node_base() = default; + std::unique_ptr next_; + }; + + template + struct dyn_arg_node : dyn_arg_node_base { + T value_; + FMT_CONSTEXPR explicit dyn_arg_node(T&& arg) : value_{arg}{} + }; + + std::unique_ptr head_{nullptr}; + +public: + FMT_CONSTEXPR dyn_arg_storage() = default; + dyn_arg_storage(const dyn_arg_storage&) = delete; + FMT_CONSTEXPR dyn_arg_storage(dyn_arg_storage&&) = default; + + dyn_arg_storage& operator=(const dyn_arg_storage&) = delete; + FMT_CONSTEXPR dyn_arg_storage& operator=(dyn_arg_storage&&) = default; + + template + const T& emplace_front(T&& val) { + auto node{new dyn_arg_node{std::forward(val)}}; + std::unique_ptr ptr{node}; + swap(ptr, head_); + head_->next_ = std::move(ptr); + return node->value_; + } +}; } // namespace internal @@ -76,7 +104,7 @@ const T& get(const StorageValue& v) { into type-erased formatting functions such as `~fmt::vformat`. \endrst */ -template +template class dynamic_format_arg_store #if FMT_GCC_VERSION < 409 // Workaround a GCC template argument substitution bug. @@ -85,21 +113,8 @@ class dynamic_format_arg_store { private: using char_type = typename Context::char_type; - - static const bool has_custom_args = (sizeof...(Args) > 0); using string_type = std::basic_string; -#ifdef FMT_HAS_VARIANT - using storage_item_type = - conditional_t, - string_type>; -#else - static_assert(!has_custom_args, - "std::variant<> is required to support " - "custom types in dynamic_format_arg_store"); - using storage_item_type = string_type; -#endif using value_type = basic_format_arg; - using named_value_type = internal::named_arg_base; template using storaged_type = @@ -112,15 +127,10 @@ class dynamic_format_arg_store // Storage of arguments not fitting into basic_format_arg must grow // without relocation because items in data_ refer to it. - std::forward_list storage_; + internal::dyn_arg_storage storage_; friend class basic_format_args; - template const T& get_last_pushed() const { - using internal::get; - return get(storage_.front()); - } - unsigned long long get_types() const { return internal::is_unpacked_bit | data_.size(); } @@ -136,9 +146,7 @@ class dynamic_format_arg_store template const storaged_type& stored_value(const T& arg, std::true_type) { - using type = storaged_type; - storage_.emplace_front(type{arg}); - return get_last_pushed(); + return storage_.emplace_front(storaged_type{arg}); } template void emplace_arg(const T& arg) { diff --git a/test/format-dyn-args-test.cc b/test/format-dyn-args-test.cc index 94befa1f..ad7d60ad 100644 --- a/test/format-dyn-args-test.cc +++ b/test/format-dyn-args-test.cc @@ -49,10 +49,8 @@ template <> struct formatter { }; FMT_END_NAMESPACE -#ifdef FMT_HAS_VARIANT - TEST(FormatDynArgsTest, CustomFormat) { - fmt::dynamic_format_arg_store store; + fmt::dynamic_format_arg_store store; Custom c{}; store.push_back(c); ++c.i; @@ -66,8 +64,6 @@ TEST(FormatDynArgsTest, CustomFormat) { EXPECT_EQ("cust=0 and cust=1 and cust=3", result); } -#endif // FMT_HAS_VARIANT - TEST(FormatDynArgsTest, NamedArgByRef) { fmt::dynamic_format_arg_store store;