|
- /*!
- * \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 <http://www.gnu.org/licenses/>.
- *
- */
- #ifndef __utl_container_array_h__
- #define __utl_container_array_h__
-
- #include <utl/core/impl.h>
- #include <algorithm>
-
- namespace utl {
-
- /*!
- * \ingroup containers
- * \brief
- * array container traits helper
- */
- //! @{
- template<typename _Tp, size_t _Nm>
- 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<typename _Tp>
- 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:
- * <a href="tables.html#65">container</a>,
- * <a href="tables.html#66">reversible container</a>,
- * <a href="tables.html#67">sequence</a>.
- * Sets support random access iterators.
- *
- * \tparam _Tp type of element. Required to be a complete type.
- * \tparam _Nm Number of elements.
- */
- template <typename _Tp, size_t _Nm>
- 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 <iterator>;
- using const_reverse_iterator
- = std::reverse_iterator <const_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<typename _Tp, size_t _Nm>
- inline bool operator== (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
- return std::equal (lhs.begin(), lhs.end(), rhs.begin());
- }
-
- template<typename _Tp, size_t _Nm>
- inline bool operator!= (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
- return !(lhs == rhs);
- }
-
- template<typename _Tp, size_t _Nm>
- 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<typename _Tp, size_t _Nm>
- inline bool operator> (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
- return rhs < lhs;
- }
-
- template<typename _Tp, size_t _Nm>
- inline bool operator<= (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
- return !(lhs > rhs);
- }
-
- template<typename _Tp, size_t _Nm>
- inline bool
- operator>= (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
- return !(lhs < rhs);
- }
- //!@}
-
- // Specialized algorithms.
- template<typename _Tp, size_t _Nm>
- inline void swap (array<_Tp, _Nm>& lhs, array<_Tp, _Nm>& rhs)
- noexcept (noexcept (lhs.swap(rhs))) {
- lhs.swap (rhs);
- }
-
- template<size_t _Int, typename _Tp, size_t _Nm>
- 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<size_t _Int, typename _Tp, size_t _Nm>
- 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<size_t _Int, typename _Tp, size_t _Nm>
- 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__ */
|