Files
chatterino2/src/common/FlagsEnum.hpp

151 lines
3.9 KiB
C++

#pragma once
#include <concepts>
#include <type_traits>
namespace chatterino {
template <typename T>
requires std::is_enum_v<T>
class FlagsEnum
{
public:
using Int = std::underlying_type_t<T>;
constexpr FlagsEnum() noexcept = default;
constexpr FlagsEnum(std::convertible_to<T> auto... flags) noexcept
: value_(
static_cast<T>((static_cast<Int>(static_cast<T>(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<T> auto... flags) noexcept
{
this->value_ =
static_cast<T>(static_cast<Int>(this->value_) |
(static_cast<Int>(static_cast<T>(flags)) | ...));
}
/** Adds the flags from `flags` in this enum. */
constexpr void set(FlagsEnum flags) noexcept
{
this->value_ = static_cast<T>(static_cast<Int>(this->value_) |
static_cast<Int>(flags.value_));
}
constexpr void unset(std::convertible_to<T> auto... flags) noexcept
{
this->value_ =
static_cast<T>(static_cast<Int>(this->value_) &
~(static_cast<Int>(static_cast<T>(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<T>(static_cast<Int>(this->value_) |
static_cast<Int>(flag));
}
constexpr FlagsEnum operator|(FlagsEnum rhs) const noexcept
{
return static_cast<T>(static_cast<Int>(this->value_) |
static_cast<Int>(rhs.value_));
}
constexpr bool has(T flag) const noexcept
{
return static_cast<Int>(this->value_) & static_cast<Int>(flag);
}
constexpr bool hasAny(FlagsEnum flags) const noexcept
{
return (static_cast<Int>(this->value_) &
static_cast<Int>(flags.value_)) != 0;
}
constexpr bool hasAny(std::convertible_to<T> auto... flags) const noexcept
{
return this->hasAny(FlagsEnum{flags...});
}
constexpr bool hasAll(FlagsEnum flags) const noexcept
{
return (static_cast<Int>(this->value_) &
static_cast<Int>(flags.value_)) ==
static_cast<Int>(flags.value_);
}
constexpr bool hasAll(std::convertible_to<T> auto... flags) const noexcept
{
return this->hasAll(FlagsEnum{flags...});
}
constexpr bool hasNone(FlagsEnum flags) const noexcept
{
return (static_cast<Int>(this->value_) &
static_cast<Int>(flags.value_)) == 0;
}
constexpr bool hasNone() const noexcept = delete;
constexpr bool hasNone(std::convertible_to<T> 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<Int>(this->value_) == 0;
}
constexpr T value() const noexcept
{
return this->value_;
}
private:
T value_{};
};
} // namespace chatterino