120 lines
3.4 KiB
C
120 lines
3.4 KiB
C
|
#pragma once
|
||
|
|
||
|
#include <initializer_list>
|
||
|
#include <type_traits>
|
||
|
|
||
|
#include "prim/seadBitFlag.h"
|
||
|
|
||
|
namespace sead
|
||
|
{
|
||
|
template <typename Enum, typename Storage = std::underlying_type_t<Enum>>
|
||
|
class TypedBitFlag
|
||
|
{
|
||
|
public:
|
||
|
static_assert(std::is_enum<Enum>(), "Enum must be an enum");
|
||
|
using UnderlyingType = std::underlying_type_t<Enum>;
|
||
|
|
||
|
TypedBitFlag() : mBits(0) {}
|
||
|
explicit TypedBitFlag(UnderlyingType bits) : mBits(bits) {}
|
||
|
TypedBitFlag(Enum bits) : mBits(UnderlyingType(bits)) {}
|
||
|
template <typename T>
|
||
|
explicit TypedBitFlag(const TypedBitFlag<Enum, T>& other)
|
||
|
{
|
||
|
*this = other;
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
TypedBitFlag& operator=(const TypedBitFlag<Enum, T>& other)
|
||
|
{
|
||
|
mBits = other.getDirect();
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
TypedBitFlag& operator=(Enum value)
|
||
|
{
|
||
|
setDirect(value);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
void makeAllZero() { mBits = 0; }
|
||
|
void makeAllOne() { mBits = ~UnderlyingType(0); }
|
||
|
|
||
|
void setDirect(UnderlyingType bits) { mBits = bits; }
|
||
|
void setDirect(Enum bits) { mBits = UnderlyingType(bits); }
|
||
|
UnderlyingType getDirect() const { return mBits; }
|
||
|
Storage& getStorage() { return mBits; }
|
||
|
|
||
|
bool set(Enum val)
|
||
|
{
|
||
|
const auto mask = UnderlyingType(val);
|
||
|
return ((mBits |= mask) & mask) == 0;
|
||
|
}
|
||
|
|
||
|
bool reset(Enum val)
|
||
|
{
|
||
|
const auto mask = UnderlyingType(val);
|
||
|
return ((mBits &= ~mask) & mask) != 0;
|
||
|
}
|
||
|
|
||
|
UnderlyingType toggle(Enum val) { mBits ^= UnderlyingType(val); }
|
||
|
bool change(Enum val, bool on) { return on ? set(val) : reset(val); }
|
||
|
bool isZero() const { return mBits == 0; }
|
||
|
/// Checks if (at least) one of the bits are set.
|
||
|
bool isOn(Enum val) const { return (mBits & UnderlyingType(val)) != 0; }
|
||
|
bool isAnyOn(std::initializer_list<Enum> list) const { return (mBits & orEnums_(list)) != 0; }
|
||
|
/// Checks if all of the bits are set.
|
||
|
bool isOnAll(Enum val) const { return (mBits & UnderlyingType(val)) == UnderlyingType(val); }
|
||
|
bool isOff(Enum val) const { return !isOn(val); }
|
||
|
|
||
|
bool testAndClear(Enum val)
|
||
|
{
|
||
|
if (!isOn(val))
|
||
|
return false;
|
||
|
reset(val);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/// Popcount.
|
||
|
int countOnBit() const
|
||
|
{
|
||
|
if constexpr (sizeof(UnderlyingType) <= 4)
|
||
|
return BitFlagUtil::countOnBit(mBits);
|
||
|
else
|
||
|
return BitFlagUtil::countOnBit64(mBits);
|
||
|
}
|
||
|
/// Count trailing zeroes.
|
||
|
int countContinuousOffBitFromRight() const
|
||
|
{
|
||
|
if constexpr (sizeof(UnderlyingType) <= 4)
|
||
|
return BitFlagUtil::countContinuousOffBitFromRight(mBits);
|
||
|
else
|
||
|
return BitFlagUtil::countContinuousOffBitFromRight64(mBits);
|
||
|
}
|
||
|
int countRightOnBit(int bit) const
|
||
|
{
|
||
|
if constexpr (sizeof(UnderlyingType) <= 4)
|
||
|
return BitFlagUtil::countRightOnBit(mBits, bit);
|
||
|
else
|
||
|
return BitFlagUtil::countRightOnBit64(mBits, bit);
|
||
|
}
|
||
|
int findOnBitFromRight(int num) const
|
||
|
{
|
||
|
if constexpr (sizeof(UnderlyingType) <= 4)
|
||
|
return BitFlagUtil::findOnBitFromRight(mBits, num);
|
||
|
else
|
||
|
return BitFlagUtil::findOnBitFromRight64(mBits, num);
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
static constexpr UnderlyingType orEnums_(std::initializer_list<Enum> list)
|
||
|
{
|
||
|
UnderlyingType value{};
|
||
|
for (auto x : list)
|
||
|
value |= static_cast<UnderlyingType>(x);
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
Storage mBits;
|
||
|
};
|
||
|
} // namespace sead
|