//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Arbitrary length bit string // ** NOTE: This class does NOT override the bitwise operators // as doing so would require overriding the operators // to allocate memory for the returned bitstring. This method // would be prone to memory leaks as the calling party // would have to remember to delete the memory. Funtions // are used instead to require the calling party to allocate // and destroy their own memory // // $Workfile: $ // $Date: $ // //----------------------------------------------------------------------------- // $Log: $ // // $NoKeywords: $ //=============================================================================// #ifndef BITSTRING_H #define BITSTRING_H #pragma once class CUtlBuffer; //----------------------------------------------------------------------------- // OPTIMIZE: Removed the platform independence for speed #define LOG2_BITS_PER_INT 5 #define BITS_PER_INT 32 //------------------------------------- extern unsigned g_BitStringEndMasks[]; inline unsigned GetEndMask( int numBits ) { return g_BitStringEndMasks[numBits % BITS_PER_INT]; } inline int CalcNumIntsForBits( int numBits ) { return (numBits + (BITS_PER_INT-1)) / BITS_PER_INT; } void DebugPrintBitStringBits( const int *pInts, int nInts ); void SaveBitString(const int *pInts, int nInts, CUtlBuffer& buf); void LoadBitString(int *pInts, int nInts, CUtlBuffer& buf); #define BitString_Bit( bitNum ) ( 1 << ( (bitNum) & (BITS_PER_INT-1) ) ) #define BitString_Int( bitNum ) ( (bitNum) >> LOG2_BITS_PER_INT ) //----------------------------------------------------------------------------- // template CBitStringT // // Defines the operations relevant to any bit array. Simply requires a base // class that implements Size(), GetInts(), GetNumInts() & ValidateOperand() // // CBitString and CFixedBitString are the actual classes generally used // by clients // template class CBitStringT : public BASE_OPS { public: CBitStringT(); CBitStringT(int numBits); // Must be initialized with the number of bits // Do NOT override bitwise operators (see note in header) void And(const CBitStringT &andStr, CBitStringT *out) const; void Or(const CBitStringT &orStr, CBitStringT *out) const; void Xor(const CBitStringT &orStr, CBitStringT *out) const; void Not(CBitStringT *out) const; void Copy(CBitStringT *out) const; bool IsAllClear(void) const; // Are all bits zero? bool IsAllSet(void) const; // Are all bits one? bool GetBit( int bitNum ) const; void SetBit( int bitNum ); void ClearBit(int bitNum); void SetAllBits(void); // Sets all bits void ClearAllBits(void); // Clears all bits void DebugPrintBits(void) const; // For debugging void SaveBitString(CUtlBuffer& buf) const; void LoadBitString(CUtlBuffer& buf); }; //----------------------------------------------------------------------------- // class CVariableBitStringBase // // Defines the operations necessary for a variable sized bit array class CVariableBitStringBase { public: bool IsFixedSize() const { return false; } int Size(void) const { return m_numBits; } void Resize( int numBits ); // resizes bit array int GetNumInts() const { return m_numInts; } int * GetInts() { return m_pInt; } const int * GetInts() const { return m_pInt; } protected: CVariableBitStringBase(); CVariableBitStringBase(int numBits); CVariableBitStringBase( const CVariableBitStringBase &from ); CVariableBitStringBase &operator=( const CVariableBitStringBase &from ); ~CVariableBitStringBase(void); void ValidateOperand( const CVariableBitStringBase &operand ) const; unsigned GetEndMask() const { return ::GetEndMask( Size() ); } private: unsigned short m_numBits; // Number of bits in the bitstring unsigned short m_numInts; // Number of ints to needed to store bitstring int m_iBitStringStorage; // If the bit string fits in one int, it goes here int *m_pInt; // Array of ints containing the bitstring void AllocInts( int numInts ); // Free the allocated bits void ReallocInts( int numInts ); void FreeInts( void ); // Free the allocated bits }; //----------------------------------------------------------------------------- // class CFixedBitStringBase // // Defines the operations necessary for a fixed sized bit array. // template struct BitCountToEndMask_t { }; template <> struct BitCountToEndMask_t< 0> { enum { MASK = 0x00000000 }; }; template <> struct BitCountToEndMask_t< 1> { enum { MASK = 0xfffffffe }; }; template <> struct BitCountToEndMask_t< 2> { enum { MASK = 0xfffffffc }; }; template <> struct BitCountToEndMask_t< 3> { enum { MASK = 0xfffffff8 }; }; template <> struct BitCountToEndMask_t< 4> { enum { MASK = 0xfffffff0 }; }; template <> struct BitCountToEndMask_t< 5> { enum { MASK = 0xffffffe0 }; }; template <> struct BitCountToEndMask_t< 6> { enum { MASK = 0xffffffc0 }; }; template <> struct BitCountToEndMask_t< 7> { enum { MASK = 0xffffff80 }; }; template <> struct BitCountToEndMask_t< 8> { enum { MASK = 0xffffff00 }; }; template <> struct BitCountToEndMask_t< 9> { enum { MASK = 0xfffffe00 }; }; template <> struct BitCountToEndMask_t<10> { enum { MASK = 0xfffffc00 }; }; template <> struct BitCountToEndMask_t<11> { enum { MASK = 0xfffff800 }; }; template <> struct BitCountToEndMask_t<12> { enum { MASK = 0xfffff000 }; }; template <> struct BitCountToEndMask_t<13> { enum { MASK = 0xffffe000 }; }; template <> struct BitCountToEndMask_t<14> { enum { MASK = 0xffffc000 }; }; template <> struct BitCountToEndMask_t<15> { enum { MASK = 0xffff8000 }; }; template <> struct BitCountToEndMask_t<16> { enum { MASK = 0xffff0000 }; }; template <> struct BitCountToEndMask_t<17> { enum { MASK = 0xfffe0000 }; }; template <> struct BitCountToEndMask_t<18> { enum { MASK = 0xfffc0000 }; }; template <> struct BitCountToEndMask_t<19> { enum { MASK = 0xfff80000 }; }; template <> struct BitCountToEndMask_t<20> { enum { MASK = 0xfff00000 }; }; template <> struct BitCountToEndMask_t<21> { enum { MASK = 0xffe00000 }; }; template <> struct BitCountToEndMask_t<22> { enum { MASK = 0xffc00000 }; }; template <> struct BitCountToEndMask_t<23> { enum { MASK = 0xff800000 }; }; template <> struct BitCountToEndMask_t<24> { enum { MASK = 0xff000000 }; }; template <> struct BitCountToEndMask_t<25> { enum { MASK = 0xfe000000 }; }; template <> struct BitCountToEndMask_t<26> { enum { MASK = 0xfc000000 }; }; template <> struct BitCountToEndMask_t<27> { enum { MASK = 0xf8000000 }; }; template <> struct BitCountToEndMask_t<28> { enum { MASK = 0xf0000000 }; }; template <> struct BitCountToEndMask_t<29> { enum { MASK = 0xe0000000 }; }; template <> struct BitCountToEndMask_t<30> { enum { MASK = 0xc0000000 }; }; template <> struct BitCountToEndMask_t<31> { enum { MASK = 0x80000000 }; }; //------------------------------------- template class CFixedBitStringBase { public: bool IsFixedSize() const { return true; } int Size(void) const { return NUM_BITS; } void Resize( int numBits ) { Assert(numBits == NUM_BITS); }// for syntatic consistency (for when using templates) int GetNumInts() const { return NUM_INTS; } int * GetInts() { return m_Ints; } const int * GetInts() const { return m_Ints; } protected: CFixedBitStringBase() {} CFixedBitStringBase(int numBits) { Assert( numBits == NUM_BITS ); } // doesn't make sense, really. Supported to simplify templates & allow easy replacement of variable void ValidateOperand( const CFixedBitStringBase &operand ) const { } // no need, compiler does so statically public: // for test code unsigned GetEndMask() const { return static_cast( BitCountToEndMask_t::MASK ); } private: enum { NUM_INTS = (NUM_BITS + (BITS_PER_INT-1)) / BITS_PER_INT }; int m_Ints[(NUM_BITS + (BITS_PER_INT-1)) / BITS_PER_INT]; }; //----------------------------------------------------------------------------- // // The actual classes used // // inheritance instead of typedef to allow forward declarations class CBitString : public CBitStringT { public: CBitString() { } CBitString(int numBits) : CBitStringT(numBits) { } }; //----------------------------------------------------------------------------- template < int NUM_BITS > class CFixedBitString : public CBitStringT< CFixedBitStringBase > { public: CFixedBitString() { } CFixedBitString(int numBits) : CBitStringT< CFixedBitStringBase >(numBits) { } }; //----------------------------------------------------------------------------- inline CVariableBitStringBase::CVariableBitStringBase() { memset( this, 0, sizeof( *this ) ); } //----------------------------------------------------------------------------- inline CVariableBitStringBase::CVariableBitStringBase(int numBits) { Assert( numBits ); m_numBits = numBits; // Figure out how many ints are needed m_numInts = CalcNumIntsForBits( numBits ); m_pInt = NULL; AllocInts( m_numInts ); } //----------------------------------------------------------------------------- inline CVariableBitStringBase::CVariableBitStringBase( const CVariableBitStringBase &from ) { if ( from.m_numInts ) { m_numBits = from.m_numBits; m_numInts = from.m_numInts; m_pInt = NULL; AllocInts( m_numInts ); memcpy( m_pInt, from.m_pInt, m_numInts * sizeof(int) ); } else memset( this, 0, sizeof( *this ) ); } //----------------------------------------------------------------------------- inline CVariableBitStringBase &CVariableBitStringBase::operator=( const CVariableBitStringBase &from ) { Resize( from.Size() ); if ( m_pInt ) memcpy( m_pInt, from.m_pInt, m_numInts * sizeof(int) ); return (*this); } //----------------------------------------------------------------------------- // Purpose: Destructor // Input : // Output : //----------------------------------------------------------------------------- inline CVariableBitStringBase::~CVariableBitStringBase(void) { FreeInts(); } //----------------------------------------------------------------------------- template inline CBitStringT::CBitStringT() { // undef this is ints are not 4 bytes // generate a compile error if sizeof(int) is not 4 (HACK: can't use the preprocessor so use the compiler) COMPILE_TIME_ASSERT( sizeof(int)==4 ); // Initialize bitstring by clearing all bits ClearAllBits(); } //----------------------------------------------------------------------------- template inline CBitStringT::CBitStringT(int numBits) : BASE_OPS( numBits ) { // undef this is ints are not 4 bytes // generate a compile error if sizeof(int) is not 4 (HACK: can't use the preprocessor so use the compiler) COMPILE_TIME_ASSERT( sizeof(int)==4 ); // Initialize bitstring by clearing all bits ClearAllBits(); } //----------------------------------------------------------------------------- template inline bool CBitStringT::GetBit( int bitNum ) const { Assert( bitNum >= 0 && bitNum < Size() ); const int *pInt = GetInts() + BitString_Int( bitNum ); return ( ( *pInt & BitString_Bit( bitNum ) ) != 0 ); } //----------------------------------------------------------------------------- template inline void CBitStringT::SetBit( int bitNum ) { Assert( bitNum >= 0 && bitNum < Size() ); int *pInt = GetInts() + BitString_Int( bitNum ); *pInt |= BitString_Bit( bitNum ); } //----------------------------------------------------------------------------- template inline void CBitStringT::ClearBit(int bitNum) { Assert( bitNum >= 0 && bitNum < Size() ); int *pInt = GetInts() + BitString_Int( bitNum ); *pInt &= ~BitString_Bit( bitNum ); } //----------------------------------------------------------------------------- // Purpose: // Input : // Output : //----------------------------------------------------------------------------- template inline void CBitStringT::And(const CBitStringT &addStr, CBitStringT *out) const { ValidateOperand( addStr ); ValidateOperand( *out ); int * pDest = out->GetInts(); const int *pOperand1 = GetInts(); const int *pOperand2 = addStr.GetInts(); for (int i = GetNumInts() - 1; i >= 0 ; --i) { pDest[i] = pOperand1[i] & pOperand2[i]; } } //----------------------------------------------------------------------------- // Purpose: // Input : // Output : //----------------------------------------------------------------------------- template inline void CBitStringT::Or(const CBitStringT &orStr, CBitStringT *out) const { ValidateOperand( orStr ); ValidateOperand( *out ); int * pDest = out->GetInts(); const int *pOperand1 = GetInts(); const int *pOperand2 = orStr.GetInts(); for (int i = GetNumInts() - 1; i >= 0; --i) { pDest[i] = pOperand1[i] | pOperand2[i]; } } //----------------------------------------------------------------------------- // Purpose: // Input : // Output : //----------------------------------------------------------------------------- template inline void CBitStringT::Xor(const CBitStringT &xorStr, CBitStringT *out) const { int * pDest = out->GetInts(); const int *pOperand1 = GetInts(); const int *pOperand2 = xorStr.GetInts(); for (int i = GetNumInts() - 1; i >= 0; --i) { pDest[i] = pOperand1[i] ^ pOperand2[i]; } } //----------------------------------------------------------------------------- // Purpose: // Input : // Output : //----------------------------------------------------------------------------- template inline void CBitStringT::Not(CBitStringT *out) const { ValidateOperand( *out ); int * pDest = out->GetInts(); const int *pOperand = GetInts(); for (int i = GetNumInts() - 1; i >= 0; --i) { pDest[i] = ~(pOperand[i]); } } //----------------------------------------------------------------------------- // Purpose: Copy a bit string // Input : // Output : //----------------------------------------------------------------------------- template inline void CBitStringT::Copy(CBitStringT *out) const { ValidateOperand( *out ); Assert( out != this ); memcpy( out->GetInts(), GetInts(), GetNumInts() * sizeof( int ) ); } //----------------------------------------------------------------------------- // Purpose: Are all bits zero? // Input : // Output : //----------------------------------------------------------------------------- template inline bool CBitStringT::IsAllClear(void) const { // Number of available bits may be more than the number // actually used, so make sure to mask out unused bits // before testing for zero (const_cast(this))->GetInts()[GetNumInts()-1] &= ~CBitStringT::GetEndMask(); // external semantics of const retained for (int i = GetNumInts() - 1; i >= 0; --i) { if ( GetInts()[i] !=0 ) { return false; } } return true; } //----------------------------------------------------------------------------- // Purpose: Are all bits set? // Input : // Output : //----------------------------------------------------------------------------- template inline bool CBitStringT::IsAllSet(void) const { // Number of available bits may be more than the number // actually used, so make sure to mask out unused bits // before testing for set bits (const_cast(this))->GetInts()[GetNumInts()-1] |= CBitStringT::GetEndMask(); // external semantics of const retained for (int i = GetNumInts() - 1; i >= 0; --i) { if ( GetInts()[i] != ~0 ) { return false; } } return true; } //----------------------------------------------------------------------------- // Purpose: Sets all bits // Input : // Output : //----------------------------------------------------------------------------- template inline void CBitStringT::SetAllBits(void) { if ( GetInts() ) memset( GetInts(), 0xff, GetNumInts() * sizeof(int) ); } //----------------------------------------------------------------------------- // Purpose: Clears all bits // Input : // Output : //----------------------------------------------------------------------------- template inline void CBitStringT::ClearAllBits(void) { if ( GetInts() ) memset( GetInts(), 0, GetNumInts() * sizeof(int) ); } //----------------------------------------------------------------------------- template inline void CBitStringT::DebugPrintBits(void) const { (const_cast(this))->GetInts()[GetNumInts()-1] &= ~CBitStringT::GetEndMask(); // external semantics of const retained DebugPrintBitStringBits( GetInts(), GetNumInts() ); } //----------------------------------------------------------------------------- template inline void CBitStringT::SaveBitString(CUtlBuffer& buf) const { (const_cast(this))->GetInts()[GetNumInts()-1] &= ~CBitStringT::GetEndMask(); // external semantics of const retained ::SaveBitString( GetInts(), GetNumInts(), buf ); } //----------------------------------------------------------------------------- template inline void CBitStringT::LoadBitString(CUtlBuffer& buf) { (const_cast(this))->GetInts()[GetNumInts()-1] &= ~CBitStringT::GetEndMask(); ::LoadBitString( GetInts(), GetNumInts(), buf ); } //----------------------------------------------------------------------------- // @Note (toml 11-09-02): these methods are a nod to a heavy user of the // bit string, AI conditions. This assumes MAX_CONDITIONS == 128 template<> inline void CBitStringT< CFixedBitStringBase<128> >::And(const CBitStringT &addStr, CBitStringT *out) const { int * pDest = out->GetInts(); const int *pOperand1 = GetInts(); const int *pOperand2 = addStr.GetInts(); pDest[0] = pOperand1[0] & pOperand2[0]; pDest[1] = pOperand1[1] & pOperand2[1]; pDest[2] = pOperand1[2] & pOperand2[2]; pDest[3] = pOperand1[3] & pOperand2[3]; } template<> inline bool CBitStringT< CFixedBitStringBase<128> >::IsAllClear(void) const { const int *pInts = GetInts(); return ( pInts[0] == 0 && pInts[1] == 0 && pInts[2] == 0 && pInts[3] == 0 ); } template<> inline void CBitStringT< CFixedBitStringBase<128> >::Copy(CBitStringT *out) const { int * pDest = out->GetInts(); const int *pInts = GetInts(); pDest[0] = pInts[0]; pDest[1] = pInts[1]; pDest[2] = pInts[2]; pDest[3] = pInts[3]; } //============================================================================= #endif // BITSTRING_H