#ifndef UTLHASHMAP_H
#define UTLHASHMAP_H
#pragma once
#include <tier0/dbg.h>
#include "utlvector.h"
#define FOR_EACH_HASHMAP( mapName, iteratorName ) \
for ( int iteratorName = 0; iteratorName < (mapName).MaxElement(); ++iteratorName ) if ( !(mapName).IsValidIndex( iteratorName ) ) continue; else
template <typename K, typename T, typename L, typename H >
class CUtlHashMap
{
protected:
enum ReplaceExisting
{
False = 0,
True = 1,
};
public:
using KeyType_t= K;
using ElemType_t = T;
using IndexType_t = int;
using EqualityFunc_t = L;
using HashFunc_t = H;
static constexpr IndexType_t kInvalidIndex = -1;
CUtlHashMap()
{
m_cElements = 0;
m_nMaxElement = 0;
m_nNeedRehashStart = 0;
m_nNeedRehashEnd = 0;
m_nMinBucketMask = 1;
m_iNodeFreeListHead = kInvalidIndex;
}
CUtlHashMap( int cElementsExpected )
{
m_cElements = 0;
m_nMaxElement = 0;
m_nNeedRehashStart = 0;
m_nNeedRehashEnd = 0;
m_nMinBucketMask = 1;
m_iNodeFreeListHead = kInvalidIndex;
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 ) );
}
}
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; }
const KeyType_t & Key( IndexType_t i ) const { return m_memNodes.Element( i ).m_key; }
IndexType_t Count() const { return m_cElements; }
IndexType_t MaxElement() const { return m_nMaxElement; }
bool IsValidIndex( IndexType_t i ) const { return (unsigned)i < (unsigned)m_nMaxElement && m_memNodes[i].m_iNextNode >= -1; }
static constexpr IndexType_t InvalidIndex() { return -1; }
IndexType_t Insert( const KeyType_t &key ) { return FindOrInsert_Internal( key, ReplaceExisting::True ); }
IndexType_t Insert( KeyType_t &&key ) { return FindOrInsert_Internal( std::move(key), ReplaceExisting::True ); }
IndexType_t Insert( const KeyType_t &key, const ElemType_t &insert ) { return FindOrInsert_Internal( key, insert, ReplaceExisting::True ); }
IndexType_t Insert( const KeyType_t &key, ElemType_t &&insert ) { return FindOrInsert_Internal( key, std::move(insert), ReplaceExisting::True ); }
IndexType_t Insert( KeyType_t &&key, const ElemType_t &insert ) { return FindOrInsert_Internal( std::move(key), insert, ReplaceExisting::True ); }
IndexType_t Insert( KeyType_t &&key, ElemType_t &&insert ) { return FindOrInsert_Internal( std::move(key), std::move(insert), ReplaceExisting::True ); }
IndexType_t InsertOrReplace( const KeyType_t &key, const ElemType_t &insert ) { return FindOrInsert_Internal( key, insert, ReplaceExisting::True ); }
IndexType_t InsertOrReplace( const KeyType_t &key, ElemType_t &&insert ) { return FindOrInsert_Internal( key, std::move(insert), ReplaceExisting::True ); }
IndexType_t InsertOrReplace( KeyType_t &&key, const ElemType_t &insert ) { return FindOrInsert_Internal( std::move(key), insert, ReplaceExisting::True ); }
IndexType_t InsertOrReplace( KeyType_t &&key, ElemType_t &&insert ) { return FindOrInsert_Internal( std::move(key), std::move(insert), ReplaceExisting::True ); }
IndexType_t InsertWithDupes( const KeyType_t &key, const ElemType_t &insert ) { return InsertWithDupes_Internal( key, insert ); }
IndexType_t InsertWithDupes( const KeyType_t &key, ElemType_t &&insert ) { return InsertWithDupes_Internal( key, std::move(insert) ); }
IndexType_t InsertWithDupes( KeyType_t &&key, const ElemType_t &insert ) { return InsertWithDupes_Internal( std::move(key), insert ); }
IndexType_t InsertWithDupes( KeyType_t &&key, ElemType_t &&insert ) { return InsertWithDupes_Internal( std::move(key), std::move(insert) ); }
IndexType_t FindOrInsert( const KeyType_t &key ) { return FindOrInsert_Internal( key, ReplaceExisting::False ); }
IndexType_t FindOrInsert( KeyType_t &&key ) { return FindOrInsert_Internal( std::move(key), ReplaceExisting::False ); }
IndexType_t FindOrInsert( const KeyType_t &key, const ElemType_t &insert ) { return FindOrInsert_Internal( key, insert, ReplaceExisting::False ); }
IndexType_t FindOrInsert( const KeyType_t &key, ElemType_t &&insert ) { return FindOrInsert_Internal( key, std::move(insert), ReplaceExisting::False ); }
IndexType_t FindOrInsert( KeyType_t &&key, const ElemType_t &insert ) { return FindOrInsert_Internal( std::move(key), insert, ReplaceExisting::False ); }
IndexType_t FindOrInsert( KeyType_t &&key, ElemType_t &&insert ) { return FindOrInsert_Internal( std::move(key), std::move(insert), ReplaceExisting::False ); }
ElemType_t *FindOrInsertGetPtr( const KeyType_t &key )
{
IndexType_t i = FindOrInsert(key);
return &m_memNodes.Element( i ).m_elem;
}
ElemType_t *FindOrInsertGetPtr( KeyType_t &&key )
{
IndexType_t i = FindOrInsert( std::move( key ) );
return &m_memNodes.Element( i ).m_elem;
}
IndexType_t Find( const KeyType_t &key ) const;
ElemType_t *FindGetPtr( const KeyType_t &key )
{
IndexType_t i = Find(key);
return i == kInvalidIndex ? nullptr : &m_memNodes.Element( i ).m_elem;
}
const ElemType_t *FindGetPtr( const KeyType_t &key ) const
{
IndexType_t i = Find(key);
return i == kInvalidIndex ? nullptr : &m_memNodes.Element( i ).m_elem;
}
bool HasElement( const KeyType_t &key ) const { return Find( key ) != kInvalidIndex; }
IndexType_t FindExact( const KeyType_t &key, const ElemType_t &elem ) const;
IndexType_t NextSameKey( IndexType_t i ) const;
void EnsureCapacity( int num );
const ElemType_t &FindElement( const KeyType_t &key, const ElemType_t &defaultValue ) const
{
IndexType_t i = Find( key );
if ( i == kInvalidIndex )
return defaultValue;
return Element( i );
}
void RemoveAt( IndexType_t i );
bool Remove( const KeyType_t &key )
{
int iMap = Find( key );
if ( iMap != kInvalidIndex )
{
RemoveAt( iMap );
return true;
}
return false;
}
void RemoveAll();
void Purge();
void PurgeAndDeleteElements()
{
FOR_EACH_HASHMAP( *this, i )
delete this->Element(i);
Purge();
}
void Swap( CUtlHashMap< K, T, L, H > &that );
protected:
template < typename pf_key >
IndexType_t FindOrInsert_Internal( pf_key &&key, ReplaceExisting bReplace );
template < typename pf_key, typename pf_elem >
IndexType_t FindOrInsert_Internal( pf_key &&key, pf_elem &&insert, ReplaceExisting bReplace );
template < typename pf_key, typename pf_elem >
IndexType_t InsertWithDupes_Internal( pf_key &&key, pf_elem &&insert );
template < typename KeyType_universal_ref >
IndexType_t InsertUnconstructed( KeyType_universal_ref &&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; }
int FindInBucket( int iBucket, const KeyType_t &key ) const;
int AllocNode();
void RehashNodesInBucket( int iBucket );
void LinkNodeIntoBucket( int iBucket, int iNewNode );
bool RemoveNodeFromBucket( int iBucket, int iNodeToRemove );
void IncrementalRehash();
struct HashBucket_t
{
IndexType_t m_iNode;
};
CUtlVector<HashBucket_t> m_vecHashBuckets;
struct Node_t
{
KeyType_t m_key;
ElemType_t m_elem;
int m_iNextNode;
};
CUtlMemory<Node_t> m_memNodes;
IndexType_t m_iNodeFreeListHead;
IndexType_t m_cElements;
IndexType_t m_nMaxElement;
IndexType_t m_nNeedRehashStart, m_nNeedRehashEnd; IndexType_t m_nMinBucketMask; EqualityFunc_t m_EqualityFunc;
HashFunc_t m_HashFunc;
public:
class ItemRef
{
protected:
Node_t &m_node;
const int m_idx;
public:
inline ItemRef( const CUtlHashMap< K, T, L, H > &map, int idx ) : m_node( const_cast< Node_t &>( map.m_memNodes[idx] ) ), m_idx(idx) {}
ItemRef( const ItemRef &x ) = default;
inline int Index() const { return m_idx; }
inline const KeyType_t &Key() const { return m_node.m_key; }
inline const ElemType_t &Element() const { return m_node.m_elem; }
};
struct MutableItemRef : ItemRef
{
inline MutableItemRef( CUtlHashMap< K, T, L, H > &map, int idx ) : ItemRef( map, idx ) {}
MutableItemRef( const MutableItemRef &x ) = default;
using ItemRef::Element; inline ElemType_t &Element() const { return this->m_node.m_elem; } };
class Iterator
{
protected:
CUtlHashMap<K, T, L, H > &m_map;
int m_idx;
public:
inline Iterator( const CUtlHashMap< K, T, L, H > &map, int idx ) : m_map( const_cast< CUtlHashMap< K, T, L, H > &>( map ) ), m_idx(idx) {}
Iterator( const Iterator &x ) = default;
inline bool operator==( const Iterator &x ) const { return &m_map == &x.m_map && m_idx == x.m_idx; } inline bool operator!=( const Iterator &x ) const { return &m_map != &x.m_map || m_idx != x.m_idx; }
inline void operator++()
{
if ( m_idx == kInvalidIndex )
return;
do
{
++m_idx;
if ( m_idx >= m_map.m_nMaxElement )
{
m_idx = kInvalidIndex;
break;
}
} while ( m_map.m_memNodes[m_idx].m_iNextNode < -1 );
}
};
struct MutableIterator : Iterator
{
inline MutableIterator( const MutableIterator &x ) = default;
inline MutableIterator( CUtlHashMap< K, T, L, H > &map, int idx ) : Iterator( map, idx ) {}
};
struct KeyIterator : Iterator
{
using Iterator::Iterator;
inline const KeyType_t &operator*() { return this->m_map.m_memNodes[this->m_idx].m_key; }
};
struct ConstValueIterator : Iterator
{
using Iterator::Iterator;
inline const ElemType_t &operator*() { return this->m_map.m_memNodes[this->m_idx].m_elem; }
};
struct MutableValueIterator : MutableIterator
{
using MutableIterator::MutableIterator;
inline ElemType_t &operator*() { return this->m_map.m_memNodes[this->m_idx].m_elem; }
};
struct ConstItemIterator : Iterator
{
using Iterator::Iterator;
inline ItemRef operator*() { return ItemRef( this->m_map, this->m_idx ); }
};
struct MutableItemIterator : public MutableIterator
{
using MutableIterator::MutableIterator;
inline MutableItemRef operator*() { return MutableItemRef( this->m_map, this->m_idx ); }
};
template <typename TIterator>
class Range
{
CUtlHashMap< K, T, L, H > &m_map;
public:
Range( const CUtlHashMap< K, T, L, H > &map ) : m_map( const_cast< CUtlHashMap< K, T, L, H > &>( map ) ) {}
TIterator begin() const
{
int idx;
if ( m_map.m_cElements <= 0 )
{
idx = kInvalidIndex;
}
else
{
idx = 0;
while ( m_map.m_memNodes[idx].m_iNextNode < -1 )
{
++idx;
Assert( idx < m_map.m_nMaxElement ); }
}
return TIterator( m_map, idx );
}
TIterator end() const { return TIterator( m_map, kInvalidIndex ); }
};
Range<KeyIterator> IterKeys() const { return Range<KeyIterator>(*this); }
Range<ConstValueIterator> IterValues() const { return Range<ConstValueIterator>(*this); }
Range<MutableValueIterator> IterValues() { return Range<MutableValueIterator>(*this); }
Range<ConstItemIterator> IterItems() const { return Range<ConstItemIterator>(*this); }
Range<MutableItemIterator> IterItems() { return Range<MutableItemIterator>(*this); }
};
template <typename K, typename T, typename L, typename H>
template <typename KeyType_universal_ref>
inline int CUtlHashMap<K,T,L,H>::InsertUnconstructed( KeyType_universal_ref &&key, int *piNodeExistingIfDupe, bool bAllowDupes )
{
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 );
if ( m_nNeedRehashStart < m_nNeedRehashEnd )
IncrementalRehash();
int hash = (int)m_HashFunc( key );
int nBucketMaskMigrate = ( m_vecHashBuckets.Count() >> 1 ) - 1;
while ( nBucketMaskMigrate >= m_nMinBucketMask )
{
int iBucketMigrate = hash & nBucketMaskMigrate;
if ( iBucketMigrate < m_nNeedRehashStart )
break;
RehashNodesInBucket( iBucketMigrate );
nBucketMaskMigrate >>= 1;
}
int iBucket = hash & ( m_vecHashBuckets.Count()-1 );
if ( !bAllowDupes )
{
IndexType_t iNode = FindInBucket( iBucket, key );
if ( iNode != kInvalidIndex )
{
if ( piNodeExistingIfDupe )
{
*piNodeExistingIfDupe = iNode;
}
return kInvalidIndex;
}
}
int iNewNode = AllocNode();
m_memNodes[iNewNode].m_iNextNode = kInvalidIndex;
Construct( &m_memNodes[iNewNode].m_key, std::forward<KeyType_universal_ref>( key ) );
LinkNodeIntoBucket( iBucket, iNewNode );
if ( piNodeExistingIfDupe )
{
*piNodeExistingIfDupe = kInvalidIndex;
}
return iNewNode;
}
template <typename K, typename T, typename L, typename H>
template < typename pf_key >
inline int CUtlHashMap<K,T,L,H>::FindOrInsert_Internal( pf_key &&key, ReplaceExisting bReplace )
{
int iNodeExisting;
int iNodeInserted = InsertUnconstructed( std::forward<pf_key>( key ), &iNodeExisting, false );
if ( bReplace && iNodeExisting != kInvalidIndex )
{
Destruct( &m_memNodes[ iNodeExisting ].m_elem );
ValueInitializeConstruct( &m_memNodes[ iNodeExisting ].m_elem );
}
else if ( iNodeInserted != kInvalidIndex )
{
ValueInitializeConstruct( &m_memNodes[ iNodeInserted ].m_elem );
return iNodeInserted;
}
return iNodeExisting;
}
template <typename K, typename T, typename L, typename H>
template < typename pf_key, typename pf_elem >
inline int CUtlHashMap<K,T,L,H>::FindOrInsert_Internal( pf_key &&key, pf_elem &&elem, ReplaceExisting bReplace )
{
int iNodeExisting;
int iNodeInserted = InsertUnconstructed( std::forward<pf_key>( key ), &iNodeExisting, false );
if ( bReplace && iNodeExisting != kInvalidIndex )
{
Destruct( &m_memNodes[ iNodeExisting ].m_elem );
Construct( &m_memNodes[ iNodeExisting ].m_elem, std::forward<pf_elem>( elem ) );
}
else if ( iNodeInserted != kInvalidIndex )
{
Construct( &m_memNodes[ iNodeInserted ].m_elem, std::forward<pf_elem>( elem ) );
return iNodeInserted;
}
return iNodeExisting;
}
template <typename K, typename T, typename L, typename H>
template < typename pf_key, typename pf_elem >
inline int CUtlHashMap<K,T,L,H>::InsertWithDupes_Internal( pf_key &&key, pf_elem &&insert )
{
int iNodeInserted = InsertUnconstructed( std::forward<pf_key>( key ), NULL, true ); if ( iNodeInserted != kInvalidIndex )
{
Construct( &m_memNodes[ iNodeInserted ].m_elem, std::forward<pf_elem>( insert ) );
}
return iNodeInserted;
}
template <typename K, typename T, typename L, typename H>
inline void CUtlHashMap<K,T,L,H>::EnsureCapacity( int amount )
{
m_memNodes.EnsureCapacity( amount );
if ( amount <= m_vecHashBuckets.Count() )
return;
int cBucketsNeeded = MAX( 16, m_vecHashBuckets.Count() );
while ( cBucketsNeeded < amount )
cBucketsNeeded <<= 1;
DbgAssert( ( cBucketsNeeded & (cBucketsNeeded-1) ) == 0 );
int grow = cBucketsNeeded - m_vecHashBuckets.Count();
int iFirst = m_vecHashBuckets.AddMultipleToTail( grow );
memset( &m_vecHashBuckets[iFirst], 0xFFFFFFFF, grow*sizeof(m_vecHashBuckets[iFirst]) );
DbgAssert( m_vecHashBuckets.Count() == cBucketsNeeded );
if ( m_cElements > 0 )
{
m_nNeedRehashStart = 0;
m_nNeedRehashEnd = iFirst;
}
else
{
m_nNeedRehashStart = m_vecHashBuckets.Count();
m_nNeedRehashEnd = m_nNeedRehashStart;
m_nMinBucketMask = m_nNeedRehashStart-1;
}
}
template <typename K, typename T, typename L, typename H>
inline int CUtlHashMap<K,T,L,H>::AllocNode()
{
if ( m_cElements == m_nMaxElement )
{
m_cElements++;
return m_nMaxElement++;
}
DbgAssert( m_iNodeFreeListHead != kInvalidIndex );
int iNewNode = m_iNodeFreeListHead;
m_iNodeFreeListHead = FreeNodeIDToIndex( m_memNodes[iNewNode].m_iNextNode );
m_cElements++;
return iNewNode;
}
template <typename K, typename T, typename L, typename H>
inline void CUtlHashMap<K,T,L,H>::RehashNodesInBucket( int iBucketSrc )
{
IndexType_t *pLink = &m_vecHashBuckets[iBucketSrc].m_iNode;
for (;;)
{
IndexType_t iNode = *pLink;
if ( iNode == kInvalidIndex )
break;
Node_t &node = m_memNodes[iNode];
DbgAssert( node.m_iNextNode != iNode );
int hash = (int)m_HashFunc( node.m_key );
int iBucketDest = hash & (m_vecHashBuckets.Count()-1);
if ( iBucketDest != iBucketSrc )
{
*pLink = node.m_iNextNode;
LinkNodeIntoBucket( iBucketDest, iNode );
}
else
{
pLink = &node.m_iNextNode;
}
}
}
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 kInvalidIndex;
if ( m_nNeedRehashStart < m_nNeedRehashEnd )
(const_cast<CUtlHashMap<K,T,L,H> *>( this ))->IncrementalRehash();
int hash = (int)m_HashFunc( key );
int cBucketsMask = m_vecHashBuckets.Count()-1;
int iBucket = hash & cBucketsMask;
do
{
int iNode = FindInBucket( iBucket, key );
if ( iNode != kInvalidIndex )
return iNode;
cBucketsMask >>= 1;
if ( cBucketsMask < m_nMinBucketMask )
break;
iBucket = hash & cBucketsMask;
} while ( iBucket >= m_nNeedRehashStart );
return kInvalidIndex;
}
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 != kInvalidIndex )
{
if ( elem == m_memNodes[iNode].m_elem )
return iNode;
iNode = NextSameKey( iNode );
}
return kInvalidIndex;
}
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;
while ( iNode != kInvalidIndex )
{
DbgAssert( iNode < m_nMaxElement );
if ( m_EqualityFunc( key, m_memNodes[iNode].m_key ) )
return iNode;
iNode = m_memNodes[iNode].m_iNextNode;
}
}
return kInvalidIndex;
}
template <typename K, typename T, typename L, typename H>
inline int CUtlHashMap<K,T,L,H>::FindInBucket( int iBucket, const KeyType_t &key ) const
{
IndexType_t iNode = m_vecHashBuckets[iBucket].m_iNode;
while ( iNode != kInvalidIndex )
{
DbgAssert( iNode < m_nMaxElement );
const Node_t &node = m_memNodes[iNode];
if ( m_EqualityFunc( key, node.m_key ) )
return iNode;
iNode = node.m_iNextNode;
}
return kInvalidIndex;
}
template <typename K, typename T, typename L, typename H>
inline void CUtlHashMap<K,T,L,H>::LinkNodeIntoBucket( int iBucket, int iNewNode )
{
m_memNodes[iNewNode].m_iNextNode = m_vecHashBuckets[iBucket].m_iNode;
m_vecHashBuckets[iBucket].m_iNode = iNewNode;
}
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;
}
if ( m_nNeedRehashStart < m_nNeedRehashEnd )
IncrementalRehash();
int hash = (int)m_HashFunc( m_memNodes[i].m_key );
int nBucketMask = m_vecHashBuckets.Count()-1;
if ( RemoveNodeFromBucket( hash & nBucketMask, i ) )
return;
for (;;)
{
nBucketMask >>= 1;
if ( nBucketMask < m_nMinBucketMask )
break;
int iBucket = hash & nBucketMask;
if ( iBucket < m_nNeedRehashStart )
break;
if ( RemoveNodeFromBucket( iBucket, i ) )
return;
}
Assert( false );
}
template <typename K, typename T, typename L, typename H>
inline bool CUtlHashMap<K,T,L,H>::RemoveNodeFromBucket( IndexType_t iBucket, int iNodeToRemove )
{
IndexType_t *pLink = &m_vecHashBuckets[iBucket].m_iNode;
for (;;)
{
IndexType_t iNode = *pLink;
if ( iNode == kInvalidIndex )
break;
Node_t &node = m_memNodes[iNode];
DbgAssert( node.m_iNextNode != iNode );
if ( iNodeToRemove == iNode )
{
*pLink = node.m_iNextNode;
Destruct( &node.m_key );
Destruct( &node.m_elem );
node.m_iNextNode = FreeNodeIndexToID( m_iNodeFreeListHead );
m_iNodeFreeListHead = iNode;
m_cElements--;
if ( m_cElements == 0 )
{
m_nNeedRehashStart = m_vecHashBuckets.Count();
m_nNeedRehashEnd = m_nNeedRehashStart;
m_nMinBucketMask = m_vecHashBuckets.Count()-1;
}
return true;
}
pLink = &node.m_iNextNode;
}
return false;
}
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 )
{
Node_t &node = m_memNodes[i];
Destruct( &node.m_key );
Destruct( &node.m_elem );
}
m_cElements = 0;
m_nMaxElement = 0;
m_iNodeFreeListHead = kInvalidIndex;
m_nNeedRehashStart = m_vecHashBuckets.Count();
m_nNeedRehashEnd = m_nNeedRehashStart;
DbgAssert( m_vecHashBuckets.Count() >= 2 );
m_nMinBucketMask = m_vecHashBuckets.Count()-1;
memset( m_vecHashBuckets.Base(), 0xFF, m_vecHashBuckets.Count() * sizeof(HashBucket_t) );
}
}
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 )
{
Node_t &node = m_memNodes[i];
Destruct( &node.m_key );
Destruct( &node.m_elem );
}
}
m_cElements = 0;
m_nMaxElement = 0;
m_iNodeFreeListHead = kInvalidIndex;
m_nNeedRehashStart = 0;
m_nNeedRehashEnd = 0;
m_nMinBucketMask = 1;
m_vecHashBuckets.Purge();
m_memNodes.Purge();
}
template <typename K, typename T, typename L, typename H>
inline void CUtlHashMap<K,T,L,H>::IncrementalRehash()
{
DbgAssert( m_nNeedRehashStart < m_nNeedRehashEnd );
do
{
int iBucketSrc = m_nNeedRehashStart;
++m_nNeedRehashStart;
if ( m_vecHashBuckets[iBucketSrc].m_iNode != kInvalidIndex )
{
RehashNodesInBucket( iBucketSrc );
if ( m_nNeedRehashStart < m_nNeedRehashEnd )
return;
break;
}
} while ( m_nNeedRehashStart < m_nNeedRehashEnd );
DbgAssert( m_vecHashBuckets.Count() >= 2 );
m_nNeedRehashStart = m_vecHashBuckets.Count();
m_nNeedRehashEnd = m_nNeedRehashStart;
m_nMinBucketMask = m_vecHashBuckets.Count()-1;
}
template <typename K, typename T, typename L, typename H>
inline void CUtlHashMap<K,T,L,H>::Swap( CUtlHashMap<K,T,L,H> &that )
{
m_vecHashBuckets.Swap( that.m_vecHashBuckets );
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_nNeedRehashStart, that.m_nNeedRehashStart );
SWAP( m_nNeedRehashEnd, that.m_nNeedRehashEnd );
SWAP( m_nMinBucketMask, that.m_nMinBucketMask );
}
#endif