HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
enum_metadata.hpp
1// Copyright Take Vos 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "utility.hpp"
8#include "cast.hpp"
9#include <cstddef>
10#include <type_traits>
11#include <array>
12#include <algorithm>
13#include <string_view>
14
15hi_warning_push();
16// C26445: Do not assign gsl::span or std::string_view to a reference. They are cheap to construct and are not owners of
17// the underlying data. (gsl.view).
18// False positive, sometimes the template is instantiated with string_view, sometimes not.
19hi_warning_ignore_msvc(26445);
20
21namespace hi::inline v1 {
22
29template<typename ValueType, typename NameType, std::size_t N>
31public:
32 using value_type = ValueType;
33 using name_type = NameType;
34
37 static constexpr std::size_t count = N;
38
42
43 static_assert(std::is_enum_v<value_type>, "value_type Must be an enum");
44 static_assert(N != 0);
45
48 [[nodiscard]] constexpr size_t size() const noexcept
49 {
50 return count;
51 }
52
55 [[nodiscard]] constexpr value_type minimum() const noexcept
56 {
57 return std::get<0>(_by_value).value;
58 }
59
62 [[nodiscard]] constexpr value_type maximum() const noexcept
63 {
64 return std::get<N - 1>(_by_value).value;
65 }
66
80 template<typename... Args>
81 [[nodiscard]] constexpr enum_metadata(Args const&...args) noexcept
82 {
83 static_assert(sizeof...(Args) == N * 2);
84 add_value_name<0>(args...);
85
86 std::sort(_by_name.begin(), _by_name.end(), [](hilet& a, hilet& b) {
87 return a.name < b.name;
88 });
89
90 std::sort(_by_value.begin(), _by_value.end(), [](hilet& a, hilet& b) {
91 return to_underlying(a.value) < to_underlying(b.value);
92 });
93
94 values_are_continues = check_values_are_continues();
95 }
96
102 [[nodiscard]] constexpr bool contains(std::convertible_to<name_type> auto&& name) const noexcept
103 {
104 return find(name_type{hi_forward(name)}) != nullptr;
105 }
106
112 [[nodiscard]] constexpr bool contains(value_type value) const noexcept
113 {
114 return find(value) != nullptr;
115 }
116
123 [[nodiscard]] constexpr value_type at(std::convertible_to<name_type> auto&& name) const
124 {
125 if (hilet *value = find(name_type{hi_forward(name)})) {
126 return *value;
127 } else {
128 throw std::out_of_range{"enum_metadata::at"};
129 }
130 }
131
138 [[nodiscard]] constexpr name_type const& at(value_type value) const
139 {
140 if (hilet *name = find(value)) {
141 return *name;
142 } else {
143 throw std::out_of_range{"enum_metadata::at"};
144 }
145 }
146
152 [[nodiscard]] constexpr std::optional<value_type> at_if(std::convertible_to<name_type> auto&& name) const noexcept
153 {
154 if (hilet *value = find(name_type{hi_forward(name)})) {
155 return *value;
156 } else {
157 return std::nullopt;
158 }
159 }
160
167 [[nodiscard]] constexpr value_type at(std::convertible_to<name_type> auto&& name, value_type default_value) const noexcept
168 {
169 if (hilet *value = find(name_type{hi_forward(name)})) {
170 return *value;
171 } else {
172 return default_value;
173 }
174 }
175
182 [[nodiscard]] constexpr name_type at(value_type value, std::convertible_to<name_type> auto&& default_name) const noexcept
183 {
184 if (hilet *name = find(value)) {
185 return *name;
186 } else {
187 return hi_forward(default_name);
188 }
189 }
190
197 [[nodiscard]] constexpr value_type operator[](std::convertible_to<name_type> auto&& name) const noexcept
198 {
199 auto *value = find(name_type{hi_forward(name)});
200 hi_assert_not_null(value);
201 return *value;
202 }
203
210 [[nodiscard]] constexpr name_type const& operator[](value_type value) const noexcept
211 {
212 auto *name = find(value);
213 hi_assert_not_null(name);
214 return *name;
215 }
216
217private:
218 struct value_name {
219 value_type value;
220 name_type name;
221
222 constexpr value_name() noexcept : value(), name() {}
223 constexpr value_name(value_type value, name_type name) noexcept : value(value), name(std::move(name)) {}
224 };
225
228
229 [[nodiscard]] constexpr name_type const *find(value_type value) const noexcept
230 {
231 if (values_are_continues) {
232 // If the enum values are continues we can do an associative lookup.
233 hilet it = _by_value.begin();
234 hilet offset = to_underlying(it->value);
235 hilet i = to_underlying(value) - offset;
236 return (i >= 0 and i < N) ? &(it + i)->name : nullptr;
237
238 } else {
239 hilet it = std::lower_bound(_by_value.begin(), _by_value.end(), value, [](hilet& item, hilet& key) {
240 return item.value < key;
241 });
242
243 return (it != _by_value.end() and it->value == value) ? &it->name : nullptr;
244 }
245 }
246
247 [[nodiscard]] constexpr value_type const *find(name_type const& name) const noexcept
248 {
249 hilet it = std::lower_bound(_by_name.begin(), _by_name.end(), name, [](hilet& item, hilet& key) {
250 return item.name < key;
251 });
252
253 return (it != _by_name.end() and it->name == name) ? &it->value : nullptr;
254 }
255
260 template<std::size_t I, typename... Rest>
261 constexpr void add_value_name(value_type value, name_type name, Rest const&...rest) noexcept
262 {
263 static_assert(sizeof...(Rest) % 2 == 0);
264
265 std::get<I>(_by_name) = {value, name};
266 std::get<I>(_by_value) = {value, std::move(name)};
267
268 if constexpr (sizeof...(Rest) > 0) {
269 add_value_name<I + 1>(rest...);
270 }
271 }
272
277 [[nodiscard]] constexpr bool check_values_are_continues() const noexcept
278 {
279 auto check_value = to_underlying(minimum());
280 for (hilet& item : _by_value) {
281 if (to_underlying(item.value) != check_value++) {
282 return false;
283 }
284 }
285 return true;
286 }
287};
288
289template<typename T>
291 using type = std::decay_t<T>;
292};
293
294// clang-format off
295template<> struct enum_metadata_name<char const *> { using type = std::string_view; };
296template<> struct enum_metadata_name<char *> { using type = std::string_view; };
297template<size_t N> struct enum_metadata_name<char [N]> { using type = std::string_view; };
298template<size_t N> struct enum_metadata_name<char const [N]> { using type = std::string_view; };
299// clang-format on
300
301template<typename T>
302using enum_metadata_name_t = enum_metadata_name<T>::type;
303
304template<typename ValueType, typename NameType, typename... Rest>
305enum_metadata(ValueType const&, NameType const&, Rest const&...)
306 -> enum_metadata<ValueType, enum_metadata_name_t<NameType>, (sizeof...(Rest) + 2) / 2>;
307
308} // namespace hi::inline v1
309
310hi_warning_pop();
#define hi_assert_not_null(x,...)
Assert if an expression is not nullptr.
Definition assert.hpp:238
Utilities used by the HikoGUI library itself.
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
#define hi_forward(x)
Forward a value, based on the decltype of the value.
Definition utility.hpp:29
Functions for casting values between types savely.
DOXYGEN BUG.
Definition algorithm.hpp:13
A object that holds enum-values and strings.
Definition enum_metadata.hpp:30
constexpr std::optional< value_type > at_if(std::convertible_to< name_type > auto &&name) const noexcept
Get an enum-value from a name.
Definition enum_metadata.hpp:152
constexpr bool contains(value_type value) const noexcept
Check if the enum has a value.
Definition enum_metadata.hpp:112
constexpr size_t size() const noexcept
Get the number of enum values.
Definition enum_metadata.hpp:48
constexpr value_type maximum() const noexcept
Get the maximum value.
Definition enum_metadata.hpp:62
bool values_are_continues
The numeric values in the enum do not contain a gap.
Definition enum_metadata.hpp:41
constexpr name_type const & operator[](value_type value) const noexcept
Get a name from an enum-value.
Definition enum_metadata.hpp:210
constexpr bool contains(std::convertible_to< name_type > auto &&name) const noexcept
Check if the enum has a name.
Definition enum_metadata.hpp:102
constexpr name_type at(value_type value, std::convertible_to< name_type > auto &&default_name) const noexcept
Get a name from an enum-value.
Definition enum_metadata.hpp:182
constexpr value_type minimum() const noexcept
Get the minimum value.
Definition enum_metadata.hpp:55
constexpr enum_metadata(Args const &...args) noexcept
Construct a enum-names table object.
Definition enum_metadata.hpp:81
constexpr value_type operator[](std::convertible_to< name_type > auto &&name) const noexcept
Get an enum-value from a name.
Definition enum_metadata.hpp:197
constexpr value_type at(std::convertible_to< name_type > auto &&name, value_type default_value) const noexcept
Get an enum-value from a name.
Definition enum_metadata.hpp:167
constexpr value_type at(std::convertible_to< name_type > auto &&name) const
Get an enum-value from a name.
Definition enum_metadata.hpp:123
constexpr name_type const & at(value_type value) const
Get a name from an enum-value.
Definition enum_metadata.hpp:138
Definition enum_metadata.hpp:290
T begin(T... args)
T end(T... args)
T find(T... args)
T lower_bound(T... args)
T move(T... args)
T sort(T... args)