blob: 98076f298b705266de9f2deec14a082f41fc5761 [file] [log] [blame]
// __ __ _ ______ _____
// | \/ | (_) | ____| / ____|_ _
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
// __/ | https://github.com/Neargye/magic_enum
// |___/ version 0.6.6
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2020 Daniil Goncharov <neargye@gmail.com>.
//
// 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.
//
// Modified based on the following file in the original repository:
// - include/magic_enum.hpp
//
#ifndef SRC_UI_LIB_ESCHER_THIRD_PARTY_ENUM_UTILS_ENUM_UTILS_H_
#define SRC_UI_LIB_ESCHER_THIRD_PARTY_ENUM_UTILS_ENUM_UTILS_H_
#include <algorithm>
#include <iterator>
#include <optional>
#include <string_view>
#include <utility>
namespace escher::enum_utils {
namespace internal {
// Check if |V| is a valid enum value of type E.
//
// This uses the compiler's __PRETTY_FUNCTION__ feature: For non-enum values,
// the value of __PRETTY_FUNCTION__ looks like:
// "constexpr bool IsValidEnum() [with E = Enum; E V = (Enum)0]"
// However, for defined enum values, the value looks like:
// "constexpr bool IsValidEnum() [with E = Enum; E V = Enum::IDENTIFIER]"
//
// We can check whether if the value of |V| is displayed as an identifier in the
// __PRETTY_FUNCTION__ string to know whether it is a valid enum value.
template <typename E, E V>
constexpr bool IsValidEnum() {
std::string_view name{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2};
for (std::size_t i = name.size(); i > 0; --i) {
if (!((name[i - 1] >= '0' && name[i - 1] <= '9') ||
(name[i - 1] >= 'a' && name[i - 1] <= 'z') ||
(name[i - 1] >= 'A' && name[i - 1] <= 'Z') || (name[i - 1] == '_'))) {
name.remove_prefix(i);
break;
}
}
return !name.empty() && ((name.front() >= 'a' && name.front() <= 'z') ||
(name.front() >= 'A' && name.front() <= 'Z') || (name.front() == '_'));
}
// Helper function check if |Begin + Offset| is a valid enum value in |E|.
template <typename E, auto Begin, auto Offset>
constexpr bool IsValueValidEnum() {
return IsValidEnum<E, static_cast<E>(Begin + Offset)>();
}
// Helper function counting all the valid enum values in integer sequence
// {Begin, Begin + 1, ..., Begin + Ints.size() - 1}.
template <typename E, auto Begin, auto... Ints>
constexpr size_t CountEnumElementInSequence(std::integer_sequence<decltype(Begin), Ints...> seq) {
return (0ul + ... + IsValueValidEnum<E, Begin, Ints>());
}
// Helper function finding the maximum enum values in integer sequence
// {Begin, Begin + 1, ..., Begin + Ints.size() - 1}.
//
// Returns std::nullopt if none of the values is valid in the sequence.
template <typename E, auto Min, auto... Ints>
constexpr std::optional<decltype(Min)> MaxEnumElementInSequence(
std::integer_sequence<decltype(Min), Ints...> seq) {
auto values = {(IsValueValidEnum<E, Min, Ints>())...};
for (auto it = std::rbegin(values); it != std::rend(values); it++) {
if (*it) {
return std::make_optional<decltype(Min)>(Min + (std::rend(values) - it) - 1);
}
}
return std::nullopt;
}
// Helper function finding the minimum enum values in integer sequence
// {Begin, Begin + 1, ..., Begin + Ints.size() - 1}.
//
// Returns std::nullopt if none of the values is valid in the sequence.
template <typename E, auto Min, auto... Ints>
constexpr std::optional<decltype(Min)> MinEnumElementInSequence(
std::integer_sequence<decltype(Min), Ints...> seq) {
auto values = {(IsValueValidEnum<E, Min, Ints>())...};
for (auto it = std::begin(values); it != std::end(values); it++) {
if (*it) {
return std::make_optional<decltype(Min)>(Min + (it - std::begin(values)));
}
}
return std::nullopt;
}
} // namespace internal
// The enum value check uses clang/gcc's __PRETTY_FUNCTION__ feature, and only
// certain versions of the compilers are supported.
constexpr bool IsSupported() {
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9
return true;
#else
return false;
#endif
}
constexpr auto kDefaultEnumValueBegin = -128;
constexpr auto kDefaultEnumValueEnd = 128;
// Count number of elements in an enum / enum class type |E|.
//
// This compile-time function checks all the values in sequence {Begin,
// Begin + 1, ..., End - 1} to count all defined enum values at compilation
// time.
template <typename E, auto Begin = kDefaultEnumValueBegin, auto End = kDefaultEnumValueEnd,
auto... Ints>
constexpr size_t CountEnumElement() {
static_assert(std::is_enum<E>(), "Non-enum type is not supported!");
static_assert(End > Begin);
static_assert(IsSupported(), "enum_utils is not supported by the compiler!");
return internal::CountEnumElementInSequence<E, Begin>(
std::make_integer_sequence<int, End - Begin>{});
}
// Get the maximum element in an enum / enum class type |E|.
//
// This compile-time function checks all the values in sequence {Begin,
// Begin + 1, ..., End - 1} to find the maximum defined enum values at
// compilation time.
template <typename E, auto Begin = kDefaultEnumValueBegin, auto End = kDefaultEnumValueEnd,
auto... Ints>
constexpr std::optional<decltype(Begin)> MaxEnumElementValue() {
static_assert(std::is_enum<E>(), "Non-enum type is not supported!");
static_assert(End > Begin);
static_assert(IsSupported(), "enum_utils is not supported by the compiler!");
return internal::MaxEnumElementInSequence<E, Begin>(
std::make_integer_sequence<int, End - Begin>{});
}
// Get the minimum element in an enum / enum class type |E|.
//
// This compile-time function checks all the values in sequence {Begin,
// Begin + 1, ..., End - 1} to find the minimum defined enum values at
// compilation time.
template <typename E, auto Begin = kDefaultEnumValueBegin, auto End = kDefaultEnumValueEnd,
auto... Ints>
constexpr std::optional<decltype(Begin)> MinEnumElementValue() {
static_assert(std::is_enum<E>(), "Non-enum type is not supported!");
static_assert(End > Begin);
static_assert(IsSupported(), "enum_utils is not supported by the compiler!");
return internal::MinEnumElementInSequence<E, Begin>(
std::make_integer_sequence<int, End - Begin>{});
}
} // namespace escher::enum_utils
#endif // SRC_UI_LIB_ESCHER_THIRD_PARTY_ENUM_UTILS_ENUM_UTILS_H_