mirror of
https://github.com/ValveSoftware/GameNetworkingSockets.git
synced 2026-05-29 16:20:34 +00:00
Delete hashmap and bitstring files.
They are only used by the SDR connection source files, which aren't part of the opensource distribution.
This commit is contained in:
@@ -133,8 +133,6 @@ sources = [
|
||||
'tier0/cpu.cpp',
|
||||
'tier0/dbg.cpp',
|
||||
'tier0/platformtime.cpp',
|
||||
'tier1/bitstring.cpp',
|
||||
'tier1/generichash.cpp',
|
||||
'tier1/netadr.cpp',
|
||||
'tier1/utlbuffer.cpp',
|
||||
'tier1/utlmemory.cpp',
|
||||
|
||||
@@ -1,584 +0,0 @@
|
||||
//========= 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<int> are the actual classes generally used
|
||||
// by clients
|
||||
//
|
||||
|
||||
template <class BASE_OPS>
|
||||
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_numInts == 1 ? &m_iBitStringStorage : m_pInt; }
|
||||
const int * GetInts() const { return m_numInts == 1 ? &m_iBitStringStorage : m_pInt; }
|
||||
|
||||
void Validate( class CValidator &validator, const char *pchName );
|
||||
|
||||
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:
|
||||
|
||||
int m_numBits; // Number of bits in the bitstring
|
||||
int 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 <int bits> 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 <int NUM_BITS>
|
||||
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<NUM_BITS> &operand ) const { } // no need, compiler does so statically
|
||||
|
||||
public: // for test code
|
||||
unsigned GetEndMask() const { return static_cast<unsigned>( BitCountToEndMask_t<NUM_BITS % BITS_PER_INT>::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<CVariableBitStringBase>
|
||||
{
|
||||
public:
|
||||
CBitString()
|
||||
{
|
||||
}
|
||||
|
||||
CBitString(int numBits)
|
||||
: CBitStringT<CVariableBitStringBase>(numBits)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template < int NUM_BITS >
|
||||
class CFixedBitString : public CBitStringT< CFixedBitStringBase<NUM_BITS> >
|
||||
{
|
||||
public:
|
||||
CFixedBitString()
|
||||
{
|
||||
}
|
||||
|
||||
CFixedBitString(int numBits)
|
||||
: CBitStringT< CFixedBitStringBase<NUM_BITS> >(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( GetInts(), from.GetInts(), m_numInts * sizeof(int) );
|
||||
}
|
||||
else
|
||||
memset( this, 0, sizeof( *this ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline CVariableBitStringBase &CVariableBitStringBase::operator=( const CVariableBitStringBase &from )
|
||||
{
|
||||
Resize( from.Size() );
|
||||
if ( GetInts() )
|
||||
memcpy( GetInts(), from.GetInts(), m_numInts * sizeof(int) );
|
||||
return (*this);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline CVariableBitStringBase::~CVariableBitStringBase(void)
|
||||
{
|
||||
FreeInts();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <class BASE_OPS>
|
||||
inline CBitStringT<BASE_OPS>::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 <class BASE_OPS>
|
||||
inline CBitStringT<BASE_OPS>::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 <class BASE_OPS>
|
||||
inline bool CBitStringT<BASE_OPS>::GetBit( int bitNum ) const
|
||||
{
|
||||
Assert( bitNum >= 0 && bitNum < this->Size() );
|
||||
const int *pInt = this->GetInts() + BitString_Int( bitNum );
|
||||
return ( ( *pInt & BitString_Bit( bitNum ) ) != 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <class BASE_OPS>
|
||||
inline void CBitStringT<BASE_OPS>::SetBit( int bitNum )
|
||||
{
|
||||
Assert( bitNum >= 0 && bitNum < this->Size() );
|
||||
int *pInt = this->GetInts() + BitString_Int( bitNum );
|
||||
*pInt |= BitString_Bit( bitNum );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <class BASE_OPS>
|
||||
inline void CBitStringT<BASE_OPS>::ClearBit(int bitNum)
|
||||
{
|
||||
Assert( bitNum >= 0 && bitNum < this->Size() );
|
||||
int *pInt = this->GetInts() + BitString_Int( bitNum );
|
||||
*pInt &= ~BitString_Bit( bitNum );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class BASE_OPS>
|
||||
inline void CBitStringT<BASE_OPS>::And(const CBitStringT &addStr, CBitStringT *out) const
|
||||
{
|
||||
ValidateOperand( addStr );
|
||||
ValidateOperand( *out );
|
||||
|
||||
int * pDest = out->GetInts();
|
||||
const int *pOperand1 = this->GetInts();
|
||||
const int *pOperand2 = addStr.GetInts();
|
||||
|
||||
for (int i = this->GetNumInts() - 1; i >= 0 ; --i)
|
||||
{
|
||||
pDest[i] = pOperand1[i] & pOperand2[i];
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class BASE_OPS>
|
||||
inline void CBitStringT<BASE_OPS>::Or(const CBitStringT &orStr, CBitStringT *out) const
|
||||
{
|
||||
ValidateOperand( orStr );
|
||||
ValidateOperand( *out );
|
||||
|
||||
int * pDest = out->GetInts();
|
||||
const int *pOperand1 = this->GetInts();
|
||||
const int *pOperand2 = orStr.GetInts();
|
||||
|
||||
for (int i = this->GetNumInts() - 1; i >= 0; --i)
|
||||
{
|
||||
pDest[i] = pOperand1[i] | pOperand2[i];
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class BASE_OPS>
|
||||
inline void CBitStringT<BASE_OPS>::Xor(const CBitStringT &xorStr, CBitStringT *out) const
|
||||
{
|
||||
int * pDest = out->GetInts();
|
||||
const int *pOperand1 = this->GetInts();
|
||||
const int *pOperand2 = xorStr.GetInts();
|
||||
|
||||
for (int i = this->GetNumInts() - 1; i >= 0; --i)
|
||||
{
|
||||
pDest[i] = pOperand1[i] ^ pOperand2[i];
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class BASE_OPS>
|
||||
inline void CBitStringT<BASE_OPS>::Not(CBitStringT *out) const
|
||||
{
|
||||
ValidateOperand( *out );
|
||||
|
||||
int * pDest = out->GetInts();
|
||||
const int *pOperand = this->GetInts();
|
||||
|
||||
for (int i = this->GetNumInts() - 1; i >= 0; --i)
|
||||
{
|
||||
pDest[i] = ~(pOperand[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Copy a bit string
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class BASE_OPS>
|
||||
inline void CBitStringT<BASE_OPS>::Copy(CBitStringT *out) const
|
||||
{
|
||||
ValidateOperand( *out );
|
||||
Assert( out != this );
|
||||
|
||||
memcpy( out->GetInts(), this->GetInts(), this->GetNumInts() * sizeof( int ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Are all bits zero?
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class BASE_OPS>
|
||||
inline bool CBitStringT<BASE_OPS>::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<CBitStringT *>(this))->GetInts()[this->GetNumInts()-1] &= ~CBitStringT<BASE_OPS>::GetEndMask(); // external semantics of const retained
|
||||
|
||||
for (int i = this->GetNumInts() - 1; i >= 0; --i)
|
||||
{
|
||||
if ( this->GetInts()[i] !=0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Are all bits set?
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class BASE_OPS>
|
||||
inline bool CBitStringT<BASE_OPS>::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<CBitStringT *>(this))->GetInts()[this->GetNumInts()-1] |= CBitStringT<BASE_OPS>::GetEndMask(); // external semantics of const retained
|
||||
|
||||
for (int i = this->GetNumInts() - 1; i >= 0; --i)
|
||||
{
|
||||
if ( this->GetInts()[i] != ~0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets all bits
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class BASE_OPS>
|
||||
inline void CBitStringT<BASE_OPS>::SetAllBits(void)
|
||||
{
|
||||
if ( this->GetInts() )
|
||||
memset( this->GetInts(), 0xff, this->GetNumInts() * sizeof(int) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Clears all bits
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class BASE_OPS>
|
||||
inline void CBitStringT<BASE_OPS>::ClearAllBits(void)
|
||||
{
|
||||
if ( this->GetInts() )
|
||||
memset( this->GetInts(), 0, this->GetNumInts() * sizeof(int) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <class BASE_OPS>
|
||||
inline void CBitStringT<BASE_OPS>::DebugPrintBits(void) const
|
||||
{
|
||||
(const_cast<CBitStringT *>(this))->GetInts()[this->GetNumInts()-1] &= ~CBitStringT<BASE_OPS>::GetEndMask(); // external semantics of const retained
|
||||
DebugPrintBitStringBits( this->GetInts(), this->GetNumInts() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <class BASE_OPS>
|
||||
inline void CBitStringT<BASE_OPS>::SaveBitString(CUtlBuffer& buf) const
|
||||
{
|
||||
(const_cast<CBitStringT *>(this))->GetInts()[this->GetNumInts()-1] &= ~CBitStringT<BASE_OPS>::GetEndMask(); // external semantics of const retained
|
||||
::SaveBitString( this->GetInts(), this->GetNumInts(), buf );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <class BASE_OPS>
|
||||
inline void CBitStringT<BASE_OPS>::LoadBitString(CUtlBuffer& buf)
|
||||
{
|
||||
(const_cast<CBitStringT *>(this))->GetInts()[this->GetNumInts()-1] &= ~CBitStringT<BASE_OPS>::GetEndMask();
|
||||
::LoadBitString( this->GetInts(), this->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 = this->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 = this->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
|
||||
@@ -1,980 +0,0 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. =================//
|
||||
//
|
||||
// Purpose: index-based hash map container
|
||||
// Use FOR_EACH_HASHMAP to iterate through CUtlHashMap.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef UTLHASHMAP_H
|
||||
#define UTLHASHMAP_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/bitstring.h"
|
||||
#include "tier1/generichash.h"
|
||||
//SDR_PUBLIC #include "tier1/utlstring.h"
|
||||
#include "tier1/utliterator.h"
|
||||
#include "tier1/utlvector.h"
|
||||
|
||||
#define FOR_EACH_HASHMAP( mapName, iteratorName ) \
|
||||
for ( int iteratorName = 0; iteratorName < (mapName).MaxElement(); ++iteratorName ) if ( !(mapName).IsValidIndex( iteratorName ) ) continue; else
|
||||
|
||||
// default comparison operator
|
||||
template <typename T>
|
||||
class CDefEquals
|
||||
{
|
||||
public:
|
||||
CDefEquals() {}
|
||||
CDefEquals( int i ) {}
|
||||
inline bool operator()( const T &lhs, const T &rhs ) const { return ( lhs == rhs ); }
|
||||
inline bool operator!() const { return false; }
|
||||
};
|
||||
|
||||
|
||||
// Specialization to compare pointers
|
||||
template <typename T>
|
||||
class CDefEquals<T*>
|
||||
{
|
||||
public:
|
||||
CDefEquals() {}
|
||||
CDefEquals( int i ) {}
|
||||
inline bool operator()( const T *lhs, const T *rhs ) const
|
||||
{
|
||||
if ( lhs == rhs )
|
||||
return true;
|
||||
else if ( NULL == lhs || NULL == rhs )
|
||||
return false;
|
||||
else
|
||||
return ( *lhs == *rhs );
|
||||
}
|
||||
inline bool operator!() const { return false; }
|
||||
};
|
||||
|
||||
// Specialization to compare VOID pointers AS pointers
|
||||
template <>
|
||||
class CDefEquals<void*>
|
||||
{
|
||||
public:
|
||||
CDefEquals() {}
|
||||
CDefEquals( int i ) {}
|
||||
inline bool operator()( const void *lhs, const void *rhs ) const
|
||||
{
|
||||
return ( lhs == rhs );
|
||||
}
|
||||
inline bool operator!() const { return false; }
|
||||
};
|
||||
|
||||
// Specialization to compare char * AS strings
|
||||
template <>
|
||||
class CDefEquals<const char *>
|
||||
{
|
||||
public:
|
||||
CDefEquals() {}
|
||||
CDefEquals( int i ) {}
|
||||
inline bool operator()( const char *lhs, const char *rhs ) const
|
||||
{
|
||||
return ( V_strcmp( lhs, rhs ) == 0 );
|
||||
}
|
||||
inline bool operator!() const { return false; }
|
||||
};
|
||||
|
||||
//SDR_PUBLIC // Specialization to compare char * AS strings
|
||||
//SDR_PUBLIC template <>
|
||||
//SDR_PUBLIC class CDefEquals < CUtlString >
|
||||
//SDR_PUBLIC {
|
||||
//SDR_PUBLIC public:
|
||||
//SDR_PUBLIC CDefEquals() {}
|
||||
//SDR_PUBLIC CDefEquals( int i ) {}
|
||||
//SDR_PUBLIC inline bool operator()( CUtlString lhs, CUtlString rhs ) const
|
||||
//SDR_PUBLIC {
|
||||
//SDR_PUBLIC return (V_strcmp( lhs.String(), rhs.String() ) == 0);
|
||||
//SDR_PUBLIC }
|
||||
//SDR_PUBLIC inline bool operator!() const { return false; }
|
||||
//SDR_PUBLIC };
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Case insensitive const char * comparison
|
||||
//-----------------------------------------------------------------------------
|
||||
class CDefCaselessStringEquals
|
||||
{
|
||||
public:
|
||||
CDefCaselessStringEquals() {}
|
||||
CDefCaselessStringEquals( int i ) {}
|
||||
inline bool operator()( const char *lhs, const char *rhs ) const
|
||||
{
|
||||
return ( V_stricmp( lhs, rhs ) == 0 );
|
||||
}
|
||||
inline bool operator!() const { return false; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Purpose: An associative container. Pretty much identical to CUtlMap without the ability to walk in-order
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L = CDefEquals<K>, typename H = HashFunctor<K> >
|
||||
class CUtlHashMap
|
||||
{
|
||||
public:
|
||||
typedef K KeyType_t;
|
||||
typedef T ElemType_t;
|
||||
typedef int IndexType_t;
|
||||
typedef L EqualityFunc_t;
|
||||
typedef H HashFunc_t;
|
||||
|
||||
CUtlHashMap()
|
||||
{
|
||||
m_cElements = 0;
|
||||
m_nMaxElement = 0;
|
||||
m_nMinRehashedBucket = InvalidIndex();
|
||||
m_nMaxRehashedBucket = InvalidIndex();
|
||||
m_iNodeFreeListHead = InvalidIndex();
|
||||
}
|
||||
|
||||
CUtlHashMap( int cElementsExpected )
|
||||
{
|
||||
m_cElements = 0;
|
||||
m_nMaxElement = 0;
|
||||
m_nMinRehashedBucket = InvalidIndex();
|
||||
m_nMaxRehashedBucket = InvalidIndex();
|
||||
m_iNodeFreeListHead = InvalidIndex();
|
||||
EnsureCapacity( cElementsExpected );
|
||||
}
|
||||
|
||||
~CUtlHashMap()
|
||||
{
|
||||
Purge();
|
||||
}
|
||||
|
||||
void CopyFullHashMap( CUtlHashMap< K, T, L, H > &target ) const
|
||||
{
|
||||
target.RemoveAll();
|
||||
FOR_EACH_HASHMAP( *this, i )
|
||||
{
|
||||
target.Insert( this->Key( i ), this->Element( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
// gets particular elements
|
||||
ElemType_t & Element( IndexType_t i ) { return m_memNodes.Element( i ).m_elem; }
|
||||
const ElemType_t & Element( IndexType_t i ) const { return m_memNodes.Element( i ).m_elem; }
|
||||
ElemType_t & operator[]( IndexType_t i ) { return m_memNodes.Element( i ).m_elem; }
|
||||
const ElemType_t & operator[]( IndexType_t i ) const { return m_memNodes.Element( i ).m_elem; }
|
||||
KeyType_t & Key( IndexType_t i ) { return m_memNodes.Element( i ).m_key; }
|
||||
const KeyType_t & Key( IndexType_t i ) const { return m_memNodes.Element( i ).m_key; }
|
||||
|
||||
// Num elements
|
||||
IndexType_t Count() const { return m_cElements; }
|
||||
|
||||
// Max "size" of the vector
|
||||
IndexType_t MaxElement() const { return m_nMaxElement; }
|
||||
|
||||
// Checks if a node is valid and in the map
|
||||
bool IsValidIndex( IndexType_t i ) const { return i >= 0 && i < m_nMaxElement && !IsFreeNodeID( m_memNodes[i].m_iNextNode ); }
|
||||
|
||||
// Invalid index
|
||||
static IndexType_t InvalidIndex() { return -1; }
|
||||
|
||||
// Insert method
|
||||
IndexType_t Insert( const KeyType_t &key ) { return InsertOrReplace( key ); }
|
||||
IndexType_t Insert( const KeyType_t &key, const ElemType_t &insert ) { return InsertOrReplace( key, insert ); }
|
||||
IndexType_t InsertOrReplace( const KeyType_t &key );
|
||||
IndexType_t InsertOrReplace( const KeyType_t &key, const ElemType_t &insert );
|
||||
IndexType_t InsertWithDupes( const KeyType_t &key, const ElemType_t &insert );
|
||||
|
||||
// Find-or-insert method, one-arg - can insert default-constructed element
|
||||
// when there is no available copy constructor or assignment operator
|
||||
IndexType_t FindOrInsert( const KeyType_t &key );
|
||||
|
||||
// Find-or-insert method, two-arg - can insert an element when there is no
|
||||
// copy constructor for the type (but does require assignment operator)
|
||||
IndexType_t FindOrInsert( const KeyType_t &key, const ElemType_t &insert );
|
||||
|
||||
// Finds an element
|
||||
IndexType_t Find( const KeyType_t &key ) const;
|
||||
|
||||
// Finds an exact key/value match, even with duplicate keys. Requires operator== for ElemType_t.
|
||||
IndexType_t FindExact( const KeyType_t &key, const ElemType_t &elem ) const;
|
||||
|
||||
// Find next element with same key
|
||||
IndexType_t NextSameKey( IndexType_t i ) const;
|
||||
|
||||
// has an element
|
||||
bool HasElement( const KeyType_t &key ) const { return Find( key ) != InvalidIndex(); }
|
||||
|
||||
void EnsureCapacity( int num );
|
||||
|
||||
const ElemType_t &FindElement( const KeyType_t &key, const ElemType_t &defaultValue ) const
|
||||
{
|
||||
IndexType_t i = Find( key );
|
||||
if ( i == InvalidIndex() )
|
||||
return defaultValue;
|
||||
return Element( i );
|
||||
}
|
||||
|
||||
void RemoveAt( IndexType_t i );
|
||||
bool Remove( const KeyType_t &key )
|
||||
{
|
||||
int iMap = Find( key );
|
||||
if ( iMap != InvalidIndex() )
|
||||
{
|
||||
RemoveAt( iMap );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void RemoveAll();
|
||||
void Purge();
|
||||
|
||||
// call delete on each element (as a pointer) and then purge
|
||||
void PurgeAndDeleteElements()
|
||||
{
|
||||
FOR_EACH_HASHMAP( *this, i )
|
||||
delete this->Element(i);
|
||||
Purge();
|
||||
}
|
||||
|
||||
void Swap( CUtlHashMap< K, T, L, H > &that );
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
void Validate( CValidator &validator, const char *pchName );
|
||||
void ValidateSelfAndElements( CValidator &validator, const char *pchName );
|
||||
void ValidateSelfAndKeys( CValidator& validator, const char* pchName );
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
|
||||
protected:
|
||||
IndexType_t InsertUnconstructed( const KeyType_t &key, IndexType_t *pExistingIndex, bool bAllowDupes );
|
||||
|
||||
inline IndexType_t FreeNodeIDToIndex( IndexType_t i ) const { return (0-i)-3; }
|
||||
inline IndexType_t FreeNodeIndexToID( IndexType_t i ) const { return (-3)-i; }
|
||||
inline bool IsFreeNodeID( IndexType_t i ) const { return i < InvalidIndex(); }
|
||||
|
||||
int FindInBucket( int iBucket, const KeyType_t &key ) const;
|
||||
int AllocNode();
|
||||
void RehashNodesInBucket( int iBucket );
|
||||
void LinkNodeIntoBucket( int iBucket, int iNewNode );
|
||||
void UnlinkNodeFromBucket( int iBucket, int iNewNode );
|
||||
bool RemoveNodeFromBucket( int iBucket, int iNodeToRemove );
|
||||
void IncrementalRehash();
|
||||
|
||||
struct HashBucket_t
|
||||
{
|
||||
IndexType_t m_iNode;
|
||||
};
|
||||
CUtlVector<HashBucket_t> m_vecHashBuckets;
|
||||
|
||||
CBitString m_bitsMigratedBuckets;
|
||||
|
||||
// DO NOT CHANGE Node_t WITHOUT MODIFYING IteratorNode_t INSIDE THE IteratorProxyAlias CLASS!
|
||||
struct Node_t
|
||||
{
|
||||
KeyType_t m_key;
|
||||
ElemType_t m_elem;
|
||||
int m_iNextNode;
|
||||
};
|
||||
// DO NOT CHANGE Node_t WITHOUT MODIFYING IteratorNode_t INSIDE THE IteratorProxyAlias CLASS!
|
||||
|
||||
CUtlMemory<Node_t> m_memNodes;
|
||||
IndexType_t m_iNodeFreeListHead;
|
||||
|
||||
public:
|
||||
// STL / C++11-style iterators (unspecified / in-memory order!)
|
||||
struct IterateKeyElemProxyAlias
|
||||
{
|
||||
// Define a compatible type that uses the same key,elem names as CUtlMap.
|
||||
// This will be pointer-aliased to the Node_t elements of m_memNodes!
|
||||
struct IteratorNode_t
|
||||
{
|
||||
K key;
|
||||
T elem;
|
||||
};
|
||||
typedef IteratorNode_t ElemType_t;
|
||||
typedef typename CUtlHashMap::IndexType_t IndexType_t;
|
||||
|
||||
typedef CUtlForwardIteratorImplT< IterateKeyElemProxyAlias, false > iterator;
|
||||
typedef CUtlForwardIteratorImplT< IterateKeyElemProxyAlias, true > const_iterator;
|
||||
|
||||
ElemType_t & Element( IndexType_t i ) { return *reinterpret_cast<IteratorNode_t*>( &reinterpret_cast<CUtlHashMap*>(this)->m_memNodes.Element( i ) ); }
|
||||
const ElemType_t & Element( IndexType_t i ) const { return *reinterpret_cast<const IteratorNode_t*>( &reinterpret_cast<const CUtlHashMap*>(this)->m_memNodes.Element( i ) ); }
|
||||
IndexType_t IteratorNext( IndexType_t i ) const { auto pSelf = reinterpret_cast<const CUtlHashMap*>(this); while ( ++i < pSelf->MaxElement() ) { if ( pSelf->IsValidIndex( i ) ) return i; } return -1; }
|
||||
|
||||
iterator begin() { return iterator( this, IteratorNext( -1 ) ); }
|
||||
iterator end() { return iterator( this, -1 ); }
|
||||
const_iterator begin() const { return const_iterator( this, IteratorNext( -1 ) ); }
|
||||
const_iterator end() const { return const_iterator( this, -1 ); }
|
||||
};
|
||||
|
||||
friend struct IterateKeyElemProxyAlias;
|
||||
|
||||
typedef CUtlForwardIteratorImplT< IterateKeyElemProxyAlias, false > iterator;
|
||||
typedef CUtlForwardIteratorImplT< IterateKeyElemProxyAlias, true > const_iterator;
|
||||
iterator begin() { return reinterpret_cast<IterateKeyElemProxyAlias*>(this)->begin(); }
|
||||
iterator end() { return reinterpret_cast<IterateKeyElemProxyAlias*>(this)->end(); }
|
||||
const_iterator begin() const { return reinterpret_cast<const IterateKeyElemProxyAlias*>(this)->begin(); }
|
||||
const_iterator end() const { return reinterpret_cast<const IterateKeyElemProxyAlias*>(this)->end(); }
|
||||
|
||||
protected:
|
||||
IndexType_t m_cElements;
|
||||
IndexType_t m_nMaxElement;
|
||||
IndexType_t m_nMinRehashedBucket, m_nMaxRehashedBucket;
|
||||
EqualityFunc_t m_EqualityFunc;
|
||||
HashFunc_t m_HashFunc;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: inserts a key into the map with an unconstructed element member
|
||||
// (to be copy constructed or default-constructed by a wrapper function)
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMap<K,T,L,H>::InsertUnconstructed( const KeyType_t &key, int *piNodeExistingIfDupe, bool bAllowDupes )
|
||||
{
|
||||
// make sure we have room in the hash table
|
||||
if ( m_cElements >= m_vecHashBuckets.Count() )
|
||||
EnsureCapacity( MAX( 16, m_vecHashBuckets.Count() * 2 ) );
|
||||
if ( m_cElements >= m_memNodes.Count() )
|
||||
m_memNodes.Grow( m_memNodes.Count() * 2 );
|
||||
|
||||
// rehash incrementally
|
||||
IncrementalRehash();
|
||||
|
||||
// hash the item
|
||||
auto hash = m_HashFunc( key );
|
||||
|
||||
// migrate data forward, if necessary
|
||||
int cBucketsToModAgainst = m_vecHashBuckets.Count() >> 1;
|
||||
int iBucket = basetypes::ModPowerOf2(hash, cBucketsToModAgainst);
|
||||
while ( iBucket >= m_nMinRehashedBucket
|
||||
&& !m_bitsMigratedBuckets.GetBit( iBucket ) )
|
||||
{
|
||||
RehashNodesInBucket( iBucket );
|
||||
cBucketsToModAgainst >>= 1;
|
||||
iBucket = basetypes::ModPowerOf2(hash, cBucketsToModAgainst);
|
||||
}
|
||||
|
||||
// return existing node without insert, if duplicates are not permitted
|
||||
if ( !bAllowDupes && m_cElements )
|
||||
{
|
||||
// look in the bucket to see if we have a conflict
|
||||
int iBucket2 = basetypes::ModPowerOf2( hash, m_vecHashBuckets.Count() );
|
||||
IndexType_t iNode = FindInBucket( iBucket2, key );
|
||||
if ( piNodeExistingIfDupe )
|
||||
{
|
||||
*piNodeExistingIfDupe = iNode;
|
||||
}
|
||||
if ( iNode != InvalidIndex() )
|
||||
{
|
||||
return InvalidIndex();
|
||||
}
|
||||
}
|
||||
|
||||
// make an item
|
||||
int iNewNode = AllocNode();
|
||||
m_memNodes[iNewNode].m_iNextNode = InvalidIndex();
|
||||
CopyConstruct( &m_memNodes[iNewNode].m_key, key );
|
||||
// Note: m_elem remains intentionally unconstructed here
|
||||
|
||||
iBucket = basetypes::ModPowerOf2( hash, m_vecHashBuckets.Count() );
|
||||
|
||||
// link ourselves in
|
||||
// ::OutputDebugStr( CFmtStr( "insert %d into bucket %d\n", key, iBucket ).Access() );
|
||||
LinkNodeIntoBucket( iBucket, iNewNode );
|
||||
|
||||
// Initialized to placate the compiler's uninitialized value checking.
|
||||
if ( piNodeExistingIfDupe )
|
||||
{
|
||||
*piNodeExistingIfDupe = InvalidIndex();
|
||||
}
|
||||
|
||||
// return the new node
|
||||
return iNewNode;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: inserts a default item into the map, no change if key already exists
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMap<K,T,L,H>::FindOrInsert( const KeyType_t &key )
|
||||
{
|
||||
int iNodeExisting;
|
||||
int iNodeInserted = InsertUnconstructed( key, &iNodeExisting, false /*no duplicates allowed*/ );
|
||||
if ( iNodeInserted != InvalidIndex() )
|
||||
{
|
||||
Construct( &m_memNodes[ iNodeInserted ].m_elem );
|
||||
return iNodeInserted;
|
||||
}
|
||||
return iNodeExisting;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: inserts an item into the map, no change if key already exists
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMap<K,T,L,H>::FindOrInsert( const KeyType_t &key, const ElemType_t &insert )
|
||||
{
|
||||
int iNodeExisting;
|
||||
int iNodeInserted = InsertUnconstructed( key, &iNodeExisting, false /*no duplicates allowed*/ );
|
||||
if ( iNodeInserted != InvalidIndex() )
|
||||
{
|
||||
CopyConstruct( &m_memNodes[ iNodeInserted ].m_elem, insert );
|
||||
return iNodeInserted;
|
||||
}
|
||||
return iNodeExisting;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: inserts an item into the map, replaces existing item with same key
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMap<K,T,L,H>::InsertOrReplace( const KeyType_t &key )
|
||||
{
|
||||
int iNodeExisting;
|
||||
int iNodeInserted = InsertUnconstructed( key, &iNodeExisting, false /*no duplicates allowed*/ );
|
||||
if ( iNodeInserted != InvalidIndex() )
|
||||
{
|
||||
Construct( &m_memNodes[ iNodeInserted ].m_elem );
|
||||
return iNodeInserted;
|
||||
}
|
||||
return iNodeExisting;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: inserts an item into the map, replaces existing item with same key
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMap<K,T,L,H>::InsertOrReplace( const KeyType_t &key, const ElemType_t &insert )
|
||||
{
|
||||
int iNodeExisting;
|
||||
int iNodeInserted = InsertUnconstructed( key, &iNodeExisting, false /*no duplicates allowed*/ );
|
||||
if ( iNodeInserted != InvalidIndex() )
|
||||
{
|
||||
CopyConstruct( &m_memNodes[ iNodeInserted ].m_elem, insert );
|
||||
return iNodeInserted;
|
||||
}
|
||||
m_memNodes[ iNodeExisting ].m_elem = insert;
|
||||
return iNodeExisting;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: inserts element no matter what, even if key already exists
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMap<K,T,L,H>::InsertWithDupes( const KeyType_t &key, const ElemType_t &insert )
|
||||
{
|
||||
int iNodeInserted = InsertUnconstructed( key, NULL, true /*duplicates allowed!*/ );
|
||||
if ( iNodeInserted != InvalidIndex() )
|
||||
{
|
||||
CopyConstruct( &m_memNodes[ iNodeInserted ].m_elem, insert );
|
||||
}
|
||||
return iNodeInserted;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: grows the map to fit the specified amount
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMap<K,T,L,H>::EnsureCapacity( int amount )
|
||||
{
|
||||
m_memNodes.EnsureCapacity( amount );
|
||||
// ::OutputDebugStr( CFmtStr( "grown m_memNodes from %d to %d\n", m_cElements, m_memNodes.Count() ).Access() );
|
||||
|
||||
if ( amount <= m_vecHashBuckets.Count() )
|
||||
return;
|
||||
int cBucketsNeeded = MAX( 16, m_vecHashBuckets.Count() );
|
||||
while ( cBucketsNeeded < amount )
|
||||
cBucketsNeeded *= 2;
|
||||
|
||||
// ::OutputDebugStr( CFmtStr( "grown m_vecHashBuckets from %d to %d\n", m_vecHashBuckets.Count(), cBucketsNeeded ).Access() );
|
||||
|
||||
// grow the hash buckets
|
||||
int grow = cBucketsNeeded - m_vecHashBuckets.Count();
|
||||
int iFirst = m_vecHashBuckets.AddMultipleToTail( grow );
|
||||
// clear all the new data to invalid bits
|
||||
memset( &m_vecHashBuckets[iFirst], 0xFFFFFFFF, grow*sizeof(m_vecHashBuckets[iFirst]) );
|
||||
DbgAssert( basetypes::IsPowerOf2( m_vecHashBuckets.Count() ) );
|
||||
|
||||
// we'll have to rehash, all the buckets that existed before growth
|
||||
m_nMinRehashedBucket = 0;
|
||||
m_nMaxRehashedBucket = iFirst;
|
||||
if ( m_cElements > 0 )
|
||||
{
|
||||
// remove all the current bits
|
||||
m_bitsMigratedBuckets.Resize( 0 );
|
||||
// re-add new bits; these will all be reset to 0
|
||||
m_bitsMigratedBuckets.Resize( m_vecHashBuckets.Count() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// no elements - no rehashing
|
||||
m_nMinRehashedBucket = m_vecHashBuckets.Count();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets a new node, from the free list if possible
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMap<K,T,L,H>::AllocNode()
|
||||
{
|
||||
// if we're out of free elements, get the max
|
||||
if ( m_cElements == m_nMaxElement )
|
||||
{
|
||||
m_cElements++;
|
||||
return m_nMaxElement++;
|
||||
}
|
||||
|
||||
// pull from the free list
|
||||
DbgAssert( m_iNodeFreeListHead != InvalidIndex() );
|
||||
int iNewNode = m_iNodeFreeListHead;
|
||||
m_iNodeFreeListHead = FreeNodeIDToIndex( m_memNodes[iNewNode].m_iNextNode );
|
||||
m_cElements++;
|
||||
return iNewNode;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: takes a bucket of nodes and re-hashes them into a more optimal bucket
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMap<K,T,L,H>::RehashNodesInBucket( int iBucketSrc )
|
||||
{
|
||||
// mark us as migrated
|
||||
m_bitsMigratedBuckets.SetBit( iBucketSrc );
|
||||
|
||||
// walk the list of items, re-hashing them
|
||||
IndexType_t iNode = m_vecHashBuckets[iBucketSrc].m_iNode;
|
||||
while ( iNode != InvalidIndex() )
|
||||
{
|
||||
IndexType_t iNodeNext = m_memNodes[iNode].m_iNextNode;
|
||||
DbgAssert( iNodeNext != iNode );
|
||||
|
||||
// work out where the node should go
|
||||
const KeyType_t &key = m_memNodes[iNode].m_key;
|
||||
auto hash = m_HashFunc( key );
|
||||
int iBucketDest = basetypes::ModPowerOf2( hash, m_vecHashBuckets.Count() );
|
||||
|
||||
// if the hash bucket has changed, move it
|
||||
if ( iBucketDest != iBucketSrc )
|
||||
{
|
||||
// ::OutputDebugStr( CFmtStr( "moved key %d from bucket %d to %d\n", key, iBucketSrc, iBucketDest ).Access() );
|
||||
|
||||
// remove from this bucket list
|
||||
UnlinkNodeFromBucket( iBucketSrc, iNode );
|
||||
|
||||
// link into new bucket list
|
||||
LinkNodeIntoBucket( iBucketDest, iNode );
|
||||
}
|
||||
iNode = iNodeNext;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: searches for an item by key, returning the index handle
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMap<K,T,L,H>::Find( const KeyType_t &key ) const
|
||||
{
|
||||
if ( m_cElements == 0 )
|
||||
return InvalidIndex();
|
||||
|
||||
// hash the item
|
||||
auto hash = m_HashFunc( key );
|
||||
|
||||
// find the bucket
|
||||
int cBucketsToModAgainst = m_vecHashBuckets.Count();
|
||||
int iBucket = basetypes::ModPowerOf2( hash, cBucketsToModAgainst );
|
||||
|
||||
// look in the bucket for the item
|
||||
int iNode = FindInBucket( iBucket, key );
|
||||
if ( iNode != InvalidIndex() )
|
||||
return iNode;
|
||||
|
||||
// not found? we may have to look in older buckets
|
||||
cBucketsToModAgainst >>= 1;
|
||||
while ( cBucketsToModAgainst >= m_nMinRehashedBucket )
|
||||
{
|
||||
iBucket = basetypes::ModPowerOf2( hash, cBucketsToModAgainst );
|
||||
|
||||
if ( !m_bitsMigratedBuckets.GetBit( iBucket ) )
|
||||
{
|
||||
int iNode2 = FindInBucket( iBucket, key );
|
||||
if ( iNode2 != InvalidIndex() )
|
||||
return iNode2;
|
||||
}
|
||||
|
||||
cBucketsToModAgainst >>= 1;
|
||||
}
|
||||
|
||||
return InvalidIndex();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: searches for an item by key and element equality, returning the index handle
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMap<K, T, L, H>::FindExact( const KeyType_t &key, const ElemType_t &elem ) const
|
||||
{
|
||||
int iNode = Find( key );
|
||||
while ( iNode != InvalidIndex() )
|
||||
{
|
||||
if ( elem == m_memNodes[iNode].m_elem )
|
||||
return iNode;
|
||||
iNode = NextSameKey( iNode );
|
||||
}
|
||||
return InvalidIndex();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: find the next element with the same key, if insertwithdupes was used
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMap<K, T, L, H>::NextSameKey( IndexType_t i ) const
|
||||
{
|
||||
if ( m_memNodes.IsIdxValid( i ) )
|
||||
{
|
||||
const KeyType_t &key = m_memNodes[i].m_key;
|
||||
IndexType_t iNode = m_memNodes[i].m_iNextNode;
|
||||
DbgAssert( iNode < m_nMaxElement );
|
||||
while ( iNode != InvalidIndex() )
|
||||
{
|
||||
// equality check
|
||||
if ( m_EqualityFunc( key, m_memNodes[iNode].m_key ) )
|
||||
return iNode;
|
||||
|
||||
iNode = m_memNodes[iNode].m_iNextNode;
|
||||
}
|
||||
}
|
||||
return InvalidIndex();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: searches for an item by key, returning the index handle
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMap<K,T,L,H>::FindInBucket( int iBucket, const KeyType_t &key ) const
|
||||
{
|
||||
if ( m_vecHashBuckets[iBucket].m_iNode != InvalidIndex() )
|
||||
{
|
||||
IndexType_t iNode = m_vecHashBuckets[iBucket].m_iNode;
|
||||
DbgAssert( iNode < m_nMaxElement );
|
||||
while ( iNode != InvalidIndex() )
|
||||
{
|
||||
// equality check
|
||||
if ( m_EqualityFunc( key, m_memNodes[iNode].m_key ) )
|
||||
return iNode;
|
||||
|
||||
iNode = m_memNodes[iNode].m_iNextNode;
|
||||
}
|
||||
}
|
||||
|
||||
return InvalidIndex();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: links a node into a bucket
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
void CUtlHashMap<K,T,L,H>::LinkNodeIntoBucket( int iBucket, int iNewNode )
|
||||
{
|
||||
// add into the start of the bucket's list
|
||||
m_memNodes[iNewNode].m_iNextNode = m_vecHashBuckets[iBucket].m_iNode;
|
||||
m_vecHashBuckets[iBucket].m_iNode = iNewNode;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: unlinks a node from the bucket
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
void CUtlHashMap<K,T,L,H>::UnlinkNodeFromBucket( int iBucket, int iNodeToUnlink )
|
||||
{
|
||||
int iNodeNext = m_memNodes[iNodeToUnlink].m_iNextNode;
|
||||
|
||||
// if it's the first node, just update the bucket to point to the new place
|
||||
int iNode = m_vecHashBuckets[iBucket].m_iNode;
|
||||
if ( iNode == iNodeToUnlink )
|
||||
{
|
||||
m_vecHashBuckets[iBucket].m_iNode = iNodeNext;
|
||||
return;
|
||||
}
|
||||
|
||||
// walk the list to find where
|
||||
while ( iNode != InvalidIndex() )
|
||||
{
|
||||
if ( m_memNodes[iNode].m_iNextNode == iNodeToUnlink )
|
||||
{
|
||||
m_memNodes[iNode].m_iNextNode = iNodeNext;
|
||||
return;
|
||||
}
|
||||
iNode = m_memNodes[iNode].m_iNextNode;
|
||||
}
|
||||
|
||||
// should always be valid to unlink
|
||||
DbgAssert( false );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: removes a single item from the map
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMap<K,T,L,H>::RemoveAt( IndexType_t i )
|
||||
{
|
||||
if ( !IsValidIndex( i ) )
|
||||
{
|
||||
Assert( false );
|
||||
return;
|
||||
}
|
||||
|
||||
// unfortunately, we have to re-hash to find which bucket we're in
|
||||
auto hash = m_HashFunc( m_memNodes[i].m_key );
|
||||
int cBucketsToModAgainst = m_vecHashBuckets.Count();
|
||||
int iBucket = basetypes::ModPowerOf2( hash, cBucketsToModAgainst );
|
||||
if ( RemoveNodeFromBucket( iBucket, i ) )
|
||||
return;
|
||||
|
||||
// wasn't found; look in older buckets
|
||||
cBucketsToModAgainst >>= 1;
|
||||
while ( cBucketsToModAgainst >= m_nMinRehashedBucket )
|
||||
{
|
||||
iBucket = basetypes::ModPowerOf2( hash, cBucketsToModAgainst );
|
||||
|
||||
if ( !m_bitsMigratedBuckets.GetBit( iBucket ) )
|
||||
{
|
||||
if ( RemoveNodeFromBucket( iBucket, i ) )
|
||||
return;
|
||||
}
|
||||
|
||||
cBucketsToModAgainst >>= 1;
|
||||
}
|
||||
|
||||
// never found, container is busted
|
||||
DbgAssert( false );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: removes a node from the bucket, return true if it was found
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline bool CUtlHashMap<K,T,L,H>::RemoveNodeFromBucket( IndexType_t iBucket, int iNodeToRemove )
|
||||
{
|
||||
IndexType_t iNode = m_vecHashBuckets[iBucket].m_iNode;
|
||||
while ( iNode != InvalidIndex() )
|
||||
{
|
||||
if ( iNodeToRemove == iNode )
|
||||
{
|
||||
// found it, remove
|
||||
UnlinkNodeFromBucket( iBucket, iNodeToRemove );
|
||||
Destruct( &m_memNodes[iNode].m_key );
|
||||
Destruct( &m_memNodes[iNode].m_elem );
|
||||
|
||||
// link into free list
|
||||
m_memNodes[iNode].m_iNextNode = FreeNodeIndexToID( m_iNodeFreeListHead );
|
||||
m_iNodeFreeListHead = iNode;
|
||||
m_cElements--;
|
||||
if ( m_cElements == 0 )
|
||||
{
|
||||
m_nMinRehashedBucket = m_vecHashBuckets.Count();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
iNode = m_memNodes[iNode].m_iNextNode;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: removes all items from the hash map
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMap<K,T,L,H>::RemoveAll()
|
||||
{
|
||||
if ( m_cElements > 0 )
|
||||
{
|
||||
FOR_EACH_HASHMAP( *this, i )
|
||||
{
|
||||
Destruct( &m_memNodes[i].m_key );
|
||||
Destruct( &m_memNodes[i].m_elem );
|
||||
}
|
||||
|
||||
m_cElements = 0;
|
||||
m_nMaxElement = 0;
|
||||
m_iNodeFreeListHead = InvalidIndex();
|
||||
m_nMinRehashedBucket = m_vecHashBuckets.Count();
|
||||
m_nMaxRehashedBucket = InvalidIndex();
|
||||
m_bitsMigratedBuckets.Resize( 0 );
|
||||
memset( m_vecHashBuckets.Base(), 0xFF, m_vecHashBuckets.Count() * sizeof(HashBucket_t) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: removes all items from the hash map and frees all memory
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMap<K,T,L,H>::Purge()
|
||||
{
|
||||
if ( m_cElements > 0 )
|
||||
{
|
||||
FOR_EACH_HASHMAP( *this, i )
|
||||
{
|
||||
Destruct( &m_memNodes[i].m_key );
|
||||
Destruct( &m_memNodes[i].m_elem );
|
||||
}
|
||||
}
|
||||
|
||||
m_cElements = 0;
|
||||
m_nMaxElement = 0;
|
||||
m_iNodeFreeListHead = InvalidIndex();
|
||||
m_nMinRehashedBucket = InvalidIndex();
|
||||
m_nMaxRehashedBucket = InvalidIndex();
|
||||
m_bitsMigratedBuckets.Resize( 0 );
|
||||
m_vecHashBuckets.Purge();
|
||||
m_memNodes.Purge();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: rehashes buckets
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMap<K,T,L,H>::IncrementalRehash()
|
||||
{
|
||||
if ( m_nMinRehashedBucket < m_nMaxRehashedBucket )
|
||||
{
|
||||
while ( m_nMinRehashedBucket < m_nMaxRehashedBucket )
|
||||
{
|
||||
// see if the bucket needs rehashing
|
||||
if ( m_vecHashBuckets[m_nMinRehashedBucket].m_iNode != InvalidIndex()
|
||||
&& !m_bitsMigratedBuckets.GetBit(m_nMinRehashedBucket) )
|
||||
{
|
||||
// rehash this bucket
|
||||
RehashNodesInBucket( m_nMinRehashedBucket );
|
||||
// only actively do one - don't want to do it too fast since we may be on a rapid growth path
|
||||
++m_nMinRehashedBucket;
|
||||
break;
|
||||
}
|
||||
|
||||
// nothing to rehash in that bucket - increment and look again
|
||||
++m_nMinRehashedBucket;
|
||||
}
|
||||
|
||||
if ( m_nMinRehashedBucket >= m_nMaxRehashedBucket )
|
||||
{
|
||||
// we're done; don't need any bits anymore
|
||||
m_nMinRehashedBucket = m_vecHashBuckets.Count();
|
||||
m_nMaxRehashedBucket = InvalidIndex();
|
||||
m_bitsMigratedBuckets.Resize( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: swaps with another hash map
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
void CUtlHashMap<K,T,L,H>::Swap( CUtlHashMap<K,T,L,H> &that )
|
||||
{
|
||||
m_vecHashBuckets.Swap( that.m_vecHashBuckets );
|
||||
SWAP( m_bitsMigratedBuckets, that.m_bitsMigratedBuckets );
|
||||
m_memNodes.Swap( that.m_memNodes );
|
||||
SWAP( m_iNodeFreeListHead, that.m_iNodeFreeListHead );
|
||||
SWAP( m_cElements, that.m_cElements );
|
||||
SWAP( m_nMaxElement, that.m_nMaxElement );
|
||||
SWAP( m_nMinRehashedBucket, that.m_nMinRehashedBucket );
|
||||
SWAP( m_nMaxRehashedBucket, that.m_nMaxRehashedBucket );
|
||||
}
|
||||
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: memory validation
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMap<K,T,L,H>::Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
VALIDATE_SCOPE();
|
||||
|
||||
ValidateObj( m_vecHashBuckets );
|
||||
ValidateObj( m_memNodes );
|
||||
ValidateObj( m_bitsMigratedBuckets );
|
||||
}
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
void CUtlHashMap<K,T,L,H>::ValidateSelfAndElements( CValidator &validator, const char *pchName )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
validator.Push( typeid(*this).raw_name(), this, pchName );
|
||||
#else
|
||||
validator.Push( typeid(*this).name(), this, pchName );
|
||||
#endif
|
||||
|
||||
ValidateObj( m_vecHashBuckets );
|
||||
ValidateObj( m_memNodes );
|
||||
ValidateObj( m_bitsMigratedBuckets );
|
||||
|
||||
CValidateHelper< T > functor( validator );
|
||||
|
||||
FOR_EACH_HASHMAP( *this, i )
|
||||
{
|
||||
// Typically, very simple types are the key, so there's no need to validate it.
|
||||
//
|
||||
//Key( i ).Validate( validator, "Keys" );
|
||||
functor( Element( i ), "Elements" );
|
||||
}
|
||||
|
||||
validator.Pop();
|
||||
}
|
||||
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
void CUtlHashMap<K,T,L,H>::ValidateSelfAndKeys( CValidator &validator, const char *pchName )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
validator.Push( typeid(*this).raw_name(), this, pchName );
|
||||
#else
|
||||
validator.Push( typeid(*this).name(), this, pchName );
|
||||
#endif
|
||||
|
||||
ValidateObj( m_vecHashBuckets );
|
||||
ValidateObj( m_memNodes );
|
||||
ValidateObj( m_bitsMigratedBuckets );
|
||||
|
||||
CValidateHelper< K > functor( validator );
|
||||
|
||||
FOR_EACH_HASHMAP( *this, i )
|
||||
{
|
||||
// Ok - complicated key, and simple element - validate the key..
|
||||
//
|
||||
functor( Key( i ), "Keys" );
|
||||
}
|
||||
|
||||
validator.Pop();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // UTLHASHMAP_H
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "../steamnetworking_statsutils.h"
|
||||
#include <tier1/utllinkedlist.h>
|
||||
#include <tier1/netadr.h>
|
||||
#include <tier1/utlhashmap.h>
|
||||
#include "steamnetworkingsockets_lowlevel.h"
|
||||
#include "keypair.h"
|
||||
#include <tier0/memdbgoff.h>
|
||||
|
||||
@@ -1,254 +0,0 @@
|
||||
//========= 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. Functions
|
||||
// are used instead to require the calling party to allocate
|
||||
// and destroy their own memory
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include <tier1/utlbuffer.h>
|
||||
#include <tier0/dbg.h>
|
||||
#include <tier1/bitstring.h>
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Init static vars
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Calculate a mask for the last int in the array
|
||||
// Input : numBits -
|
||||
// Output : static int
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
unsigned g_BitStringEndMasks[] =
|
||||
{
|
||||
0x00000000,
|
||||
0xfffffffe,
|
||||
0xfffffffc,
|
||||
0xfffffff8,
|
||||
0xfffffff0,
|
||||
0xffffffe0,
|
||||
0xffffffc0,
|
||||
0xffffff80,
|
||||
0xffffff00,
|
||||
0xfffffe00,
|
||||
0xfffffc00,
|
||||
0xfffff800,
|
||||
0xfffff000,
|
||||
0xffffe000,
|
||||
0xffffc000,
|
||||
0xffff8000,
|
||||
0xffff0000,
|
||||
0xfffe0000,
|
||||
0xfffc0000,
|
||||
0xfff80000,
|
||||
0xfff00000,
|
||||
0xffe00000,
|
||||
0xffc00000,
|
||||
0xff800000,
|
||||
0xff000000,
|
||||
0xfe000000,
|
||||
0xfc000000,
|
||||
0xf8000000,
|
||||
0xf0000000,
|
||||
0xe0000000,
|
||||
0xc0000000,
|
||||
0x80000000,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Print bits for debugging purposes
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void DebugPrintBitStringBits( const int *pInts, int nInts )
|
||||
{
|
||||
for (int i=0;i<nInts;i++)
|
||||
{
|
||||
for (int j =0; j<BITS_PER_INT;j++)
|
||||
{
|
||||
Msg( "%d", (pInts[i] & (1<<j)) ? 1:0);
|
||||
}
|
||||
}
|
||||
Msg( "\n");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Saves a bit string to the given file
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
void SaveBitString(const int *pInts, int nInts, CUtlBuffer& buf)
|
||||
{
|
||||
buf.EnsureCapacity( buf.TellPut() + (sizeof( int )*nInts) );
|
||||
for (int i=0;i<nInts;i++)
|
||||
{
|
||||
buf.PutInt( pInts[i] );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Loads a bit string from the given file
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void LoadBitString(int *pInts, int nInts, CUtlBuffer& buf)
|
||||
{
|
||||
for (int i=0; i<nInts; i++)
|
||||
{
|
||||
pInts[i] = buf.GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CVariableBitStringBase::ValidateOperand( const CVariableBitStringBase &operand ) const
|
||||
{
|
||||
Assert(Size() == operand.Size());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Resizes the bit string to a new number of bits
|
||||
// Input : resizeNumBits -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVariableBitStringBase::Resize( int resizeNumBits )
|
||||
{
|
||||
Assert( resizeNumBits >= 0 );
|
||||
|
||||
int newIntCount = CalcNumIntsForBits( resizeNumBits );
|
||||
if ( newIntCount != GetNumInts() )
|
||||
{
|
||||
if ( GetInts() )
|
||||
{
|
||||
int oldIntCount = m_numInts;
|
||||
ReallocInts( newIntCount );
|
||||
m_numInts = newIntCount;
|
||||
|
||||
if ( resizeNumBits >= Size() )
|
||||
{
|
||||
GetInts()[GetNumInts() - 1] &= ~GetEndMask();
|
||||
memset( GetInts() + oldIntCount, 0, (newIntCount - oldIntCount) * sizeof(int) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Figure out how many ints are needed
|
||||
AllocInts( newIntCount );
|
||||
m_numInts = newIntCount;
|
||||
|
||||
// Initialize bitstring by clearing all bits
|
||||
memset( GetInts(), 0, newIntCount * sizeof(int) );
|
||||
}
|
||||
}
|
||||
else if ( resizeNumBits >= Size() && GetInts() )
|
||||
GetInts()[GetNumInts() - 1] &= ~GetEndMask();
|
||||
|
||||
// store the new size and end mask
|
||||
m_numBits = resizeNumBits;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allocate the storage for the ints
|
||||
// Input : numInts -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVariableBitStringBase::AllocInts( int numInts )
|
||||
{
|
||||
Assert( !m_pInt );
|
||||
|
||||
if ( numInts == 0 )
|
||||
return;
|
||||
|
||||
if ( numInts == 1 )
|
||||
{
|
||||
m_pInt = NULL; // we will use m_iBitStringStorage
|
||||
return;
|
||||
}
|
||||
|
||||
m_pInt = (int *)malloc( numInts * sizeof(int) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reallocate the storage for the ints
|
||||
// Input : numInts -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVariableBitStringBase::ReallocInts( int numInts )
|
||||
{
|
||||
Assert( GetInts() );
|
||||
if ( numInts == 0)
|
||||
{
|
||||
FreeInts();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_numInts == 1 ) // we were using m_iBitStringStorage
|
||||
{
|
||||
if ( numInts != 1 )
|
||||
{
|
||||
m_pInt = ((int *)malloc( numInts * sizeof(int) ));
|
||||
*m_pInt = m_iBitStringStorage;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( numInts == 1 )
|
||||
{
|
||||
m_iBitStringStorage = *m_pInt;
|
||||
free( m_pInt );
|
||||
m_pInt = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
m_pInt = (int *)realloc( m_pInt, numInts * sizeof(int) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Free storage allocated with AllocInts
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVariableBitStringBase::FreeInts( void )
|
||||
{
|
||||
if ( m_numInts > 1 )
|
||||
{
|
||||
free( m_pInt );
|
||||
}
|
||||
m_pInt = NULL;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Ensure that all of our internal structures are consistent, and
|
||||
// account for all memory that we've allocated.
|
||||
// Input: validator - Our global validator object
|
||||
// pchName - Our name (typically a member var in our container)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVariableBitStringBase::Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
validator.Push( "CVariableBitStringBase", this, pchName );
|
||||
|
||||
if ( m_numInts > 1 )
|
||||
{
|
||||
validator.ClaimMemory( m_pInt );
|
||||
}
|
||||
|
||||
validator.Pop();
|
||||
}
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
@@ -1,319 +0,0 @@
|
||||
//======= Copyright © 2005-2011, Valve Corporation, All rights reserved. =========
|
||||
//
|
||||
// Public domain MurmurHash3 by Austin Appleby is a very solid general-purpose
|
||||
// hash with a 32-bit output. References:
|
||||
// http://code.google.com/p/smhasher/ (home of MurmurHash3)
|
||||
// https://sites.google.com/site/murmurhash/avalanche
|
||||
// http://www.strchr.com/hash_functions
|
||||
//
|
||||
// Variant Pearson Hash general purpose hashing algorithm described
|
||||
// by Cargill in C++ Report 1994. Generates a 16-bit result.
|
||||
// Now relegated to PearsonHash namespace, not recommended for use
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(_MINIMUM_BUILD_)
|
||||
#include <stdlib.h>
|
||||
#include <tier0/basetypes.h>
|
||||
#include <tier0/platform.h>
|
||||
#include <tier1/generichash.h>
|
||||
#include <vstdlib/strtools.h>
|
||||
#else
|
||||
#include <tier0/basetypes.h>
|
||||
#include <tier1/generichash.h>
|
||||
|
||||
// in platform.h...
|
||||
#define LittleDWord( val ) ( val )
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
#define ROTL32(x,y) _rotl(x,y)
|
||||
#define ROTL64(x,y) _rotl64(x,y)
|
||||
|
||||
#define BIG_CONSTANT(x) (x)
|
||||
|
||||
#else // defined(_MSC_VER)
|
||||
|
||||
static inline uint32 rotl32( uint32 x, int8 r )
|
||||
{
|
||||
return ( x << r ) | ( x >> ( 32 - r ) );
|
||||
}
|
||||
|
||||
static inline uint64 rotl64( uint64 x, int8 r )
|
||||
{
|
||||
return ( x << r ) | ( x >> ( 64 - r ) );
|
||||
}
|
||||
|
||||
#define ROTL32(x,y) rotl32(x,y)
|
||||
#define ROTL64(x,y) rotl64(x,y)
|
||||
|
||||
#define BIG_CONSTANT(x) (x##LLU)
|
||||
|
||||
#endif // !defined(_MSC_VER)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
uint32 MurmurHash3_32( const void * key, size_t len, uint32 seed, bool bCaselessStringVariant )
|
||||
{
|
||||
const uint8 * data = (const uint8*)key;
|
||||
const ptrdiff_t nblocks = len / 4;
|
||||
uint32 uSourceBitwiseAndMask = 0xDFDFDFDF | ((uint32)bCaselessStringVariant - 1);
|
||||
|
||||
uint32 h1 = seed;
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const uint32 * blocks = (const uint32 *)(data + nblocks*4);
|
||||
|
||||
for(ptrdiff_t i = -nblocks; i; i++)
|
||||
{
|
||||
uint32 k1 = LittleDWord(blocks[i]);
|
||||
k1 &= uSourceBitwiseAndMask;
|
||||
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = (k1 << 15) | (k1 >> 17);
|
||||
k1 *= 0x1b873593;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = (h1 << 13) | (h1 >> 19);
|
||||
h1 = h1*5+0xe6546b64;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8 * tail = (const uint8*)(data + nblocks*4);
|
||||
|
||||
uint32 k1 = 0;
|
||||
|
||||
switch(len & 3)
|
||||
{
|
||||
case 3: k1 ^= tail[2] << 16;
|
||||
case 2: k1 ^= tail[1] << 8;
|
||||
case 1: k1 ^= tail[0];
|
||||
k1 &= uSourceBitwiseAndMask;
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = (k1 << 15) | (k1 >> 17);
|
||||
k1 *= 0x1b873593;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len;
|
||||
|
||||
h1 ^= h1 >> 16;
|
||||
h1 *= 0x85ebca6b;
|
||||
h1 ^= h1 >> 13;
|
||||
h1 *= 0xc2b2ae35;
|
||||
h1 ^= h1 >> 16;
|
||||
|
||||
return h1;
|
||||
}
|
||||
|
||||
static inline uint64 fmix64( uint64 k )
|
||||
{
|
||||
k ^= k >> 33;
|
||||
k *= BIG_CONSTANT( 0xff51afd7ed558ccd );
|
||||
k ^= k >> 33;
|
||||
k *= BIG_CONSTANT( 0xc4ceb9fe1a85ec53 );
|
||||
k ^= k >> 33;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
void MurmurHash3_128( const void * key, const int len, const uint32 seed, void * out )
|
||||
{
|
||||
const uint8 * data = ( const uint8* )key;
|
||||
const int nblocks = len / 16;
|
||||
|
||||
uint64 h1 = seed;
|
||||
uint64 h2 = seed;
|
||||
|
||||
const uint64 c1 = BIG_CONSTANT( 0x87c37b91114253d5 );
|
||||
const uint64 c2 = BIG_CONSTANT( 0x4cf5ad432745937f );
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const uint64 * blocks = ( const uint64 * )( data );
|
||||
|
||||
for ( int i = 0; i < nblocks; i++ )
|
||||
{
|
||||
uint64 k1 = blocks[i * 2 + 0];
|
||||
uint64 k2 = blocks[i * 2 + 1];
|
||||
|
||||
k1 *= c1; k1 = ROTL64( k1, 31 ); k1 *= c2; h1 ^= k1;
|
||||
|
||||
h1 = ROTL64( h1, 27 ); h1 += h2; h1 = h1 * 5 + 0x52dce729;
|
||||
|
||||
k2 *= c2; k2 = ROTL64( k2, 33 ); k2 *= c1; h2 ^= k2;
|
||||
|
||||
h2 = ROTL64( h2, 31 ); h2 += h1; h2 = h2 * 5 + 0x38495ab5;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8 * tail = ( const uint8* )( data + nblocks * 16 );
|
||||
|
||||
uint64 k1 = 0;
|
||||
uint64 k2 = 0;
|
||||
|
||||
switch ( len & 15 )
|
||||
{
|
||||
case 15: k2 ^= ( ( uint64 )tail[14] ) << 48;
|
||||
case 14: k2 ^= ( ( uint64 )tail[13] ) << 40;
|
||||
case 13: k2 ^= ( ( uint64 )tail[12] ) << 32;
|
||||
case 12: k2 ^= ( ( uint64 )tail[11] ) << 24;
|
||||
case 11: k2 ^= ( ( uint64 )tail[10] ) << 16;
|
||||
case 10: k2 ^= ( ( uint64 )tail[9] ) << 8;
|
||||
case 9: k2 ^= ( ( uint64 )tail[8] ) << 0;
|
||||
k2 *= c2; k2 = ROTL64( k2, 33 ); k2 *= c1; h2 ^= k2;
|
||||
|
||||
case 8: k1 ^= ( ( uint64 )tail[7] ) << 56;
|
||||
case 7: k1 ^= ( ( uint64 )tail[6] ) << 48;
|
||||
case 6: k1 ^= ( ( uint64 )tail[5] ) << 40;
|
||||
case 5: k1 ^= ( ( uint64 )tail[4] ) << 32;
|
||||
case 4: k1 ^= ( ( uint64 )tail[3] ) << 24;
|
||||
case 3: k1 ^= ( ( uint64 )tail[2] ) << 16;
|
||||
case 2: k1 ^= ( ( uint64 )tail[1] ) << 8;
|
||||
case 1: k1 ^= ( ( uint64 )tail[0] ) << 0;
|
||||
k1 *= c1; k1 = ROTL64( k1, 31 ); k1 *= c2; h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len; h2 ^= len;
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
h1 = fmix64( h1 );
|
||||
h2 = fmix64( h2 );
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
( ( uint64* )out )[0] = h1;
|
||||
( ( uint64* )out )[1] = h2;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(_MINIMUM_BUILD_)
|
||||
|
||||
namespace PearsonHash
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Table of randomly shuffled values from 0-255 generated by:
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
/*
|
||||
void MakeRandomValues()
|
||||
{
|
||||
int i, j, r;
|
||||
unsigned t;
|
||||
srand( 0xdeadbeef );
|
||||
|
||||
for ( i = 0; i < 256; i++ )
|
||||
{
|
||||
g_nRandomValues[i] = (unsigned )i;
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
r = rand() & 0xff;
|
||||
t = g_nRandomValues[i];
|
||||
g_nRandomValues[i] = g_nRandomValues[r];
|
||||
g_nRandomValues[r] = t;
|
||||
}
|
||||
}
|
||||
|
||||
printf("static unsigned g_nRandomValues[256] =\n{\n");
|
||||
|
||||
for (i = 0; i < 256; i += 16)
|
||||
{
|
||||
printf("\t");
|
||||
for (j = 0; j < 16; j++)
|
||||
printf(" %3d,", g_nRandomValues[i+j]);
|
||||
printf("\n");
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
*/
|
||||
|
||||
static const unsigned char g_nRandomValues[256] =
|
||||
{
|
||||
131, 184, 146, 42, 124, 142, 226, 76, 8, 135, 215, 116, 228, 49, 144, 231,
|
||||
238, 25, 156, 125, 128, 87, 223, 38, 98, 122, 105, 4, 35, 180, 188, 160,
|
||||
179, 59, 218, 0, 192, 207, 209, 150, 227, 143, 140, 161, 73, 84, 111, 162,
|
||||
239, 74, 210, 195, 15, 225, 104, 221, 245, 12, 72, 47, 109, 187, 40, 178,
|
||||
208, 56, 190, 193, 126, 95, 33, 45, 177, 170, 186, 123, 202, 149, 60, 194,
|
||||
168, 102, 71, 148, 46, 121, 52, 119, 196, 247, 127, 145, 75, 79, 61, 254,
|
||||
9, 44, 23, 211, 18, 175, 251, 130, 203, 108, 85, 167, 29, 250, 138, 182,
|
||||
101, 213, 159, 92, 36, 10, 86, 32, 176, 80, 17, 134, 181, 114, 64, 165,
|
||||
89, 68, 6, 14, 205, 137, 117, 7, 39, 132, 26, 19, 214, 99, 166, 163,
|
||||
69, 174, 157, 100, 201, 118, 2, 28, 235, 236, 139, 244, 70, 20, 155, 82,
|
||||
51, 154, 115, 94, 93, 83, 136, 27, 198, 43, 50, 243, 183, 153, 53, 206,
|
||||
77, 55, 57, 3, 220, 147, 253, 110, 37, 246, 97, 13, 120, 103, 91, 169,
|
||||
58, 11, 133, 22, 152, 189, 222, 151, 141, 88, 224, 1, 48, 191, 249, 173,
|
||||
106, 113, 252, 172, 232, 66, 219, 96, 237, 21, 233, 62, 242, 54, 230, 65,
|
||||
78, 248, 16, 41, 31, 200, 90, 112, 255, 171, 164, 24, 199, 81, 212, 197,
|
||||
185, 67, 5, 234, 30, 129, 216, 63, 204, 158, 217, 229, 107, 240, 241, 34,
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// String
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashString( const char *pszKey )
|
||||
{
|
||||
const uint8 *k = (const uint8 *)pszKey;
|
||||
uint8 even = 0, odd = 0, n;
|
||||
|
||||
while ((n = *k++) != 0)
|
||||
{
|
||||
even = g_nRandomValues[even ^ n];
|
||||
if ((n = *k++) != 0)
|
||||
odd = g_nRandomValues[odd ^ n];
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return ((unsigned int)even << 8) | odd;
|
||||
}
|
||||
|
||||
#define InlineToUpper( c ) ( (( c >= 'a' ) && ( c <= 'z' )) ? (c-0x20) : c )
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Case-insensitive string
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashStringCaseless( const char *pszKey )
|
||||
{
|
||||
const uint8 *k = (const uint8 *) pszKey;
|
||||
uint8 even = 0, odd = 0, n;
|
||||
|
||||
while ((n = *k++) != 0)
|
||||
{
|
||||
even = g_nRandomValues[even ^ InlineToUpper(n) ];
|
||||
|
||||
if ( (n = *k++) != 0)
|
||||
odd = g_nRandomValues[odd ^ InlineToUpper(n) ];
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return ((unsigned int)even << 8) | odd;
|
||||
}
|
||||
|
||||
}
|
||||
#endif // _MINIMUM_BUILD_
|
||||
Reference in New Issue
Block a user