#pragma once #include "common.hpp" #include "details/string_view.hpp" #include "enchantum.hpp" #ifndef ENCHANTUM_ALIAS_STRING #include #endif namespace enchantum { #ifdef ENCHANTUM_ALIAS_STRING ENCHANTUM_ALIAS_STRING; #else using ::std::string; #endif } // namespace enchantum namespace enchantum { template inline constexpr E value_ors = [] { using T = std::underlying_type_t; T ret{}; for (const auto val : values) ret |= static_cast(val); return static_cast(ret); }(); template [[nodiscard]] constexpr bool contains_bitflag(const std::underlying_type_t value) noexcept { if (value == 0) return has_zero_flag; using T = std::underlying_type_t; T valid_bits = 0; for (auto i = std::size_t{has_zero_flag}; i < count; ++i) { const auto v = static_cast(values[i]); if ((value & v) == v) valid_bits |= v; } return valid_bits == value; } template [[nodiscard]] constexpr bool contains_bitflag(const E value) noexcept { return enchantum::contains_bitflag(static_cast>(value)); } template BinaryPred> [[nodiscard]] constexpr bool contains_bitflag(const string_view s, const char sep, const BinaryPred binary_pred) noexcept { std::size_t pos = 0; for (std::size_t i = s.find(sep); i != s.npos; i = s.find(sep, pos)) { if (!enchantum::contains(s.substr(pos, i - pos)), binary_pred) return false; pos = i + 1; } return enchantum::contains(s.substr(pos), binary_pred); } template [[nodiscard]] constexpr bool contains_bitflag(const string_view s, const char sep = '|') noexcept { std::size_t pos = 0; for (std::size_t i = s.find(sep); i != s.npos; i = s.find(sep, pos)) { if (!enchantum::contains(s.substr(pos, i - pos))) return false; pos = i + 1; } return enchantum::contains(s.substr(pos)); } template [[nodiscard]] constexpr String to_string_bitflag(const E value, const char sep = '|') { using T = std::underlying_type_t; if constexpr (has_zero_flag) if (static_cast(value) == 0) return String(names[0]); String name; T check_value = 0; for (auto i = std::size_t{has_zero_flag}; i < count; ++i) { const auto& [v, s] = entries[i]; if (v == (value & v)) { if (!name.empty()) name.append(1, sep); // append separator if not the first value name.append(s.data(), s.size()); // not using operator += since this may not be std::string_view always check_value |= static_cast(v); } } if (check_value == static_cast(value)) return name; return String(); } template BinaryPred> [[nodiscard]] constexpr optional cast_bitflag(const string_view s, const char sep, const BinaryPred binary_pred) noexcept { using T = std::underlying_type_t; T check_value{}; std::size_t pos = 0; for (std::size_t i = s.find(sep); i != s.npos; i = s.find(sep, pos)) { if (const auto v = enchantum::cast(s.substr(pos, i - pos), binary_pred)) check_value |= static_cast(*v); else return optional(); pos = i + 1; } if (const auto v = enchantum::cast(s.substr(pos), binary_pred)) return optional(static_cast(check_value | static_cast(*v))); return optional(); } template [[nodiscard]] constexpr optional cast_bitflag(const string_view s, const char sep = '|') noexcept { return enchantum::cast_bitflag(s, sep, [](const auto& a, const auto& b) { return a == b; }); } template [[nodiscard]] constexpr optional cast_bitflag(const E value) noexcept { using T = std::underlying_type_t; const auto raw_value = static_cast(value); if constexpr (has_zero_flag) if (raw_value == 0) return optional(E{}); T valid_bits{0}; for (auto i = std::size_t{has_zero_flag}; i < count; ++i) { const auto v = static_cast(values[i]); if ((raw_value & v) == v) valid_bits |= v; } return valid_bits == raw_value ? optional(value) : optional(); } } // namespace enchantum