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:
Spiros Tsalikis 2022-03-23 22:54:46 -04:00
parent db745986f2
commit b679ebba04
3 changed files with 133 additions and 11 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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");
}