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
153 [[nodiscard]] constexpr value_type at(std::convertible_to<name_type> auto&& name, value_type default_value) const noexcept
154 {
155 if (hilet *value = find(name_type{hi_forward(name)})) {
156 return *value;
157 } else {
158 return default_value;
159 }
160 }
161
168 [[nodiscard]] constexpr name_type at(value_type value, std::convertible_to<name_type> auto&& default_name) const noexcept
169 {
170 if (hilet *name = find(value)) {
171 return *name;
172 } else {
173 return hi_forward(default_name);
174 }
175 }
176
183 [[nodiscard]] constexpr value_type operator[](std::convertible_to<name_type> auto&& name) const noexcept
184 {
185 auto *value = find(name_type{hi_forward(name)});
186 hi_assert_not_null(value);
187 return *value;
188 }
189
196 [[nodiscard]] constexpr name_type const& operator[](value_type value) const noexcept
197 {
198 auto *name = find(value);
199 hi_assert_not_null(name);
200 return *name;
201 }
202
203private:
204 struct value_name {
205 value_type value;
206 name_type name;
207
208 constexpr value_name() noexcept : value(), name() {}
209 constexpr value_name(value_type value, name_type name) noexcept : value(value), name(std::move(name)) {}
210 };
211
214
215 [[nodiscard]] constexpr name_type const *find(value_type value) const noexcept
216 {
217 if (values_are_continues) {
218 // If the enum values are continues we can do an associative lookup.
219 hilet it = _by_value.begin();
220 hilet offset = to_underlying(it->value);
221 hilet i = to_underlying(value) - offset;
222 return (i >= 0 and i < N) ? &(it + i)->name : nullptr;
223
224 } else {
225 hilet it = std::lower_bound(_by_value.begin(), _by_value.end(), value, [](hilet& item, hilet& key) {
226 return item.value < key;
227 });
228
229 return (it != _by_value.end() and it->value == value) ? &it->name : nullptr;
230 }
231 }
232
233 [[nodiscard]] constexpr value_type const *find(name_type const& name) const noexcept
234 {
235 hilet it = std::lower_bound(_by_name.begin(), _by_name.end(), name, [](hilet& item, hilet& key) {
236 return item.name < key;
237 });
238
239 return (it != _by_name.end() and it->name == name) ? &it->value : nullptr;
240 }
241
246 template<std::size_t I, typename... Rest>
247 constexpr void add_value_name(value_type value, name_type name, Rest const&...rest) noexcept
248 {
249 static_assert(sizeof...(Rest) % 2 == 0);
250
251 std::get<I>(_by_name) = {value, name};
252 std::get<I>(_by_value) = {value, std::move(name)};
253
254 if constexpr (sizeof...(Rest) > 0) {
255 add_value_name<I + 1>(rest...);
256 }
257 }
258
263 [[nodiscard]] constexpr bool check_values_are_continues() const noexcept
264 {
265 auto check_value = to_underlying(minimum());
266 for (hilet& item : _by_value) {
267 if (to_underlying(item.value) != check_value++) {
268 return false;
269 }
270 }
271 return true;
272 }
273};
274
275template<typename T>
277 using type = std::decay_t<T>;
278};
279
280// clang-format off
281template<> struct enum_metadata_name<char const *> { using type = std::string_view; };
282template<> struct enum_metadata_name<char *> { using type = std::string_view; };
283template<size_t N> struct enum_metadata_name<char [N]> { using type = std::string_view; };
284template<size_t N> struct enum_metadata_name<char const [N]> { using type = std::string_view; };
285// clang-format on
286
287template<typename T>
288using enum_metadata_name_t = enum_metadata_name<T>::type;
289
290template<typename ValueType, typename NameType, typename... Rest>
291enum_metadata(ValueType const&, NameType const&, Rest const&...)
292 -> enum_metadata<ValueType, enum_metadata_name_t<NameType>, (sizeof...(Rest) + 2) / 2>;
293
294} // namespace hi::inline v1
295
296hi_warning_pop();
#define hi_assert_not_null(x,...)
Assert if an expression is not nullptr.
Definition assert.hpp:223
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
DOXYGEN BUG.
Definition algorithm.hpp:13
A object that holds enum-values and strings.
Definition enum_metadata.hpp:30
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:196
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:168
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:183
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:153
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:276
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)