251 lines
6.7 KiB
C++
251 lines
6.7 KiB
C++
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
|
|
|
#pragma once
|
|
#ifndef NV_CORE_BITARRAY_H
|
|
#define NV_CORE_BITARRAY_H
|
|
|
|
#include "nvcore.h"
|
|
#include "Array.inl"
|
|
|
|
namespace nv
|
|
{
|
|
|
|
// @@ Uh, this could be much faster.
|
|
inline uint countSetBits(uint32 x) {
|
|
uint count = 0;
|
|
for(; x != 0; x >>= 1) {
|
|
count += (x & 1);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
// @@ This is even more lame. What was I thinking?
|
|
inline uint countSetBits(uint32 x, int bits) {
|
|
uint count = 0;
|
|
for(; x != 0 && bits != 0; x >>= 1, bits--) {
|
|
count += (x & 1);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
// See "Conditionally set or clear bits without branching" at http://graphics.stanford.edu/~seander/bithacks.html
|
|
inline uint setBits(uint w, uint m, bool b) {
|
|
return (w & ~m) | (-int(b) & m);
|
|
}
|
|
|
|
|
|
|
|
// Simple bit array.
|
|
class BitArray
|
|
{
|
|
public:
|
|
|
|
BitArray() {}
|
|
BitArray(uint sz) {
|
|
resize(sz);
|
|
}
|
|
|
|
uint size() const { return m_size; }
|
|
void clear() { resize(0); }
|
|
|
|
void resize(uint new_size)
|
|
{
|
|
m_size = new_size;
|
|
m_wordArray.resize( (m_size + 31) >> 5 );
|
|
}
|
|
|
|
void resize(uint new_size, bool init)
|
|
{
|
|
//if (new_size == m_size) return;
|
|
|
|
uint old_size = m_size;
|
|
uint size_mod_32 = old_size & 31;
|
|
uint last_word_index = ((old_size + 31) >> 5) - 1;
|
|
uint mask = (1 << size_mod_32) - 1;
|
|
|
|
uint init_dword;
|
|
if (init) {
|
|
if (size_mod_32) m_wordArray[last_word_index] |= ~mask;
|
|
init_dword = ~0;
|
|
}
|
|
else {
|
|
if (size_mod_32) m_wordArray[last_word_index] &= mask;
|
|
init_dword = 0;
|
|
}
|
|
|
|
m_size = new_size;
|
|
m_wordArray.resize((new_size + 31) >> 5, init_dword);
|
|
|
|
// Make sure new bits are initialized correctly.
|
|
/*for (uint i = old_size; i < new_size; i++) {
|
|
nvCheck(bitAt(i) == init);
|
|
}*/
|
|
}
|
|
|
|
|
|
/// Get bit.
|
|
bool bitAt(uint b) const
|
|
{
|
|
nvDebugCheck( b < m_size );
|
|
return (m_wordArray[b >> 5] & (1 << (b & 31))) != 0;
|
|
}
|
|
|
|
// It may be useful to pack mulitple bit arrays together interleaving their bits.
|
|
uint bitsAt(uint idx, uint count) const
|
|
{
|
|
//nvDebugCheck(count == 2 || count == 4 || count == 8 || count == 16 || count == 32);
|
|
nvDebugCheck(count == 2); // @@ Hardcoded for two.
|
|
uint b = idx * count;
|
|
nvDebugCheck(b < m_size);
|
|
return (m_wordArray[b >> 5] & (0x3 << (b & 31))) >> (b & 31);
|
|
}
|
|
|
|
// It would be useful to have a function to set two bits simultaneously.
|
|
/*void setBitsAt(uint idx, uint count, uint bits) const
|
|
{
|
|
//nvDebugCheck(count == 2 || count == 4 || count == 8 || count == 16 || count == 32);
|
|
nvDebugCheck(count == 2); // @@ Hardcoded for two.
|
|
uint b = idx * count;
|
|
nvDebugCheck(b < m_size);
|
|
return (m_wordArray[b >> 5] & (0x3 << (b & 31))) >> (b & 31);
|
|
}*/
|
|
|
|
|
|
|
|
// Set a bit.
|
|
void setBitAt(uint idx)
|
|
{
|
|
nvDebugCheck(idx < m_size);
|
|
m_wordArray[idx >> 5] |= (1 << (idx & 31));
|
|
}
|
|
|
|
// Clear a bit.
|
|
void clearBitAt(uint idx)
|
|
{
|
|
nvDebugCheck(idx < m_size);
|
|
m_wordArray[idx >> 5] &= ~(1 << (idx & 31));
|
|
}
|
|
|
|
// Toggle a bit.
|
|
void toggleBitAt(uint idx)
|
|
{
|
|
nvDebugCheck(idx < m_size);
|
|
m_wordArray[idx >> 5] ^= (1 << (idx & 31));
|
|
}
|
|
|
|
// Set a bit to the given value. @@ Rename modifyBitAt?
|
|
void setBitAt(uint idx, bool b)
|
|
{
|
|
nvDebugCheck(idx < m_size);
|
|
m_wordArray[idx >> 5] = setBits(m_wordArray[idx >> 5], 1 << (idx & 31), b);
|
|
nvDebugCheck(bitAt(idx) == b);
|
|
}
|
|
|
|
void append(bool value)
|
|
{
|
|
resize(m_size + 1);
|
|
setBitAt(m_size - 1, value);
|
|
}
|
|
|
|
|
|
// Clear all the bits.
|
|
void clearAll()
|
|
{
|
|
memset(m_wordArray.buffer(), 0, m_wordArray.size() * sizeof(uint));
|
|
}
|
|
|
|
// Set all the bits.
|
|
void setAll()
|
|
{
|
|
memset(m_wordArray.buffer(), 0xFF, m_wordArray.size() * sizeof(uint));
|
|
}
|
|
|
|
// Toggle all the bits.
|
|
void toggleAll()
|
|
{
|
|
const uint wordCount = m_wordArray.count();
|
|
for(uint b = 0; b < wordCount; b++) {
|
|
m_wordArray[b] ^= 0xFFFFFFFF;
|
|
}
|
|
}
|
|
|
|
// Count the number of bits set.
|
|
uint countSetBits() const
|
|
{
|
|
const uint num = m_wordArray.size();
|
|
if( num == 0 ) {
|
|
return 0;
|
|
}
|
|
|
|
uint count = 0;
|
|
for(uint i = 0; i < num - 1; i++) {
|
|
count += nv::countSetBits(m_wordArray[i]);
|
|
}
|
|
count += nv::countSetBits(m_wordArray[num - 1], m_size & 31);
|
|
|
|
//piDebugCheck(count + countClearBits() == m_size);
|
|
return count;
|
|
}
|
|
|
|
// Count the number of bits clear.
|
|
uint countClearBits() const {
|
|
|
|
const uint num = m_wordArray.size();
|
|
if( num == 0 ) {
|
|
return 0;
|
|
}
|
|
|
|
uint count = 0;
|
|
for(uint i = 0; i < num - 1; i++) {
|
|
count += nv::countSetBits(~m_wordArray[i]);
|
|
}
|
|
count += nv::countSetBits(~m_wordArray[num - 1], m_size & 31);
|
|
|
|
//piDebugCheck(count + countSetBits() == m_size);
|
|
return count;
|
|
}
|
|
|
|
friend void swap(BitArray & a, BitArray & b)
|
|
{
|
|
swap(a.m_size, b.m_size);
|
|
swap(a.m_wordArray, b.m_wordArray);
|
|
}
|
|
|
|
void operator &= (const BitArray & other) {
|
|
if (other.m_size != m_size) {
|
|
resize(other.m_size);
|
|
}
|
|
|
|
const uint wordCount = m_wordArray.count();
|
|
for (uint i = 0; i < wordCount; i++) {
|
|
m_wordArray[i] &= other.m_wordArray[i];
|
|
}
|
|
}
|
|
|
|
void operator |= (const BitArray & other) {
|
|
if (other.m_size != m_size) {
|
|
resize(other.m_size);
|
|
}
|
|
|
|
const uint wordCount = m_wordArray.count();
|
|
for (uint i = 0; i < wordCount; i++) {
|
|
m_wordArray[i] |= other.m_wordArray[i];
|
|
}
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
// Number of bits stored.
|
|
uint m_size;
|
|
|
|
// Array of bits.
|
|
Array<uint> m_wordArray;
|
|
|
|
};
|
|
|
|
} // nv namespace
|
|
|
|
#endif // NV_CORE_BITARRAY_H
|
|
|