Files
waylight/src/enum_array.hpp
Slendi aeeae20aff format
Signed-off-by: Slendi <slendi@socopon.com>
2025-10-10 12:45:35 +03:00

80 lines
2.1 KiB
C++

#pragma once
#include <array>
#include <cstddef>
#include <stdexcept>
#include <type_traits>
template<class E> struct enum_traits;
template<class E>
concept EnumLike = std::is_enum_v<E>;
template<EnumLike E>
constexpr usize enum_count_v
= static_cast<usize>(enum_traits<E>::last)
- static_cast<usize>(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 = usize;
static constexpr E first = enum_traits<E>::first;
static constexpr E last = enum_traits<E>::last;
static constexpr usize size_value = enum_count_v<E>;
std::array<T, size_value> _data {};
static constexpr usize 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 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 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(T const &v) { _data.fill(v); }
private:
static constexpr usize to_index(E e) noexcept
{
return static_cast<usize>(e) - static_cast<usize>(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;
}