/*! * \file utl/containers/array.h * \brief An std::array equivalent implementation * * Copyright (C) 2018 Christos Choutouridis * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef __utl_container_array_h__ #define __utl_container_array_h__ #include #include namespace utl { /*! * \ingroup containers * \brief * array container traits helper */ //! @{ template struct array_traits { typedef _Tp type[_Nm]; static constexpr _Tp& Ref (const type& t, size_t n) noexcept { return const_cast<_Tp&>(t[n]); } static constexpr _Tp* Ptr(const type& t) noexcept { return const_cast<_Tp*>(t); } }; template struct array_traits<_Tp, 0> { struct type { }; static constexpr _Tp& Ref(const type&, size_t) noexcept { return *static_cast<_Tp*>(nullptr); } static constexpr _Tp* Ptr(const type&) noexcept { return nullptr; } }; //! @} /*! * \ingroup containers * \brief * A standard container for storing a fixed size sequence of elements. * * Meets the requirements of: * container, * reversible container, * sequence. * Sets support random access iterators. * * \tparam _Tp type of element. Required to be a complete type. * \tparam _Nm Number of elements. */ template struct array { using value_type = _Tp; using pointer = value_type*; using const_pointer = const value_type*; using reference = value_type&; using const_reference = const value_type&; using iterator = value_type*; using const_iterator = const value_type*; using size_type = size_t; using difference_type = ptrdiff_t; using reverse_iterator = std::reverse_iterator ; using const_reverse_iterator = std::reverse_iterator ; // type and data //using empty_t = array_traits<_Tp, 0>; using array_t = array_traits<_Tp, _Nm>; typename array_t::type _data; // No explicit construct/copy/destroy for aggregate type. // DR 776. void fill (const value_type& v) { std::fill_n (begin(), size(), v); } void swap (array& other) noexcept { std::swap_ranges (begin(), end(), other.begin()); } //! \name Iterators. //!@{ iterator begin() noexcept { return iterator (data()); } const_iterator begin() const noexcept { return const_iterator (data()); } iterator end() noexcept { return iterator (data() + _Nm); } const_iterator end() const noexcept { return const_iterator (data() + _Nm); } const_iterator cbegin() const noexcept { return const_iterator (data()); } const_iterator cend() const noexcept { return const_iterator (data() + _Nm); } reverse_iterator rbegin() noexcept { return reverse_iterator (end()); } reverse_iterator rend() noexcept { return reverse_iterator (begin()); } const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator (end()); } const_reverse_iterator rend() const noexcept { return const_reverse_iterator (begin()); } const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator (end()); } const_reverse_iterator crend() const noexcept { return const_reverse_iterator (begin()); } //!@{ //! \name Capacity. //!@{ constexpr size_type size() const noexcept { return _Nm; } constexpr size_type max_size() const noexcept { return _Nm; } constexpr bool empty() const noexcept { return size() == 0; } //!@{ //! \name Element access. //!@{ //! Operator [] reference operator[] (size_type n) noexcept { return array_t::Ref(_data, n); } //! Operator [] for const constexpr const_reference operator[](size_type n) const noexcept { return array_t::Ref(_data, n); } /*! * Boundary check dereference operator. * If out of bounds, abort (for now) */ reference at (size_type n) noexcept { if (n < _Nm) return array_t::Ref(_data, n); else abort (); //XXX: Throw here } //! Compile time boundary check dereference operator. constexpr const_reference at (size_type n) const noexcept { static_assert ((n < _Nm), "array::at: out of range"); return array_t::Ref(_data, n); } // first item reference front () noexcept { return *begin (); } constexpr const_reference front() const noexcept { return array_t::Ref(_data, 0); } // Last item reference back () noexcept { return _Nm ? *(end() - 1) : *end(); } constexpr const_reference back () const noexcept { return _Nm ? array_t::Ref(_data, _Nm - 1) : array_t::Ref(_data, 0); } // Pointer to data pointer data () noexcept { return array_t::Ptr(_data); } const_pointer data () const noexcept { return array_t::Ptr(_data); } //!<@} }; //! \name Array comparisons. //!@{ template inline bool operator== (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) { return std::equal (lhs.begin(), lhs.end(), rhs.begin()); } template inline bool operator!= (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) { return !(lhs == rhs); } template inline bool operator< (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) { return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } template inline bool operator> (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) { return rhs < lhs; } template inline bool operator<= (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) { return !(lhs > rhs); } template inline bool operator>= (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) { return !(lhs < rhs); } //!@} // Specialized algorithms. template inline void swap (array<_Tp, _Nm>& lhs, array<_Tp, _Nm>& rhs) noexcept (noexcept (lhs.swap(rhs))) { lhs.swap (rhs); } template constexpr _Tp& get (array<_Tp, _Nm>& arr) noexcept { static_assert(_Int < _Nm, "Index is out of bounds"); return array_traits<_Tp, _Nm>::Ref(arr._data, _Int); } template constexpr _Tp&& get (array<_Tp, _Nm>&& arr) noexcept { static_assert(_Int < _Nm, "Index is out of bounds"); return std::move(std::get<_Int>(arr)); } template constexpr const _Tp& get (const array<_Tp, _Nm>& arr) noexcept { static_assert(_Int < _Nm, "Index is out of bounds"); return array_traits<_Tp, _Nm>::Ref(arr._data, _Int); } } // namespace utl #endif /* __utl_continer_array_h__ */