/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2017 Danny Robson */ #pragma once #include "../iterator/zip.hpp" #include #include namespace cruft { /// An array-like object with capacity fixed at instantiation time, and a /// size which is variable at runtime. template class darray { public: using value_type = ValueT; using size_type = std::size_t; static constexpr auto elements = CapacityV; using pointer = ValueT*; using const_pointer = ValueT const*; using iterator = pointer; using const_iterator = const_pointer; darray (): m_size (0) { ; } darray (darray const&) = default; darray (darray &&) = default; darray& operator= (darray const&) = default; darray& operator= (darray &&) = default; ~darray () { for (auto &i: *this) i.~ValueT (); } darray (std::initializer_list init): m_size (init.size ()) { CHECK_LE (init.size (), CapacityV); for (auto &&[idx, src]: cruft::iterator::izip (init)) m_data.objects[idx] = std::move (src); } template darray (InputT first, InputT last): darray () { for ( ; first != last; ++first) { CHECK_LT (m_size, CapacityV); m_data.objects[m_size++] = *first; } } ValueT& operator[] (std::size_t idx)& noexcept { CHECK_LT (idx, m_size); return m_data.objects[idx]; } ValueT const& operator[] (std::size_t idx) const& noexcept { CHECK_LT (idx, m_size); return m_data.objects[idx]; } iterator begin (void)& { return m_data.objects + 0; } iterator end (void)& { return m_data.objects + m_size; } const_iterator begin (void) const& { return m_data.objects + 0; } const_iterator end (void) const& { return m_data.objects + m_size; } decltype(auto) cbegin (void) const& { return begin (); } decltype(auto) cend (void) const& { return end (); } std::size_t size (void) const noexcept { return m_size; } constexpr auto capacity (void) const noexcept { return CapacityV; } constexpr auto remain (void) const noexcept { return capacity () - size (); } constexpr bool empty (void) const noexcept { return m_size == 0; } constexpr bool full (void) const noexcept { return m_size == CapacityV; } void erase (iterator pos) { CHECK_LIMIT (pos, begin (), end ()); for (auto cursor = pos + 1; cursor != end (); ++cursor) *(cursor - 1) = std::move (*cursor); --m_size; } /// Insert one copy of `value' before `pos' iterator insert (iterator pos, ValueT const &val) { return insert (pos, 1u, val); } /// Insert `count' copies of `value' before `pos'. iterator insert (const_iterator pos, size_type count, ValueT const &val) { // Ensure we have enough space CHECK_LIMIT (pos, begin (), end ()); CHECK_LE (m_size, CapacityV - count); std::move_backward (pos, cend (), end () + count); m_size += count; auto dst = const_cast (pos); std::fill_n (dst, count, val); return dst; } iterator push_back (value_type const &val)& { CHECK_LT (m_size, CapacityV); m_data.objects[m_size] = val; return m_data.objects + m_size++; } iterator push_back (value_type &&val)& { CHECK_LT (m_size, CapacityV); m_data.objects[m_size] = std::move (val); return m_data.objects + m_size++; } private: union alignas (ValueT) { char store[sizeof (ValueT) * CapacityV]; ValueT objects[CapacityV]; } m_data; std::size_t m_size; }; //------------------------------------------------------------------------- template < std::size_t SizeA, typename ValueA, std::size_t SizeB, typename ValueB > constexpr auto operator== ( darray const &a, darray const &b ) { return std::equal ( a.begin (), a.end (), b.begin (), b.end () ); } //------------------------------------------------------------------------- template < std::size_t SizeA, typename ValueA, std::size_t SizeB, typename ValueB > constexpr auto operator!= ( darray const &a, darray const &b ) { return !(a == b); } }