dynamic_format_arg_store: Add copy constructor
To implement this copy constructor we need the following copy constructors too: 1) dynamic_arg_list 2) basic_format_arg 1) value 3) named_arg_info
This commit is contained in:
parent
db745986f2
commit
b679ebba04
@ -33,23 +33,61 @@ class dynamic_arg_list {
|
||||
// unit for placing vtable. So storage_node_base is made a fake template.
|
||||
template <typename = void> struct node {
|
||||
virtual ~node() = default;
|
||||
virtual std::unique_ptr<node<>> clone() const = 0;
|
||||
std::unique_ptr<node<>> next;
|
||||
};
|
||||
|
||||
template <typename T> struct typed_node : node<> {
|
||||
T value;
|
||||
|
||||
FMT_CONSTEXPR typed_node(const typed_node<T>& node) : value(node.value) {}
|
||||
|
||||
template <typename Arg>
|
||||
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
|
||||
: value(arg.data(), arg.size()) {}
|
||||
|
||||
std::unique_ptr<node<>> clone() const override {
|
||||
return std::unique_ptr<typed_node<T>>(new typed_node<T>(*this));
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<node<>> head_;
|
||||
|
||||
public:
|
||||
constexpr dynamic_arg_list() = default;
|
||||
|
||||
dynamic_arg_list(const dynamic_arg_list& arg_list) {
|
||||
if (arg_list.head_) {
|
||||
head_ = arg_list.head_->clone();
|
||||
auto temp = head_.get();
|
||||
auto arg_list_temp = arg_list.head_.get();
|
||||
while (arg_list_temp->next) {
|
||||
temp->next = arg_list_temp->next->clone();
|
||||
temp = temp->next.get();
|
||||
arg_list_temp = arg_list_temp->next.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic_arg_list& operator=(const dynamic_arg_list& arg_list) {
|
||||
if (this != &arg_list) {
|
||||
if (arg_list.head_) {
|
||||
head_ = arg_list.head_->clone();
|
||||
auto temp = head_.get();
|
||||
auto arg_list_temp = arg_list.head_.get();
|
||||
while (arg_list_temp->next) {
|
||||
temp->next = arg_list_temp->next->clone();
|
||||
temp = temp->next.get();
|
||||
arg_list_temp = arg_list_temp->next.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename Arg> const T& push(const Arg& arg) {
|
||||
auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
|
||||
auto& value = new_node->value;
|
||||
@ -145,6 +183,15 @@ class dynamic_format_arg_store
|
||||
public:
|
||||
constexpr dynamic_format_arg_store() = default;
|
||||
|
||||
dynamic_format_arg_store(const dynamic_format_arg_store<Context>& store)
|
||||
:
|
||||
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
||||
basic_format_args<Context>(),
|
||||
#endif
|
||||
data_(store.data_),
|
||||
named_info_(store.named_info_),
|
||||
dynamic_args_(store.dynamic_args_) {
|
||||
}
|
||||
/**
|
||||
\rst
|
||||
Adds an argument into the dynamic store for later passing to a formatting
|
||||
|
||||
@ -1204,6 +1204,63 @@ template <typename Context> class value {
|
||||
named_arg_value<char_type> named_args;
|
||||
};
|
||||
|
||||
FMT_INLINE value(const value<Context>& v, const type& t) {
|
||||
switch (t) {
|
||||
case type::none_type:
|
||||
no_value = monostate();
|
||||
break;
|
||||
case type::int_type:
|
||||
int_value = v.int_value;
|
||||
break;
|
||||
case type::uint_type:
|
||||
uint_value = v.uint_value;
|
||||
break;
|
||||
case type::long_long_type:
|
||||
long_long_value = v.long_long_value;
|
||||
break;
|
||||
case type::ulong_long_type:
|
||||
ulong_long_value = v.ulong_long_value;
|
||||
break;
|
||||
case type::int128_type:
|
||||
int128_value = v.int128_value;
|
||||
break;
|
||||
case type::uint128_type:
|
||||
uint128_value = v.uint128_value;
|
||||
break;
|
||||
case type::bool_type:
|
||||
bool_value = v.bool_value;
|
||||
break;
|
||||
case type::char_type:
|
||||
char_value = v.char_value;
|
||||
break;
|
||||
case type::float_type:
|
||||
float_value = v.float_value;
|
||||
break;
|
||||
case type::double_type:
|
||||
double_value = v.double_value;
|
||||
break;
|
||||
case type::long_double_type:
|
||||
long_double_value = v.long_double_value;
|
||||
break;
|
||||
case type::cstring_type:
|
||||
case type::string_type:
|
||||
string.data = v.string.data;
|
||||
string.size = v.string.size;
|
||||
break;
|
||||
case type::pointer_type:
|
||||
pointer = v.pointer;
|
||||
break;
|
||||
case type::custom_type:
|
||||
custom.value = v.custom.value;
|
||||
custom.format = v.custom.format;
|
||||
break;
|
||||
default:
|
||||
named_args.data = v.named_args.data;
|
||||
named_args.size = v.named_args.size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr FMT_INLINE value() : no_value() {}
|
||||
constexpr FMT_INLINE value(int val) : int_value(val) {}
|
||||
constexpr FMT_INLINE value(unsigned val) : uint_value(val) {}
|
||||
@ -1548,6 +1605,9 @@ template <typename Context> class basic_format_arg {
|
||||
|
||||
constexpr basic_format_arg() : type_(detail::type::none_type) {}
|
||||
|
||||
basic_format_arg(const basic_format_arg<Context>& arg)
|
||||
: value_(arg.value_, arg.type_), type_(arg.type_) {}
|
||||
|
||||
constexpr explicit operator bool() const noexcept {
|
||||
return type_ != detail::type::none_type;
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(args_test, basic) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||
store.push_back(42);
|
||||
store.push_back("abc1");
|
||||
store.push_back(1.5f);
|
||||
@ -21,7 +21,7 @@ TEST(args_test, basic) {
|
||||
|
||||
TEST(args_test, strings_and_refs) {
|
||||
// Unfortunately the tests are compiled with old ABI so strings use COW.
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||
char str[] = "1234567890";
|
||||
store.push_back(str);
|
||||
store.push_back(std::cref(str));
|
||||
@ -50,7 +50,7 @@ template <> struct formatter<custom_type> {
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(args_test, custom_format) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||
auto c = custom_type();
|
||||
store.push_back(c);
|
||||
++c.i;
|
||||
@ -79,7 +79,7 @@ template <> struct formatter<to_stringable> {
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(args_test, to_string_and_formatter) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||
auto s = to_stringable();
|
||||
store.push_back(s);
|
||||
store.push_back(std::cref(s));
|
||||
@ -87,13 +87,13 @@ TEST(args_test, to_string_and_formatter) {
|
||||
}
|
||||
|
||||
TEST(args_test, named_int) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||
store.push_back(fmt::arg("a1", 42));
|
||||
EXPECT_EQ("42", fmt::vformat("{a1}", store));
|
||||
}
|
||||
|
||||
TEST(args_test, named_strings) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||
char str[] = "1234567890";
|
||||
store.push_back(fmt::arg("a1", str));
|
||||
store.push_back(fmt::arg("a2", std::cref(str)));
|
||||
@ -102,7 +102,7 @@ TEST(args_test, named_strings) {
|
||||
}
|
||||
|
||||
TEST(args_test, named_arg_by_ref) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||
char band[] = "Rolling Stones";
|
||||
store.push_back(fmt::arg("band", std::cref(band)));
|
||||
band[9] = 'c'; // Changing band affects the output.
|
||||
@ -110,7 +110,7 @@ TEST(args_test, named_arg_by_ref) {
|
||||
}
|
||||
|
||||
TEST(args_test, named_custom_format) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||
auto c = custom_type();
|
||||
store.push_back(fmt::arg("c1", c));
|
||||
++c.i;
|
||||
@ -123,7 +123,7 @@ TEST(args_test, named_custom_format) {
|
||||
}
|
||||
|
||||
TEST(args_test, clear) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||
store.push_back(42);
|
||||
|
||||
auto result = fmt::vformat("{}", store);
|
||||
@ -140,7 +140,7 @@ TEST(args_test, clear) {
|
||||
}
|
||||
|
||||
TEST(args_test, reserve) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||
store.reserve(2, 1);
|
||||
store.push_back(1.5f);
|
||||
store.push_back(fmt::arg("a1", 42));
|
||||
@ -165,7 +165,7 @@ template <> struct formatter<copy_throwable> {
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(args_test, throw_on_copy) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||
store.push_back(std::string("foo"));
|
||||
try {
|
||||
store.push_back(copy_throwable());
|
||||
@ -184,3 +184,18 @@ TEST(args_test, move_constructor) {
|
||||
store.reset();
|
||||
EXPECT_EQ(fmt::vformat("{} {} {a1}", moved_store), "42 foo foo");
|
||||
}
|
||||
|
||||
TEST(args_test, copy_constructor) {
|
||||
using store_type = fmt::dynamic_format_arg_store<fmt::format_context>;
|
||||
auto store = std::unique_ptr<store_type>(new store_type());
|
||||
store->push_back(fmt::arg("test1", "value1"));
|
||||
store->push_back(fmt::arg("test2", "value2"));
|
||||
store->push_back(fmt::arg("test3", "value3"));
|
||||
|
||||
auto store2 = std::unique_ptr<store_type>(new store_type(*store));
|
||||
store.reset();
|
||||
store2->push_back(fmt::arg("test4", "value4"));
|
||||
|
||||
auto result = fmt::vformat("{test1} {test2} {test3} {test4}", *store2);
|
||||
EXPECT_EQ(result, "value1 value2 value3 value4");
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user