// File: crn_sparse_bit_array.h // See Copyright Notice and license at the end of inc/crnlib.h #include "crn_core.h" #include "crn_sparse_bit_array.h" namespace crnlib { sparse_bit_array::sparse_bit_array() : m_num_groups(0), m_ppGroups(NULL) { } sparse_bit_array::sparse_bit_array(uint size) : m_num_groups(0), m_ppGroups(NULL) { resize(size); } sparse_bit_array::sparse_bit_array(sparse_bit_array& other) { m_num_groups = other.m_num_groups; m_ppGroups = (uint32**)crnlib_malloc(m_num_groups * sizeof(uint32*)); CRNLIB_VERIFY(m_ppGroups); for (uint i = 0; i < m_num_groups; i++) { if (other.m_ppGroups[i]) { m_ppGroups[i] = alloc_group(false); memcpy(m_ppGroups[i], other.m_ppGroups[i], cBytesPerGroup); } else m_ppGroups[i] = NULL; } } sparse_bit_array::~sparse_bit_array() { clear(); } sparse_bit_array& sparse_bit_array::operator= (sparse_bit_array& other) { if (this == &other) return *this; if (m_num_groups != other.m_num_groups) { clear(); m_num_groups = other.m_num_groups; m_ppGroups = (uint32**)crnlib_calloc(m_num_groups, sizeof(uint32*)); CRNLIB_VERIFY(m_ppGroups); } for (uint i = 0; i < m_num_groups; i++) { if (other.m_ppGroups[i]) { if (!m_ppGroups[i]) m_ppGroups[i] = alloc_group(false); memcpy(m_ppGroups[i], other.m_ppGroups[i], cBytesPerGroup); } else if (m_ppGroups[i]) { free_group(m_ppGroups[i]); m_ppGroups[i] = NULL; } } return *this; } void sparse_bit_array::clear() { if (!m_num_groups) return; for (uint i = 0; i < m_num_groups; i++) free_group(m_ppGroups[i]); crnlib_free(m_ppGroups); m_ppGroups = NULL; m_num_groups = 0; } void sparse_bit_array::swap(sparse_bit_array& other) { utils::swap(m_ppGroups, other.m_ppGroups); utils::swap(m_num_groups, other.m_num_groups); } void sparse_bit_array::optimize() { for (uint i = 0; i < m_num_groups; i++) { uint32* s = m_ppGroups[i]; if (s) { uint j; for (j = 0; j < cDWORDsPerGroup; j++) if (s[j]) break; if (j == cDWORDsPerGroup) { free_group(s); m_ppGroups[i] = NULL; } } } } void sparse_bit_array::set_bit_range(uint index, uint num) { CRNLIB_ASSERT((index + num) <= (m_num_groups << cBitsPerGroupShift)); if (!num) return; else if (num == 1) { set_bit(index); return; } while ((index & cBitsPerGroupMask) || (num <= cBitsPerGroup)) { 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; } const uint group_bit_ofs = index & cBitsPerGroupMask; const uint dword_bit_ofs = group_bit_ofs & 31; const uint max_bits_to_set = 32 - dword_bit_ofs; const uint bits_to_set = math::minimum(max_bits_to_set, num); const uint32 msk = (0xFFFFFFFFU >> (32 - bits_to_set)); pGroup[group_bit_ofs >> 5] |= (msk << dword_bit_ofs); num -= bits_to_set; if (!num) return; index += bits_to_set; } while (num >= cBitsPerGroup) { 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; } memset(pGroup, 0xFF, sizeof(uint32) * cDWORDsPerGroup); num -= cBitsPerGroup; index += cBitsPerGroup; } while (num) { 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 group_bit_ofs = index & cBitsPerGroupMask; uint bits_to_set = math::minimum(32U, num); uint32 msk = (0xFFFFFFFFU >> (32 - bits_to_set)); pGroup[group_bit_ofs >> 5] |= (msk << (group_bit_ofs & 31)); num -= bits_to_set; index += bits_to_set; } } void sparse_bit_array::clear_all_bits() { for (uint i = 0; i < m_num_groups; i++) { uint32* pGroup = m_ppGroups[i]; if (pGroup) memset(pGroup, 0, sizeof(uint32) * cDWORDsPerGroup); } } void sparse_bit_array::clear_bit_range(uint index, uint num) { CRNLIB_ASSERT((index + num) <= (m_num_groups << cBitsPerGroupShift)); if (!num) return; else if (num == 1) { clear_bit(index); return; } while ((index & cBitsPerGroupMask) || (num <= cBitsPerGroup)) { uint group_index = index >> cBitsPerGroupShift; CRNLIB_ASSERT(group_index < m_num_groups); const uint group_bit_ofs = index & cBitsPerGroupMask; const uint dword_bit_ofs = group_bit_ofs & 31; const uint max_bits_to_set = 32 - dword_bit_ofs; const uint bits_to_set = math::minimum(max_bits_to_set, num); uint32* pGroup = m_ppGroups[group_index]; if (pGroup) { const uint32 msk = (0xFFFFFFFFU >> (32 - bits_to_set)); pGroup[group_bit_ofs >> 5] &= (~(msk << dword_bit_ofs)); } num -= bits_to_set; if (!num) return; index += bits_to_set; } while (num >= cBitsPerGroup) { uint group_index = index >> cBitsPerGroupShift; CRNLIB_ASSERT(group_index < m_num_groups); uint32* pGroup = m_ppGroups[group_index]; if (pGroup) { free_group(pGroup); m_ppGroups[group_index] = NULL; } num -= cBitsPerGroup; index += cBitsPerGroup; } while (num) { uint group_index = index >> cBitsPerGroupShift; CRNLIB_ASSERT(group_index < m_num_groups); uint bits_to_set = math::minimum(32u, num); uint32* pGroup = m_ppGroups[group_index]; if (pGroup) { uint group_bit_ofs = index & cBitsPerGroupMask; uint32 msk = (0xFFFFFFFFU >> (32 - bits_to_set)); pGroup[group_bit_ofs >> 5] &= (~(msk << (group_bit_ofs & 31))); } num -= bits_to_set; index += bits_to_set; } } void sparse_bit_array::resize(uint size) { uint num_groups = (size + cBitsPerGroup - 1) >> cBitsPerGroupShift; if (num_groups == m_num_groups) return; if (!num_groups) { clear(); return; } sparse_bit_array temp; temp.swap(*this); m_num_groups = num_groups; m_ppGroups = (uint32**)crnlib_calloc(m_num_groups, sizeof(uint32*)); CRNLIB_VERIFY(m_ppGroups); uint n = math::minimum(temp.m_num_groups, m_num_groups); for (uint i = 0; i < n; i++) { uint32* p = temp.m_ppGroups[i]; if (p) { m_ppGroups[i] = temp.m_ppGroups[i]; temp.m_ppGroups[i] = NULL; } } } sparse_bit_array& sparse_bit_array::operator&= (const sparse_bit_array& other) { if (this == &other) return *this; CRNLIB_VERIFY(other.m_num_groups == m_num_groups); for (uint i = 0; i < m_num_groups; i++) { uint32* d = m_ppGroups[i]; if (!d) continue; uint32* s = other.m_ppGroups[i]; if (!s) { free_group(d); m_ppGroups[i] = NULL; } else { uint32 oc = 0; for (uint j = 0; j < cDWORDsPerGroup; j++) { uint32 c = d[j] & s[j]; d[j] = c; oc |= c; } if (!oc) { free_group(d); m_ppGroups[i] = NULL; } } } return *this; } sparse_bit_array& sparse_bit_array::operator|= (const sparse_bit_array& other) { if (this == &other) return *this; CRNLIB_VERIFY(other.m_num_groups == m_num_groups); for (uint i = 0; i < m_num_groups; i++) { uint32* s = other.m_ppGroups[i]; if (!s) continue; uint32* d = m_ppGroups[i]; if (!d) { d = alloc_group(true); m_ppGroups[i] = d; memcpy(d, s, cBytesPerGroup); } else { uint32 oc = 0; for (uint j = 0; j < cDWORDsPerGroup; j++) { uint32 c = d[j] | s[j]; d[j] = c; oc |= c; } if (!oc) { free_group(d); m_ppGroups[i] = NULL; } } } return *this; } sparse_bit_array& sparse_bit_array::and_not(const sparse_bit_array& other) { if (this == &other) return *this; CRNLIB_VERIFY(other.m_num_groups == m_num_groups); for (uint i = 0; i < m_num_groups; i++) { uint32* d = m_ppGroups[i]; if (!d) continue; uint32* s = other.m_ppGroups[i]; if (!s) continue; uint32 oc = 0; for (uint j = 0; j < cDWORDsPerGroup; j++) { uint32 c = d[j] & (~s[j]); d[j] = c; oc |= c; } if (!oc) { free_group(d); m_ppGroups[i] = NULL; } } return *this; } int sparse_bit_array::find_first_set_bit(uint index, uint num) const { CRNLIB_ASSERT((index + num) <= (m_num_groups << cBitsPerGroupShift)); if (!num) return -1; while ((index & cBitsPerGroupMask) || (num <= cBitsPerGroup)) { uint group_index = index >> cBitsPerGroupShift; CRNLIB_ASSERT(group_index < m_num_groups); const uint group_bit_ofs = index & cBitsPerGroupMask; const uint dword_bit_ofs = group_bit_ofs & 31; const uint max_bits_to_examine = 32 - dword_bit_ofs; const uint bits_to_examine = math::minimum(max_bits_to_examine, num); uint32* pGroup = m_ppGroups[group_index]; if (pGroup) { const uint32 msk = (0xFFFFFFFFU >> (32 - bits_to_examine)); uint bits = pGroup[group_bit_ofs >> 5] & (msk << dword_bit_ofs); if (bits) { uint num_trailing_zeros = math::count_trailing_zero_bits(bits); int set_index = num_trailing_zeros + (index & ~31); CRNLIB_ASSERT(get_bit(set_index)); return set_index; } } num -= bits_to_examine; if (!num) return -1; index += bits_to_examine; } while (num >= cBitsPerGroup) { uint group_index = index >> cBitsPerGroupShift; CRNLIB_ASSERT(group_index < m_num_groups); uint32* pGroup = m_ppGroups[group_index]; if (pGroup) { for (uint i = 0; i < cDWORDsPerGroup; i++) { uint32 bits = pGroup[i]; if (bits) { uint num_trailing_zeros = math::count_trailing_zero_bits(bits); int set_index = num_trailing_zeros + index + (i << 5); CRNLIB_ASSERT(get_bit(set_index)); return set_index; } } } num -= cBitsPerGroup; index += cBitsPerGroup; } while (num) { uint group_index = index >> cBitsPerGroupShift; CRNLIB_ASSERT(group_index < m_num_groups); uint bits_to_examine = math::minimum(32U, num); uint32* pGroup = m_ppGroups[group_index]; if (pGroup) { uint group_bit_ofs = index & cBitsPerGroupMask; uint32 msk = (0xFFFFFFFFU >> (32 - bits_to_examine)); uint32 bits = pGroup[group_bit_ofs >> 5] & (msk << (group_bit_ofs & 31)); if (bits) { uint num_trailing_zeros = math::count_trailing_zero_bits(bits); int set_index = num_trailing_zeros + (index & ~31); CRNLIB_ASSERT(get_bit(set_index)); return set_index; } } num -= bits_to_examine; index += bits_to_examine; } return -1; } } // namespace crnlib