xenia-canary/third_party/crunch/crnlib/crn_sparse_bit_array.h

177 lines
4.7 KiB
C++

// File: crn_sparse_bit_array.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
class sparse_bit_array
{
public:
sparse_bit_array();
sparse_bit_array(uint size);
sparse_bit_array(sparse_bit_array& other);
~sparse_bit_array();
sparse_bit_array& operator= (sparse_bit_array& other);
void clear();
inline uint get_size() { return (m_num_groups << cBitsPerGroupShift); }
void resize(uint size);
sparse_bit_array& operator&= (const sparse_bit_array& other);
sparse_bit_array& operator|= (const sparse_bit_array& other);
sparse_bit_array& and_not(const sparse_bit_array& other);
void swap(sparse_bit_array& other);
void optimize();
void set_bit_range(uint index, uint num);
void clear_bit_range(uint index, uint num);
void clear_all_bits();
inline void set_bit(uint index)
{
uint group_index = index >> cBitsPerGroupShift;
CRNLIB_ASSERT(group_index < m_num_groups);
uint32* pGroup = m_ppGroups[group_index];
if (!pGroup)
{
pGroup = alloc_group(true);
m_ppGroups[group_index] = pGroup;
}
uint bit_ofs = index & (cBitsPerGroup - 1);
pGroup[bit_ofs >> 5] |= (1U << (bit_ofs & 31));
}
inline void clear_bit(uint index)
{
uint group_index = index >> cBitsPerGroupShift;
CRNLIB_ASSERT(group_index < m_num_groups);
uint32* pGroup = m_ppGroups[group_index];
if (!pGroup)
{
pGroup = alloc_group(true);
m_ppGroups[group_index] = pGroup;
}
uint bit_ofs = index & (cBitsPerGroup - 1);
pGroup[bit_ofs >> 5] &= (~(1U << (bit_ofs & 31)));
}
inline void set(uint index, bool value)
{
uint group_index = index >> cBitsPerGroupShift;
CRNLIB_ASSERT(group_index < m_num_groups);
uint32* pGroup = m_ppGroups[group_index];
if (!pGroup)
{
pGroup = alloc_group(true);
m_ppGroups[group_index] = pGroup;
}
uint bit_ofs = index & (cBitsPerGroup - 1);
uint bit = (1U << (bit_ofs & 31));
uint c = pGroup[bit_ofs >> 5];
uint mask = (uint)(-(int)value);
pGroup[bit_ofs >> 5] = (c & ~bit) | (mask & bit);
}
inline bool get_bit(uint index) const
{
uint group_index = index >> cBitsPerGroupShift;
CRNLIB_ASSERT(group_index < m_num_groups);
uint32* pGroup = m_ppGroups[group_index];
if (!pGroup)
return 0;
uint bit_ofs = index & (cBitsPerGroup - 1);
uint bit = (1U << (bit_ofs & 31));
return (pGroup[bit_ofs >> 5] & bit) != 0;
}
inline uint32 get_uint32(uint index) const
{
uint group_index = index >> cBitsPerGroupShift;
CRNLIB_ASSERT(group_index < m_num_groups);
uint32* pGroup = m_ppGroups[group_index];
if (!pGroup)
return 0;
uint bit_ofs = index & (cBitsPerGroup - 1);
return pGroup[bit_ofs >> 5];
}
inline void set_uint32(uint index, uint32 value) const
{
uint group_index = index >> cBitsPerGroupShift;
CRNLIB_ASSERT(group_index < m_num_groups);
uint32* pGroup = m_ppGroups[group_index];
if (!pGroup)
{
pGroup = alloc_group(true);
m_ppGroups[group_index] = pGroup;
}
uint bit_ofs = index & (cBitsPerGroup - 1);
pGroup[bit_ofs >> 5] = value;
}
int find_first_set_bit(uint index, uint num) const;
enum
{
cDWORDsPerGroupShift = 4U,
cDWORDsPerGroup = 1U << cDWORDsPerGroupShift,
cBitsPerGroupShift = cDWORDsPerGroupShift + 5,
cBitsPerGroup = 1U << cBitsPerGroupShift,
cBitsPerGroupMask = cBitsPerGroup - 1U,
cBytesPerGroup = cDWORDsPerGroup * sizeof(uint32)
};
uint get_num_groups() const { return m_num_groups; }
uint32** get_groups() { return m_ppGroups; }
private:
uint m_num_groups;
uint32** m_ppGroups;
static inline uint32* alloc_group(bool clear)
{
uint32* p = (uint32*)crnlib_malloc(cBytesPerGroup);
CRNLIB_VERIFY(p);
if (clear) memset(p, 0, cBytesPerGroup);
return p;
}
static inline void free_group(void* p)
{
if (p)
crnlib_free(p);
}
};
} // namespace crnlib