constexpr enum functions

This commit is contained in:
janis 2022-06-30 17:05:59 +01:00
parent 1461f84141
commit 250dd20a6a

View file

@ -4,55 +4,58 @@
#include <utility> #include <utility>
namespace util { namespace util {
namespace bitflag_operators {
template <typename E>
concept enum_type = std::is_enum_v<E>;
template <enum_type E> auto operator&(const E &rhs, const E &lhs) -> E {
return static_cast<E>(underlying_type_cast(rhs) & underlying_type_cast(lhs));
}
template <enum_type E> auto operator&=(E &rhs, const E &lhs) -> E & {
rhs = rhs & lhs;
return rhs;
}
template <enum_type E> auto operator|(const E &rhs, const E &lhs) -> E {
return static_cast<E>(underlying_type_cast(rhs) | underlying_type_cast(lhs));
}
template <enum_type E> auto operator|=(E &rhs, const E &lhs) -> E & {
rhs = rhs | lhs;
return rhs;
}
template <enum_type E> auto operator^(const E &rhs, const E &lhs) -> E {
return static_cast<E>(underlying_type_cast(rhs) ^ underlying_type_cast(lhs));
}
template <enum_type E> auto operator^=(E &rhs, const E &lhs) -> E & {
rhs = rhs ^ lhs;
return rhs;
}
template <enum_type E> auto operator~(const E &rhs) -> E {
return static_cast<E>(~underlying_type_cast(rhs));
}
template <enum_type E> auto is_empty(const E &value) -> bool {
return std::to_underlying(value) == 0;
}
} // namespace bitflag_operators
using bitflag_operators::enum_type;
template <typename E> template <typename E>
constexpr auto underlying_type_cast(const E &value) -> std::underlying_type_t<E> constexpr auto underlying_type_cast(const E &value) -> std::underlying_type_t<E>
requires std::is_enum_v<E> { requires std::is_enum_v<E> {
return static_cast<std::underlying_type_t<E>>(value); return static_cast<std::underlying_type_t<E>>(value);
} }
namespace bitflag_operators {
template <typename E>
concept enum_type = std::is_enum_v<E>;
template <enum_type E>
constexpr auto operator&(const E &rhs, const E &lhs) -> E {
return static_cast<E>(underlying_type_cast(rhs) & underlying_type_cast(lhs));
}
template <enum_type E> constexpr auto operator&=(E &rhs, const E &lhs) -> E & {
rhs = rhs & lhs;
return rhs;
}
template <enum_type E>
constexpr auto operator|(const E &rhs, const E &lhs) -> E {
return static_cast<E>(underlying_type_cast(rhs) | underlying_type_cast(lhs));
}
template <enum_type E> constexpr auto operator|=(E &rhs, const E &lhs) -> E & {
rhs = rhs | lhs;
return rhs;
}
template <enum_type E>
constexpr auto operator^(const E &rhs, const E &lhs) -> E {
return static_cast<E>(underlying_type_cast(rhs) ^ underlying_type_cast(lhs));
}
template <enum_type E> constexpr auto operator^=(E &rhs, const E &lhs) -> E & {
rhs = rhs ^ lhs;
return rhs;
}
template <enum_type E> constexpr auto operator~(const E &rhs) -> E {
return static_cast<E>(~underlying_type_cast(rhs));
}
template <enum_type E> constexpr auto is_empty(const E &value) -> bool {
return std::to_underlying(value) == 0;
}
} // namespace bitflag_operators
using bitflag_operators::enum_type;
template <typename E> template <typename E>
requires std::is_enum_v<E> requires std::is_enum_v<E>
@ -63,92 +66,96 @@ public:
using U = std::underlying_type_t<E>; using U = std::underlying_type_t<E>;
using value_type = U; using value_type = U;
EnumFlag() : flags(static_cast<E>(U(0))) {} constexpr EnumFlag() noexcept : flags(static_cast<E>(U(0))) {}
EnumFlag(const U &value) : flags(static_cast<E>(value)) {} constexpr EnumFlag(const U &value) noexcept : flags(static_cast<E>(value)) {}
EnumFlag(const E &value) : flags(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<E>(value); flags = static_cast<E>(value);
return *this; return *this;
} }
auto operator=(const E &value) -> EnumFlag & { constexpr auto operator=(const E &value) -> EnumFlag & {
flags = value; flags = value;
return *this; return *this;
} }
auto as_underlying_type() const -> U { return static_cast<U>(flags); } constexpr auto as_underlying_type() const -> U {
auto as_enum_type() const -> E { return flags; } return static_cast<U>(flags);
}
constexpr auto as_enum_type() const -> E { return flags; }
/// `union` is reserved /// `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; return *this & other;
} }
auto contains(const EnumFlag &other) const -> bool { constexpr auto contains(const EnumFlag &other) const -> bool {
return intersection(other).as_underlying_type() == return intersection(other).as_underlying_type() ==
other.as_underlying_type(); other.as_underlying_type();
} }
auto intersects(const EnumFlag &other) const -> bool { constexpr auto intersects(const EnumFlag &other) const -> bool {
return intersection().as_underlying_type() != 0; return intersection(other).as_underlying_type() != 0;
} }
auto add(const EnumFlag &other) -> EnumFlag & { constexpr auto add(const EnumFlag &other) -> EnumFlag & {
*this |= other; *this |= other;
return *this; return *this;
} }
auto remove(const EnumFlag &other) -> EnumFlag & { constexpr auto remove(const EnumFlag &other) -> EnumFlag & {
*this &= ~other; *this &= ~other;
return *this; return *this;
} }
operator U() const { return as_underlying_type(); } constexpr operator U() const { return as_underlying_type(); }
operator E() const { return as_enum_type(); } constexpr operator E() const { return as_enum_type(); }
// auto operator==(const EnumFlag& other) const { // auto operator==(const EnumFlag& other) const {
// return as_underlying_type() == other.as_underlying_type(); // 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(); return other.as_underlying_type() <=> other.as_underlying_type();
} }
// operator bool() const { return as_underlying_type() != 0; } // operator bool() const { return as_underlying_type() != 0; }
auto operator|=(const EnumFlag &other) { constexpr auto operator|=(const EnumFlag &other) {
flags = static_cast<E>(as_underlying_type() | other.as_underlying_type()); flags = static_cast<E>(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; auto flag = *this;
flag |= other; flag |= other;
return flag; return flag;
} }
auto operator&=(const EnumFlag &other) { constexpr auto operator&=(const EnumFlag &other) {
flags = static_cast<E>(as_underlying_type() & other.as_underlying_type()); flags = static_cast<E>(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; auto flag = *this;
flag &= other; flag &= other;
return flag; return flag;
} }
auto operator~() const -> EnumFlag { constexpr auto operator~() const -> EnumFlag {
return static_cast<E>(~as_underlying_type()); return static_cast<E>(~as_underlying_type());
} }
auto operator^=(const EnumFlag &other) { constexpr auto operator^=(const EnumFlag &other) {
flags = static_cast<E>(as_underlying_type() ^ other.as_underlying_type()); flags = static_cast<E>(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; auto flag = *this;
flag ^= other; flag ^= other;