Custom list -- first cut.

Pending: cleanup.
This commit is contained in:
vsol 2020-03-12 10:30:25 +03:00
parent f0984c43bc
commit 107f9a84b4
3 changed files with 38 additions and 35 deletions

View File

@ -1288,7 +1288,7 @@ inline format_arg_store<Context, Args...> make_format_args(
return {args...}; return {args...};
} }
template <typename Context, typename... Args> class dynamic_format_arg_store; template <typename Context> class dynamic_format_arg_store;
/** /**
\rst \rst
@ -1367,8 +1367,7 @@ template <typename Context> class basic_format_args {
`~fmt::dynamic_format_arg_store`. `~fmt::dynamic_format_arg_store`.
\endrst \endrst
*/ */
template <typename... Args> basic_format_args(const dynamic_format_arg_store<Context>& store)
basic_format_args(const dynamic_format_arg_store<Context, Args...>& store)
: types_(store.get_types()) { : types_(store.get_types()) {
set_data(store.data_.data()); set_data(store.data_.data());
} }

View File

@ -6,6 +6,7 @@
#include <forward_list> #include <forward_list>
#include <functional> #include <functional>
#include <memory>
#include <vector> #include <vector>
#include "core.h" #include "core.h"
@ -59,10 +60,37 @@ template <typename T, typename Context> struct need_dyn_copy {
template <typename T, typename Context> template <typename T, typename Context>
using need_dyn_copy_t = typename need_dyn_copy<T, Context>::type; using need_dyn_copy_t = typename need_dyn_copy<T, Context>::type;
template <typename T, typename StorageValue> class dyn_arg_storage {
const T& get(const StorageValue& v) { struct dyn_arg_node_base {
return v; virtual ~dyn_arg_node_base() = default;
} std::unique_ptr<dyn_arg_node_base> next_;
};
template<typename T>
struct dyn_arg_node : dyn_arg_node_base {
T value_;
FMT_CONSTEXPR explicit dyn_arg_node(T&& arg) : value_{arg}{}
};
std::unique_ptr<dyn_arg_node_base> 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<typename T>
const T& emplace_front(T&& val) {
auto node{new dyn_arg_node<T>{std::forward<T>(val)}};
std::unique_ptr<dyn_arg_node_base> ptr{node};
swap(ptr, head_);
head_->next_ = std::move(ptr);
return node->value_;
}
};
} // namespace internal } // namespace internal
@ -76,7 +104,7 @@ const T& get(const StorageValue& v) {
into type-erased formatting functions such as `~fmt::vformat`. into type-erased formatting functions such as `~fmt::vformat`.
\endrst \endrst
*/ */
template <typename Context, typename... Args> template <typename Context>
class dynamic_format_arg_store class dynamic_format_arg_store
#if FMT_GCC_VERSION < 409 #if FMT_GCC_VERSION < 409
// Workaround a GCC template argument substitution bug. // Workaround a GCC template argument substitution bug.
@ -85,21 +113,8 @@ class dynamic_format_arg_store
{ {
private: private:
using char_type = typename Context::char_type; using char_type = typename Context::char_type;
static const bool has_custom_args = (sizeof...(Args) > 0);
using string_type = std::basic_string<char_type>; using string_type = std::basic_string<char_type>;
#ifdef FMT_HAS_VARIANT
using storage_item_type =
conditional_t<has_custom_args, std::variant<string_type, Args...>,
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<Context>; using value_type = basic_format_arg<Context>;
using named_value_type = internal::named_arg_base<char_type>;
template <typename T> template <typename T>
using storaged_type = using storaged_type =
@ -112,15 +127,10 @@ class dynamic_format_arg_store
// Storage of arguments not fitting into basic_format_arg must grow // Storage of arguments not fitting into basic_format_arg must grow
// without relocation because items in data_ refer to it. // without relocation because items in data_ refer to it.
std::forward_list<storage_item_type> storage_; internal::dyn_arg_storage storage_;
friend class basic_format_args<Context>; friend class basic_format_args<Context>;
template <typename T> const T& get_last_pushed() const {
using internal::get;
return get<T>(storage_.front());
}
unsigned long long get_types() const { unsigned long long get_types() const {
return internal::is_unpacked_bit | data_.size(); return internal::is_unpacked_bit | data_.size();
} }
@ -136,9 +146,7 @@ class dynamic_format_arg_store
template <typename T> template <typename T>
const storaged_type<T>& stored_value(const T& arg, std::true_type) { const storaged_type<T>& stored_value(const T& arg, std::true_type) {
using type = storaged_type<T>; return storage_.emplace_front(storaged_type<T>{arg});
storage_.emplace_front(type{arg});
return get_last_pushed<type>();
} }
template <typename T> void emplace_arg(const T& arg) { template <typename T> void emplace_arg(const T& arg) {

View File

@ -49,10 +49,8 @@ template <> struct formatter<Custom> {
}; };
FMT_END_NAMESPACE FMT_END_NAMESPACE
#ifdef FMT_HAS_VARIANT
TEST(FormatDynArgsTest, CustomFormat) { TEST(FormatDynArgsTest, CustomFormat) {
fmt::dynamic_format_arg_store<fmt::format_context, Custom> store; fmt::dynamic_format_arg_store<fmt::format_context> store;
Custom c{}; Custom c{};
store.push_back(c); store.push_back(c);
++c.i; ++c.i;
@ -66,8 +64,6 @@ TEST(FormatDynArgsTest, CustomFormat) {
EXPECT_EQ("cust=0 and cust=1 and cust=3", result); EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
} }
#endif // FMT_HAS_VARIANT
TEST(FormatDynArgsTest, NamedArgByRef) { TEST(FormatDynArgsTest, NamedArgByRef) {
fmt::dynamic_format_arg_store<fmt::format_context> store; fmt::dynamic_format_arg_store<fmt::format_context> store;