summaryrefslogtreecommitdiffhomepage
path: root/vendor/toml++/impl/array.hpp
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal@nekernel.org>2026-03-08 15:47:16 +0100
committerAmlal El Mahrouss <amlal@nekernel.org>2026-03-08 15:47:16 +0100
commitddb1cbc831b6d13b985d91022f01e955e24ae871 (patch)
tree985c7eda4fafa827eaad88b6b469b0baba791817 /vendor/toml++/impl/array.hpp
parent7a469801ecb55fcde0199d4e41b1cec3a17dcb05 (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/array.hpp')
-rw-r--r--vendor/toml++/impl/array.hpp3261
1 files changed, 1510 insertions, 1751 deletions
diff --git a/vendor/toml++/impl/array.hpp b/vendor/toml++/impl/array.hpp
index ad79379..c276637 100644
--- a/vendor/toml++/impl/array.hpp
+++ b/vendor/toml++/impl/array.hpp
@@ -1,15 +1,15 @@
-//# 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 "header_start.hpp"
+#include "make_node.hpp"
+#include "std_initializer_list.hpp"
#include "std_utility.hpp"
#include "std_vector.hpp"
-#include "std_initializer_list.hpp"
#include "value.hpp"
-#include "make_node.hpp"
-#include "header_start.hpp"
#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
#if TOML_GCC && TOML_GCC <= 7
@@ -19,1771 +19,1530 @@
#endif
#endif
-#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN && !defined(TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED)
-#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE \
- "If you're seeing this error it's because you're using one of toml++'s for_each() functions on a compiler with " \
- "known bugs in that area (e.g. GCC 7). On these compilers returning a bool (or bool-convertible) value from the " \
- "for_each() callable causes spurious compilation failures, while returning nothing (void) works fine. " \
- "If you believe this message is incorrect for your compiler, you can try your luck by #defining " \
- "TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN as 0 and recompiling - if it works, great! Let me know at " \
- "https://github.com/marzer/tomlplusplus/issues. Alternatively, if you don't have any need for early-exiting from " \
- "for_each(), you can suppress this error by #defining TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED " \
- "and moving on with your life."
+#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN && \
+ !defined(TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED)
+#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE \
+ "If you're seeing this error it's because you're using one of toml++'s for_each() functions on " \
+ "a compiler with " \
+ "known bugs in that area (e.g. GCC 7). On these compilers returning a bool (or " \
+ "bool-convertible) value from the " \
+ "for_each() callable causes spurious compilation failures, while returning nothing (void) " \
+ "works fine. " \
+ "If you believe this message is incorrect for your compiler, you can try your luck by " \
+ "#defining " \
+ "TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN as 0 and recompiling - if it works, great! Let me know " \
+ "at " \
+ "https://github.com/marzer/tomlplusplus/issues. Alternatively, if you don't have any need for " \
+ "early-exiting from " \
+ "for_each(), you can suppress this error by #defining " \
+ "TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED " \
+ "and moving on with your life."
#endif
/// \cond
-TOML_IMPL_NAMESPACE_START
-{
- template <bool IsConst>
- class TOML_TRIVIAL_ABI array_iterator
- {
- private:
- template <bool>
- friend class array_iterator;
-
- using mutable_vector_iterator = std::vector<node_ptr>::iterator;
- using const_vector_iterator = std::vector<node_ptr>::const_iterator;
- using vector_iterator = std::conditional_t<IsConst, const_vector_iterator, mutable_vector_iterator>;
-
- mutable vector_iterator iter_;
-
- public:
- using value_type = std::conditional_t<IsConst, const node, node>;
- using reference = value_type&;
- using pointer = value_type*;
- using difference_type = ptrdiff_t;
- using iterator_category = typename std::iterator_traits<vector_iterator>::iterator_category;
-
- TOML_NODISCARD_CTOR
- array_iterator() noexcept = default;
-
- TOML_NODISCARD_CTOR
- explicit array_iterator(mutable_vector_iterator iter) noexcept //
- : iter_{ iter }
- {}
-
- TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
- TOML_NODISCARD_CTOR
- explicit array_iterator(const_vector_iterator iter) noexcept //
- : iter_{ iter }
- {}
-
- TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
- TOML_NODISCARD_CTOR
- array_iterator(const array_iterator<false>& other) noexcept //
- : iter_{ other.iter_ }
- {}
-
- TOML_NODISCARD_CTOR
- array_iterator(const array_iterator&) noexcept = default;
-
- array_iterator& operator=(const array_iterator&) noexcept = default;
-
- array_iterator& operator++() noexcept // ++pre
- {
- ++iter_;
- return *this;
- }
-
- array_iterator operator++(int) noexcept // post++
- {
- array_iterator out{ iter_ };
- ++iter_;
- return out;
- }
-
- array_iterator& operator--() noexcept // --pre
- {
- --iter_;
- return *this;
- }
-
- array_iterator operator--(int) noexcept // post--
- {
- array_iterator out{ iter_ };
- --iter_;
- return out;
- }
-
- TOML_PURE_INLINE_GETTER
- reference operator*() const noexcept
- {
- return *iter_->get();
- }
-
- TOML_PURE_INLINE_GETTER
- pointer operator->() const noexcept
- {
- return iter_->get();
- }
-
- TOML_PURE_INLINE_GETTER
- explicit operator const vector_iterator&() const noexcept
- {
- return iter_;
- }
-
- TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
- TOML_PURE_INLINE_GETTER
- explicit operator const const_vector_iterator() const noexcept
- {
- return iter_;
- }
-
- array_iterator& operator+=(ptrdiff_t rhs) noexcept
- {
- iter_ += rhs;
- return *this;
- }
-
- array_iterator& operator-=(ptrdiff_t rhs) noexcept
- {
- iter_ -= rhs;
- return *this;
- }
-
- TOML_NODISCARD
- friend array_iterator operator+(const array_iterator& lhs, ptrdiff_t rhs) noexcept
- {
- return array_iterator{ lhs.iter_ + rhs };
- }
-
- TOML_NODISCARD
- friend array_iterator operator+(ptrdiff_t lhs, const array_iterator& rhs) noexcept
- {
- return array_iterator{ rhs.iter_ + lhs };
- }
-
- TOML_NODISCARD
- friend array_iterator operator-(const array_iterator& lhs, ptrdiff_t rhs) noexcept
- {
- return array_iterator{ lhs.iter_ - rhs };
- }
-
- TOML_PURE_INLINE_GETTER
- friend ptrdiff_t operator-(const array_iterator& lhs, const array_iterator& rhs) noexcept
- {
- return lhs.iter_ - rhs.iter_;
- }
-
- TOML_PURE_INLINE_GETTER
- friend bool operator==(const array_iterator& lhs, const array_iterator& rhs) noexcept
- {
- return lhs.iter_ == rhs.iter_;
- }
-
- TOML_PURE_INLINE_GETTER
- friend bool operator!=(const array_iterator& lhs, const array_iterator& rhs) noexcept
- {
- return lhs.iter_ != rhs.iter_;
- }
-
- TOML_PURE_INLINE_GETTER
- friend bool operator<(const array_iterator& lhs, const array_iterator& rhs) noexcept
- {
- return lhs.iter_ < rhs.iter_;
- }
-
- TOML_PURE_INLINE_GETTER
- friend bool operator<=(const array_iterator& lhs, const array_iterator& rhs) noexcept
- {
- return lhs.iter_ <= rhs.iter_;
- }
-
- TOML_PURE_INLINE_GETTER
- friend bool operator>(const array_iterator& lhs, const array_iterator& rhs) noexcept
- {
- return lhs.iter_ > rhs.iter_;
- }
-
- TOML_PURE_INLINE_GETTER
- friend bool operator>=(const array_iterator& lhs, const array_iterator& rhs) noexcept
- {
- return lhs.iter_ >= rhs.iter_;
- }
-
- TOML_PURE_INLINE_GETTER
- reference operator[](ptrdiff_t idx) const noexcept
- {
- return *(iter_ + idx)->get();
- }
- };
-
- struct array_init_elem
- {
- mutable node_ptr value;
-
- template <typename T>
- TOML_NODISCARD_CTOR
- array_init_elem(T&& val, value_flags flags = preserve_source_value_flags) //
- : value{ make_node(static_cast<T&&>(val), flags) }
- {}
- };
+TOML_IMPL_NAMESPACE_START {
+ template <bool IsConst>
+ class TOML_TRIVIAL_ABI array_iterator {
+ private:
+ template <bool>
+ friend class array_iterator;
+
+ using mutable_vector_iterator = std::vector<node_ptr>::iterator;
+ using const_vector_iterator = std::vector<node_ptr>::const_iterator;
+ using vector_iterator =
+ std::conditional_t<IsConst, const_vector_iterator, mutable_vector_iterator>;
+
+ mutable vector_iterator iter_;
+
+ public:
+ using value_type = std::conditional_t<IsConst, const node, node>;
+ using reference = value_type&;
+ using pointer = value_type*;
+ using difference_type = ptrdiff_t;
+ using iterator_category = typename std::iterator_traits<vector_iterator>::iterator_category;
+
+ TOML_NODISCARD_CTOR
+ array_iterator() noexcept = default;
+
+ TOML_NODISCARD_CTOR
+ explicit array_iterator(mutable_vector_iterator iter) noexcept //
+ : iter_{iter} {}
+
+ TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
+ TOML_NODISCARD_CTOR
+ explicit array_iterator(const_vector_iterator iter) noexcept //
+ : iter_{iter} {}
+
+ TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
+ TOML_NODISCARD_CTOR
+ array_iterator(const array_iterator<false>& other) noexcept //
+ : iter_{other.iter_} {}
+
+ TOML_NODISCARD_CTOR
+ array_iterator(const array_iterator&) noexcept = default;
+
+ array_iterator& operator=(const array_iterator&) noexcept = default;
+
+ array_iterator& operator++() noexcept // ++pre
+ {
+ ++iter_;
+ return *this;
+ }
+
+ array_iterator operator++(int) noexcept // post++
+ {
+ array_iterator out{iter_};
+ ++iter_;
+ return out;
+ }
+
+ array_iterator& operator--() noexcept // --pre
+ {
+ --iter_;
+ return *this;
+ }
+
+ array_iterator operator--(int) noexcept // post--
+ {
+ array_iterator out{iter_};
+ --iter_;
+ return out;
+ }
+
+ TOML_PURE_INLINE_GETTER
+ reference operator*() const noexcept { return *iter_->get(); }
+
+ TOML_PURE_INLINE_GETTER
+ pointer operator->() const noexcept { return iter_->get(); }
+
+ TOML_PURE_INLINE_GETTER
+ explicit operator const vector_iterator&() const noexcept { return iter_; }
+
+ TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
+ TOML_PURE_INLINE_GETTER
+ explicit operator const const_vector_iterator() const noexcept { return iter_; }
+
+ array_iterator& operator+=(ptrdiff_t rhs) noexcept {
+ iter_ += rhs;
+ return *this;
+ }
+
+ array_iterator& operator-=(ptrdiff_t rhs) noexcept {
+ iter_ -= rhs;
+ return *this;
+ }
+
+ TOML_NODISCARD
+ friend array_iterator operator+(const array_iterator& lhs, ptrdiff_t rhs) noexcept {
+ return array_iterator{lhs.iter_ + rhs};
+ }
+
+ TOML_NODISCARD
+ friend array_iterator operator+(ptrdiff_t lhs, const array_iterator& rhs) noexcept {
+ return array_iterator{rhs.iter_ + lhs};
+ }
+
+ TOML_NODISCARD
+ friend array_iterator operator-(const array_iterator& lhs, ptrdiff_t rhs) noexcept {
+ return array_iterator{lhs.iter_ - rhs};
+ }
+
+ TOML_PURE_INLINE_GETTER
+ friend ptrdiff_t operator-(const array_iterator& lhs, const array_iterator& rhs) noexcept {
+ return lhs.iter_ - rhs.iter_;
+ }
+
+ TOML_PURE_INLINE_GETTER
+ friend bool operator==(const array_iterator& lhs, const array_iterator& rhs) noexcept {
+ return lhs.iter_ == rhs.iter_;
+ }
+
+ TOML_PURE_INLINE_GETTER
+ friend bool operator!=(const array_iterator& lhs, const array_iterator& rhs) noexcept {
+ return lhs.iter_ != rhs.iter_;
+ }
+
+ TOML_PURE_INLINE_GETTER
+ friend bool operator<(const array_iterator& lhs, const array_iterator& rhs) noexcept {
+ return lhs.iter_ < rhs.iter_;
+ }
+
+ TOML_PURE_INLINE_GETTER
+ friend bool operator<=(const array_iterator& lhs, const array_iterator& rhs) noexcept {
+ return lhs.iter_ <= rhs.iter_;
+ }
+
+ TOML_PURE_INLINE_GETTER
+ friend bool operator>(const array_iterator& lhs, const array_iterator& rhs) noexcept {
+ return lhs.iter_ > rhs.iter_;
+ }
+
+ TOML_PURE_INLINE_GETTER
+ friend bool operator>=(const array_iterator& lhs, const array_iterator& rhs) noexcept {
+ return lhs.iter_ >= rhs.iter_;
+ }
+
+ TOML_PURE_INLINE_GETTER
+ reference operator[](ptrdiff_t idx) const noexcept { return *(iter_ + idx)->get(); }
+ };
+
+ struct array_init_elem {
+ mutable node_ptr value;
+
+ template <typename T>
+ TOML_NODISCARD_CTOR array_init_elem(T&& val,
+ value_flags flags = preserve_source_value_flags) //
+ : value{make_node(static_cast<T&&>(val), flags)} {}
+ };
}
TOML_IMPL_NAMESPACE_END;
/// \endcond
-TOML_NAMESPACE_START
-{
- /// \brief A RandomAccessIterator for iterating over elements in a toml::array.
- using array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<false>);
-
- /// \brief A RandomAccessIterator for iterating over const elements in a toml::array.
- using const_array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<true>);
-
- /// \brief A TOML array.
- ///
- /// \detail The interface of this type is modeled after std::vector, with some
- /// additional considerations made for the heterogeneous nature of a
- /// TOML array.
- ///
- /// \godbolt{sjK4da}
- ///
- /// \cpp
- ///
- /// toml::table tbl = toml::parse(R"(
- /// arr = [1, 2, 3, 4, 'five']
- /// )"sv);
- ///
- /// // get the element as an array
- /// toml::array& arr = *tbl.get_as<toml::array>("arr");
- /// std::cout << arr << "\n";
- ///
- /// // increment each element with visit()
- /// for (auto&& elem : arr)
- /// {
- /// elem.visit([](auto&& el) noexcept
- /// {
- /// if constexpr (toml::is_number<decltype(el)>)
- /// (*el)++;
- /// else if constexpr (toml::is_string<decltype(el)>)
- /// el = "six"sv;
- /// });
- /// }
- /// std::cout << arr << "\n";
- ///
- /// // add and remove elements
- /// arr.push_back(7);
- /// arr.push_back(8.0f);
- /// arr.push_back("nine"sv);
- /// arr.erase(arr.cbegin());
- /// std::cout << arr << "\n";
- ///
- /// // emplace elements
- /// arr.emplace_back("ten");
- /// arr.emplace_back<toml::array>(11, 12.0);
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 2, 3, 4, 'five' ]
- /// [ 2, 3, 4, 5, 'six' ]
- /// [ 3, 4, 5, 'six', 7, 8.0, 'nine' ]
- /// [ 3, 4, 5, 'six', 7, 8.0, 'nine', 'ten', [ 11, 12.0 ] ]
- /// \eout
- class TOML_EXPORTED_CLASS array : public node
- {
- private:
- /// \cond
-
- using vector_type = std::vector<impl::node_ptr>;
- using vector_iterator = typename vector_type::iterator;
- using const_vector_iterator = typename vector_type::const_iterator;
- vector_type elems_;
-
- TOML_NODISCARD_CTOR
- TOML_EXPORTED_MEMBER_FUNCTION
- array(const impl::array_init_elem*, const impl::array_init_elem*);
-
- TOML_NODISCARD_CTOR
- array(std::false_type, std::initializer_list<impl::array_init_elem> elems) //
- : array{ elems.begin(), elems.end() }
- {}
-
- TOML_EXPORTED_MEMBER_FUNCTION
- void preinsertion_resize(size_t idx, size_t count);
-
- TOML_EXPORTED_MEMBER_FUNCTION
- void insert_at_back(impl::node_ptr&&);
-
- TOML_EXPORTED_MEMBER_FUNCTION
- vector_iterator insert_at(const_vector_iterator, impl::node_ptr&&);
-
- template <typename T>
- void emplace_back_if_not_empty_view(T&& val, value_flags flags)
- {
- if constexpr (is_node_view<T>)
- {
- if (!val)
- return;
- }
- insert_at_back(impl::make_node(static_cast<T&&>(val), flags));
- }
-
- TOML_NODISCARD
- TOML_EXPORTED_MEMBER_FUNCTION
- size_t total_leaf_count() const noexcept;
-
- TOML_EXPORTED_MEMBER_FUNCTION
- void flatten_child(array&& child, size_t& dest_index) noexcept;
-
- /// \endcond
-
- public:
- using value_type = node;
- using size_type = size_t;
- using difference_type = ptrdiff_t;
- using reference = node&;
- using const_reference = const node&;
-
- /// \brief Default constructor.
- TOML_NODISCARD_CTOR
- TOML_EXPORTED_MEMBER_FUNCTION
- array() noexcept;
-
- TOML_EXPORTED_MEMBER_FUNCTION
- ~array() noexcept;
-
- /// \brief Copy constructor.
- TOML_NODISCARD_CTOR
- TOML_EXPORTED_MEMBER_FUNCTION
- array(const array&);
-
- /// \brief Move constructor.
- TOML_NODISCARD_CTOR
- TOML_EXPORTED_MEMBER_FUNCTION
- array(array&& other) noexcept;
-
- /// \brief Constructs an array with one or more initial elements.
- ///
- /// \detail \cpp
- /// auto arr = toml::array{ 1, 2.0, "three"sv, toml::array{ 4, 5 } };
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 2.0, 'three', [ 4, 5 ] ]
- /// \eout
- ///
- /// \remark \parblock If you need to construct an array with one child array element, the array's move constructor
- /// will take precedence and perform a move-construction instead. You can use toml::inserter to
- /// suppress this behaviour: \cpp
- /// // desired result: [ [ 42 ] ]
- /// auto bad = toml::array{ toml::array{ 42 } }
- /// auto good = toml::array{ toml::inserter{ toml::array{ 42 } } }
- /// std::cout << "bad: " << bad << "\n";
- /// std::cout << "good:" << good << "\n";
- /// \ecpp
- ///
- /// \out
- /// bad: [ 42 ]
- /// good: [ [ 42 ] ]
- /// \eout
- ///
- /// \endparblock
- ///
- /// \tparam ElemType One of the TOML node or value types (or a type promotable to one).
- /// \tparam ElemTypes One of the TOML node or value types (or a type promotable to one).
- /// \param val The node or value used to initialize element 0.
- /// \param vals The nodes or values used to initialize elements 1...N.
- TOML_CONSTRAINED_TEMPLATE((sizeof...(ElemTypes) > 0 || !std::is_same_v<impl::remove_cvref<ElemType>, array>),
- typename ElemType,
- typename... ElemTypes)
- TOML_NODISCARD_CTOR
- explicit array(ElemType&& val, ElemTypes&&... vals)
- : array{ std::false_type{},
- std::initializer_list<impl::array_init_elem>{ static_cast<ElemType&&>(val),
- static_cast<ElemTypes&&>(vals)... } }
- {}
-
- /// \brief Copy-assignment operator.
- TOML_EXPORTED_MEMBER_FUNCTION
- array& operator=(const array&);
-
- /// \brief Move-assignment operator.
- TOML_EXPORTED_MEMBER_FUNCTION
- array& operator=(array&& rhs) noexcept;
-
- /// \name Type checks
- /// @{
-
- /// \brief Returns #toml::node_type::array.
- TOML_CONST_INLINE_GETTER
- node_type type() const noexcept final
- {
- return node_type::array;
- }
-
- 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 array::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 `false`.
- TOML_CONST_INLINE_GETTER
- bool is_table() const noexcept final
- {
- return false;
- }
-
- /// \brief Returns `true`.
- TOML_CONST_INLINE_GETTER
- bool is_array() const noexcept final
- {
- return true;
- }
-
- /// \brief Returns `true` if the array contains only tables.
- TOML_PURE_GETTER
- bool is_array_of_tables() const noexcept final
- {
- return is_homogeneous(node_type::table);
- }
-
- /// \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 `nullptr`.
- TOML_CONST_INLINE_GETTER
- table* as_table() noexcept final
- {
- return nullptr;
- }
-
- /// \brief Returns a pointer to the array.
- TOML_CONST_INLINE_GETTER
- array* as_array() noexcept final
- {
- return this;
- }
-
- /// \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 `nullptr`.
- TOML_CONST_INLINE_GETTER
- const table* as_table() const noexcept final
- {
- return nullptr;
- }
-
- /// \brief Returns a const-qualified pointer to the array.
- TOML_CONST_INLINE_GETTER
- const array* as_array() const noexcept final
- {
- return this;
- }
-
- /// \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 Value retrieval
- /// @{
-
- /// \brief Gets a pointer to the element at a specific index.
- ///
- /// \detail \cpp
- /// auto arr = toml::array{ 99, "bottles of beer on the wall" };
- /// std::cout << "element [0] exists: "sv << !!arr.get(0) << "\n";
- /// std::cout << "element [1] exists: "sv << !!arr.get(1) << "\n";
- /// std::cout << "element [2] exists: "sv << !!arr.get(2) << "\n";
- /// if (toml::node* val = arr.get(0))
- /// std::cout << "element [0] is an "sv << val->type() << "\n";
- /// \ecpp
- ///
- /// \out
- /// element [0] exists: true
- /// element [1] exists: true
- /// element [2] exists: false
- /// element [0] is an integer
- /// \eout
- ///
- /// \param index The element's index.
- ///
- /// \returns A pointer to the element at the specified index if one existed, or nullptr.
- TOML_PURE_INLINE_GETTER
- node* get(size_t index) noexcept
- {
- return index < elems_.size() ? elems_[index].get() : nullptr;
- }
-
- /// \brief Gets a pointer to the element at a specific index (const overload).
- ///
- /// \param index The element's index.
- ///
- /// \returns A pointer to the element at the specified index if one existed, or nullptr.
- TOML_PURE_INLINE_GETTER
- const node* get(size_t index) const noexcept
- {
- return const_cast<array&>(*this).get(index);
- }
-
- /// \brief Gets a pointer to the element at a specific index if it is a particular type.
- ///
- /// \detail \cpp
- /// auto arr = toml::array{ 42, "is the meaning of life, apparently."sv };
- /// if (toml::value<int64_t>* val = arr.get_as<int64_t>(0))
- /// std::cout << "element [0] is an integer with value "sv << *val << "\n";
- /// \ecpp
- ///
- /// \out
- /// element [0] is an integer with value 42
- /// \eout
- ///
- /// \tparam ElemType toml::table, toml::array, or a native TOML value type
- /// \param index The element's index.
- ///
- /// \returns A pointer to the selected element if it existed and was of the specified type, or nullptr.
- template <typename ElemType>
- TOML_NODISCARD
- impl::wrap_node<ElemType>* get_as(size_t index) noexcept
- {
- if (auto val = get(index))
- return val->template as<ElemType>();
- return nullptr;
- }
-
- /// \brief Gets a pointer to the element at a specific index if it is a particular type (const overload).
- ///
- /// \tparam ElemType toml::table, toml::array, or a native TOML value type
- /// \param index The element's index.
- ///
- /// \returns A pointer to the selected element if it existed and was of the specified type, or nullptr.
- template <typename ElemType>
- TOML_NODISCARD
- const impl::wrap_node<ElemType>* get_as(size_t index) const noexcept
- {
- return const_cast<array&>(*this).template get_as<ElemType>(index);
- }
-
- /// \cond
- using node::operator[]; // inherit operator[toml::path]
- /// \endcond
-
- /// \brief Gets a reference to the element at a specific index.
- TOML_NODISCARD
- node& operator[](size_t index) noexcept
- {
- return *elems_[index];
- }
-
- /// \brief Gets a reference to the element at a specific index.
- TOML_NODISCARD
- const node& operator[](size_t index) const noexcept
- {
- return *elems_[index];
- }
-
- /// \brief Gets a reference to the element at a specific index, throwing `std::out_of_range` if none existed.
- TOML_NODISCARD
- TOML_EXPORTED_MEMBER_FUNCTION
- node& at(size_t index);
-
- /// \brief Gets a reference to the element at a specific index, throwing `std::out_of_range` if none existed.
- TOML_NODISCARD
- const node& at(size_t index) const
- {
- return const_cast<array&>(*this).at(index);
- }
-
- /// \brief Returns a reference to the first element in the array.
- TOML_NODISCARD
- node& front() noexcept
- {
- return *elems_.front();
- }
-
- /// \brief Returns a reference to the first element in the array.
- TOML_NODISCARD
- const node& front() const noexcept
- {
- return *elems_.front();
- }
-
- /// \brief Returns a reference to the last element in the array.
- TOML_NODISCARD
- node& back() noexcept
- {
- return *elems_.back();
- }
-
- /// \brief Returns a reference to the last element in the array.
- TOML_NODISCARD
- const node& back() const noexcept
- {
- return *elems_.back();
- }
-
- /// @}
-
- /// \name Iteration
- /// @{
-
- /// \brief A RandomAccessIterator for iterating over elements in a toml::array.
- using iterator = array_iterator;
-
- /// \brief A RandomAccessIterator for iterating over const elements in a toml::array.
- using const_iterator = const_array_iterator;
-
- /// \brief Returns an iterator to the first element.
- TOML_NODISCARD
- iterator begin() noexcept
- {
- return iterator{ elems_.begin() };
- }
-
- /// \brief Returns an iterator to the first element.
- TOML_NODISCARD
- const_iterator begin() const noexcept
- {
- return const_iterator{ elems_.cbegin() };
- }
-
- /// \brief Returns an iterator to the first element.
- TOML_NODISCARD
- const_iterator cbegin() const noexcept
- {
- return const_iterator{ elems_.cbegin() };
- }
-
- /// \brief Returns an iterator to one-past-the-last element.
- TOML_NODISCARD
- iterator end() noexcept
- {
- return iterator{ elems_.end() };
- }
-
- /// \brief Returns an iterator to one-past-the-last element.
- TOML_NODISCARD
- const_iterator end() const noexcept
- {
- return const_iterator{ elems_.cend() };
- }
-
- /// \brief Returns an iterator to one-past-the-last element.
- TOML_NODISCARD
- const_iterator cend() const noexcept
- {
- return const_iterator{ elems_.cend() };
- }
-
- private:
- /// \cond
-
- template <typename T, typename Array>
- using for_each_elem_ref = impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Array>;
-
- template <typename Func, typename Array, typename T>
- using can_for_each = std::disjunction<std::is_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
- std::is_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
- std::is_invocable<Func, for_each_elem_ref<T, Array>>>;
-
- template <typename Func, typename Array, typename T>
- using can_for_each_nothrow = std::conditional_t<
- // first form
- std::is_invocable_v<Func, for_each_elem_ref<T, Array>, size_t>,
- std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
- std::conditional_t<
- // second form
- std::is_invocable_v<Func, size_t, for_each_elem_ref<T, Array>>,
- std::is_nothrow_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
- std::conditional_t<
- // third form
- std::is_invocable_v<Func, for_each_elem_ref<T, Array>>,
- std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>>,
- std::false_type>>>;
-
- template <typename Func, typename Array>
- using can_for_each_any = std::disjunction<can_for_each<Func, Array, table>,
- can_for_each<Func, Array, array>,
- can_for_each<Func, Array, std::string>,
- can_for_each<Func, Array, int64_t>,
- can_for_each<Func, Array, double>,
- can_for_each<Func, Array, bool>,
- can_for_each<Func, Array, date>,
- can_for_each<Func, Array, time>,
- can_for_each<Func, Array, date_time>>;
-
- template <typename Func, typename Array, typename T>
- using for_each_is_nothrow_one = std::disjunction<std::negation<can_for_each<Func, Array, T>>, //
- can_for_each_nothrow<Func, Array, T>>;
-
- template <typename Func, typename Array>
- using for_each_is_nothrow = std::conjunction<for_each_is_nothrow_one<Func, Array, table>,
- for_each_is_nothrow_one<Func, Array, array>,
- for_each_is_nothrow_one<Func, Array, std::string>,
- for_each_is_nothrow_one<Func, Array, int64_t>,
- for_each_is_nothrow_one<Func, Array, double>,
- for_each_is_nothrow_one<Func, Array, bool>,
- for_each_is_nothrow_one<Func, Array, date>,
- for_each_is_nothrow_one<Func, Array, time>,
- for_each_is_nothrow_one<Func, Array, date_time>>;
-
- template <typename Func, typename Array>
- static void do_for_each(Func&& visitor, Array&& arr) //
- noexcept(for_each_is_nothrow<Func&&, Array&&>::value)
- {
- static_assert(can_for_each_any<Func&&, Array&&>::value,
- "TOML array for_each visitors must be invocable for at least one of the toml::node "
- "specializations:" TOML_SA_NODE_TYPE_LIST);
-
- for (size_t i = 0; i < arr.size(); i++)
- {
- using node_ref = impl::copy_cvref<toml::node, Array&&>;
- static_assert(std::is_reference_v<node_ref>);
+TOML_NAMESPACE_START {
+ /// \brief A RandomAccessIterator for iterating over elements in a toml::array.
+ using array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<false>);
+
+ /// \brief A RandomAccessIterator for iterating over const elements in a toml::array.
+ using const_array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<true>);
+
+ /// \brief A TOML array.
+ ///
+ /// \detail The interface of this type is modeled after std::vector, with some
+ /// additional considerations made for the heterogeneous nature of a
+ /// TOML array.
+ ///
+ /// \godbolt{sjK4da}
+ ///
+ /// \cpp
+ ///
+ /// toml::table tbl = toml::parse(R"(
+ /// arr = [1, 2, 3, 4, 'five']
+ /// )"sv);
+ ///
+ /// // get the element as an array
+ /// toml::array& arr = *tbl.get_as<toml::array>("arr");
+ /// std::cout << arr << "\n";
+ ///
+ /// // increment each element with visit()
+ /// for (auto&& elem : arr)
+ /// {
+ /// elem.visit([](auto&& el) noexcept
+ /// {
+ /// if constexpr (toml::is_number<decltype(el)>)
+ /// (*el)++;
+ /// else if constexpr (toml::is_string<decltype(el)>)
+ /// el = "six"sv;
+ /// });
+ /// }
+ /// std::cout << arr << "\n";
+ ///
+ /// // add and remove elements
+ /// arr.push_back(7);
+ /// arr.push_back(8.0f);
+ /// arr.push_back("nine"sv);
+ /// arr.erase(arr.cbegin());
+ /// std::cout << arr << "\n";
+ ///
+ /// // emplace elements
+ /// arr.emplace_back("ten");
+ /// arr.emplace_back<toml::array>(11, 12.0);
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 2, 3, 4, 'five' ]
+ /// [ 2, 3, 4, 5, 'six' ]
+ /// [ 3, 4, 5, 'six', 7, 8.0, 'nine' ]
+ /// [ 3, 4, 5, 'six', 7, 8.0, 'nine', 'ten', [ 11, 12.0 ] ]
+ /// \eout
+ class TOML_EXPORTED_CLASS array : public node {
+ private:
+ /// \cond
+
+ using vector_type = std::vector<impl::node_ptr>;
+ using vector_iterator = typename vector_type::iterator;
+ using const_vector_iterator = typename vector_type::const_iterator;
+ vector_type elems_;
+
+ TOML_NODISCARD_CTOR
+ TOML_EXPORTED_MEMBER_FUNCTION
+ array(const impl::array_init_elem*, const impl::array_init_elem*);
+
+ TOML_NODISCARD_CTOR
+ array(std::false_type, std::initializer_list<impl::array_init_elem> elems) //
+ : array{elems.begin(), elems.end()} {}
+
+ TOML_EXPORTED_MEMBER_FUNCTION
+ void preinsertion_resize(size_t idx, size_t count);
+
+ TOML_EXPORTED_MEMBER_FUNCTION
+ void insert_at_back(impl::node_ptr&&);
+
+ TOML_EXPORTED_MEMBER_FUNCTION
+ vector_iterator insert_at(const_vector_iterator, impl::node_ptr&&);
+
+ template <typename T>
+ void emplace_back_if_not_empty_view(T&& val, value_flags flags) {
+ if constexpr (is_node_view<T>) {
+ if (!val) return;
+ }
+ insert_at_back(impl::make_node(static_cast<T&&>(val), flags));
+ }
+
+ TOML_NODISCARD
+ TOML_EXPORTED_MEMBER_FUNCTION
+ size_t total_leaf_count() const noexcept;
+
+ TOML_EXPORTED_MEMBER_FUNCTION
+ void flatten_child(array&& child, size_t& dest_index) noexcept;
+
+ /// \endcond
+
+ public:
+ using value_type = node;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using reference = node&;
+ using const_reference = const node&;
+
+ /// \brief Default constructor.
+ TOML_NODISCARD_CTOR
+ TOML_EXPORTED_MEMBER_FUNCTION
+ array() noexcept;
+
+ TOML_EXPORTED_MEMBER_FUNCTION
+ ~array() noexcept;
+
+ /// \brief Copy constructor.
+ TOML_NODISCARD_CTOR
+ TOML_EXPORTED_MEMBER_FUNCTION
+ array(const array&);
+
+ /// \brief Move constructor.
+ TOML_NODISCARD_CTOR
+ TOML_EXPORTED_MEMBER_FUNCTION
+ array(array&& other) noexcept;
+
+ /// \brief Constructs an array with one or more initial elements.
+ ///
+ /// \detail \cpp
+ /// auto arr = toml::array{ 1, 2.0, "three"sv, toml::array{ 4, 5 } };
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 2.0, 'three', [ 4, 5 ] ]
+ /// \eout
+ ///
+ /// \remark \parblock If you need to construct an array with one child array element, the
+ /// array's move constructor will take precedence and perform a move-construction instead. You
+ /// can use toml::inserter to suppress this behaviour: \cpp
+ /// // desired result: [ [ 42 ] ]
+ /// auto bad = toml::array{ toml::array{ 42 } }
+ /// auto good = toml::array{ toml::inserter{ toml::array{ 42 } } }
+ /// std::cout << "bad: " << bad << "\n";
+ /// std::cout << "good:" << good << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// bad: [ 42 ]
+ /// good: [ [ 42 ] ]
+ /// \eout
+ ///
+ /// \endparblock
+ ///
+ /// \tparam ElemType One of the TOML node or value types (or a type promotable to one).
+ /// \tparam ElemTypes One of the TOML node or value types (or a type promotable to one).
+ /// \param val The node or value used to initialize element 0.
+ /// \param vals The nodes or values used to initialize elements 1...N.
+ TOML_CONSTRAINED_TEMPLATE((sizeof...(ElemTypes) > 0 ||
+ !std::is_same_v<impl::remove_cvref<ElemType>, array>),
+ typename ElemType, typename... ElemTypes)
+ TOML_NODISCARD_CTOR
+ explicit array(ElemType&& val, ElemTypes&&... vals)
+ : array{std::false_type{},
+ std::initializer_list<impl::array_init_elem>{static_cast<ElemType&&>(val),
+ static_cast<ElemTypes&&>(vals)...}} {}
+
+ /// \brief Copy-assignment operator.
+ TOML_EXPORTED_MEMBER_FUNCTION
+ array& operator=(const array&);
+
+ /// \brief Move-assignment operator.
+ TOML_EXPORTED_MEMBER_FUNCTION
+ array& operator=(array&& rhs) noexcept;
+
+ /// \name Type checks
+ /// @{
+
+ /// \brief Returns #toml::node_type::array.
+ TOML_CONST_INLINE_GETTER
+ node_type type() const noexcept final { return node_type::array; }
+
+ 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 array::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 `false`.
+ TOML_CONST_INLINE_GETTER
+ bool is_table() const noexcept final { return false; }
+
+ /// \brief Returns `true`.
+ TOML_CONST_INLINE_GETTER
+ bool is_array() const noexcept final { return true; }
+
+ /// \brief Returns `true` if the array contains only tables.
+ TOML_PURE_GETTER
+ bool is_array_of_tables() const noexcept final { return is_homogeneous(node_type::table); }
+
+ /// \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 `nullptr`.
+ TOML_CONST_INLINE_GETTER
+ table* as_table() noexcept final { return nullptr; }
+
+ /// \brief Returns a pointer to the array.
+ TOML_CONST_INLINE_GETTER
+ array* as_array() noexcept final { return this; }
+
+ /// \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 `nullptr`.
+ TOML_CONST_INLINE_GETTER
+ const table* as_table() const noexcept final { return nullptr; }
+
+ /// \brief Returns a const-qualified pointer to the array.
+ TOML_CONST_INLINE_GETTER
+ const array* as_array() const noexcept final { return this; }
+
+ /// \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 Value retrieval
+ /// @{
+
+ /// \brief Gets a pointer to the element at a specific index.
+ ///
+ /// \detail \cpp
+ /// auto arr = toml::array{ 99, "bottles of beer on the wall" };
+ /// std::cout << "element [0] exists: "sv << !!arr.get(0) << "\n";
+ /// std::cout << "element [1] exists: "sv << !!arr.get(1) << "\n";
+ /// std::cout << "element [2] exists: "sv << !!arr.get(2) << "\n";
+ /// if (toml::node* val = arr.get(0))
+ /// std::cout << "element [0] is an "sv << val->type() << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// element [0] exists: true
+ /// element [1] exists: true
+ /// element [2] exists: false
+ /// element [0] is an integer
+ /// \eout
+ ///
+ /// \param index The element's index.
+ ///
+ /// \returns A pointer to the element at the specified index if one existed, or nullptr.
+ TOML_PURE_INLINE_GETTER
+ node* get(size_t index) noexcept {
+ return index < elems_.size() ? elems_[index].get() : nullptr;
+ }
+
+ /// \brief Gets a pointer to the element at a specific index (const overload).
+ ///
+ /// \param index The element's index.
+ ///
+ /// \returns A pointer to the element at the specified index if one existed, or nullptr.
+ TOML_PURE_INLINE_GETTER
+ const node* get(size_t index) const noexcept { return const_cast<array&>(*this).get(index); }
+
+ /// \brief Gets a pointer to the element at a specific index if it is a particular type.
+ ///
+ /// \detail \cpp
+ /// auto arr = toml::array{ 42, "is the meaning of life, apparently."sv };
+ /// if (toml::value<int64_t>* val = arr.get_as<int64_t>(0))
+ /// std::cout << "element [0] is an integer with value "sv << *val << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// element [0] is an integer with value 42
+ /// \eout
+ ///
+ /// \tparam ElemType toml::table, toml::array, or a native TOML value type
+ /// \param index The element's index.
+ ///
+ /// \returns A pointer to the selected element if it existed and was of the specified type, or
+ /// nullptr.
+ template <typename ElemType>
+ TOML_NODISCARD impl::wrap_node<ElemType>* get_as(size_t index) noexcept {
+ if (auto val = get(index)) return val->template as<ElemType>();
+ return nullptr;
+ }
+
+ /// \brief Gets a pointer to the element at a specific index if it is a particular type (const
+ /// overload).
+ ///
+ /// \tparam ElemType toml::table, toml::array, or a native TOML value type
+ /// \param index The element's index.
+ ///
+ /// \returns A pointer to the selected element if it existed and was of the specified type, or
+ /// nullptr.
+ template <typename ElemType>
+ TOML_NODISCARD const impl::wrap_node<ElemType>* get_as(size_t index) const noexcept {
+ return const_cast<array&>(*this).template get_as<ElemType>(index);
+ }
+
+ /// \cond
+ using node::operator[]; // inherit operator[toml::path]
+ /// \endcond
+
+ /// \brief Gets a reference to the element at a specific index.
+ TOML_NODISCARD
+ node& operator[](size_t index) noexcept { return *elems_[index]; }
+
+ /// \brief Gets a reference to the element at a specific index.
+ TOML_NODISCARD
+ const node& operator[](size_t index) const noexcept { return *elems_[index]; }
+
+ /// \brief Gets a reference to the element at a specific index, throwing `std::out_of_range` if
+ /// none existed.
+ TOML_NODISCARD
+ TOML_EXPORTED_MEMBER_FUNCTION
+ node& at(size_t index);
+
+ /// \brief Gets a reference to the element at a specific index, throwing `std::out_of_range` if
+ /// none existed.
+ TOML_NODISCARD
+ const node& at(size_t index) const { return const_cast<array&>(*this).at(index); }
+
+ /// \brief Returns a reference to the first element in the array.
+ TOML_NODISCARD
+ node& front() noexcept { return *elems_.front(); }
+
+ /// \brief Returns a reference to the first element in the array.
+ TOML_NODISCARD
+ const node& front() const noexcept { return *elems_.front(); }
+
+ /// \brief Returns a reference to the last element in the array.
+ TOML_NODISCARD
+ node& back() noexcept { return *elems_.back(); }
+
+ /// \brief Returns a reference to the last element in the array.
+ TOML_NODISCARD
+ const node& back() const noexcept { return *elems_.back(); }
+
+ /// @}
+
+ /// \name Iteration
+ /// @{
+
+ /// \brief A RandomAccessIterator for iterating over elements in a toml::array.
+ using iterator = array_iterator;
+
+ /// \brief A RandomAccessIterator for iterating over const elements in a toml::array.
+ using const_iterator = const_array_iterator;
+
+ /// \brief Returns an iterator to the first element.
+ TOML_NODISCARD
+ iterator begin() noexcept { return iterator{elems_.begin()}; }
+
+ /// \brief Returns an iterator to the first element.
+ TOML_NODISCARD
+ const_iterator begin() const noexcept { return const_iterator{elems_.cbegin()}; }
+
+ /// \brief Returns an iterator to the first element.
+ TOML_NODISCARD
+ const_iterator cbegin() const noexcept { return const_iterator{elems_.cbegin()}; }
+
+ /// \brief Returns an iterator to one-past-the-last element.
+ TOML_NODISCARD
+ iterator end() noexcept { return iterator{elems_.end()}; }
+
+ /// \brief Returns an iterator to one-past-the-last element.
+ TOML_NODISCARD
+ const_iterator end() const noexcept { return const_iterator{elems_.cend()}; }
+
+ /// \brief Returns an iterator to one-past-the-last element.
+ TOML_NODISCARD
+ const_iterator cend() const noexcept { return const_iterator{elems_.cend()}; }
+
+ private:
+ /// \cond
+
+ template <typename T, typename Array>
+ using for_each_elem_ref =
+ impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Array>;
+
+ template <typename Func, typename Array, typename T>
+ using can_for_each =
+ std::disjunction<std::is_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
+ std::is_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
+ std::is_invocable<Func, for_each_elem_ref<T, Array>>>;
+
+ template <typename Func, typename Array, typename T>
+ using can_for_each_nothrow = std::conditional_t<
+ // first form
+ std::is_invocable_v<Func, for_each_elem_ref<T, Array>, size_t>,
+ std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
+ std::conditional_t<
+ // second form
+ std::is_invocable_v<Func, size_t, for_each_elem_ref<T, Array>>,
+ std::is_nothrow_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
+ std::conditional_t<
+ // third form
+ std::is_invocable_v<Func, for_each_elem_ref<T, Array>>,
+ std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>>, std::false_type>>>;
+
+ template <typename Func, typename Array>
+ using can_for_each_any =
+ std::disjunction<can_for_each<Func, Array, table>, can_for_each<Func, Array, array>,
+ can_for_each<Func, Array, std::string>, can_for_each<Func, Array, int64_t>,
+ can_for_each<Func, Array, double>, can_for_each<Func, Array, bool>,
+ can_for_each<Func, Array, date>, can_for_each<Func, Array, time>,
+ can_for_each<Func, Array, date_time>>;
+
+ template <typename Func, typename Array, typename T>
+ using for_each_is_nothrow_one =
+ std::disjunction<std::negation<can_for_each<Func, Array, T>>, //
+ can_for_each_nothrow<Func, Array, T>>;
+
+ template <typename Func, typename Array>
+ using for_each_is_nothrow = std::conjunction<
+ for_each_is_nothrow_one<Func, Array, table>, for_each_is_nothrow_one<Func, Array, array>,
+ for_each_is_nothrow_one<Func, Array, std::string>,
+ for_each_is_nothrow_one<Func, Array, int64_t>, for_each_is_nothrow_one<Func, Array, double>,
+ for_each_is_nothrow_one<Func, Array, bool>, for_each_is_nothrow_one<Func, Array, date>,
+ for_each_is_nothrow_one<Func, Array, time>,
+ for_each_is_nothrow_one<Func, Array, date_time>>;
+
+ template <typename Func, typename Array>
+ static void do_for_each(Func&& visitor, Array&& arr) //
+ noexcept(for_each_is_nothrow<Func&&, Array&&>::value) {
+ static_assert(
+ can_for_each_any<Func&&, Array&&>::value,
+ "TOML array for_each visitors must be invocable for at least one of the toml::node "
+ "specializations:" TOML_SA_NODE_TYPE_LIST);
+
+ for (size_t i = 0; i < arr.size(); i++) {
+ using node_ref = impl::copy_cvref<toml::node, Array&&>;
+ 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, Array, node_ref>, //
- TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE);
+ static_assert(impl::always_false<Func, Array, node_ref>, //
+ TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE);
#endif
- static_cast<node_ref>(static_cast<Array&&>(arr)[i])
- .visit(
- [&]([[maybe_unused]] auto&& elem) //
- noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value)
- {
- using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
- static_assert(std::is_reference_v<elem_ref>);
-
- // func(elem, i)
- if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>)
- {
- static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
- }
-
- // func(i, elem)
- else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>)
- {
- static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
- }
-
- // func(elem)
- else if constexpr (std::is_invocable_v<Func&&, elem_ref>)
- {
- static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
- }
- });
+ static_cast<node_ref>(static_cast<Array&&>(arr)[i])
+ .visit([&]([[maybe_unused]] auto&& elem) //
+ noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value) {
+ using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
+ static_assert(std::is_reference_v<elem_ref>);
+
+ // func(elem, i)
+ if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>) {
+ static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
+ }
+
+ // func(i, elem)
+ else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>) {
+ static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
+ }
+
+ // func(elem)
+ else if constexpr (std::is_invocable_v<Func&&, elem_ref>) {
+ static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
+ }
+ });
#else
- const auto keep_going =
- static_cast<node_ref>(static_cast<Array&&>(arr)[i])
- .visit(
- [&]([[maybe_unused]] auto&& elem) //
- noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value)
- {
- using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
- static_assert(std::is_reference_v<elem_ref>);
-
- // func(elem, i)
- if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>)
- {
- using return_type =
- decltype(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i));
-
- if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
- {
- return static_cast<bool>(
- static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i));
- }
- else
- {
- static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
- return true;
- }
- }
-
- // func(i, elem)
- else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>)
- {
- using return_type =
- decltype(static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem)));
-
- if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
- {
- return static_cast<bool>(
- static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem)));
- }
- else
- {
- static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
- return true;
- }
- }
-
- // func(elem)
- else if constexpr (std::is_invocable_v<Func&&, elem_ref>)
- {
- using return_type =
- decltype(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem)));
-
- if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
- {
- return static_cast<bool>(
- static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem)));
- }
- else
- {
- static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
- return true;
- }
- }
-
- // visitor not compatible with this particular type
- else
- return true;
- });
-
- if (!keep_going)
- return;
+ const auto keep_going =
+ static_cast<node_ref>(static_cast<Array&&>(arr)[i])
+ .visit(
+ [&]([[maybe_unused]] auto&& elem) //
+ noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value) {
+ using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
+ static_assert(std::is_reference_v<elem_ref>);
+
+ // func(elem, i)
+ if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>) {
+ using return_type =
+ decltype(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i));
+
+ if constexpr (impl::is_constructible_or_convertible<bool, return_type>) {
+ return static_cast<bool>(
+ static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i));
+ } else {
+ static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
+ return true;
+ }
+ }
+
+ // func(i, elem)
+ else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>) {
+ using return_type =
+ decltype(static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem)));
+
+ if constexpr (impl::is_constructible_or_convertible<bool, return_type>) {
+ return static_cast<bool>(
+ static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem)));
+ } else {
+ static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
+ return true;
+ }
+ }
+
+ // func(elem)
+ else if constexpr (std::is_invocable_v<Func&&, elem_ref>) {
+ using return_type =
+ decltype(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem)));
+
+ if constexpr (impl::is_constructible_or_convertible<bool, return_type>) {
+ return static_cast<bool>(
+ static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem)));
+ } else {
+ static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
+ 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 element in the array.
- ///
- /// \tparam Func A callable type invocable with one of the following signatures:
- /// <ul>
- /// <li> `func(elem, index)`
- /// <li> `func(elem)`
- /// <li> `func(index, elem)`
- /// </ul>
- /// Where:
- /// <ul>
- /// <li> `elem` will recieve the element as it's concrete type with cvref-qualifications matching the array
- /// <li> `index` will recieve a `size_t` indicating the element's index
- /// </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 array.
- ///
- /// \details \cpp
- /// toml::array arr{ 0, 1, 2, 3.0, "four", "five", 6 };
- ///
- /// // select only the integers using a strongly-typed visitor
- /// arr.for_each([](toml::value<int64_t>& elem)
- /// {
- /// std::cout << elem << ", ";
- /// });
- /// std::cout << "\n";
- ///
- /// // select all the numeric values using a generic visitor + is_number<> metafunction
- /// arr.for_each([](auto&& elem)
- /// {
- /// if constexpr (toml::is_number<decltype(elem)>)
- /// std::cout << elem << ", ";
- /// });
- /// std::cout << "\n";
- ///
- /// // select all the numeric values until we encounter something non-numeric
- /// arr.for_each([](auto&& elem)
- /// {
- /// if constexpr (toml::is_number<decltype(elem)>)
- /// {
- /// std::cout << elem << ", ";
- /// return true; // "keep going"
- /// }
- /// else
- /// return false; // "stop!"
- ///
- /// });
- /// std::cout << "\n";
- ///
- /// \ecpp
- /// \out
- /// 0, 1, 2, 6,
- /// 0, 1, 2, 3.0, 6,
- /// 0, 1, 2, 3.0,
- /// \eout
- ///
- /// \see node::visit()
- template <typename Func>
- array& for_each(Func&& visitor) & //
- noexcept(for_each_is_nothrow<Func&&, array&>::value)
- {
- do_for_each(static_cast<Func&&>(visitor), *this);
- return *this;
- }
-
- /// \brief Invokes a visitor on each element in the array (rvalue overload).
- template <typename Func>
- array&& for_each(Func&& visitor) && //
- noexcept(for_each_is_nothrow<Func&&, array&&>::value)
- {
- do_for_each(static_cast<Func&&>(visitor), static_cast<array&&>(*this));
- return static_cast<array&&>(*this);
- }
-
- /// \brief Invokes a visitor on each element in the array (const lvalue overload).
- template <typename Func>
- const array& for_each(Func&& visitor) const& //
- noexcept(for_each_is_nothrow<Func&&, const array&>::value)
- {
- do_for_each(static_cast<Func&&>(visitor), *this);
- return *this;
- }
-
- /// \brief Invokes a visitor on each element in the array (const rvalue overload).
- template <typename Func>
- const array&& for_each(Func&& visitor) const&& //
- noexcept(for_each_is_nothrow<Func&&, const array&&>::value)
- {
- do_for_each(static_cast<Func&&>(visitor), static_cast<const array&&>(*this));
- return static_cast<const array&&>(*this);
- }
-
- /// @}
-
- /// \name Size and Capacity
- /// @{
-
- /// \brief Returns true if the array is empty.
- TOML_NODISCARD
- bool empty() const noexcept
- {
- return elems_.empty();
- }
-
- /// \brief Returns the number of elements in the array.
- TOML_NODISCARD
- size_t size() const noexcept
- {
- return elems_.size();
- }
-
- /// \brief Returns the maximum number of elements that can be stored in an array on the current platform.
- TOML_NODISCARD
- size_t max_size() const noexcept
- {
- return elems_.max_size();
- }
-
- /// \brief Returns the current max number of elements that may be held in the array's internal storage.
- TOML_NODISCARD
- size_t capacity() const noexcept
- {
- return elems_.capacity();
- }
-
- /// \brief Reserves internal storage capacity up to a pre-determined number of elements.
- TOML_EXPORTED_MEMBER_FUNCTION
- void reserve(size_t new_capacity);
-
- /// \brief Requests the removal of any unused internal storage capacity.
- TOML_EXPORTED_MEMBER_FUNCTION
- void shrink_to_fit();
-
- /// \brief Shrinks the array to the given size.
- ///
- /// \detail \godbolt{rxEzK5}
- ///
- /// \cpp
- /// auto arr = toml::array{ 1, 2, 3 };
- /// std::cout << arr << "\n";
- ///
- /// arr.truncate(5); // no-op
- /// std::cout << arr << "\n";
- ///
- /// arr.truncate(1);
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 2, 3 ]
- /// [ 1, 2, 3 ]
- /// [ 1]
- /// \eout
- ///
- /// \remarks Does nothing if the requested size is larger than or equal to the current size.
- TOML_EXPORTED_MEMBER_FUNCTION
- void truncate(size_t new_size);
-
- /// \brief Resizes the array.
- ///
- /// \detail \godbolt{W5zqx3}
- ///
- /// \cpp
- /// auto arr = toml::array{ 1, 2, 3 };
- /// std::cout << arr << "\n";
- ///
- /// arr.resize(6, 42);
- /// std::cout << arr << "\n";
- ///
- /// arr.resize(2, 0);
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 2, 3 ]
- /// [ 1, 2, 3, 42, 42, 42 ]
- /// [ 1, 2 ]
- /// \eout
- ///
- /// \tparam ElemType toml::node, toml::table, toml::array, or a native TOML value type
- /// (or a type promotable to one).
- ///
- /// \param new_size The number of elements the array will have after resizing.
- /// \param default_init_val The node or value used to initialize new elements if the array needs to grow.
- /// \param default_init_flags Value flags to apply to new values created if new elements are created by growing.
- template <typename ElemType>
- void resize(size_t new_size,
- ElemType&& default_init_val,
- value_flags default_init_flags = preserve_source_value_flags)
- {
- static_assert(!is_node_view<ElemType>,
- "The default element type argument to toml::array::resize may not be toml::node_view.");
-
- if (!new_size)
- clear();
- else if (new_size > elems_.size())
- insert(cend(), new_size - elems_.size(), static_cast<ElemType&&>(default_init_val), default_init_flags);
- else
- truncate(new_size);
- }
-
- /// @}
-
- /// \name Erasure
- /// @{
-
- /// \brief Removes the specified element from the array.
- ///
- /// \detail \cpp
- /// auto arr = toml::array{ 1, 2, 3 };
- /// std::cout << arr << "\n";
- ///
- /// arr.erase(arr.cbegin() + 1);
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 2, 3 ]
- /// [ 1, 3 ]
- /// \eout
- ///
- /// \param pos Iterator to the element being erased.
- ///
- /// \returns Iterator to the first element immediately following the removed element.
- TOML_EXPORTED_MEMBER_FUNCTION
- iterator erase(const_iterator pos) noexcept;
-
- /// \brief Removes the elements in the range [first, last) from the array.
- ///
- /// \detail \cpp
- /// auto arr = toml::array{ 1, "bad", "karma" 2 };
- /// std::cout << arr << "\n";
- ///
- /// arr.erase(arr.cbegin() + 1, arr.cbegin() + 3);
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 'bad', 'karma', 3 ]
- /// [ 1, 3 ]
- /// \eout
- ///
- /// \param first Iterator to the first element being erased.
- /// \param last Iterator to the one-past-the-last element being erased.
- ///
- /// \returns Iterator to the first element immediately following the last removed element.
- TOML_EXPORTED_MEMBER_FUNCTION
- iterator erase(const_iterator first, const_iterator last) noexcept;
-
- /// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself.
- ///
- /// \detail \cpp
- ///
- /// auto arr = toml::array{ 1, 2, toml::array{ 3, 4, toml::array{ 5 } }, 6, toml::array{} };
- /// std::cout << arr << "\n";
- ///
- /// arr.flatten();
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 2, [ 3, 4, [ 5 ] ], 6, [] ]
- /// [ 1, 2, 3, 4, 5, 6 ]
- /// \eout
- ///
- /// \remarks Arrays inside child tables are not flattened.
- ///
- /// \returns A reference to the array.
- TOML_EXPORTED_MEMBER_FUNCTION
- array& flatten() &;
-
- /// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself (rvalue overload).
- array&& flatten() &&
- {
- return static_cast<toml::array&&>(this->flatten());
- }
-
- /// \brief Removes empty child arrays and tables.
- ///
- /// \detail \cpp
- ///
- /// auto arr = toml::array{ 1, 2, toml::array{ }, toml::array{ 3, toml::array{ } }, 4 };
- /// std::cout << arr << "\n";
- ///
- /// arr.prune(true);
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 2, [], [ 3, [] ], 4 ]
- /// [ 1, 2, [ 3 ], 4 ]
- /// \eout
- ///
- /// \param recursive Should child arrays and tables themselves be pruned?
- ///
- /// \returns A reference to the array.
- TOML_EXPORTED_MEMBER_FUNCTION
- array& 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 array.
- array&& prune(bool recursive = true) && noexcept
- {
- return static_cast<toml::array&&>(this->prune(recursive));
- }
-
- /// \brief Removes the last element from the array.
- TOML_EXPORTED_MEMBER_FUNCTION
- void pop_back() noexcept;
-
- /// \brief Removes all elements from the array.
- TOML_EXPORTED_MEMBER_FUNCTION
- void clear() noexcept;
-
- /// @}
-
- /// \name Insertion and Emplacement
- /// @{
-
- /// \brief Inserts a new element at a specific position in the array.
- ///
- /// \detail \cpp
- /// auto arr = toml::array{ 1, 3 };
- /// arr.insert(arr.cbegin() + 1, "two");
- /// arr.insert(arr.cend(), toml::array{ 4, 5 });
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 'two', 3, [ 4, 5 ] ]
- /// \eout
- ///
- /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
- /// (or a type promotable to one).
- /// \param pos The insertion position.
- /// \param val The node or value being inserted.
- /// \param flags Value flags to apply to new values.
- ///
- /// \returns \conditional_return{Valid input}
- /// An iterator to the newly-inserted element.
- /// \conditional_return{Input is a null toml::node_view}
- /// end()
- ///
- /// \attention The return value will always be `end()` if the input value was a null toml::node_view,
- /// because no insertion can take place. This is the only circumstance in which this can occur.
- template <typename ElemType>
- iterator insert(const_iterator pos, ElemType&& val, value_flags flags = preserve_source_value_flags)
- {
- if constexpr (is_node_view<ElemType>)
- {
- if (!val)
- return end();
- }
- return iterator{ insert_at(const_vector_iterator{ pos },
- impl::make_node(static_cast<ElemType&&>(val), flags)) };
- }
-
- /// \brief Repeatedly inserts a new element starting at a specific position in the array.
- ///
- /// \detail \cpp
- /// auto arr = toml::array{
- /// "with an evil twinkle in its eye the goose said",
- /// "and immediately we knew peace was never an option."
- /// };
- /// arr.insert(arr.cbegin() + 1, 3, "honk");
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [
- /// 'with an evil twinkle in its eye the goose said',
- /// 'honk',
- /// 'honk',
- /// 'honk',
- /// 'and immediately we knew peace was never an option.'
- /// ]
- /// \eout
- ///
- /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
- /// (or a type promotable to one).
- /// \param pos The insertion position.
- /// \param count The number of times the node or value should be inserted.
- /// \param val The node or value being inserted.
- /// \param flags Value flags to apply to new values.
- ///
- /// \returns \conditional_return{Valid input}
- /// An iterator to the newly-inserted element.
- /// \conditional_return{count == 0}
- /// A copy of pos
- /// \conditional_return{Input is a null toml::node_view}
- /// end()
- ///
- /// \attention The return value will always be `end()` if the input value was a null toml::node_view,
- /// because no insertion can take place. This is the only circumstance in which this can occur.
- template <typename ElemType>
- iterator insert(const_iterator pos,
- size_t count,
- ElemType&& val,
- value_flags flags = preserve_source_value_flags)
- {
- if constexpr (is_node_view<ElemType>)
- {
- if (!val)
- return end();
- }
- switch (count)
- {
- case 0: return iterator{ elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin()) };
- case 1: return insert(pos, static_cast<ElemType&&>(val), flags);
- default:
- {
- const auto start_idx = static_cast<size_t>(const_vector_iterator{ pos } - elems_.cbegin());
- preinsertion_resize(start_idx, count);
- size_t i = start_idx;
- for (size_t e = start_idx + count - 1u; i < e; i++)
- elems_[i] = impl::make_node(val, flags);
-
- //# potentially move the initial value into the last element
- elems_[i] = impl::make_node(static_cast<ElemType&&>(val), flags);
- return iterator{ elems_.begin() + static_cast<ptrdiff_t>(start_idx) };
- }
- }
- }
-
- /// \brief Inserts a range of elements into the array at a specific position.
- ///
- /// \tparam Iter An iterator type. Must satisfy ForwardIterator.
- /// \param pos The insertion position.
- /// \param first Iterator to the first node or value being inserted.
- /// \param last Iterator to the one-past-the-last node or value being inserted.
- /// \param flags Value flags to apply to new values.
- ///
- /// \returns \conditional_return{Valid input}
- /// An iterator to the first newly-inserted element.
- /// \conditional_return{first >= last}
- /// A copy of pos
- /// \conditional_return{All objects in the range were null toml::node_views}
- /// A copy of pos
- template <typename Iter>
- iterator insert(const_iterator pos, Iter first, Iter last, value_flags flags = preserve_source_value_flags)
- {
- const auto distance = std::distance(first, last);
- if (distance <= 0)
- return iterator{ elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin()) };
- else
- {
- auto count = distance;
- using deref_type = decltype(*first);
- if constexpr (is_node_view<deref_type>)
- {
- for (auto it = first; it != last; it++)
- if (!(*it))
- count--;
- if (!count)
- return iterator{ elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin()) };
- }
- const auto start_idx = static_cast<size_t>(const_vector_iterator{ pos } - elems_.cbegin());
- preinsertion_resize(start_idx, static_cast<size_t>(count));
- size_t i = start_idx;
- for (auto it = first; it != last; it++)
- {
- if constexpr (is_node_view<deref_type>)
- {
- if (!(*it))
- continue;
- }
- if constexpr (std::is_rvalue_reference_v<deref_type>)
- elems_[i++] = impl::make_node(std::move(*it), flags);
- else
- elems_[i++] = impl::make_node(*it, flags);
- }
- return iterator{ elems_.begin() + static_cast<ptrdiff_t>(start_idx) };
- }
- }
-
- /// \brief Inserts a range of elements into the array at a specific position.
- ///
- /// \tparam ElemType toml::node_view, toml::table, toml::array, or a native TOML value type
- /// (or a type promotable to one).
- /// \param pos The insertion position.
- /// \param ilist An initializer list containing the values to be inserted.
- /// \param flags Value flags to apply to new values.
- ///
- /// \returns \conditional_return{Valid input}
- /// An iterator to the first newly-inserted element.
- /// \conditional_return{Input list is empty}
- /// A copy of pos
- /// \conditional_return{All objects in the list were null toml::node_views}
- /// A copy of pos
- template <typename ElemType>
- iterator insert(const_iterator pos,
- std::initializer_list<ElemType> ilist,
- value_flags flags = preserve_source_value_flags)
- {
- return insert(pos, ilist.begin(), ilist.end(), flags);
- }
-
- /// \brief Emplaces a new element at a specific position in the array.
- ///
- /// \detail \cpp
- /// auto arr = toml::array{ 1, 2 };
- ///
- /// //add a string using std::string's substring constructor
- /// arr.emplace<std::string>(arr.cbegin() + 1, "this is not a drill"sv, 14, 5);
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 'drill', 2 ]
- /// \eout
- ///
- /// \tparam ElemType toml::table, toml::array, or any native TOML value type.
- /// \tparam Args Value constructor argument types.
- /// \param pos The insertion position.
- /// \param args Arguments to forward to the value's constructor.
- ///
- /// \returns An iterator to the inserted element.
- ///
- /// \remarks There is no difference between insert() and emplace()
- /// for trivial value types (floats, ints, bools).
- template <typename ElemType = void, typename... Args>
- iterator emplace(const_iterator pos, Args&&... args)
- {
- using raw_elem_type = impl::remove_cvref<ElemType>;
- using elem_type = std::conditional_t<std::is_void_v<raw_elem_type>, //
- impl::emplaced_type_of<Args&&...>,
- raw_elem_type>;
-
- using type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
- static_assert(impl::is_native<type> || impl::is_one_of<type, table, array>,
- "Emplacement type parameter must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
-
- return iterator{ insert_at(const_vector_iterator{ pos },
- impl::node_ptr{ new impl::wrap_node<type>{ static_cast<Args&&>(args)... } }) };
- }
-
- /// \brief Replaces the element at a specific position in the array with a different value.
- ///
- /// \detail \cpp
- /// auto arr = toml::array{ 1, 2, 3 };
- /// std::cout << arr << "\n";
- /// arr.replace(arr.cbegin() + 1, "two");
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 2, 3 ]
- /// [ 1, 'two', 3 ]
- /// \eout
- ///
- /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
- /// (or a type promotable to one).
- /// \param pos The insertion position.
- /// \param val The node or value being inserted.
- /// \param flags Value flags to apply to new values.
- ///
- /// \returns \conditional_return{Valid input}
- /// An iterator to the replaced element.
- /// \conditional_return{Input is a null toml::node_view}
- /// end()
- ///
- /// \attention The return value will always be `end()` if the input value was a null toml::node_view,
- /// because no replacement can take place. This is the only circumstance in which this can occur.
- template <typename ElemType>
- iterator replace(const_iterator pos, ElemType&& val, value_flags flags = preserve_source_value_flags)
- {
- TOML_ASSERT(pos >= cbegin() && pos < cend());
-
- if constexpr (is_node_view<ElemType>)
- {
- if (!val)
- return end();
- }
-
- const auto it = elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin());
- *it = impl::make_node(static_cast<ElemType&&>(val), flags);
- return iterator{ it };
- }
-
- /// \brief Appends a new element to the end of the array.
- ///
- /// \detail \cpp
- /// auto arr = toml::array{ 1, 2 };
- /// arr.push_back(3);
- /// arr.push_back(4.0);
- /// arr.push_back(toml::array{ 5, "six"sv });
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 2, 3, 4.0, [ 5, 'six' ] ]
- /// \eout
- ///
- /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
- /// \param val The node or value being added.
- /// \param flags Value flags to apply to new values.
- ///
- /// \attention No insertion takes place if the input value is a null toml::node_view.
- /// This is the only circumstance in which this can occur.
- template <typename ElemType>
- void push_back(ElemType&& val, value_flags flags = preserve_source_value_flags)
- {
- emplace_back_if_not_empty_view(static_cast<ElemType&&>(val), flags);
- }
-
- /// \brief Emplaces a new element at the end of the array.
- ///
- /// \detail \cpp
- /// auto arr = toml::array{ 1, 2 };
- /// arr.emplace_back<toml::array>(3, "four"sv);
- /// std::cout << arr << "\n";
- /// \ecpp
- ///
- /// \out
- /// [ 1, 2, [ 3, 'four' ] ]
- /// \eout
- ///
- /// \tparam ElemType toml::table, toml::array, or a native TOML value type
- /// \tparam Args Element constructor argument types.
- /// \param args Arguments to forward to the elements's constructor.
- ///
- /// \returns A reference to the newly-constructed element.
- ///
- /// \remarks There is no difference between push_back() and emplace_back()
- /// For trivial value types (floats, ints, bools).
- template <typename ElemType = void, typename... Args>
- decltype(auto) emplace_back(Args&&... args)
- {
- using raw_elem_type = impl::remove_cvref<ElemType>;
- using elem_type = std::conditional_t<std::is_void_v<raw_elem_type>, //
- impl::emplaced_type_of<Args&&...>,
- raw_elem_type>;
-
- static constexpr auto moving_node_ptr = std::is_same_v<elem_type, impl::node_ptr> //
- && sizeof...(Args) == 1u //
- && impl::first_is_same<impl::node_ptr&&, Args&&...>;
-
- using unwrapped_type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
-
- static_assert(
- moving_node_ptr //
- || impl::is_native<unwrapped_type> //
- || impl::is_one_of<unwrapped_type, table, array>, //
- "ElemType argument of array::emplace_back() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
-
- if constexpr (moving_node_ptr)
- {
- insert_at_back(static_cast<Args&&>(args)...);
- return *elems_.back();
- }
- else
- {
- auto ptr = new impl::wrap_node<unwrapped_type>{ static_cast<Args&&>(args)... };
- insert_at_back(impl::node_ptr{ ptr });
- return *ptr;
- }
- }
-
- /// @}
-
- private:
- /// \cond
-
- TOML_NODISCARD
- TOML_EXPORTED_STATIC_FUNCTION
- static bool TOML_CALLCONV equal(const array&, const array&) noexcept;
-
- template <typename T>
- TOML_NODISCARD
- static bool equal_to_container(const array& lhs, const T& rhs) noexcept
- {
- using element_type = std::remove_const_t<typename T::value_type>;
- static_assert(impl::is_losslessly_convertible_to_native<element_type>,
- "Container element type must be losslessly convertible one of the native TOML value types");
-
- if (lhs.size() != rhs.size())
- return false;
- if (rhs.size() == 0u)
- return true;
-
- size_t i{};
- for (auto& list_elem : rhs)
- {
- const auto elem = lhs.get_as<impl::native_type_of<element_type>>(i++);
- if (!elem || *elem != list_elem)
- return false;
- }
-
- return true;
- }
-
- /// \endcond
-
- public:
- /// \name Equality
- /// @{
-
- /// \brief Equality operator.
- ///
- /// \param lhs The LHS array.
- /// \param rhs The RHS array.
- ///
- /// \returns True if the arrays contained the same elements.
- TOML_NODISCARD
- friend bool operator==(const array& lhs, const array& rhs) noexcept
- {
- return equal(lhs, rhs);
- }
-
- /// \brief Inequality operator.
- ///
- /// \param lhs The LHS array.
- /// \param rhs The RHS array.
- ///
- /// \returns True if the arrays did not contain the same elements.
- TOML_NODISCARD
- friend bool operator!=(const array& lhs, const array& rhs) noexcept
- {
- return !equal(lhs, rhs);
- }
-
- /// \brief Initializer list equality operator.
- template <typename T>
- TOML_NODISCARD
- friend bool operator==(const array& lhs, const std::initializer_list<T>& rhs) noexcept
- {
- return equal_to_container(lhs, rhs);
- }
- TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::initializer_list<T>&, template <typename T>);
-
- /// \brief Vector equality operator.
- template <typename T>
- TOML_NODISCARD
- friend bool operator==(const array& lhs, const std::vector<T>& rhs) noexcept
- {
- return equal_to_container(lhs, rhs);
- }
- TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::vector<T>&, template <typename T>);
-
- /// @}
+ }
+ }
+
+ /// \endcond
+
+ public:
+ /// \brief Invokes a visitor on each element in the array.
+ ///
+ /// \tparam Func A callable type invocable with one of the following signatures:
+ /// <ul>
+ /// <li> `func(elem, index)`
+ /// <li> `func(elem)`
+ /// <li> `func(index, elem)`
+ /// </ul>
+ /// Where:
+ /// <ul>
+ /// <li> `elem` will recieve the element as it's concrete type with cvref-qualifications
+ ///matching the array <li> `index` will recieve a `size_t` indicating the element's index
+ /// </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 array.
+ ///
+ /// \details \cpp
+ /// toml::array arr{ 0, 1, 2, 3.0, "four", "five", 6 };
+ ///
+ /// // select only the integers using a strongly-typed visitor
+ /// arr.for_each([](toml::value<int64_t>& elem)
+ /// {
+ /// std::cout << elem << ", ";
+ /// });
+ /// std::cout << "\n";
+ ///
+ /// // select all the numeric values using a generic visitor + is_number<> metafunction
+ /// arr.for_each([](auto&& elem)
+ /// {
+ /// if constexpr (toml::is_number<decltype(elem)>)
+ /// std::cout << elem << ", ";
+ /// });
+ /// std::cout << "\n";
+ ///
+ /// // select all the numeric values until we encounter something non-numeric
+ /// arr.for_each([](auto&& elem)
+ /// {
+ /// if constexpr (toml::is_number<decltype(elem)>)
+ /// {
+ /// std::cout << elem << ", ";
+ /// return true; // "keep going"
+ /// }
+ /// else
+ /// return false; // "stop!"
+ ///
+ /// });
+ /// std::cout << "\n";
+ ///
+ /// \ecpp
+ /// \out
+ /// 0, 1, 2, 6,
+ /// 0, 1, 2, 3.0, 6,
+ /// 0, 1, 2, 3.0,
+ /// \eout
+ ///
+ /// \see node::visit()
+ template <typename Func>
+ array& for_each(Func&& visitor) & //
+ noexcept(for_each_is_nothrow<Func&&, array&>::value) {
+ do_for_each(static_cast<Func&&>(visitor), *this);
+ return *this;
+ }
+
+ /// \brief Invokes a visitor on each element in the array (rvalue overload).
+ template <typename Func>
+ array&& for_each(Func&& visitor) && //
+ noexcept(for_each_is_nothrow<Func&&, array&&>::value) {
+ do_for_each(static_cast<Func&&>(visitor), static_cast<array&&>(*this));
+ return static_cast<array&&>(*this);
+ }
+
+ /// \brief Invokes a visitor on each element in the array (const lvalue overload).
+ template <typename Func>
+ const array& for_each(Func&& visitor) const& //
+ noexcept(for_each_is_nothrow<Func&&, const array&>::value) {
+ do_for_each(static_cast<Func&&>(visitor), *this);
+ return *this;
+ }
+
+ /// \brief Invokes a visitor on each element in the array (const rvalue overload).
+ template <typename Func>
+ const array&& for_each(Func&& visitor) const&& //
+ noexcept(for_each_is_nothrow<Func&&, const array&&>::value) {
+ do_for_each(static_cast<Func&&>(visitor), static_cast<const array&&>(*this));
+ return static_cast<const array&&>(*this);
+ }
+
+ /// @}
+
+ /// \name Size and Capacity
+ /// @{
+
+ /// \brief Returns true if the array is empty.
+ TOML_NODISCARD
+ bool empty() const noexcept { return elems_.empty(); }
+
+ /// \brief Returns the number of elements in the array.
+ TOML_NODISCARD
+ size_t size() const noexcept { return elems_.size(); }
+
+ /// \brief Returns the maximum number of elements that can be stored in an array on the current
+ /// platform.
+ TOML_NODISCARD
+ size_t max_size() const noexcept { return elems_.max_size(); }
+
+ /// \brief Returns the current max number of elements that may be held in the array's internal
+ /// storage.
+ TOML_NODISCARD
+ size_t capacity() const noexcept { return elems_.capacity(); }
+
+ /// \brief Reserves internal storage capacity up to a pre-determined number of elements.
+ TOML_EXPORTED_MEMBER_FUNCTION
+ void reserve(size_t new_capacity);
+
+ /// \brief Requests the removal of any unused internal storage capacity.
+ TOML_EXPORTED_MEMBER_FUNCTION
+ void shrink_to_fit();
+
+ /// \brief Shrinks the array to the given size.
+ ///
+ /// \detail \godbolt{rxEzK5}
+ ///
+ /// \cpp
+ /// auto arr = toml::array{ 1, 2, 3 };
+ /// std::cout << arr << "\n";
+ ///
+ /// arr.truncate(5); // no-op
+ /// std::cout << arr << "\n";
+ ///
+ /// arr.truncate(1);
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 2, 3 ]
+ /// [ 1, 2, 3 ]
+ /// [ 1]
+ /// \eout
+ ///
+ /// \remarks Does nothing if the requested size is larger than or equal to the current size.
+ TOML_EXPORTED_MEMBER_FUNCTION
+ void truncate(size_t new_size);
+
+ /// \brief Resizes the array.
+ ///
+ /// \detail \godbolt{W5zqx3}
+ ///
+ /// \cpp
+ /// auto arr = toml::array{ 1, 2, 3 };
+ /// std::cout << arr << "\n";
+ ///
+ /// arr.resize(6, 42);
+ /// std::cout << arr << "\n";
+ ///
+ /// arr.resize(2, 0);
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 2, 3 ]
+ /// [ 1, 2, 3, 42, 42, 42 ]
+ /// [ 1, 2 ]
+ /// \eout
+ ///
+ /// \tparam ElemType toml::node, toml::table, toml::array, or a native TOML value type
+ /// (or a type promotable to one).
+ ///
+ /// \param new_size The number of elements the array will have after resizing.
+ /// \param default_init_val The node or value used to initialize new elements if the array
+ /// needs to grow.
+ /// \param default_init_flags Value flags to apply to new values created if new elements are
+ /// created by growing.
+ template <typename ElemType>
+ void resize(size_t new_size, ElemType&& default_init_val,
+ value_flags default_init_flags = preserve_source_value_flags) {
+ static_assert(
+ !is_node_view<ElemType>,
+ "The default element type argument to toml::array::resize may not be toml::node_view.");
+
+ if (!new_size)
+ clear();
+ else if (new_size > elems_.size())
+ insert(cend(), new_size - elems_.size(), static_cast<ElemType&&>(default_init_val),
+ default_init_flags);
+ else
+ truncate(new_size);
+ }
+
+ /// @}
+
+ /// \name Erasure
+ /// @{
+
+ /// \brief Removes the specified element from the array.
+ ///
+ /// \detail \cpp
+ /// auto arr = toml::array{ 1, 2, 3 };
+ /// std::cout << arr << "\n";
+ ///
+ /// arr.erase(arr.cbegin() + 1);
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 2, 3 ]
+ /// [ 1, 3 ]
+ /// \eout
+ ///
+ /// \param pos Iterator to the element being erased.
+ ///
+ /// \returns Iterator to the first element immediately following the removed element.
+ TOML_EXPORTED_MEMBER_FUNCTION
+ iterator erase(const_iterator pos) noexcept;
+
+ /// \brief Removes the elements in the range [first, last) from the array.
+ ///
+ /// \detail \cpp
+ /// auto arr = toml::array{ 1, "bad", "karma" 2 };
+ /// std::cout << arr << "\n";
+ ///
+ /// arr.erase(arr.cbegin() + 1, arr.cbegin() + 3);
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 'bad', 'karma', 3 ]
+ /// [ 1, 3 ]
+ /// \eout
+ ///
+ /// \param first Iterator to the first element being erased.
+ /// \param last Iterator to the one-past-the-last element being erased.
+ ///
+ /// \returns Iterator to the first element immediately following the last removed element.
+ TOML_EXPORTED_MEMBER_FUNCTION
+ iterator erase(const_iterator first, const_iterator last) noexcept;
+
+ /// \brief Flattens this array, recursively hoisting the contents of child arrays up into
+ /// itself.
+ ///
+ /// \detail \cpp
+ ///
+ /// auto arr = toml::array{ 1, 2, toml::array{ 3, 4, toml::array{ 5 } }, 6, toml::array{} };
+ /// std::cout << arr << "\n";
+ ///
+ /// arr.flatten();
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 2, [ 3, 4, [ 5 ] ], 6, [] ]
+ /// [ 1, 2, 3, 4, 5, 6 ]
+ /// \eout
+ ///
+ /// \remarks Arrays inside child tables are not flattened.
+ ///
+ /// \returns A reference to the array.
+ TOML_EXPORTED_MEMBER_FUNCTION
+ array& flatten() &;
+
+ /// \brief Flattens this array, recursively hoisting the contents of child arrays up into
+ /// itself (rvalue overload).
+ array&& flatten() && { return static_cast<toml::array&&>(this->flatten()); }
+
+ /// \brief Removes empty child arrays and tables.
+ ///
+ /// \detail \cpp
+ ///
+ /// auto arr = toml::array{ 1, 2, toml::array{ }, toml::array{ 3, toml::array{ } }, 4 };
+ /// std::cout << arr << "\n";
+ ///
+ /// arr.prune(true);
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 2, [], [ 3, [] ], 4 ]
+ /// [ 1, 2, [ 3 ], 4 ]
+ /// \eout
+ ///
+ /// \param recursive Should child arrays and tables themselves be pruned?
+ ///
+ /// \returns A reference to the array.
+ TOML_EXPORTED_MEMBER_FUNCTION
+ array& 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 array.
+ array&& prune(bool recursive = true) && noexcept {
+ return static_cast<toml::array&&>(this->prune(recursive));
+ }
+
+ /// \brief Removes the last element from the array.
+ TOML_EXPORTED_MEMBER_FUNCTION
+ void pop_back() noexcept;
+
+ /// \brief Removes all elements from the array.
+ TOML_EXPORTED_MEMBER_FUNCTION
+ void clear() noexcept;
+
+ /// @}
+
+ /// \name Insertion and Emplacement
+ /// @{
+
+ /// \brief Inserts a new element at a specific position in the array.
+ ///
+ /// \detail \cpp
+ /// auto arr = toml::array{ 1, 3 };
+ /// arr.insert(arr.cbegin() + 1, "two");
+ /// arr.insert(arr.cend(), toml::array{ 4, 5 });
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 'two', 3, [ 4, 5 ] ]
+ /// \eout
+ ///
+ /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML
+ /// value type (or a type promotable to one).
+ /// \param pos The insertion position.
+ /// \param val The node or value being inserted.
+ /// \param flags Value flags to apply to new values.
+ ///
+ /// \returns \conditional_return{Valid input}
+ /// An iterator to the newly-inserted element.
+ /// \conditional_return{Input is a null toml::node_view}
+ /// end()
+ ///
+ /// \attention The return value will always be `end()` if the input value was a null
+ /// toml::node_view, because no insertion can take place. This is the only circumstance in which
+ /// this can occur.
+ template <typename ElemType>
+ iterator insert(const_iterator pos, ElemType&& val,
+ value_flags flags = preserve_source_value_flags) {
+ if constexpr (is_node_view<ElemType>) {
+ if (!val) return end();
+ }
+ return iterator{insert_at(const_vector_iterator{pos},
+ impl::make_node(static_cast<ElemType&&>(val), flags))};
+ }
+
+ /// \brief Repeatedly inserts a new element starting at a specific position in the array.
+ ///
+ /// \detail \cpp
+ /// auto arr = toml::array{
+ /// "with an evil twinkle in its eye the goose said",
+ /// "and immediately we knew peace was never an option."
+ /// };
+ /// arr.insert(arr.cbegin() + 1, 3, "honk");
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [
+ /// 'with an evil twinkle in its eye the goose said',
+ /// 'honk',
+ /// 'honk',
+ /// 'honk',
+ /// 'and immediately we knew peace was never an option.'
+ /// ]
+ /// \eout
+ ///
+ /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML
+ /// value type (or a type promotable to one).
+ /// \param pos The insertion position.
+ /// \param count The number of times the node or value should be inserted.
+ /// \param val The node or value being inserted.
+ /// \param flags Value flags to apply to new values.
+ ///
+ /// \returns \conditional_return{Valid input}
+ /// An iterator to the newly-inserted element.
+ /// \conditional_return{count == 0}
+ /// A copy of pos
+ /// \conditional_return{Input is a null toml::node_view}
+ /// end()
+ ///
+ /// \attention The return value will always be `end()` if the input value was a null
+ /// toml::node_view, because no insertion can take place. This is the only circumstance in which
+ /// this can occur.
+ template <typename ElemType>
+ iterator insert(const_iterator pos, size_t count, ElemType&& val,
+ value_flags flags = preserve_source_value_flags) {
+ if constexpr (is_node_view<ElemType>) {
+ if (!val) return end();
+ }
+ switch (count) {
+ case 0:
+ return iterator{elems_.begin() + (const_vector_iterator{pos} - elems_.cbegin())};
+ case 1:
+ return insert(pos, static_cast<ElemType&&>(val), flags);
+ default: {
+ const auto start_idx = static_cast<size_t>(const_vector_iterator{pos} - elems_.cbegin());
+ preinsertion_resize(start_idx, count);
+ size_t i = start_idx;
+ for (size_t e = start_idx + count - 1u; i < e; i++)
+ elems_[i] = impl::make_node(val, flags);
+
+ // # potentially move the initial value into the last element
+ elems_[i] = impl::make_node(static_cast<ElemType&&>(val), flags);
+ return iterator{elems_.begin() + static_cast<ptrdiff_t>(start_idx)};
+ }
+ }
+ }
+
+ /// \brief Inserts a range of elements into the array at a specific position.
+ ///
+ /// \tparam Iter An iterator type. Must satisfy ForwardIterator.
+ /// \param pos The insertion position.
+ /// \param first Iterator to the first node or value being inserted.
+ /// \param last Iterator to the one-past-the-last node or value being inserted.
+ /// \param flags Value flags to apply to new values.
+ ///
+ /// \returns \conditional_return{Valid input}
+ /// An iterator to the first newly-inserted element.
+ /// \conditional_return{first >= last}
+ /// A copy of pos
+ /// \conditional_return{All objects in the range were null toml::node_views}
+ /// A copy of pos
+ template <typename Iter>
+ iterator insert(const_iterator pos, Iter first, Iter last,
+ value_flags flags = preserve_source_value_flags) {
+ const auto distance = std::distance(first, last);
+ if (distance <= 0)
+ return iterator{elems_.begin() + (const_vector_iterator{pos} - elems_.cbegin())};
+ else {
+ auto count = distance;
+ using deref_type = decltype(*first);
+ if constexpr (is_node_view<deref_type>) {
+ for (auto it = first; it != last; it++)
+ if (!(*it)) count--;
+ if (!count)
+ return iterator{elems_.begin() + (const_vector_iterator{pos} - elems_.cbegin())};
+ }
+ const auto start_idx = static_cast<size_t>(const_vector_iterator{pos} - elems_.cbegin());
+ preinsertion_resize(start_idx, static_cast<size_t>(count));
+ size_t i = start_idx;
+ for (auto it = first; it != last; it++) {
+ if constexpr (is_node_view<deref_type>) {
+ if (!(*it)) continue;
+ }
+ if constexpr (std::is_rvalue_reference_v<deref_type>)
+ elems_[i++] = impl::make_node(std::move(*it), flags);
+ else
+ elems_[i++] = impl::make_node(*it, flags);
+ }
+ return iterator{elems_.begin() + static_cast<ptrdiff_t>(start_idx)};
+ }
+ }
+
+ /// \brief Inserts a range of elements into the array at a specific position.
+ ///
+ /// \tparam ElemType toml::node_view, toml::table, toml::array, or a native TOML value type
+ /// (or a type promotable to one).
+ /// \param pos The insertion position.
+ /// \param ilist An initializer list containing the values to be inserted.
+ /// \param flags Value flags to apply to new values.
+ ///
+ /// \returns \conditional_return{Valid input}
+ /// An iterator to the first newly-inserted element.
+ /// \conditional_return{Input list is empty}
+ /// A copy of pos
+ /// \conditional_return{All objects in the list were null toml::node_views}
+ /// A copy of pos
+ template <typename ElemType>
+ iterator insert(const_iterator pos, std::initializer_list<ElemType> ilist,
+ value_flags flags = preserve_source_value_flags) {
+ return insert(pos, ilist.begin(), ilist.end(), flags);
+ }
+
+ /// \brief Emplaces a new element at a specific position in the array.
+ ///
+ /// \detail \cpp
+ /// auto arr = toml::array{ 1, 2 };
+ ///
+ /// //add a string using std::string's substring constructor
+ /// arr.emplace<std::string>(arr.cbegin() + 1, "this is not a drill"sv, 14, 5);
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 'drill', 2 ]
+ /// \eout
+ ///
+ /// \tparam ElemType toml::table, toml::array, or any native TOML value type.
+ /// \tparam Args Value constructor argument types.
+ /// \param pos The insertion position.
+ /// \param args Arguments to forward to the value's constructor.
+ ///
+ /// \returns An iterator to the inserted element.
+ ///
+ /// \remarks There is no difference between insert() and emplace()
+ /// for trivial value types (floats, ints, bools).
+ template <typename ElemType = void, typename... Args>
+ iterator emplace(const_iterator pos, Args&&... args) {
+ using raw_elem_type = impl::remove_cvref<ElemType>;
+ using elem_type = std::conditional_t<std::is_void_v<raw_elem_type>, //
+ impl::emplaced_type_of<Args&&...>, raw_elem_type>;
+
+ using type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
+ static_assert(impl::is_native<type> || impl::is_one_of<type, table, array>,
+ "Emplacement type parameter must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
+
+ return iterator{
+ insert_at(const_vector_iterator{pos},
+ impl::node_ptr{new impl::wrap_node<type>{static_cast<Args&&>(args)...}})};
+ }
+
+ /// \brief Replaces the element at a specific position in the array with a different value.
+ ///
+ /// \detail \cpp
+ /// auto arr = toml::array{ 1, 2, 3 };
+ /// std::cout << arr << "\n";
+ /// arr.replace(arr.cbegin() + 1, "two");
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 2, 3 ]
+ /// [ 1, 'two', 3 ]
+ /// \eout
+ ///
+ /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML
+ /// value type (or a type promotable to one).
+ /// \param pos The insertion position.
+ /// \param val The node or value being inserted.
+ /// \param flags Value flags to apply to new values.
+ ///
+ /// \returns \conditional_return{Valid input}
+ /// An iterator to the replaced element.
+ /// \conditional_return{Input is a null toml::node_view}
+ /// end()
+ ///
+ /// \attention The return value will always be `end()` if the input value was a null
+ /// toml::node_view, because no replacement can take place. This is the only circumstance in
+ /// which this can occur.
+ template <typename ElemType>
+ iterator replace(const_iterator pos, ElemType&& val,
+ value_flags flags = preserve_source_value_flags) {
+ TOML_ASSERT(pos >= cbegin() && pos < cend());
+
+ if constexpr (is_node_view<ElemType>) {
+ if (!val) return end();
+ }
+
+ const auto it = elems_.begin() + (const_vector_iterator{pos} - elems_.cbegin());
+ *it = impl::make_node(static_cast<ElemType&&>(val), flags);
+ return iterator{it};
+ }
+
+ /// \brief Appends a new element to the end of the array.
+ ///
+ /// \detail \cpp
+ /// auto arr = toml::array{ 1, 2 };
+ /// arr.push_back(3);
+ /// arr.push_back(4.0);
+ /// arr.push_back(toml::array{ 5, "six"sv });
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 2, 3, 4.0, [ 5, 'six' ] ]
+ /// \eout
+ ///
+ /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML
+ /// value type
+ /// \param val The node or value being added.
+ /// \param flags Value flags to apply to new values.
+ ///
+ /// \attention No insertion takes place if the input value is a null toml::node_view.
+ /// This is the only circumstance in which this can occur.
+ template <typename ElemType>
+ void push_back(ElemType&& val, value_flags flags = preserve_source_value_flags) {
+ emplace_back_if_not_empty_view(static_cast<ElemType&&>(val), flags);
+ }
+
+ /// \brief Emplaces a new element at the end of the array.
+ ///
+ /// \detail \cpp
+ /// auto arr = toml::array{ 1, 2 };
+ /// arr.emplace_back<toml::array>(3, "four"sv);
+ /// std::cout << arr << "\n";
+ /// \ecpp
+ ///
+ /// \out
+ /// [ 1, 2, [ 3, 'four' ] ]
+ /// \eout
+ ///
+ /// \tparam ElemType toml::table, toml::array, or a native TOML value type
+ /// \tparam Args Element constructor argument types.
+ /// \param args Arguments to forward to the elements's constructor.
+ ///
+ /// \returns A reference to the newly-constructed element.
+ ///
+ /// \remarks There is no difference between push_back() and emplace_back()
+ /// For trivial value types (floats, ints, bools).
+ template <typename ElemType = void, typename... Args>
+ decltype(auto) emplace_back(Args&&... args) {
+ using raw_elem_type = impl::remove_cvref<ElemType>;
+ using elem_type = std::conditional_t<std::is_void_v<raw_elem_type>, //
+ impl::emplaced_type_of<Args&&...>, raw_elem_type>;
+
+ static constexpr auto moving_node_ptr = std::is_same_v<elem_type, impl::node_ptr> //
+ && sizeof...(Args) == 1u //
+ && impl::first_is_same<impl::node_ptr&&, Args&&...>;
+
+ using unwrapped_type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
+
+ static_assert(moving_node_ptr //
+ || impl::is_native<unwrapped_type> //
+ || impl::is_one_of<unwrapped_type, table, array>, //
+ "ElemType argument of array::emplace_back() must be one "
+ "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
+
+ if constexpr (moving_node_ptr) {
+ insert_at_back(static_cast<Args&&>(args)...);
+ return *elems_.back();
+ } else {
+ auto ptr = new impl::wrap_node<unwrapped_type>{static_cast<Args&&>(args)...};
+ insert_at_back(impl::node_ptr{ptr});
+ return *ptr;
+ }
+ }
+
+ /// @}
+
+ private:
+ /// \cond
+
+ TOML_NODISCARD
+ TOML_EXPORTED_STATIC_FUNCTION
+ static bool TOML_CALLCONV equal(const array&, const array&) noexcept;
+
+ template <typename T>
+ TOML_NODISCARD static bool equal_to_container(const array& lhs, const T& rhs) noexcept {
+ using element_type = std::remove_const_t<typename T::value_type>;
+ static_assert(impl::is_losslessly_convertible_to_native<element_type>,
+ "Container element type must be losslessly convertible one of the native TOML "
+ "value types");
+
+ if (lhs.size() != rhs.size()) return false;
+ if (rhs.size() == 0u) return true;
+
+ size_t i{};
+ for (auto& list_elem : rhs) {
+ const auto elem = lhs.get_as<impl::native_type_of<element_type>>(i++);
+ if (!elem || *elem != list_elem) return false;
+ }
+
+ return true;
+ }
+
+ /// \endcond
+
+ public:
+ /// \name Equality
+ /// @{
+
+ /// \brief Equality operator.
+ ///
+ /// \param lhs The LHS array.
+ /// \param rhs The RHS array.
+ ///
+ /// \returns True if the arrays contained the same elements.
+ TOML_NODISCARD
+ friend bool operator==(const array& lhs, const array& rhs) noexcept { return equal(lhs, rhs); }
+
+ /// \brief Inequality operator.
+ ///
+ /// \param lhs The LHS array.
+ /// \param rhs The RHS array.
+ ///
+ /// \returns True if the arrays did not contain the same elements.
+ TOML_NODISCARD
+ friend bool operator!=(const array& lhs, const array& rhs) noexcept { return !equal(lhs, rhs); }
+
+ /// \brief Initializer list equality operator.
+ template <typename T>
+ TOML_NODISCARD friend bool operator==(const array& lhs,
+ const std::initializer_list<T>& rhs) noexcept {
+ return equal_to_container(lhs, rhs);
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::initializer_list<T>&,
+ template <typename T>);
+
+ /// \brief Vector equality operator.
+ template <typename T>
+ TOML_NODISCARD friend bool operator==(const array& lhs, const std::vector<T>& rhs) noexcept {
+ return equal_to_container(lhs, rhs);
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::vector<T>&, template <typename T>);
+
+ /// @}
#if TOML_ENABLE_FORMATTERS
- /// \brief Prints the array 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 array& rhs)
- {
- impl::print_to_stream(lhs, rhs);
- return lhs;
- }
+ /// \brief Prints the array 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 array& rhs) {
+ impl::print_to_stream(lhs, rhs);
+ return lhs;
+ }
#endif
- };
+ };
}
TOML_NAMESPACE_END;