//# This file is a part of toml++ and is subject to the the terms of the MIT license. //# Copyright (c) Mark Gillard //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. // SPDX-License-Identifier: MIT #pragma once #include "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 #define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 1 #else #define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 0 #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." #endif /// \cond TOML_IMPL_NAMESPACE_START { template class TOML_TRIVIAL_ABI array_iterator { private: template friend class array_iterator; using mutable_vector_iterator = std::vector::iterator; using const_vector_iterator = std::vector::const_iterator; using vector_iterator = std::conditional_t; mutable vector_iterator iter_; public: using value_type = std::conditional_t; using reference = value_type&; using pointer = value_type*; using difference_type = ptrdiff_t; using iterator_category = typename std::iterator_traits::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& 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 TOML_NODISCARD_CTOR array_init_elem(T&& val, value_flags flags = preserve_source_value_flags) // : value{ make_node(static_cast(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); /// \brief A RandomAccessIterator for iterating over const elements in a toml::array. using const_array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator); /// \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("arr"); /// std::cout << arr << "\n"; /// /// // increment each element with visit() /// for (auto&& elem : arr) /// { /// elem.visit([](auto&& el) noexcept /// { /// if constexpr (toml::is_number) /// (*el)++; /// else if constexpr (toml::is_string) /// 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(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; 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 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 void emplace_back_if_not_empty_view(T&& val, value_flags flags) { if constexpr (is_node_view) { if (!val) return; } insert_at_back(impl::make_node(static_cast(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, array>), typename ElemType, typename... ElemTypes) TOML_NODISCARD_CTOR explicit array(ElemType&& val, ElemTypes&&... vals) : array{ std::false_type{}, std::initializer_list{ static_cast(val), static_cast(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 TOML_PURE_GETTER bool is_homogeneous() const noexcept { using type = impl::remove_cvref>; static_assert(std::is_void_v || toml::is_value || toml::is_container, "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); } /// \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* as_string() noexcept final { return nullptr; } /// \brief Returns `nullptr`. TOML_CONST_INLINE_GETTER toml::value* as_integer() noexcept final { return nullptr; } /// \brief Returns `nullptr`. TOML_CONST_INLINE_GETTER toml::value* as_floating_point() noexcept final { return nullptr; } /// \brief Returns `nullptr`. TOML_CONST_INLINE_GETTER toml::value* as_boolean() noexcept final { return nullptr; } /// \brief Returns `nullptr`. TOML_CONST_INLINE_GETTER toml::value* as_date() noexcept final { return nullptr; } /// \brief Returns `nullptr`. TOML_CONST_INLINE_GETTER toml::value