containers: An std::array equivalent container added
We will recode this when we will add the rest of the containers. Until then...
This commit is contained in:
parent
7d394fa4f5
commit
3e7709666e
240
include/utl/container/array.h
Normal file
240
include/utl/container/array.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef __utl_container_array_h__
|
||||
#define __utl_container_array_h__
|
||||
|
||||
#include <utl/impl/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__ */
|
Loading…
x
Reference in New Issue
Block a user