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 "assert.hpp"
10#include <cstddef>
11#include <type_traits>
12#include <array>
13#include <algorithm>
14#include <string_view>
15
16hi_warning_push();
17// C26445: Do not assign gsl::span or std::string_view to a reference. They are cheap to construct and are not owners of
18// the underlying data. (gsl.view).
19// False positive, sometimes the template is instantiated with string_view, sometimes not.
20hi_warning_ignore_msvc(26445);
21
22namespace hi::inline v1 {
23
30template<typename ValueType, typename NameType, std::size_t N>
32public:
33 using value_type = ValueType;
34 using name_type = NameType;
35
38 static constexpr std::size_t count = N;
39
43
44 static_assert(std::is_enum_v<value_type>, "value_type Must be an enum");
45 static_assert(N != 0);
46
49 [[nodiscard]] constexpr size_t size() const noexcept
50 {
51 return count;
52 }
53
56 [[nodiscard]] constexpr value_type minimum() const noexcept
57 {
58 return std::get<0>(_by_value).value;
59 }
60
63 [[nodiscard]] constexpr value_type maximum() const noexcept
64 {
65 return std::get<N - 1>(_by_value).value;
66 }
67
81 template<typename... Args>
82 [[nodiscard]] constexpr enum_metadata(Args const&...args) noexcept
83 {
84 static_assert(sizeof...(Args) == N * 2);
85 add_value_name<0>(args...);
86
87 std::sort(_by_name.begin(), _by_name.end(), [](hilet& a, hilet& b) {
88 return a.name < b.name;
89 });
90
91 std::sort(_by_value.begin(), _by_value.end(), [](hilet& a, hilet& b) {
92 return to_underlying(a.value) < to_underlying(b.value);
93 });
94
95 values_are_continues = check_values_are_continues();
96 }
97
103 [[nodiscard]] constexpr bool contains(std::convertible_to<name_type> auto&& name) const noexcept
104 {
105 return find(name_type{hi_forward(name)}) != nullptr;
106 }
107
113 [[nodiscard]] constexpr bool contains(value_type value) const noexcept
114 {
115 return find(value) != nullptr;
116 }
117
124 [[nodiscard]] constexpr value_type at(std::convertible_to<name_type> auto&& name) const
125 {
126 if (hilet *value = find(name_type{hi_forward(name)})) {
127 return *value;
128 } else {
129 throw std::out_of_range{"enum_metadata::at"};
130 }
131 }
132
139 [[nodiscard]] constexpr name_type const& at(value_type value) const
140 {
141 if (hilet *name = find(value)) {
142 return *name;
143 } else {
144 throw std::out_of_range{"enum_metadata::at"};
145 }
146 }
147
154 [[nodiscard]] constexpr value_type at(std::convertible_to<name_type> auto&& name, value_type default_value) const noexcept
155 {
156 if (hilet *value = find(name_type{hi_forward(name)})) {
157 return *value;
158 } else {
159 return default_value;
160 }
161 }
162
169 [[nodiscard]] constexpr name_type at(value_type value, std::convertible_to<name_type> auto&& default_name) const noexcept
170 {
171 if (hilet *name = find(value)) {
172 return *name;
173 } else {
174 return hi_forward(default_name);
175 }
176 }
177
184 [[nodiscard]] constexpr value_type operator[](std::convertible_to<name_type> auto&& name) const noexcept
185 {
186 auto *value = find(name_type{hi_forward(name)});
187 hi_assert_not_null(value);
188 return *value;
189 }
190
197 [[nodiscard]] constexpr name_type const& operator[](value_type value) const noexcept
198 {
199 auto *name = find(value);
200 hi_assert_not_null(name);
201 return *name;
202 }
203
204private:
205 struct value_name {
206 value_type value;
207 name_type name;
208
209 constexpr value_name() noexcept : value(), name() {}
210 constexpr value_name(value_type value, name_type name) noexcept : value(value), name(std::move(name)) {}
211 };
212
215
216 [[nodiscard]] constexpr name_type const *find(value_type value) const noexcept
217 {
218 if (values_are_continues) {
219 // If the enum values are continues we can do an associative lookup.
220 hilet it = _by_value.begin();
221 hilet offset = to_underlying(it->value);
222 hilet i = to_underlying(value) - offset;
223 return (i >= 0 and i < N) ? &(it + i)->name : nullptr;
224
225 } else {
226 hilet it = std::lower_bound(_by_value.begin(), _by_value.end(), value, [](hilet& item, hilet& key) {
227 return item.value < key;
228 });
229
230 return (it != _by_value.end() and it->value == value) ? &it->name : nullptr;
231 }
232 }
233
234 [[nodiscard]] constexpr value_type const *find(name_type const& name) const noexcept
235 {
236 hilet it = std::lower_bound(_by_name.begin(), _by_name.end(), name, [](hilet& item, hilet& key) {
237 return item.name < key;
238 });
239
240 return (it != _by_name.end() and it->name == name) ? &it->value : nullptr;
241 }
242
247 template<std::size_t I, typename... Rest>
248 constexpr void add_value_name(value_type value, name_type name, Rest const&...rest) noexcept
249 {
250 static_assert(sizeof...(Rest) % 2 == 0);
251
252 std::get<I>(_by_name) = {value, name};
253 std::get<I>(_by_value) = {value, std::move(name)};
254
255 if constexpr (sizeof...(Rest) > 0) {
256 add_value_name<I + 1>(rest...);
257 }
258 }
259
264 [[nodiscard]] constexpr bool check_values_are_continues() const noexcept
265 {
266 auto check_value = to_underlying(minimum());
267 for (hilet& item : _by_value) {
268 if (to_underlying(item.value) != check_value++) {
269 return false;
270 }
271 }
272 return true;
273 }
274};
275
276template<typename T>
278 using type = std::decay_t<T>;
279};
280
281// clang-format off
282template<> struct enum_metadata_name<char const *> { using type = std::string_view; };
283template<> struct enum_metadata_name<char *> { using type = std::string_view; };
284template<size_t N> struct enum_metadata_name<char [N]> { using type = std::string_view; };
285template<size_t N> struct enum_metadata_name<char const [N]> { using type = std::string_view; };
286// clang-format on
287
288template<typename T>
289using enum_metadata_name_t = enum_metadata_name<T>::type;
290
291template<typename ValueType, typename NameType, typename... Rest>
292enum_metadata(ValueType const&, NameType const&, Rest const&...)
293 -> enum_metadata<ValueType, enum_metadata_name_t<NameType>, (sizeof...(Rest) + 2) / 2>;
294
295} // namespace hi::inline v1
296
297hi_warning_pop();
Utilities to assert and bound check.
#define hi_assert_not_null(x)
Assert if an expression is not nullptr.
Definition assert.hpp:118
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:15
A object that holds enum-values and strings.
Definition enum_metadata.hpp:31
constexpr bool contains(value_type value) const noexcept
Check if the enum has a value.
Definition enum_metadata.hpp:113
constexpr size_t size() const noexcept
Get the number of enum values.
Definition enum_metadata.hpp:49
constexpr value_type maximum() const noexcept
Get the maximum value.
Definition enum_metadata.hpp:63
bool values_are_continues
The numeric values in the enum do not contain a gap.
Definition enum_metadata.hpp:42
constexpr name_type const & operator[](value_type value) const noexcept
Get a name from an enum-value.
Definition enum_metadata.hpp:197
constexpr bool contains(std::convertible_to< name_type > auto &&name) const noexcept
Check if the enum has a name.
Definition enum_metadata.hpp:103
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:169
constexpr value_type minimum() const noexcept
Get the minimum value.
Definition enum_metadata.hpp:56
constexpr enum_metadata(Args const &...args) noexcept
Construct a enum-names table object.
Definition enum_metadata.hpp:82
constexpr value_type operator[](std::convertible_to< name_type > auto &&name) const noexcept
Get an enum-value from a name.
Definition enum_metadata.hpp:184
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:154
constexpr value_type at(std::convertible_to< name_type > auto &&name) const
Get an enum-value from a name.
Definition enum_metadata.hpp:124
constexpr name_type const & at(value_type value) const
Get a name from an enum-value.
Definition enum_metadata.hpp:139
Definition enum_metadata.hpp:277
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)