9#ifndef AVARA3D_UTIL_ENUM_H
10#define AVARA3D_UTIL_ENUM_H
19namespace a3d::util::enums {
24 static constexpr int ENUM_RANGE_MIN = -128;
25 static constexpr int ENUM_RANGE_MAX = 127;
28 constexpr int range_min() noexcept {
29 if constexpr (std::is_signed_v<std::underlying_type_t<E>>) {
30 return ENUM_RANGE_MIN;
38 constexpr int range_max() noexcept {
39 return ENUM_RANGE_MAX;
42 constexpr std::string_view unqualified_name(std::string_view name)
noexcept {
44 const auto scope = name.rfind(
"::");
45 if (scope != std::string_view::npos) {
46 name.remove_prefix(scope + 2);
53 consteval std::string_view enum_name_impl() noexcept {
55 using E =
decltype(V);
56 static_assert(std::is_enum_v<E>);
58#if defined(__clang__) || defined(__GNUC__)
60 constexpr std::string_view signature = __PRETTY_FUNCTION__;
61 constexpr std::string_view prefix =
"V = ";
63 const auto prefixPos = signature.find(prefix);
64 if (prefixPos == std::string_view::npos) {
68 const auto begin = prefixPos + prefix.size();
70 #if defined(__clang__)
71 const auto end = signature.find(
']', begin);
73 auto end = signature.find(
';', begin);
74 if (end == std::string_view::npos) {
75 end = signature.find(
']', begin);
79 if (end == std::string_view::npos) {
83 auto name = signature.substr(begin, end - begin);
85#elif defined(_MSC_VER)
87 constexpr std::string_view signature = __FUNCSIG__;
88 constexpr std::string_view prefix =
"enum_name_impl<";
90 const auto prefixPos = signature.find(prefix);
91 if (prefixPos == std::string_view::npos) {
95 const auto begin = prefixPos + prefix.size();
96 const auto end = signature.find(
">(void)", begin);
97 if (end == std::string_view::npos) {
101 auto name = signature.substr(begin, end - begin);
104 #error Unsupported compiler for a3d::util::enums
109 if (name.empty() || name.front() ==
'(' || name.front() ==
'-'
110 || (name.front() >=
'0' && name.front() <=
'9')) {
114 return unqualified_name(name);
117 template<
typename E,
int Min, std::size_t... I>
118 consteval auto make_names(std::index_sequence<I...>)
noexcept {
120 return std::array<std::string_view,
sizeof...(I)> {
121 enum_name_impl<static_cast<E>(Min +
static_cast<int>(I))>()...
127 static_assert(std::is_enum_v<E>);
129 static constexpr int min = range_min<E>();
130 static constexpr int max = range_max<E>();
131 static constexpr std::size_t count =
static_cast<std::size_t
>(max - min + 1);
133 static constexpr auto names = make_names<E, min>(std::make_index_sequence<count> {});
146 constexpr std::string_view enum_name(E value)
noexcept {
148 static_assert(std::is_enum_v<E>,
"a3d::util::enums::enum_name() requires an enum type");
150 using U = std::underlying_type_t<E>;
152 constexpr int min = detail::EnumData<E>::min;
153 constexpr int max = detail::EnumData<E>::max;
154 constexpr auto& names = detail::EnumData<E>::names;
156 const U raw =
static_cast<U
>(value);
157 if (raw <
static_cast<U
>(min) || raw >
static_cast<U
>(max)) {
161 return names[
static_cast<std::size_t
>(raw -
static_cast<U
>(min))];
170 constexpr std::optional<E> enum_cast(std::string_view name)
noexcept {
172 static_assert(std::is_enum_v<E>,
"a3d::util::enums::enum_cast() requires an enum type");
174 constexpr int min = detail::EnumData<E>::min;
175 constexpr auto& names = detail::EnumData<E>::names;
177 for (std::size_t i = 0; i < names.size(); ++i) {
178 if (!names[i].empty() && names[i] == name) {
179 return static_cast<E
>(min +
static_cast<int>(i));
188 constexpr std::underlying_type_t<E> to_underlying(E value)
noexcept {
190 static_assert(std::is_enum_v<E>,
"a3d::util::enums::to_underlying() requires an enum type");
191 return static_cast<std::underlying_type_t<E>
>(value);