@@ -5,69 +5,75 @@
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
||||
template <class E> struct enum_traits;
|
||||
template<class E> struct enum_traits;
|
||||
|
||||
template <class E>
|
||||
template<class E>
|
||||
concept EnumLike = std::is_enum_v<E>;
|
||||
|
||||
template <EnumLike E>
|
||||
constexpr std::size_t enum_count_v =
|
||||
static_cast<std::size_t>(enum_traits<E>::last) -
|
||||
static_cast<std::size_t>(enum_traits<E>::first) + 1;
|
||||
template<EnumLike E>
|
||||
constexpr std::size_t enum_count_v
|
||||
= static_cast<std::size_t>(enum_traits<E>::last)
|
||||
- static_cast<std::size_t>(enum_traits<E>::first) + 1;
|
||||
|
||||
template <EnumLike E, class T> struct enum_array {
|
||||
using value_type = T;
|
||||
using enum_type = E;
|
||||
using underlying_index_type = std::size_t;
|
||||
template<EnumLike E, class T> struct enum_array {
|
||||
using value_type = T;
|
||||
using enum_type = E;
|
||||
using underlying_index_type = std::size_t;
|
||||
|
||||
static constexpr E first = enum_traits<E>::first;
|
||||
static constexpr E last = enum_traits<E>::last;
|
||||
static constexpr std::size_t size_value = enum_count_v<E>;
|
||||
static constexpr E first = enum_traits<E>::first;
|
||||
static constexpr E last = enum_traits<E>::last;
|
||||
static constexpr std::size_t size_value = enum_count_v<E>;
|
||||
|
||||
std::array<T, size_value> _data{};
|
||||
std::array<T, size_value> _data {};
|
||||
|
||||
static constexpr std::size_t size() noexcept { return size_value; }
|
||||
constexpr T *data() noexcept { return _data.data(); }
|
||||
constexpr const T *data() const noexcept { return _data.data(); }
|
||||
constexpr T *begin() noexcept { return _data.begin().operator->(); }
|
||||
constexpr const T *begin() const noexcept {
|
||||
return _data.begin().operator->();
|
||||
}
|
||||
constexpr T *end() noexcept { return _data.end().operator->(); }
|
||||
constexpr const T *end() const noexcept { return _data.end().operator->(); }
|
||||
static constexpr std::size_t size() noexcept { return size_value; }
|
||||
constexpr T *data() noexcept { return _data.data(); }
|
||||
constexpr T const *data() const noexcept { return _data.data(); }
|
||||
constexpr T *begin() noexcept { return _data.begin().operator->(); }
|
||||
constexpr T const *begin() const noexcept
|
||||
{
|
||||
return _data.begin().operator->();
|
||||
}
|
||||
constexpr T *end() noexcept { return _data.end().operator->(); }
|
||||
constexpr T const *end() const noexcept { return _data.end().operator->(); }
|
||||
|
||||
constexpr T &operator[](E e) noexcept { return _data[to_index(e)]; }
|
||||
constexpr const T &operator[](E e) const noexcept {
|
||||
return _data[to_index(e)];
|
||||
}
|
||||
constexpr T &operator[](E e) noexcept { return _data[to_index(e)]; }
|
||||
constexpr T const &operator[](E e) const noexcept
|
||||
{
|
||||
return _data[to_index(e)];
|
||||
}
|
||||
|
||||
constexpr T &at(E e) {
|
||||
auto i = to_index(e);
|
||||
if (i >= size_value)
|
||||
throw std::out_of_range("enum_array::at");
|
||||
return _data[i];
|
||||
}
|
||||
constexpr const T &at(E e) const {
|
||||
auto i = to_index(e);
|
||||
if (i >= size_value)
|
||||
throw std::out_of_range("enum_array::at");
|
||||
return _data[i];
|
||||
}
|
||||
constexpr T &at(E e)
|
||||
{
|
||||
auto i = to_index(e);
|
||||
if (i >= size_value)
|
||||
throw std::out_of_range("enum_array::at");
|
||||
return _data[i];
|
||||
}
|
||||
constexpr T const &at(E e) const
|
||||
{
|
||||
auto i = to_index(e);
|
||||
if (i >= size_value)
|
||||
throw std::out_of_range("enum_array::at");
|
||||
return _data[i];
|
||||
}
|
||||
|
||||
constexpr void fill(const T &v) { _data.fill(v); }
|
||||
constexpr void fill(T const &v) { _data.fill(v); }
|
||||
|
||||
private:
|
||||
static constexpr std::size_t to_index(E e) noexcept {
|
||||
return static_cast<std::size_t>(e) - static_cast<std::size_t>(first);
|
||||
}
|
||||
static constexpr std::size_t to_index(E e) noexcept
|
||||
{
|
||||
return static_cast<std::size_t>(e) - static_cast<std::size_t>(first);
|
||||
}
|
||||
};
|
||||
|
||||
template <class E, class T, class... U>
|
||||
requires EnumLike<E> && (std::is_same_v<T, U> && ...)
|
||||
constexpr auto make_enum_array(T &&first_val, U &&...rest) {
|
||||
enum_array<E, std::decay_t<T>> arr;
|
||||
static_assert(sizeof...(rest) + 1 == enum_count_v<E>,
|
||||
"initializer count must match enum range");
|
||||
arr._data = {std::forward<T>(first_val), std::forward<U>(rest)...};
|
||||
return arr;
|
||||
template<class E, class T, class... U>
|
||||
requires EnumLike<E> && (std::is_same_v<T, U> && ...)
|
||||
constexpr auto make_enum_array(T &&first_val, U &&...rest)
|
||||
{
|
||||
enum_array<E, std::decay_t<T>> arr;
|
||||
static_assert(sizeof...(rest) + 1 == enum_count_v<E>,
|
||||
"initializer count must match enum range");
|
||||
arr._data = { std::forward<T>(first_val), std::forward<U>(rest)... };
|
||||
return arr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user