mirror of https://github.com/zeldaret/botw.git
150 lines
4.2 KiB
C++
150 lines
4.2 KiB
C++
#pragma once
|
|
|
|
#include <ore/Allocator.h>
|
|
#include <ore/Types.h>
|
|
|
|
namespace ore {
|
|
|
|
constexpr int PopCount(u32 x) {
|
|
x = x - ((x >> 1) & 0x55555555);
|
|
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
|
|
x = (x + (x >> 4)) & 0x0F0F0F0F;
|
|
x += (x >> 8);
|
|
x += (x >> 16);
|
|
return int(x & 0x3f);
|
|
}
|
|
|
|
constexpr int PopCount(u64 x) {
|
|
x = x - ((x >> 1) & 0x5555555555555555);
|
|
x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333);
|
|
x = (x + (x >> 4)) & 0x0F0F0F0F0F0F0F0F;
|
|
x += (x >> 8);
|
|
x += (x >> 16);
|
|
x += (x >> 32);
|
|
return int(x & 0x7f);
|
|
}
|
|
|
|
constexpr int CountTrailingZeros(u32 x) {
|
|
return PopCount((x & -x) - 1);
|
|
}
|
|
|
|
constexpr int CountTrailingZeros(u64 x) {
|
|
return PopCount((x & -x) - 1);
|
|
}
|
|
|
|
namespace detail {
|
|
template <typename T>
|
|
constexpr T AlignUpToPowerOf2(T val, int base) {
|
|
return val + base - 1 & static_cast<unsigned int>(-base);
|
|
}
|
|
} // namespace detail
|
|
|
|
class BitArray {
|
|
public:
|
|
using Word = size_t;
|
|
static constexpr int NumBitsPerWord = sizeof(Word) * 8;
|
|
static constexpr int ClearMask = ~(NumBitsPerWord - 1);
|
|
static constexpr int ShiftAmount = CountTrailingZeros(u32(NumBitsPerWord));
|
|
|
|
class TestIter {
|
|
public:
|
|
TestIter(const Word* start, const Word* end);
|
|
TestIter& operator++();
|
|
|
|
int operator*() const { return m_bit; }
|
|
bool operator==(const TestIter& other) const { return m_bit == other.m_bit; }
|
|
bool operator!=(const TestIter& other) const { return !operator==(other); }
|
|
|
|
private:
|
|
void SetInvalid() {
|
|
m_bit = -1;
|
|
m_current_word = nullptr;
|
|
m_last_word = nullptr;
|
|
m_next = 0;
|
|
}
|
|
|
|
int m_bit;
|
|
const Word* m_current_word;
|
|
const Word* m_last_word;
|
|
Word m_next;
|
|
};
|
|
|
|
/// Same as TestIter but clears bits after iterating over them.
|
|
class TestClearIter {
|
|
public:
|
|
TestClearIter(Word* start, Word* end);
|
|
TestClearIter& operator++();
|
|
int operator*() const { return m_bit; }
|
|
bool operator==(const TestClearIter& other) const { return m_bit == other.m_bit; }
|
|
bool operator!=(const TestClearIter& other) const { return !operator==(other); }
|
|
|
|
private:
|
|
void SetInvalid() {
|
|
m_bit = -1;
|
|
m_current_word = nullptr;
|
|
m_last_word = nullptr;
|
|
m_next = 0;
|
|
}
|
|
|
|
int m_bit;
|
|
Word* m_current_word;
|
|
Word* m_last_word;
|
|
Word m_next;
|
|
};
|
|
|
|
constexpr BitArray() = default;
|
|
constexpr BitArray(void* buffer, int num_bits) { SetData(buffer, num_bits); }
|
|
constexpr BitArray(ore::Allocator* allocator, int num_bits) {
|
|
AllocateBuffer(allocator, num_bits);
|
|
}
|
|
|
|
void SetData(void* buffer, int num_bits) {
|
|
m_words = reinterpret_cast<Word*>(buffer);
|
|
m_num_bits = num_bits;
|
|
}
|
|
|
|
void AllocateBuffer(ore::Allocator* allocator, int num_bits) {
|
|
SetData(allocator->New(GetRequiredBufferSize(num_bits)), num_bits);
|
|
SetAllOff();
|
|
}
|
|
|
|
void FreeBufferIfNeeded(ore::Allocator* allocator) {
|
|
if (m_words)
|
|
allocator->Delete(m_words);
|
|
}
|
|
|
|
void FreeBuffer(ore::Allocator* allocator) { allocator->Delete(m_words); }
|
|
|
|
bool Test(int bit) const {
|
|
return (GetWord(bit) & (Word(1) << (Word(bit) % NumBitsPerWord))) != 0;
|
|
}
|
|
void Set(int bit) { GetWord(bit) |= Word(1) << (Word(bit) % NumBitsPerWord); }
|
|
void Clear(int bit) { GetWord(bit) &= ~(Word(1) << (Word(bit) % NumBitsPerWord)); }
|
|
|
|
void SetAllOn();
|
|
void SetAllOff();
|
|
TestIter BeginTest() const;
|
|
TestIter EndTest() const;
|
|
TestClearIter BeginTestClear();
|
|
TestClearIter EndTestClear();
|
|
|
|
static int GetRequiredBufferSize(int num_bits) {
|
|
return sizeof(Word) * (detail::AlignUpToPowerOf2(num_bits, NumBitsPerWord) >> ShiftAmount);
|
|
}
|
|
|
|
private:
|
|
Word& GetWord(int bit) const { return m_words[bit >> ShiftAmount]; }
|
|
int GetNumWords() const { return int((m_num_bits + NumBitsPerWord - 1) >> ShiftAmount); }
|
|
|
|
void Fill(int num, Word value) {
|
|
auto* it = m_words;
|
|
for (int i = num - 1; i >= 0; --i)
|
|
*it++ = value;
|
|
}
|
|
|
|
Word* m_words{};
|
|
int m_num_bits{};
|
|
};
|
|
|
|
} // namespace ore
|