Add constexpr C++ array wrapper

This commit is contained in:
BlackMark 2022-05-27 20:39:17 +02:00
parent 632ed6cf41
commit 5282fdde46
2 changed files with 245 additions and 5 deletions

238
array.hpp Normal file
View 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

View File

@ -33,6 +33,10 @@ template <bool B> using bool_constant = integral_constant<bool, B>;
using false_type = bool_constant<false>; using false_type = bool_constant<false>;
using true_type = bool_constant<true>; 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 : false_type {};
template <typename T> struct is_const<const T> : true_type {}; template <typename T> struct is_const<const T> : true_type {};
template <typename T> inline constexpr bool is_const_v = is_const<T>::value; 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> struct reference_wrapper;
template <typename T> inline constexpr T &&forward(util::remove_reference_t<T> &t) noexcept; 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 } // 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> struct invoke_result : detail::invoke_result<void, Fn, ArgTypes...> {};
template <typename Fn, typename... ArgTypes> using invoke_result_t = typename invoke_result<Fn, ArgTypes...>::type; 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> // <limits>
template <typename T> struct numeric_limits {}; template <typename T> struct numeric_limits {};