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 "../macros.hpp"
8#include "cast.hpp"
9#include "debugger.hpp"
10#include "exception.hpp"
11#include <cstddef>
12#include <type_traits>
13#include <array>
14#include <algorithm>
15#include <string_view>
16#include <stdexcept>
17
18hi_export_module(hikogui.utility.enum_metadata);
19
20hi_warning_push();
21// C26445: Do not assign gsl::span or std::string_view to a reference. They are cheap to construct and are not owners of
22// the underlying data. (gsl.view).
23// False positive, sometimes the template is instantiated with string_view, sometimes not.
24hi_warning_ignore_msvc(26445);
25
26hi_export namespace hi { inline namespace v1 {
27
34template<typename ValueType, typename NameType, std::size_t N>
36public:
37 using value_type = ValueType;
38 using name_type = NameType;
39
42 constexpr static std::size_t count = N;
43
47
48 static_assert(std::is_enum_v<value_type>, "value_type Must be an enum");
49 static_assert(N != 0);
50
53 [[nodiscard]] constexpr size_t size() const noexcept
54 {
55 return count;
56 }
57
60 [[nodiscard]] constexpr value_type minimum() const noexcept
61 {
62 return std::get<0>(_by_value).value;
63 }
64
67 [[nodiscard]] constexpr value_type maximum() const noexcept
68 {
69 return std::get<N - 1>(_by_value).value;
70 }
71
85 template<typename... Args>
86 [[nodiscard]] constexpr enum_metadata(Args const&...args) noexcept
87 {
88 static_assert(sizeof...(Args) == N * 2);
89 add_value_name<0>(args...);
90
91 std::sort(_by_name.begin(), _by_name.end(), [](hilet& a, hilet& b) {
92 return a.name < b.name;
93 });
94
95 std::sort(_by_value.begin(), _by_value.end(), [](hilet& a, hilet& b) {
96 return std::to_underlying(a.value) < std::to_underlying(b.value);
97 });
98
99 values_are_continues = check_values_are_continues();
100 }
101
107 [[nodiscard]] constexpr bool contains(std::convertible_to<name_type> auto&& name) const noexcept
108 {
109 return find(name_type{hi_forward(name)}) != nullptr;
110 }
111
117 [[nodiscard]] constexpr bool contains(value_type value) const noexcept
118 {
119 return find(value) != nullptr;
120 }
121
128 [[nodiscard]] constexpr value_type at(std::convertible_to<name_type> auto&& name) const
129 {
130 if (hilet *value = find(name_type{hi_forward(name)})) {
131 return *value;
132 } else {
133 throw std::out_of_range{"enum_metadata::at"};
134 }
135 }
136
143 [[nodiscard]] constexpr name_type const& at(value_type value) const
144 {
145 if (hilet *name = find(value)) {
146 return *name;
147 } else {
148 throw std::out_of_range{"enum_metadata::at"};
149 }
150 }
151
157 [[nodiscard]] constexpr std::optional<value_type> at_if(std::convertible_to<name_type> auto&& name) const noexcept
158 {
159 if (hilet *value = find(name_type{hi_forward(name)})) {
160 return *value;
161 } else {
162 return std::nullopt;
163 }
164 }
165
172 [[nodiscard]] constexpr value_type at(std::convertible_to<name_type> auto&& name, value_type default_value) const noexcept
173 {
174 if (hilet *value = find(name_type{hi_forward(name)})) {
175 return *value;
176 } else {
177 return default_value;
178 }
179 }
180
187 [[nodiscard]] constexpr name_type at(value_type value, std::convertible_to<name_type> auto&& default_name) const noexcept
188 {
189 if (hilet *name = find(value)) {
190 return *name;
191 } else {
192 return hi_forward(default_name);
193 }
194 }
195
202 [[nodiscard]] constexpr value_type operator[](std::convertible_to<name_type> auto&& name) const noexcept
203 {
204 auto *value = find(name_type{hi_forward(name)});
205 hi_assert_not_null(value);
206 return *value;
207 }
208
215 [[nodiscard]] constexpr name_type const& operator[](value_type value) const noexcept
216 {
217 auto *name = find(value);
218 hi_assert_not_null(name);
219 return *name;
220 }
221
222private:
223 struct value_name {
224 value_type value;
225 name_type name;
226
227 constexpr value_name() noexcept : value(), name() {}
228 constexpr value_name(value_type value, name_type name) noexcept : value(value), name(std::move(name)) {}
229 };
230
233
234 [[nodiscard]] constexpr name_type const *find(value_type value) const noexcept
235 {
237 // If the enum values are continues we can do an associative lookup.
238 hilet it = _by_value.begin();
239 hilet offset = std::to_underlying(it->value);
240 hilet i = std::to_underlying(value) - offset;
241 return (i >= 0 and i < N) ? &(it + i)->name : nullptr;
242
243 } else {
244 hilet it = std::lower_bound(_by_value.begin(), _by_value.end(), value, [](hilet& item, hilet& key) {
245 return item.value < key;
246 });
247
248 return (it != _by_value.end() and it->value == value) ? &it->name : nullptr;
249 }
250 }
251
252 [[nodiscard]] constexpr value_type const *find(name_type const& name) const noexcept
253 {
254 hilet it = std::lower_bound(_by_name.begin(), _by_name.end(), name, [](hilet& item, hilet& key) {
255 return item.name < key;
256 });
257
258 return (it != _by_name.end() and it->name == name) ? &it->value : nullptr;
259 }
260
265 template<std::size_t I, typename... Rest>
266 constexpr void add_value_name(value_type value, name_type name, Rest const&...rest) noexcept
267 {
268 static_assert(sizeof...(Rest) % 2 == 0);
269
270 std::get<I>(_by_name) = {value, name};
271 std::get<I>(_by_value) = {value, std::move(name)};
272
273 if constexpr (sizeof...(Rest) > 0) {
275 }
276 }
277
282 [[nodiscard]] constexpr bool check_values_are_continues() const noexcept
283 {
284 auto check_value = std::to_underlying(minimum());
285 for (hilet& item : _by_value) {
286 if (std::to_underlying(item.value) != check_value++) {
287 return false;
288 }
289 }
290 return true;
291 }
292};
293
294template<typename T>
296 using type = std::decay_t<T>;
297};
298
299// clang-format off
300template<> struct enum_metadata_name<char const *> { using type = std::string_view; };
301template<> struct enum_metadata_name<char *> { using type = std::string_view; };
302template<size_t N> struct enum_metadata_name<char [N]> { using type = std::string_view; };
303template<size_t N> struct enum_metadata_name<char const [N]> { using type = std::string_view; };
304// clang-format on
305
306template<typename T>
307using enum_metadata_name_t = enum_metadata_name<T>::type;
308
309template<typename ValueType, typename NameType, typename... Rest>
310enum_metadata(ValueType const&, NameType const&, Rest const&...)
311 -> enum_metadata<ValueType, enum_metadata_name_t<NameType>, (sizeof...(Rest) + 2) / 2>;
312
313}} // namespace hi::inline v1
314
315hi_warning_pop();
Functions for casting values between types savely.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
A object that holds enum-values and strings.
Definition enum_metadata.hpp:35
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:157
constexpr value_type maximum() const noexcept
Get the maximum value.
Definition enum_metadata.hpp:67
constexpr value_type operator[](std::convertible_to< name_type > auto &&name) const noexcept
Get an enum-value from a name.
Definition enum_metadata.hpp:202
constexpr value_type minimum() const noexcept
Get the minimum value.
Definition enum_metadata.hpp:60
constexpr bool contains(std::convertible_to< name_type > auto &&name) const noexcept
Check if the enum has a name.
Definition enum_metadata.hpp:107
constexpr bool contains(value_type value) const noexcept
Check if the enum has a value.
Definition enum_metadata.hpp:117
constexpr name_type const & at(value_type value) const
Get a name from an enum-value.
Definition enum_metadata.hpp:143
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:187
static constexpr std::size_t count
The number of enum values.
Definition enum_metadata.hpp:42
constexpr size_t size() const noexcept
Get the number of enum values.
Definition enum_metadata.hpp:53
constexpr value_type at(std::convertible_to< name_type > auto &&name) const
Get an enum-value from a name.
Definition enum_metadata.hpp:128
constexpr enum_metadata(Args const &...args) noexcept
Construct a enum-names table object.
Definition enum_metadata.hpp:86
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:172
bool values_are_continues
The numeric values in the enum do not contain a gap.
Definition enum_metadata.hpp:46
constexpr name_type const & operator[](value_type value) const noexcept
Get a name from an enum-value.
Definition enum_metadata.hpp:215
Definition enum_metadata.hpp:295
T begin(T... args)
T end(T... args)
T lower_bound(T... args)
T move(T... args)
T sort(T... args)