constexpr enum functions
This commit is contained in:
parent
1461f84141
commit
250dd20a6a
141
include/enum.hpp
141
include/enum.hpp
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue