diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index b6b51cc..0bbd935 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -9,6 +9,14 @@
"problemMatcher": [
"$gcc"
]
+ },
+ {
+ "label": "build Frontend",
+ "type": "shell",
+ "command": "npm run build",
+ "options": {
+ "cwd": "frontend"
+ }
}
]
}
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5b5b63f..221f926 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,11 +33,20 @@ foreach(file IN LISTS TEMPLATE_FILES)
configure_file("${file}" "${CMAKE_BINARY_DIR}/${rel_path}" COPYONLY)
endforeach()
+# warnings to ignore
add_compile_options(-Wno-deprecated-declarations)
add_compile_options(-Wno-deprecated-literal-operator)
# Use Crow from system include (installed via yay -S crow + asio)
-include_directories(/usr/include src src/htmx src/shadowrun src/database src/login)
+include_directories(
+ /usr/include
+ include/libs
+ src
+ src/htmx
+ src/shadowrun
+ src/database
+ src/login
+)
add_executable(${TARGET_NAME}
src/main.cpp
@@ -47,7 +56,6 @@ add_executable(${TARGET_NAME}
src/htmx/HtmxTable.h
src/systemd.cpp
src/systemd.h
- src/json.hpp
src/htmx/HtmxTableRow.cpp
src/htmx/HtmxTableRow.h
src/htmx/HtmxObject.cpp
@@ -56,11 +64,9 @@ add_executable(${TARGET_NAME}
src/htmx_helper.h
src/json_settings.cpp
src/json_settings.h
- src/json.hpp
src/database/database.cpp
src/database/database.hpp
- src/database/sqlite_orm.h
# Shadowrun
src/shadowrun/HtmxShItemList.cpp
diff --git a/frontend/src/lib/ShadowrunCharacter.svelte b/frontend/src/lib/ShadowrunCharacter.svelte
index 61ce0f0..84cdd81 100644
--- a/frontend/src/lib/ShadowrunCharacter.svelte
+++ b/frontend/src/lib/ShadowrunCharacter.svelte
@@ -1,21 +1,37 @@
+
+
Name: {currentCharacter.name}
+
Character Info
-{#each Object.entries(characterInfo) as [key, value], i}
+{#each Object.entries(characterData["Info"]) as [key, value], i}
{/each}
Attributes
-{#each attributes as field, i}
-
+{#each Object.entries(characterData["Attributes"]) as [key, value], i}
+
+
+
+
{/each}
-
+
+
diff --git a/frontend/src/routes/shadowrun/+page.svelte b/frontend/src/routes/shadowrun/+page.svelte
index 4ed86dd..db6e19a 100644
--- a/frontend/src/routes/shadowrun/+page.svelte
+++ b/frontend/src/routes/shadowrun/+page.svelte
@@ -9,6 +9,8 @@
};
let characters: Character[] = [];
+ let currentCharacter: any = null;
+ let currentCharacterData : any = null
let selectedCharId: number | null = null;
let creatingNew = false;
let newCharName = '';
@@ -20,6 +22,12 @@
characters = await res.json();
}
+ async function loadCharacterData(characterId : number) {
+ const res = await fetch(`${API_BASE}/api/shadowrun/characters_data/${characterId}`);
+ if (res.ok)
+ currentCharacterData = await res.json();
+ }
+
onMount(loadCharacters);
async function loadCharacter() {
@@ -28,6 +36,7 @@
const res = await fetch(`${API_BASE}/api/shadowrun/characters/${selectedCharId}`);
if (res.ok) {
const data = await res.json();
+ await loadCharacterData(data.id)
currentCharacter = data;
creatingNew = false;
}
@@ -49,7 +58,6 @@
}
}
- let currentCharacter: any = null;
{#if !currentCharacter}
@@ -76,5 +84,5 @@
{:else}
-
+
{/if}
diff --git a/src/json.hpp b/include/libs/json.hpp
similarity index 100%
rename from src/json.hpp
rename to include/libs/json.hpp
diff --git a/include/libs/magic_enum.hpp b/include/libs/magic_enum.hpp
new file mode 100644
index 0000000..29ad7a0
--- /dev/null
+++ b/include/libs/magic_enum.hpp
@@ -0,0 +1,1564 @@
+// __ __ _ ______ _____
+// | \/ | (_) | ____| / ____|_ _
+// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
+// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
+// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
+// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
+// __/ | https://github.com/Neargye/magic_enum
+// |___/ version 0.9.7
+//
+// Licensed under the MIT License .
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2019 - 2024 Daniil Goncharov .
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+#ifndef NEARGYE_MAGIC_ENUM_HPP
+#define NEARGYE_MAGIC_ENUM_HPP
+
+#define MAGIC_ENUM_VERSION_MAJOR 0
+#define MAGIC_ENUM_VERSION_MINOR 9
+#define MAGIC_ENUM_VERSION_PATCH 7
+
+#ifndef MAGIC_ENUM_USE_STD_MODULE
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+
+#if defined(MAGIC_ENUM_CONFIG_FILE)
+# include MAGIC_ENUM_CONFIG_FILE
+#endif
+
+#ifndef MAGIC_ENUM_USE_STD_MODULE
+#if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)
+# include
+#endif
+#if !defined(MAGIC_ENUM_USING_ALIAS_STRING)
+# include
+#endif
+#if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)
+# include
+#endif
+#endif
+
+#if defined(MAGIC_ENUM_NO_ASSERT)
+# define MAGIC_ENUM_ASSERT(...) static_cast(0)
+#elif !defined(MAGIC_ENUM_ASSERT)
+# include
+# define MAGIC_ENUM_ASSERT(...) assert((__VA_ARGS__))
+#endif
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wunknown-warning-option"
+# pragma clang diagnostic ignored "-Wenum-constexpr-conversion"
+# pragma clang diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast('\0')' for char_type = char (common on Linux).
+#elif defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.
+# pragma GCC diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast('\0')' for char_type = char (common on Linux).
+#elif defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable : 26495) // Variable 'static_str::chars_' is uninitialized.
+# pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value.
+# pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call.
+# pragma warning(disable : 4514) // Unreferenced inline function has been removed.
+#endif
+
+// Checks magic_enum compiler compatibility.
+#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 || defined(__RESHARPER__)
+# undef MAGIC_ENUM_SUPPORTED
+# define MAGIC_ENUM_SUPPORTED 1
+#endif
+
+// Checks magic_enum compiler aliases compatibility.
+#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920
+# undef MAGIC_ENUM_SUPPORTED_ALIASES
+# define MAGIC_ENUM_SUPPORTED_ALIASES 1
+#endif
+
+// Specify the calling convention for compilers that need it in order to get reliable mangled names under different
+// compiler flags. In particular, MSVC allows changing the default calling convention on x86.
+#if defined(__clang__) || defined(__GNUC__)
+#define MAGIC_ENUM_CALLING_CONVENTION
+#elif defined(_MSC_VER)
+#define MAGIC_ENUM_CALLING_CONVENTION __cdecl
+#endif
+
+// Enum value must be greater or equals than MAGIC_ENUM_RANGE_MIN. By default MAGIC_ENUM_RANGE_MIN = -128.
+// If need another min range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN.
+#if !defined(MAGIC_ENUM_RANGE_MIN)
+# define MAGIC_ENUM_RANGE_MIN -128
+#endif
+
+// Enum value must be less or equals than MAGIC_ENUM_RANGE_MAX. By default MAGIC_ENUM_RANGE_MAX = 127.
+// If need another max range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX.
+#if !defined(MAGIC_ENUM_RANGE_MAX)
+# define MAGIC_ENUM_RANGE_MAX 127
+#endif
+
+// Improve ReSharper C++ intellisense performance with builtins, avoiding unnecessary template instantiations.
+#if defined(__RESHARPER__)
+# undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN
+# undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN
+# if __RESHARPER__ >= 20230100
+# define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) __rscpp_enumerator_name(V)
+# define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) __rscpp_type_name()
+# else
+# define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) nullptr
+# define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) nullptr
+# endif
+#endif
+
+namespace magic_enum {
+
+// If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL.
+#if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)
+MAGIC_ENUM_USING_ALIAS_OPTIONAL
+#else
+using std::optional;
+#endif
+
+// If need another string_view type, define the macro MAGIC_ENUM_USING_ALIAS_STRING_VIEW.
+#if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)
+MAGIC_ENUM_USING_ALIAS_STRING_VIEW
+#else
+using std::string_view;
+#endif
+
+// If need another string type, define the macro MAGIC_ENUM_USING_ALIAS_STRING.
+#if defined(MAGIC_ENUM_USING_ALIAS_STRING)
+MAGIC_ENUM_USING_ALIAS_STRING
+#else
+using std::string;
+#endif
+
+using char_type = string_view::value_type;
+static_assert(std::is_same_v, "magic_enum::customize requires same string_view::value_type and string::value_type");
+static_assert([] {
+ if constexpr (std::is_same_v) {
+ constexpr const char c[] = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
+ constexpr const wchar_t wc[] = L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
+ static_assert(std::size(c) == std::size(wc), "magic_enum::customize identifier characters are multichars in wchar_t.");
+
+ for (std::size_t i = 0; i < std::size(c); ++i) {
+ if (c[i] != wc[i]) {
+ return false;
+ }
+ }
+ }
+ return true;
+} (), "magic_enum::customize wchar_t is not compatible with ASCII.");
+
+namespace customize {
+ template
+ struct enum_range;
+}
+
+namespace detail {
+ template
+ constexpr inline std::size_t prefix_length_or_zero = 0;
+
+ template
+ constexpr inline auto prefix_length_or_zero::prefix_length)>> = std::size_t{customize::enum_range::prefix_length};
+}
+
+namespace customize {
+
+template
+struct adl_info_holder {
+ constexpr static int max = Max;
+ constexpr static int min = Min;
+ constexpr static bool is_flags =IsFlags;
+ constexpr static std::size_t prefix_length = PrefixLength;
+
+ template
+ constexpr static adl_info_holder minmax() { return {}; }
+
+ template
+ constexpr static adl_info_holder flag() { return {}; }
+
+ template
+ constexpr static adl_info_holder prefix() { return {}; }
+};
+
+constexpr adl_info_holder<> adl_info() { return {}; }
+
+// 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 = 127.
+// If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX.
+// If need another range for specific enum type, add specialization enum_range for necessary enum type.
+template
+struct enum_range {
+ static constexpr int min = MAGIC_ENUM_RANGE_MIN;
+ static constexpr int max = MAGIC_ENUM_RANGE_MAX;
+};
+
+template
+struct enum_range : decltype(magic_enum_define_range_adl(E{})) {};
+
+static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN.");
+
+namespace detail {
+
+enum class customize_tag {
+ default_tag,
+ invalid_tag,
+ custom_tag
+};
+
+} // namespace magic_enum::customize::detail
+
+class customize_t : public std::pair {
+ public:
+ constexpr customize_t(string_view srt) : std::pair{detail::customize_tag::custom_tag, srt} {}
+ constexpr customize_t(const char_type* srt) : customize_t{string_view{srt}} {}
+ constexpr customize_t(detail::customize_tag tag) : std::pair{tag, string_view{}} {
+ MAGIC_ENUM_ASSERT(tag != detail::customize_tag::custom_tag);
+ }
+};
+
+// Default customize.
+inline constexpr auto default_tag = customize_t{detail::customize_tag::default_tag};
+// Invalid customize.
+inline constexpr auto invalid_tag = customize_t{detail::customize_tag::invalid_tag};
+
+// If need custom names for enum, add specialization enum_name for necessary enum type.
+template
+constexpr customize_t enum_name(E) noexcept {
+ return default_tag;
+}
+
+// If need custom type name for enum, add specialization enum_type_name for necessary enum type.
+template
+constexpr customize_t enum_type_name() noexcept {
+ return default_tag;
+}
+
+} // namespace magic_enum::customize
+
+namespace detail {
+
+template
+struct supported
+#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT)
+ : std::true_type {};
+#else
+ : std::false_type {};
+#endif
+
+template , std::enable_if_t, int> = 0>
+using enum_constant = std::integral_constant;
+
+template
+inline constexpr bool always_false_v = false;
+
+template
+struct has_is_flags : std::false_type {};
+
+template
+struct has_is_flags::is_flags)>> : std::bool_constant::is_flags)>>> {};
+
+template
+struct range_min : std::integral_constant {};
+
+template
+struct range_min::min)>> : std::integral_constant::min), customize::enum_range::min> {};
+
+template
+struct range_max : std::integral_constant {};
+
+template
+struct range_max::max)>> : std::integral_constant::max), customize::enum_range::max> {};
+
+struct str_view {
+ const char* str_ = nullptr;
+ std::size_t size_ = 0;
+};
+
+template
+class static_str {
+ public:
+ constexpr explicit static_str(str_view str) noexcept : static_str{str.str_, std::make_integer_sequence{}} {
+ MAGIC_ENUM_ASSERT(str.size_ == N);
+ }
+
+ constexpr explicit static_str(const char* const str) noexcept : static_str{ str, std::make_integer_sequence{} } {
+ }
+
+ constexpr explicit static_str(string_view str) noexcept : static_str{str.data(), std::make_integer_sequence{}} {
+ MAGIC_ENUM_ASSERT(str.size() == N);
+ }
+
+ constexpr const char_type* data() const noexcept { return chars_; }
+
+ constexpr std::uint16_t size() const noexcept { return N; }
+
+ constexpr string_view str() const noexcept { return string_view(data(), size()); }
+
+ private:
+ template
+ constexpr static_str(const char* str, std::integer_sequence) noexcept : chars_{static_cast(str[I])..., static_cast('\0')} {}
+
+ template
+ constexpr static_str(string_view str, std::integer_sequence) noexcept : chars_{str[I]..., static_cast('\0')} {}
+
+ char_type chars_[static_cast(N) + 1];
+};
+
+template <>
+class static_str<0> {
+ public:
+ constexpr static_str() noexcept = default;
+
+ constexpr static_str(str_view) noexcept {}
+
+ constexpr static_str(string_view) noexcept {}
+
+ constexpr const char_type* data() const noexcept { return chars_; }
+
+ constexpr std::uint16_t size() const noexcept { return 0; }
+
+ constexpr string_view str() const noexcept { return string_view(data(), size()); }
+
+private:
+ static constexpr char_type chars_[1] = {};
+};
+
+template >
+class case_insensitive {
+ static constexpr char_type to_lower(char_type c) noexcept {
+ return (c >= static_cast('A') && c <= static_cast('Z')) ? static_cast(c + (static_cast('a') - static_cast('A'))) : c;
+ }
+
+ public:
+ template
+ constexpr auto operator()(L lhs, R rhs) const noexcept -> std::enable_if_t, char_type> && std::is_same_v, char_type>, bool> {
+ return Op{}(to_lower(lhs), to_lower(rhs));
+ }
+};
+
+constexpr std::size_t find(string_view str, char_type c) noexcept {
+#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
+// https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc
+// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html
+ constexpr bool workaround = true;
+#else
+ constexpr bool workaround = false;
+#endif
+
+ if constexpr (workaround) {
+ for (std::size_t i = 0; i < str.size(); ++i) {
+ if (str[i] == c) {
+ return i;
+ }
+ }
+
+ return string_view::npos;
+ } else {
+ return str.find(c);
+ }
+}
+
+template
+inline constexpr bool is_default_predicate_v = std::is_same_v, std::equal_to> || std::is_same_v, std::equal_to<>>;
+
+
+template
+inline constexpr bool is_nothrow_invocable_v = is_default_predicate_v || std::is_nothrow_invocable_r_v;
+
+
+template
+constexpr bool cmp_equal(string_view lhs, string_view rhs, [[maybe_unused]] BinaryPredicate&& p) noexcept(is_nothrow_invocable_v) {
+#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
+ // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html
+ // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html
+ constexpr bool workaround = true;
+#else
+ constexpr bool workaround = false;
+#endif
+
+ if constexpr (!is_default_predicate_v || workaround) {
+ if (lhs.size() != rhs.size()) {
+ return false;
+ }
+
+ const auto size = lhs.size();
+ for (std::size_t i = 0; i < size; ++i) {
+ if (!p(lhs[i], rhs[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ } else {
+ return lhs == rhs;
+ }
+}
+
+template
+constexpr bool cmp_less(L lhs, R rhs) noexcept {
+ static_assert(std::is_integral_v && std::is_integral_v, "magic_enum::detail::cmp_less requires integral type.");
+
+ if constexpr (std::is_signed_v == std::is_signed_v) {
+ // If same signedness (both signed or both unsigned).
+ return lhs < rhs;
+ } else if constexpr (std::is_same_v) { // bool special case
+ return static_cast(lhs) < rhs;
+ } else if constexpr (std::is_same_v) { // bool special case
+ return lhs < static_cast(rhs);
+ } else if constexpr (std::is_signed_v) {
+ // If 'right' is negative, then result is 'false', otherwise cast & compare.
+ return rhs > 0 && lhs < static_cast>(rhs);
+ } else {
+ // If 'left' is negative, then result is 'true', otherwise cast & compare.
+ return lhs < 0 || static_cast>(lhs) < rhs;
+ }
+}
+
+template
+constexpr I log2(I value) noexcept {
+ static_assert(std::is_integral_v, "magic_enum::detail::log2 requires integral type.");
+
+ if constexpr (std::is_same_v) { // bool special case
+ return MAGIC_ENUM_ASSERT(false), value;
+ } else {
+ auto ret = I{0};
+ for (; value > I{1}; value >>= I{1}, ++ret) {}
+
+ return ret;
+ }
+}
+
+#if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
+# define MAGIC_ENUM_ARRAY_CONSTEXPR 1
+#else
+template
+constexpr std::array, N> to_array(T (&a)[N], std::index_sequence) noexcept {
+ return {{a[I]...}};
+}
+#endif
+
+template
+inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>;
+
+template
+constexpr auto MAGIC_ENUM_CALLING_CONVENTION n() noexcept {
+ static_assert(is_enum_v, "magic_enum::detail::n requires enum type.");
+
+ if constexpr (supported::value) {
+#if defined(MAGIC_ENUM_GET_TYPE_NAME_BUILTIN)
+ constexpr auto name_ptr = MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(E);
+ constexpr auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{};
+#elif defined(__clang__)
+ str_view name;
+ if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
+ static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
+ return str_view{};
+ } else {
+ name.size_ = sizeof(__PRETTY_FUNCTION__) - 36;
+ name.str_ = __PRETTY_FUNCTION__ + 34;
+ }
+#elif defined(__GNUC__)
+ auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1};
+ if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
+ static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
+ return str_view{};
+ } else if (name.str_[name.size_ - 1] == ']') {
+ name.size_ -= 50;
+ name.str_ += 49;
+ } else {
+ name.size_ -= 40;
+ name.str_ += 37;
+ }
+#elif defined(_MSC_VER)
+ // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284).
+ str_view name;
+ name.str_ = __FUNCSIG__;
+ name.str_ += 40;
+ name.size_ += sizeof(__FUNCSIG__) - 57;
+#else
+ auto name = str_view{};
+#endif
+ std::size_t p = 0;
+ for (std::size_t i = name.size_; i > 0; --i) {
+ if (name.str_[i] == ':') {
+ p = i + 1;
+ break;
+ }
+ }
+ if (p > 0) {
+ name.size_ -= p;
+ name.str_ += p;
+ }
+ return name;
+ } else {
+ return str_view{}; // Unsupported compiler or Invalid customize.
+ }
+}
+
+template
+constexpr auto type_name() noexcept {
+ [[maybe_unused]] constexpr auto custom = customize::enum_type_name();
+ static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type.");
+ if constexpr (custom.first == customize::detail::customize_tag::custom_tag) {
+ constexpr auto name = custom.second;
+ static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
+ return static_str{name};
+ } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) {
+ return static_str<0>{};
+ } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) {
+ constexpr auto name = n();
+ return static_str{name};
+ } else {
+ static_assert(always_false_v, "magic_enum::customize invalid.");
+ }
+}
+
+template
+inline constexpr auto type_name_v = type_name();
+
+template
+constexpr auto MAGIC_ENUM_CALLING_CONVENTION n() noexcept {
+ static_assert(is_enum_v, "magic_enum::detail::n requires enum type.");
+
+ if constexpr (supported::value) {
+#if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
+ constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
+ auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{};
+#elif defined(__clang__)
+ str_view name;
+ if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
+ static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
+ return str_view{};
+ } else {
+ name.size_ = sizeof(__PRETTY_FUNCTION__) - 36;
+ name.str_ = __PRETTY_FUNCTION__ + 34;
+ }
+ if (name.size_ > 22 && name.str_[0] == '(' && name.str_[1] == 'a' && name.str_[10] == ' ' && name.str_[22] == ':') {
+ name.size_ -= 23;
+ name.str_ += 23;
+ }
+ if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) {
+ name = str_view{};
+ }
+#elif defined(__GNUC__)
+ auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1};
+ if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
+ static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
+ return str_view{};
+ } else if (name.str_[name.size_ - 1] == ']') {
+ name.size_ -= 55;
+ name.str_ += 54;
+ } else {
+ name.size_ -= 40;
+ name.str_ += 37;
+ }
+ if (name.str_[0] == '(') {
+ name = str_view{};
+ }
+#elif defined(_MSC_VER)
+ str_view name;
+ if ((__FUNCSIG__[5] == '_' && __FUNCSIG__[35] != '(') || (__FUNCSIG__[5] == 'c' && __FUNCSIG__[41] != '(')) {
+ // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284).
+ name.str_ = __FUNCSIG__;
+ name.str_ += 35;
+ name.size_ = sizeof(__FUNCSIG__) - 52;
+ }
+#else
+ auto name = str_view{};
+#endif
+ std::size_t p = 0;
+ for (std::size_t i = name.size_; i > 0; --i) {
+ if (name.str_[i] == ':') {
+ p = i + 1;
+ break;
+ }
+ }
+ if (p > 0) {
+ name.size_ -= p;
+ name.str_ += p;
+ }
+ return name;
+ } else {
+ return str_view{}; // Unsupported compiler or Invalid customize.
+ }
+}
+
+#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920
+# define MAGIC_ENUM_VS_2017_WORKAROUND 1
+#endif
+
+#if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
+template
+constexpr auto MAGIC_ENUM_CALLING_CONVENTION n() noexcept {
+ static_assert(is_enum_v, "magic_enum::detail::n requires enum type.");
+
+# if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
+ constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
+ auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{};
+# else
+ // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284).
+ str_view name;
+ name.str_ = __FUNCSIG__;
+ name.size_ = sizeof(__FUNCSIG__) - 17;
+ std::size_t p = 0;
+ for (std::size_t i = name.size_; i > 0; --i) {
+ if (name.str_[i] == ',' || name.str_[i] == ':') {
+ p = i + 1;
+ break;
+ }
+ }
+ if (p > 0) {
+ name.size_ -= p;
+ name.str_ += p;
+ }
+ if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) {
+ name = str_view{};
+ }
+ return name;
+# endif
+}
+#endif
+
+template
+constexpr auto enum_name() noexcept {
+ [[maybe_unused]] constexpr auto custom = customize::enum_name(V);
+ static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type.");
+ if constexpr (custom.first == customize::detail::customize_tag::custom_tag) {
+ constexpr auto name = custom.second;
+ static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
+ return static_str{name};
+ } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) {
+ return static_str<0>{};
+ } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) {
+#if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
+ constexpr auto name = n();
+#else
+ constexpr auto name = n();
+#endif
+ return static_str>{name.str_ + prefix_length_or_zero};
+ } else {
+ static_assert(always_false_v, "magic_enum::customize invalid.");
+ }
+}
+
+template
+inline constexpr auto enum_name_v = enum_name();
+
+// CWG1766: Values outside the range of the values of an enumeration
+// https://reviews.llvm.org/D130058, https://reviews.llvm.org/D131307
+#if defined(__clang__) && __clang_major__ >= 16
+template
+inline constexpr bool is_enum_constexpr_static_cast_valid = false;
+template
+inline constexpr bool is_enum_constexpr_static_cast_valid(V)>>> = true;
+#else
+template
+inline constexpr bool is_enum_constexpr_static_cast_valid = true;
+#endif
+
+template
+constexpr bool is_valid() noexcept {
+ if constexpr (is_enum_constexpr_static_cast_valid) {
+ constexpr E v = static_cast(V);
+ [[maybe_unused]] constexpr auto custom = customize::enum_name(v);
+ static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type.");
+ if constexpr (custom.first == customize::detail::customize_tag::custom_tag) {
+ constexpr auto name = custom.second;
+ static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
+ return name.size() != 0;
+ } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) {
+#if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
+ return n().size_ != 0;
+#else
+ return n().size_ != 0;
+#endif
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+}
+
+enum class enum_subtype {
+ common,
+ flags
+};
+
+template >
+constexpr U ualue(std::size_t i) noexcept {
+ if constexpr (std::is_same_v) { // bool special case
+ static_assert(O == 0, "magic_enum::detail::ualue requires valid offset.");
+
+ return static_cast(i);
+ } else if constexpr (S == enum_subtype::flags) {
+ return static_cast(U{1} << static_cast(static_cast(i) + O));
+ } else {
+ return static_cast(static_cast(i) + O);
+ }
+}
+
+template >
+constexpr E value(std::size_t i) noexcept {
+ return static_cast(ualue(i));
+}
+
+template >
+constexpr int reflected_min() noexcept {
+ if constexpr (S == enum_subtype::flags) {
+ return 0;
+ } else {
+ constexpr auto lhs = range_min::value;
+ constexpr auto rhs = (std::numeric_limits::min)();
+
+ if constexpr (cmp_less(rhs, lhs)) {
+ return lhs;
+ } else {
+ return rhs;
+ }
+ }
+}
+
+template >
+constexpr int reflected_max() noexcept {
+ if constexpr (S == enum_subtype::flags) {
+ return std::numeric_limits::digits - 1;
+ } else {
+ constexpr auto lhs = range_max::value;
+ constexpr auto rhs = (std::numeric_limits::max)();
+
+ if constexpr (cmp_less(lhs, rhs)) {
+ return lhs;
+ } else {
+ return rhs;
+ }
+ }
+}
+
+#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) \
+ 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) \
+ 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) \
+ 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) \
+ 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) \
+ 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) \
+ 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) \
+ 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)
+
+template
+constexpr void valid_count(bool* valid, std::size_t& count) noexcept {
+#define MAGIC_ENUM_V(O) \
+ if constexpr ((I + O) < Size) { \
+ if constexpr (is_valid(I + O)>()) { \
+ valid[I + O] = true; \
+ ++count; \
+ } \
+ }
+
+ MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_V)
+
+ if constexpr ((I + 256) < Size) {
+ valid_count(valid, count);
+ }
+#undef MAGIC_ENUM_V
+}
+
+template
+struct valid_count_t {
+ std::size_t count = 0;
+ bool valid[N] = {};
+};
+
+template
+constexpr auto valid_count() noexcept {
+ valid_count_t vc;
+ valid_count(vc.valid, vc.count);
+ return vc;
+}
+
+template
+constexpr auto values() noexcept {
+ constexpr auto vc = valid_count();
+
+ if constexpr (vc.count > 0) {
+#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
+ std::array values = {};
+#else
+ E values[vc.count] = {};
+#endif
+ for (std::size_t i = 0, v = 0; v < vc.count; ++i) {
+ if (vc.valid[i]) {
+ values[v++] = value(i);
+ }
+ }
+#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
+ return values;
+#else
+ return to_array(values, std::make_index_sequence{});
+#endif
+ } else {
+ return std::array{};
+ }
+}
+
+template >
+constexpr auto values() noexcept {
+ constexpr auto min = reflected_min();
+ constexpr auto max = reflected_max();
+ constexpr auto range_size = max - min + 1;
+ static_assert(range_size > 0, "magic_enum::enum_range requires valid size.");
+
+ return values();
+}
+
+template >
+constexpr enum_subtype subtype(std::true_type) noexcept {
+ if constexpr (std::is_same_v) { // bool special case
+ return enum_subtype::common;
+ } else if constexpr (has_is_flags::value) {
+ return customize::enum_range::is_flags ? enum_subtype::flags : enum_subtype::common;
+ } else {
+#if defined(MAGIC_ENUM_AUTO_IS_FLAGS)
+ constexpr auto flags_values = values();
+ constexpr auto default_values = values();
+ if (flags_values.size() == 0 || default_values.size() > flags_values.size()) {
+ return enum_subtype::common;
+ }
+ for (std::size_t i = 0; i < default_values.size(); ++i) {
+ const auto v = static_cast(default_values[i]);
+ if (v != 0 && (v & (v - 1)) != 0) {
+ return enum_subtype::common;
+ }
+ }
+ return enum_subtype::flags;
+#else
+ return enum_subtype::common;
+#endif
+ }
+}
+
+template
+constexpr enum_subtype subtype(std::false_type) noexcept {
+ // For non-enum type return default common subtype.
+ return enum_subtype::common;
+}
+
+template >
+inline constexpr auto subtype_v = subtype(std::is_enum{});
+
+template
+inline constexpr auto values_v = values();
+
+template >
+using values_t = decltype((values_v));
+
+template
+inline constexpr auto count_v = values_v.size();
+
+template >
+inline constexpr auto min_v = (count_v > 0) ? static_cast(values_v.front()) : U{0};
+
+template >
+inline constexpr auto max_v = (count_v > 0) ? static_cast(values_v.back()) : U{0};
+
+template
+constexpr auto names(std::index_sequence) noexcept {
+ constexpr auto names = std::array{{enum_name_v[I]>.str()...}};
+ return names;
+}
+
+template
+inline constexpr auto names_v = names(std::make_index_sequence>{});
+
+template >
+using names_t = decltype((names_v));
+
+template
+constexpr auto entries(std::index_sequence) noexcept {
+ constexpr auto entries = std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>.str()}...}};
+ return entries;
+}
+
+template
+inline constexpr auto entries_v = entries(std::make_index_sequence>{});
+
+template >
+using entries_t = decltype((entries_v));
+
+template >
+constexpr bool is_sparse() noexcept {
+ if constexpr (count_v == 0) {
+ return false;
+ } else if constexpr (std::is_same_v) { // bool special case
+ return false;
+ } else {
+ constexpr auto max = (S == enum_subtype::flags) ? log2(max_v) : max_v;
+ constexpr auto min = (S == enum_subtype::flags) ? log2(min_v) : min_v;
+ constexpr auto range_size = max - min + 1;
+
+ return range_size != count_v;
+ }
+}
+
+template >
+inline constexpr bool is_sparse_v = is_sparse();
+
+template
+struct is_reflected
+#if defined(MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM)
+ : std::true_type {};
+#else
+ : std::bool_constant && (count_v != 0)> {};
+#endif
+
+template
+inline constexpr bool is_reflected_v = is_reflected, S>{};
+
+template
+struct enable_if_enum {};
+
+template