summaryrefslogtreecommitdiff
path: root/lib/enumDetails.hpp
blob: ace6252121cb2c3c2997f60b3c99e3913e370e8a (plain)
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
#pragma once

#include <algorithm>
#include <array>
#include <limits>
#include <optional>
#include <string_view>

/// EnumTypeDetails
// Extracts the fully qualified name of the enumeration
template<typename E> struct EnumTypeDetails {
#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 {[]() {
		std::array<char, typeNameLen> out;
		typeraw().copy(out.begin(), typeNameEnd - typeNameStart, typeNameStart);
		return out;
	}()};

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 {[]() {
		std::array<char, nameLen> out;
		raw().copy(out.begin(), nameLen, nameStart);
		return out;
	}()};

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};
};

template<typename E> struct EnumValueCollection {
	using Vs = std::make_integer_sequence<int, 256>;
};

template<typename E> struct EnumDetails {
public:
	using EVC = EnumValueCollection<E>;

#ifndef ENUM_PROBE
private:
#endif
	template<auto... n>
	constexpr static auto
	get_valids(std::integer_sequence<int, n...>)
	{
		return std::array {EnumValueDetails<static_cast<E>(n)>::valid...};
	}
	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...};
	}

	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 {})};

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;
		auto write = out.begin();
		for (auto v = values.begin(); const bool & valid : valid_flags) {
			if (valid) {
				*write++ = static_cast<E>(*v);
			}
			++v;
		}
		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
	{
		if (const auto itr = std::find(names.begin(), names.end(), name); itr != names.end()) {
			return values[std::distance(names.begin(), itr)];
		}
		return std::nullopt;
	}

	constexpr static std::optional<std::string_view>
	to_string(E value) noexcept
	{
		if (const auto itr = std::find(values.begin(), values.end(), value); itr != values.end()) {
			return names[std::distance(values.begin(), itr)];
		}
		return std::nullopt;
	}
};