diff --git a/IL2CppDLL.vcxproj b/IL2CppDLL.vcxproj
index 26a783f..838b9a7 100644
--- a/IL2CppDLL.vcxproj
+++ b/IL2CppDLL.vcxproj
@@ -90,6 +90,7 @@
+
@@ -123,6 +124,7 @@
{AFA414F5-355A-472E-822F-244F167E5B0D}
Il2CppDLL
DevourClient
+ 10.0
@@ -232,12 +234,13 @@
Level3
true
- _DEBUG;IL2CPPDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ _DEBUG;IL2CPPDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
true
Use
pch-il2cpp.h
true
$(ProjectDir)appdata;$(ProjectDir)framework;$(ProjectDir)user;$(ProjectDir)lib\public;
+ stdcpp17
Windows
@@ -251,12 +254,13 @@
true
true
true
- NDEBUG;IL2CPPDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ NDEBUG;IL2CPPDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
true
Use
pch-il2cpp.h
true
$(ProjectDir)appdata;$(ProjectDir)framework;$(ProjectDir)user;$(ProjectDir)lib\public
+ stdcpp17
Windows
diff --git a/IL2CppDLL.vcxproj.filters b/IL2CppDLL.vcxproj.filters
index b5db620..7fe401d 100644
--- a/IL2CppDLL.vcxproj.filters
+++ b/IL2CppDLL.vcxproj.filters
@@ -243,6 +243,9 @@
lib\public\UnityEngine
+
+ include
+
diff --git a/framework/helpers.cpp b/framework/helpers.cpp
index bc9b258..4885215 100644
--- a/framework/helpers.cpp
+++ b/framework/helpers.cpp
@@ -41,6 +41,14 @@ void il2cpp_close_console() {
FreeConsole();
}
+bool string_replace(std::string& str, const std::string& from, const std::string& to) {
+ size_t start_pos = str.find(from);
+ if (start_pos == std::string::npos)
+ return false;
+ str.replace(start_pos, from.length(), to);
+ return true;
+}
+
#if _MSC_VER >= 1920
// Helper function to convert Il2CppString to std::string
std::string il2cppi_to_string(Il2CppString* str) {
@@ -52,6 +60,7 @@ std::string il2cppi_to_string(Il2CppString* str) {
std::string il2cppi_to_string(app::String* str) {
return il2cppi_to_string(reinterpret_cast(str));
}
+
app::String* ConvertToSystemString(const char* str)
{
Il2CppString* il2cpp_str = il2cpp_string_new(str);
diff --git a/framework/helpers.h b/framework/helpers.h
index 5c973d7..1657ea7 100644
--- a/framework/helpers.h
+++ b/framework/helpers.h
@@ -9,6 +9,8 @@
#include "il2cpp-metadata-version.h"
+#define il2cpp_object_get_field_value(object, type, field) *(type*)((uintptr_t)object + field->offset)
+
// Helper function to get the module base address
uintptr_t il2cppi_get_base_address();
@@ -20,6 +22,8 @@ void il2cppi_new_console();
void il2cpp_close_console();
+bool string_replace(std::string& str, const std::string& from, const std::string& to);
+
#if _MSC_VER >= 1920
// Helper function to convert Il2CppString to std::string
std::string il2cppi_to_string(Il2CppString* str);
diff --git a/include/magic_enum.hpp b/include/magic_enum.hpp
new file mode 100644
index 0000000..192bff4
--- /dev/null
+++ b/include/magic_enum.hpp
@@ -0,0 +1,1520 @@
+// __ __ _ ______ _____
+// | \/ | (_) | ____| / ____|_ _
+// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
+// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
+// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
+// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
+// __/ | https://github.com/Neargye/magic_enum
+// |___/ version 0.9.5
+//
+// 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 5
+
+#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
+
+// 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 = 128.
+// 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 {
+
+ // 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.
+ // 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;
+ };
+
+ 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(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 operator string_view() const noexcept { return { 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 explicit static_str() = default;
+
+ constexpr explicit static_str(str_view) noexcept {}
+
+ constexpr explicit static_str(string_view) noexcept {}
+
+ constexpr const char_type* data() const noexcept { return nullptr; }
+
+ constexpr std::uint16_t size() const noexcept { return 0; }
+
+ constexpr operator string_view() const noexcept { return {}; }
+ };
+
+ 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
+ constexpr bool is_default_predicate() noexcept {
+ return std::is_same_v, std::equal_to> ||
+ std::is_same_v, std::equal_to<>>;
+ }
+
+ template
+ constexpr bool is_nothrow_invocable() {
+ return is_default_predicate() ||
+ 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()) {
+#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() || 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 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 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 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};
+ }
+ else {
+ static_assert(always_false_v, "magic_enum::customize invalid.");
+ }
+ }
+
+ template
+ inline constexpr auto enum_name_v = enum_name();
+
+ template
+ constexpr bool is_valid() noexcept {
+#if defined(__clang__) && __clang_major__ >= 16
+ // https://reviews.llvm.org/D130058, https://reviews.llvm.org/D131307
+ constexpr E v = __builtin_bit_cast(E, V);
+#else
+ constexpr E v = static_cast(V);
+#endif
+ [[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;
+ }
+ }
+
+ 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]>...}};
+ 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]>}...}};
+ 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
+ struct enable_if_enum {
+ using type = R;
+ static_assert(supported::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
+ };
+
+ template , typename D = std::decay_t>
+ using enable_if_t = typename enable_if_enum&& std::is_invocable_r_v, R>::type;
+
+ template >, int> = 0>
+ using enum_concept = T;
+
+ template >
+ struct is_scoped_enum : std::false_type {};
+
+ template
+ struct is_scoped_enum : std::bool_constant>> {};
+
+ template >
+ struct is_unscoped_enum : std::false_type {};
+
+ template
+ struct is_unscoped_enum : std::bool_constant>> {};
+
+ template >>
+ struct underlying_type {};
+
+ template
+ struct underlying_type : std::underlying_type