//# This file is a part of toml++ and is subject to the the terms of the MIT license. //# Copyright (c) Mark Gillard //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. // SPDX-License-Identifier: MIT #pragma once #include "array.h" #include "make_node.h" #include "std_map.h" #include "node_view.h" #include "header_start.h" /// \cond TOML_IMPL_NAMESPACE_START { template struct table_proxy_pair final { using value_type = std::conditional_t; const std::string& first; value_type& second; }; template class table_iterator final { private: template friend class table_iterator; friend class TOML_NAMESPACE::table; using proxy_type = table_proxy_pair; using raw_mutable_iterator = std::map, std::less<>>::iterator; using raw_const_iterator = std::map, std::less<>>::const_iterator; using raw_iterator = std::conditional_t; mutable raw_iterator raw_; mutable std::aligned_storage_t proxy; mutable bool proxy_instantiated = false; TOML_NODISCARD proxy_type* get_proxy() const noexcept { if (!proxy_instantiated) { auto p = ::new (static_cast(&proxy)) proxy_type{ raw_->first, *raw_->second.get() }; proxy_instantiated = true; return p; } else return TOML_LAUNDER(reinterpret_cast(&proxy)); } TOML_NODISCARD_CTOR table_iterator(raw_mutable_iterator raw) noexcept // : raw_{ raw } {} TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst) TOML_NODISCARD_CTOR table_iterator(raw_const_iterator raw) noexcept // : raw_{ raw } {} public: TOML_NODISCARD_CTOR table_iterator() noexcept = default; TOML_NODISCARD_CTOR table_iterator(const table_iterator& other) noexcept // : raw_{ other.raw_ } {} table_iterator& operator=(const table_iterator& rhs) noexcept { raw_ = rhs.raw_; proxy_instantiated = false; return *this; } using value_type = table_proxy_pair; using reference = value_type&; using pointer = value_type*; using difference_type = typename std::iterator_traits::difference_type; using iterator_category = typename std::iterator_traits::iterator_category; table_iterator& operator++() noexcept // ++pre { ++raw_; proxy_instantiated = false; return *this; } table_iterator operator++(int) noexcept // post++ { table_iterator out{ raw_ }; ++raw_; proxy_instantiated = false; return out; } table_iterator& operator--() noexcept // --pre { --raw_; proxy_instantiated = false; return *this; } table_iterator operator--(int) noexcept // post-- { table_iterator out{ raw_ }; --raw_; proxy_instantiated = false; return out; } TOML_NODISCARD reference operator*() const noexcept { return *get_proxy(); } TOML_NODISCARD pointer operator->() const noexcept { return get_proxy(); } TOML_NODISCARD friend bool operator==(const table_iterator& lhs, const table_iterator& rhs) noexcept { return lhs.raw_ == rhs.raw_; } TOML_NODISCARD friend bool operator!=(const table_iterator& lhs, const table_iterator& rhs) noexcept { return lhs.raw_ != rhs.raw_; } TOML_DISABLE_WARNINGS; TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst) TOML_NODISCARD operator table_iterator() const noexcept { return table_iterator{ raw_ }; } TOML_ENABLE_WARNINGS; }; struct table_init_pair final { std::string key; std::unique_ptr value; template TOML_NODISCARD_CTOR table_init_pair(std::string&& k, V&& v) noexcept // : key{ std::move(k) }, value{ make_node(static_cast(v)) } {} template TOML_NODISCARD_CTOR table_init_pair(std::string_view k, V&& v) noexcept // : key{ k }, value{ make_node(static_cast(v)) } {} template TOML_NODISCARD_CTOR table_init_pair(const char* k, V&& v) noexcept // : key{ k }, value{ make_node(static_cast(v)) } {} #if TOML_WINDOWS_COMPAT template TOML_NODISCARD_CTOR table_init_pair(std::wstring&& k, V&& v) noexcept // : key{ narrow(k) }, value{ make_node(static_cast(v)) } {} template TOML_NODISCARD_CTOR table_init_pair(std::wstring_view k, V&& v) noexcept // : key{ narrow(k) }, value{ make_node(static_cast(v)) } {} template TOML_NODISCARD_CTOR table_init_pair(const wchar_t* k, V&& v) noexcept // : key{ narrow(std::wstring_view{ k }) }, value{ make_node(static_cast(v)) } {} #endif }; } 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); /// \brief A BidirectionalIterator for iterating over const key-value pairs in a toml::table. using const_table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator); /// \brief A TOML table. /// /// \remarks The interface of this type is modeled after std::map, with some /// additional considerations made for the heterogeneous nature of a /// TOML table, and for the removal of some cruft (the public interface of /// std::map is, simply, _a hot mess_). class table final : public node { private: /// \cond friend class TOML_PARSER_TYPENAME; std::map, std::less<>> map_; bool inline_ = false; TOML_NODISCARD_CTOR TOML_API table(impl::table_init_pair*, size_t) noexcept; template TOML_NODISCARD static auto do_get(Map& vals, const Key& key) noexcept -> std::conditional_t, const node*, node*> { static_assert( !impl::is_wide_string || TOML_WINDOWS_COMPAT, "Retrieval using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."); if constexpr (impl::is_wide_string) { #if TOML_WINDOWS_COMPAT return do_get(vals, impl::narrow(key)); #else static_assert(impl::dependent_false, "Evaluated unreachable branch!"); #endif } else { if (auto it = vals.find(key); it != vals.end()) return { it->second.get() }; return {}; } } template TOML_NODISCARD static auto do_get_as(Map& vals, const Key& key) noexcept { const auto node = do_get(vals, key); return node ? node->template as() : nullptr; } template TOML_NODISCARD TOML_ALWAYS_INLINE static bool do_contains(Map& vals, const Key& key) noexcept { return do_get(vals, key) != nullptr; } /// \endcond public: /// \brief A BidirectionalIterator for iterating over key-value pairs in a toml::table. using iterator = table_iterator; /// \brief A BidirectionalIterator for iterating over const key-value pairs in a toml::table. using const_iterator = const_table_iterator; #if TOML_LIFETIME_HOOKS TOML_NODISCARD_CTOR table() noexcept { TOML_TABLE_CREATED; } ~table() noexcept { TOML_TABLE_DESTROYED; } #else /// \brief Default constructor. TOML_NODISCARD_CTOR table() noexcept = default; #endif /// \brief Copy constructor. TOML_NODISCARD_CTOR TOML_API table(const table&) noexcept; /// \brief Move constructor. TOML_NODISCARD_CTOR TOML_API table(table&& other) noexcept; /// \brief Copy-assignment operator. TOML_API table& operator=(const table&) noexcept; /// \brief Move-assignment operator. TOML_API table& operator=(table&& rhs) noexcept; /// \brief Constructs a table with one or more initial key-value pairs. /// /// \detail \cpp /// auto tbl = toml::table{{ // double braces required :( - see remark /// { "foo", 1 }, /// { "bar", 2.0 }, /// { "kek", "three" } /// }}; /// std::cout << tbl << "\n"; /// /// \ecpp /// /// \out /// { foo = 1, bar = 2.0, kek = "three" } /// \eout /// /// \tparam N Number of key-value pairs used to initialize the table. /// \param arr An array of key-value pairs used to initialize the table. /// /// \remarks C++ std::initializer_lists represent their member elements as /// const even if the list's value type is non-const. This is great for /// compiler writers, I guess, but pretty annoying for me since /// TOML key-value pairs are polymorphic (and thus move-only). This means /// that for the human-friendly braced init list syntax to work I can't use /// std::initializer_list and must instead invent an annoying proxy type, /// which means an extra level of nesting. ///

/// See https://en.cppreference.com/w/cpp/utility/initializer_list /// if you'd like to learn more about this. template TOML_NODISCARD_CTOR explicit table(impl::table_init_pair(&&arr)[N]) noexcept // : table{ arr, N } { #if TOML_LIFETIME_HOOKS TOML_TABLE_CREATED; #endif } /// \name Type checks /// @{ TOML_NODISCARD node_type type() const noexcept final { return node_type::table; } TOML_NODISCARD bool is_table() const noexcept final { return true; } TOML_NODISCARD bool is_homogeneous(node_type ntype) const noexcept final; TOML_NODISCARD bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final; TOML_NODISCARD bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final; template TOML_NODISCARD bool is_homogeneous() const noexcept { using type = impl::unwrap_node; static_assert( std::is_void_v< type> || ((impl::is_native || impl::is_one_of)&&!impl::is_cvref), "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); } /// @} /// \name Type casts /// @{ TOML_NODISCARD table* as_table() noexcept final { return this; } TOML_NODISCARD const table* as_table() const noexcept final { return this; } /// @} /// \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_NODISCARD 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 Node views /// @{ /// \brief Gets a node_view for the selected key-value pair. /// /// \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. /// This is not an error. /// /// \see toml::node_view TOML_NODISCARD node_view operator[](std::string_view key) noexcept { return node_view{ this->get(key) }; } /// \brief Gets a node_view for the selected key-value pair (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. /// This is not an error. /// /// \see toml::node_view TOML_NODISCARD node_view operator[](std::string_view key) const noexcept { return node_view{ this->get(key) }; } #if TOML_WINDOWS_COMPAT /// \brief Gets a node_view for the selected key-value pair. /// /// \availability This overload is only available when #TOML_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. /// This is not an error. /// /// \see toml::node_view TOML_NODISCARD node_view operator[](std::wstring_view key) noexcept { return node_view{ this->get(key) }; } /// \brief Gets a node_view for the selected key-value pair (const overload). /// /// \availability This overload is only available when #TOML_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. /// This is not an error. /// /// \see toml::node_view TOML_NODISCARD node_view operator[](std::wstring_view key) const noexcept { return node_view{ this->get(key) }; } #endif // TOML_WINDOWS_COMPAT /// @} /// \name Table operations /// @{ /// \brief Returns an iterator to the first key-value pair. TOML_NODISCARD iterator begin() noexcept { return { map_.begin() }; } /// \brief Returns an iterator to the first key-value pair. TOML_NODISCARD const_iterator begin() const noexcept { return { map_.cbegin() }; } /// \brief Returns an iterator to the first key-value pair. TOML_NODISCARD const_iterator cbegin() const noexcept { return { map_.cbegin() }; } /// \brief Returns an iterator to one-past-the-last key-value pair. TOML_NODISCARD iterator end() noexcept { return { map_.end() }; } /// \brief Returns an iterator to one-past-the-last key-value pair. TOML_NODISCARD const_iterator end() const noexcept { return { map_.cend() }; } /// \brief Returns an iterator to one-past-the-last key-value pair. TOML_NODISCARD const_iterator cend() const noexcept { return { map_.cend() }; } /// \brief Returns true if the table is empty. TOML_NODISCARD bool empty() const noexcept { return map_.empty(); } /// \brief Returns the number of key-value pairs in the table. TOML_NODISCARD size_t size() const noexcept { return map_.size(); } /// \brief Removes all key-value pairs from the table. void clear() noexcept { map_.clear(); } /// \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 std::string (or a type convertible to it). /// \tparam ValueType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type /// (or a type promotable to one). /// \param key The key at which to insert the new value. /// \param val The new value to insert. /// /// \returns \conditional_return{Valid input} ///
    ///
  • An iterator to the insertion position (or the position of the value that prevented insertion) ///
  • A boolean indicating if the insertion was successful. ///
/// \conditional_return{Input is an empty toml::node_view} /// `{ end(), false }` /// /// \attention The return value will always be `{ end(), false }` if the input value was an /// empty toml::node_view, because no insertion can take place. This is the only circumstance /// in which this can occur. TOML_CONSTRAINED_TEMPLATE((std::is_convertible_v || impl::is_wide_string), typename KeyType, typename ValueType) std::pair insert(KeyType&& key, ValueType&& val) noexcept { static_assert( !impl::is_wide_string || TOML_WINDOWS_COMPAT, "Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."); if constexpr (is_node_view) { if (!val) return { end(), false }; } if constexpr (impl::is_wide_string) { #if TOML_WINDOWS_COMPAT return insert(impl::narrow(std::forward(key)), std::forward(val)); #else static_assert(impl::dependent_false, "Evaluated unreachable branch!"); #endif } else { auto ipos = map_.lower_bound(key); if (ipos == map_.end() || ipos->first != key) { ipos = map_.emplace_hint(ipos, std::forward(key), impl::make_node(std::forward(val))); 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, 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 first An iterator to the first value in the input collection. /// \param last An iterator to one-past-the-last value in the input collection. /// /// \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((!std::is_convertible_v && !impl::is_wide_string), typename Iter) void insert(Iter first, Iter last) noexcept { if (first == last) return; for (auto it = first; it != last; it++) { if constexpr (std::is_rvalue_reference_v) insert(std::move((*it).first), std::move((*it).second)); else insert((*it).first, (*it).second); } } /// \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 std::string (or a type convertible to it). /// \tparam ValueType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type /// (or a type promotable to one). /// \param key The key at which to insert or assign the value. /// \param val The value to insert/assign. /// /// \returns \conditional_return{Valid input} ///
    ///
  • An iterator to the value's position ///
  • `true` if the value was inserted, `false` if it was assigned. ///
/// \conditional_return{Input is an empty toml::node_view} /// `{ end(), false }` /// /// \attention The return value will always be `{ end(), false }` if the input value was /// an empty toml::node_view, because no insertion or assignment can take place. /// This is the only circumstance in which this can occur. template std::pair insert_or_assign(KeyType&& key, ValueType&& val) noexcept { static_assert( !impl::is_wide_string || TOML_WINDOWS_COMPAT, "Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."); if constexpr (is_node_view) { if (!val) return { end(), false }; } if constexpr (impl::is_wide_string) { #if TOML_WINDOWS_COMPAT return insert_or_assign(impl::narrow(std::forward(key)), std::forward(val)); #else static_assert(impl::dependent_false, "Evaluated unreachable branch!"); #endif } else { auto ipos = map_.lower_bound(key); if (ipos == map_.end() || ipos->first != key) { ipos = map_.emplace_hint(ipos, std::forward(key), impl::make_node(std::forward(val))); return { iterator{ ipos }, true }; } else { (*ipos).second.reset(impl::make_node(std::forward(val))); 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(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 std::string (or a type convertible to it). /// \tparam ValueArgs Value constructor argument types. /// \param key The key at which to emplace the new value. /// \param args Arguments to forward to the value's constructor. /// /// \returns A std::pair containing:
/// - 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). template std::pair emplace(KeyType&& key, ValueArgs&&... args) noexcept { static_assert( !impl::is_wide_string || TOML_WINDOWS_COMPAT, "Emplacement using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."); if constexpr (impl::is_wide_string) { #if TOML_WINDOWS_COMPAT return emplace(impl::narrow(std::forward(key)), std::forward(args)...); #else static_assert(impl::dependent_false, "Evaluated unreachable branch!"); #endif } else { using type = impl::unwrap_node; static_assert((impl::is_native || impl::is_one_of)&&!impl::is_cvref, "The emplacement type argument of table::emplace() must be one " "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); auto ipos = map_.lower_bound(key); if (ipos == map_.end() || ipos->first != key) { ipos = map_.emplace_hint(ipos, std::forward(key), new impl::wrap_node{ std::forward(args)... }); return { iterator{ ipos }, true }; } return { iterator{ ipos }, false }; } } /// \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 { map_.erase(pos.raw_) }; } /// \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 { map_.erase(pos.raw_) }; } /// \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 first Iterator to the first key-value pair being erased. /// \param last 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 first, const_iterator last) noexcept { return { map_.erase(first.raw_, last.raw_) }; } /// \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 True if any values with matching keys were found and erased. bool erase(std::string_view key) noexcept { if (auto it = map_.find(key); it != map_.end()) { map_.erase(it); return true; } return false; } #if TOML_WINDOWS_COMPAT /// \brief Removes the value with the given key from the table. /// /// \availability This overload is only available when #TOML_WINDOWS_COMPAT is enabled. /// /// \param key Key to erase. /// /// \returns True if any values with matching keys were found and erased. bool erase(std::wstring_view key) noexcept { return erase(impl::narrow(key)); } #endif // TOML_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_NODISCARD iterator find(std::string_view key) noexcept { return { map_.find(key) }; } /// \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_NODISCARD const_iterator find(std::string_view key) const noexcept { return { map_.find(key) }; } /// \brief Returns true if the table contains a node at the given key. TOML_NODISCARD bool contains(std::string_view key) const noexcept { return do_contains(map_, key); } #if TOML_WINDOWS_COMPAT /// \brief Gets an iterator to the node at a specific key. /// /// \availability This overload is only available when #TOML_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) noexcept { 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_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 noexcept { 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_WINDOWS_COMPAT is enabled. TOML_NODISCARD bool contains(std::wstring_view key) const noexcept { return contains(impl::narrow(key)); } #endif // TOML_WINDOWS_COMPAT /// @} /// \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_NODISCARD node* get(std::string_view key) noexcept { return do_get(map_, key); } /// \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_NODISCARD const node* get(std::string_view key) const noexcept { return do_get(map_, key); } #if TOML_WINDOWS_COMPAT /// \brief Gets the node at a specific key. /// /// \availability This overload is only available when #TOML_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) noexcept { return get(impl::narrow(key)); } /// \brief Gets the node at a specific key (const overload). /// /// \availability This overload is only available when #TOML_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 noexcept { return get(impl::narrow(key)); } #endif // TOML_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("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 ValueType 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 TOML_NODISCARD impl::wrap_node* get_as(std::string_view key) noexcept { return do_get_as(map_, key); } /// \brief Gets the node at a specific key if it is a particular type (const overload). /// /// \tparam ValueType 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 TOML_NODISCARD const impl::wrap_node* get_as(std::string_view key) const noexcept { return do_get_as(map_, key); } #if TOML_WINDOWS_COMPAT /// \brief Gets the node at a specific key if it is a particular type. /// /// \availability This overload is only available when #TOML_WINDOWS_COMPAT is enabled. /// /// \tparam ValueType 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 TOML_NODISCARD impl::wrap_node* get_as(std::wstring_view key) noexcept { return get_as(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_WINDOWS_COMPAT is enabled. /// /// \tparam ValueType 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 TOML_NODISCARD const impl::wrap_node* get_as(std::wstring_view key) const noexcept { return get_as(impl::narrow(key)); } #endif // TOML_WINDOWS_COMPAT /// @} private: /// \cond TOML_NODISCARD TOML_API static bool equal(const table&, const table&) noexcept; /// \endcond public: /// \name Equality /// @{ /// \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 Prints the table out to a stream as formatted TOML. friend std::ostream& operator<<(std::ostream& lhs, const table& rhs) { impl::print_to_stream(lhs, rhs); return lhs; } }; //# template //# inline std::vector node::select_exact() const noexcept //# { //# using namespace impl; //# //# static_assert( //# !is_wide_string || TOML_WINDOWS_COMPAT, //# "Retrieving values as wide-character strings with node::select_exact() is only " //# "supported on Windows with TOML_WINDOWS_COMPAT enabled." //# ); //# //# static_assert( //# (is_native || can_represent_native) && !is_cvref, //# TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::select_exact()") //# ); //# } //# template //# inline std::vector node::select() const noexcept //# { //# using namespace impl; //# //# static_assert( //# !is_wide_string || TOML_WINDOWS_COMPAT, //# "Retrieving values as wide-character strings with node::select() is only " //# "supported on Windows with TOML_WINDOWS_COMPAT enabled." //# ); //# static_assert( //# (is_native || can_represent_native || can_partially_represent_native) && !is_cvref, //# TOML_SA_VALUE_FUNC_MESSAGE("return type of node::select()") //# ); //# } } TOML_NAMESPACE_END; #include "header_end.h"