Commit 6f0b3228ef0712e327eaf049acc7366541eec6c4

Authored by Patric Stout
1 parent 6a66c78c

chore(cmake): switch to conan for dependencies

CMakeLists.txt
@@ -17,6 +17,9 @@ set(MIN_LOGGER_LEVEL "INFO" CACHE STRING "Set minimal logger level (TRACE, DEBUG @@ -17,6 +17,9 @@ set(MIN_LOGGER_LEVEL "INFO" CACHE STRING "Set minimal logger level (TRACE, DEBUG
17 17
18 include(GNUInstallDirs) 18 include(GNUInstallDirs)
19 19
  20 +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
  21 +conan_basic_setup()
  22 +
20 add_library(${PROJECT_NAME} 23 add_library(${PROJECT_NAME}
21 src/Client.cpp 24 src/Client.cpp
22 src/Connection.cpp 25 src/Connection.cpp
@@ -25,11 +28,10 @@ add_library(${PROJECT_NAME} @@ -25,11 +28,10 @@ add_library(${PROJECT_NAME}
25 target_include_directories(${PROJECT_NAME} 28 target_include_directories(${PROJECT_NAME}
26 PUBLIC include 29 PUBLIC include
27 PRIVATE src 30 PRIVATE src
28 - PRIVATE vendor/magic_enum/include  
29 ) 31 )
30 32
31 find_package(Threads REQUIRED) 33 find_package(Threads REQUIRED)
32 -target_link_libraries(${PROJECT_NAME} PRIVATE Threads::Threads) 34 +target_link_libraries(${PROJECT_NAME} PRIVATE ${CONAN_LIBS} Threads::Threads)
33 35
34 set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1 PUBLIC_HEADER include/TrueMQTT.h) 36 set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1 PUBLIC_HEADER include/TrueMQTT.h)
35 configure_file(truemqtt.pc.in truemqtt.pc @ONLY) 37 configure_file(truemqtt.pc.in truemqtt.pc @ONLY)
README.md
@@ -6,9 +6,22 @@ All basic functionality is in there, but it is lacking some QoL functionalities, @@ -6,9 +6,22 @@ All basic functionality is in there, but it is lacking some QoL functionalities,
6 6
7 ## Development 7 ## Development
8 8
  9 +Prepare a build folder:
  10 +
9 ```bash 11 ```bash
10 mkdir build 12 mkdir build
11 cd build 13 cd build
  14 +```
  15 +
  16 +Install dependencies via [conan](https://conan.io/downloads.html):
  17 +
  18 +```bash
  19 +conan install ..
  20 +```
  21 +
  22 +Now you can compile this library:
  23 +
  24 +```bash
12 cmake .. -DBUILD_SHARED_LIBS=ON -DMIN_LOGGER_LEVEL=INFO 25 cmake .. -DBUILD_SHARED_LIBS=ON -DMIN_LOGGER_LEVEL=INFO
13 make -j$(nproc) 26 make -j$(nproc)
14 27
conanfile.txt 0 → 100644
  1 +[requires]
  2 +catch2/3.1.0
  3 +magic_enum/0.8.1
  4 +
  5 +[generators]
  6 +cmake
vendor/magic_enum/LICENSE deleted
1 -MIT License  
2 -  
3 -Copyright (c) 2019 - 2022 Daniil Goncharov  
4 -  
5 -Permission is hereby granted, free of charge, to any person obtaining a copy  
6 -of this software and associated documentation files (the "Software"), to deal  
7 -in the Software without restriction, including without limitation the rights  
8 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
9 -copies of the Software, and to permit persons to whom the Software is  
10 -furnished to do so, subject to the following conditions:  
11 -  
12 -The above copyright notice and this permission notice shall be included in all  
13 -copies or substantial portions of the Software.  
14 -  
15 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
16 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
17 -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
18 -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
19 -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
20 -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  
21 -SOFTWARE.  
vendor/magic_enum/README.md deleted
1 -# Magic Enum  
2 -  
3 -This is v0.8.1 of [magic_enum](https://github.com/Neargye/magic_enum).  
4 -  
5 -See upstream for more details about magic_enum.  
6 -  
vendor/magic_enum/include/magic_enum.hpp deleted
1 -// __ __ _ ______ _____  
2 -// | \/ | (_) | ____| / ____|_ _  
3 -// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_  
4 -// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|  
5 -// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|  
6 -// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|  
7 -// __/ | https://github.com/Neargye/magic_enum  
8 -// |___/ version 0.8.1  
9 -//  
10 -// Licensed under the MIT License <http://opensource.org/licenses/MIT>.  
11 -// SPDX-License-Identifier: MIT  
12 -// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.  
13 -//  
14 -// Permission is hereby granted, free of charge, to any person obtaining a copy  
15 -// of this software and associated documentation files (the "Software"), to deal  
16 -// in the Software without restriction, including without limitation the rights  
17 -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
18 -// copies of the Software, and to permit persons to whom the Software is  
19 -// furnished to do so, subject to the following conditions:  
20 -//  
21 -// The above copyright notice and this permission notice shall be included in all  
22 -// copies or substantial portions of the Software.  
23 -//  
24 -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
25 -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
26 -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
27 -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
28 -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
29 -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  
30 -// SOFTWARE.  
31 -  
32 -#ifndef NEARGYE_MAGIC_ENUM_HPP  
33 -#define NEARGYE_MAGIC_ENUM_HPP  
34 -  
35 -#define MAGIC_ENUM_VERSION_MAJOR 0  
36 -#define MAGIC_ENUM_VERSION_MINOR 8  
37 -#define MAGIC_ENUM_VERSION_PATCH 1  
38 -  
39 -#include <array>  
40 -#include <cassert>  
41 -#include <cstdint>  
42 -#include <cstddef>  
43 -#include <iosfwd>  
44 -#include <limits>  
45 -#include <type_traits>  
46 -#include <utility>  
47 -#include <variant>  
48 -  
49 -#if defined(MAGIC_ENUM_CONFIG_FILE)  
50 -#include MAGIC_ENUM_CONFIG_FILE  
51 -#endif  
52 -  
53 -#if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)  
54 -#include <optional>  
55 -#endif  
56 -#if !defined(MAGIC_ENUM_USING_ALIAS_STRING)  
57 -#include <string>  
58 -#endif  
59 -#if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)  
60 -#include <string_view>  
61 -#endif  
62 -  
63 -#if defined(__clang__)  
64 -# pragma clang diagnostic push  
65 -#elif defined(__GNUC__)  
66 -# pragma GCC diagnostic push  
67 -# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.  
68 -#elif defined(_MSC_VER)  
69 -# pragma warning(push)  
70 -# pragma warning(disable : 26495) // Variable 'static_string<N>::chars_' is uninitialized.  
71 -# pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value.  
72 -# pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call.  
73 -# pragma warning(disable : 4514) // Unreferenced inline function has been removed.  
74 -#endif  
75 -  
76 -// Checks magic_enum compiler compatibility.  
77 -#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910  
78 -# undef MAGIC_ENUM_SUPPORTED  
79 -# define MAGIC_ENUM_SUPPORTED 1  
80 -#endif  
81 -  
82 -// Checks magic_enum compiler aliases compatibility.  
83 -#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920  
84 -# undef MAGIC_ENUM_SUPPORTED_ALIASES  
85 -# define MAGIC_ENUM_SUPPORTED_ALIASES 1  
86 -#endif  
87 -  
88 -// Enum value must be greater or equals than MAGIC_ENUM_RANGE_MIN. By default MAGIC_ENUM_RANGE_MIN = -128.  
89 -// If need another min range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN.  
90 -#if !defined(MAGIC_ENUM_RANGE_MIN)  
91 -# define MAGIC_ENUM_RANGE_MIN -128  
92 -#endif  
93 -  
94 -// Enum value must be less or equals than MAGIC_ENUM_RANGE_MAX. By default MAGIC_ENUM_RANGE_MAX = 128.  
95 -// If need another max range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX.  
96 -#if !defined(MAGIC_ENUM_RANGE_MAX)  
97 -# define MAGIC_ENUM_RANGE_MAX 128  
98 -#endif  
99 -  
100 -namespace magic_enum {  
101 -  
102 -// If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL.  
103 -#if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)  
104 -MAGIC_ENUM_USING_ALIAS_OPTIONAL  
105 -#else  
106 -using std::optional;  
107 -#endif  
108 -  
109 -// If need another string_view type, define the macro MAGIC_ENUM_USING_ALIAS_STRING_VIEW.  
110 -#if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)  
111 -MAGIC_ENUM_USING_ALIAS_STRING_VIEW  
112 -#else  
113 -using std::string_view;  
114 -#endif  
115 -  
116 -// If need another string type, define the macro MAGIC_ENUM_USING_ALIAS_STRING.  
117 -#if defined(MAGIC_ENUM_USING_ALIAS_STRING)  
118 -MAGIC_ENUM_USING_ALIAS_STRING  
119 -#else  
120 -using std::string;  
121 -#endif  
122 -  
123 -namespace customize {  
124 -  
125 -// Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128.  
126 -// If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX.  
127 -// If need another range for specific enum type, add specialization enum_range for necessary enum type.  
128 -template <typename E>  
129 -struct enum_range {  
130 - static_assert(std::is_enum_v<E>, "magic_enum::customize::enum_range requires enum type.");  
131 - static constexpr int min = MAGIC_ENUM_RANGE_MIN;  
132 - static constexpr int max = MAGIC_ENUM_RANGE_MAX;  
133 - static_assert(max > min, "magic_enum::customize::enum_range requires max > min.");  
134 -};  
135 -  
136 -static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN.");  
137 -static_assert((MAGIC_ENUM_RANGE_MAX - MAGIC_ENUM_RANGE_MIN) < (std::numeric_limits<std::uint16_t>::max)(), "MAGIC_ENUM_RANGE must be less than UINT16_MAX.");  
138 -  
139 -namespace detail {  
140 -enum class default_customize_tag {};  
141 -enum class invalid_customize_tag {};  
142 -} // namespace magic_enum::customize::detail  
143 -  
144 -using customize_t = std::variant<string_view, detail::default_customize_tag, detail::invalid_customize_tag>;  
145 -  
146 -// Default customize.  
147 -inline constexpr auto default_tag = detail::default_customize_tag{};  
148 -// Invalid customize.  
149 -inline constexpr auto invalid_tag = detail::invalid_customize_tag{};  
150 -  
151 -// If need custom names for enum, add specialization enum_name for necessary enum type.  
152 -template <typename E>  
153 -constexpr customize_t enum_name(E) noexcept {  
154 - return default_tag;  
155 -}  
156 -  
157 -// If need custom type name for enum, add specialization enum_type_name for necessary enum type.  
158 -template <typename E>  
159 -constexpr customize_t enum_type_name() noexcept {  
160 - return default_tag;  
161 -}  
162 -  
163 -} // namespace magic_enum::customize  
164 -  
165 -namespace detail {  
166 -  
167 -template <auto V, typename = std::enable_if_t<std::is_enum_v<std::decay_t<decltype(V)>>>>  
168 -using enum_constant = std::integral_constant<std::decay_t<decltype(V)>, V>;  
169 -  
170 -template <typename... T>  
171 -inline constexpr bool always_false_v = false;  
172 -  
173 -template <typename T>  
174 -struct supported  
175 -#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT)  
176 - : std::true_type {};  
177 -#else  
178 - : std::false_type {};  
179 -#endif  
180 -  
181 -template <typename T, typename = void>  
182 -struct has_is_flags : std::false_type {};  
183 -  
184 -template <typename T>  
185 -struct has_is_flags<T, std::void_t<decltype(customize::enum_range<T>::is_flags)>> : std::bool_constant<std::is_same_v<bool, std::decay_t<decltype(customize::enum_range<T>::is_flags)>>> {};  
186 -  
187 -template <typename T, typename = void>  
188 -struct range_min : std::integral_constant<int, MAGIC_ENUM_RANGE_MIN> {};  
189 -  
190 -template <typename T>  
191 -struct range_min<T, std::void_t<decltype(customize::enum_range<T>::min)>> : std::integral_constant<decltype(customize::enum_range<T>::min), customize::enum_range<T>::min> {};  
192 -  
193 -template <typename T, typename = void>  
194 -struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {};  
195 -  
196 -template <typename T>  
197 -struct range_max<T, std::void_t<decltype(customize::enum_range<T>::max)>> : std::integral_constant<decltype(customize::enum_range<T>::max), customize::enum_range<T>::max> {};  
198 -  
199 -template <std::size_t N>  
200 -class static_string {  
201 - public:  
202 - constexpr explicit static_string(string_view str) noexcept : static_string{str, std::make_index_sequence<N>{}} {  
203 - assert(str.size() == N);  
204 - }  
205 -  
206 - constexpr const char* data() const noexcept { return chars_; }  
207 -  
208 - constexpr std::size_t size() const noexcept { return N; }  
209 -  
210 - constexpr operator string_view() const noexcept { return {data(), size()}; }  
211 -  
212 - private:  
213 - template <std::size_t... I>  
214 - constexpr static_string(string_view str, std::index_sequence<I...>) noexcept : chars_{str[I]..., '\0'} {}  
215 -  
216 - char chars_[N + 1];  
217 -};  
218 -  
219 -template <>  
220 -class static_string<0> {  
221 - public:  
222 - constexpr explicit static_string() = default;  
223 -  
224 - constexpr explicit static_string(string_view) noexcept {}  
225 -  
226 - constexpr const char* data() const noexcept { return nullptr; }  
227 -  
228 - constexpr std::size_t size() const noexcept { return 0; }  
229 -  
230 - constexpr operator string_view() const noexcept { return {}; }  
231 -};  
232 -  
233 -constexpr string_view pretty_name(string_view name) noexcept {  
234 - for (std::size_t i = name.size(); i > 0; --i) {  
235 - if (!((name[i - 1] >= '0' && name[i - 1] <= '9') ||  
236 - (name[i - 1] >= 'a' && name[i - 1] <= 'z') ||  
237 - (name[i - 1] >= 'A' && name[i - 1] <= 'Z') ||  
238 -#if defined(MAGIC_ENUM_ENABLE_NONASCII)  
239 - (name[i - 1] & 0x80) ||  
240 -#endif  
241 - (name[i - 1] == '_'))) {  
242 - name.remove_prefix(i);  
243 - break;  
244 - }  
245 - }  
246 -  
247 - if (name.size() > 0 && ((name.front() >= 'a' && name.front() <= 'z') ||  
248 - (name.front() >= 'A' && name.front() <= 'Z') ||  
249 -#if defined(MAGIC_ENUM_ENABLE_NONASCII)  
250 - (name.front() & 0x80) ||  
251 -#endif  
252 - (name.front() == '_'))) {  
253 - return name;  
254 - }  
255 -  
256 - return {}; // Invalid name.  
257 -}  
258 -  
259 -class case_insensitive {  
260 - static constexpr char to_lower(char c) noexcept {  
261 - return (c >= 'A' && c <= 'Z') ? static_cast<char>(c + ('a' - 'A')) : c;  
262 - }  
263 -  
264 - public:  
265 - template <typename L, typename R>  
266 - constexpr auto operator()([[maybe_unused]] L lhs, [[maybe_unused]] R rhs) const noexcept -> std::enable_if_t<std::is_same_v<std::decay_t<L>, char> && std::is_same_v<std::decay_t<R>, char>, bool> {  
267 -#if defined(MAGIC_ENUM_ENABLE_NONASCII)  
268 - static_assert(always_false_v<L, R>, "magic_enum::case_insensitive not supported Non-ASCII feature.");  
269 - return false;  
270 -#else  
271 - return to_lower(lhs) == to_lower(rhs);  
272 -#endif  
273 - }  
274 -};  
275 -  
276 -constexpr std::size_t find(string_view str, char c) noexcept {  
277 -#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)  
278 -// https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc  
279 -// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html  
280 - constexpr bool workaround = true;  
281 -#else  
282 - constexpr bool workaround = false;  
283 -#endif  
284 -  
285 - if constexpr (workaround) {  
286 - for (std::size_t i = 0; i < str.size(); ++i) {  
287 - if (str[i] == c) {  
288 - return i;  
289 - }  
290 - }  
291 -  
292 - return string_view::npos;  
293 - } else {  
294 - return str.find_first_of(c);  
295 - }  
296 -}  
297 -  
298 -template <typename T, std::size_t N, std::size_t... I>  
299 -constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N], std::index_sequence<I...>) noexcept {  
300 - return {{a[I]...}};  
301 -}  
302 -  
303 -template <typename BinaryPredicate>  
304 -constexpr bool is_default_predicate() noexcept {  
305 - return std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<string_view::value_type>> ||  
306 - std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<>>;  
307 -}  
308 -  
309 -template <typename BinaryPredicate>  
310 -constexpr bool is_nothrow_invocable() {  
311 - return is_default_predicate<BinaryPredicate>() ||  
312 - std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>;  
313 -}  
314 -  
315 -template <typename BinaryPredicate>  
316 -constexpr bool cmp_equal(string_view lhs, string_view rhs, [[maybe_unused]] BinaryPredicate&& p) noexcept(is_nothrow_invocable<BinaryPredicate>()) {  
317 -#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)  
318 - // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html  
319 - // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html  
320 - constexpr bool workaround = true;  
321 -#else  
322 - constexpr bool workaround = false;  
323 -#endif  
324 -  
325 - if constexpr (!is_default_predicate<BinaryPredicate>() || workaround) {  
326 - if (lhs.size() != rhs.size()) {  
327 - return false;  
328 - }  
329 -  
330 - const auto size = lhs.size();  
331 - for (std::size_t i = 0; i < size; ++i) {  
332 - if (!p(lhs[i], rhs[i])) {  
333 - return false;  
334 - }  
335 - }  
336 -  
337 - return true;  
338 - } else {  
339 - return lhs == rhs;  
340 - }  
341 -}  
342 -  
343 -template <typename L, typename R>  
344 -constexpr bool cmp_less(L lhs, R rhs) noexcept {  
345 - static_assert(std::is_integral_v<L> && std::is_integral_v<R>, "magic_enum::detail::cmp_less requires integral type.");  
346 -  
347 - if constexpr (std::is_signed_v<L> == std::is_signed_v<R>) {  
348 - // If same signedness (both signed or both unsigned).  
349 - return lhs < rhs;  
350 - } else if constexpr (std::is_same_v<L, bool>) { // bool special case  
351 - return static_cast<R>(lhs) < rhs;  
352 - } else if constexpr (std::is_same_v<R, bool>) { // bool special case  
353 - return lhs < static_cast<L>(rhs);  
354 - } else if constexpr (std::is_signed_v<R>) {  
355 - // If 'right' is negative, then result is 'false', otherwise cast & compare.  
356 - return rhs > 0 && lhs < static_cast<std::make_unsigned_t<R>>(rhs);  
357 - } else {  
358 - // If 'left' is negative, then result is 'true', otherwise cast & compare.  
359 - return lhs < 0 || static_cast<std::make_unsigned_t<L>>(lhs) < rhs;  
360 - }  
361 -}  
362 -  
363 -template <typename I>  
364 -constexpr I log2(I value) noexcept {  
365 - static_assert(std::is_integral_v<I>, "magic_enum::detail::log2 requires integral type.");  
366 -  
367 - if constexpr (std::is_same_v<I, bool>) { // bool special case  
368 - return assert(false), value;  
369 - } else {  
370 - auto ret = I{0};  
371 - for (; value > I{1}; value >>= I{1}, ++ret) {}  
372 -  
373 - return ret;  
374 - }  
375 -}  
376 -  
377 -template <typename T>  
378 -inline constexpr bool is_enum_v = std::is_enum_v<T> && std::is_same_v<T, std::decay_t<T>>;  
379 -  
380 -template <typename E>  
381 -constexpr auto n() noexcept {  
382 - static_assert(is_enum_v<E>, "magic_enum::detail::n requires enum type.");  
383 -  
384 - [[maybe_unused]] constexpr auto custom = customize::enum_type_name<E>();  
385 - static_assert(std::is_same_v<std::decay_t<decltype(custom)>, customize::customize_t>, "magic_enum::customize requires customize_t type.");  
386 - if constexpr (custom.index() == 0) {  
387 - constexpr auto name = std::get<string_view>(custom);  
388 - static_assert(!name.empty(), "magic_enum::customize requires not empty string.");  
389 - return static_string<name.size()>{name};  
390 - } else if constexpr (custom.index() == 1 && supported<E>::value) {  
391 -#if defined(__clang__) || defined(__GNUC__)  
392 - constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2});  
393 -#elif defined(_MSC_VER)  
394 - constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17});  
395 -#else  
396 - constexpr auto name = string_view{};  
397 -#endif  
398 - return static_string<name.size()>{name};  
399 - } else {  
400 - return static_string<0>{}; // Unsupported compiler or Invalid customize.  
401 - }  
402 -}  
403 -  
404 -template <typename E>  
405 -inline constexpr auto type_name_v = n<E>();  
406 -  
407 -template <typename E, E V>  
408 -constexpr auto n() noexcept {  
409 - static_assert(is_enum_v<E>, "magic_enum::detail::n requires enum type.");  
410 -  
411 - [[maybe_unused]] constexpr auto custom = customize::enum_name<E>(V);  
412 - static_assert(std::is_same_v<std::decay_t<decltype(custom)>, customize::customize_t>, "magic_enum::customize requires customize_t type.");  
413 - if constexpr (custom.index() == 0) {  
414 - constexpr auto name = std::get<string_view>(custom);  
415 - static_assert(!name.empty(), "magic_enum::customize requires not empty string.");  
416 - return static_string<name.size()>{name};  
417 - } else if constexpr (custom.index() == 1 && supported<E>::value) {  
418 -#if defined(__clang__) || defined(__GNUC__)  
419 - constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2});  
420 -#elif defined(_MSC_VER)  
421 - constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17});  
422 -#else  
423 - constexpr auto name = string_view{};  
424 -#endif  
425 - return static_string<name.size()>{name};  
426 - } else {  
427 - return static_string<0>{}; // Unsupported compiler or Invalid customize.  
428 - }  
429 -}  
430 -  
431 -template <typename E, E V>  
432 -inline constexpr auto enum_name_v = n<E, V>();  
433 -  
434 -template <typename E, auto V>  
435 -constexpr bool is_valid() noexcept {  
436 - static_assert(is_enum_v<E>, "magic_enum::detail::is_valid requires enum type.");  
437 -  
438 - return n<E, static_cast<E>(V)>().size() != 0;  
439 -}  
440 -  
441 -template <typename E, int O, bool IsFlags, typename U = std::underlying_type_t<E>>  
442 -constexpr E value(std::size_t i) noexcept {  
443 - static_assert(is_enum_v<E>, "magic_enum::detail::value requires enum type.");  
444 -  
445 - if constexpr (std::is_same_v<U, bool>) { // bool special case  
446 - static_assert(O == 0, "magic_enum::detail::value requires valid offset.");  
447 -  
448 - return static_cast<E>(i);  
449 - } else if constexpr (IsFlags) {  
450 - return static_cast<E>(U{1} << static_cast<U>(static_cast<int>(i) + O));  
451 - } else {  
452 - return static_cast<E>(static_cast<int>(i) + O);  
453 - }  
454 -}  
455 -  
456 -template <typename E, bool IsFlags, typename U = std::underlying_type_t<E>>  
457 -constexpr int reflected_min() noexcept {  
458 - static_assert(is_enum_v<E>, "magic_enum::detail::reflected_min requires enum type.");  
459 -  
460 - if constexpr (IsFlags) {  
461 - return 0;  
462 - } else {  
463 - constexpr auto lhs = range_min<E>::value;  
464 - constexpr auto rhs = (std::numeric_limits<U>::min)();  
465 -  
466 - if constexpr (cmp_less(rhs, lhs)) {  
467 - return lhs;  
468 - } else {  
469 - return rhs;  
470 - }  
471 - }  
472 -}  
473 -  
474 -template <typename E, bool IsFlags, typename U = std::underlying_type_t<E>>  
475 -constexpr int reflected_max() noexcept {  
476 - static_assert(is_enum_v<E>, "magic_enum::detail::reflected_max requires enum type.");  
477 -  
478 - if constexpr (IsFlags) {  
479 - return std::numeric_limits<U>::digits - 1;  
480 - } else {  
481 - constexpr auto lhs = range_max<E>::value;  
482 - constexpr auto rhs = (std::numeric_limits<U>::max)();  
483 -  
484 - if constexpr (cmp_less(lhs, rhs)) {  
485 - return lhs;  
486 - } else {  
487 - return rhs;  
488 - }  
489 - }  
490 -}  
491 -  
492 -template <typename E, bool IsFlags>  
493 -inline constexpr auto reflected_min_v = reflected_min<E, IsFlags>();  
494 -  
495 -template <typename E, bool IsFlags>  
496 -inline constexpr auto reflected_max_v = reflected_max<E, IsFlags>();  
497 -  
498 -template <std::size_t N>  
499 -constexpr std::size_t values_count(const bool (&valid)[N]) noexcept {  
500 - auto count = std::size_t{0};  
501 - for (std::size_t i = 0; i < N; ++i) {  
502 - if (valid[i]) {  
503 - ++count;  
504 - }  
505 - }  
506 -  
507 - return count;  
508 -}  
509 -  
510 -template <typename E, bool IsFlags, int Min, std::size_t... I>  
511 -constexpr auto values(std::index_sequence<I...>) noexcept {  
512 - static_assert(is_enum_v<E>, "magic_enum::detail::values requires enum type.");  
513 - constexpr bool valid[sizeof...(I)] = {is_valid<E, value<E, Min, IsFlags>(I)>()...};  
514 - constexpr std::size_t count = values_count(valid);  
515 -  
516 - if constexpr (count > 0) {  
517 - E values[count] = {};  
518 - for (std::size_t i = 0, v = 0; v < count; ++i) {  
519 - if (valid[i]) {  
520 - values[v++] = value<E, Min, IsFlags>(i);  
521 - }  
522 - }  
523 -  
524 - return to_array(values, std::make_index_sequence<count>{});  
525 - } else {  
526 - return std::array<E, 0>{};  
527 - }  
528 -}  
529 -  
530 -template <typename E, bool IsFlags, typename U = std::underlying_type_t<E>>  
531 -constexpr auto values() noexcept {  
532 - static_assert(is_enum_v<E>, "magic_enum::detail::values requires enum type.");  
533 - constexpr auto min = reflected_min_v<E, IsFlags>;  
534 - constexpr auto max = reflected_max_v<E, IsFlags>;  
535 - constexpr auto range_size = max - min + 1;  
536 - static_assert(range_size > 0, "magic_enum::enum_range requires valid size.");  
537 - static_assert(range_size < (std::numeric_limits<std::uint16_t>::max)(), "magic_enum::enum_range requires valid size.");  
538 -  
539 - return values<E, IsFlags, reflected_min_v<E, IsFlags>>(std::make_index_sequence<range_size>{});  
540 -}  
541 -  
542 -template <typename E, typename U = std::underlying_type_t<E>>  
543 -constexpr bool is_flags_enum() noexcept {  
544 - static_assert(is_enum_v<E>, "magic_enum::detail::is_flags_enum requires enum type.");  
545 -  
546 - if constexpr (has_is_flags<E>::value) {  
547 - return customize::enum_range<E>::is_flags;  
548 - } else if constexpr (std::is_same_v<U, bool>) { // bool special case  
549 - return false;  
550 - } else {  
551 -#if defined(MAGIC_ENUM_NO_CHECK_FLAGS)  
552 - return false;  
553 -#else  
554 - constexpr auto flags_values = values<E, true>();  
555 - constexpr auto default_values = values<E, false>();  
556 - if (flags_values.size() == 0 || default_values.size() > flags_values.size()) {  
557 - return false;  
558 - }  
559 - for (std::size_t i = 0; i < default_values.size(); ++i) {  
560 - const auto v = static_cast<U>(default_values[i]);  
561 - if (v != 0 && (v & (v - 1)) != 0) {  
562 - return false;  
563 - }  
564 - }  
565 - return flags_values.size() > 0;  
566 -#endif  
567 - }  
568 -}  
569 -  
570 -template <typename E>  
571 -inline constexpr bool is_flags_v = is_flags_enum<E>();  
572 -  
573 -template <typename E>  
574 -inline constexpr std::array values_v = values<E, is_flags_v<E>>();  
575 -  
576 -template <typename E, typename D = std::decay_t<E>>  
577 -using values_t = decltype((values_v<D>));  
578 -  
579 -template <typename E>  
580 -inline constexpr auto count_v = values_v<E>.size();  
581 -  
582 -template <typename E, typename U = std::underlying_type_t<E>>  
583 -inline constexpr auto min_v = (count_v<E> > 0) ? static_cast<U>(values_v<E>.front()) : U{0};  
584 -  
585 -template <typename E, typename U = std::underlying_type_t<E>>  
586 -inline constexpr auto max_v = (count_v<E> > 0) ? static_cast<U>(values_v<E>.back()) : U{0};  
587 -  
588 -template <typename E, std::size_t... I>  
589 -constexpr auto names(std::index_sequence<I...>) noexcept {  
590 - static_assert(is_enum_v<E>, "magic_enum::detail::names requires enum type.");  
591 -  
592 - return std::array<string_view, sizeof...(I)>{{enum_name_v<E, values_v<E>[I]>...}};  
593 -}  
594 -  
595 -template <typename E>  
596 -inline constexpr std::array names_v = names<E>(std::make_index_sequence<count_v<E>>{});  
597 -  
598 -template <typename E, typename D = std::decay_t<E>>  
599 -using names_t = decltype((names_v<D>));  
600 -  
601 -template <typename E, std::size_t... I>  
602 -constexpr auto entries(std::index_sequence<I...>) noexcept {  
603 - static_assert(is_enum_v<E>, "magic_enum::detail::entries requires enum type.");  
604 -  
605 - return std::array<std::pair<E, string_view>, sizeof...(I)>{{{values_v<E>[I], enum_name_v<E, values_v<E>[I]>}...}};  
606 -}  
607 -  
608 -template <typename E>  
609 -inline constexpr std::array entries_v = entries<E>(std::make_index_sequence<count_v<E>>{});  
610 -  
611 -template <typename E, typename D = std::decay_t<E>>  
612 -using entries_t = decltype((entries_v<D>));  
613 -  
614 -template <typename E, typename U = std::underlying_type_t<E>>  
615 -constexpr bool is_sparse() noexcept {  
616 - static_assert(is_enum_v<E>, "magic_enum::detail::is_sparse requires enum type.");  
617 -  
618 - if constexpr (count_v<E> == 0) {  
619 - return false;  
620 - } else if constexpr (std::is_same_v<U, bool>) { // bool special case  
621 - return false;  
622 - } else {  
623 - constexpr auto max = is_flags_v<E> ? log2(max_v<E>) : max_v<E>;  
624 - constexpr auto min = is_flags_v<E> ? log2(min_v<E>) : min_v<E>;  
625 - constexpr auto range_size = max - min + 1;  
626 -  
627 - return range_size != count_v<E>;  
628 - }  
629 -}  
630 -  
631 -template <typename E>  
632 -inline constexpr bool is_sparse_v = is_sparse<E>();  
633 -  
634 -template <typename E, typename U = std::underlying_type_t<E>>  
635 -constexpr U values_ors() noexcept {  
636 - static_assert(is_enum_v<E>, "magic_enum::detail::values_ors requires enum type.");  
637 -  
638 - auto ors = U{0};  
639 - for (std::size_t i = 0; i < count_v<E>; ++i) {  
640 - ors |= static_cast<U>(values_v<E>[i]);  
641 - }  
642 -  
643 - return ors;  
644 -}  
645 -  
646 -template <bool, typename R>  
647 -struct enable_if_enum {};  
648 -  
649 -template <typename R>  
650 -struct enable_if_enum<true, R> {  
651 - using type = R;  
652 - static_assert(supported<R>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");  
653 -};  
654 -  
655 -template <typename T, typename R, typename BinaryPredicate = std::equal_to<>>  
656 -using enable_if_t = typename enable_if_enum<std::is_enum_v<std::decay_t<T>> && std::is_invocable_r_v<bool, BinaryPredicate, char, char>, R>::type;  
657 -  
658 -template <typename T, typename Enable = std::enable_if_t<std::is_enum_v<std::decay_t<T>>>>  
659 -using enum_concept = T;  
660 -  
661 -template <typename T, bool = std::is_enum_v<T>>  
662 -struct is_scoped_enum : std::false_type {};  
663 -  
664 -template <typename T>  
665 -struct is_scoped_enum<T, true> : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};  
666 -  
667 -template <typename T, bool = std::is_enum_v<T>>  
668 -struct is_unscoped_enum : std::false_type {};  
669 -  
670 -template <typename T>  
671 -struct is_unscoped_enum<T, true> : std::bool_constant<std::is_convertible_v<T, std::underlying_type_t<T>>> {};  
672 -  
673 -template <typename T, bool = std::is_enum_v<std::decay_t<T>>>  
674 -struct underlying_type {};  
675 -  
676 -template <typename T>  
677 -struct underlying_type<T, true> : std::underlying_type<std::decay_t<T>> {};  
678 -  
679 -template <typename Value, typename = void>  
680 -struct constexpr_hash_t;  
681 -  
682 -template <typename Value>  
683 -struct constexpr_hash_t<Value, std::enable_if_t<is_enum_v<Value>>> {  
684 - constexpr auto operator()(Value value) const noexcept {  
685 - using U = typename underlying_type<Value>::type;  
686 - if constexpr (std::is_same_v<U, bool>) { // bool special case  
687 - return static_cast<std::size_t>(value);  
688 - } else {  
689 - return static_cast<U>(value);  
690 - }  
691 - }  
692 - using secondary_hash = constexpr_hash_t;  
693 -};  
694 -  
695 -template <typename Value>  
696 -struct constexpr_hash_t<Value, std::enable_if_t<std::is_same_v<Value, string_view>>> {  
697 - static constexpr std::uint32_t crc_table[256] {  
698 - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,  
699 - 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,  
700 - 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,  
701 - 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,  
702 - 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,  
703 - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,  
704 - 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,  
705 - 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,  
706 - 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,  
707 - 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,  
708 - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,  
709 - 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,  
710 - 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,  
711 - 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,  
712 - 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,  
713 - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,  
714 - 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,  
715 - 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,  
716 - 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,  
717 - 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,  
718 - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,  
719 - 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,  
720 - 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,  
721 - 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,  
722 - 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,  
723 - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,  
724 - 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,  
725 - 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,  
726 - 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,  
727 - 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,  
728 - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,  
729 - 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL  
730 - };  
731 - constexpr std::uint32_t operator()(string_view value) const noexcept {  
732 - auto crc = static_cast<std::uint32_t>(0xffffffffL);  
733 - for (const auto c : value) {  
734 - crc = (crc >> 8) ^ crc_table[(crc ^ static_cast<std::uint32_t>(c)) & 0xff];  
735 - }  
736 - return crc ^ 0xffffffffL;  
737 - }  
738 -  
739 - struct secondary_hash {  
740 - constexpr std::uint32_t operator()(string_view value) const noexcept {  
741 - auto acc = static_cast<std::uint64_t>(2166136261ULL);  
742 - for (const auto c : value) {  
743 - acc = ((acc ^ static_cast<std::uint64_t>(c)) * static_cast<std::uint64_t>(16777619ULL)) & (std::numeric_limits<std::uint32_t>::max)();  
744 - }  
745 - return static_cast<std::uint32_t>(acc);  
746 - }  
747 - };  
748 -};  
749 -  
750 -template <typename Hash>  
751 -constexpr static Hash hash_v{};  
752 -  
753 -template <auto* GlobValues, typename Hash>  
754 -constexpr auto calculate_cases(std::size_t Page) noexcept {  
755 - constexpr std::array values = *GlobValues;  
756 - constexpr std::size_t size = values.size();  
757 -  
758 - using switch_t = std::invoke_result_t<Hash, typename decltype(values)::value_type>;  
759 - static_assert(std::is_integral_v<switch_t> && !std::is_same_v<switch_t, bool>);  
760 - const std::size_t values_to = (std::min)(static_cast<std::size_t>(256), size - Page);  
761 -  
762 - std::array<switch_t, 256> result{};  
763 - auto fill = result.begin();  
764 - {  
765 - auto first = values.begin() + static_cast<std::ptrdiff_t>(Page);  
766 - auto last = values.begin() + static_cast<std::ptrdiff_t>(Page + values_to);  
767 - while (first != last) {  
768 - *fill++ = hash_v<Hash>(*first++);  
769 - }  
770 - }  
771 -  
772 - // dead cases, try to avoid case collisions  
773 - for (switch_t last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits<switch_t>::max)(); *fill++ = ++last_value) {  
774 - }  
775 -  
776 - {  
777 - auto it = result.begin();  
778 - auto last_value = (std::numeric_limits<switch_t>::min)();  
779 - for (; fill != result.end(); *fill++ = last_value++) {  
780 - while (last_value == *it) {  
781 - ++last_value, ++it;  
782 - }  
783 - }  
784 - }  
785 -  
786 - return result;  
787 -}  
788 -  
789 -template <typename R, typename F, typename... Args>  
790 -constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>) {  
791 - if constexpr (std::is_void_v<R>) {  
792 - std::forward<F>(f)(std::forward<Args>(args)...);  
793 - } else {  
794 - return static_cast<R>(std::forward<F>(f)(std::forward<Args>(args)...));  
795 - }  
796 -}  
797 -  
798 -enum class case_call_t {  
799 - index, value  
800 -};  
801 -  
802 -template <typename T = void>  
803 -inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v<T>) { return T{}; };  
804 -  
805 -template <>  
806 -inline constexpr auto default_result_type_lambda<void> = []() noexcept {};  
807 -  
808 -template <auto* Arr, typename Hash>  
809 -constexpr bool no_duplicate() noexcept {  
810 - using value_t = std::decay_t<decltype((*Arr)[0])>;  
811 - using hash_value_t = std::invoke_result_t<Hash, value_t>;  
812 - std::array<hash_value_t, Arr->size()> hashes{};  
813 - std::size_t size = 0;  
814 - for (auto elem : *Arr) {  
815 - hashes[size] = hash_v<Hash>(elem);  
816 - for (auto i = size++; i > 0; --i) {  
817 - if (hashes[i] < hashes[i - 1]) {  
818 - auto tmp = hashes[i];  
819 - hashes[i] = hashes[i - 1];  
820 - hashes[i - 1] = tmp;  
821 - } else if (hashes[i] == hashes[i - 1]) {  
822 - return false;  
823 - } else {  
824 - break;  
825 - }  
826 - }  
827 - }  
828 - return true;  
829 -}  
830 -  
831 -#define MAGIC_ENUM_FOR_EACH_256(T) T(0)T(1)T(2)T(3)T(4)T(5)T(6)T(7)T(8)T(9)T(10)T(11)T(12)T(13)T(14)T(15)T(16)T(17)T(18)T(19)T(20)T(21)T(22)T(23)T(24)T(25)T(26)T(27)T(28)T(29)T(30)T(31) \  
832 - T(32)T(33)T(34)T(35)T(36)T(37)T(38)T(39)T(40)T(41)T(42)T(43)T(44)T(45)T(46)T(47)T(48)T(49)T(50)T(51)T(52)T(53)T(54)T(55)T(56)T(57)T(58)T(59)T(60)T(61)T(62)T(63) \  
833 - T(64)T(65)T(66)T(67)T(68)T(69)T(70)T(71)T(72)T(73)T(74)T(75)T(76)T(77)T(78)T(79)T(80)T(81)T(82)T(83)T(84)T(85)T(86)T(87)T(88)T(89)T(90)T(91)T(92)T(93)T(94)T(95) \  
834 - T(96)T(97)T(98)T(99)T(100)T(101)T(102)T(103)T(104)T(105)T(106)T(107)T(108)T(109)T(110)T(111)T(112)T(113)T(114)T(115)T(116)T(117)T(118)T(119)T(120)T(121)T(122)T(123)T(124)T(125)T(126)T(127) \  
835 - T(128)T(129)T(130)T(131)T(132)T(133)T(134)T(135)T(136)T(137)T(138)T(139)T(140)T(141)T(142)T(143)T(144)T(145)T(146)T(147)T(148)T(149)T(150)T(151)T(152)T(153)T(154)T(155)T(156)T(157)T(158)T(159) \  
836 - T(160)T(161)T(162)T(163)T(164)T(165)T(166)T(167)T(168)T(169)T(170)T(171)T(172)T(173)T(174)T(175)T(176)T(177)T(178)T(179)T(180)T(181)T(182)T(183)T(184)T(185)T(186)T(187)T(188)T(189)T(190)T(191) \  
837 - T(192)T(193)T(194)T(195)T(196)T(197)T(198)T(199)T(200)T(201)T(202)T(203)T(204)T(205)T(206)T(207)T(208)T(209)T(210)T(211)T(212)T(213)T(214)T(215)T(216)T(217)T(218)T(219)T(220)T(221)T(222)T(223) \  
838 - T(224)T(225)T(226)T(227)T(228)T(229)T(230)T(231)T(232)T(233)T(234)T(235)T(236)T(237)T(238)T(239)T(240)T(241)T(242)T(243)T(244)T(245)T(246)T(247)T(248)T(249)T(250)T(251)T(252)T(253)T(254)T(255)  
839 -  
840 -#define MAGIC_ENUM_CASE(val) \  
841 - case cases[val]: \  
842 - if constexpr ((val) + Page < size) { \  
843 - if (!pred(values[val + Page], searched)) { \  
844 - break; \  
845 - } \  
846 - if constexpr (CallValue == case_call_t::index) { \  
847 - if constexpr (std::is_invocable_r_v<result_t, Lambda, std::integral_constant<std::size_t, val + Page>>) { \  
848 - return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), std::integral_constant<std::size_t, val + Page>{}); \  
849 - } else if constexpr (std::is_invocable_v<Lambda, std::integral_constant<std::size_t, val + Page>>) { \  
850 - assert(false && "magic_enum::detail::constexpr_switch wrong result type."); \  
851 - } \  
852 - } else if constexpr (CallValue == case_call_t::value) { \  
853 - if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \  
854 - return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), enum_constant<values[val + Page]>{}); \  
855 - } else if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \  
856 - assert(false && "magic_enum::detail::constexpr_switch wrong result type."); \  
857 - } \  
858 - } \  
859 - break; \  
860 - } else [[fallthrough]];  
861 -  
862 -template <auto* GlobValues,  
863 - case_call_t CallValue,  
864 - std::size_t Page = 0,  
865 - typename Hash = constexpr_hash_t<typename std::decay_t<decltype(*GlobValues)>::value_type>,  
866 - typename Lambda, typename ResultGetterType = decltype(default_result_type_lambda<>),  
867 - typename BinaryPredicate = std::equal_to<>>  
868 -constexpr std::invoke_result_t<ResultGetterType> constexpr_switch(  
869 - Lambda&& lambda,  
870 - typename std::decay_t<decltype(*GlobValues)>::value_type searched,  
871 - ResultGetterType&& def = default_result_type_lambda<>,  
872 - BinaryPredicate&& pred = {}) {  
873 - using result_t = std::invoke_result_t<ResultGetterType>;  
874 - using hash_t = std::conditional_t<no_duplicate<GlobValues, Hash>(), Hash, typename Hash::secondary_hash>;  
875 - constexpr std::array values = *GlobValues;  
876 - constexpr std::size_t size = values.size();  
877 - constexpr std::array cases = calculate_cases<GlobValues, hash_t>(Page);  
878 -  
879 - switch (hash_v<hash_t>(searched)) {  
880 - MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_CASE)  
881 - default:  
882 - if constexpr (size > 256 + Page) {  
883 - return constexpr_switch<GlobValues, CallValue, Page + 256, Hash>(std::forward<Lambda>(lambda), searched, std::forward<ResultGetterType>(def));  
884 - }  
885 - break;  
886 - }  
887 - return def();  
888 -}  
889 -  
890 -#undef MAGIC_ENUM_FOR_EACH_256  
891 -#undef MAGIC_ENUM_CASE  
892 -  
893 -template <typename E, typename Lambda, std::size_t... I>  
894 -constexpr auto for_each(Lambda&& lambda, std::index_sequence<I...>) {  
895 - static_assert(is_enum_v<E>, "magic_enum::detail::for_each requires enum type.");  
896 - constexpr bool has_void_return = (std::is_void_v<std::invoke_result_t<Lambda, enum_constant<values_v<E>[I]>>> || ...);  
897 - constexpr bool all_same_return = (std::is_same_v<std::invoke_result_t<Lambda, enum_constant<values_v<E>[0]>>, std::invoke_result_t<Lambda, enum_constant<values_v<E>[I]>>> && ...);  
898 -  
899 - if constexpr (has_void_return) {  
900 - (lambda(enum_constant<values_v<E>[I]>{}), ...);  
901 - } else if constexpr (all_same_return) {  
902 - return std::array{lambda(enum_constant<values_v<E>[I]>{})...};  
903 - } else {  
904 - return std::tuple{lambda(enum_constant<values_v<E>[I]>{})...};  
905 - }  
906 -}  
907 -  
908 -} // namespace magic_enum::detail  
909 -  
910 -// Checks is magic_enum supported compiler.  
911 -inline constexpr bool is_magic_enum_supported = detail::supported<void>::value;  
912 -  
913 -template <typename T>  
914 -using Enum = detail::enum_concept<T>;  
915 -  
916 -// Checks whether T is an Unscoped enumeration type.  
917 -// Provides the member constant value which is equal to true, if T is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration) type. Otherwise, value is equal to false.  
918 -template <typename T>  
919 -struct is_unscoped_enum : detail::is_unscoped_enum<T> {};  
920 -  
921 -template <typename T>  
922 -inline constexpr bool is_unscoped_enum_v = is_unscoped_enum<T>::value;  
923 -  
924 -// Checks whether T is an Scoped enumeration type.  
925 -// Provides the member constant value which is equal to true, if T is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations) type. Otherwise, value is equal to false.  
926 -template <typename T>  
927 -struct is_scoped_enum : detail::is_scoped_enum<T> {};  
928 -  
929 -template <typename T>  
930 -inline constexpr bool is_scoped_enum_v = is_scoped_enum<T>::value;  
931 -  
932 -// If T is a complete enumeration type, provides a member typedef type that names the underlying type of T.  
933 -// Otherwise, if T is not an enumeration type, there is no member type. Otherwise (T is an incomplete enumeration type), the program is ill-formed.  
934 -template <typename T>  
935 -struct underlying_type : detail::underlying_type<T> {};  
936 -  
937 -template <typename T>  
938 -using underlying_type_t = typename underlying_type<T>::type;  
939 -  
940 -template <auto V>  
941 -using enum_constant = detail::enum_constant<V>;  
942 -  
943 -// Returns type name of enum.  
944 -template <typename E>  
945 -[[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_t<E, string_view> {  
946 - constexpr string_view name = detail::type_name_v<std::decay_t<E>>;  
947 - static_assert(!name.empty(), "magic_enum::enum_type_name enum type does not have a name.");  
948 -  
949 - return name;  
950 -}  
951 -  
952 -// Returns number of enum values.  
953 -template <typename E>  
954 -[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_t<E, std::size_t> {  
955 - return detail::count_v<std::decay_t<E>>;  
956 -}  
957 -  
958 -// Returns enum value at specified index.  
959 -// No bounds checking is performed: the behavior is undefined if index >= number of enum values.  
960 -template <typename E>  
961 -[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {  
962 - using D = std::decay_t<E>;  
963 -  
964 - if constexpr (detail::is_sparse_v<D>) {  
965 - return assert((index < detail::count_v<D>)), detail::values_v<D>[index];  
966 - } else {  
967 - constexpr bool is_flag = detail::is_flags_v<D>;  
968 - constexpr auto min = is_flag ? detail::log2(detail::min_v<D>) : detail::min_v<D>;  
969 -  
970 - return assert((index < detail::count_v<D>)), detail::value<D, min, is_flag>(index);  
971 - }  
972 -}  
973 -  
974 -// Returns enum value at specified index.  
975 -template <typename E, std::size_t I>  
976 -[[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t<E, std::decay_t<E>> {  
977 - using D = std::decay_t<E>;  
978 - static_assert(I < detail::count_v<D>, "magic_enum::enum_value out of range.");  
979 -  
980 - return enum_value<D>(I);  
981 -}  
982 -  
983 -// Returns std::array with enum values, sorted by enum value.  
984 -template <typename E>  
985 -[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t<E, detail::values_t<E>> {  
986 - return detail::values_v<std::decay_t<E>>;  
987 -}  
988 -  
989 -// Returns integer value from enum value.  
990 -template <typename E>  
991 -[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_t<E, underlying_type_t<E>> {  
992 - return static_cast<underlying_type_t<E>>(value);  
993 -}  
994 -  
995 -// Returns underlying value from enum value.  
996 -template <typename E>  
997 -[[nodiscard]] constexpr auto enum_underlying(E value) noexcept -> detail::enable_if_t<E, underlying_type_t<E>> {  
998 - return static_cast<underlying_type_t<E>>(value);  
999 -}  
1000 -  
1001 -// Obtains index in enum values from enum value.  
1002 -// Returns optional with index.  
1003 -template <typename E>  
1004 -[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {  
1005 - using D = std::decay_t<E>;  
1006 - using U = underlying_type_t<D>;  
1007 -  
1008 - if constexpr (detail::count_v<D> == 0) {  
1009 - return {}; // Empty enum.  
1010 - } else if constexpr (detail::is_sparse_v<D> || detail::is_flags_v<D>) {  
1011 - return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::index>(  
1012 - [](std::size_t i) { return optional<std::size_t>{i}; },  
1013 - value,  
1014 - detail::default_result_type_lambda<optional<std::size_t>>);  
1015 - } else {  
1016 - const auto v = static_cast<U>(value);  
1017 - if (v >= detail::min_v<D> && v <= detail::max_v<D>) {  
1018 - return static_cast<std::size_t>(v - detail::min_v<D>);  
1019 - }  
1020 - return {}; // Invalid value or out of range.  
1021 - }  
1022 -}  
1023 -  
1024 -// Obtains index in enum values from static storage enum variable.  
1025 -template <auto V>  
1026 -[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t<decltype(V), std::size_t> {  
1027 - constexpr auto index = enum_index<std::decay_t<decltype(V)>>(V);  
1028 - static_assert(index, "magic_enum::enum_index enum value does not have a index.");  
1029 -  
1030 - return *index;  
1031 -}  
1032 -  
1033 -// Returns name from static storage enum variable.  
1034 -// This version is much lighter on the compile times and is not restricted to the enum_range limitation.  
1035 -template <auto V>  
1036 -[[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_t<decltype(V), string_view> {  
1037 - constexpr string_view name = detail::enum_name_v<std::decay_t<decltype(V)>, V>;  
1038 - static_assert(!name.empty(), "magic_enum::enum_name enum value does not have a name.");  
1039 -  
1040 - return name;  
1041 -}  
1042 -  
1043 -// Returns name from enum value.  
1044 -// If enum value does not have name or value out of range, returns empty string.  
1045 -template <typename E>  
1046 -[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t<E, string_view> {  
1047 - using D = std::decay_t<E>;  
1048 -  
1049 - if (const auto i = enum_index<D>(value)) {  
1050 - return detail::names_v<D>[*i];  
1051 - }  
1052 - return {};  
1053 -}  
1054 -  
1055 -// Returns name from enum-flags value.  
1056 -// If enum-flags value does not have name or value out of range, returns empty string.  
1057 -template <typename E>  
1058 -[[nodiscard]] auto enum_flags_name(E value) -> detail::enable_if_t<E, string> {  
1059 - using D = std::decay_t<E>;  
1060 - using U = underlying_type_t<D>;  
1061 -  
1062 - if constexpr (detail::is_flags_v<D>) {  
1063 - string name;  
1064 - auto check_value = U{0};  
1065 - for (std::size_t i = 0; i < detail::count_v<D>; ++i) {  
1066 - if (const auto v = static_cast<U>(enum_value<D>(i)); (static_cast<U>(value) & v) != 0) {  
1067 - check_value |= v;  
1068 - const auto n = detail::names_v<D>[i];  
1069 - if (!name.empty()) {  
1070 - name.append(1, '|');  
1071 - }  
1072 - name.append(n.data(), n.size());  
1073 - }  
1074 - }  
1075 -  
1076 - if (check_value != 0 && check_value == static_cast<U>(value)) {  
1077 - return name;  
1078 - }  
1079 -  
1080 - return {}; // Invalid value or out of range.  
1081 - } else {  
1082 - return string{enum_name<D>(value)};  
1083 - }  
1084 -}  
1085 -  
1086 -// Returns std::array with names, sorted by enum value.  
1087 -template <typename E>  
1088 -[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t<E, detail::names_t<E>> {  
1089 - return detail::names_v<std::decay_t<E>>;  
1090 -}  
1091 -  
1092 -// Returns std::array with pairs (value, name), sorted by enum value.  
1093 -template <typename E>  
1094 -[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t<E, detail::entries_t<E>> {  
1095 - return detail::entries_v<std::decay_t<E>>;  
1096 -}  
1097 -  
1098 -// Allows you to write magic_enum::enum_cast<foo>("bar", magic_enum::case_insensitive);  
1099 -inline constexpr auto case_insensitive = detail::case_insensitive{};  
1100 -  
1101 -// Obtains enum value from integer value.  
1102 -// Returns optional with enum value.  
1103 -template <typename E>  
1104 -[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {  
1105 - using D = std::decay_t<E>;  
1106 - using U = underlying_type_t<D>;  
1107 -  
1108 - if constexpr (detail::count_v<D> == 0) {  
1109 - return {}; // Empty enum.  
1110 - } else if constexpr (detail::is_sparse_v<D>) {  
1111 - if constexpr (detail::is_flags_v<D>) {  
1112 - constexpr auto count = detail::count_v<D>;  
1113 - auto check_value = U{0};  
1114 - for (std::size_t i = 0; i < count; ++i) {  
1115 - if (const auto v = static_cast<U>(enum_value<D>(i)); (value & v) != 0) {  
1116 - check_value |= v;  
1117 - }  
1118 - }  
1119 -  
1120 - if (check_value != 0 && check_value == value) {  
1121 - return static_cast<D>(value);  
1122 - }  
1123 - return {}; // Invalid value or out of range.  
1124 - } else {  
1125 - return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::value>(  
1126 - [](D v) { return optional<D>{v}; },  
1127 - static_cast<D>(value),  
1128 - detail::default_result_type_lambda<optional<D>>);  
1129 - }  
1130 - } else {  
1131 - constexpr auto min = detail::min_v<D>;  
1132 - constexpr auto max = detail::is_flags_v<D> ? detail::values_ors<D>() : detail::max_v<D>;  
1133 -  
1134 - if (value >= min && value <= max) {  
1135 - return static_cast<D>(value);  
1136 - }  
1137 - return {}; // Invalid value or out of range.  
1138 - }  
1139 -}  
1140 -  
1141 -// Obtains enum value from name.  
1142 -// Returns optional with enum value.  
1143 -template <typename E, typename BinaryPredicate = std::equal_to<>>  
1144 -[[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate&& p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {  
1145 - static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_cast requires bool(char, char) invocable predicate.");  
1146 - using D = std::decay_t<E>;  
1147 - using U = underlying_type_t<D>;  
1148 -  
1149 - if constexpr (detail::count_v<D> == 0) {  
1150 - return {}; // Empty enum.  
1151 - } else if constexpr (detail::is_flags_v<D>) {  
1152 - auto result = U{0};  
1153 - while (!value.empty()) {  
1154 - const auto d = detail::find(value, '|');  
1155 - const auto s = (d == string_view::npos) ? value : value.substr(0, d);  
1156 - auto f = U{0};  
1157 - for (std::size_t i = 0; i < detail::count_v<D>; ++i) {  
1158 - if (detail::cmp_equal(s, detail::names_v<D>[i], p)) {  
1159 - f = static_cast<U>(enum_value<D>(i));  
1160 - result |= f;  
1161 - break;  
1162 - }  
1163 - }  
1164 - if (f == U{0}) {  
1165 - return {}; // Invalid value or out of range.  
1166 - }  
1167 - value.remove_prefix((d == string_view::npos) ? value.size() : d + 1);  
1168 - }  
1169 -  
1170 - if (result != U{0}) {  
1171 - return static_cast<D>(result);  
1172 - }  
1173 - return {}; // Invalid value or out of range.  
1174 - } else if constexpr (detail::count_v<D> > 0) {  
1175 - if constexpr (detail::is_default_predicate<BinaryPredicate>()) {  
1176 - return detail::constexpr_switch<&detail::names_v<D>, detail::case_call_t::index>(  
1177 - [](std::size_t i) { return optional<D>{detail::values_v<D>[i]}; },  
1178 - value,  
1179 - detail::default_result_type_lambda<optional<D>>,  
1180 - [&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); });  
1181 - } else {  
1182 - for (std::size_t i = 0; i < detail::count_v<D>; ++i) {  
1183 - if (detail::cmp_equal(value, detail::names_v<D>[i], p)) {  
1184 - return enum_value<D>(i);  
1185 - }  
1186 - }  
1187 - return {}; // Invalid value or out of range.  
1188 - }  
1189 - }  
1190 -}  
1191 -  
1192 -// Checks whether enum contains enumerator with such enum value.  
1193 -template <typename E>  
1194 -[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t<E, bool> {  
1195 - using D = std::decay_t<E>;  
1196 - using U = underlying_type_t<D>;  
1197 -  
1198 - return static_cast<bool>(enum_cast<D>(static_cast<U>(value)));  
1199 -}  
1200 -  
1201 -// Checks whether enum contains enumerator with such integer value.  
1202 -template <typename E>  
1203 -[[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {  
1204 - using D = std::decay_t<E>;  
1205 -  
1206 - return static_cast<bool>(enum_cast<D>(value));  
1207 -}  
1208 -  
1209 -// Checks whether enum contains enumerator with such name.  
1210 -template <typename E, typename BinaryPredicate = std::equal_to<>>  
1211 -[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate&& p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, bool, BinaryPredicate> {  
1212 - static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_contains requires bool(char, char) invocable predicate.");  
1213 - using D = std::decay_t<E>;  
1214 -  
1215 - return static_cast<bool>(enum_cast<D>(value, std::forward<BinaryPredicate>(p)));  
1216 -}  
1217 -  
1218 -template <typename Result = void, typename E, typename Lambda>  
1219 -constexpr auto enum_switch(Lambda&& lambda, E value) -> detail::enable_if_t<E, Result> {  
1220 - using D = std::decay_t<E>;  
1221 -  
1222 - return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::value>(  
1223 - std::forward<Lambda>(lambda),  
1224 - value,  
1225 - detail::default_result_type_lambda<Result>);  
1226 -}  
1227 -  
1228 -template <typename Result, typename E, typename Lambda>  
1229 -constexpr auto enum_switch(Lambda&& lambda, E value, Result&& result) -> detail::enable_if_t<E, Result> {  
1230 - using D = std::decay_t<E>;  
1231 -  
1232 - return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::value>(  
1233 - std::forward<Lambda>(lambda),  
1234 - value,  
1235 - [&result] { return std::forward<Result>(result); });  
1236 -}  
1237 -  
1238 -template <typename E, typename Result = void, typename BinaryPredicate = std::equal_to<>, typename Lambda>  
1239 -constexpr auto enum_switch(Lambda&& lambda, string_view name, BinaryPredicate&& p = {}) -> detail::enable_if_t<E, Result, BinaryPredicate> {  
1240 - static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_switch requires bool(char, char) invocable predicate.");  
1241 - using D = std::decay_t<E>;  
1242 -  
1243 - if (const auto v = enum_cast<D>(name, std::forward<BinaryPredicate>(p))) {  
1244 - return enum_switch<Result, D>(std::forward<Lambda>(lambda), *v);  
1245 - }  
1246 - return detail::default_result_type_lambda<Result>();  
1247 -}  
1248 -  
1249 -template <typename E, typename Result, typename BinaryPredicate = std::equal_to<>, typename Lambda>  
1250 -constexpr auto enum_switch(Lambda&& lambda, string_view name, Result&& result, BinaryPredicate&& p = {}) -> detail::enable_if_t<E, Result, BinaryPredicate> {  
1251 - static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_switch requires bool(char, char) invocable predicate.");  
1252 - using D = std::decay_t<E>;  
1253 -  
1254 - if (const auto v = enum_cast<D>(name, std::forward<BinaryPredicate>(p))) {  
1255 - return enum_switch<Result, D>(std::forward<Lambda>(lambda), *v, std::forward<Result>(result));  
1256 - }  
1257 - return std::forward<Result>(result);  
1258 -}  
1259 -  
1260 -template <typename E, typename Result = void, typename Lambda>  
1261 -constexpr auto enum_switch(Lambda&& lambda, underlying_type_t<E> value) -> detail::enable_if_t<E, Result> {  
1262 - using D = std::decay_t<E>;  
1263 -  
1264 - if (const auto v = enum_cast<D>(value)) {  
1265 - return enum_switch<Result, D>(std::forward<Lambda>(lambda), *v);  
1266 - }  
1267 - return detail::default_result_type_lambda<Result>();  
1268 -}  
1269 -  
1270 -template <typename E, typename Result, typename Lambda>  
1271 -constexpr auto enum_switch(Lambda&& lambda, underlying_type_t<E> value, Result&& result) -> detail::enable_if_t<E, Result> {  
1272 - using D = std::decay_t<E>;  
1273 -  
1274 - if (const auto v = enum_cast<D>(value)) {  
1275 - return enum_switch<Result, D>(std::forward<Lambda>(lambda), *v, std::forward<Result>(result));  
1276 - }  
1277 - return std::forward<Result>(result);  
1278 -}  
1279 -  
1280 -template <typename E, typename Lambda>  
1281 -constexpr auto enum_for_each(Lambda&& lambda) {  
1282 - using D = std::decay_t<E>;  
1283 - static_assert(std::is_enum_v<D>, "magic_enum::enum_for_each requires enum type.");  
1284 -  
1285 - return detail::for_each<D>(std::forward<Lambda>(lambda), std::make_index_sequence<detail::count_v<D>>{});  
1286 -}  
1287 -  
1288 -namespace ostream_operators {  
1289 -  
1290 -template <typename Char, typename Traits, typename E, detail::enable_if_t<E, int> = 0>  
1291 -std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, E value) {  
1292 - using D = std::decay_t<E>;  
1293 - using U = underlying_type_t<D>;  
1294 -  
1295 - if constexpr (detail::supported<D>::value) {  
1296 - if (const auto name = enum_flags_name<D>(value); !name.empty()) {  
1297 - for (const auto c : name) {  
1298 - os.put(c);  
1299 - }  
1300 - return os;  
1301 - }  
1302 - }  
1303 - return (os << static_cast<U>(value));  
1304 -}  
1305 -  
1306 -template <typename Char, typename Traits, typename E, detail::enable_if_t<E, int> = 0>  
1307 -std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, optional<E> value) {  
1308 - return value ? (os << *value) : os;  
1309 -}  
1310 -  
1311 -} // namespace magic_enum::ostream_operators  
1312 -  
1313 -namespace istream_operators {  
1314 -  
1315 -template <typename Char, typename Traits, typename E, detail::enable_if_t<E, int> = 0>  
1316 -std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& is, E& value) {  
1317 - using D = std::decay_t<E>;  
1318 -  
1319 - std::basic_string<Char, Traits> s;  
1320 - is >> s;  
1321 - if (const auto v = enum_cast<D>(s)) {  
1322 - value = *v;  
1323 - } else {  
1324 - is.setstate(std::basic_ios<Char>::failbit);  
1325 - }  
1326 - return is;  
1327 -}  
1328 -  
1329 -} // namespace magic_enum::istream_operators  
1330 -  
1331 -namespace iostream_operators {  
1332 -  
1333 -using namespace ostream_operators;  
1334 -using namespace istream_operators;  
1335 -  
1336 -} // namespace magic_enum::iostream_operators  
1337 -  
1338 -namespace bitwise_operators {  
1339 -  
1340 -template <typename E, detail::enable_if_t<E, int> = 0>  
1341 -constexpr E operator~(E rhs) noexcept {  
1342 - return static_cast<E>(~static_cast<underlying_type_t<E>>(rhs));  
1343 -}  
1344 -  
1345 -template <typename E, detail::enable_if_t<E, int> = 0>  
1346 -constexpr E operator|(E lhs, E rhs) noexcept {  
1347 - return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) | static_cast<underlying_type_t<E>>(rhs));  
1348 -}  
1349 -  
1350 -template <typename E, detail::enable_if_t<E, int> = 0>  
1351 -constexpr E operator&(E lhs, E rhs) noexcept {  
1352 - return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) & static_cast<underlying_type_t<E>>(rhs));  
1353 -}  
1354 -  
1355 -template <typename E, detail::enable_if_t<E, int> = 0>  
1356 -constexpr E operator^(E lhs, E rhs) noexcept {  
1357 - return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) ^ static_cast<underlying_type_t<E>>(rhs));  
1358 -}  
1359 -  
1360 -template <typename E, detail::enable_if_t<E, int> = 0>  
1361 -constexpr E& operator|=(E& lhs, E rhs) noexcept {  
1362 - return lhs = (lhs | rhs);  
1363 -}  
1364 -  
1365 -template <typename E, detail::enable_if_t<E, int> = 0>  
1366 -constexpr E& operator&=(E& lhs, E rhs) noexcept {  
1367 - return lhs = (lhs & rhs);  
1368 -}  
1369 -  
1370 -template <typename E, detail::enable_if_t<E, int> = 0>  
1371 -constexpr E& operator^=(E& lhs, E rhs) noexcept {  
1372 - return lhs = (lhs ^ rhs);  
1373 -}  
1374 -  
1375 -} // namespace magic_enum::bitwise_operators  
1376 -  
1377 -} // namespace magic_enum  
1378 -  
1379 -#if defined(__clang__)  
1380 -# pragma clang diagnostic pop  
1381 -#elif defined(__GNUC__)  
1382 -# pragma GCC diagnostic pop  
1383 -#elif defined(_MSC_VER)  
1384 -# pragma warning(pop)  
1385 -#endif  
1386 -  
1387 -#endif // NEARGYE_MAGIC_ENUM_HPP  
vendor/magic_enum/include/magic_enum_format.hpp deleted
1 -// __ __ _ ______ _____  
2 -// | \/ | (_) | ____| / ____|_ _  
3 -// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_  
4 -// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|  
5 -// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|  
6 -// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|  
7 -// __/ | https://github.com/Neargye/magic_enum  
8 -// |___/ version 0.8.1  
9 -//  
10 -// Licensed under the MIT License <http://opensource.org/licenses/MIT>.  
11 -// SPDX-License-Identifier: MIT  
12 -// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.  
13 -//  
14 -// Permission is hereby granted, free of charge, to any person obtaining a copy  
15 -// of this software and associated documentation files (the "Software"), to deal  
16 -// in the Software without restriction, including without limitation the rights  
17 -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
18 -// copies of the Software, and to permit persons to whom the Software is  
19 -// furnished to do so, subject to the following conditions:  
20 -//  
21 -// The above copyright notice and this permission notice shall be included in all  
22 -// copies or substantial portions of the Software.  
23 -//  
24 -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
25 -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
26 -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
27 -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
28 -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
29 -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  
30 -// SOFTWARE.  
31 -  
32 -#ifndef NEARGYE_MAGIC_ENUM_FORMAT_HPP  
33 -#define NEARGYE_MAGIC_ENUM_FORMAT_HPP  
34 -  
35 -#if !defined(__cpp_lib_format)  
36 -# error "Format is not supported"  
37 -#endif  
38 -  
39 -#include "magic_enum.hpp"  
40 -  
41 -#if !defined(MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT)  
42 -# define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT true  
43 -# define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE  
44 -#endif // MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT  
45 -  
46 -namespace magic_enum::customize {  
47 - // customize enum to enable/disable automatic std::format  
48 - template <typename E>  
49 - constexpr bool enum_format_enabled() noexcept {  
50 - return MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT;  
51 - }  
52 -} // magic_enum::customize  
53 -  
54 -#include <format>  
55 -  
56 -template <typename E>  
57 -struct std::formatter<E, std::enable_if_t<std::is_enum_v<E> && magic_enum::customize::enum_format_enabled<E>(), char>> : std::formatter<std::string_view, char> {  
58 - auto format(E e, format_context& ctx) {  
59 - using D = std::decay_t<E>;  
60 - if constexpr (magic_enum::detail::is_flags_v<D>) {  
61 - if (auto name = magic_enum::enum_flags_name<D>(e); !name.empty()) {  
62 - return this->std::formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);  
63 - }  
64 - } else {  
65 - if (auto name = magic_enum::enum_name<D>(e); !name.empty()) {  
66 - return this->std::formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);  
67 - }  
68 - }  
69 - constexpr auto type_name = magic_enum::enum_type_name<E>();  
70 - throw std::format_error("Type of " + std::string{type_name.data(), type_name.size()} + " enum value: " + std::to_string(magic_enum::enum_integer<D>(e)) + " is not exists.");  
71 - }  
72 -};  
73 -  
74 -#if defined(MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE)  
75 -# undef MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT  
76 -# undef MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE  
77 -#endif // MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE  
78 -  
79 -#endif // NEARGYE_MAGIC_ENUM_FORMAT_HPP  
vendor/magic_enum/include/magic_enum_fuse.hpp deleted
1 -// __ __ _ ______ _____  
2 -// | \/ | (_) | ____| / ____|_ _  
3 -// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_  
4 -// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|  
5 -// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|  
6 -// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|  
7 -// __/ | https://github.com/Neargye/magic_enum  
8 -// |___/ version 0.8.1  
9 -//  
10 -// Licensed under the MIT License <http://opensource.org/licenses/MIT>.  
11 -// SPDX-License-Identifier: MIT  
12 -// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.  
13 -//  
14 -// Permission is hereby granted, free of charge, to any person obtaining a copy  
15 -// of this software and associated documentation files (the "Software"), to deal  
16 -// in the Software without restriction, including without limitation the rights  
17 -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
18 -// copies of the Software, and to permit persons to whom the Software is  
19 -// furnished to do so, subject to the following conditions:  
20 -//  
21 -// The above copyright notice and this permission notice shall be included in all  
22 -// copies or substantial portions of the Software.  
23 -//  
24 -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
25 -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
26 -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
27 -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
28 -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
29 -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  
30 -// SOFTWARE.  
31 -  
32 -#ifndef NEARGYE_MAGIC_ENUM_FUSE_HPP  
33 -#define NEARGYE_MAGIC_ENUM_FUSE_HPP  
34 -  
35 -#include "magic_enum.hpp"  
36 -  
37 -namespace magic_enum {  
38 -  
39 -namespace detail {  
40 -  
41 -template <typename E>  
42 -constexpr optional<std::uintmax_t> fuse_one_enum(optional<std::uintmax_t> hash, E value) noexcept {  
43 - if (hash) {  
44 - if (const auto index = enum_index(value)) {  
45 - return (*hash << log2(enum_count<E>() + 1)) | *index;  
46 - }  
47 - }  
48 - return {};  
49 -}  
50 -  
51 -template <typename E>  
52 -constexpr optional<std::uintmax_t> fuse_enum(E value) noexcept {  
53 - return fuse_one_enum(0, value);  
54 -}  
55 -  
56 -template <typename E, typename... Es>  
57 -constexpr optional<std::uintmax_t> fuse_enum(E head, Es... tail) noexcept {  
58 - return fuse_one_enum(fuse_enum(tail...), head);  
59 -}  
60 -  
61 -template <typename... Es>  
62 -constexpr auto typesafe_fuse_enum(Es... values) noexcept {  
63 - enum class enum_fuse_t : std::uintmax_t;  
64 - const auto fuse = fuse_enum(values...);  
65 - if (fuse) {  
66 - return optional<enum_fuse_t>{static_cast<enum_fuse_t>(*fuse)};  
67 - }  
68 - return optional<enum_fuse_t>{};  
69 -}  
70 -  
71 -} // namespace magic_enum::detail  
72 -  
73 -// Returns a bijective mix of several enum values. This can be used to emulate 2D switch/case statements.  
74 -template <typename... Es>  
75 -[[nodiscard]] constexpr auto enum_fuse(Es... values) noexcept {  
76 - static_assert((std::is_enum_v<std::decay_t<Es>> && ...), "magic_enum::enum_fuse requires enum type.");  
77 - static_assert(sizeof...(Es) >= 2, "magic_enum::enum_fuse requires at least 2 values.");  
78 - static_assert((detail::log2(enum_count<std::decay_t<Es>>() + 1) + ...) <= (sizeof(std::uintmax_t) * 8), "magic_enum::enum_fuse does not work for large enums");  
79 -#if defined(MAGIC_ENUM_NO_TYPESAFE_ENUM_FUSE)  
80 - const auto fuse = detail::fuse_enum<std::decay_t<Es>...>(values...);  
81 -#else  
82 - const auto fuse = detail::typesafe_fuse_enum<std::decay_t<Es>...>(values...);  
83 -#endif  
84 - return assert(fuse), fuse;  
85 -}  
86 -  
87 -} // namespace magic_enum  
88 -  
89 -#endif // NEARGYE_MAGIC_ENUM_FUSE_HPP