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.
|
// unit for placing vtable. So storage_node_base is made a fake template.
|
||||||
template <typename = void> struct node {
|
template <typename = void> struct node {
|
||||||
virtual ~node() = default;
|
virtual ~node() = default;
|
||||||
|
virtual std::unique_ptr<node<>> clone() const = 0;
|
||||||
std::unique_ptr<node<>> next;
|
std::unique_ptr<node<>> next;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> struct typed_node : node<> {
|
template <typename T> struct typed_node : node<> {
|
||||||
T value;
|
T value;
|
||||||
|
|
||||||
|
FMT_CONSTEXPR typed_node(const typed_node<T>& node) : value(node.value) {}
|
||||||
|
|
||||||
template <typename Arg>
|
template <typename Arg>
|
||||||
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
|
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
|
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
|
||||||
: value(arg.data(), arg.size()) {}
|
: 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_;
|
std::unique_ptr<node<>> head_;
|
||||||
|
|
||||||
public:
|
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) {
|
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 new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
|
||||||
auto& value = new_node->value;
|
auto& value = new_node->value;
|
||||||
@ -145,6 +183,15 @@ class dynamic_format_arg_store
|
|||||||
public:
|
public:
|
||||||
constexpr dynamic_format_arg_store() = default;
|
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
|
\rst
|
||||||
Adds an argument into the dynamic store for later passing to a formatting
|
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;
|
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() : no_value() {}
|
||||||
constexpr FMT_INLINE value(int val) : int_value(val) {}
|
constexpr FMT_INLINE value(int val) : int_value(val) {}
|
||||||
constexpr FMT_INLINE value(unsigned val) : uint_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) {}
|
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 {
|
constexpr explicit operator bool() const noexcept {
|
||||||
return type_ != detail::type::none_type;
|
return type_ != detail::type::none_type;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
TEST(args_test, basic) {
|
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(42);
|
||||||
store.push_back("abc1");
|
store.push_back("abc1");
|
||||||
store.push_back(1.5f);
|
store.push_back(1.5f);
|
||||||
@ -21,7 +21,7 @@ TEST(args_test, basic) {
|
|||||||
|
|
||||||
TEST(args_test, strings_and_refs) {
|
TEST(args_test, strings_and_refs) {
|
||||||
// Unfortunately the tests are compiled with old ABI so strings use COW.
|
// 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";
|
char str[] = "1234567890";
|
||||||
store.push_back(str);
|
store.push_back(str);
|
||||||
store.push_back(std::cref(str));
|
store.push_back(std::cref(str));
|
||||||
@ -50,7 +50,7 @@ template <> struct formatter<custom_type> {
|
|||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
TEST(args_test, custom_format) {
|
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();
|
auto c = custom_type();
|
||||||
store.push_back(c);
|
store.push_back(c);
|
||||||
++c.i;
|
++c.i;
|
||||||
@ -79,7 +79,7 @@ template <> struct formatter<to_stringable> {
|
|||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
TEST(args_test, to_string_and_formatter) {
|
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();
|
auto s = to_stringable();
|
||||||
store.push_back(s);
|
store.push_back(s);
|
||||||
store.push_back(std::cref(s));
|
store.push_back(std::cref(s));
|
||||||
@ -87,13 +87,13 @@ TEST(args_test, to_string_and_formatter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(args_test, named_int) {
|
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));
|
store.push_back(fmt::arg("a1", 42));
|
||||||
EXPECT_EQ("42", fmt::vformat("{a1}", store));
|
EXPECT_EQ("42", fmt::vformat("{a1}", store));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(args_test, named_strings) {
|
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";
|
char str[] = "1234567890";
|
||||||
store.push_back(fmt::arg("a1", str));
|
store.push_back(fmt::arg("a1", str));
|
||||||
store.push_back(fmt::arg("a2", std::cref(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) {
|
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";
|
char band[] = "Rolling Stones";
|
||||||
store.push_back(fmt::arg("band", std::cref(band)));
|
store.push_back(fmt::arg("band", std::cref(band)));
|
||||||
band[9] = 'c'; // Changing band affects the output.
|
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) {
|
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();
|
auto c = custom_type();
|
||||||
store.push_back(fmt::arg("c1", c));
|
store.push_back(fmt::arg("c1", c));
|
||||||
++c.i;
|
++c.i;
|
||||||
@ -123,7 +123,7 @@ TEST(args_test, named_custom_format) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(args_test, clear) {
|
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);
|
store.push_back(42);
|
||||||
|
|
||||||
auto result = fmt::vformat("{}", store);
|
auto result = fmt::vformat("{}", store);
|
||||||
@ -140,7 +140,7 @@ TEST(args_test, clear) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(args_test, reserve) {
|
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.reserve(2, 1);
|
||||||
store.push_back(1.5f);
|
store.push_back(1.5f);
|
||||||
store.push_back(fmt::arg("a1", 42));
|
store.push_back(fmt::arg("a1", 42));
|
||||||
@ -165,7 +165,7 @@ template <> struct formatter<copy_throwable> {
|
|||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
TEST(args_test, throw_on_copy) {
|
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"));
|
store.push_back(std::string("foo"));
|
||||||
try {
|
try {
|
||||||
store.push_back(copy_throwable());
|
store.push_back(copy_throwable());
|
||||||
@ -184,3 +184,18 @@ TEST(args_test, move_constructor) {
|
|||||||
store.reset();
|
store.reset();
|
||||||
EXPECT_EQ(fmt::vformat("{} {} {a1}", moved_store), "42 foo foo");
|
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