/* * 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 "../debug/assert.hpp" #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 &&) noexcept (std::is_trivial_v) = default; darray& operator= (darray const&) noexcept (std::is_nothrow_copy_assignable_v) = default; darray& operator= (darray &&) noexcept (std::is_nothrow_move_assignable_v)= 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[] (size_type idx)& noexcept { CHECK_LT (idx, m_size); return m_data.objects[idx]; } ValueT const& operator[] (size_type 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 (); } constexpr value_type* data (void)& noexcept { return m_data.objects + 0; } constexpr value_type const* data (void) const& noexcept { return m_data.objects + 0; } size_type 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 void resize (size_type const count, value_type const &value) { if (count < m_size) { while (m_size > count) { --m_size; m_data.objects[m_size].~ValueT (); } return; } if (count > m_size) { for ( ; m_size < count; ++m_size) new (m_data.objects + m_size) ValueT (value); return; } } constexpr void resize (size_type count) { return resize (count, value_type {}); } 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_GE (pos, begin ()); CHECK_LT (pos, 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_GE (pos, begin ()); CHECK_LT (pos, 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) storage_t { storage_t () { }; char store[sizeof (ValueT) * CapacityV]; ValueT objects[CapacityV]; } m_data; size_type 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); } }