//# 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 "value.h" #include "std_vector.h" #include "std_initializer_list.h" #include "make_node.h" #include "header_start.h" /// \cond TOML_IMPL_NAMESPACE_START { template class TOML_TRIVIAL_ABI array_iterator { private: template friend class array_iterator; friend class TOML_NAMESPACE::array; using raw_mutable_iterator = std::vector>::iterator; using raw_const_iterator = std::vector>::const_iterator; using raw_iterator = std::conditional_t; mutable raw_iterator raw_; TOML_NODISCARD_CTOR array_iterator(raw_mutable_iterator raw) noexcept // : raw_{ raw } {} TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst) TOML_NODISCARD_CTOR array_iterator(raw_const_iterator raw) noexcept // : raw_{ raw } {} 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 array_iterator(const array_iterator&) noexcept = default; array_iterator& operator=(const array_iterator&) noexcept = default; array_iterator& operator++() noexcept // ++pre { ++raw_; return *this; } array_iterator operator++(int) noexcept // post++ { array_iterator out{ raw_ }; ++raw_; return out; } array_iterator& operator--() noexcept // --pre { --raw_; return *this; } array_iterator operator--(int) noexcept // post-- { array_iterator out{ raw_ }; --raw_; return out; } TOML_NODISCARD reference operator*() const noexcept { return *raw_->get(); } TOML_NODISCARD pointer operator->() const noexcept { return raw_->get(); } array_iterator& operator+=(ptrdiff_t rhs) noexcept { raw_ += rhs; return *this; } array_iterator& operator-=(ptrdiff_t rhs) noexcept { raw_ -= rhs; return *this; } TOML_NODISCARD friend array_iterator operator+(const array_iterator& lhs, ptrdiff_t rhs) noexcept { return { lhs.raw_ + rhs }; } TOML_NODISCARD friend array_iterator operator+(ptrdiff_t lhs, const array_iterator& rhs) noexcept { return { rhs.raw_ + lhs }; } TOML_NODISCARD friend array_iterator operator-(const array_iterator& lhs, ptrdiff_t rhs) noexcept { return { lhs.raw_ - rhs }; } TOML_NODISCARD friend ptrdiff_t operator-(const array_iterator& lhs, const array_iterator& rhs) noexcept { return lhs.raw_ - rhs.raw_; } TOML_NODISCARD friend bool operator==(const array_iterator& lhs, const array_iterator& rhs) noexcept { return lhs.raw_ == rhs.raw_; } TOML_NODISCARD friend bool operator!=(const array_iterator& lhs, const array_iterator& rhs) noexcept { return lhs.raw_ != rhs.raw_; } TOML_NODISCARD friend bool operator<(const array_iterator& lhs, const array_iterator& rhs) noexcept { return lhs.raw_ < rhs.raw_; } TOML_NODISCARD friend bool operator<=(const array_iterator& lhs, const array_iterator& rhs) noexcept { return lhs.raw_ <= rhs.raw_; } TOML_NODISCARD friend bool operator>(const array_iterator& lhs, const array_iterator& rhs) noexcept { return lhs.raw_ > rhs.raw_; } TOML_NODISCARD friend bool operator>=(const array_iterator& lhs, const array_iterator& rhs) noexcept { return lhs.raw_ >= rhs.raw_; } TOML_NODISCARD reference operator[](ptrdiff_t idx) const noexcept { return *(raw_ + idx)->get(); } TOML_DISABLE_WARNINGS; TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst) TOML_NODISCARD operator array_iterator() const noexcept { return array_iterator{ raw_ }; } TOML_ENABLE_WARNINGS; }; } 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 array : public node { private: /// \cond friend class TOML_PARSER_TYPENAME; std::vector> elems_; TOML_API void preinsertion_resize(size_t idx, size_t count); template void emplace_back_if_not_empty_view(T&& val, value_flags flags) { if constexpr (is_node_view) { if (!val) return; } elems_.emplace_back(impl::make_node(static_cast(val), flags)); } TOML_NODISCARD TOML_API size_t total_leaf_count() const noexcept; TOML_API 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 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; #if TOML_LIFETIME_HOOKS TOML_NODISCARD_CTOR array() noexcept { TOML_ARRAY_CREATED; } ~array() noexcept { TOML_ARRAY_DESTROYED; } #else /// \brief Default constructor. TOML_NODISCARD_CTOR array() noexcept = default; #endif /// \brief Copy constructor. TOML_NODISCARD_CTOR TOML_API array(const array&); /// \brief Move constructor. TOML_NODISCARD_CTOR TOML_API array(array&& other) noexcept; /// \brief Copy-assignment operator. TOML_API array& operator=(const array&); /// \brief Move-assignment operator. TOML_API array& operator=(array&& rhs) 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) { elems_.reserve(sizeof...(ElemTypes) + 1u); emplace_back_if_not_empty_view(static_cast(val), preserve_source_value_flags); if constexpr (sizeof...(ElemTypes) > 0) { (emplace_back_if_not_empty_view(static_cast(vals), preserve_source_value_flags), ...); } #if TOML_LIFETIME_HOOKS TOML_ARRAY_CREATED; #endif } /// \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_API bool is_homogeneous(node_type ntype) const noexcept final; TOML_PURE_GETTER TOML_API bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final; TOML_PURE_GETTER TOML_API 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::unwrap_node; static_assert( std::is_void_v< type> || ((impl::is_native || impl::is_one_of)&&!impl::is_cvref), "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