9#ifndef AVARA3D_UTIL_ENUM_H
10#define AVARA3D_UTIL_ENUM_H
19namespace a3d::util::enums {
23 static constexpr int ENUM_RANGE_MIN = -128;
24 static constexpr int ENUM_RANGE_MAX = 127;
27 constexpr int range_min() noexcept {
28 if constexpr (std::is_signed_v<std::underlying_type_t<E>>) {
29 return ENUM_RANGE_MIN;
37 constexpr int range_max() noexcept {
38 return ENUM_RANGE_MAX;
41 constexpr std::string_view unqualified_name(std::string_view name)
noexcept {
43 const auto scope = name.rfind(
"::");
44 if (scope != std::string_view::npos) {
45 name.remove_prefix(scope + 2);
52 consteval std::string_view enum_name_impl() noexcept {
54 using E =
decltype(V);
55 static_assert(std::is_enum_v<E>);
57#if defined(__clang__) || defined(__GNUC__)
59 constexpr std::string_view signature = __PRETTY_FUNCTION__;
60 constexpr std::string_view prefix =
"V = ";
62 const auto prefixPos = signature.find(prefix);
63 if (prefixPos == std::string_view::npos) {
67 const auto begin = prefixPos + prefix.size();
69 #if defined(__clang__)
70 const auto end = signature.find(
']', begin);
72 auto end = signature.find(
';', begin);
73 if (end == std::string_view::npos) {
74 end = signature.find(
']', begin);
78 if (end == std::string_view::npos) {
82 auto name = signature.substr(begin, end - begin);
84#elif defined(_MSC_VER)
86 constexpr std::string_view signature = __FUNCSIG__;
87 constexpr std::string_view prefix =
"enum_name_impl<";
89 const auto prefixPos = signature.find(prefix);
90 if (prefixPos == std::string_view::npos) {
94 const auto begin = prefixPos + prefix.size();
95 const auto end = signature.find(
">(void)", begin);
96 if (end == std::string_view::npos) {
100 auto name = signature.substr(begin, end - begin);
103 #error Unsupported compiler for a3d::util::enums
108 if (name.empty() || name.front() ==
'(' || name.front() ==
'-'
109 || (name.front() >=
'0' && name.front() <=
'9')) {
113 return unqualified_name(name);
116 template<
typename E,
int Min, std::size_t... I>
117 consteval auto make_names(std::index_sequence<I...>)
noexcept {
119 return std::array<std::string_view,
sizeof...(I)> {
120 enum_name_impl<static_cast<E>(Min +
static_cast<int>(I))>()...};
125 static_assert(std::is_enum_v<E>);
127 static constexpr int min = range_min<E>();
128 static constexpr int max = range_max<E>();
129 static constexpr std::size_t count =
static_cast<std::size_t
>(max - min + 1);
131 static constexpr auto names = make_names<E, min>(std::make_index_sequence<count> {});
144constexpr std::string_view enum_name(E value)
noexcept {
146 static_assert(std::is_enum_v<E>,
"a3d::util::enums::enum_name() requires an enum type");
148 using U = std::underlying_type_t<E>;
150 constexpr int min = detail::EnumData<E>::min;
151 constexpr int max = detail::EnumData<E>::max;
152 constexpr auto& names = detail::EnumData<E>::names;
154 const U raw =
static_cast<U
>(value);
155 if (raw <
static_cast<U
>(min) || raw >
static_cast<U
>(max)) {
159 return names[
static_cast<std::size_t
>(raw -
static_cast<U
>(min))];
168constexpr std::optional<E> enum_cast(std::string_view name)
noexcept {
170 static_assert(std::is_enum_v<E>,
"a3d::util::enums::enum_cast() requires an enum type");
172 constexpr int min = detail::EnumData<E>::min;
173 constexpr auto& names = detail::EnumData<E>::names;
175 for (std::size_t i = 0; i < names.size(); ++i) {
176 if (!names[i].empty() && names[i] == name) {
177 return static_cast<E
>(min +
static_cast<int>(i));
186constexpr std::underlying_type_t<E> to_underlying(E value)
noexcept {
188 static_assert(std::is_enum_v<E>,
"a3d::util::enums::to_underlying() requires an enum type");
189 return static_cast<std::underlying_type_t<E>
>(value);