#pragma once #include #include namespace chatterino { template requires std::is_enum_v class FlagsEnum { public: using Int = std::underlying_type_t; constexpr FlagsEnum() noexcept = default; constexpr FlagsEnum(std::convertible_to auto... flags) noexcept : value_( static_cast((static_cast(static_cast(flags)) | ...))) { } friend constexpr bool operator==(FlagsEnum lhs, FlagsEnum rhs) noexcept { return lhs.value_ == rhs.value_; } friend constexpr bool operator!=(FlagsEnum lhs, FlagsEnum rhs) noexcept { return lhs.value_ != rhs.value_; } friend constexpr bool operator==(FlagsEnum lhs, T rhs) noexcept { return lhs.value_ == rhs; } friend constexpr bool operator!=(FlagsEnum lhs, T rhs) noexcept { return lhs.value_ != rhs; } friend constexpr bool operator==(T lhs, FlagsEnum rhs) noexcept { return lhs == rhs.value_; } friend constexpr bool operator!=(T lhs, FlagsEnum rhs) noexcept { return lhs != rhs.value_; } constexpr void set(std::convertible_to auto... flags) noexcept { this->value_ = static_cast(static_cast(this->value_) | (static_cast(static_cast(flags)) | ...)); } /** Adds the flags from `flags` in this enum. */ constexpr void set(FlagsEnum flags) noexcept { this->value_ = static_cast(static_cast(this->value_) | static_cast(flags.value_)); } constexpr void unset(std::convertible_to auto... flags) noexcept { this->value_ = static_cast(static_cast(this->value_) & ~(static_cast(static_cast(flags)) | ...)); } constexpr void set(T flag, bool value) noexcept { if (value) { this->set(flag); } else { this->unset(flag); } } constexpr FlagsEnum operator|(T flag) const noexcept { return static_cast(static_cast(this->value_) | static_cast(flag)); } constexpr FlagsEnum operator|(FlagsEnum rhs) const noexcept { return static_cast(static_cast(this->value_) | static_cast(rhs.value_)); } constexpr bool has(T flag) const noexcept { return static_cast(this->value_) & static_cast(flag); } constexpr bool hasAny(FlagsEnum flags) const noexcept { return (static_cast(this->value_) & static_cast(flags.value_)) != 0; } constexpr bool hasAny(std::convertible_to auto... flags) const noexcept { return this->hasAny(FlagsEnum{flags...}); } constexpr bool hasAll(FlagsEnum flags) const noexcept { return (static_cast(this->value_) & static_cast(flags.value_)) == static_cast(flags.value_); } constexpr bool hasAll(std::convertible_to auto... flags) const noexcept { return this->hasAll(FlagsEnum{flags...}); } constexpr bool hasNone(FlagsEnum flags) const noexcept { return (static_cast(this->value_) & static_cast(flags.value_)) == 0; } constexpr bool hasNone() const noexcept = delete; constexpr bool hasNone(std::convertible_to auto... flags) const noexcept { return this->hasNone(FlagsEnum{flags...}); } /// Returns true if the enum has no flag set (i.e. its underlying value is 0) constexpr bool isEmpty() const noexcept { return static_cast(this->value_) == 0; } constexpr T value() const noexcept { return this->value_; } private: T value_{}; }; } // namespace chatterino