// 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