Add constexpr C++ array wrapper
This commit is contained in:
parent
632ed6cf41
commit
5282fdde46
238
array.hpp
Normal file
238
array.hpp
Normal file
@ -0,0 +1,238 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "type.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace util {
|
||||
|
||||
template <class T, size_t N>
|
||||
struct array {
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using reference = value_type &;
|
||||
using const_reference = const value_type &;
|
||||
using pointer = value_type *;
|
||||
using const_pointer = const value_type *;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
// using reverse_iterator = <not implemented>;
|
||||
// using const_reverse_iterator = <not implemented>;
|
||||
|
||||
constexpr reference at(size_type pos)
|
||||
{
|
||||
if (pos >= N) {
|
||||
return *static_cast<pointer>(nullptr);
|
||||
}
|
||||
|
||||
return m_data[pos];
|
||||
}
|
||||
|
||||
constexpr const_reference at(size_type pos) const
|
||||
{
|
||||
if (pos >= N) {
|
||||
return *static_cast<pointer>(nullptr);
|
||||
}
|
||||
|
||||
return m_data[pos];
|
||||
}
|
||||
|
||||
constexpr reference operator[](size_type pos)
|
||||
{
|
||||
return m_data[pos];
|
||||
}
|
||||
|
||||
constexpr const_reference operator[](size_type pos) const
|
||||
{
|
||||
return m_data[pos];
|
||||
}
|
||||
|
||||
constexpr reference front()
|
||||
{
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
constexpr const_reference front() const
|
||||
{
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
constexpr reference back()
|
||||
{
|
||||
return m_data[N - 1];
|
||||
}
|
||||
|
||||
constexpr const_reference back() const
|
||||
{
|
||||
return m_data[N - 1];
|
||||
}
|
||||
|
||||
constexpr pointer data() noexcept
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
constexpr const_pointer data() const noexcept
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
constexpr iterator begin() noexcept
|
||||
{
|
||||
return &m_data[0];
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() const noexcept
|
||||
{
|
||||
return &m_data[0];
|
||||
}
|
||||
|
||||
constexpr const_iterator cbegin() const noexcept
|
||||
{
|
||||
return &m_data[0];
|
||||
}
|
||||
|
||||
constexpr iterator end() noexcept
|
||||
{
|
||||
return &m_data[N];
|
||||
}
|
||||
|
||||
constexpr const_iterator end() const noexcept
|
||||
{
|
||||
return &m_data[N];
|
||||
}
|
||||
|
||||
constexpr const_iterator cend() const noexcept
|
||||
{
|
||||
return &m_data[N];
|
||||
}
|
||||
|
||||
// reverse_iterator rbegin() noexcept;
|
||||
// const_reverse_iterator rbegin() const noexcept;
|
||||
// const_reverse_iterator crbegin() const noexcept;
|
||||
|
||||
// reverse_iterator rend() noexcept;
|
||||
// const_reverse_iterator rend() const noexcept;
|
||||
// const_reverse_iterator crend() const noexcept;
|
||||
|
||||
constexpr bool empty() const noexcept
|
||||
{
|
||||
return N == 0;
|
||||
}
|
||||
|
||||
constexpr size_type size() const noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
constexpr size_type max_size() const noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
constexpr void fill(const T &value)
|
||||
{
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
m_data[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void swap(array &other) noexcept(noexcept(swap(declval<T &>(), declval<T &>())))
|
||||
{
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
T tmp = m_data[i];
|
||||
m_data[i] = other.m_data[i];
|
||||
other.m_data[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
friend constexpr bool operator==(const array &lhs, const array &rhs)
|
||||
{
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (!(lhs[i] == rhs[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
friend constexpr bool operator!=(const array &lhs, const array &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
friend constexpr bool operator<(const array &lhs, const array &rhs)
|
||||
{
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (rhs[i] < lhs[i]) {
|
||||
return false;
|
||||
} else if (lhs[i] < rhs[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
friend constexpr bool operator<=(const array &lhs, const array &rhs)
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
friend constexpr bool operator>(const array &lhs, const array &rhs)
|
||||
{
|
||||
return (rhs < lhs);
|
||||
}
|
||||
|
||||
friend constexpr bool operator>=(const array &lhs, const array &rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
T m_data[N];
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T, size_t N, size_t... I>
|
||||
constexpr array<remove_cv_t<T>, N> to_array_impl(T (&a)[N], index_sequence<I...>)
|
||||
{
|
||||
return {{a[I]...}};
|
||||
}
|
||||
|
||||
template <typename T, size_t N, size_t... I>
|
||||
constexpr array<remove_cv_t<T>, N> to_array_impl(T(&&a)[N], index_sequence<I...>)
|
||||
{
|
||||
return {{move(a[I])...}};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, size_t N>
|
||||
constexpr array<remove_cv_t<T>, N> to_array(T (&a)[N])
|
||||
{
|
||||
return detail::to_array_impl(a, make_index_sequence<N>{});
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
constexpr array<remove_cv_t<T>, N> to_array(T(&&a)[N])
|
||||
{
|
||||
return detail::to_array_impl(move(a), make_index_sequence<N>{});
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// deduction guides
|
||||
|
||||
template <typename T, typename... U>
|
||||
array(T, U...)->array<T, 1 + sizeof...(U)>;
|
||||
|
||||
} // namespace util
|
12
type.hpp
12
type.hpp
@ -33,6 +33,10 @@ template <bool B> using bool_constant = integral_constant<bool, B>;
|
||||
using false_type = bool_constant<false>;
|
||||
using true_type = bool_constant<true>;
|
||||
|
||||
// Not part of <type_traits>, but very useful
|
||||
template <typename...> struct always_false : false_type {};
|
||||
template <typename... Ts> inline constexpr auto always_false_v = always_false<Ts...>::value;
|
||||
|
||||
template <typename T> struct is_const : false_type {};
|
||||
template <typename T> struct is_const<const T> : true_type {};
|
||||
template <typename T> inline constexpr bool is_const_v = is_const<T>::value;
|
||||
@ -247,7 +251,9 @@ namespace util {
|
||||
|
||||
template <typename T> struct reference_wrapper;
|
||||
template <typename T> inline constexpr T &&forward(util::remove_reference_t<T> &t) noexcept;
|
||||
template <typename T> util::add_rvalue_reference_t<T> declval() noexcept;
|
||||
template <typename T> util::add_rvalue_reference_t<T> declval() noexcept {
|
||||
static_assert(always_false_v<T>, "declval not allowed in an evaluated context");
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
||||
@ -307,10 +313,6 @@ struct invoke_result<decltype(void(INVOKE(util::declval<Fn>(), util::declval<Arg
|
||||
template <typename Fn, typename... ArgTypes> struct invoke_result : detail::invoke_result<void, Fn, ArgTypes...> {};
|
||||
template <typename Fn, typename... ArgTypes> using invoke_result_t = typename invoke_result<Fn, ArgTypes...>::type;
|
||||
|
||||
// Not part of <type_traits>, but very useful
|
||||
template <typename...> struct always_false : false_type {};
|
||||
template <typename... Ts> inline constexpr auto always_false_v = always_false<Ts...>::value;
|
||||
|
||||
// <limits>
|
||||
|
||||
template <typename T> struct numeric_limits {};
|
||||
|
Loading…
Reference in New Issue
Block a user