diff options
| author | Amlal El Mahrouss <amlal@nekernel.org> | 2026-03-08 15:47:16 +0100 |
|---|---|---|
| committer | Amlal El Mahrouss <amlal@nekernel.org> | 2026-03-08 15:47:16 +0100 |
| commit | ddb1cbc831b6d13b985d91022f01e955e24ae871 (patch) | |
| tree | 985c7eda4fafa827eaad88b6b469b0baba791817 /vendor/toml++/impl/table.hpp | |
| parent | 7a469801ecb55fcde0199d4e41b1cec3a17dcb05 (diff) | |
[CHORE] Patching TOML manifest parser to avoid null deref.nebuild-patches-deref
Signed-off-by: Amlal El Mahrouss <amlal@nekernel.org>
Diffstat (limited to 'vendor/toml++/impl/table.hpp')
| -rw-r--r-- | vendor/toml++/impl/table.hpp | 3591 |
1 files changed, 1661 insertions, 1930 deletions
diff --git a/vendor/toml++/impl/table.hpp b/vendor/toml++/impl/table.hpp index edb7316..a49b16b 100644 --- a/vendor/toml++/impl/table.hpp +++ b/vendor/toml++/impl/table.hpp @@ -1,1995 +1,1726 @@ -//# This file is a part of toml++ and is subject to the the terms of the MIT license. -//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au> -//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. -// SPDX-License-Identifier: MIT +// # This file is a part of toml++ and is subject to the the terms of the MIT license. +// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au> +// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT #pragma once -#include "forward_declarations.hpp" -#include "std_map.hpp" -#include "std_initializer_list.hpp" #include "array.hpp" +#include "forward_declarations.hpp" +#include "header_start.hpp" +#include "key.hpp" #include "make_node.hpp" #include "node_view.hpp" -#include "key.hpp" -#include "header_start.hpp" +#include "std_initializer_list.hpp" +#include "std_map.hpp" /// \cond -TOML_IMPL_NAMESPACE_START -{ - template <bool IsConst> - struct table_proxy_pair - { - using value_type = std::conditional_t<IsConst, const node, node>; - - const toml::key& first; - value_type& second; - }; - - template <bool IsConst> - class table_iterator - { - private: - template <bool> - friend class table_iterator; - - using proxy_type = table_proxy_pair<IsConst>; - using mutable_map_iterator = std::map<toml::key, node_ptr, std::less<>>::iterator; - using const_map_iterator = std::map<toml::key, node_ptr, std::less<>>::const_iterator; - using map_iterator = std::conditional_t<IsConst, const_map_iterator, mutable_map_iterator>; - - mutable map_iterator iter_; - alignas(proxy_type) mutable unsigned char proxy_[sizeof(proxy_type)]; - mutable bool proxy_instantiated_ = false; - - TOML_NODISCARD - proxy_type* get_proxy() const noexcept - { - if (!proxy_instantiated_) - { - auto p = ::new (static_cast<void*>(proxy_)) proxy_type{ iter_->first, *iter_->second.get() }; - proxy_instantiated_ = true; - return p; - } - else - return TOML_LAUNDER(reinterpret_cast<proxy_type*>(proxy_)); - } - - public: - TOML_NODISCARD_CTOR - table_iterator() noexcept = default; - - TOML_NODISCARD_CTOR - explicit table_iterator(mutable_map_iterator iter) noexcept // - : iter_{ iter } - {} - - TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst) - TOML_NODISCARD_CTOR - explicit table_iterator(const_map_iterator iter) noexcept // - : iter_{ iter } - {} - - TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst) - TOML_NODISCARD_CTOR - table_iterator(const table_iterator<false>& other) noexcept // - : iter_{ other.iter_ } - {} - - TOML_NODISCARD_CTOR - table_iterator(const table_iterator& other) noexcept // - : iter_{ other.iter_ } - {} - - table_iterator& operator=(const table_iterator& rhs) noexcept - { - iter_ = rhs.iter_; - proxy_instantiated_ = false; - return *this; - } - - using value_type = table_proxy_pair<IsConst>; - using reference = value_type&; - using pointer = value_type*; - using difference_type = typename std::iterator_traits<map_iterator>::difference_type; - using iterator_category = typename std::iterator_traits<map_iterator>::iterator_category; - - table_iterator& operator++() noexcept // ++pre - { - ++iter_; - proxy_instantiated_ = false; - return *this; - } - - table_iterator operator++(int) noexcept // post++ - { - table_iterator out{ iter_ }; - ++iter_; - proxy_instantiated_ = false; - return out; - } - - table_iterator& operator--() noexcept // --pre - { - --iter_; - proxy_instantiated_ = false; - return *this; - } - - table_iterator operator--(int) noexcept // post-- - { - table_iterator out{ iter_ }; - --iter_; - proxy_instantiated_ = false; - return out; - } - - TOML_PURE_INLINE_GETTER - reference operator*() const noexcept - { - return *get_proxy(); - } - - TOML_PURE_INLINE_GETTER - pointer operator->() const noexcept - { - return get_proxy(); - } - - TOML_PURE_INLINE_GETTER - explicit operator const map_iterator&() const noexcept - { - return iter_; - } - - TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst) - TOML_PURE_INLINE_GETTER - explicit operator const const_map_iterator() const noexcept - { - return iter_; - } - - TOML_PURE_INLINE_GETTER - friend bool operator==(const table_iterator& lhs, const table_iterator& rhs) noexcept - { - return lhs.iter_ == rhs.iter_; - } - - TOML_PURE_INLINE_GETTER - friend bool operator!=(const table_iterator& lhs, const table_iterator& rhs) noexcept - { - return lhs.iter_ != rhs.iter_; - } - }; - - struct table_init_pair - { - mutable toml::key key; - mutable node_ptr value; - - template <typename K, typename V> - TOML_NODISCARD_CTOR - table_init_pair(K&& k, V&& v, value_flags flags = preserve_source_value_flags) // - : key{ static_cast<K&&>(k) }, - value{ make_node(static_cast<V&&>(v), flags) } - {} - }; +TOML_IMPL_NAMESPACE_START { + template <bool IsConst> + struct table_proxy_pair { + using value_type = std::conditional_t<IsConst, const node, node>; + + const toml::key& first; + value_type& second; + }; + + template <bool IsConst> + class table_iterator { + private: + template <bool> + friend class table_iterator; + + using proxy_type = table_proxy_pair<IsConst>; + using mutable_map_iterator = std::map<toml::key, node_ptr, std::less<>>::iterator; + using const_map_iterator = std::map<toml::key, node_ptr, std::less<>>::const_iterator; + using map_iterator = std::conditional_t<IsConst, const_map_iterator, mutable_map_iterator>; + + mutable map_iterator iter_; + alignas(proxy_type) mutable unsigned char proxy_[sizeof(proxy_type)]; + mutable bool proxy_instantiated_ = false; + + TOML_NODISCARD + proxy_type* get_proxy() const noexcept { + if (!proxy_instantiated_) { + auto p = ::new (static_cast<void*>(proxy_)) proxy_type{iter_->first, *iter_->second.get()}; + proxy_instantiated_ = true; + return p; + } else + return TOML_LAUNDER(reinterpret_cast<proxy_type*>(proxy_)); + } + + public: + TOML_NODISCARD_CTOR + table_iterator() noexcept = default; + + TOML_NODISCARD_CTOR + explicit table_iterator(mutable_map_iterator iter) noexcept // + : iter_{iter} {} + + TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst) + TOML_NODISCARD_CTOR + explicit table_iterator(const_map_iterator iter) noexcept // + : iter_{iter} {} + + TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst) + TOML_NODISCARD_CTOR + table_iterator(const table_iterator<false>& other) noexcept // + : iter_{other.iter_} {} + + TOML_NODISCARD_CTOR + table_iterator(const table_iterator& other) noexcept // + : iter_{other.iter_} {} + + table_iterator& operator=(const table_iterator& rhs) noexcept { + iter_ = rhs.iter_; + proxy_instantiated_ = false; + return *this; + } + + using value_type = table_proxy_pair<IsConst>; + using reference = value_type&; + using pointer = value_type*; + using difference_type = typename std::iterator_traits<map_iterator>::difference_type; + using iterator_category = typename std::iterator_traits<map_iterator>::iterator_category; + + table_iterator& operator++() noexcept // ++pre + { + ++iter_; + proxy_instantiated_ = false; + return *this; + } + + table_iterator operator++(int) noexcept // post++ + { + table_iterator out{iter_}; + ++iter_; + proxy_instantiated_ = false; + return out; + } + + table_iterator& operator--() noexcept // --pre + { + --iter_; + proxy_instantiated_ = false; + return *this; + } + + table_iterator operator--(int) noexcept // post-- + { + table_iterator out{iter_}; + --iter_; + proxy_instantiated_ = false; + return out; + } + + TOML_PURE_INLINE_GETTER + reference operator*() const noexcept { return *get_proxy(); } + + TOML_PURE_INLINE_GETTER + pointer operator->() const noexcept { return get_proxy(); } + + TOML_PURE_INLINE_GETTER + explicit operator const map_iterator&() const noexcept { return iter_; } + + TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst) + TOML_PURE_INLINE_GETTER + explicit operator const const_map_iterator() const noexcept { return iter_; } + + TOML_PURE_INLINE_GETTER + friend bool operator==(const table_iterator& lhs, const table_iterator& rhs) noexcept { + return lhs.iter_ == rhs.iter_; + } + + TOML_PURE_INLINE_GETTER + friend bool operator!=(const table_iterator& lhs, const table_iterator& rhs) noexcept { + return lhs.iter_ != rhs.iter_; + } + }; + + struct table_init_pair { + mutable toml::key key; + mutable node_ptr value; + + template <typename K, typename V> + TOML_NODISCARD_CTOR table_init_pair(K&& k, V&& v, + value_flags flags = preserve_source_value_flags) // + : key{static_cast<K&&>(k)}, value{make_node(static_cast<V&&>(v), flags)} {} + }; } TOML_IMPL_NAMESPACE_END; /// \endcond -TOML_NAMESPACE_START -{ - /// \brief A BidirectionalIterator for iterating over key-value pairs in a toml::table. - using table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<false>); - - /// \brief A BidirectionalIterator for iterating over const key-value pairs in a toml::table. - using const_table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<true>); - - /// \brief A TOML table. - /// - /// \detail The interface of this type is modeled after std::map, with some - /// additional considerations made for the heterogeneous nature of a - /// TOML table. - /// - /// \cpp - /// toml::table tbl = toml::parse(R"( - /// - /// [animals] - /// cats = [ "tiger", "lion", "puma" ] - /// birds = [ "macaw", "pigeon", "canary" ] - /// fish = [ "salmon", "trout", "carp" ] - /// - /// )"sv); - /// - /// // operator[] retrieves node-views - /// std::cout << "cats: " << tbl["animals"]["cats"] << "\n"; - /// std::cout << "fish[1]: " << tbl["animals"]["fish"][1] << "\n"; - /// - /// // at_path() does fully-qualified "toml path" lookups - /// std::cout << "cats: " << tbl.at_path("animals.cats") << "\n"; - /// std::cout << "fish[1]: " << tbl.at_path("animals.fish[1]") << "\n"; - /// \ecpp - /// - /// \out - /// cats: ['tiger', 'lion', 'puma'] - /// fish[1] : 'trout' - /// cats : ['tiger', 'lion', 'puma'] - /// fish[1] : 'trout' - /// \eout - class TOML_EXPORTED_CLASS table : public node - { - private: - /// \cond - - using map_type = std::map<toml::key, impl::node_ptr, std::less<>>; - using map_pair = std::pair<const toml::key, impl::node_ptr>; - using map_iterator = typename map_type::iterator; - using const_map_iterator = typename map_type::const_iterator; - map_type map_; - - bool inline_ = false; - - TOML_NODISCARD_CTOR - TOML_EXPORTED_MEMBER_FUNCTION - table(const impl::table_init_pair*, const impl::table_init_pair*); - - /// \endcond - - public: - /// \brief Default constructor. - TOML_NODISCARD_CTOR - TOML_EXPORTED_MEMBER_FUNCTION - table() noexcept; - - TOML_EXPORTED_MEMBER_FUNCTION - ~table() noexcept; - - /// \brief Copy constructor. - TOML_NODISCARD_CTOR - TOML_EXPORTED_MEMBER_FUNCTION - table(const table&); - - /// \brief Move constructor. - TOML_NODISCARD_CTOR - TOML_EXPORTED_MEMBER_FUNCTION - table(table&& other) noexcept; - - /// \brief Constructs a table with one or more initial key-value pairs. - /// - /// \detail \cpp - /// auto tbl = toml::table{ - /// { "foo", 1 }, - /// { "bar", 2.0 }, - /// { "kek", "three" } - /// }; - /// std::cout << tbl << "\n"; - /// \ecpp - /// - /// \out - /// { foo = 1, bar = 2.0, kek = "three" } - /// \eout - /// - /// \param kvps A list of key-value pairs used to initialize the table. - TOML_NODISCARD_CTOR - TOML_EXPORTED_MEMBER_FUNCTION - explicit table(std::initializer_list<impl::table_init_pair> kvps) // - : table(kvps.begin(), kvps.end()) - {} - - /// \brief Copy-assignment operator. - TOML_EXPORTED_MEMBER_FUNCTION - table& operator=(const table&); - - /// \brief Move-assignment operator. - TOML_EXPORTED_MEMBER_FUNCTION - table& operator=(table&& rhs) noexcept; - - /// \name Type checks - /// @{ - - /// \brief Returns #toml::node_type::table. - TOML_CONST_INLINE_GETTER - node_type type() const noexcept final - { - return node_type::table; - } - - TOML_PURE_GETTER - TOML_EXPORTED_MEMBER_FUNCTION - bool is_homogeneous(node_type ntype) const noexcept final; - - TOML_PURE_GETTER - TOML_EXPORTED_MEMBER_FUNCTION - bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final; - - TOML_PURE_GETTER - TOML_EXPORTED_MEMBER_FUNCTION - bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final; - - /// \cond - template <typename ElemType = void> - TOML_PURE_GETTER - bool is_homogeneous() const noexcept - { - using type = impl::remove_cvref<impl::unwrap_node<ElemType>>; - static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>, - "The template type argument of table::is_homogeneous() must be void or one " - "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); - - return is_homogeneous(impl::node_type_of<type>); - } - /// \endcond - - /// \brief Returns `true`. - TOML_CONST_INLINE_GETTER - bool is_table() const noexcept final - { - return true; - } - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_array() const noexcept final - { - return false; - } - - /// \brief Returns `false`. - TOML_PURE_GETTER - bool is_array_of_tables() const noexcept final - { - return false; - } - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_value() const noexcept final - { - return false; - } - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_string() const noexcept final - { - return false; - } - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_integer() const noexcept final - { - return false; - } - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_floating_point() const noexcept final - { - return false; - } - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_number() const noexcept final - { - return false; - } - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_boolean() const noexcept final - { - return false; - } - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_date() const noexcept final - { - return false; - } - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_time() const noexcept final - { - return false; - } - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_date_time() const noexcept final - { - return false; - } - - /// @} - - /// \name Type casts - /// @{ - - /// \brief Returns a pointer to the table. - TOML_CONST_INLINE_GETTER - table* as_table() noexcept final - { - return this; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - array* as_array() noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - toml::value<std::string>* as_string() noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - toml::value<int64_t>* as_integer() noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - toml::value<double>* as_floating_point() noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - toml::value<bool>* as_boolean() noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - toml::value<date>* as_date() noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - toml::value<time>* as_time() noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - toml::value<date_time>* as_date_time() noexcept final - { - return nullptr; - } - - /// \brief Returns a const-qualified pointer to the table. - TOML_CONST_INLINE_GETTER - const table* as_table() const noexcept final - { - return this; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - const array* as_array() const noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - const toml::value<std::string>* as_string() const noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - const toml::value<int64_t>* as_integer() const noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - const toml::value<double>* as_floating_point() const noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - const toml::value<bool>* as_boolean() const noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - const toml::value<date>* as_date() const noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - const toml::value<time>* as_time() const noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - const toml::value<date_time>* as_date_time() const noexcept final - { - return nullptr; - } - - /// @} - - /// \name Metadata - /// @{ - - /// \brief Returns true if this table is an inline table. - /// - /// \remarks Runtime-constructed tables (i.e. those not created during - /// parsing) are not inline by default. - TOML_PURE_INLINE_GETTER - bool is_inline() const noexcept - { - return inline_; - } - - /// \brief Sets whether this table is a TOML inline table. - /// - /// \detail \godbolt{an9xdj} - /// - /// \cpp - /// auto tbl = toml::table{ - /// { "a", 1 }, - /// { "b", 2 }, - /// { "c", 3 }, - /// { "d", toml::table{ { "e", 4 } } } - /// }; - /// std::cout << "is inline? "sv << tbl.is_inline() << "\n"; - /// std::cout << tbl << "\n\n"; - /// - /// tbl.is_inline(!tbl.is_inline()); - /// std::cout << "is inline? "sv << tbl.is_inline() << "\n"; - /// std::cout << tbl << "\n"; - /// \ecpp - /// - /// \out - /// is inline? false - /// a = 1 - /// b = 2 - /// c = 3 - /// - /// [d] - /// e = 4 - /// - /// - /// is inline? true - /// { a = 1, b = 2, c = 3, d = { e = 4 } } - /// \eout - /// - /// \remarks A table being 'inline' is only relevent during printing; - /// it has no effect on the general functionality of the table - /// object. - /// - /// \param val The new value for 'inline'. - void is_inline(bool val) noexcept - { - inline_ = val; - } - - /// @} - - /// \name Value retrieval - /// @{ - - /// \brief Gets the node at a specific key. - /// - /// \detail \cpp - /// auto tbl = toml::table{ - /// { "a", 42, }, - /// { "b", "is the meaning of life, apparently." } - /// }; - /// std::cout << R"(node ["a"] exists: )"sv << !!arr.get("a") << "\n"; - /// std::cout << R"(node ["b"] exists: )"sv << !!arr.get("b") << "\n"; - /// std::cout << R"(node ["c"] exists: )"sv << !!arr.get("c") << "\n"; - /// if (auto val = arr.get("a")) - /// std::cout << R"(node ["a"] was an )"sv << val->type() << "\n"; - /// \ecpp - /// - /// \out - /// node ["a"] exists: true - /// node ["b"] exists: true - /// node ["c"] exists: false - /// node ["a"] was an integer - /// \eout - /// - /// \param key The node's key. - /// - /// \returns A pointer to the node at the specified key, or nullptr. - TOML_PURE_GETTER - TOML_EXPORTED_MEMBER_FUNCTION - node* get(std::string_view key) noexcept; - - /// \brief Gets the node at a specific key (const overload). - /// - /// \param key The node's key. - /// - /// \returns A pointer to the node at the specified key, or nullptr. - TOML_PURE_INLINE_GETTER - const node* get(std::string_view key) const noexcept - { - return const_cast<table&>(*this).get(key); - } +TOML_NAMESPACE_START { + /// \brief A BidirectionalIterator for iterating over key-value pairs in a toml::table. + using table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<false>); + + /// \brief A BidirectionalIterator for iterating over const key-value pairs in a toml::table. + using const_table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<true>); + + /// \brief A TOML table. + /// + /// \detail The interface of this type is modeled after std::map, with some + /// additional considerations made for the heterogeneous nature of a + /// TOML table. + /// + /// \cpp + /// toml::table tbl = toml::parse(R"( + /// + /// [animals] + /// cats = [ "tiger", "lion", "puma" ] + /// birds = [ "macaw", "pigeon", "canary" ] + /// fish = [ "salmon", "trout", "carp" ] + /// + /// )"sv); + /// + /// // operator[] retrieves node-views + /// std::cout << "cats: " << tbl["animals"]["cats"] << "\n"; + /// std::cout << "fish[1]: " << tbl["animals"]["fish"][1] << "\n"; + /// + /// // at_path() does fully-qualified "toml path" lookups + /// std::cout << "cats: " << tbl.at_path("animals.cats") << "\n"; + /// std::cout << "fish[1]: " << tbl.at_path("animals.fish[1]") << "\n"; + /// \ecpp + /// + /// \out + /// cats: ['tiger', 'lion', 'puma'] + /// fish[1] : 'trout' + /// cats : ['tiger', 'lion', 'puma'] + /// fish[1] : 'trout' + /// \eout + class TOML_EXPORTED_CLASS table : public node { + private: + /// \cond + + using map_type = std::map<toml::key, impl::node_ptr, std::less<>>; + using map_pair = std::pair<const toml::key, impl::node_ptr>; + using map_iterator = typename map_type::iterator; + using const_map_iterator = typename map_type::const_iterator; + map_type map_; + + bool inline_ = false; + + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + table(const impl::table_init_pair*, const impl::table_init_pair*); + + /// \endcond + + public: + /// \brief Default constructor. + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + table() noexcept; + + TOML_EXPORTED_MEMBER_FUNCTION + ~table() noexcept; + + /// \brief Copy constructor. + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + table(const table&); + + /// \brief Move constructor. + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + table(table&& other) noexcept; + + /// \brief Constructs a table with one or more initial key-value pairs. + /// + /// \detail \cpp + /// auto tbl = toml::table{ + /// { "foo", 1 }, + /// { "bar", 2.0 }, + /// { "kek", "three" } + /// }; + /// std::cout << tbl << "\n"; + /// \ecpp + /// + /// \out + /// { foo = 1, bar = 2.0, kek = "three" } + /// \eout + /// + /// \param kvps A list of key-value pairs used to initialize the table. + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + explicit table(std::initializer_list<impl::table_init_pair> kvps) // + : table(kvps.begin(), kvps.end()) {} + + /// \brief Copy-assignment operator. + TOML_EXPORTED_MEMBER_FUNCTION + table& operator=(const table&); + + /// \brief Move-assignment operator. + TOML_EXPORTED_MEMBER_FUNCTION + table& operator=(table&& rhs) noexcept; + + /// \name Type checks + /// @{ + + /// \brief Returns #toml::node_type::table. + TOML_CONST_INLINE_GETTER + node_type type() const noexcept final { return node_type::table; } + + TOML_PURE_GETTER + TOML_EXPORTED_MEMBER_FUNCTION + bool is_homogeneous(node_type ntype) const noexcept final; + + TOML_PURE_GETTER + TOML_EXPORTED_MEMBER_FUNCTION + bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final; + + TOML_PURE_GETTER + TOML_EXPORTED_MEMBER_FUNCTION + bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final; + + /// \cond + template <typename ElemType = void> + TOML_PURE_GETTER bool is_homogeneous() const noexcept { + using type = impl::remove_cvref<impl::unwrap_node<ElemType>>; + static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>, + "The template type argument of table::is_homogeneous() must be void or one " + "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); + + return is_homogeneous(impl::node_type_of<type>); + } + /// \endcond + + /// \brief Returns `true`. + TOML_CONST_INLINE_GETTER + bool is_table() const noexcept final { return true; } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_array() const noexcept final { return false; } + + /// \brief Returns `false`. + TOML_PURE_GETTER + bool is_array_of_tables() const noexcept final { return false; } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_value() const noexcept final { return false; } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_string() const noexcept final { return false; } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_integer() const noexcept final { return false; } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_floating_point() const noexcept final { return false; } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_number() const noexcept final { return false; } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_boolean() const noexcept final { return false; } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_date() const noexcept final { return false; } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_time() const noexcept final { return false; } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_date_time() const noexcept final { return false; } + + /// @} + + /// \name Type casts + /// @{ + + /// \brief Returns a pointer to the table. + TOML_CONST_INLINE_GETTER + table* as_table() noexcept final { return this; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + array* as_array() noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value<std::string>* as_string() noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value<int64_t>* as_integer() noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value<double>* as_floating_point() noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value<bool>* as_boolean() noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value<date>* as_date() noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value<time>* as_time() noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + toml::value<date_time>* as_date_time() noexcept final { return nullptr; } + + /// \brief Returns a const-qualified pointer to the table. + TOML_CONST_INLINE_GETTER + const table* as_table() const noexcept final { return this; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + const array* as_array() const noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + const toml::value<std::string>* as_string() const noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + const toml::value<int64_t>* as_integer() const noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + const toml::value<double>* as_floating_point() const noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + const toml::value<bool>* as_boolean() const noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + const toml::value<date>* as_date() const noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + const toml::value<time>* as_time() const noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + const toml::value<date_time>* as_date_time() const noexcept final { return nullptr; } + + /// @} + + /// \name Metadata + /// @{ + + /// \brief Returns true if this table is an inline table. + /// + /// \remarks Runtime-constructed tables (i.e. those not created during + /// parsing) are not inline by default. + TOML_PURE_INLINE_GETTER + bool is_inline() const noexcept { return inline_; } + + /// \brief Sets whether this table is a TOML inline table. + /// + /// \detail \godbolt{an9xdj} + /// + /// \cpp + /// auto tbl = toml::table{ + /// { "a", 1 }, + /// { "b", 2 }, + /// { "c", 3 }, + /// { "d", toml::table{ { "e", 4 } } } + /// }; + /// std::cout << "is inline? "sv << tbl.is_inline() << "\n"; + /// std::cout << tbl << "\n\n"; + /// + /// tbl.is_inline(!tbl.is_inline()); + /// std::cout << "is inline? "sv << tbl.is_inline() << "\n"; + /// std::cout << tbl << "\n"; + /// \ecpp + /// + /// \out + /// is inline? false + /// a = 1 + /// b = 2 + /// c = 3 + /// + /// [d] + /// e = 4 + /// + /// + /// is inline? true + /// { a = 1, b = 2, c = 3, d = { e = 4 } } + /// \eout + /// + /// \remarks A table being 'inline' is only relevent during printing; + /// it has no effect on the general functionality of the table + /// object. + /// + /// \param val The new value for 'inline'. + void is_inline(bool val) noexcept { inline_ = val; } + + /// @} + + /// \name Value retrieval + /// @{ + + /// \brief Gets the node at a specific key. + /// + /// \detail \cpp + /// auto tbl = toml::table{ + /// { "a", 42, }, + /// { "b", "is the meaning of life, apparently." } + /// }; + /// std::cout << R"(node ["a"] exists: )"sv << !!arr.get("a") << "\n"; + /// std::cout << R"(node ["b"] exists: )"sv << !!arr.get("b") << "\n"; + /// std::cout << R"(node ["c"] exists: )"sv << !!arr.get("c") << "\n"; + /// if (auto val = arr.get("a")) + /// std::cout << R"(node ["a"] was an )"sv << val->type() << "\n"; + /// \ecpp + /// + /// \out + /// node ["a"] exists: true + /// node ["b"] exists: true + /// node ["c"] exists: false + /// node ["a"] was an integer + /// \eout + /// + /// \param key The node's key. + /// + /// \returns A pointer to the node at the specified key, or nullptr. + TOML_PURE_GETTER + TOML_EXPORTED_MEMBER_FUNCTION + node* get(std::string_view key) noexcept; + + /// \brief Gets the node at a specific key (const overload). + /// + /// \param key The node's key. + /// + /// \returns A pointer to the node at the specified key, or nullptr. + TOML_PURE_INLINE_GETTER + const node* get(std::string_view key) const noexcept { + return const_cast<table&>(*this).get(key); + } #if TOML_ENABLE_WINDOWS_COMPAT - /// \brief Gets the node at a specific key. - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \param key The node's key. - /// - /// \returns A pointer to the node at the specified key, or nullptr. - TOML_NODISCARD - node* get(std::wstring_view key) - { - if (empty()) - return nullptr; - - return get(impl::narrow(key)); - } - - /// \brief Gets the node at a specific key (const overload). - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \param key The node's key. - /// - /// \returns A pointer to the node at the specified key, or nullptr. - TOML_NODISCARD - const node* get(std::wstring_view key) const - { - return const_cast<table&>(*this).get(key); - } - -#endif // TOML_ENABLE_WINDOWS_COMPAT - - /// \brief Gets the node at a specific key if it is a particular type. - /// - /// \detail \cpp - /// auto tbl = toml::table{ - /// { "a", 42, }, - /// { "b", "is the meaning of life, apparently." } - /// }; - /// if (auto val = arr.get_as<int64_t>("a")) - /// std::cout << R"(node ["a"] was an integer with value )"sv << **val << "\n"; - /// \ecpp - /// - /// \out - /// node ["a"] was an integer with value 42 - /// \eout - /// - /// \tparam T One of the TOML node or value types. - /// \param key The node's key. - /// - /// \returns A pointer to the node at the specified key if it was of the given type, or nullptr. - template <typename T> - TOML_PURE_GETTER - impl::wrap_node<T>* get_as(std::string_view key) noexcept - { - const auto n = this->get(key); - return n ? n->template as<T>() : nullptr; - } - - /// \brief Gets the node at a specific key if it is a particular type (const overload). - /// - /// \tparam T One of the TOML node or value types. - /// \param key The node's key. - /// - /// \returns A pointer to the node at the specified key if it was of the given type, or nullptr. - template <typename T> - TOML_PURE_GETTER - const impl::wrap_node<T>* get_as(std::string_view key) const noexcept - { - return const_cast<table&>(*this).template get_as<T>(key); - } + /// \brief Gets the node at a specific key. + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \param key The node's key. + /// + /// \returns A pointer to the node at the specified key, or nullptr. + TOML_NODISCARD + node* get(std::wstring_view key) { + if (empty()) return nullptr; + + return get(impl::narrow(key)); + } + + /// \brief Gets the node at a specific key (const overload). + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \param key The node's key. + /// + /// \returns A pointer to the node at the specified key, or nullptr. + TOML_NODISCARD + const node* get(std::wstring_view key) const { return const_cast<table&>(*this).get(key); } + +#endif // TOML_ENABLE_WINDOWS_COMPAT + + /// \brief Gets the node at a specific key if it is a particular type. + /// + /// \detail \cpp + /// auto tbl = toml::table{ + /// { "a", 42, }, + /// { "b", "is the meaning of life, apparently." } + /// }; + /// if (auto val = arr.get_as<int64_t>("a")) + /// std::cout << R"(node ["a"] was an integer with value )"sv << **val << "\n"; + /// \ecpp + /// + /// \out + /// node ["a"] was an integer with value 42 + /// \eout + /// + /// \tparam T One of the TOML node or value types. + /// \param key The node's key. + /// + /// \returns A pointer to the node at the specified key if it was of the given type, or + /// nullptr. + template <typename T> + TOML_PURE_GETTER impl::wrap_node<T>* get_as(std::string_view key) noexcept { + const auto n = this->get(key); + return n ? n->template as<T>() : nullptr; + } + + /// \brief Gets the node at a specific key if it is a particular type (const overload). + /// + /// \tparam T One of the TOML node or value types. + /// \param key The node's key. + /// + /// \returns A pointer to the node at the specified key if it was of the given type, or + /// nullptr. + template <typename T> + TOML_PURE_GETTER const impl::wrap_node<T>* get_as(std::string_view key) const noexcept { + return const_cast<table&>(*this).template get_as<T>(key); + } #if TOML_ENABLE_WINDOWS_COMPAT - /// \brief Gets the node at a specific key if it is a particular type. - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \tparam T One of the TOML node or value types. - /// \param key The node's key. - /// - /// \returns A pointer to the node at the specified key if it was of the given type, or nullptr. - template <typename T> - TOML_NODISCARD - impl::wrap_node<T>* get_as(std::wstring_view key) - { - if (empty()) - return nullptr; - - return get_as<T>(impl::narrow(key)); - } - - /// \brief Gets the node at a specific key if it is a particular type (const overload). - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \tparam T One of the TOML node or value types. - /// \param key The node's key. - /// - /// \returns A pointer to the node at the specified key if it was of the given type, or nullptr. - template <typename T> - TOML_NODISCARD - const impl::wrap_node<T>* get_as(std::wstring_view key) const - { - return const_cast<table&>(*this).template get_as<T>(key); - } - -#endif // TOML_ENABLE_WINDOWS_COMPAT - - /// \brief Gets a reference to the element at a specific key, throwing `std::out_of_range` if none existed. - TOML_NODISCARD - TOML_EXPORTED_MEMBER_FUNCTION - node& at(std::string_view key); - - /// \brief Gets a reference to the element at a specific key, throwing `std::out_of_range` if none existed. - TOML_NODISCARD - const node& at(std::string_view key) const - { - return const_cast<table&>(*this).at(key); - } + /// \brief Gets the node at a specific key if it is a particular type. + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \tparam T One of the TOML node or value types. + /// \param key The node's key. + /// + /// \returns A pointer to the node at the specified key if it was of the given type, or + /// nullptr. + template <typename T> + TOML_NODISCARD impl::wrap_node<T>* get_as(std::wstring_view key) { + if (empty()) return nullptr; + + return get_as<T>(impl::narrow(key)); + } + + /// \brief Gets the node at a specific key if it is a particular type (const overload). + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \tparam T One of the TOML node or value types. + /// \param key The node's key. + /// + /// \returns A pointer to the node at the specified key if it was of the given type, or + /// nullptr. + template <typename T> + TOML_NODISCARD const impl::wrap_node<T>* get_as(std::wstring_view key) const { + return const_cast<table&>(*this).template get_as<T>(key); + } + +#endif // TOML_ENABLE_WINDOWS_COMPAT + + /// \brief Gets a reference to the element at a specific key, throwing `std::out_of_range` if + /// none existed. + TOML_NODISCARD + TOML_EXPORTED_MEMBER_FUNCTION + node& at(std::string_view key); + + /// \brief Gets a reference to the element at a specific key, throwing `std::out_of_range` if + /// none existed. + TOML_NODISCARD + const node& at(std::string_view key) const { return const_cast<table&>(*this).at(key); } #if TOML_ENABLE_WINDOWS_COMPAT - /// \brief Gets a reference to the element at a specific key, throwing `std::out_of_range` if none existed. - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - TOML_NODISCARD - node& at(std::wstring_view key) - { - return at(impl::narrow(key)); - } - - /// \brief Gets a reference to the element at a specific key, throwing `std::out_of_range` if none existed. - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - TOML_NODISCARD - const node& at(std::wstring_view key) const - { - return const_cast<table&>(*this).at(key); - } - -#endif // TOML_ENABLE_WINDOWS_COMPAT - - /// @} - - /// \name Iteration - /// @{ - - /// \brief A BidirectionalIterator for iterating over key-value pairs in a toml::table. - using iterator = toml::table_iterator; - - /// \brief A BidirectionalIterator for iterating over const key-value pairs in a toml::table. - using const_iterator = toml::const_table_iterator; - - /// \brief Returns an iterator to the first key-value pair. - TOML_PURE_INLINE_GETTER - iterator begin() noexcept - { - return iterator{ map_.begin() }; - } - - /// \brief Returns an iterator to the first key-value pair. - TOML_PURE_INLINE_GETTER - const_iterator begin() const noexcept - { - return const_iterator{ map_.cbegin() }; - } - - /// \brief Returns an iterator to the first key-value pair. - TOML_PURE_INLINE_GETTER - const_iterator cbegin() const noexcept - { - return const_iterator{ map_.cbegin() }; - } - - /// \brief Returns an iterator to one-past-the-last key-value pair. - TOML_PURE_INLINE_GETTER - iterator end() noexcept - { - return iterator{ map_.end() }; - } - - /// \brief Returns an iterator to one-past-the-last key-value pair. - TOML_PURE_INLINE_GETTER - const_iterator end() const noexcept - { - return const_iterator{ map_.cend() }; - } - - /// \brief Returns an iterator to one-past-the-last key-value pair. - TOML_PURE_INLINE_GETTER - const_iterator cend() const noexcept - { - return const_iterator{ map_.cend() }; - } - - private: - /// \cond - - template <typename T, typename Table> - using for_each_value_ref = impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Table>; - - template <typename Func, typename Table, typename T> - using can_for_each = std::disjunction<std::is_invocable<Func, const key&, for_each_value_ref<T, Table>>, // - std::is_invocable<Func, for_each_value_ref<T, Table>>>; - - template <typename Func, typename Table, typename T> - using can_for_each_nothrow = std::conditional_t< - // first form - std::is_invocable_v<Func, const key&, for_each_value_ref<T, Table>>, - std::is_nothrow_invocable<Func, const key&, for_each_value_ref<T, Table>>, - std::conditional_t< - // second form - std::is_invocable_v<Func, for_each_value_ref<T, Table>>, - std::is_nothrow_invocable<Func, for_each_value_ref<T, Table>>, - std::false_type>>; - - template <typename Func, typename Table> - using can_for_each_any = std::disjunction<can_for_each<Func, Table, table>, - can_for_each<Func, Table, array>, - can_for_each<Func, Table, std::string>, - can_for_each<Func, Table, int64_t>, - can_for_each<Func, Table, double>, - can_for_each<Func, Table, bool>, - can_for_each<Func, Table, date>, - can_for_each<Func, Table, time>, - can_for_each<Func, Table, date_time>>; - - template <typename Func, typename Table, typename T> - using for_each_is_nothrow_one = std::disjunction<std::negation<can_for_each<Func, Table, T>>, // - can_for_each_nothrow<Func, Table, T>>; - - template <typename Func, typename Table> - using for_each_is_nothrow = std::conjunction<for_each_is_nothrow_one<Func, Table, table>, - for_each_is_nothrow_one<Func, Table, array>, - for_each_is_nothrow_one<Func, Table, std::string>, - for_each_is_nothrow_one<Func, Table, int64_t>, - for_each_is_nothrow_one<Func, Table, double>, - for_each_is_nothrow_one<Func, Table, bool>, - for_each_is_nothrow_one<Func, Table, date>, - for_each_is_nothrow_one<Func, Table, time>, - for_each_is_nothrow_one<Func, Table, date_time>>; - - template <typename Func, typename Table> - static void do_for_each(Func&& visitor, Table&& tbl) // - noexcept(for_each_is_nothrow<Func&&, Table&&>::value) - { - static_assert(can_for_each_any<Func&&, Table&&>::value, - "TOML table for_each visitors must be invocable for at least one of the toml::node " - "specializations:" TOML_SA_NODE_TYPE_LIST); - - using kvp_type = impl::copy_cv<map_pair, std::remove_reference_t<Table>>; - - for (kvp_type& kvp : tbl.map_) - { - using node_ref = impl::copy_cvref<toml::node, Table&&>; - static_assert(std::is_reference_v<node_ref>); + /// \brief Gets a reference to the element at a specific key, throwing `std::out_of_range` if + /// none existed. + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + TOML_NODISCARD + node& at(std::wstring_view key) { return at(impl::narrow(key)); } + + /// \brief Gets a reference to the element at a specific key, throwing `std::out_of_range` if + /// none existed. + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + TOML_NODISCARD + const node& at(std::wstring_view key) const { return const_cast<table&>(*this).at(key); } + +#endif // TOML_ENABLE_WINDOWS_COMPAT + + /// @} + + /// \name Iteration + /// @{ + + /// \brief A BidirectionalIterator for iterating over key-value pairs in a toml::table. + using iterator = toml::table_iterator; + + /// \brief A BidirectionalIterator for iterating over const key-value pairs in a toml::table. + using const_iterator = toml::const_table_iterator; + + /// \brief Returns an iterator to the first key-value pair. + TOML_PURE_INLINE_GETTER + iterator begin() noexcept { return iterator{map_.begin()}; } + + /// \brief Returns an iterator to the first key-value pair. + TOML_PURE_INLINE_GETTER + const_iterator begin() const noexcept { return const_iterator{map_.cbegin()}; } + + /// \brief Returns an iterator to the first key-value pair. + TOML_PURE_INLINE_GETTER + const_iterator cbegin() const noexcept { return const_iterator{map_.cbegin()}; } + + /// \brief Returns an iterator to one-past-the-last key-value pair. + TOML_PURE_INLINE_GETTER + iterator end() noexcept { return iterator{map_.end()}; } + + /// \brief Returns an iterator to one-past-the-last key-value pair. + TOML_PURE_INLINE_GETTER + const_iterator end() const noexcept { return const_iterator{map_.cend()}; } + + /// \brief Returns an iterator to one-past-the-last key-value pair. + TOML_PURE_INLINE_GETTER + const_iterator cend() const noexcept { return const_iterator{map_.cend()}; } + + private: + /// \cond + + template <typename T, typename Table> + using for_each_value_ref = + impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Table>; + + template <typename Func, typename Table, typename T> + using can_for_each = + std::disjunction<std::is_invocable<Func, const key&, for_each_value_ref<T, Table>>, // + std::is_invocable<Func, for_each_value_ref<T, Table>>>; + + template <typename Func, typename Table, typename T> + using can_for_each_nothrow = std::conditional_t< + // first form + std::is_invocable_v<Func, const key&, for_each_value_ref<T, Table>>, + std::is_nothrow_invocable<Func, const key&, for_each_value_ref<T, Table>>, + std::conditional_t< + // second form + std::is_invocable_v<Func, for_each_value_ref<T, Table>>, + std::is_nothrow_invocable<Func, for_each_value_ref<T, Table>>, std::false_type>>; + + template <typename Func, typename Table> + using can_for_each_any = + std::disjunction<can_for_each<Func, Table, table>, can_for_each<Func, Table, array>, + can_for_each<Func, Table, std::string>, can_for_each<Func, Table, int64_t>, + can_for_each<Func, Table, double>, can_for_each<Func, Table, bool>, + can_for_each<Func, Table, date>, can_for_each<Func, Table, time>, + can_for_each<Func, Table, date_time>>; + + template <typename Func, typename Table, typename T> + using for_each_is_nothrow_one = + std::disjunction<std::negation<can_for_each<Func, Table, T>>, // + can_for_each_nothrow<Func, Table, T>>; + + template <typename Func, typename Table> + using for_each_is_nothrow = std::conjunction< + for_each_is_nothrow_one<Func, Table, table>, for_each_is_nothrow_one<Func, Table, array>, + for_each_is_nothrow_one<Func, Table, std::string>, + for_each_is_nothrow_one<Func, Table, int64_t>, for_each_is_nothrow_one<Func, Table, double>, + for_each_is_nothrow_one<Func, Table, bool>, for_each_is_nothrow_one<Func, Table, date>, + for_each_is_nothrow_one<Func, Table, time>, + for_each_is_nothrow_one<Func, Table, date_time>>; + + template <typename Func, typename Table> + static void do_for_each(Func&& visitor, Table&& tbl) // + noexcept(for_each_is_nothrow<Func&&, Table&&>::value) { + static_assert( + can_for_each_any<Func&&, Table&&>::value, + "TOML table for_each visitors must be invocable for at least one of the toml::node " + "specializations:" TOML_SA_NODE_TYPE_LIST); + + using kvp_type = impl::copy_cv<map_pair, std::remove_reference_t<Table>>; + + for (kvp_type& kvp : tbl.map_) { + using node_ref = impl::copy_cvref<toml::node, Table&&>; + static_assert(std::is_reference_v<node_ref>); #if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN #ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED - static_assert(impl::always_false<Func, Table, kvp_type, node_ref>, // - TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE); + static_assert(impl::always_false<Func, Table, kvp_type, node_ref>, // + TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE); #endif - static_cast<node_ref>(*kvp.second) - .visit( - [&]([[maybe_unused]] auto&& v) // - noexcept(for_each_is_nothrow_one<Func&&, Table&&, decltype(v)>::value) - { - using value_ref = for_each_value_ref<decltype(v), Table&&>; - static_assert(std::is_reference_v<value_ref>); - - // func(key, val) - if constexpr (std::is_invocable_v<Func&&, const key&, value_ref>) - { - static_cast<Func&&>(visitor)(static_cast<const key&>(kvp.first), - static_cast<value_ref>(v)); - } - - // func(val) - else if constexpr (std::is_invocable_v<Func&&, value_ref>) - { - static_cast<Func&&>(visitor)(static_cast<value_ref>(v)); - } - }); + static_cast<node_ref>(*kvp.second) + .visit([&]([[maybe_unused]] auto&& v) // + noexcept(for_each_is_nothrow_one<Func&&, Table&&, decltype(v)>::value) { + using value_ref = for_each_value_ref<decltype(v), Table&&>; + static_assert(std::is_reference_v<value_ref>); + + // func(key, val) + if constexpr (std::is_invocable_v<Func&&, const key&, value_ref>) { + static_cast<Func&&>(visitor)(static_cast<const key&>(kvp.first), + static_cast<value_ref>(v)); + } + + // func(val) + else if constexpr (std::is_invocable_v<Func&&, value_ref>) { + static_cast<Func&&>(visitor)(static_cast<value_ref>(v)); + } + }); #else - const auto keep_going = - static_cast<node_ref>(*kvp.second) - .visit( - [&]([[maybe_unused]] auto&& v) // - noexcept(for_each_is_nothrow_one<Func&&, Table&&, decltype(v)>::value) - { - using value_ref = for_each_value_ref<decltype(v), Table&&>; - static_assert(std::is_reference_v<value_ref>); - - // func(key, val) - if constexpr (std::is_invocable_v<Func&&, const key&, value_ref>) - { - using return_type = decltype(static_cast<Func&&>( - visitor)(static_cast<const key&>(kvp.first), static_cast<value_ref>(v))); - - if constexpr (impl::is_constructible_or_convertible<bool, return_type>) - { - return static_cast<bool>(static_cast<Func&&>( - visitor)(static_cast<const key&>(kvp.first), static_cast<value_ref>(v))); - } - else - { - static_cast<Func&&>(visitor)(static_cast<const key&>(kvp.first), - static_cast<value_ref>(v)); - return true; - } - } - - // func(val) - else if constexpr (std::is_invocable_v<Func&&, value_ref>) - { - using return_type = - decltype(static_cast<Func&&>(visitor)(static_cast<value_ref>(v))); - - if constexpr (impl::is_constructible_or_convertible<bool, return_type>) - { - return static_cast<bool>( - static_cast<Func&&>(visitor)(static_cast<value_ref>(v))); - } - else - { - static_cast<Func&&>(visitor)(static_cast<value_ref>(v)); - return true; - } - } - - // visitor not compatible with this particular type - else - return true; - }); - - if (!keep_going) - return; + const auto keep_going = + static_cast<node_ref>(*kvp.second) + .visit([&]([[maybe_unused]] auto&& v) // + noexcept(for_each_is_nothrow_one<Func&&, Table&&, decltype(v)>::value) { + using value_ref = for_each_value_ref<decltype(v), Table&&>; + static_assert(std::is_reference_v<value_ref>); + + // func(key, val) + if constexpr (std::is_invocable_v<Func&&, const key&, value_ref>) { + using return_type = decltype(static_cast<Func&&>(visitor)( + static_cast<const key&>(kvp.first), static_cast<value_ref>(v))); + + if constexpr (impl::is_constructible_or_convertible<bool, return_type>) { + return static_cast<bool>(static_cast<Func&&>(visitor)( + static_cast<const key&>(kvp.first), static_cast<value_ref>(v))); + } else { + static_cast<Func&&>(visitor)(static_cast<const key&>(kvp.first), + static_cast<value_ref>(v)); + return true; + } + } + + // func(val) + else if constexpr (std::is_invocable_v<Func&&, value_ref>) { + using return_type = + decltype(static_cast<Func&&>(visitor)(static_cast<value_ref>(v))); + + if constexpr (impl::is_constructible_or_convertible<bool, return_type>) { + return static_cast<bool>( + static_cast<Func&&>(visitor)(static_cast<value_ref>(v))); + } else { + static_cast<Func&&>(visitor)(static_cast<value_ref>(v)); + return true; + } + } + + // visitor not compatible with this particular type + else + return true; + }); + + if (!keep_going) return; #endif - } - } - - /// \endcond - - public: - /// \brief Invokes a visitor on each key-value pair in the table. - /// - /// \tparam Func A callable type invocable with one of the following signatures: - /// <ul> - /// <li> `func(key, val)` - /// <li> `func(val)` - /// </ul> - /// Where: - /// <ul> - /// <li> `key` will recieve a const reference to a toml::key - /// <li> `val` will recieve the value as it's concrete type with cvref-qualifications matching the table - /// </ul> - /// Visitors returning `bool` (or something convertible to `bool`) will cause iteration to - /// stop if they return `false`. - /// - /// \param visitor The visitor object. - /// - /// \returns A reference to the table. - /// - /// \details \cpp - /// toml::table tbl{ - /// { "0", 0 }, - /// { "1", 1 }, - /// { "2", 2 }, - /// { "3", 3.0 }, - /// { "4", "four" }, - /// { "5", "five" }, - /// { "6", 6 } - /// }; - /// - /// // select only the integers using a strongly-typed visitor - /// tbl.for_each([](toml::value<int64_t>& val) - /// { - /// std::cout << val << ", "; - /// }); - /// std::cout << "\n"; - /// - /// // select all the numeric values using a generic visitor + is_number<> metafunction - /// tbl.for_each([](auto&& val) - /// { - /// if constexpr (toml::is_number<decltype(val)>) - /// std::cout << val << ", "; - /// }); - /// std::cout << "\n"; - /// - /// // select all the numeric values until we encounter something non-numeric - /// tbl.for_each([](auto&& val) - /// { - /// if constexpr (toml::is_number<decltype(val)>) - /// { - /// std::cout << val << ", "; - /// return true; // "keep going" - /// } - /// else - /// return false; // "stop!" - /// - /// }); - /// std::cout << "\n\n"; - /// - /// // visitors may also recieve the key - /// tbl.for_each([](const toml::key& key, auto&& val) - /// { - /// std::cout << key << ": " << val << "\n"; - /// }); - /// - /// \ecpp - /// \out - /// 0, 1, 2, 6, - /// 0, 1, 2, 3.0, 6, - /// 0, 1, 2, 3.0, - /// - /// 0: 0 - /// 1: 1 - /// 2: 2 - /// 3: 3.0 - /// 4: 'four' - /// 5: 'five' - /// 6: 6 - /// \eout - /// - /// \see node::visit() - template <typename Func> - table& for_each(Func&& visitor) & // - noexcept(for_each_is_nothrow<Func&&, table&>::value) - { - do_for_each(static_cast<Func&&>(visitor), *this); - return *this; - } - - /// \brief Invokes a visitor on each key-value pair in the table (rvalue overload). - template <typename Func> - table&& for_each(Func&& visitor) && // - noexcept(for_each_is_nothrow<Func&&, table&&>::value) - { - do_for_each(static_cast<Func&&>(visitor), static_cast<table&&>(*this)); - return static_cast<table&&>(*this); - } - - /// \brief Invokes a visitor on each key-value pair in the table (const lvalue overload). - template <typename Func> - const table& for_each(Func&& visitor) const& // - noexcept(for_each_is_nothrow<Func&&, const table&>::value) - { - do_for_each(static_cast<Func&&>(visitor), *this); - return *this; - } - - /// \brief Invokes a visitor on each key-value pair in the table (const rvalue overload). - template <typename Func> - const table&& for_each(Func&& visitor) const&& // - noexcept(for_each_is_nothrow<Func&&, const table&&>::value) - { - do_for_each(static_cast<Func&&>(visitor), static_cast<const table&&>(*this)); - return static_cast<const table&&>(*this); - } - - /// @} - - /// \name Size and Capacity - /// @{ - - /// \brief Returns true if the table is empty. - TOML_PURE_INLINE_GETTER - bool empty() const noexcept - { - return map_.empty(); - } - - /// \brief Returns the number of key-value pairs in the table. - TOML_PURE_INLINE_GETTER - size_t size() const noexcept - { - return map_.size(); - } - - /// @} - - /// \name Searching - /// @{ - - private: - /// \cond - - TOML_PURE_GETTER - TOML_EXPORTED_MEMBER_FUNCTION - map_iterator get_lower_bound(std::string_view) noexcept; - - /// \endcond - - public: - /// \brief Returns an iterator to the first key-value pair with key that is _not less_ than the given key. - /// - /// \returns An iterator to the first matching key-value pair, or #end(). - TOML_PURE_GETTER - iterator lower_bound(std::string_view key) noexcept - { - return iterator{ get_lower_bound(key) }; - } - - /// \brief Returns a const iterator to the first key-value pair with key that is _not less_ than the given key. - /// - /// \returns An iterator to the first matching key-value pair, or #end(). - TOML_PURE_GETTER - const_iterator lower_bound(std::string_view key) const noexcept - { - return const_iterator{ const_cast<table&>(*this).get_lower_bound(key) }; - } + } + } + + /// \endcond + + public: + /// \brief Invokes a visitor on each key-value pair in the table. + /// + /// \tparam Func A callable type invocable with one of the following signatures: + /// <ul> + /// <li> `func(key, val)` + /// <li> `func(val)` + /// </ul> + /// Where: + /// <ul> + /// <li> `key` will recieve a const reference to a toml::key + /// <li> `val` will recieve the value as it's concrete type with cvref-qualifications + ///matching the table + /// </ul> + /// Visitors returning `bool` (or something convertible to `bool`) will cause iteration + ///to stop if they return `false`. + /// + /// \param visitor The visitor object. + /// + /// \returns A reference to the table. + /// + /// \details \cpp + /// toml::table tbl{ + /// { "0", 0 }, + /// { "1", 1 }, + /// { "2", 2 }, + /// { "3", 3.0 }, + /// { "4", "four" }, + /// { "5", "five" }, + /// { "6", 6 } + /// }; + /// + /// // select only the integers using a strongly-typed visitor + /// tbl.for_each([](toml::value<int64_t>& val) + /// { + /// std::cout << val << ", "; + /// }); + /// std::cout << "\n"; + /// + /// // select all the numeric values using a generic visitor + is_number<> metafunction + /// tbl.for_each([](auto&& val) + /// { + /// if constexpr (toml::is_number<decltype(val)>) + /// std::cout << val << ", "; + /// }); + /// std::cout << "\n"; + /// + /// // select all the numeric values until we encounter something non-numeric + /// tbl.for_each([](auto&& val) + /// { + /// if constexpr (toml::is_number<decltype(val)>) + /// { + /// std::cout << val << ", "; + /// return true; // "keep going" + /// } + /// else + /// return false; // "stop!" + /// + /// }); + /// std::cout << "\n\n"; + /// + /// // visitors may also recieve the key + /// tbl.for_each([](const toml::key& key, auto&& val) + /// { + /// std::cout << key << ": " << val << "\n"; + /// }); + /// + /// \ecpp + /// \out + /// 0, 1, 2, 6, + /// 0, 1, 2, 3.0, 6, + /// 0, 1, 2, 3.0, + /// + /// 0: 0 + /// 1: 1 + /// 2: 2 + /// 3: 3.0 + /// 4: 'four' + /// 5: 'five' + /// 6: 6 + /// \eout + /// + /// \see node::visit() + template <typename Func> + table& for_each(Func&& visitor) & // + noexcept(for_each_is_nothrow<Func&&, table&>::value) { + do_for_each(static_cast<Func&&>(visitor), *this); + return *this; + } + + /// \brief Invokes a visitor on each key-value pair in the table (rvalue overload). + template <typename Func> + table&& for_each(Func&& visitor) && // + noexcept(for_each_is_nothrow<Func&&, table&&>::value) { + do_for_each(static_cast<Func&&>(visitor), static_cast<table&&>(*this)); + return static_cast<table&&>(*this); + } + + /// \brief Invokes a visitor on each key-value pair in the table (const lvalue overload). + template <typename Func> + const table& for_each(Func&& visitor) const& // + noexcept(for_each_is_nothrow<Func&&, const table&>::value) { + do_for_each(static_cast<Func&&>(visitor), *this); + return *this; + } + + /// \brief Invokes a visitor on each key-value pair in the table (const rvalue overload). + template <typename Func> + const table&& for_each(Func&& visitor) const&& // + noexcept(for_each_is_nothrow<Func&&, const table&&>::value) { + do_for_each(static_cast<Func&&>(visitor), static_cast<const table&&>(*this)); + return static_cast<const table&&>(*this); + } + + /// @} + + /// \name Size and Capacity + /// @{ + + /// \brief Returns true if the table is empty. + TOML_PURE_INLINE_GETTER + bool empty() const noexcept { return map_.empty(); } + + /// \brief Returns the number of key-value pairs in the table. + TOML_PURE_INLINE_GETTER + size_t size() const noexcept { return map_.size(); } + + /// @} + + /// \name Searching + /// @{ + + private: + /// \cond + + TOML_PURE_GETTER + TOML_EXPORTED_MEMBER_FUNCTION + map_iterator get_lower_bound(std::string_view) noexcept; + + /// \endcond + + public: + /// \brief Returns an iterator to the first key-value pair with key that is _not less_ than the + /// given key. + /// + /// \returns An iterator to the first matching key-value pair, or #end(). + TOML_PURE_GETTER + iterator lower_bound(std::string_view key) noexcept { return iterator{get_lower_bound(key)}; } + + /// \brief Returns a const iterator to the first key-value pair with key that is _not less_ than + /// the given key. + /// + /// \returns An iterator to the first matching key-value pair, or #end(). + TOML_PURE_GETTER + const_iterator lower_bound(std::string_view key) const noexcept { + return const_iterator{const_cast<table&>(*this).get_lower_bound(key)}; + } #if TOML_ENABLE_WINDOWS_COMPAT - /// \brief Returns an iterator to the first key-value pair with key that is _not less_ than the given key. - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \returns An iterator to the first matching key-value pair, or #end(). - TOML_NODISCARD - iterator lower_bound(std::wstring_view key) - { - if (empty()) - return end(); - - return lower_bound(impl::narrow(key)); - } - - /// \brief Returns a const iterator to the first key-value pair with key that is _not less_ than the given key. - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \returns An iterator to the first matching key-value pair, or #end(). - TOML_NODISCARD - const_iterator lower_bound(std::wstring_view key) const - { - if (empty()) - return end(); - - return lower_bound(impl::narrow(key)); - } - -#endif // TOML_ENABLE_WINDOWS_COMPAT - - /// \brief Gets an iterator to the node at a specific key. - /// - /// \param key The node's key. - /// - /// \returns An iterator to the node at the specified key, or end(). - TOML_PURE_GETTER - TOML_EXPORTED_MEMBER_FUNCTION - iterator find(std::string_view key) noexcept; - - /// \brief Gets an iterator to the node at a specific key (const overload) - /// - /// \param key The node's key. - /// - /// \returns A const iterator to the node at the specified key, or cend(). - TOML_PURE_GETTER - TOML_EXPORTED_MEMBER_FUNCTION - const_iterator find(std::string_view key) const noexcept; - - /// \brief Returns true if the table contains a node at the given key. - TOML_PURE_GETTER - bool contains(std::string_view key) const noexcept - { - return get(key) != nullptr; - } + /// \brief Returns an iterator to the first key-value pair with key that is _not less_ than the + /// given key. + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \returns An iterator to the first matching key-value pair, or #end(). + TOML_NODISCARD + iterator lower_bound(std::wstring_view key) { + if (empty()) return end(); + + return lower_bound(impl::narrow(key)); + } + + /// \brief Returns a const iterator to the first key-value pair with key that is _not less_ than + /// the given key. + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \returns An iterator to the first matching key-value pair, or #end(). + TOML_NODISCARD + const_iterator lower_bound(std::wstring_view key) const { + if (empty()) return end(); + + return lower_bound(impl::narrow(key)); + } + +#endif // TOML_ENABLE_WINDOWS_COMPAT + + /// \brief Gets an iterator to the node at a specific key. + /// + /// \param key The node's key. + /// + /// \returns An iterator to the node at the specified key, or end(). + TOML_PURE_GETTER + TOML_EXPORTED_MEMBER_FUNCTION + iterator find(std::string_view key) noexcept; + + /// \brief Gets an iterator to the node at a specific key (const overload) + /// + /// \param key The node's key. + /// + /// \returns A const iterator to the node at the specified key, or cend(). + TOML_PURE_GETTER + TOML_EXPORTED_MEMBER_FUNCTION + const_iterator find(std::string_view key) const noexcept; + + /// \brief Returns true if the table contains a node at the given key. + TOML_PURE_GETTER + bool contains(std::string_view key) const noexcept { return get(key) != nullptr; } #if TOML_ENABLE_WINDOWS_COMPAT - /// \brief Gets an iterator to the node at a specific key. - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \param key The node's key. - /// - /// \returns An iterator to the node at the specified key, or end(). - TOML_NODISCARD - iterator find(std::wstring_view key) - { - if (empty()) - return end(); - - return find(impl::narrow(key)); - } - - /// \brief Gets an iterator to the node at a specific key (const overload). - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \param key The node's key. - /// - /// \returns A const iterator to the node at the specified key, or cend(). - TOML_NODISCARD - const_iterator find(std::wstring_view key) const - { - return find(impl::narrow(key)); - } - - /// \brief Returns true if the table contains a node at the given key. - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - TOML_NODISCARD - bool contains(std::wstring_view key) const - { - return contains(impl::narrow(key)); - } - -#endif // TOML_ENABLE_WINDOWS_COMPAT - - /// @} - - /// \name Erasure - /// @{ - - private: - /// \cond - - TOML_EXPORTED_MEMBER_FUNCTION - map_iterator erase(const_map_iterator) noexcept; - - TOML_EXPORTED_MEMBER_FUNCTION - map_iterator erase(const_map_iterator, const_map_iterator) noexcept; - - /// \endcond - - public: - /// \brief Removes the specified key-value pair from the table. - /// - /// \detail \cpp - /// auto tbl = toml::table{ - /// { "a", 1 }, - /// { "b", 2 }, - /// { "c", 3 } - /// }; - /// std::cout << tbl << "\n"; - /// - /// tbl.erase(tbl.begin() + 1); - /// std::cout << tbl << "\n"; - /// \ecpp - /// - /// \out - /// { a = 1, b = 2, c = 3 } - /// { a = 1, c = 3 } - /// \eout - /// - /// \param pos Iterator to the key-value pair being erased. - /// - /// \returns Iterator to the first key-value pair immediately following the removed key-value pair. - iterator erase(iterator pos) noexcept - { - return iterator{ erase(const_map_iterator{ pos }) }; - } - - /// \brief Removes the specified key-value pair from the table (const iterator overload). - /// - /// \detail \cpp - /// auto tbl = toml::table{ - /// { "a", 1 }, - /// { "b", 2 }, - /// { "c", 3 } - /// }; - /// std::cout << tbl << "\n"; - /// - /// tbl.erase(tbl.cbegin() + 1); - /// std::cout << tbl << "\n"; - /// \ecpp - /// - /// \out - /// { a = 1, b = 2, c = 3 } - /// { a = 1, c = 3 } - /// \eout - /// - /// \param pos Iterator to the key-value pair being erased. - /// - /// \returns Iterator to the first key-value pair immediately following the removed key-value pair. - iterator erase(const_iterator pos) noexcept - { - return iterator{ erase(const_map_iterator{ pos }) }; - } - - /// \brief Removes the key-value pairs in the range [first, last) from the table. - /// - /// \detail \cpp - /// auto tbl = toml::table{ - /// { "a", 1 }, - /// { "b", "bad" }, - /// { "c", "karma" }, - /// { "d", 2 } - /// }; - /// std::cout << tbl << "\n"; - /// - /// tbl.erase(tbl.cbegin() + 1, tbl.cbegin() + 3); - /// std::cout << tbl << "\n"; - /// \ecpp - /// - /// \out - /// { a = 1, b = "bad", c = "karma", d = 2 } - /// { a = 1, d = 2 } - /// \eout - /// - /// \param begin Iterator to the first key-value pair being erased. - /// \param end Iterator to the one-past-the-last key-value pair being erased. - /// - /// \returns Iterator to the first key-value pair immediately following the last removed key-value pair. - iterator erase(const_iterator begin, const_iterator end) noexcept - { - return iterator{ erase(const_map_iterator{ begin }, const_map_iterator{ end }) }; - } - - /// \brief Removes the value with the given key from the table. - /// - /// \detail \cpp - /// auto tbl = toml::table{ - /// { "a", 1 }, - /// { "b", 2 }, - /// { "c", 3 } - /// }; - /// std::cout << tbl << "\n"; - /// - /// std::cout << tbl.erase("b") << "\n"; - /// std::cout << tbl.erase("not an existing key") << "\n"; - /// std::cout << tbl << "\n"; - /// \ecpp - /// - /// \out - /// { a = 1, b = 2, c = 3 } - /// true - /// false - /// { a = 1, c = 3 } - /// \eout - /// - /// \param key Key to erase. - /// - /// \returns Number of elements removed (0 or 1). - TOML_EXPORTED_MEMBER_FUNCTION - size_t erase(std::string_view key) noexcept; + /// \brief Gets an iterator to the node at a specific key. + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \param key The node's key. + /// + /// \returns An iterator to the node at the specified key, or end(). + TOML_NODISCARD + iterator find(std::wstring_view key) { + if (empty()) return end(); + + return find(impl::narrow(key)); + } + + /// \brief Gets an iterator to the node at a specific key (const overload). + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \param key The node's key. + /// + /// \returns A const iterator to the node at the specified key, or cend(). + TOML_NODISCARD + const_iterator find(std::wstring_view key) const { return find(impl::narrow(key)); } + + /// \brief Returns true if the table contains a node at the given key. + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + TOML_NODISCARD + bool contains(std::wstring_view key) const { return contains(impl::narrow(key)); } + +#endif // TOML_ENABLE_WINDOWS_COMPAT + + /// @} + + /// \name Erasure + /// @{ + + private: + /// \cond + + TOML_EXPORTED_MEMBER_FUNCTION + map_iterator erase(const_map_iterator) noexcept; + + TOML_EXPORTED_MEMBER_FUNCTION + map_iterator erase(const_map_iterator, const_map_iterator) noexcept; + + /// \endcond + + public: + /// \brief Removes the specified key-value pair from the table. + /// + /// \detail \cpp + /// auto tbl = toml::table{ + /// { "a", 1 }, + /// { "b", 2 }, + /// { "c", 3 } + /// }; + /// std::cout << tbl << "\n"; + /// + /// tbl.erase(tbl.begin() + 1); + /// std::cout << tbl << "\n"; + /// \ecpp + /// + /// \out + /// { a = 1, b = 2, c = 3 } + /// { a = 1, c = 3 } + /// \eout + /// + /// \param pos Iterator to the key-value pair being erased. + /// + /// \returns Iterator to the first key-value pair immediately following the removed key-value + /// pair. + iterator erase(iterator pos) noexcept { return iterator{erase(const_map_iterator{pos})}; } + + /// \brief Removes the specified key-value pair from the table (const iterator overload). + /// + /// \detail \cpp + /// auto tbl = toml::table{ + /// { "a", 1 }, + /// { "b", 2 }, + /// { "c", 3 } + /// }; + /// std::cout << tbl << "\n"; + /// + /// tbl.erase(tbl.cbegin() + 1); + /// std::cout << tbl << "\n"; + /// \ecpp + /// + /// \out + /// { a = 1, b = 2, c = 3 } + /// { a = 1, c = 3 } + /// \eout + /// + /// \param pos Iterator to the key-value pair being erased. + /// + /// \returns Iterator to the first key-value pair immediately following the removed key-value + /// pair. + iterator erase(const_iterator pos) noexcept { return iterator{erase(const_map_iterator{pos})}; } + + /// \brief Removes the key-value pairs in the range [first, last) from the table. + /// + /// \detail \cpp + /// auto tbl = toml::table{ + /// { "a", 1 }, + /// { "b", "bad" }, + /// { "c", "karma" }, + /// { "d", 2 } + /// }; + /// std::cout << tbl << "\n"; + /// + /// tbl.erase(tbl.cbegin() + 1, tbl.cbegin() + 3); + /// std::cout << tbl << "\n"; + /// \ecpp + /// + /// \out + /// { a = 1, b = "bad", c = "karma", d = 2 } + /// { a = 1, d = 2 } + /// \eout + /// + /// \param begin Iterator to the first key-value pair being erased. + /// \param end Iterator to the one-past-the-last key-value pair being erased. + /// + /// \returns Iterator to the first key-value pair immediately following the last removed + /// key-value pair. + iterator erase(const_iterator begin, const_iterator end) noexcept { + return iterator{erase(const_map_iterator{begin}, const_map_iterator{end})}; + } + + /// \brief Removes the value with the given key from the table. + /// + /// \detail \cpp + /// auto tbl = toml::table{ + /// { "a", 1 }, + /// { "b", 2 }, + /// { "c", 3 } + /// }; + /// std::cout << tbl << "\n"; + /// + /// std::cout << tbl.erase("b") << "\n"; + /// std::cout << tbl.erase("not an existing key") << "\n"; + /// std::cout << tbl << "\n"; + /// \ecpp + /// + /// \out + /// { a = 1, b = 2, c = 3 } + /// true + /// false + /// { a = 1, c = 3 } + /// \eout + /// + /// \param key Key to erase. + /// + /// \returns Number of elements removed (0 or 1). + TOML_EXPORTED_MEMBER_FUNCTION + size_t erase(std::string_view key) noexcept; #if TOML_ENABLE_WINDOWS_COMPAT - /// \brief Removes the value with the given key from the table. - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \param key Key to erase. - /// - /// \returns Number of elements removed (0 or 1). - size_t erase(std::wstring_view key) - { - if (empty()) - return false; - - return erase(impl::narrow(key)); - } - -#endif // TOML_ENABLE_WINDOWS_COMPAT - - /// \brief Removes empty child arrays and tables. - /// - /// \detail \cpp - /// - /// auto tbl = toml::table{ { "a", 1 }, { "b", toml::array{ } }, { "c", toml::array{ toml::table{}, toml::array{} } } }; - /// std::cout << arr << "\n"; - /// - /// arr.prune(); - /// std::cout << arr << "\n"; - /// \ecpp - /// - /// \out - /// { a = 1, b = [], c = [ {}, [] ] } - /// { a = 1 } - /// \eout - /// - /// \param recursive Should child arrays and tables themselves be pruned? - /// - /// \returns A reference to the table. - TOML_EXPORTED_MEMBER_FUNCTION - table& prune(bool recursive = true) & noexcept; - - /// \brief Removes empty child arrays and tables (rvalue overload). - /// - /// \param recursive Should child arrays and tables themselves be pruned? - /// - /// \returns An rvalue reference to the table. - table&& prune(bool recursive = true) && noexcept - { - return static_cast<toml::table&&>(this->prune(recursive)); - } - - /// \brief Removes all key-value pairs from the table. - TOML_EXPORTED_MEMBER_FUNCTION - void clear() noexcept; - - /// @} - - /// \name Insertion and Emplacement - /// @{ - - private: - /// \cond - - TOML_EXPORTED_MEMBER_FUNCTION - map_iterator insert_with_hint(const_iterator, key&&, impl::node_ptr&&); - - /// \endcond - - public: - /// \brief Emplaces a new value at a specific key if one did not already exist. - /// - /// \tparam ValueType toml::table, toml::array, or any native TOML value type. - /// \tparam KeyType A toml::key or any compatible string type. - /// \tparam ValueArgs Value constructor argument types. - /// \param hint Iterator to the position before which the new element will be emplaced. - /// \param key The key at which to emplace the new value. - /// \param args Arguments to forward to the value's constructor. - /// - /// \returns An iterator to the emplacement position (or the position of the value that prevented emplacement) - /// - /// \note This function has exactly the same semantics as [std::map::emplace_hint()](https://en.cppreference.com/w/cpp/container/map/emplace_hint). - TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>), - typename ValueType = void, - typename KeyType, - typename... ValueArgs) - iterator emplace_hint(const_iterator hint, KeyType&& key, ValueArgs&&... args) - { - static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT, - "Emplacement using wide-character keys is only supported on Windows with " - "TOML_ENABLE_WINDOWS_COMPAT enabled."); - - using raw_value_type = impl::remove_cvref<ValueType>; - using value_type = std:: - conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>; - - if constexpr (impl::is_wide_string<KeyType>) - { + /// \brief Removes the value with the given key from the table. + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \param key Key to erase. + /// + /// \returns Number of elements removed (0 or 1). + size_t erase(std::wstring_view key) { + if (empty()) return false; + + return erase(impl::narrow(key)); + } + +#endif // TOML_ENABLE_WINDOWS_COMPAT + + /// \brief Removes empty child arrays and tables. + /// + /// \detail \cpp + /// + /// auto tbl = toml::table{ { "a", 1 }, { "b", toml::array{ } }, { "c", toml::array{ + /// toml::table{}, toml::array{} } } }; std::cout << arr << "\n"; + /// + /// arr.prune(); + /// std::cout << arr << "\n"; + /// \ecpp + /// + /// \out + /// { a = 1, b = [], c = [ {}, [] ] } + /// { a = 1 } + /// \eout + /// + /// \param recursive Should child arrays and tables themselves be pruned? + /// + /// \returns A reference to the table. + TOML_EXPORTED_MEMBER_FUNCTION + table& prune(bool recursive = true) & noexcept; + + /// \brief Removes empty child arrays and tables (rvalue overload). + /// + /// \param recursive Should child arrays and tables themselves be pruned? + /// + /// \returns An rvalue reference to the table. + table&& prune(bool recursive = true) && noexcept { + return static_cast<toml::table&&>(this->prune(recursive)); + } + + /// \brief Removes all key-value pairs from the table. + TOML_EXPORTED_MEMBER_FUNCTION + void clear() noexcept; + + /// @} + + /// \name Insertion and Emplacement + /// @{ + + private: + /// \cond + + TOML_EXPORTED_MEMBER_FUNCTION + map_iterator insert_with_hint(const_iterator, key&&, impl::node_ptr&&); + + /// \endcond + + public: + /// \brief Emplaces a new value at a specific key if one did not already exist. + /// + /// \tparam ValueType toml::table, toml::array, or any native TOML value type. + /// \tparam KeyType A toml::key or any compatible string type. + /// \tparam ValueArgs Value constructor argument types. + /// \param hint Iterator to the position before which the new element will be emplaced. + /// \param key The key at which to emplace the new value. + /// \param args Arguments to forward to the value's constructor. + /// + /// \returns An iterator to the emplacement position (or the position of the value that + /// prevented emplacement) + /// + /// \note This function has exactly the same semantics as + /// [std::map::emplace_hint()](https://en.cppreference.com/w/cpp/container/map/emplace_hint). + TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>), + typename ValueType = void, typename KeyType, typename... ValueArgs) + iterator emplace_hint(const_iterator hint, KeyType&& key, ValueArgs&&... args) { + static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT, + "Emplacement using wide-character keys is only supported on Windows with " + "TOML_ENABLE_WINDOWS_COMPAT enabled."); + + using raw_value_type = impl::remove_cvref<ValueType>; + using value_type = std::conditional_t<std::is_void_v<raw_value_type>, + impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>; + + if constexpr (impl::is_wide_string<KeyType>) { #if TOML_ENABLE_WINDOWS_COMPAT - return emplace_hint<value_type>(hint, - impl::narrow(static_cast<KeyType&&>(key)), - static_cast<ValueArgs&&>(args)...); + return emplace_hint<value_type>(hint, impl::narrow(static_cast<KeyType&&>(key)), + static_cast<ValueArgs&&>(args)...); #else - static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!"); + static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!"); #endif - } - else - { - static constexpr auto moving_node_ptr = std::is_same_v<value_type, impl::node_ptr> // - && sizeof...(ValueArgs) == 1u // - && impl::first_is_same<impl::node_ptr&&, ValueArgs&&...>; - using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>; - - static_assert(moving_node_ptr // - || impl::is_native<unwrapped_type> // - || impl::is_one_of<unwrapped_type, table, array>, // - "ValueType argument of table::emplace_hint() must be one " - "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); - - map_iterator ipos = insert_with_hint(hint, toml::key{ static_cast<KeyType&&>(key) }, nullptr); - - // if second is nullptr then we successully claimed the key and inserted the empty sentinel, - // so now we have to construct the actual value - if (!ipos->second) - { - if constexpr (moving_node_ptr) - ipos->second = std::move(static_cast<ValueArgs&&>(args)...); - else - { + } else { + static constexpr auto moving_node_ptr = + std::is_same_v<value_type, impl::node_ptr> // + && sizeof...(ValueArgs) == 1u // + && impl::first_is_same<impl::node_ptr&&, ValueArgs&&...>; + using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>; + + static_assert(moving_node_ptr // + || impl::is_native<unwrapped_type> // + || impl::is_one_of<unwrapped_type, table, array>, // + "ValueType argument of table::emplace_hint() must be one " + "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); + + map_iterator ipos = insert_with_hint(hint, toml::key{static_cast<KeyType&&>(key)}, nullptr); + + // if second is nullptr then we successully claimed the key and inserted the empty sentinel, + // so now we have to construct the actual value + if (!ipos->second) { + if constexpr (moving_node_ptr) + ipos->second = std::move(static_cast<ValueArgs&&>(args)...); + else { #if TOML_COMPILER_HAS_EXCEPTIONS - try - { + try { #endif - ipos->second.reset( - new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... }); + ipos->second.reset( + new impl::wrap_node<unwrapped_type>{static_cast<ValueArgs&&>(args)...}); #if TOML_COMPILER_HAS_EXCEPTIONS - } - catch (...) - { - erase(const_map_iterator{ ipos }); // strong exception guarantee - throw; - } + } catch (...) { + erase(const_map_iterator{ipos}); // strong exception guarantee + throw; + } #endif - } - } - return iterator{ ipos }; - } - } - - /// \brief Inserts a new value at a specific key if one did not already exist. - /// - /// \detail \godbolt{bMnW5r} - /// - /// \cpp - /// auto tbl = toml::table{ - /// { "a", 1 }, - /// { "b", 2 }, - /// { "c", 3 } - /// }; - /// std::cout << tbl << "\n"; - /// - /// for (auto k : { "a", "d" }) - /// { - /// auto result = tbl.insert(k, 42); - /// std::cout << "inserted with key '"sv << k << "': "sv << result.second << "\n"; - /// } - /// std::cout << tbl << "\n"; - /// \ecpp - /// - /// \out - /// a = 1 - /// b = 2 - /// c = 3 - /// - /// inserted with key 'a': false - /// inserted with key 'd': true - /// a = 1 - /// b = 2 - /// c = 3 - /// d = 42 - /// \eout - /// - /// \tparam KeyType A toml::key or any compatible string type. - /// \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. - /// \param flags Value flags to apply to new values. - /// - /// \returns \conditional_return{Valid input} - /// <ul> - /// <li>An iterator to the insertion position (or the position of the value that prevented insertion) - /// <li>A boolean indicating if the insertion was successful. - /// </ul> - /// \conditional_return{Input is a null toml::node_view} - /// `{ end(), false }` - /// - /// \attention The return value will always be `{ end(), false }` if the input value was an - /// null toml::node_view, because no insertion can take place. This is the only circumstance - /// in which this can occur. - TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>), - typename KeyType, - typename ValueType) - std::pair<iterator, bool> insert(KeyType&& key, - ValueType&& val, - value_flags flags = preserve_source_value_flags) - { - static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT, - "Insertion using wide-character keys is only supported on Windows with " - "TOML_ENABLE_WINDOWS_COMPAT enabled."); - - if constexpr (is_node_view<ValueType>) - { - if (!val) - return { end(), false }; - } - - if constexpr (impl::is_wide_string<KeyType>) - { + } + } + return iterator{ipos}; + } + } + + /// \brief Inserts a new value at a specific key if one did not already exist. + /// + /// \detail \godbolt{bMnW5r} + /// + /// \cpp + /// auto tbl = toml::table{ + /// { "a", 1 }, + /// { "b", 2 }, + /// { "c", 3 } + /// }; + /// std::cout << tbl << "\n"; + /// + /// for (auto k : { "a", "d" }) + /// { + /// auto result = tbl.insert(k, 42); + /// std::cout << "inserted with key '"sv << k << "': "sv << result.second << "\n"; + /// } + /// std::cout << tbl << "\n"; + /// \ecpp + /// + /// \out + /// a = 1 + /// b = 2 + /// c = 3 + /// + /// inserted with key 'a': false + /// inserted with key 'd': true + /// a = 1 + /// b = 2 + /// c = 3 + /// d = 42 + /// \eout + /// + /// \tparam KeyType A toml::key or any compatible string type. + /// \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. + /// \param flags Value flags to apply to new values. + /// + /// \returns \conditional_return{Valid input} + /// <ul> + /// <li>An iterator to the insertion position (or the position of the value that + /// prevented insertion) <li>A boolean indicating if the insertion was successful. + /// </ul> + /// \conditional_return{Input is a null toml::node_view} + /// `{ end(), false }` + /// + /// \attention The return value will always be `{ end(), false }` if the input value was an + /// null toml::node_view, because no insertion can take place. This is the only + /// circumstance in which this can occur. + TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>), + typename KeyType, typename ValueType) + std::pair<iterator, bool> insert(KeyType&& key, ValueType&& val, + value_flags flags = preserve_source_value_flags) { + static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT, + "Insertion using wide-character keys is only supported on Windows with " + "TOML_ENABLE_WINDOWS_COMPAT enabled."); + + if constexpr (is_node_view<ValueType>) { + if (!val) return {end(), false}; + } + + if constexpr (impl::is_wide_string<KeyType>) { #if TOML_ENABLE_WINDOWS_COMPAT - return insert(impl::narrow(static_cast<KeyType&&>(key)), static_cast<ValueType&&>(val), flags); + return insert(impl::narrow(static_cast<KeyType&&>(key)), static_cast<ValueType&&>(val), + flags); #else - static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!"); + static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!"); #endif - } - else - { - const auto key_view = std::string_view{ key }; - map_iterator ipos = get_lower_bound(key_view); - if (ipos == map_.end() || ipos->first != key_view) - { - ipos = insert_with_hint(const_iterator{ ipos }, - toml::key{ static_cast<KeyType&&>(key) }, - impl::make_node(static_cast<ValueType&&>(val), flags)); - return { iterator{ ipos }, true }; - } - return { iterator{ ipos }, false }; - } - } - - /// \brief Inserts a series of key-value pairs into the table. - /// - /// \detail \godbolt{bzYcce} - /// - /// \cpp - /// auto tbl = toml::table{ - /// { "a", 1 }, - /// { "b", 2 }, - /// { "c", 3 } - /// }; - /// std::cout << tbl << "\n"; - /// - /// auto kvps = std::array<std::pair<std::string, int>, 2>{{ - /// { "d", 42 }, - /// { "a", 43 } // won't be inserted, 'a' already exists - /// }}; - /// tbl.insert(kvps.begin(), kvps.end()); - /// std::cout << tbl << "\n"; - /// \ecpp - /// - /// \out - /// a = 1 - /// b = 2 - /// c = 3 - /// - /// a = 1 - /// b = 2 - /// c = 3 - /// d = 42 - /// \eout - /// - /// \tparam Iter An InputIterator to a collection of key-value pairs. - /// \param begin An iterator to the first value in the input collection. - /// \param end An iterator to one-past-the-last value in the input collection. - /// \param flags Value flags to apply to new values. - /// - /// \remarks This function is morally equivalent to calling `insert(key, value)` for each - /// key-value pair covered by the iterator range, so any values with keys already found in the - /// table will not be replaced. - TOML_CONSTRAINED_TEMPLATE((!is_key_or_convertible<Iter> && !impl::is_wide_string<Iter>), typename Iter) - void insert(Iter begin, Iter end, value_flags flags = preserve_source_value_flags) - { - if (begin == end) - return; - for (auto it = begin; it != end; it++) - { - if constexpr (std::is_rvalue_reference_v<decltype(*it)>) - insert(std::move((*it).first), std::move((*it).second), flags); - else - insert((*it).first, (*it).second, flags); - } - } - - /// \brief Inserts or assigns a value at a specific key. - /// - /// \detail \godbolt{ddK563} - /// - /// \cpp - /// auto tbl = toml::table{ - /// { "a", 1 }, - /// { "b", 2 }, - /// { "c", 3 } - /// }; - /// std::cout << tbl << "\n"; - /// - /// for (auto k : { "a", "d" }) - /// { - /// auto result = tbl.insert_or_assign(k, 42); - /// std::cout << "value at key '"sv << k - /// << "' was "sv << (result.second ? "inserted"sv : "assigned"sv) << "\n"; - /// } - /// std::cout << tbl << "\n"; - /// \ecpp - /// - /// \out - /// a = 1 - /// b = 2 - /// c = 3 - /// - /// value at key 'a' was assigned - /// value at key 'd' was inserted - /// a = 42 - /// b = 2 - /// c = 3 - /// d = 42 - /// \eout - /// - /// \tparam KeyType A toml::key or any compatible string type. - /// \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. - /// \param flags Value flags to apply to new values. - /// - /// \returns \conditional_return{Valid input} - /// <ul> - /// <li>An iterator to the value's position - /// <li>`true` if the value was inserted, `false` if it was assigned. - /// </ul> - /// \conditional_return{Input is a null toml::node_view} - /// `{ end(), false }` - /// - /// \attention The return value will always be `{ end(), false }` if the input value was - /// a null toml::node_view, because no insertion or assignment can take place. - /// This is the only circumstance in which this can occur. - TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>), - typename KeyType, - typename ValueType) - std::pair<iterator, bool> insert_or_assign(KeyType&& key, - ValueType&& val, - value_flags flags = preserve_source_value_flags) - { - static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT, - "Insertion using wide-character keys is only supported on Windows with " - "TOML_ENABLE_WINDOWS_COMPAT enabled."); - - if constexpr (is_node_view<ValueType>) - { - if (!val) - return { end(), false }; - } - - if constexpr (impl::is_wide_string<KeyType>) - { + } else { + const auto key_view = std::string_view{key}; + map_iterator ipos = get_lower_bound(key_view); + if (ipos == map_.end() || ipos->first != key_view) { + ipos = insert_with_hint(const_iterator{ipos}, toml::key{static_cast<KeyType&&>(key)}, + impl::make_node(static_cast<ValueType&&>(val), flags)); + return {iterator{ipos}, true}; + } + return {iterator{ipos}, false}; + } + } + + /// \brief Inserts a series of key-value pairs into the table. + /// + /// \detail \godbolt{bzYcce} + /// + /// \cpp + /// auto tbl = toml::table{ + /// { "a", 1 }, + /// { "b", 2 }, + /// { "c", 3 } + /// }; + /// std::cout << tbl << "\n"; + /// + /// auto kvps = std::array<std::pair<std::string, int>, 2>{{ + /// { "d", 42 }, + /// { "a", 43 } // won't be inserted, 'a' already exists + /// }}; + /// tbl.insert(kvps.begin(), kvps.end()); + /// std::cout << tbl << "\n"; + /// \ecpp + /// + /// \out + /// a = 1 + /// b = 2 + /// c = 3 + /// + /// a = 1 + /// b = 2 + /// c = 3 + /// d = 42 + /// \eout + /// + /// \tparam Iter An InputIterator to a collection of key-value pairs. + /// \param begin An iterator to the first value in the input collection. + /// \param end An iterator to one-past-the-last value in the input collection. + /// \param flags Value flags to apply to new values. + /// + /// \remarks This function is morally equivalent to calling `insert(key, value)` for each + /// key-value pair covered by the iterator range, so any values with keys already found in + /// the table will not be replaced. + TOML_CONSTRAINED_TEMPLATE((!is_key_or_convertible<Iter> && !impl::is_wide_string<Iter>), + typename Iter) + void insert(Iter begin, Iter end, value_flags flags = preserve_source_value_flags) { + if (begin == end) return; + for (auto it = begin; it != end; it++) { + if constexpr (std::is_rvalue_reference_v<decltype(*it)>) + insert(std::move((*it).first), std::move((*it).second), flags); + else + insert((*it).first, (*it).second, flags); + } + } + + /// \brief Inserts or assigns a value at a specific key. + /// + /// \detail \godbolt{ddK563} + /// + /// \cpp + /// auto tbl = toml::table{ + /// { "a", 1 }, + /// { "b", 2 }, + /// { "c", 3 } + /// }; + /// std::cout << tbl << "\n"; + /// + /// for (auto k : { "a", "d" }) + /// { + /// auto result = tbl.insert_or_assign(k, 42); + /// std::cout << "value at key '"sv << k + /// << "' was "sv << (result.second ? "inserted"sv : "assigned"sv) << "\n"; + /// } + /// std::cout << tbl << "\n"; + /// \ecpp + /// + /// \out + /// a = 1 + /// b = 2 + /// c = 3 + /// + /// value at key 'a' was assigned + /// value at key 'd' was inserted + /// a = 42 + /// b = 2 + /// c = 3 + /// d = 42 + /// \eout + /// + /// \tparam KeyType A toml::key or any compatible string type. + /// \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. + /// \param flags Value flags to apply to new values. + /// + /// \returns \conditional_return{Valid input} + /// <ul> + /// <li>An iterator to the value's position + /// <li>`true` if the value was inserted, `false` if it was assigned. + /// </ul> + /// \conditional_return{Input is a null toml::node_view} + /// `{ end(), false }` + /// + /// \attention The return value will always be `{ end(), false }` if the input value was + /// a null toml::node_view, because no insertion or assignment can take place. + /// This is the only circumstance in which this can occur. + TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>), + typename KeyType, typename ValueType) + std::pair<iterator, bool> insert_or_assign(KeyType&& key, ValueType&& val, + value_flags flags = preserve_source_value_flags) { + static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT, + "Insertion using wide-character keys is only supported on Windows with " + "TOML_ENABLE_WINDOWS_COMPAT enabled."); + + if constexpr (is_node_view<ValueType>) { + if (!val) return {end(), false}; + } + + if constexpr (impl::is_wide_string<KeyType>) { #if TOML_ENABLE_WINDOWS_COMPAT - return insert_or_assign(impl::narrow(static_cast<KeyType&&>(key)), - static_cast<ValueType&&>(val), - flags); + return insert_or_assign(impl::narrow(static_cast<KeyType&&>(key)), + static_cast<ValueType&&>(val), flags); #else - static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!"); + static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!"); #endif - } - else - { - const auto key_view = std::string_view{ key }; - map_iterator ipos = get_lower_bound(key_view); - if (ipos == map_.end() || ipos->first != key_view) - { - ipos = insert_with_hint(const_iterator{ ipos }, - toml::key{ static_cast<KeyType&&>(key) }, - impl::make_node(static_cast<ValueType&&>(val), flags)); - return { iterator{ ipos }, true }; - } - else - { - (*ipos).second = impl::make_node(static_cast<ValueType&&>(val), flags); - return { iterator{ ipos }, false }; - } - } - } - - /// \brief Emplaces a new value at a specific key if one did not already exist. - /// - /// \detail \cpp - /// auto tbl = toml::table{ - /// { "a", 1 }, - /// { "b", 2 }, - /// { "c", 3 } - /// }; - /// std::cout << tbl << "\n"; - /// - /// for (auto k : { "a", "d" }) - /// { - /// // add a string using std::string's substring constructor - /// auto result = tbl.emplace<std::string>(k, "this is not a drill"sv, 14, 5); - /// std::cout << "emplaced with key '"sv << k << "': "sv << result.second << "\n"; - /// } - /// std::cout << tbl << "\n"; - /// \ecpp - /// - /// \out - /// { a = 1, b = 2, c = 3 } - /// emplaced with key 'a': false - /// emplaced with key 'd': true - /// { a = 1, b = 2, c = 3, d = "drill" } - /// \eout - /// - /// \tparam ValueType toml::table, toml::array, or any native TOML value type. - /// \tparam KeyType A toml::key or any compatible string type. - /// \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: <br> - /// - An iterator to the emplacement position (or the position of the value that prevented emplacement) - /// - A boolean indicating if the emplacement was successful. - /// - /// \remark There is no difference between insert() and emplace() for trivial value types (floats, ints, bools). - TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>), - typename ValueType = void, - typename KeyType, - typename... ValueArgs) - std::pair<iterator, bool> emplace(KeyType&& key, ValueArgs&&... args) - { - static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT, - "Emplacement using wide-character keys is only supported on Windows with " - "TOML_ENABLE_WINDOWS_COMPAT enabled."); - - using raw_value_type = impl::remove_cvref<ValueType>; - using value_type = std:: - conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>; - - if constexpr (impl::is_wide_string<KeyType>) - { + } else { + const auto key_view = std::string_view{key}; + map_iterator ipos = get_lower_bound(key_view); + if (ipos == map_.end() || ipos->first != key_view) { + ipos = insert_with_hint(const_iterator{ipos}, toml::key{static_cast<KeyType&&>(key)}, + impl::make_node(static_cast<ValueType&&>(val), flags)); + return {iterator{ipos}, true}; + } else { + (*ipos).second = impl::make_node(static_cast<ValueType&&>(val), flags); + return {iterator{ipos}, false}; + } + } + } + + /// \brief Emplaces a new value at a specific key if one did not already exist. + /// + /// \detail \cpp + /// auto tbl = toml::table{ + /// { "a", 1 }, + /// { "b", 2 }, + /// { "c", 3 } + /// }; + /// std::cout << tbl << "\n"; + /// + /// for (auto k : { "a", "d" }) + /// { + /// // add a string using std::string's substring constructor + /// auto result = tbl.emplace<std::string>(k, "this is not a drill"sv, 14, 5); + /// std::cout << "emplaced with key '"sv << k << "': "sv << result.second << "\n"; + /// } + /// std::cout << tbl << "\n"; + /// \ecpp + /// + /// \out + /// { a = 1, b = 2, c = 3 } + /// emplaced with key 'a': false + /// emplaced with key 'd': true + /// { a = 1, b = 2, c = 3, d = "drill" } + /// \eout + /// + /// \tparam ValueType toml::table, toml::array, or any native TOML value type. + /// \tparam KeyType A toml::key or any compatible string type. + /// \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: <br> + /// - An iterator to the emplacement position (or the position of the value that prevented + /// emplacement) + /// - A boolean indicating if the emplacement was successful. + /// + /// \remark There is no difference between insert() and emplace() for trivial value types + /// (floats, ints, bools). + TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>), + typename ValueType = void, typename KeyType, typename... ValueArgs) + std::pair<iterator, bool> emplace(KeyType&& key, ValueArgs&&... args) { + static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT, + "Emplacement using wide-character keys is only supported on Windows with " + "TOML_ENABLE_WINDOWS_COMPAT enabled."); + + using raw_value_type = impl::remove_cvref<ValueType>; + using value_type = std::conditional_t<std::is_void_v<raw_value_type>, + impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>; + + if constexpr (impl::is_wide_string<KeyType>) { #if TOML_ENABLE_WINDOWS_COMPAT - return emplace<value_type>(impl::narrow(static_cast<KeyType&&>(key)), - static_cast<ValueArgs&&>(args)...); + return emplace<value_type>(impl::narrow(static_cast<KeyType&&>(key)), + static_cast<ValueArgs&&>(args)...); #else - static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!"); + static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!"); #endif - } - else - { - using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>; - static_assert((impl::is_native<unwrapped_type> || impl::is_one_of<unwrapped_type, table, array>), - "ValueType argument of table::emplace() must be one " - "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); - - const auto key_view = std::string_view{ key }; - auto ipos = get_lower_bound(key_view); - if (ipos == map_.end() || ipos->first != key_view) - { - ipos = insert_with_hint( - const_iterator{ ipos }, - toml::key{ static_cast<KeyType&&>(key) }, - impl::node_ptr{ new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... } }); - return { iterator{ ipos }, true }; - } - return { iterator{ ipos }, false }; - } - } - - /// @} - - /// \name Node views - /// @{ - - /// \cond - using node::operator[]; // inherit operator[toml::path] - /// \endcond - - /// \brief Gets a node_view for the selected value. - /// - /// \param key The key used for the lookup. - /// - /// \returns A view of the value at the given key if one existed, or an empty node view. - /// - /// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it - /// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it. - /// <strong>This is not an error.</strong> - /// - /// \see toml::node_view - TOML_NODISCARD - node_view<node> operator[](std::string_view key) noexcept - { - return node_view<node>{ get(key) }; - } - - /// \brief Gets a node_view for the selected value (const overload). - /// - /// \param key The key used for the lookup. - /// - /// \returns A view of the value at the given key if one existed, or an empty node view. - /// - /// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it - /// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it. - /// <strong>This is not an error.</strong> - /// - /// \see toml::node_view - TOML_NODISCARD - node_view<const node> operator[](std::string_view key) const noexcept - { - return node_view<const node>{ get(key) }; - } + } else { + using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>; + static_assert( + (impl::is_native<unwrapped_type> || impl::is_one_of<unwrapped_type, table, array>), + "ValueType argument of table::emplace() must be one " + "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); + + const auto key_view = std::string_view{key}; + auto ipos = get_lower_bound(key_view); + if (ipos == map_.end() || ipos->first != key_view) { + ipos = insert_with_hint(const_iterator{ipos}, toml::key{static_cast<KeyType&&>(key)}, + impl::node_ptr{new impl::wrap_node<unwrapped_type>{ + static_cast<ValueArgs&&>(args)...}}); + return {iterator{ipos}, true}; + } + return {iterator{ipos}, false}; + } + } + + /// @} + + /// \name Node views + /// @{ + + /// \cond + using node::operator[]; // inherit operator[toml::path] + /// \endcond + + /// \brief Gets a node_view for the selected value. + /// + /// \param key The key used for the lookup. + /// + /// \returns A view of the value at the given key if one existed, or an empty node view. + /// + /// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it + /// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it. + /// <strong>This is not an error.</strong> + /// + /// \see toml::node_view + TOML_NODISCARD + node_view<node> operator[](std::string_view key) noexcept { return node_view<node>{get(key)}; } + + /// \brief Gets a node_view for the selected value (const overload). + /// + /// \param key The key used for the lookup. + /// + /// \returns A view of the value at the given key if one existed, or an empty node view. + /// + /// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it + /// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it. + /// <strong>This is not an error.</strong> + /// + /// \see toml::node_view + TOML_NODISCARD + node_view<const node> operator[](std::string_view key) const noexcept { + return node_view<const node>{get(key)}; + } #if TOML_ENABLE_WINDOWS_COMPAT - /// \brief Gets a node_view for the selected value. - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \param key The key used for the lookup. - /// - /// \returns A view of the value at the given key if one existed, or an empty node view. - /// - /// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it - /// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it. - /// <strong>This is not an error.</strong> - /// - /// \see toml::node_view - TOML_NODISCARD - node_view<node> operator[](std::wstring_view key) - { - return node_view<node>{ get(key) }; - } - - /// \brief Gets a node_view for the selected value (const overload). - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \param key The key used for the lookup. - /// - /// \returns A view of the value at the given key if one existed, or an empty node view. - /// - /// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it - /// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it. - /// <strong>This is not an error.</strong> - /// - /// \see toml::node_view - TOML_NODISCARD - node_view<const node> operator[](std::wstring_view key) const - { - return node_view<const node>{ get(key) }; - } - -#endif // TOML_ENABLE_WINDOWS_COMPAT - - /// @} - - /// \name Equality - /// @{ - - private: - /// \cond - - TOML_PURE_GETTER - TOML_EXPORTED_STATIC_FUNCTION - static bool TOML_CALLCONV equal(const table&, const table&) noexcept; - - /// \endcond - public: - /// \brief Equality operator. - /// - /// \param lhs The LHS table. - /// \param rhs The RHS table. - /// - /// \returns True if the tables contained the same keys and map. - TOML_NODISCARD - friend bool operator==(const table& lhs, const table& rhs) noexcept - { - return equal(lhs, rhs); - } - - /// \brief Inequality operator. - /// - /// \param lhs The LHS table. - /// \param rhs The RHS table. - /// - /// \returns True if the tables did not contain the same keys and map. - TOML_NODISCARD - friend bool operator!=(const table& lhs, const table& rhs) noexcept - { - return !equal(lhs, rhs); - } - - /// @} + /// \brief Gets a node_view for the selected value. + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \param key The key used for the lookup. + /// + /// \returns A view of the value at the given key if one existed, or an empty node view. + /// + /// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it + /// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it. + /// <strong>This is not an error.</strong> + /// + /// \see toml::node_view + TOML_NODISCARD + node_view<node> operator[](std::wstring_view key) { return node_view<node>{get(key)}; } + + /// \brief Gets a node_view for the selected value (const overload). + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \param key The key used for the lookup. + /// + /// \returns A view of the value at the given key if one existed, or an empty node view. + /// + /// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it + /// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it. + /// <strong>This is not an error.</strong> + /// + /// \see toml::node_view + TOML_NODISCARD + node_view<const node> operator[](std::wstring_view key) const { + return node_view<const node>{get(key)}; + } + +#endif // TOML_ENABLE_WINDOWS_COMPAT + + /// @} + + /// \name Equality + /// @{ + + private: + /// \cond + + TOML_PURE_GETTER + TOML_EXPORTED_STATIC_FUNCTION + static bool TOML_CALLCONV equal(const table&, const table&) noexcept; + + /// \endcond + public: + /// \brief Equality operator. + /// + /// \param lhs The LHS table. + /// \param rhs The RHS table. + /// + /// \returns True if the tables contained the same keys and map. + TOML_NODISCARD + friend bool operator==(const table& lhs, const table& rhs) noexcept { return equal(lhs, rhs); } + + /// \brief Inequality operator. + /// + /// \param lhs The LHS table. + /// \param rhs The RHS table. + /// + /// \returns True if the tables did not contain the same keys and map. + TOML_NODISCARD + friend bool operator!=(const table& lhs, const table& rhs) noexcept { return !equal(lhs, rhs); } + + /// @} #if TOML_ENABLE_FORMATTERS - /// \brief Prints the table out to a stream as formatted TOML. - /// - /// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled. - friend std::ostream& operator<<(std::ostream& lhs, const table& rhs) - { - impl::print_to_stream(lhs, rhs); - return lhs; - } + /// \brief Prints the table out to a stream as formatted TOML. + /// + /// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled. + friend std::ostream& operator<<(std::ostream& lhs, const table& rhs) { + impl::print_to_stream(lhs, rhs); + return lhs; + } #endif - }; + }; } TOML_NAMESPACE_END; |
