From 250dd20a6a379ab6f93fc103d0d86280d4891e73 Mon Sep 17 00:00:00 2001 From: janis Date: Thu, 30 Jun 2022 17:05:59 +0100 Subject: [PATCH] constexpr enum functions --- include/enum.hpp | 141 +++++++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 67 deletions(-) diff --git a/include/enum.hpp b/include/enum.hpp index d6c5621..5cb8414 100644 --- a/include/enum.hpp +++ b/include/enum.hpp @@ -4,55 +4,58 @@ #include namespace util { -namespace bitflag_operators { - -template -concept enum_type = std::is_enum_v; - -template auto operator&(const E &rhs, const E &lhs) -> E { - return static_cast(underlying_type_cast(rhs) & underlying_type_cast(lhs)); -} - -template auto operator&=(E &rhs, const E &lhs) -> E & { - rhs = rhs & lhs; - return rhs; -} - -template auto operator|(const E &rhs, const E &lhs) -> E { - return static_cast(underlying_type_cast(rhs) | underlying_type_cast(lhs)); -} - -template auto operator|=(E &rhs, const E &lhs) -> E & { - rhs = rhs | lhs; - return rhs; -} - -template auto operator^(const E &rhs, const E &lhs) -> E { - return static_cast(underlying_type_cast(rhs) ^ underlying_type_cast(lhs)); -} - -template auto operator^=(E &rhs, const E &lhs) -> E & { - rhs = rhs ^ lhs; - return rhs; -} - -template auto operator~(const E &rhs) -> E { - return static_cast(~underlying_type_cast(rhs)); -} - -template auto is_empty(const E &value) -> bool { - return std::to_underlying(value) == 0; -} - -} // namespace bitflag_operators - -using bitflag_operators::enum_type; template constexpr auto underlying_type_cast(const E &value) -> std::underlying_type_t requires std::is_enum_v { return static_cast>(value); } +namespace bitflag_operators { + +template +concept enum_type = std::is_enum_v; + +template +constexpr auto operator&(const E &rhs, const E &lhs) -> E { + return static_cast(underlying_type_cast(rhs) & underlying_type_cast(lhs)); +} + +template constexpr auto operator&=(E &rhs, const E &lhs) -> E & { + rhs = rhs & lhs; + return rhs; +} + +template +constexpr auto operator|(const E &rhs, const E &lhs) -> E { + return static_cast(underlying_type_cast(rhs) | underlying_type_cast(lhs)); +} + +template constexpr auto operator|=(E &rhs, const E &lhs) -> E & { + rhs = rhs | lhs; + return rhs; +} + +template +constexpr auto operator^(const E &rhs, const E &lhs) -> E { + return static_cast(underlying_type_cast(rhs) ^ underlying_type_cast(lhs)); +} + +template constexpr auto operator^=(E &rhs, const E &lhs) -> E & { + rhs = rhs ^ lhs; + return rhs; +} + +template constexpr auto operator~(const E &rhs) -> E { + return static_cast(~underlying_type_cast(rhs)); +} + +template constexpr auto is_empty(const E &value) -> bool { + return std::to_underlying(value) == 0; +} + +} // namespace bitflag_operators + +using bitflag_operators::enum_type; template requires std::is_enum_v @@ -63,92 +66,96 @@ public: using U = std::underlying_type_t; using value_type = U; - EnumFlag() : flags(static_cast(U(0))) {} - EnumFlag(const U &value) : flags(static_cast(value)) {} - EnumFlag(const E &value) : flags(value) {} + constexpr EnumFlag() noexcept : flags(static_cast(U(0))) {} + constexpr EnumFlag(const U &value) noexcept : flags(static_cast(value)) {} + constexpr EnumFlag(const E &value) noexcept : flags(value) {} - auto operator=(const U &value) -> EnumFlag & { + constexpr auto operator=(const U &value) -> EnumFlag & { flags = static_cast(value); return *this; } - auto operator=(const E &value) -> EnumFlag & { + constexpr auto operator=(const E &value) -> EnumFlag & { flags = value; return *this; } - auto as_underlying_type() const -> U { return static_cast(flags); } - auto as_enum_type() const -> E { return flags; } + constexpr auto as_underlying_type() const -> U { + return static_cast(flags); + } + constexpr auto as_enum_type() const -> E { return flags; } /// `union` is reserved - auto unison(const EnumFlag &other) const -> EnumFlag { return this | other; } + constexpr auto unison(const EnumFlag &other) const -> EnumFlag { + return this | other; + } - auto intersection(const EnumFlag &other) const -> EnumFlag { + constexpr auto intersection(const EnumFlag &other) const -> EnumFlag { return *this & other; } - auto contains(const EnumFlag &other) const -> bool { + constexpr auto contains(const EnumFlag &other) const -> bool { return intersection(other).as_underlying_type() == other.as_underlying_type(); } - auto intersects(const EnumFlag &other) const -> bool { - return intersection().as_underlying_type() != 0; + constexpr auto intersects(const EnumFlag &other) const -> bool { + return intersection(other).as_underlying_type() != 0; } - auto add(const EnumFlag &other) -> EnumFlag & { + constexpr auto add(const EnumFlag &other) -> EnumFlag & { *this |= other; return *this; } - auto remove(const EnumFlag &other) -> EnumFlag & { + constexpr auto remove(const EnumFlag &other) -> EnumFlag & { *this &= ~other; return *this; } - operator U() const { return as_underlying_type(); } - operator E() const { return as_enum_type(); } + constexpr operator U() const { return as_underlying_type(); } + constexpr operator E() const { return as_enum_type(); } // auto operator==(const EnumFlag& other) const { // return as_underlying_type() == other.as_underlying_type(); // } - auto operator<=>(const EnumFlag &other) const { + constexpr auto operator<=>(const EnumFlag &other) const { return other.as_underlying_type() <=> other.as_underlying_type(); } // operator bool() const { return as_underlying_type() != 0; } - auto operator|=(const EnumFlag &other) { + constexpr auto operator|=(const EnumFlag &other) { flags = static_cast(as_underlying_type() | other.as_underlying_type()); } - auto operator|(const EnumFlag &other) const -> EnumFlag { + constexpr auto operator|(const EnumFlag &other) const -> EnumFlag { auto flag = *this; flag |= other; return flag; } - auto operator&=(const EnumFlag &other) { + constexpr auto operator&=(const EnumFlag &other) { flags = static_cast(as_underlying_type() & other.as_underlying_type()); } - auto operator&(const EnumFlag &other) const -> EnumFlag { + constexpr auto operator&(const EnumFlag &other) const -> EnumFlag { auto flag = *this; flag &= other; return flag; } - auto operator~() const -> EnumFlag { + constexpr auto operator~() const -> EnumFlag { return static_cast(~as_underlying_type()); } - auto operator^=(const EnumFlag &other) { + constexpr auto operator^=(const EnumFlag &other) { flags = static_cast(as_underlying_type() ^ other.as_underlying_type()); } - auto operator^(const EnumFlag &other) const -> EnumFlag { + constexpr auto operator^(const EnumFlag &other) const -> EnumFlag { auto flag = *this; flag ^= other;