HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
enum_metadata.hpp
1// Copyright Take Vos 2021.
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 "required.hpp"
8#include "cast.hpp"
9#include "assert.hpp"
10#include <cstddef>
11#include <type_traits>
12#include <array>
13#include <algorithm>
14
15namespace hi::inline v1 {
16
22template<typename T, std::size_t N>
24 static_assert(std::is_enum_v<T>, "Must be an enum");
25 static_assert(N != 0);
26
27public:
28 using value_type = T;
29
32 static constexpr std::size_t count = N;
33
37
40 [[nodiscard]] constexpr value_type minimum() const noexcept
41 {
42 return std::get<0>(_by_value).value;
43 }
44
47 [[nodiscard]] constexpr value_type maximum() const noexcept
48 {
49 return std::get<N-1>(_by_value).value;
50 }
51
65 template<typename... Args>
66 [[nodiscard]] constexpr enum_metadata(Args const &...args) noexcept
67 {
68 static_assert(sizeof...(Args) == N * 2);
69 add_value_name<0>(args...);
70
71 std::sort(_by_name.begin(), _by_name.end(), [](hilet &a, hilet &b) {
72 return a.name < b.name;
73 });
74
75 std::sort(_by_value.begin(), _by_value.end(), [](hilet &a, hilet &b) {
76 return to_underlying(a.value) < to_underlying(b.value);
77 });
78
79 values_are_continues = check_values_are_continues();
80 }
81
87 [[nodiscard]] constexpr bool contains(std::string_view name) const noexcept
88 {
89 return find(name) != nullptr;
90 }
91
97 [[nodiscard]] constexpr bool contains(value_type value) const noexcept
98 {
99 return find(value) != nullptr;
100 }
101
108 [[nodiscard]] constexpr value_type at(std::string_view name) const
109 {
110 if (hilet *value = find(name)) {
111 return *value;
112 } else {
113 throw std::out_of_range{"enum_metadata::at"};
114 }
115 }
116
123 [[nodiscard]] constexpr std::string_view const &at(value_type value) const
124 {
125 if (hilet *name = find(value)) {
126 return *name;
127 } else {
128 throw std::out_of_range{"enum_metadata::at"};
129 }
130 }
131
138 [[nodiscard]] constexpr value_type at(std::string_view name, value_type default_value) const noexcept
139 {
140 if (hilet *value = find(name)) {
141 return *value;
142 } else {
143 return default_value;
144 }
145 }
146
153 [[nodiscard]] constexpr std::string_view at(value_type value, std::string_view default_name) const noexcept
154 {
155 if (hilet *name = find(value)) {
156 return *name;
157 } else {
158 return default_name;
159 }
160 }
161
168 [[nodiscard]] constexpr value_type operator[](std::string_view name) const noexcept
169 {
170 auto *value = find(name);
171 hi_axiom(value != nullptr);
172 return *value;
173 }
174
181 [[nodiscard]] constexpr std::string_view const &operator[](value_type value) const noexcept
182 {
183 auto *name = find(value);
184 hi_axiom(name != nullptr);
185 return *name;
186 }
187
188private:
189 struct value_name {
190 value_type value;
191 std::string_view name;
192
193 constexpr value_name() noexcept : value(), name() {}
194 constexpr value_name(value_type value, std::string_view name) noexcept : value(value), name(name) {}
195 };
196
199
200 [[nodiscard]] constexpr std::string_view const *find(value_type value) const noexcept
201 {
202 if (values_are_continues) {
203 // If the enum values are continues we can do an associative lookup.
204 hilet it = _by_value.begin();
205 hilet offset = to_underlying(it->value);
206 hilet i = to_underlying(value) - offset;
207 return (i >= 0 and i < N) ? &(it + i)->name : nullptr;
208
209 } else {
210 hilet it = std::lower_bound(_by_value.begin(), _by_value.end(), value, [](hilet &item, hilet &key) {
211 return item.value < key;
212 });
213
214 return (it != _by_value.end() and it->value == value) ? &it->name : nullptr;
215 }
216 }
217
218 [[nodiscard]] constexpr value_type const *find(std::string_view name) const noexcept
219 {
220 hilet it = std::lower_bound(_by_name.begin(), _by_name.end(), name, [](hilet &item, hilet &key) {
221 return item.name < key;
222 });
223
224 return (it != _by_name.end() and it->name == name) ? &it->value : nullptr;
225 }
226
231 template<std::size_t I, typename... Rest>
232 constexpr void add_value_name(value_type value, std::string_view name, Rest const &...rest) noexcept
233 {
234 static_assert(sizeof...(Rest) % 2 == 0);
235
236 std::get<I>(_by_name) = {value, name};
237 std::get<I>(_by_value) = {value, name};
238
239 if constexpr (sizeof...(Rest) > 0) {
240 add_value_name<I + 1>(rest...);
241 }
242 }
243
248 [[nodiscard]] constexpr bool check_values_are_continues() const noexcept
249 {
250 auto check_value = to_underlying(minimum());
251 for (hilet &item : _by_value) {
252 if (to_underlying(item.value) != check_value++) {
253 return false;
254 }
255 }
256 return true;
257 }
258};
259
260template<typename T, typename... Rest>
261enum_metadata(T const &, Rest const &...) -> enum_metadata<T, (sizeof...(Rest) + 1) / 2>;
262
263} // namespace hi
This file includes required definitions.
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
A object that holds enum-values and strings.
Definition enum_metadata.hpp:23
constexpr std::string_view const & operator[](value_type value) const noexcept
Get a name from an enum-value.
Definition enum_metadata.hpp:181
constexpr std::string_view const & at(value_type value) const
Get a name from an enum-value.
Definition enum_metadata.hpp:123
constexpr value_type at(std::string_view name, value_type default_value) const noexcept
Get an enum-value from a name.
Definition enum_metadata.hpp:138
bool values_are_continues
The numeric values in the enum do not contain a gap.
Definition enum_metadata.hpp:36
constexpr value_type at(std::string_view name) const
Get an enum-value from a name.
Definition enum_metadata.hpp:108
constexpr enum_metadata(Args const &...args) noexcept
Construct a enum-names table object.
Definition enum_metadata.hpp:66
constexpr value_type operator[](std::string_view name) const noexcept
Get an enum-value from a name.
Definition enum_metadata.hpp:168
constexpr value_type minimum() const noexcept
Get the minimum value.
Definition enum_metadata.hpp:40
constexpr bool contains(value_type value) const noexcept
Check if the enum has a value.
Definition enum_metadata.hpp:97
constexpr bool contains(std::string_view name) const noexcept
Check if the enum has a name.
Definition enum_metadata.hpp:87
constexpr std::string_view at(value_type value, std::string_view default_name) const noexcept
Get a name from an enum-value.
Definition enum_metadata.hpp:153
constexpr value_type maximum() const noexcept
Get the maximum value.
Definition enum_metadata.hpp:47
T begin(T... args)
T end(T... args)
T find(T... args)
T lower_bound(T... args)
T sort(T... args)