sandbox
Loading...
Searching...
No Matches
enum.hpp
1#ifndef LIBSBX_UTILITY_ENUM_HPP_
2#define LIBSBX_UTILITY_ENUM_HPP_
3
4#include <type_traits>
5#include <array>
6#include <ranges>
7#include <optional>
8#include <string_view>
9
10#include <libsbx/utility/string_literal.hpp>
11
12namespace sbx::utility {
13
14template<typename Enum>
15requires (std::is_enum_v<Enum>)
16constexpr auto to_underlying(const Enum value) -> std::underlying_type_t<Enum> {
17 return static_cast<std::underlying_type_t<Enum>>(value);
18}
19
20template<typename Enum>
21requires (std::is_enum_v<Enum>)
22constexpr auto from_underlying(const std::underlying_type_t<Enum> value) -> Enum {
23 return static_cast<Enum>(value);
24}
25
26template<auto... Values>
27requires (std::is_enum_v<decltype(Values)> && ...)
28struct enum_list {
29
30 inline static constexpr auto values = std::array{Values...};
31
32 inline static constexpr auto contains(const typename decltype(values)::value_type value) noexcept -> bool {
33 for (auto entry : values) {
34 if (entry == value) {
35 return true;
36 }
37 }
38
39 return false;
40 }
41
42 inline static constexpr auto size() noexcept -> std::size_t {
43 return values.size();
44 }
45
46 inline static constexpr auto is_empty() noexcept -> std::size_t {
47 return size() == 0u;
48 }
49
50}; // struct enum_list
51
52template<>
53struct enum_list<> {
54
55 template<typename Type>
56 requires (std::is_enum_v<Type>)
57 inline static constexpr auto contains(const Type value) noexcept -> bool {
58 return false;
59 }
60
61 inline static constexpr auto size() noexcept -> std::size_t {
62 return 0u;
63 }
64
65 inline static constexpr auto is_empty() noexcept -> std::size_t {
66 return true;
67 }
68
69}; // struct enum_list
70
71template<typename Enum>
72requires (std::is_enum_v<Enum>)
73struct is_bit_field : std::false_type { };
74
75template<typename Enum>
76requires (std::is_enum_v<Enum>)
77inline constexpr auto is_bit_field_v = is_bit_field<Enum>::value;
78
79template<std::size_t Shift>
80struct bit : std::integral_constant<std::size_t, (std::size_t{1} << Shift)> { };
81
82template<std::size_t Shift>
83inline constexpr auto bit_v = bit<Shift>::value;
84
85template<typename Enum, typename Underlying = std::underlying_type_t<Enum>>
86requires (std::is_enum_v<Enum>)
87class bit_field {
88
89public:
90
91 using value_type = Enum;
92 using underlying_type = Underlying;
93
94 constexpr bit_field() noexcept
95 : _value{underlying_type{0}} { }
96
97 constexpr bit_field(const value_type value) noexcept
98 : _value{to_underlying(value)} { }
99
100 explicit constexpr bit_field(const underlying_type value) noexcept
101 : _value{value} { }
102
103 constexpr auto set(const value_type value) noexcept -> void {
104 _value |= static_cast<underlying_type>(value);
105 }
106
107 constexpr auto clear(const value_type value) noexcept -> void {
108 _value &= ~static_cast<underlying_type>(value);
109 }
110
111 constexpr auto has(const value_type value) const noexcept -> bool {
112 return _value & static_cast<underlying_type>(value);
113 }
114
115 constexpr auto has_any() const noexcept -> bool {
116 return _value != underlying_type{0};
117 }
118
119 constexpr auto has_none() const noexcept -> bool {
120 return _value == underlying_type{0};
121 }
122
123 constexpr auto operator*() const noexcept -> value_type {
124 return from_underlying<value_type>(_value);
125 }
126
127 constexpr auto value() const -> value_type {
128 return static_cast<value_type>(_value);
129 }
130
131 constexpr auto underlying() const -> underlying_type {
132 return _value;
133 }
134
135private:
136
137 underlying_type _value;
138
139}; // class bit_field
140
141template<typename Enum>
142requires (std::is_enum_v<Enum>)
143struct entry {
144 Enum value;
145 std::string_view name;
146}; // struct entry
147
148template<typename Enum>
149requires (std::is_enum_v<Enum>)
151
152
153template<typename Type>
154concept mapped_enum = requires() {
155 std::is_enum_v<Type>;
157}; // concept mapped_enum
158
159template<mapped_enum Enum>
160constexpr auto to_string(const Enum value) -> std::string {
161 auto entry = std::ranges::find_if(enum_mapping<Enum>::values, [&value](const auto& entry){ return entry.value == value; });
162
163 if (entry == std::ranges::end(enum_mapping<Enum>::values)) {
164 return "<unknown>";
165 }
166
167 return entry->name;
168}
169
170template<mapped_enum Enum>
171constexpr auto from_string(const std::string& name) -> std::optional<Enum> {
172 auto entry = std::ranges::find_if(enum_mapping<Enum>::values, [&name](const auto& entry){ return entry.name == name; });
173
174 if (entry == std::ranges::end(enum_mapping<Enum>::values)) {
175 return std::nullopt;
176 }
177
178 return entry->value;
179}
180
181} // namespace sbx::utility
182
183template<typename Type>
184requires (sbx::utility::is_bit_field_v<Type>)
185constexpr auto operator|(const Type lhs, const Type rhs) -> Type {
186 return sbx::utility::from_underlying<Type>(sbx::utility::to_underlying(lhs) | sbx::utility::to_underlying(rhs));
187}
188
189
190template<typename Type>
191requires (sbx::utility::is_bit_field_v<Type>)
192constexpr auto operator&(const Type lhs, const Type rhs) -> Type {
193 return sbx::utility::from_underlying<Type>(sbx::utility::to_underlying(lhs) & sbx::utility::to_underlying(rhs));
194}
195
196#endif // LIBSBX_UTILITY_ENUM_HPP_
Definition: enum.hpp:80
Definition: enum.hpp:143
Definition: enum.hpp:28
Definition: enum.hpp:150
Definition: enum.hpp:73