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 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 {};
|
||||||
|
Loading…
Reference in New Issue
Block a user