From 17d187652938c228f1a54f2eef7bd7820f5ee43b Mon Sep 17 00:00:00 2001 From: Mark Gillard Date: Mon, 27 Jul 2020 13:38:01 +0300 Subject: [PATCH] added copy construction/assignment for arrays. tables and values In service of satisfying #49. --- docs/tomlplusplus.css | 6 + include/toml++/toml_array.h | 47 +++++--- include/toml++/toml_array.hpp | 60 +++++++--- include/toml++/toml_node.h | 7 +- include/toml++/toml_table.h | 23 ++-- include/toml++/toml_table.hpp | 56 +++++++--- include/toml++/toml_value.h | 27 ++++- tests/manipulating_arrays.cpp | 79 ++++++++++++- tests/manipulating_tables.cpp | 88 +++++++++++++-- tests/manipulating_values.cpp | 10 +- toml.hpp | 205 ++++++++++++++++++++++++---------- vs/toml++.natvis | 12 +- 12 files changed, 470 insertions(+), 150 deletions(-) diff --git a/docs/tomlplusplus.css b/docs/tomlplusplus.css index f7a84e7..a423855 100644 --- a/docs/tomlplusplus.css +++ b/docs/tomlplusplus.css @@ -316,3 +316,9 @@ pre > p.godbolt { float: right; } +@media only screen and ((max-width: 575px) or ((hover: none) and (pointer: coarse))) +{ + .godbolt { + display: none; + } +} diff --git a/include/toml++/toml_array.h b/include/toml++/toml_array.h index 2d8cd6c..a497c3d 100644 --- a/include/toml++/toml_array.h +++ b/include/toml++/toml_array.h @@ -176,16 +176,13 @@ TOML_IMPL_NAMESPACE_START template [[nodiscard]] TOML_ATTR(returns_nonnull) - TOML_ALWAYS_INLINE - auto* make_node(T&& val) noexcept + auto* make_node_specialized(T&& val) noexcept { using type = unwrap_node>; + static_assert(!std::is_same_v); + if constexpr (is_one_of) { - static_assert( - std::is_rvalue_reference_v, - "Tables and arrays may only be moved (not copied)." - ); return new type{ std::forward(val) }; } else @@ -215,7 +212,23 @@ TOML_IMPL_NAMESPACE_START template [[nodiscard]] TOML_ATTR(returns_nonnull) - TOML_ALWAYS_INLINE + auto* make_node(T&& val) noexcept + { + using type = unwrap_node>; + if constexpr (std::is_same_v) + { + return std::forward(val).visit([](auto&& concrete) noexcept + { + return static_cast(make_node_specialized(std::forward(concrete))); + }); + } + else + return make_node_specialized(std::forward(val)); + } + + template + [[nodiscard]] + TOML_ATTR(returns_nonnull) auto* make_node(inserter&& val) noexcept { return make_node(std::move(val.value)); @@ -308,10 +321,20 @@ TOML_NAMESPACE_START TOML_NODISCARD_CTOR array() noexcept; + /// \brief Copy constructor. + TOML_NODISCARD_CTOR + array(const array&) noexcept; + /// \brief Move constructor. TOML_NODISCARD_CTOR array(array&& other) noexcept; + /// \brief Copy-assignment operator. + array& operator= (const array&) noexcept; + + /// \brief Move-assignment operator. + array& operator= (array&& rhs) noexcept; + /// \brief Constructs an array with one or more initial elements. /// /// \detail \cpp @@ -345,7 +368,10 @@ TOML_NAMESPACE_START /// \tparam ElemTypes One of the TOML node or value types (or a type promotable to one). /// \param val The node or value used to initialize element 0. /// \param vals The nodes or values used to initialize elements 1...N. - template + template 0_sz) + || !std::is_same_v, array> + >> TOML_NODISCARD_CTOR explicit array(ElemType&& val, ElemTypes&&... vals) { @@ -360,11 +386,6 @@ TOML_NAMESPACE_START } } - /// \brief Move-assignment operator. - array& operator= (array&& rhs) noexcept; - - array(const array&) = delete; - array& operator= (const array&) = delete; /// \brief Always returns node_type::array for array nodes. [[nodiscard]] node_type type() const noexcept override; diff --git a/include/toml++/toml_array.hpp b/include/toml++/toml_array.hpp index 0eaffaf..2787336 100644 --- a/include/toml++/toml_array.hpp +++ b/include/toml++/toml_array.hpp @@ -19,6 +19,49 @@ TOML_DISABLE_PADDING_WARNINGS TOML_NAMESPACE_START { + TOML_EXTERNAL_LINKAGE + array::array() noexcept = default; + + TOML_EXTERNAL_LINKAGE + array::array(const array& other) noexcept + : node{ other } + { + elements.reserve(other.elements.size()); + for (const auto& elem : other) + elements.emplace_back(impl::make_node(elem)); + } + + TOML_EXTERNAL_LINKAGE + array::array(array&& other) noexcept + : node{ std::move(other) }, + elements{ std::move(other.elements) } + {} + + TOML_EXTERNAL_LINKAGE + array& array::operator= (const array& rhs) noexcept + { + if (&rhs != this) + { + node::operator=(rhs); + elements.clear(); + elements.reserve(rhs.elements.size()); + for (const auto& elem : rhs) + elements.emplace_back(impl::make_node(elem)); + } + return *this; + } + + TOML_EXTERNAL_LINKAGE + array& array::operator= (array&& rhs) noexcept + { + if (&rhs != this) + { + node::operator=(std::move(rhs)); + elements = std::move(rhs.elements); + } + return *this; + } + TOML_EXTERNAL_LINKAGE void array::preinsertion_resize(size_t idx, size_t count) noexcept { @@ -35,23 +78,6 @@ TOML_NAMESPACE_START } } - TOML_EXTERNAL_LINKAGE - array::array() noexcept = default; - - TOML_EXTERNAL_LINKAGE - array::array(array&& other) noexcept - : node{ std::move(other) }, - elements{ std::move(other.elements) } - {} - - TOML_EXTERNAL_LINKAGE - array& array::operator= (array&& rhs) noexcept - { - node::operator=(std::move(rhs)); - elements = std::move(rhs.elements); - return *this; - } - #define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr) TOML_MEMBER_ATTR(const) node_type array::type() const noexcept { return node_type::array; } diff --git a/include/toml++/toml_node.h b/include/toml++/toml_node.h index 252cb2b..b0ef8d9 100644 --- a/include/toml++/toml_node.h +++ b/include/toml++/toml_node.h @@ -75,7 +75,10 @@ TOML_NAMESPACE_START protected: + node() noexcept = default; + node(const node&) noexcept = default; node(node&& other) noexcept; + node& operator= (const node&) noexcept = default; node& operator= (node&& rhs) noexcept; template @@ -105,10 +108,6 @@ TOML_NAMESPACE_START template using ref_cast_type = decltype(std::declval().template ref_cast()); - node() noexcept = default; - node(const node&) = delete; - node& operator= (const node&) = delete; - public: virtual ~node() noexcept = default; diff --git a/include/toml++/toml_table.h b/include/toml++/toml_table.h index 12868d6..4c89c78 100644 --- a/include/toml++/toml_table.h +++ b/include/toml++/toml_table.h @@ -229,6 +229,20 @@ TOML_NAMESPACE_START TOML_NODISCARD_CTOR table() noexcept; + /// \brief Copy constructor. + TOML_NODISCARD_CTOR + table(const table&) noexcept; + + /// \brief Move constructor. + TOML_NODISCARD_CTOR + table(table&& other) noexcept; + + /// \brief Copy-assignment operator. + table& operator= (const table&) noexcept; + + /// \brief Move-assignment operator. + table& operator= (table&& rhs) noexcept; + /// \brief Constructs a table with one or more initial key-value pairs. /// /// \detail \cpp @@ -264,15 +278,6 @@ TOML_NAMESPACE_START : table{ arr, N } {} - /// \brief Move constructor. - TOML_NODISCARD_CTOR - table(table&& other) noexcept; - - /// \brief Move-assignment operator. - table& operator= (table&& rhs) noexcept; - - table(const table&) = delete; - table& operator= (const table&) = delete; /// \brief Always returns `node_type::table` for table nodes. [[nodiscard]] node_type type() const noexcept override; diff --git a/include/toml++/toml_table.hpp b/include/toml++/toml_table.hpp index 06452c8..82b7b82 100644 --- a/include/toml++/toml_table.hpp +++ b/include/toml++/toml_table.hpp @@ -21,19 +21,16 @@ TOML_DISABLE_PADDING_WARNINGS TOML_NAMESPACE_START { TOML_EXTERNAL_LINKAGE - table::table(impl::table_init_pair* pairs, size_t count) noexcept - { - for (size_t i = 0; i < count; i++) - { - map.insert_or_assign( - std::move(pairs[i].key), - std::move(pairs[i].value) - ); - } - } + table::table() noexcept {} TOML_EXTERNAL_LINKAGE - table::table() noexcept {} + table::table(const table& other) noexcept + : node{ std::move(other) }, + inline_{ other.inline_ } + { + for (auto&& [k, v] : other) + map.emplace_hint(map.end(), k, impl::make_node(v)); + } TOML_EXTERNAL_LINKAGE table::table(table&& other) noexcept @@ -43,14 +40,43 @@ TOML_NAMESPACE_START {} TOML_EXTERNAL_LINKAGE - table& table::operator = (table&& rhs) noexcept + table& table::operator= (const table& rhs) noexcept { - node::operator=(std::move(rhs)); - map = std::move(rhs.map); - inline_ = rhs.inline_; + if (&rhs != this) + { + node::operator=(rhs); + map.clear(); + for (auto&& [k, v] : rhs) + map.emplace_hint(map.end(), k, impl::make_node(v)); + inline_ = rhs.inline_; + } return *this; } + TOML_EXTERNAL_LINKAGE + table& table::operator= (table&& rhs) noexcept + { + if (&rhs != this) + { + node::operator=(std::move(rhs)); + map = std::move(rhs.map); + inline_ = rhs.inline_; + } + return *this; + } + + TOML_EXTERNAL_LINKAGE + table::table(impl::table_init_pair* pairs, size_t count) noexcept + { + for (size_t i = 0; i < count; i++) + { + map.insert_or_assign( + std::move(pairs[i].key), + std::move(pairs[i].value) + ); + } + } + #define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr) TOML_MEMBER_ATTR(const) node_type table::type() const noexcept { return node_type::table; } diff --git a/include/toml++/toml_value.h b/include/toml++/toml_value.h index b9f0930..3452eaa 100644 --- a/include/toml++/toml_value.h +++ b/include/toml++/toml_value.h @@ -173,6 +173,13 @@ TOML_NAMESPACE_START : val_(impl::native_value_maker...>::make(std::forward(args)...)) {} + /// \brief Copy constructor. + TOML_NODISCARD_CTOR + value(const value& other) noexcept + : node{ other }, + val_{ other.val_ } + {} + /// \brief Move constructor. TOML_NODISCARD_CTOR value(value&& other) noexcept @@ -180,16 +187,24 @@ TOML_NAMESPACE_START val_{ std::move(other.val_) } {} - /// \brief Move-assignment operator. - value& operator= (value&& rhs) noexcept + /// \brief Copy-assignment operator. + value& operator= (const value& rhs) noexcept { - node::operator=(std::move(rhs)); - val_ = std::move(rhs.val_); + node::operator=(rhs); + val_ = rhs.val_; return *this; } - value(const value&) = delete; - value& operator= (const value&) = delete; + /// \brief Move-assignment operator. + value& operator= (value&& rhs) noexcept + { + if (&rhs != this) + { + node::operator=(std::move(rhs)); + val_ = std::move(rhs.val_); + } + return *this; + } /// \brief Returns the value's node type identifier. /// diff --git a/tests/manipulating_arrays.cpp b/tests/manipulating_arrays.cpp index 2312484..a4eb11d 100644 --- a/tests/manipulating_arrays.cpp +++ b/tests/manipulating_arrays.cpp @@ -14,12 +14,7 @@ TEST_CASE("arrays - moving") R"(test = [ "foo" ])"sv, [&](table&& tbl) { - CHECK(tbl.source().begin == source_position{ 1, 1 }); - CHECK(tbl.source().end == source_position{ 1, 17 }); - CHECK(tbl.source().path); - CHECK(*tbl.source().path == filename); - CHECK(tbl.size() == 1_sz); - + // sanity-check initial state of a freshly-parsed array auto arr1 = tbl["test"].as(); REQUIRE(arr1); CHECK(arr1->size() == 1_sz); @@ -30,12 +25,14 @@ TEST_CASE("arrays - moving") REQUIRE(arr1->get_as(0_sz)); CHECK(*arr1->get_as(0_sz) == "foo"sv); + // sanity-check initial state of default-constructed array array arr2; CHECK(arr2.source().begin == source_position{}); CHECK(arr2.source().end == source_position{}); CHECK(!arr2.source().path); CHECK(arr2.size() == 0_sz); + // check the results of move-assignment arr2 = std::move(*arr1); CHECK(arr2.source().begin == source_position{ 1, 8 }); CHECK(arr2.source().end == source_position{ 1, 17 }); @@ -45,14 +42,84 @@ TEST_CASE("arrays - moving") REQUIRE(arr2.get_as(0_sz)); CHECK(*arr2.get_as(0_sz) == "foo"sv); + // check that moved-from array is now the same as default-constructed CHECK(arr1->source().begin == source_position{}); CHECK(arr1->source().end == source_position{}); CHECK(!arr1->source().path); CHECK(arr1->size() == 0_sz); + + // check the results of move-construction + array arr3{ std::move(arr2) }; + CHECK(arr3.source().begin == source_position{ 1, 8 }); + CHECK(arr3.source().end == source_position{ 1, 17 }); + CHECK(arr3.source().path); + CHECK(*arr3.source().path == filename); + CHECK(arr3.size() == 1_sz); + REQUIRE(arr3.get_as(0_sz)); + CHECK(*arr3.get_as(0_sz) == "foo"sv); + + // check that moved-from array is now the same as default-constructed + CHECK(arr2.source().begin == source_position{}); + CHECK(arr2.source().end == source_position{}); + CHECK(!arr2.source().path); + CHECK(arr2.size() == 0_sz); }, filename ); +} +TEST_CASE("arrays - copying") +{ + static constexpr auto filename = "foo.toml"sv; + + parsing_should_succeed( + FILE_LINE_ARGS, + R"(test = [ "foo" ])"sv, + [&](table&& tbl) + { + // sanity-check initial state of a freshly-parsed array + auto arr1 = tbl["test"].as(); + REQUIRE(arr1); + CHECK(arr1->size() == 1_sz); + CHECK(arr1->source().begin == source_position{ 1, 8 }); + CHECK(arr1->source().end == source_position{ 1, 17 }); + CHECK(arr1->source().path); + CHECK(*arr1->source().path == filename); + REQUIRE(arr1->get_as(0_sz)); + CHECK(*arr1->get_as(0_sz) == "foo"sv); + + // sanity-check initial state of default-constructed array + array arr2; + CHECK(arr2.source().begin == source_position{}); + CHECK(arr2.source().end == source_position{}); + CHECK(!arr2.source().path); + CHECK(arr2.size() == 0_sz); + + // check the results of copy-assignment + arr2 = *arr1; + CHECK(arr2.source().begin == source_position{ 1, 8 }); + CHECK(arr2.source().end == source_position{ 1, 17 }); + CHECK(arr2.source().path); + CHECK(*arr2.source().path == filename); + CHECK(arr2.size() == 1_sz); + REQUIRE(arr2.get_as(0_sz)); + CHECK(*arr2.get_as(0_sz) == "foo"sv); + CHECK(arr2 == *arr1); + + // check the results of copy-construction + array arr3{ arr2 }; + CHECK(arr3.source().begin == source_position{ 1, 8 }); + CHECK(arr3.source().end == source_position{ 1, 17 }); + CHECK(arr3.source().path); + CHECK(*arr3.source().path == filename); + CHECK(arr3.size() == 1_sz); + REQUIRE(arr3.get_as(0_sz)); + CHECK(*arr3.get_as(0_sz) == "foo"sv); + CHECK(arr3 == *arr1); + CHECK(arr3 == arr2); + }, + filename + ); } TEST_CASE("arrays - construction") diff --git a/tests/manipulating_tables.cpp b/tests/manipulating_tables.cpp index a791a61..6d855e1 100644 --- a/tests/manipulating_tables.cpp +++ b/tests/manipulating_tables.cpp @@ -14,19 +14,22 @@ TEST_CASE("tables - moving") R"(test = { val1 = "foo" })"sv, [&](table&& tbl) { - CHECK(tbl.source().begin == source_position{ 1, 1 }); - CHECK(tbl.source().end == source_position{ 1, 24 }); - CHECK(tbl.source().path); - CHECK(*tbl.source().path == filename); - CHECK(tbl.size() == 1_sz); - + // sanity-check initial state of a freshly-parsed table REQUIRE(tbl["test"].as()); CHECK(tbl["test"].as
()->size() == 1_sz); CHECK(tbl["test"].as
()->source().begin == source_position{ 1, 8 }); CHECK(tbl["test"].as
()->source().end == source_position{ 1, 24 }); CHECK(tbl["test"]["val1"] == "foo"); - table tbl2 = std::move(tbl); + // sanity-check initial state of default-constructed table + table tbl2; + CHECK(tbl2.source().begin == source_position{}); + CHECK(tbl2.source().end == source_position{}); + CHECK(!tbl2.source().path); + CHECK(tbl2.size() == 0_sz); + + // check the results of move-assignment + tbl2 = std::move(tbl); CHECK(tbl2.source().begin == source_position{ 1, 1 }); CHECK(tbl2.source().end == source_position{ 1, 24 }); CHECK(tbl2.source().path); @@ -36,11 +39,82 @@ TEST_CASE("tables - moving") CHECK(tbl2["test"].as
()->size() == 1_sz); CHECK(tbl2["test"]["val1"] == "foo"sv); + // check that moved-from table is now the same as default-constructed CHECK(tbl.source().begin == source_position{}); CHECK(tbl.source().end == source_position{}); CHECK(!tbl.source().path); CHECK(tbl.size() == 0_sz); CHECK(!tbl["test"].as
()); + + // check the results of move-construction + table tbl3{ std::move(tbl2) }; + CHECK(tbl3.source().begin == source_position{ 1, 1 }); + CHECK(tbl3.source().end == source_position{ 1, 24 }); + CHECK(tbl3.source().path); + CHECK(*tbl3.source().path == filename); + CHECK(tbl3.size() == 1_sz); + REQUIRE(tbl3["test"].as
()); + CHECK(tbl3["test"].as
()->size() == 1_sz); + CHECK(tbl3["test"]["val1"] == "foo"sv); + + // check that moved-from table is now the same as default-constructed + CHECK(tbl2.source().begin == source_position{}); + CHECK(tbl2.source().end == source_position{}); + CHECK(!tbl2.source().path); + CHECK(tbl2.size() == 0_sz); + CHECK(!tbl2["test"].as
()); + }, + filename + ); +} + +TEST_CASE("tables - copying") +{ + static constexpr auto filename = "foo.toml"sv; + + parsing_should_succeed( + FILE_LINE_ARGS, + R"(test = { val1 = "foo" })"sv, + [&](table&& tbl) + { + // sanity-check initial state of a freshly-parsed table + REQUIRE(tbl["test"].as
()); + CHECK(tbl["test"].as
()->size() == 1_sz); + CHECK(tbl["test"].as
()->source().begin == source_position{ 1, 8 }); + CHECK(tbl["test"].as
()->source().end == source_position{ 1, 24 }); + CHECK(tbl["test"]["val1"] == "foo"); + + // sanity-check initial state of default-constructed table + table tbl2; + CHECK(tbl2.source().begin == source_position{}); + CHECK(tbl2.source().end == source_position{}); + CHECK(!tbl2.source().path); + CHECK(tbl2.size() == 0_sz); + + // check the results of copy-assignment + tbl2 = tbl; + CHECK(tbl2.source().begin == source_position{ 1, 1 }); + CHECK(tbl2.source().end == source_position{ 1, 24 }); + CHECK(tbl2.source().path); + CHECK(*tbl2.source().path == filename); + CHECK(tbl2.size() == 1_sz); + REQUIRE(tbl2["test"].as
()); + CHECK(tbl2["test"].as
()->size() == 1_sz); + CHECK(tbl2["test"]["val1"] == "foo"sv); + CHECK(tbl2 == tbl); + + // check the results of copy-construction + table tbl3{ tbl2 }; + CHECK(tbl3.source().begin == source_position{ 1, 1 }); + CHECK(tbl3.source().end == source_position{ 1, 24 }); + CHECK(tbl3.source().path); + CHECK(*tbl3.source().path == filename); + CHECK(tbl3.size() == 1_sz); + REQUIRE(tbl3["test"].as
()); + CHECK(tbl3["test"].as
()->size() == 1_sz); + CHECK(tbl3["test"]["val1"] == "foo"sv); + CHECK(tbl3 == tbl2); + CHECK(tbl3 == tbl); }, filename ); diff --git a/tests/manipulating_values.cpp b/tests/manipulating_values.cpp index 1a37014..9a38969 100644 --- a/tests/manipulating_values.cpp +++ b/tests/manipulating_values.cpp @@ -75,11 +75,11 @@ TEST_CASE("values - construction") CHECK_VALUE_INIT2(one, int64_t, 1u); #if TOML_WINDOWS_COMPAT - - CHECK_VALUE_INIT2(L"kek", std::string, "kek"sv); - CHECK_VALUE_INIT2(L"kek"s, std::string, "kek"sv); - CHECK_VALUE_INIT2(L"kek"sv, std::string, "kek"sv); - CHECK_VALUE_INIT2(L"kek"sv.data(), std::string, "kek"sv); + + CHECK_VALUE_INIT2(L"kek", std::string, "kek"sv); + CHECK_VALUE_INIT2(L"kek"s, std::string, "kek"sv); + CHECK_VALUE_INIT2(L"kek"sv, std::string, "kek"sv); + CHECK_VALUE_INIT2(L"kek"sv.data(), std::string, "kek"sv); #endif // TOML_WINDOWS_COMPAT diff --git a/toml.hpp b/toml.hpp index 2c2afa7..def0c7a 100644 --- a/toml.hpp +++ b/toml.hpp @@ -2087,7 +2087,10 @@ TOML_NAMESPACE_START protected: + node() noexcept = default; + node(const node&) noexcept = default; node(node&& other) noexcept; + node& operator= (const node&) noexcept = default; node& operator= (node&& rhs) noexcept; template @@ -2117,10 +2120,6 @@ TOML_NAMESPACE_START template using ref_cast_type = decltype(std::declval().template ref_cast()); - node() noexcept = default; - node(const node&) = delete; - node& operator= (const node&) = delete; - public: virtual ~node() noexcept = default; @@ -2618,21 +2617,34 @@ TOML_NAMESPACE_START : val_(impl::native_value_maker...>::make(std::forward(args)...)) {} + TOML_NODISCARD_CTOR + value(const value& other) noexcept + : node{ other }, + val_{ other.val_ } + {} + TOML_NODISCARD_CTOR value(value&& other) noexcept : node{ std::move(other) }, val_{ std::move(other.val_) } {} - value& operator= (value&& rhs) noexcept + value& operator= (const value& rhs) noexcept { - node::operator=(std::move(rhs)); - val_ = std::move(rhs.val_); + node::operator=(rhs); + val_ = rhs.val_; return *this; } - value(const value&) = delete; - value& operator= (const value&) = delete; + value& operator= (value&& rhs) noexcept + { + if (&rhs != this) + { + node::operator=(std::move(rhs)); + val_ = std::move(rhs.val_); + } + return *this; + } [[nodiscard]] node_type type() const noexcept override { return impl::node_type_of; } [[nodiscard]] bool is_table() const noexcept override { return false; } @@ -3384,16 +3396,13 @@ TOML_IMPL_NAMESPACE_START template [[nodiscard]] TOML_ATTR(returns_nonnull) - TOML_ALWAYS_INLINE - auto* make_node(T&& val) noexcept + auto* make_node_specialized(T&& val) noexcept { using type = unwrap_node>; + static_assert(!std::is_same_v); + if constexpr (is_one_of) { - static_assert( - std::is_rvalue_reference_v, - "Tables and arrays may only be moved (not copied)." - ); return new type{ std::forward(val) }; } else @@ -3423,7 +3432,23 @@ TOML_IMPL_NAMESPACE_START template [[nodiscard]] TOML_ATTR(returns_nonnull) - TOML_ALWAYS_INLINE + auto* make_node(T&& val) noexcept + { + using type = unwrap_node>; + if constexpr (std::is_same_v) + { + return std::forward(val).visit([](auto&& concrete) noexcept + { + return static_cast(make_node_specialized(std::forward(concrete))); + }); + } + else + return make_node_specialized(std::forward(val)); + } + + template + [[nodiscard]] + TOML_ATTR(returns_nonnull) auto* make_node(inserter&& val) noexcept { return make_node(std::move(val.value)); @@ -3459,9 +3484,17 @@ TOML_NAMESPACE_START array() noexcept; TOML_NODISCARD_CTOR - array(array&& other) noexcept; + array(const array&) noexcept; - template + TOML_NODISCARD_CTOR + array(array&& other) noexcept; + array& operator= (const array&) noexcept; + array& operator= (array&& rhs) noexcept; + + template 0_sz) + || !std::is_same_v, array> + >> TOML_NODISCARD_CTOR explicit array(ElemType&& val, ElemTypes&&... vals) { @@ -3476,11 +3509,6 @@ TOML_NAMESPACE_START } } - array& operator= (array&& rhs) noexcept; - - array(const array&) = delete; - array& operator= (const array&) = delete; - [[nodiscard]] node_type type() const noexcept override; [[nodiscard]] bool is_table() const noexcept override; [[nodiscard]] bool is_array() const noexcept override; @@ -3950,19 +3978,20 @@ TOML_NAMESPACE_START TOML_NODISCARD_CTOR table() noexcept; + TOML_NODISCARD_CTOR + table(const table&) noexcept; + + TOML_NODISCARD_CTOR + table(table&& other) noexcept; + table& operator= (const table&) noexcept; + table& operator= (table&& rhs) noexcept; + template TOML_NODISCARD_CTOR explicit table(impl::table_init_pair(&& arr)[N]) noexcept : table{ arr, N } {} - TOML_NODISCARD_CTOR - table(table&& other) noexcept; - table& operator= (table&& rhs) noexcept; - - table(const table&) = delete; - table& operator= (const table&) = delete; - [[nodiscard]] node_type type() const noexcept override; [[nodiscard]] bool is_table() const noexcept override; [[nodiscard]] bool is_array() const noexcept override; @@ -7294,6 +7323,49 @@ TOML_DISABLE_PADDING_WARNINGS TOML_NAMESPACE_START { + TOML_EXTERNAL_LINKAGE + array::array() noexcept = default; + + TOML_EXTERNAL_LINKAGE + array::array(const array& other) noexcept + : node{ other } + { + elements.reserve(other.elements.size()); + for (const auto& elem : other) + elements.emplace_back(impl::make_node(elem)); + } + + TOML_EXTERNAL_LINKAGE + array::array(array&& other) noexcept + : node{ std::move(other) }, + elements{ std::move(other.elements) } + {} + + TOML_EXTERNAL_LINKAGE + array& array::operator= (const array& rhs) noexcept + { + if (&rhs != this) + { + node::operator=(rhs); + elements.clear(); + elements.reserve(rhs.elements.size()); + for (const auto& elem : rhs) + elements.emplace_back(impl::make_node(elem)); + } + return *this; + } + + TOML_EXTERNAL_LINKAGE + array& array::operator= (array&& rhs) noexcept + { + if (&rhs != this) + { + node::operator=(std::move(rhs)); + elements = std::move(rhs.elements); + } + return *this; + } + TOML_EXTERNAL_LINKAGE void array::preinsertion_resize(size_t idx, size_t count) noexcept { @@ -7310,23 +7382,6 @@ TOML_NAMESPACE_START } } - TOML_EXTERNAL_LINKAGE - array::array() noexcept = default; - - TOML_EXTERNAL_LINKAGE - array::array(array&& other) noexcept - : node{ std::move(other) }, - elements{ std::move(other.elements) } - {} - - TOML_EXTERNAL_LINKAGE - array& array::operator= (array&& rhs) noexcept - { - node::operator=(std::move(rhs)); - elements = std::move(rhs.elements); - return *this; - } - #define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr) TOML_MEMBER_ATTR(const) node_type array::type() const noexcept { return node_type::array; } @@ -7550,19 +7605,16 @@ TOML_DISABLE_PADDING_WARNINGS TOML_NAMESPACE_START { TOML_EXTERNAL_LINKAGE - table::table(impl::table_init_pair* pairs, size_t count) noexcept - { - for (size_t i = 0; i < count; i++) - { - map.insert_or_assign( - std::move(pairs[i].key), - std::move(pairs[i].value) - ); - } - } + table::table() noexcept {} TOML_EXTERNAL_LINKAGE - table::table() noexcept {} + table::table(const table& other) noexcept + : node{ std::move(other) }, + inline_{ other.inline_ } + { + for (auto&& [k, v] : other) + map.emplace_hint(map.end(), k, impl::make_node(v)); + } TOML_EXTERNAL_LINKAGE table::table(table&& other) noexcept @@ -7572,14 +7624,43 @@ TOML_NAMESPACE_START {} TOML_EXTERNAL_LINKAGE - table& table::operator = (table&& rhs) noexcept + table& table::operator= (const table& rhs) noexcept { - node::operator=(std::move(rhs)); - map = std::move(rhs.map); - inline_ = rhs.inline_; + if (&rhs != this) + { + node::operator=(rhs); + map.clear(); + for (auto&& [k, v] : rhs) + map.emplace_hint(map.end(), k, impl::make_node(v)); + inline_ = rhs.inline_; + } return *this; } + TOML_EXTERNAL_LINKAGE + table& table::operator= (table&& rhs) noexcept + { + if (&rhs != this) + { + node::operator=(std::move(rhs)); + map = std::move(rhs.map); + inline_ = rhs.inline_; + } + return *this; + } + + TOML_EXTERNAL_LINKAGE + table::table(impl::table_init_pair* pairs, size_t count) noexcept + { + for (size_t i = 0; i < count; i++) + { + map.insert_or_assign( + std::move(pairs[i].key), + std::move(pairs[i].value) + ); + } + } + #define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr) TOML_MEMBER_ATTR(const) node_type table::type() const noexcept { return node_type::table; } diff --git a/vs/toml++.natvis b/vs/toml++.natvis index 7017091..47a6a47 100644 --- a/vs/toml++.natvis +++ b/vs/toml++.natvis @@ -95,12 +95,12 @@ - {values} + {map} - values._Mypair._Myval2._Myval2._Mysize - values._Mypair._Myval2._Myval2._Myhead->_Parent + map._Mypair._Myval2._Myval2._Mysize + map._Mypair._Myval2._Myval2._Myhead->_Parent _Left _Right *_Myval.second @@ -109,12 +109,12 @@ - {values} + {elements} - values._Mypair._Myval2._Mylast - values._Mypair._Myval2._Myfirst - *values._Mypair._Myval2._Myfirst[$i] + elements._Mypair._Myval2._Mylast - elements._Mypair._Myval2._Myfirst + *elements._Mypair._Myval2._Myfirst[$i]