1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
#pragma once
#include <algorithm>
#include <array>
#include <limits>
#include <optional>
#include <string_view>
/// EnumDetailsBase
// Shared helpers
struct EnumDetailsBase {
template<size_t len>
constexpr static auto
strArr(auto input, auto start, auto end)
{
std::array<char, len> out;
input.copy(out.begin(), end - start, start);
return out;
}
};
/// EnumTypeDetails
// Extracts the fully qualified name of the enumeration
template<typename E> struct EnumTypeDetails : EnumDetailsBase {
#ifndef ENUM_PROBE
protected:
#endif
constexpr static std::string_view SEARCH_TYPE {"E = "};
constexpr static auto
typeraw()
{
return std::string_view {__PRETTY_FUNCTION__};
};
constexpr static auto typeNameStart {typeraw().find(SEARCH_TYPE) + SEARCH_TYPE.length()};
constexpr static auto typeNameEnd {typeraw().find_first_of("];", typeNameStart)};
constexpr static auto typeNameLen {typeNameEnd - typeNameStart};
constexpr static auto typeNameArr {strArr<typeNameLen>(typeraw(), typeNameStart, typeNameEnd)};
public:
constexpr static std::string_view typeName {typeNameArr.data(), typeNameArr.size()};
};
/// EnumValueDetails
// Extracts the value name and constructs string_views of the parts
template<auto value> struct EnumValueDetails : public EnumTypeDetails<decltype(value)> {
#ifndef ENUM_PROBE
private:
#endif
using T = EnumTypeDetails<decltype(value)>;
constexpr static auto
raw()
{
return std::string_view {__PRETTY_FUNCTION__};
};
constexpr static auto nameStart {raw().find_last_of(": ") + 1};
constexpr static auto nameEnd {raw().find_first_of("];", nameStart)};
constexpr static auto nameLen {nameEnd - nameStart};
constexpr static auto nameArr {EnumValueDetails::template strArr<nameLen>(raw(), nameStart, nameEnd)};
public:
constexpr static std::string_view valueName {nameArr.data(), nameArr.size()};
constexpr static auto valid {valueName.back() < '0' || valueName.back() > '9'};
constexpr static auto raw_value {value};
};
/// EnumValueCollection
// Customisation point for specifying the range of underlying values your enum can have
template<typename E> struct EnumValueCollection {
using Vs = std::make_integer_sequence<int, 256>;
};
/// EnumDetails
// Interface for lookups/checks/etc at runtime
template<typename E> struct EnumDetails {
#ifndef ENUM_PROBE
private:
#endif
template<auto... n>
constexpr static auto
get_valids(std::integer_sequence<int, n...>)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
return std::array {EnumValueDetails<static_cast<E>(n)>::valid...};
#pragma GCC diagnostic pop
}
template<auto... n>
constexpr static auto
get_values(std::integer_sequence<int, n...>)
{
return std::array {EnumValueDetails<static_cast<E>(n)>::raw_value...};
}
template<auto... n>
constexpr static auto
get_valueNames(std::integer_sequence<int, n...>)
{
return std::array {EnumValueDetails<values[n]>::valueName...};
}
using EVC = EnumValueCollection<E>;
constexpr static auto valid_flags {get_valids(typename EVC::Vs {})};
constexpr static auto valid_count {std::count_if(valid_flags.begin(), valid_flags.end(), std::identity {})};
constexpr static auto
lookup(const auto key, const auto & search, const auto & out)
-> std::optional<typename std::decay_t<decltype(out)>::value_type>
{
if (const auto itr = std::find(search.begin(), search.end(), key); itr != search.end()) {
return out[static_cast<std::size_t>(std::distance(search.begin(), itr))];
}
return std::nullopt;
}
public:
constexpr static auto values {[]() {
constexpr auto values {get_values(typename EVC::Vs {})};
static_assert(std::is_sorted(values.begin(), values.end()), "Candidate values must be sorted");
std::array<E, valid_count> out;
std::copy_if(values.begin(), values.end(), out.begin(), [valid = valid_flags.begin()](auto) mutable {
return *valid++;
});
return out;
}()};
constexpr static auto names {get_valueNames(std::make_integer_sequence<int, valid_count> {})};
constexpr static bool
is_valid(E value) noexcept
{
return std::binary_search(values.begin(), values.end(), value);
}
constexpr static std::optional<E>
parse(std::string_view name) noexcept
{
return lookup(name, names, values);
}
constexpr static std::optional<std::string_view>
to_string(E value) noexcept
{
return lookup(value, values, names);
}
};
|