diff --git a/include/utl/container/array.h b/include/utl/container/array.h new file mode 100644 index 0000000..55513b5 --- /dev/null +++ b/include/utl/container/array.h @@ -0,0 +1,240 @@ +/*! + * \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__ */