#pragma once #include "common.hpp" #include "details/optional.hpp" #include "details/string_view.hpp" #include "entries.hpp" #include namespace enchantum { template inline constexpr bool has_zero_flag = false; template inline constexpr bool has_zero_flag = []() { for (const auto v : values) if (static_cast>(v) == 0) return true; return false; }(); template inline constexpr bool is_contiguous = false; template inline constexpr bool is_contiguous = []() { using T = std::underlying_type_t; if constexpr (std::is_same_v) { return true; } else { constexpr auto& enums = entries; for (std::size_t i = 0; i < enums.size() - 1; ++i) if (T(enums[i].first) + 1 != T(enums[i + 1].first)) return false; return true; } }(); template concept ContiguousEnum = Enum && is_contiguous; template inline constexpr bool is_contiguous_bitflag = false; template inline constexpr bool is_contiguous_bitflag = []() { constexpr auto& enums = entries; using T = std::underlying_type_t; for (auto i = std::size_t{has_zero_flag}; i < enums.size() - 1; ++i) if (T(enums[i].first) << 1 != T(enums[i + 1].first)) return false; return true; }(); template concept ContiguousBitFlagEnum = BitFlagEnum && is_contiguous_bitflag; template [[nodiscard]] constexpr bool contains(const E value) noexcept { for (const auto v : values) if (v == value) return true; return false; } template [[nodiscard]] constexpr bool contains(const std::underlying_type_t value) noexcept { return enchantum::contains(static_cast(value)); } template [[nodiscard]] constexpr bool contains(const string_view name) noexcept { for (const auto& s : names) if (s == name) return true; return false; } template BinaryPredicate> [[nodiscard]] constexpr bool contains(const string_view name, const BinaryPredicate binary_predicate) noexcept { for (const auto& s : names) if (binary_predicate(name, s)) return true; return false; } template [[nodiscard]] constexpr bool contains(const E value) noexcept { using T = std::underlying_type_t; return T(value) <= T(max) && T(value) >= T(min); } namespace details { template struct index_to_enum_functor { [[nodiscard]] constexpr optional operator()(const std::size_t index) const noexcept { optional ret; if (index < values.size()) ret.emplace(values[index]); return ret; } }; struct enum_to_index_functor { template [[nodiscard]] constexpr optional operator()(const E e) const noexcept { if constexpr (ContiguousEnum) { using T = std::underlying_type_t; if (enchantum::contains(e)) return optional(std::size_t(T(e) - T(min))); } else { for (std::size_t i = 0; i < values.size(); ++i) if (values[i] == e) return optional(i); } return optional(); } }; template struct cast_functor { [[nodiscard]] constexpr optional operator()(const std::underlying_type_t value) const noexcept { optional a; // rvo not that it really matters if (!enchantum::contains(value)) return a; a.emplace(static_cast(value)); return a; } [[nodiscard]] constexpr optional operator()(const string_view name) const noexcept { optional a; // rvo not that it really matters for (const auto& [e, s] : entries) { if (s == name) { a.emplace(e); return a; } } return a; // nullopt } template BinaryPred> [[nodiscard]] constexpr optional operator()(const string_view name, const BinaryPred binary_predicate) const noexcept { optional a; // rvo not that it really matters for (const auto& [e, s] : entries) { if (binary_predicate(name, s)) { a.emplace(e); return a; } } return a; } }; } // namespace details template inline constexpr details::index_to_enum_functor index_to_enum{}; inline constexpr details::enum_to_index_functor enum_to_index{}; template inline constexpr details::cast_functor cast{}; namespace details { struct to_string_functor { template [[nodiscard]] constexpr string_view operator()(const E value) const noexcept { if (const auto i = enchantum::enum_to_index(value)) return names[*i]; return string_view(); } }; } // namespace details inline constexpr details::to_string_functor to_string{}; } // namespace enchantum