Botcraft 1.21.4
Loading...
Searching...
No Matches
EnumUtilities.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <type_traits>
4#include <string_view>
5#include <array>
6#include <utility>
7#include <algorithm>
8#include <iostream>
9
10namespace Botcraft::Utilities
11{
12 template <auto V>
13 constexpr auto enum_value_name() noexcept
14 {
15 static_assert(std::is_enum_v<decltype(V)>, "enum_value_name requires enum value");
16
17#if defined(__clang__)
18 constexpr std::string_view header = "auto Botcraft::Utilities::enum_value_name() [V = ";
19 constexpr std::string_view footer = "]";
20 constexpr std::string_view name = __PRETTY_FUNCTION__;
21#elif defined(__GNUC__)
22 constexpr std::string_view header = "constexpr auto Botcraft::Utilities::enum_value_name() [with auto V = ";
23 constexpr std::string_view footer = "]";
24 constexpr std::string_view name = __PRETTY_FUNCTION__;
25#elif defined(_MSC_VER)
26 constexpr std::string_view header = "auto __cdecl Botcraft::Utilities::enum_value_name<";
27 constexpr std::string_view footer = ">(void) noexcept";
28 constexpr std::string_view name = __FUNCSIG__;
29#else
30 // V == V makes the assertion evaluated only if the function is instantiated
31 static_assert(V == V && false, "enum_value_name requires either __PRETTY_FUNCTION__ or __FUNCSIG__ to be available");
32#endif
33 return name.substr(header.size(), name.size() - header.size() - footer.size());
34 }
35
36 template <class Enum>
37 constexpr std::underlying_type_t<Enum> to_underlying(const Enum e) noexcept
38 {
39 return static_cast<std::underlying_type_t<Enum>>(e);
40 }
41
42 template<class Enum, Enum MinVal, Enum MaxVal>
44 {
45 static_assert(to_underlying(MaxVal) >= to_underlying(MinVal), "MaxVal must be >= MinVal");
46
47 static inline constexpr std::underlying_type_t<Enum> start = to_underlying(MinVal);
48 static inline constexpr std::underlying_type_t<Enum> end = to_underlying(MaxVal);
49
50 template <std::size_t ... Is>
51 static constexpr std::array<std::string_view, end - start + 1> map_range(std::index_sequence<Is...>)
52 {
53 std::array<std::string_view, end - start + 1> output;
54 ((output[Is] = enum_value_name<static_cast<Enum>(start + Is)>()), ...);
55 return output;
56 }
57
58 static inline constexpr std::array<std::string_view, end - start + 1> mapping = map_range(std::make_index_sequence<end - start + 1>());
59 };
60
61 template<class Enum, Enum... pack>
62 constexpr std::array<std::pair<Enum, std::string_view>, sizeof...(pack)> GetNamedEnum()
63 {
64 return { std::make_pair(pack, enum_value_name<pack>())... };
65 }
66}
67
68#define DECLARE_ENUM_STRINGIFYER(Enum) ::std::ostream& operator <<(::std::ostream& os, const Enum v)
69
70
71#if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
72#define DEFINE_ENUM_STRINGIFYER_RANGE(Enum, min_value, max_value) \
73::std::ostream& operator <<(::std::ostream& os, const Enum v) \
74{ \
75 static_assert(::std::is_same_v<decltype(min_value), Enum>, "min_value must be "#Enum); \
76 static_assert(::std::is_same_v<decltype(max_value), Enum>, "max_value must be "#Enum); \
77 using mapper = ::Botcraft::Utilities::EnumMapperRange<Enum, min_value, max_value>; \
78 if (::Botcraft::Utilities::to_underlying(v) < mapper::start || \
79 ::Botcraft::Utilities::to_underlying(v) > mapper::end) \
80 { \
81 return os << '(' << #Enum << ')' << static_cast<int>(v); \
82 } \
83 return os << mapper::mapping[::Botcraft::Utilities::to_underlying(v) - mapper::start]; \
84} static_assert(true, "") /* To require a ; after macro call */
85#else // min_value and max_value are not necessary, but keep them to get the same interface
86#define DEFINE_ENUM_STRINGIFYER_RANGE(Enum, min_value, max_value) \
87::std::ostream& operator <<(::std::ostream& os, const Enum v) \
88{ \
89 return os << '(' << #Enum << ')' << static_cast<int>(v); \
90} static_assert(true, "") /* To require a ; after macro call */
91#endif
92
93#if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
94#define DEFINE_ENUM_STRINGIFYER_LIST(Enum, ...) \
95::std::ostream& operator <<(::std::ostream& os, const Enum v) \
96{ \
97 static constexpr auto mapper = ::Botcraft::Utilities::GetNamedEnum<Enum, __VA_ARGS__>(); \
98 const auto it = ::std::find_if(mapper.begin(), mapper.end(), \
99 [v](const ::std::pair<Enum, ::std::string_view>& p) { return p.first == v; }); \
100 if (it == mapper.end()) \
101 { \
102 return os << '(' << #Enum << ')' << static_cast<int>(v); \
103 } \
104 return os << it->second; \
105} static_assert(true, "") /* To require a ; after macro call */
106#else // value list is not necessary, but keep it to get the same interface
107#define DEFINE_ENUM_STRINGIFYER_LIST(Enum, ...) \
108::std::ostream& operator <<(::std::ostream& os, const Enum v) \
109{ \
110 return os << '(' << #Enum << ')' << static_cast<int>(v); \
111} static_assert(true, "") /* To require a ; after macro call */
112#endif
constexpr std::underlying_type_t< Enum > to_underlying(const Enum e) noexcept
constexpr auto enum_value_name() noexcept
constexpr std::array< std::pair< Enum, std::string_view >, sizeof...(pack)> GetNamedEnum()
static constexpr std::underlying_type_t< Enum > start
static constexpr std::underlying_type_t< Enum > end
static constexpr std::array< std::string_view, end - start+1 > map_range(std::index_sequence< Is... >)
static constexpr std::array< std::string_view, end - start+1 > mapping