#pragma once #include #include #include #include #include namespace sead { template > class TypedLongBitFlag { public: using Word = Storage; using RawWord = std::conditional_t<(sizeof(Storage) > 4), u64, u32>; void makeAllZero() { mStorage.fill(0); } void makeAllOne() { mStorage.fill(~Word(0)); } Word& getWord(Enum bit); const Word& getWord(Enum bit) const; bool isZero() const; void setBit(Enum bit); void resetBit(Enum bit); void changeBit(Enum bit, bool on); void toggleBit(Enum bit); bool isOnBit(Enum bit) const; bool isOffBit(Enum bit) const; /// Popcount. int countOnBit() const; protected: template auto getWord(Enum bit, const T& fn) { return fn(getWord(bit), RawWord(bit) % BitsPerWord); } template auto getWord(Enum bit, const T& fn) const { return fn(getWord(bit), RawWord(bit) % BitsPerWord); } static constexpr s32 BitsPerWord = 8 * sizeof(Word); static constexpr s32 Shift = log2(BitsPerWord); static_assert(N % BitsPerWord == 0, "N must be a multiple of the number of bits per word"); std::array mStorage{}; }; template inline typename TypedLongBitFlag::Word& TypedLongBitFlag::getWord(Enum bit) { SEAD_ASSERT_MSG(u32(bit) < u32(N), "range over [0,%d) : %d", N, s32(bit)); return mStorage[s32(bit) >> Shift]; } template inline const typename TypedLongBitFlag::Word& TypedLongBitFlag::getWord(Enum bit) const { SEAD_ASSERT_MSG(u32(bit) < u32(N), "range over [0,%d) : %d", N, s32(bit)); return mStorage[s32(bit) >> Shift]; } template inline void TypedLongBitFlag::setBit(Enum bit) { getWord(bit, [](auto& word, auto b) { word |= 1 << b; }); } template inline void TypedLongBitFlag::resetBit(Enum bit) { getWord(bit, [](auto& word, auto b) { word &= ~(1 << b); }); } template inline void TypedLongBitFlag::changeBit(Enum bit, bool on) { if (on) setBit(bit); else resetBit(bit); } template inline void TypedLongBitFlag::toggleBit(Enum bit) { getWord(bit, [](auto& word, auto b) { word ^= 1 << b; }); } template inline bool TypedLongBitFlag::isOnBit(Enum bit) const { return getWord(bit, [](const auto& word, auto b) { return word & (1 << b); }); } template inline bool TypedLongBitFlag::isOffBit(Enum bit) const { return !isOnBit(bit); } template inline bool TypedLongBitFlag::isZero() const { for (const auto& word : mStorage) { if (word != 0) return false; } return true; } template inline int TypedLongBitFlag::countOnBit() const { // This is pretty inefficient, but it appears to be how popcount is implemented // in Lunchpack's Lp::Sys::ActorSystem::countActiveChildNum. s32 count = 0; for (s32 i = 0; i < N; ++i) { if (isOnBit(i)) ++count; } return count; } } // namespace sead