// __ __ _ ______ _____ // | \/ | (_) | ____| / ____|_ _ // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum // |___/ vesion 0.2.0 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 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. #pragma once #include #include #include #include #include #include #include // Enum value must be in range (-MAGIC_ENUM_RANGE, MAGIC_ENUM_RANGE). If you need a larger range, redefine the macro MAGIC_ENUM_RANGE. #if !defined(MAGIC_ENUM_RANGE) # define MAGIC_ENUM_RANGE 128 #endif namespace magic_enum { static_assert(MAGIC_ENUM_RANGE > 0, "MAGIC_ENUM_RANGE must be positive and greater than zero."); static_assert(MAGIC_ENUM_RANGE < std::numeric_limits::max(), "MAGIC_ENUM_RANGE must be less INT_MAX."); namespace detail { [[nodiscard]] constexpr bool is_name_char(char c, bool front) noexcept { return (!front && c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; } template [[nodiscard]] constexpr std::string_view enum_to_string_impl() noexcept { static_assert(std::is_enum_v, "magic_enum::enum_to_string require enum type."); #if defined(__clang__) std::string_view name{__PRETTY_FUNCTION__}; constexpr auto suffix = sizeof("]") - 1; #elif defined(__GNUC__) && __GNUC__ >= 9 std::string_view name{__PRETTY_FUNCTION__}; constexpr auto suffix = sizeof("; std::string_view = std::basic_string_view]") - 1; #elif defined(_MSC_VER) std::string_view name{__FUNCSIG__}; constexpr auto suffix = sizeof(">(void) noexcept") - 1; #else return {}; // Unsupported compiler. #endif #if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 9) || defined(_MSC_VER) name.remove_suffix(suffix); for (std::size_t i = name.size(); i > 0; --i) { if (!is_name_char(name[i - 1], false)) { name.remove_prefix(i); break; } } if (name.length() > 0 && is_name_char(name.front(), true)) { return name; } else { return {}; // Enum value does not have name. } #endif } template [[nodiscard]] constexpr std::string_view enum_to_string_impl(int value, std::integer_sequence) noexcept { static_assert(std::is_enum_v, "magic_enum::enum_to_string require enum type."); constexpr int n = sizeof...(I); constexpr std::array names{{enum_to_string_impl(I + O)>()...}}; return names[value - O]; } template [[nodiscard]] constexpr std::optional enum_from_string_impl(std::string_view name, std::integer_sequence) noexcept { static_assert(std::is_enum_v, "magic_enum::enum_from_string require enum type."); std::optional value{std::nullopt}; (void)(((enum_to_string_impl(I + O)>() == name) ? (value = static_cast(I + O), false) : true) && ...); return value; } template [[nodiscard]] constexpr decltype(auto) enum_to_sequence_impl(std::integer_sequence) noexcept { static_assert(std::is_enum_v, "magic_enum::enum_to_sequence require enum type."); constexpr int n = sizeof...(I); constexpr std::array valid{{!enum_to_string_impl(I + O)>().empty()...}}; constexpr int num_valid = ((valid[I] ? 1 : 0) + ...); std::array sequence{}; for (int i = 0, v = 0; i < n && v < num_valid; ++i) { if (valid[i]) { sequence[v++] = static_cast(i + O); } } return sequence; } template [[nodiscard]] constexpr decltype(auto) enum_to_string_sequence_impl(std::integer_sequence s) noexcept { static_assert(std::is_enum_v, "magic_enum::enum_to_string_sequence require enum type."); constexpr int n = sizeof...(I); constexpr std::array valid{{!enum_to_string_impl(I + O)>().empty()...}}; constexpr int num_valid = ((valid[I] ? 1 : 0) + ...); std::array sequence{}; for (int i = 0, v = 0; i < n && v < num_valid; ++i) { if (valid[i]) { sequence[v++] = enum_to_string_impl(i + O, s); } } return sequence; } } // namespace detail // enum_to_string(enum) obtains string enum name from enum variable. template >>> [[nodiscard]] constexpr std::optional enum_to_string(T value) noexcept { using D = std::decay_t; using U = std::underlying_type_t; using C = std::common_type_t; constexpr int min = std::max(std::is_signed_v ? -MAGIC_ENUM_RANGE : 0, std::numeric_limits::min()); constexpr int max = std::min(MAGIC_ENUM_RANGE, std::numeric_limits::max()); constexpr int range = max - min + 1; if (static_cast(value) > max || static_cast(value) < min) { return std::nullopt; // Enum value out of range. } const auto name = detail::enum_to_string_impl(static_cast(value), std::make_integer_sequence{}); if (name.empty()) { return std::nullopt; } else { return name; // Enum value does not have name. } } // enum_to_string() obtains string enum name from static storage enum variable. template >>> [[nodiscard]] constexpr std::optional enum_to_string() noexcept { constexpr auto name = detail::enum_to_string_impl(); if (name.empty()) { return std::nullopt; } else { return name; // Enum value does not have name. } } // enum_from_string(name) obtains enum value from enum string name. template >> [[nodiscard]] constexpr std::optional enum_from_string(std::string_view name) noexcept { using U = std::underlying_type_t; using C = std::common_type_t; constexpr int min = std::max(std::is_signed_v ? -MAGIC_ENUM_RANGE : 0, std::numeric_limits::min()); constexpr int max = std::min(MAGIC_ENUM_RANGE, std::numeric_limits::max()); constexpr int range = max - min + 1; return detail::enum_from_string_impl(name, std::make_integer_sequence{}); } // enum_to_sequence() obtains value enum sequence. template >> [[nodiscard]] constexpr decltype(auto) enum_to_sequence() noexcept { using U = std::underlying_type_t; using C = std::common_type_t; constexpr int min = std::max(std::is_signed_v ? -MAGIC_ENUM_RANGE : 0, std::numeric_limits::min()); constexpr int max = std::min(MAGIC_ENUM_RANGE, std::numeric_limits::max()); constexpr int range = max - min + 1; return detail::enum_to_sequence_impl(std::make_integer_sequence{}); } // enum_to_string_sequence() obtains string enum name sequence. template >> [[nodiscard]] constexpr decltype(auto) enum_to_string_sequence() noexcept { using U = std::underlying_type_t; using C = std::common_type_t; constexpr int min = std::max(std::is_signed_v ? -MAGIC_ENUM_RANGE : 0, std::numeric_limits::min()); constexpr int max = std::min(MAGIC_ENUM_RANGE, std::numeric_limits::max()); constexpr int range = max - min + 1; return detail::enum_to_string_sequence_impl(std::make_integer_sequence{}); } } // namespace magic_enum