diff --git a/docs/Doxyfile b/docs/Doxyfile index efc5e46..5c64f60 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -350,7 +350,6 @@ PREDEFINED = \ "TOML_TRIVIAL_ABI=" \ "TOML_EMPTY_BASES=" \ "TOML_INTERFACE" \ - "TOML_SIMPLE_STATIC_ASSERT_MESSAGES=1" \ "TOML_INTERNAL_LINKAGE=static" EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = NO diff --git a/docs/tomlplusplus.css b/docs/tomlplusplus.css index a423855..6d2979d 100644 --- a/docs/tomlplusplus.css +++ b/docs/tomlplusplus.css @@ -47,7 +47,7 @@ article div > section > section pre, code, .tpp-enable-if > a { - font-family: 'Consolas', 'Source Code Pro', monospace, monospace, monospace; + font-family: 'Consolas', 'Source Code Pro', monospace; } a.tpp-external @@ -142,6 +142,7 @@ pre.m-code + pre.m-console span .m-doc-details div table.m-table.m-fullwidth.m-flat tbody tr td strong em { color: #a5c9ea; + font-style: normal; } /* comments */ @@ -316,9 +317,10 @@ pre > p.godbolt { float: right; } -@media only screen and ((max-width: 575px) or ((hover: none) and (pointer: coarse))) +@media only screen and ((max-width: 575px) or (hover: none) or (pointer: coarse) or (pointer: none)) { - .godbolt { + .godbolt + { display: none; } } diff --git a/examples/toml_generator.cpp b/examples/toml_generator.cpp index 847d48d..d74b840 100644 --- a/examples/toml_generator.cpp +++ b/examples/toml_generator.cpp @@ -129,7 +129,10 @@ int main(int argc, char** argv) toml::node* new_node{}; if (auto arr = tree.back()->as_array()) - new_node = &arr->push_back(std::forward(obj)); + { + arr->push_back(std::forward(obj)); + new_node = &arr->back(); + } else new_node = &(*tree.back()->ref().insert_or_assign( rand_string(rand(1u, 4u), '-'), diff --git a/include/toml++/toml_array.h b/include/toml++/toml_array.h index a497c3d..4497f56 100644 --- a/include/toml++/toml_array.h +++ b/include/toml++/toml_array.h @@ -15,7 +15,7 @@ TOML_IMPL_NAMESPACE_START class TOML_TRIVIAL_ABI array_iterator final { private: - friend class ::toml::array; + friend class TOML_NAMESPACE::array; using raw_mutable_iterator = std::vector>::iterator; using raw_const_iterator = std::vector>::const_iterator; @@ -180,6 +180,7 @@ TOML_IMPL_NAMESPACE_START { using type = unwrap_node>; static_assert(!std::is_same_v); + static_assert(!is_node_view); if constexpr (is_one_of) { @@ -211,12 +212,17 @@ TOML_IMPL_NAMESPACE_START template [[nodiscard]] - TOML_ATTR(returns_nonnull) auto* make_node(T&& val) noexcept { using type = unwrap_node>; - if constexpr (std::is_same_v) + if constexpr (std::is_same_v || is_node_view) { + if constexpr (is_node_view) + { + if (!val) + return static_cast(nullptr); + } + return std::forward(val).visit([](auto&& concrete) noexcept { return static_cast(make_node_specialized(std::forward(concrete))); @@ -228,7 +234,6 @@ TOML_IMPL_NAMESPACE_START template [[nodiscard]] - TOML_ATTR(returns_nonnull) auto* make_node(inserter&& val) noexcept { return make_node(std::move(val.value)); @@ -304,6 +309,17 @@ TOML_NAMESPACE_START void preinsertion_resize(size_t idx, size_t count) noexcept; + template + void emplace_back_if_not_empty_view(T&& val) noexcept + { + if constexpr (impl::is_node_view) + { + if (!val) + return; + } + elements.emplace_back(impl::make_node(std::forward(val))); + } + public: using value_type = node; @@ -376,11 +392,11 @@ TOML_NAMESPACE_START explicit array(ElemType&& val, ElemTypes&&... vals) { elements.reserve(sizeof...(ElemTypes) + 1_sz); - elements.emplace_back(impl::make_node(std::forward(val))); + emplace_back_if_not_empty_view(std::forward(val)); if constexpr (sizeof...(ElemTypes) > 0) { ( - elements.emplace_back(impl::make_node(std::forward(vals))), + emplace_back_if_not_empty_view(std::forward(vals)), ... ); } @@ -529,14 +545,27 @@ TOML_NAMESPACE_START /// [ 1, 'two', 3, [ 4, 5 ] ] /// \eout /// - /// \tparam ElemType One of the TOML node or value types (or a type promotable to one). + /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type + /// (or a type promotable to one). /// \param pos The insertion position. /// \param val The node or value being inserted. /// - /// \returns An iterator to the newly-inserted element. + /// \returns Valid input:
+ /// An iterator to the newly-inserted element. + ///

+ /// `val` is an empty toml::node_view:
+ /// end() + /// + /// \attention The return value will always be `end()` if the input value was an empty toml::node_view, + /// because no insertion can take place. This is the only circumstance in which this can occur. template iterator insert(const_iterator pos, ElemType&& val) noexcept { + if constexpr (impl::is_node_view) + { + if (!val) + return end(); + } return { elements.emplace(pos.raw_, impl::make_node(std::forward(val))) }; } @@ -562,15 +591,31 @@ TOML_NAMESPACE_START /// ] /// \eout /// - /// \tparam ElemType One of the TOML node or value types (or a type promotable to one). + /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type + /// (or a type promotable to one). /// \param pos The insertion position. /// \param count The number of times the node or value should be inserted. /// \param val The node or value being inserted. /// - /// \returns An iterator to the first newly-inserted element (or a copy of `pos` if count was 0). + /// \returns Valid input:
+ /// An iterator to the newly-inserted element. + ///

+ /// `count == 0`:
+ /// A copy of pos + ///

+ /// `val` is an empty toml::node_view:
+ /// end() + /// + /// \attention The return value will always be `end()` if the input value was an empty toml::node_view, + /// because no insertion can take place. This is the only circumstance in which this can occur. template iterator insert(const_iterator pos, size_t count, ElemType&& val) noexcept { + if constexpr (impl::is_node_view) + { + if (!val) + return end(); + } switch (count) { case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) }; @@ -597,50 +642,70 @@ TOML_NAMESPACE_START /// \param first Iterator to the first node or value being inserted. /// \param last Iterator to the one-past-the-last node or value being inserted. /// - /// \returns An iterator to the first newly-inserted element (or a copy of `pos` if `first` >= `last`). + /// \returns Valid input:
+ /// An iterator to the first newly-inserted element. + ///

+ /// `first >= last`:
+ /// A copy of pos + ///

+ /// All objects in the range were empty toml::node_views:
+ /// A copy of pos template iterator insert(const_iterator pos, Iter first, Iter last) noexcept { - const auto count = std::distance(first, last); - if (count <= 0) + const auto distance = std::distance(first, last); + if (distance <= 0) return { elements.begin() + (pos.raw_ - elements.cbegin()) }; - else if (count == 1) - return insert(pos, *first); else { + auto count = distance; + using deref_type = decltype(*first); + if constexpr (impl::is_node_view) + { + for (auto it = first; it != last; it++) + if (!(*it)) + count--; + if (!count) + return { elements.begin() + (pos.raw_ - elements.cbegin()) }; + } const auto start_idx = static_cast(pos.raw_ - elements.cbegin()); preinsertion_resize(start_idx, static_cast(count)); size_t i = start_idx; for (auto it = first; it != last; it++) - elements[i++].reset(impl::make_node(*it)); + { + if constexpr (impl::is_node_view) + { + if (!(*it)) + continue; + } + if constexpr (std::is_rvalue_reference_v) + elements[i++].reset(impl::make_node(std::move(*it))); + else + elements[i++].reset(impl::make_node(*it)); + } return { elements.begin() + static_cast(start_idx) }; } } /// \brief Inserts a range of elements into the array at a specific position. /// - /// \tparam ElemType One of the TOML node or value types (or a type promotable to one). + /// \tparam ElemType toml::node_view, toml::table, toml::array, or a native TOML value type + /// (or a type promotable to one). /// \param pos The insertion position. /// \param ilist An initializer list containing the values to be inserted. /// - /// \returns An iterator to the first newly-inserted element (or a copy of `pos` if `ilist` was empty). + /// \returns Valid input:
+ /// An iterator to the first newly-inserted element. + ///

+ /// `ilist.size() == 0`:
+ /// A copy of pos + ///

+ /// All objects in the list were empty toml::node_views:
+ /// A copy of pos template iterator insert(const_iterator pos, std::initializer_list ilist) noexcept { - switch (ilist.size()) - { - case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) }; - case 1: return insert(pos, *ilist.begin()); - default: - { - const auto start_idx = static_cast(pos.raw_ - elements.cbegin()); - preinsertion_resize(start_idx, ilist.size()); - size_t i = start_idx; - for (auto& val : ilist) - elements[i++].reset(impl::make_node(val)); - return { elements.begin() + static_cast(start_idx) }; - } - } + return insert(pos, ilist.begin(), ilist.end()); } /// \brief Emplaces a new element at a specific position in the array. @@ -658,7 +723,7 @@ TOML_NAMESPACE_START /// [ 1, 'drill', 2 ] /// \eout /// - /// \tparam ElemType One of the TOML node or value types. + /// \tparam ElemType toml::table, toml::array, or any native TOML value type. /// \tparam Args Value constructor argument types. /// \param pos The insertion position. /// \param args Arguments to forward to the value's constructor. @@ -745,13 +810,19 @@ TOML_NAMESPACE_START /// [ 1, 2 ] /// \eout /// - /// \tparam ElemType One of the TOML node or value types (or a type promotable to one). + /// \tparam ElemType toml::node, toml::table, toml::array, or a native TOML value type + /// (or a type promotable to one). /// /// \param new_size The number of elements the array will have after resizing. /// \param default_init_val The node or value used to initialize new elements if the array needs to grow. template void resize(size_t new_size, ElemType&& default_init_val) noexcept { + static_assert( + !impl::is_node_view, + "The default element type argument to toml::array::resize may not be toml::node_view." + ); + if (!new_size) elements.clear(); else if (new_size < elements.size()) @@ -800,16 +871,15 @@ TOML_NAMESPACE_START /// [ 1, 2, 3, 4.0, [ 5, 'six' ] ] /// \eout /// - /// \tparam ElemType One of the TOML node or value types (or a type promotable to one). + /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type /// \param val The node or value being added. /// - /// \returns A reference to the newly-constructed element. + /// \attention No insertion takes place if the input value is an empty toml::node_view. + /// This is the only circumstance in which this can occur. template - decltype(auto) push_back(ElemType&& val) noexcept + void push_back(ElemType&& val) noexcept { - auto nde = impl::make_node(std::forward(val)); - elements.emplace_back(nde); - return *nde; + emplace_back_if_not_empty_view(std::forward(val)); } /// \brief Emplaces a new element at the end of the array. @@ -825,7 +895,7 @@ TOML_NAMESPACE_START /// [ 1, 2, [ 3, 'four' ] ] /// \eout /// - /// \tparam ElemType One of the TOML node or value types. + /// \tparam ElemType toml::table, toml::array, or a native TOML value type /// \tparam Args Value constructor argument types. /// \param args Arguments to forward to the value's constructor. /// @@ -895,7 +965,7 @@ TOML_NAMESPACE_START /// element [0] is an integer with value 42 /// \eout /// - /// \tparam ElemType The element's type. + /// \tparam ElemType toml::table, toml::array, or a native TOML value type /// \param index The element's index. /// /// \returns A pointer to the selected element if it existed and was of the specified type, or nullptr. @@ -910,7 +980,7 @@ TOML_NAMESPACE_START /// \brief Gets the element at a specific index if it is a particular type (const overload). /// - /// \tparam ElemType The element's type. + /// \tparam ElemType toml::table, toml::array, or a native TOML value type /// \param index The element's index. /// /// \returns A pointer to the selected element if it existed and was of the specified type, or nullptr. diff --git a/include/toml++/toml_common.h b/include/toml++/toml_common.h index 51a87d3..59e5d2f 100644 --- a/include/toml++/toml_common.h +++ b/include/toml++/toml_common.h @@ -549,6 +549,9 @@ TOML_IMPL_NAMESPACE_START template <> struct node_type_getter { static constexpr auto value = node_type::array; }; template inline constexpr node_type node_type_of = node_type_getter>>::value; + + template + inline constexpr bool is_node_view = is_one_of, node_view, node_view>; } TOML_IMPL_NAMESPACE_END diff --git a/include/toml++/toml_node.h b/include/toml++/toml_node.h index b0ef8d9..494e922 100644 --- a/include/toml++/toml_node.h +++ b/include/toml++/toml_node.h @@ -10,7 +10,7 @@ TOML_PUSH_WARNINGS TOML_DISABLE_PADDING_WARNINGS TOML_DISABLE_MISC_WARNINGS -#if TOML_SIMPLE_STATIC_ASSERT_MESSAGES +#if defined(doxygen) || TOML_SIMPLE_STATIC_ASSERT_MESSAGES #define TOML_SA_NEWLINE " " #define TOML_SA_LIST_SEP ", " diff --git a/include/toml++/toml_node_view.h b/include/toml++/toml_node_view.h index ea13747..18479bb 100644 --- a/include/toml++/toml_node_view.h +++ b/include/toml++/toml_node_view.h @@ -63,8 +63,8 @@ TOML_NAMESPACE_START using viewed_type = ViewedType; private: - friend class toml::table; - template friend class toml::node_view; + friend class TOML_NAMESPACE::table; + template friend class TOML_NAMESPACE::node_view; mutable viewed_type* node_ = nullptr; @@ -83,6 +83,19 @@ TOML_NAMESPACE_START TOML_NODISCARD_CTOR node_view() noexcept = default; + ///// \brief Copy constructor. + TOML_NODISCARD_CTOR + node_view(const node_view&) noexcept = default; + + ///// \brief Copy-assignment operator. + TOML_NODISCARD_CTOR + node_view& operator= (const node_view&) noexcept = default; + + ///// \brief Move constructor. + node_view(node_view&&) noexcept = default; + + node_view& operator= (node_view&&) noexcept = delete; + /// \brief Returns true if the view references a node. [[nodiscard]] explicit operator bool() const noexcept { return node_ != nullptr; } /// \brief Returns the node that's being referenced by the view. diff --git a/include/toml++/toml_table.h b/include/toml++/toml_table.h index 4c89c78..1e82167 100644 --- a/include/toml++/toml_table.h +++ b/include/toml++/toml_table.h @@ -25,7 +25,7 @@ TOML_IMPL_NAMESPACE_START class table_iterator final { private: - friend class ::toml::table; + friend class TOML_NAMESPACE::table; using proxy_type = table_proxy_pair; using raw_mutable_iterator = string_map>::iterator; @@ -278,7 +278,6 @@ TOML_NAMESPACE_START : table{ arr, N } {} - /// \brief Always returns `node_type::table` for table nodes. [[nodiscard]] node_type type() const noexcept override; /// \brief Always returns `true` for table nodes. @@ -453,13 +452,22 @@ TOML_NAMESPACE_START /// \eout /// /// \tparam KeyType std::string (or a type convertible to it). - /// \tparam ValueType One of the TOML ndoe or value types (or a type promotable to one). + /// \tparam ValueType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type + /// (or a type promotable to one). /// \param key The key at which to insert the new value. /// \param val The new value to insert. /// - /// \returns A std::pair containing: - /// - An iterator to the insertion position (or the position of the value that prevented insertion) - /// - A boolean indicating if the insertion was successful. + /// \returns Valid input:
+ ///
    + ///
  • An iterator to the insertion position (or the position of the value that prevented insertion) + ///
  • A boolean indicating if the insertion was successful. + ///
+ /// `val` is an empty toml::node_view:
+ /// `{ end(), false }` + /// + /// \attention The return value will always be `{ end(), false }` if the input value was an + /// empty toml::node_view, because no insertion can take place. This is the only circumstance + /// in which this can occur. template || impl::is_wide_string @@ -471,6 +479,12 @@ TOML_NAMESPACE_START "Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled." ); + if constexpr (impl::is_node_view) + { + if (!val) + return { end(), false }; + } + if constexpr (impl::is_wide_string) { #if TOML_WINDOWS_COMPAT @@ -485,9 +499,9 @@ TOML_NAMESPACE_START if (ipos == map.end() || ipos->first != key) { ipos = map.emplace_hint(ipos, std::forward(key), impl::make_node(std::forward(val))); - return { ipos, true }; + return { iterator{ ipos }, true }; } - return { ipos, false }; + return { iterator{ ipos }, false }; } } @@ -583,13 +597,22 @@ TOML_NAMESPACE_START /// \eout /// /// \tparam KeyType std::string (or a type convertible to it). - /// \tparam ValueType One of the TOML node or value types (or a type promotable to one). + /// \tparam ValueType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type + /// (or a type promotable to one). /// \param key The key at which to insert or assign the value. /// \param val The value to insert/assign. /// - /// \returns A std::pair containing: - /// - An iterator to the value's position - /// - A boolean containing `true` if the value was inserted, `false` if it was assigned. + /// \returns Valid input:
+ ///
    + ///
  • An iterator to the value's position + ///
  • `true` if the value was inserted, `false` if it was assigned. + ///
+ /// `val` is an empty toml::node_view:
+ /// `{ end(), false }` + /// + /// \attention The return value will always be `{ end(), false }` if the input value was + /// an empty toml::node_view, because no insertion or assignment can take place. + /// This is the only circumstance in which this can occur. template std::pair insert_or_assign(KeyType&& key, ValueType&& val) noexcept { @@ -598,6 +621,12 @@ TOML_NAMESPACE_START "Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled." ); + if constexpr (impl::is_node_view) + { + if (!val) + return { end(), false }; + } + if constexpr (impl::is_wide_string) { #if TOML_WINDOWS_COMPAT @@ -612,12 +641,12 @@ TOML_NAMESPACE_START if (ipos == map.end() || ipos->first != key) { ipos = map.emplace_hint(ipos, std::forward(key), impl::make_node(std::forward(val))); - return { ipos, true }; + return { iterator{ ipos }, true }; } else { (*ipos).second.reset(impl::make_node(std::forward(val))); - return { ipos, false }; + return { iterator{ ipos }, false }; } } } @@ -649,13 +678,13 @@ TOML_NAMESPACE_START /// { a = 1, b = 2, c = 3, d = "drill" } /// \eout /// - /// \tparam ValueType One of the TOML node or value types. + /// \tparam ValueType toml::table, toml::array, or any native TOML value type. /// \tparam KeyType std::string (or a type convertible to it). /// \tparam ValueArgs Value constructor argument types. /// \param key The key at which to emplace the new value. /// \param args Arguments to forward to the value's constructor. /// - /// \returns A std::pair containing: + /// \returns A std::pair containing:
/// - An iterator to the emplacement position (or the position of the value that prevented emplacement) /// - A boolean indicating if the emplacement was successful. /// @@ -694,9 +723,9 @@ TOML_NAMESPACE_START std::forward(key), new impl::wrap_node{ std::forward(args)... } ); - return { ipos, true }; + return { iterator{ ipos }, true }; } - return { ipos, false }; + return { iterator{ ipos }, false }; } } diff --git a/include/toml++/toml_table.hpp b/include/toml++/toml_table.hpp index 82b7b82..2a5db9e 100644 --- a/include/toml++/toml_table.hpp +++ b/include/toml++/toml_table.hpp @@ -70,6 +70,8 @@ TOML_NAMESPACE_START { for (size_t i = 0; i < count; i++) { + if (!pairs[i].value) // empty node_views + continue; map.insert_or_assign( std::move(pairs[i].key), std::move(pairs[i].value) diff --git a/python/generate_windows_test_targets.py b/python/generate_windows_test_targets.py index 3f48f18..f7bb7b2 100644 --- a/python/generate_windows_test_targets.py +++ b/python/generate_windows_test_targets.py @@ -120,6 +120,7 @@ def main(): + diff --git a/tests/manipulating_arrays.cpp b/tests/manipulating_arrays.cpp index a4eb11d..c1b8540 100644 --- a/tests/manipulating_arrays.cpp +++ b/tests/manipulating_arrays.cpp @@ -256,7 +256,8 @@ TEST_CASE("arrays - insertion and erasure") // push_back(ElemType&& val) noexcept { - decltype(auto) val = arr.push_back("test"sv); + arr.push_back("test"sv); + auto& val = *arr.back().as_string(); CHECK(arr.size() == 6_sz); REQUIRE(arr.get_as(5_sz)); CHECK(*arr.get_as(5_sz) == "test"sv); diff --git a/tests/meson.build b/tests/meson.build index 064598b..e6b22ff 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -21,6 +21,7 @@ test_sources = [ 'manipulating_values.cpp', 'unicode.cpp', 'unicode_generated.cpp', + 'user_feedback.cpp', 'windows_compat.cpp' ] @@ -300,12 +301,6 @@ foreach cpp20 : cpp20_modes name = name + '_tlopt' endif - if compiler_supports_float16 - if compiler.get_id() == 'gcc' - args += '-mfp16-format=ieee' - endif - endif - executables += [[ name, executable( diff --git a/tests/settings.h b/tests/settings.h index 4f3f1fe..52c7cc5 100644 --- a/tests/settings.h +++ b/tests/settings.h @@ -84,12 +84,12 @@ #ifndef SHOULD_HAVE_FLOAT16 #define SHOULD_HAVE_FLOAT16 0 #endif -#ifndef SHOULD_HAVE_INT128 - #define SHOULD_HAVE_INT128 0 -#endif #ifndef SHOULD_HAVE_FLOAT128 #define SHOULD_HAVE_FLOAT128 0 #endif +#ifndef SHOULD_HAVE_INT128 + #define SHOULD_HAVE_INT128 0 +#endif #ifndef SHOULD_HAVE_EXCEPTIONS #define SHOULD_HAVE_EXCEPTIONS 1 #endif diff --git a/tests/user_feedback.cpp b/tests/user_feedback.cpp new file mode 100644 index 0000000..140df11 --- /dev/null +++ b/tests/user_feedback.cpp @@ -0,0 +1,88 @@ +// This file is a part of toml++ and is subject to the the terms of the MIT license. +// Copyright (c) 2019-2020 Mark Gillard +// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + +#include "tests.h" + +// this file is about testing user misc. repros submitted via github issues, et cetera. + +TEST_CASE("feedback - github/issues/49") +{ + // see: https://github.com/marzer/tomlplusplus/issues/49#issuecomment-664428571 + { + toml::table t1; + t1.insert_or_assign("bar1", toml::array{ 1, 2, 3 }); + CHECK(t1 == toml::table{{ + { "bar1"sv, toml::array{ 1, 2, 3 } } + }}); + + t1.insert_or_assign("foo1", *t1.get("bar1")); + CHECK(t1 == toml::table{{ + { "bar1"sv, toml::array{ 1, 2, 3 } }, + { "foo1"sv, toml::array{ 1, 2, 3 } } + }}); + + //t1["foo1"] = t1["bar1"]; // does nothing, should this fail to compile? + // - yes - + + //*t1["foo1"].node() = *t1["bar1"].node(); // compile failure; copying node_view would be a bad thing + // - correct; copying toml::node directly like that is impossible b.c. it's an abstract base class- + + toml::array* array1 = t1["foo1"].node()->as_array(); + array1->push_back(4); + CHECK(t1 == toml::table{{ + { "bar1"sv, toml::array{ 1, 2, 3 } }, + { "foo1"sv, toml::array{ 1, 2, 3, 4 } } + }}); + + t1.insert_or_assign("foo3", t1["foo1"]); + CHECK(t1 == toml::table{{ + { "bar1"sv, toml::array{ 1, 2, 3 } }, + { "foo1"sv, toml::array{ 1, 2, 3, 4 } }, + { "foo3"sv, toml::array{ 1, 2, 3, 4 } } + }}); + + t1.insert_or_assign("foo2", *t1["foo1"].node()); + CHECK(t1 == toml::table{{ + { "bar1"sv, toml::array{ 1, 2, 3 } }, + { "foo1"sv, toml::array{ 1, 2, 3, 4 } }, + { "foo2"sv, toml::array{ 1, 2, 3, 4 } }, + { "foo3"sv, toml::array{ 1, 2, 3, 4 } } + }}); + + toml::array* array2 = t1["foo2"].node()->as_array(); + array2->push_back("wrench"); + CHECK(t1 == toml::table{{ + { "bar1"sv, toml::array{ 1, 2, 3 } }, + { "foo1"sv, toml::array{ 1, 2, 3, 4 } }, + { "foo2"sv, toml::array{ 1, 2, 3, 4, "wrench" } }, + { "foo3"sv, toml::array{ 1, 2, 3, 4 } } + }}); + + toml::table t2 = t1; + CHECK(t2 == t1); + CHECK(&t2 != &t1); + + //t2.emplace("bar", toml::array{6, 7}); // fails to compile? not sure what I did wrong + // - it should be this: - + t2.emplace("bar", 6, 7); + CHECK(t2 == toml::table{{ + { "bar"sv, toml::array{ 6, 7 } }, + { "bar1"sv, toml::array{ 1, 2, 3 } }, + { "foo1"sv, toml::array{ 1, 2, 3, 4 } }, + { "foo2"sv, toml::array{ 1, 2, 3, 4, "wrench" } }, + { "foo3"sv, toml::array{ 1, 2, 3, 4 } } + }}); + + t2.insert_or_assign("bar2", toml::array{ 6, 7 }); + CHECK(t2 == toml::table{{ + { "bar"sv, toml::array{ 6, 7 } }, + { "bar1"sv, toml::array{ 1, 2, 3 } }, + { "bar2"sv, toml::array{ 6, 7 } }, + { "foo1"sv, toml::array{ 1, 2, 3, 4 } }, + { "foo2"sv, toml::array{ 1, 2, 3, 4, "wrench" } }, + { "foo3"sv, toml::array{ 1, 2, 3, 4 } } + }}); + } +} diff --git a/toml.hpp b/toml.hpp index def0c7a..10b2018 100644 --- a/toml.hpp +++ b/toml.hpp @@ -1067,6 +1067,9 @@ TOML_IMPL_NAMESPACE_START template <> struct node_type_getter { static constexpr auto value = node_type::array; }; template inline constexpr node_type node_type_of = node_type_getter>>::value; + + template + inline constexpr bool is_node_view = is_one_of, node_view, node_view>; } TOML_IMPL_NAMESPACE_END @@ -2026,7 +2029,7 @@ TOML_PUSH_WARNINGS TOML_DISABLE_PADDING_WARNINGS TOML_DISABLE_MISC_WARNINGS -#if TOML_SIMPLE_STATIC_ASSERT_MESSAGES +#if defined(doxygen) || TOML_SIMPLE_STATIC_ASSERT_MESSAGES #define TOML_SA_NEWLINE " " #define TOML_SA_LIST_SEP ", " @@ -3235,7 +3238,7 @@ TOML_IMPL_NAMESPACE_START class TOML_TRIVIAL_ABI array_iterator final { private: - friend class ::toml::array; + friend class TOML_NAMESPACE::array; using raw_mutable_iterator = std::vector>::iterator; using raw_const_iterator = std::vector>::const_iterator; @@ -3400,6 +3403,7 @@ TOML_IMPL_NAMESPACE_START { using type = unwrap_node>; static_assert(!std::is_same_v); + static_assert(!is_node_view); if constexpr (is_one_of) { @@ -3431,12 +3435,17 @@ TOML_IMPL_NAMESPACE_START template [[nodiscard]] - TOML_ATTR(returns_nonnull) auto* make_node(T&& val) noexcept { using type = unwrap_node>; - if constexpr (std::is_same_v) + if constexpr (std::is_same_v || is_node_view) { + if constexpr (is_node_view) + { + if (!val) + return static_cast(nullptr); + } + return std::forward(val).visit([](auto&& concrete) noexcept { return static_cast(make_node_specialized(std::forward(concrete))); @@ -3448,7 +3457,6 @@ TOML_IMPL_NAMESPACE_START template [[nodiscard]] - TOML_ATTR(returns_nonnull) auto* make_node(inserter&& val) noexcept { return make_node(std::move(val.value)); @@ -3470,6 +3478,17 @@ TOML_NAMESPACE_START void preinsertion_resize(size_t idx, size_t count) noexcept; + template + void emplace_back_if_not_empty_view(T&& val) noexcept + { + if constexpr (impl::is_node_view) + { + if (!val) + return; + } + elements.emplace_back(impl::make_node(std::forward(val))); + } + public: using value_type = node; @@ -3499,11 +3518,11 @@ TOML_NAMESPACE_START explicit array(ElemType&& val, ElemTypes&&... vals) { elements.reserve(sizeof...(ElemTypes) + 1_sz); - elements.emplace_back(impl::make_node(std::forward(val))); + emplace_back_if_not_empty_view(std::forward(val)); if constexpr (sizeof...(ElemTypes) > 0) { ( - elements.emplace_back(impl::make_node(std::forward(vals))), + emplace_back_if_not_empty_view(std::forward(vals)), ... ); } @@ -3560,12 +3579,22 @@ TOML_NAMESPACE_START template iterator insert(const_iterator pos, ElemType&& val) noexcept { + if constexpr (impl::is_node_view) + { + if (!val) + return end(); + } return { elements.emplace(pos.raw_, impl::make_node(std::forward(val))) }; } template iterator insert(const_iterator pos, size_t count, ElemType&& val) noexcept { + if constexpr (impl::is_node_view) + { + if (!val) + return end(); + } switch (count) { case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) }; @@ -3587,18 +3616,36 @@ TOML_NAMESPACE_START template iterator insert(const_iterator pos, Iter first, Iter last) noexcept { - const auto count = std::distance(first, last); - if (count <= 0) + const auto distance = std::distance(first, last); + if (distance <= 0) return { elements.begin() + (pos.raw_ - elements.cbegin()) }; - else if (count == 1) - return insert(pos, *first); else { + auto count = distance; + using deref_type = decltype(*first); + if constexpr (impl::is_node_view) + { + for (auto it = first; it != last; it++) + if (!(*it)) + count--; + if (!count) + return { elements.begin() + (pos.raw_ - elements.cbegin()) }; + } const auto start_idx = static_cast(pos.raw_ - elements.cbegin()); preinsertion_resize(start_idx, static_cast(count)); size_t i = start_idx; for (auto it = first; it != last; it++) - elements[i++].reset(impl::make_node(*it)); + { + if constexpr (impl::is_node_view) + { + if (!(*it)) + continue; + } + if constexpr (std::is_rvalue_reference_v) + elements[i++].reset(impl::make_node(std::move(*it))); + else + elements[i++].reset(impl::make_node(*it)); + } return { elements.begin() + static_cast(start_idx) }; } } @@ -3606,20 +3653,7 @@ TOML_NAMESPACE_START template iterator insert(const_iterator pos, std::initializer_list ilist) noexcept { - switch (ilist.size()) - { - case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) }; - case 1: return insert(pos, *ilist.begin()); - default: - { - const auto start_idx = static_cast(pos.raw_ - elements.cbegin()); - preinsertion_resize(start_idx, ilist.size()); - size_t i = start_idx; - for (auto& val : ilist) - elements[i++].reset(impl::make_node(val)); - return { elements.begin() + static_cast(start_idx) }; - } - } + return insert(pos, ilist.begin(), ilist.end()); } template @@ -3641,6 +3675,11 @@ TOML_NAMESPACE_START template void resize(size_t new_size, ElemType&& default_init_val) noexcept { + static_assert( + !impl::is_node_view, + "The default element type argument to toml::array::resize may not be toml::node_view." + ); + if (!new_size) elements.clear(); else if (new_size < elements.size()) @@ -3652,11 +3691,9 @@ TOML_NAMESPACE_START void truncate(size_t new_size); template - decltype(auto) push_back(ElemType&& val) noexcept + void push_back(ElemType&& val) noexcept { - auto nde = impl::make_node(std::forward(val)); - elements.emplace_back(nde); - return *nde; + emplace_back_if_not_empty_view(std::forward(val)); } template @@ -3786,7 +3823,7 @@ TOML_IMPL_NAMESPACE_START class table_iterator final { private: - friend class ::toml::table; + friend class TOML_NAMESPACE::table; using proxy_type = table_proxy_pair; using raw_mutable_iterator = string_map>::iterator; @@ -4031,6 +4068,12 @@ TOML_NAMESPACE_START "Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled." ); + if constexpr (impl::is_node_view) + { + if (!val) + return { end(), false }; + } + if constexpr (impl::is_wide_string) { #if TOML_WINDOWS_COMPAT @@ -4045,9 +4088,9 @@ TOML_NAMESPACE_START if (ipos == map.end() || ipos->first != key) { ipos = map.emplace_hint(ipos, std::forward(key), impl::make_node(std::forward(val))); - return { ipos, true }; + return { iterator{ ipos }, true }; } - return { ipos, false }; + return { iterator{ ipos }, false }; } } @@ -4076,6 +4119,12 @@ TOML_NAMESPACE_START "Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled." ); + if constexpr (impl::is_node_view) + { + if (!val) + return { end(), false }; + } + if constexpr (impl::is_wide_string) { #if TOML_WINDOWS_COMPAT @@ -4090,12 +4139,12 @@ TOML_NAMESPACE_START if (ipos == map.end() || ipos->first != key) { ipos = map.emplace_hint(ipos, std::forward(key), impl::make_node(std::forward(val))); - return { ipos, true }; + return { iterator{ ipos }, true }; } else { (*ipos).second.reset(impl::make_node(std::forward(val))); - return { ipos, false }; + return { iterator{ ipos }, false }; } } } @@ -4134,9 +4183,9 @@ TOML_NAMESPACE_START std::forward(key), new impl::wrap_node{ std::forward(args)... } ); - return { ipos, true }; + return { iterator{ ipos }, true }; } - return { ipos, false }; + return { iterator{ ipos }, false }; } } @@ -4274,8 +4323,8 @@ TOML_NAMESPACE_START using viewed_type = ViewedType; private: - friend class toml::table; - template friend class toml::node_view; + friend class TOML_NAMESPACE::table; + template friend class TOML_NAMESPACE::node_view; mutable viewed_type* node_ = nullptr; @@ -4292,6 +4341,16 @@ TOML_NAMESPACE_START TOML_NODISCARD_CTOR node_view() noexcept = default; + + TOML_NODISCARD_CTOR + node_view(const node_view&) noexcept = default; + + TOML_NODISCARD_CTOR + node_view& operator= (const node_view&) noexcept = default; + + node_view(node_view&&) noexcept = default; + + node_view& operator= (node_view&&) noexcept = delete; [[nodiscard]] explicit operator bool() const noexcept { return node_ != nullptr; } [[nodiscard]] viewed_type* node() const noexcept { return node_; } @@ -7654,6 +7713,8 @@ TOML_NAMESPACE_START { for (size_t i = 0; i < count; i++) { + if (!pairs[i].value) // empty node_views + continue; map.insert_or_assign( std::move(pairs[i].key), std::move(pairs[i].value) diff --git a/vs/tests/test_debug_x64.vcxproj b/vs/tests/test_debug_x64.vcxproj index be5f003..e3bb3e5 100644 --- a/vs/tests/test_debug_x64.vcxproj +++ b/vs/tests/test_debug_x64.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x64_cpplatest.vcxproj b/vs/tests/test_debug_x64_cpplatest.vcxproj index 30f808a..f83a754 100644 --- a/vs/tests/test_debug_x64_cpplatest.vcxproj +++ b/vs/tests/test_debug_x64_cpplatest.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x64_cpplatest_noexcept.vcxproj b/vs/tests/test_debug_x64_cpplatest_noexcept.vcxproj index d730ff4..b42baff 100644 --- a/vs/tests/test_debug_x64_cpplatest_noexcept.vcxproj +++ b/vs/tests/test_debug_x64_cpplatest_noexcept.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x64_cpplatest_noexcept_unrel.vcxproj b/vs/tests/test_debug_x64_cpplatest_noexcept_unrel.vcxproj index 1407c25..7bd08f3 100644 --- a/vs/tests/test_debug_x64_cpplatest_noexcept_unrel.vcxproj +++ b/vs/tests/test_debug_x64_cpplatest_noexcept_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x64_cpplatest_unrel.vcxproj b/vs/tests/test_debug_x64_cpplatest_unrel.vcxproj index c58758a..0f90ce1 100644 --- a/vs/tests/test_debug_x64_cpplatest_unrel.vcxproj +++ b/vs/tests/test_debug_x64_cpplatest_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x64_noexcept.vcxproj b/vs/tests/test_debug_x64_noexcept.vcxproj index 9ade463..c63266b 100644 --- a/vs/tests/test_debug_x64_noexcept.vcxproj +++ b/vs/tests/test_debug_x64_noexcept.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x64_noexcept_unrel.vcxproj b/vs/tests/test_debug_x64_noexcept_unrel.vcxproj index 311a383..03277e7 100644 --- a/vs/tests/test_debug_x64_noexcept_unrel.vcxproj +++ b/vs/tests/test_debug_x64_noexcept_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x64_unrel.vcxproj b/vs/tests/test_debug_x64_unrel.vcxproj index 535597d..e040934 100644 --- a/vs/tests/test_debug_x64_unrel.vcxproj +++ b/vs/tests/test_debug_x64_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x86.vcxproj b/vs/tests/test_debug_x86.vcxproj index 68de412..751de34 100644 --- a/vs/tests/test_debug_x86.vcxproj +++ b/vs/tests/test_debug_x86.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x86_cpplatest.vcxproj b/vs/tests/test_debug_x86_cpplatest.vcxproj index c2cf2ec..53fb9f6 100644 --- a/vs/tests/test_debug_x86_cpplatest.vcxproj +++ b/vs/tests/test_debug_x86_cpplatest.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x86_cpplatest_noexcept.vcxproj b/vs/tests/test_debug_x86_cpplatest_noexcept.vcxproj index 77ce436..8c61a74 100644 --- a/vs/tests/test_debug_x86_cpplatest_noexcept.vcxproj +++ b/vs/tests/test_debug_x86_cpplatest_noexcept.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x86_cpplatest_noexcept_unrel.vcxproj b/vs/tests/test_debug_x86_cpplatest_noexcept_unrel.vcxproj index 6fe294c..5edbcb5 100644 --- a/vs/tests/test_debug_x86_cpplatest_noexcept_unrel.vcxproj +++ b/vs/tests/test_debug_x86_cpplatest_noexcept_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x86_cpplatest_unrel.vcxproj b/vs/tests/test_debug_x86_cpplatest_unrel.vcxproj index a4849ef..41dceb0 100644 --- a/vs/tests/test_debug_x86_cpplatest_unrel.vcxproj +++ b/vs/tests/test_debug_x86_cpplatest_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x86_noexcept.vcxproj b/vs/tests/test_debug_x86_noexcept.vcxproj index 287b785..fe3d371 100644 --- a/vs/tests/test_debug_x86_noexcept.vcxproj +++ b/vs/tests/test_debug_x86_noexcept.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x86_noexcept_unrel.vcxproj b/vs/tests/test_debug_x86_noexcept_unrel.vcxproj index 3c12a1a..d26667e 100644 --- a/vs/tests/test_debug_x86_noexcept_unrel.vcxproj +++ b/vs/tests/test_debug_x86_noexcept_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_debug_x86_unrel.vcxproj b/vs/tests/test_debug_x86_unrel.vcxproj index bad87f4..06ef93a 100644 --- a/vs/tests/test_debug_x86_unrel.vcxproj +++ b/vs/tests/test_debug_x86_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x64.vcxproj b/vs/tests/test_release_x64.vcxproj index c2179e3..98ad596 100644 --- a/vs/tests/test_release_x64.vcxproj +++ b/vs/tests/test_release_x64.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x64_cpplatest.vcxproj b/vs/tests/test_release_x64_cpplatest.vcxproj index fcc07a9..61c0db9 100644 --- a/vs/tests/test_release_x64_cpplatest.vcxproj +++ b/vs/tests/test_release_x64_cpplatest.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x64_cpplatest_noexcept.vcxproj b/vs/tests/test_release_x64_cpplatest_noexcept.vcxproj index f2c3408..b4f6bf1 100644 --- a/vs/tests/test_release_x64_cpplatest_noexcept.vcxproj +++ b/vs/tests/test_release_x64_cpplatest_noexcept.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x64_cpplatest_noexcept_unrel.vcxproj b/vs/tests/test_release_x64_cpplatest_noexcept_unrel.vcxproj index 489cb32..ded2cdc 100644 --- a/vs/tests/test_release_x64_cpplatest_noexcept_unrel.vcxproj +++ b/vs/tests/test_release_x64_cpplatest_noexcept_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x64_cpplatest_unrel.vcxproj b/vs/tests/test_release_x64_cpplatest_unrel.vcxproj index 9ece852..dae9b33 100644 --- a/vs/tests/test_release_x64_cpplatest_unrel.vcxproj +++ b/vs/tests/test_release_x64_cpplatest_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x64_noexcept.vcxproj b/vs/tests/test_release_x64_noexcept.vcxproj index ad4e1b8..013e6c1 100644 --- a/vs/tests/test_release_x64_noexcept.vcxproj +++ b/vs/tests/test_release_x64_noexcept.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x64_noexcept_unrel.vcxproj b/vs/tests/test_release_x64_noexcept_unrel.vcxproj index b1764d3..66ce168 100644 --- a/vs/tests/test_release_x64_noexcept_unrel.vcxproj +++ b/vs/tests/test_release_x64_noexcept_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x64_unrel.vcxproj b/vs/tests/test_release_x64_unrel.vcxproj index e9ffcf2..184720c 100644 --- a/vs/tests/test_release_x64_unrel.vcxproj +++ b/vs/tests/test_release_x64_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x86.vcxproj b/vs/tests/test_release_x86.vcxproj index 67f1d27..6e706f4 100644 --- a/vs/tests/test_release_x86.vcxproj +++ b/vs/tests/test_release_x86.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x86_cpplatest.vcxproj b/vs/tests/test_release_x86_cpplatest.vcxproj index d75a411..1eced15 100644 --- a/vs/tests/test_release_x86_cpplatest.vcxproj +++ b/vs/tests/test_release_x86_cpplatest.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x86_cpplatest_noexcept.vcxproj b/vs/tests/test_release_x86_cpplatest_noexcept.vcxproj index e47e14c..bd1ab73 100644 --- a/vs/tests/test_release_x86_cpplatest_noexcept.vcxproj +++ b/vs/tests/test_release_x86_cpplatest_noexcept.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x86_cpplatest_noexcept_unrel.vcxproj b/vs/tests/test_release_x86_cpplatest_noexcept_unrel.vcxproj index 5f2e5c3..9299603 100644 --- a/vs/tests/test_release_x86_cpplatest_noexcept_unrel.vcxproj +++ b/vs/tests/test_release_x86_cpplatest_noexcept_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x86_cpplatest_unrel.vcxproj b/vs/tests/test_release_x86_cpplatest_unrel.vcxproj index 0e0fea2..623b8fb 100644 --- a/vs/tests/test_release_x86_cpplatest_unrel.vcxproj +++ b/vs/tests/test_release_x86_cpplatest_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x86_noexcept.vcxproj b/vs/tests/test_release_x86_noexcept.vcxproj index bbfd25e..571389e 100644 --- a/vs/tests/test_release_x86_noexcept.vcxproj +++ b/vs/tests/test_release_x86_noexcept.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x86_noexcept_unrel.vcxproj b/vs/tests/test_release_x86_noexcept_unrel.vcxproj index d79cc83..e6c6a2d 100644 --- a/vs/tests/test_release_x86_noexcept_unrel.vcxproj +++ b/vs/tests/test_release_x86_noexcept_unrel.vcxproj @@ -77,6 +77,7 @@ + diff --git a/vs/tests/test_release_x86_unrel.vcxproj b/vs/tests/test_release_x86_unrel.vcxproj index 7d30e43..f09c873 100644 --- a/vs/tests/test_release_x86_unrel.vcxproj +++ b/vs/tests/test_release_x86_unrel.vcxproj @@ -77,6 +77,7 @@ +