//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // //===========================================================================// #ifndef BITVEC_H #define BITVEC_H #ifdef _WIN32 #pragma once #endif #include "tier0/dbg.h" #include "tier0/basetypes.h" class CBitVecAccessor { public: CBitVecAccessor(unsigned long *pDWords, int iBit); void operator=(int val); operator unsigned long(); private: unsigned long *m_pDWords; int m_iBit; }; // CBitVec allows you to store a list of bits and do operations on them like they were an atomic type. template class CBitVec { public: CBitVec(); // Get a pointer to the raw bits. unsigned long* Base(); // Set all values to the specified value (0 or 1..) void Init(int val = 0); // Access the bits like an array. CBitVecAccessor operator[](int i); // Clear or set all bits. void ClearAll( int nBits=NUM_BITS ); void SetAll( int nBits=NUM_BITS ); // Get the state of a bit. unsigned long Get( unsigned long iBit ) const; bool IsBitSet( unsigned long iBit ) const; // Set or clear a bit. void Set( unsigned long iBit ); void Clear( unsigned long iBit ); // Set a bit either on or off. void Set( unsigned long iBit, int bOn ); // Copy the state of another CBitVec. void Copy( CBitVec const &other, int nBits=NUM_BITS ); // Returns true if the bit vectors have the same values. bool Compare( CBitVec const &other, int nBits=NUM_BITS ); // Operations on other bit vectors. CBitVec& operator=(CBitVec const &other); bool operator==(CBitVec const &other); bool operator!=(CBitVec const &other); // Get underlying dword representations of the bits. int GetNumDWords() const; unsigned long GetDWord(int i) const; void SetDWord(int i, unsigned long val); int GetNumBits() const; int FindNextSetBit(int iStartBit) const; // returns -1 if no set bit was found private: enum {NUM_DWORDS = NUM_BITS/32 + !!(NUM_BITS & 31)}; unsigned long m_DWords[NUM_DWORDS]; }; // ------------------------------------------------------------------------ // // CBitVecAccessor inlines. // ------------------------------------------------------------------------ // inline CBitVecAccessor::CBitVecAccessor(unsigned long *pDWords, int iBit) { m_pDWords = pDWords; m_iBit = iBit; } inline void CBitVecAccessor::operator=(int val) { if(val) m_pDWords[m_iBit >> 5] |= (1 << (m_iBit & 31)); else m_pDWords[m_iBit >> 5] &= ~(unsigned long)(1 << (m_iBit & 31)); } inline CBitVecAccessor::operator unsigned long() { return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); } // ------------------------------------------------------------------------ // // CBitVec inlines. // ------------------------------------------------------------------------ // template inline int CBitVec::GetNumBits() const { return NUM_BITS; } template inline CBitVec::CBitVec() { for(int i=0; i < NUM_DWORDS; i++) m_DWords[i] = 0; } template inline void CBitVec::Init(int val) { unsigned long dwVal = val ? 0xFFFFFFFF : 0; for( int i=0; i < NUM_DWORDS; i++ ) m_DWords[i] = dwVal; } template inline unsigned long* CBitVec::Base() { return m_DWords; } template inline CBitVec& CBitVec::operator=(CBitVec const &other) { memcpy(m_DWords, other.m_DWords, sizeof(m_DWords)); return *this; } template inline CBitVecAccessor CBitVec::operator[](int i) { Assert(i >= 0 && i < GetNumBits()); return CBitVecAccessor(m_DWords, i); } template< int SIZE > inline void CBitVec::ClearAll( int nBits ) { int nDWords = PAD_NUMBER( nBits, 32 ) >> 5; Assert( nDWords <= NUM_DWORDS ); for( int i=0; i < nDWords; i++ ) m_DWords[i] = 0; } template< int SIZE > inline void CBitVec::SetAll( int nBits ) { int nDWords = PAD_NUMBER( nBits, 32 ) >> 5; Assert( nDWords <= NUM_DWORDS ); for( int i=0; i < nDWords; i++ ) m_DWords[i] = 0xFFFFFFFF; } template< int SIZE > inline unsigned long CBitVec::Get( unsigned long iBit ) const { Assert( iBit < SIZE ); return m_DWords[iBit >> 5] & (1 << (iBit & 31)); } template< int SIZE > bool CBitVec::IsBitSet( unsigned long iBit ) const { return ( m_DWords[iBit >> 5] & (1 << (iBit & 31)) ) != 0; } template< int SIZE > inline void CBitVec::Set( unsigned long iBit ) { Assert( iBit < SIZE ); m_DWords[iBit >> 5] |= (1 << (iBit & 31)); } template< int SIZE > inline void CBitVec::Clear( unsigned long iBit ) { Assert( iBit < SIZE ); m_DWords[iBit >> 5] &= ~(1 << (iBit & 31)); } template< int SIZE > inline void CBitVec::Set( unsigned long iBit, int bOn ) { if( bOn ) Set( iBit ); else Clear( iBit ); } template< int SIZE > inline void CBitVec::Copy( CBitVec const &other, int nBits ) { int nBytes = PAD_NUMBER( nBits, 8 ) >> 3; Assert( nBytes <= NUM_DWORDS*4 ); memcpy( m_DWords, other.m_DWords, nBytes ); } template< int SIZE > inline bool CBitVec::Compare( CBitVec const &other, int nBits ) { int nBytes = PAD_NUMBER( nBits, 8 ) >> 3; Assert( nBytes <= NUM_DWORDS*4 ); return memcmp( m_DWords, other.m_DWords, nBytes ) == 0; } template inline bool CBitVec::operator==(CBitVec const &other) { for(int i=0; i < NUM_DWORDS; i++) if(m_DWords[i] != other.m_DWords[i]) return false; return true; } template inline bool CBitVec::operator!=(CBitVec const &other) { return !(*this == other); } template inline int CBitVec::GetNumDWords() const { return NUM_DWORDS; } template inline unsigned long CBitVec::GetDWord(int i) const { Assert(i >= 0 && i < NUM_DWORDS); return m_DWords[i]; } template inline void CBitVec::SetDWord(int i, unsigned long val) { Assert(i >= 0 && i < NUM_DWORDS); m_DWords[i] = val; } template inline int CBitVec::FindNextSetBit(int iStartBit) const { int currentBit = iStartBit; while (currentBit < NUM_BITS) { // Early out for lots of zeros in a row // check for 32 bit boundary... if ( (currentBit & 31) == 0) { if (m_DWords[currentBit>>5] == 0) { currentBit += 32; continue; } } // One bit at a time...until we reach next DWord border do { if( m_DWords[currentBit >> 5] & (1 << (currentBit & 31)) ) return currentBit; // found a set bit ++currentBit; // next please } while ( (currentBit & 31) != 0 ); } return -1; // no bit set in rest of bit array } #endif // BITVEC_H