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:
Fletcher Dunn
2018-04-02 13:46:30 -07:00
parent 7f92f7c4dc
commit 3d5b59974b
6 changed files with 0 additions and 2140 deletions
-2
View File
@@ -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',
-584
View File
@@ -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
-980
View File
@@ -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>
-254
View File
@@ -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
-319
View File
@@ -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_