// __ __ _ ______ _____ // | \/ | (_) | ____| / ____|_ _ // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum // |___/ version 0.9.2 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2023 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_FLAGS_HPP #define NEARGYE_MAGIC_ENUM_FLAGS_HPP #include "magic_enum.hpp" #if defined(__clang__) # pragma clang diagnostic push #elif defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'. #elif defined(_MSC_VER) # pragma warning(push) #endif namespace magic_enum { // Returns name from enum-flags value. // If enum-flags value does not have name or value out of range, returns empty string. template [[nodiscard]] auto enum_flags_name(E value, char_type sep = static_cast('|')) -> detail::enable_if_t { using D = std::decay_t; using U = underlying_type_t; constexpr auto S = detail::enum_subtype::flags; string name; auto check_value = U{0}; for (std::size_t i = 0; i < detail::count_v; ++i) { if (const auto v = static_cast(enum_value(i)); (static_cast(value) & v) != 0) { if (const auto n = detail::names_v[i]; !n.empty()) { check_value |= v; if (!name.empty()) { name.append(1, sep); } name.append(n.data(), n.size()); } else { return {}; // Value out of range. } } } if (check_value != 0 && check_value == static_cast(value)) { return name; } return {}; // Invalid value or out of range. } // Obtains enum-flags value from integer value. // Returns optional with enum-flags value. template [[nodiscard]] constexpr auto enum_flags_cast(underlying_type_t value) noexcept -> detail::enable_if_t>> { using D = std::decay_t; using U = underlying_type_t; constexpr auto S = detail::enum_subtype::flags; if constexpr (detail::count_v == 0) { static_cast(value); return {}; // Empty enum. } else { if constexpr (detail::is_sparse_v) { auto check_value = U{0}; for (std::size_t i = 0; i < detail::count_v; ++i) { if (const auto v = static_cast(enum_value(i)); (value & v) != 0) { check_value |= v; } } if (check_value != 0 && check_value == value) { return static_cast(value); } } else { constexpr auto min = detail::min_v; constexpr auto max = detail::values_ors(); if (value >= min && value <= max) { return static_cast(value); } } return {}; // Invalid value or out of range. } } // Obtains enum-flags value from name. // Returns optional with enum-flags value. template > [[nodiscard]] constexpr auto enum_flags_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t>, BinaryPredicate> { using D = std::decay_t; using U = underlying_type_t; constexpr auto S = detail::enum_subtype::flags; if constexpr (detail::count_v == 0) { static_cast(value); return {}; // Empty enum. } else { auto result = U{0}; while (!value.empty()) { const auto d = detail::find(value, '|'); const auto s = (d == string_view::npos) ? value : value.substr(0, d); auto f = U{0}; for (std::size_t i = 0; i < detail::count_v; ++i) { if (detail::cmp_equal(s, detail::names_v[i], p)) { f = static_cast(enum_value(i)); result |= f; break; } } if (f == U{0}) { return {}; // Invalid value or out of range. } value.remove_prefix((d == string_view::npos) ? value.size() : d + 1); } if (result != U{0}) { return static_cast(result); } return {}; // Invalid value or out of range. } } // Checks whether enum-flags contains value with such value. template [[nodiscard]] constexpr auto enum_flags_contains(E value) noexcept -> detail::enable_if_t { using D = std::decay_t; using U = underlying_type_t; return static_cast(enum_flags_cast(static_cast(value))); } // Checks whether enum-flags contains value with such integer value. template [[nodiscard]] constexpr auto enum_flags_contains(underlying_type_t value) noexcept -> detail::enable_if_t { using D = std::decay_t; return static_cast(enum_flags_cast(value)); } // Checks whether enum-flags contains enumerator with such name. template > [[nodiscard]] constexpr auto enum_flags_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t { using D = std::decay_t; return static_cast(enum_flags_cast(value, std::move(p))); } // Checks whether `flags set` contains `flag`. // Note: If `flag` equals 0, it returns false, as 0 is not a flag. template constexpr auto enum_flags_test(E flags, E flag) noexcept -> detail::enable_if_t { using U = underlying_type_t; return static_cast(flag) && ((static_cast(flags) & static_cast(flag)) == static_cast(flag)); } // Checks whether `lhs flags set` and `rhs flags set` have common flags. // Note: If `lhs flags set` or `rhs flags set` equals 0, it returns false, as 0 is not a flag, and therfore cannot have any matching flag. template constexpr auto enum_flags_test_any(E lhs, E rhs) noexcept -> detail::enable_if_t { using U = underlying_type_t; return (static_cast(lhs) & static_cast(rhs)) != 0; } } // namespace magic_enum #if defined(__clang__) # pragma clang diagnostic pop #elif defined(__GNUC__) # pragma GCC diagnostic pop #elif defined(_MSC_VER) # pragma warning(pop) #endif #endif // NEARGYE_MAGIC_ENUM_FLAGS_HPP