343 lines
9.9 KiB
C++
343 lines
9.9 KiB
C++
//========== Copyright © 2005, Valve Corporation, All rights reserved. ========
|
|
//
|
|
// Purpose:
|
|
//
|
|
//=============================================================================
|
|
|
|
#ifndef UTLHASHDICT_H
|
|
#define UTLHASHDICT_H
|
|
|
|
#if defined( _WIN32 )
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "tier1/utlhash.h"
|
|
#include "tier1/generichash.h"
|
|
#include "mathlib/mathlib.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive = true, bool bDupeStrings = true>
|
|
class CUtlHashDict
|
|
{
|
|
public:
|
|
// constructor, destructor
|
|
CUtlHashDict( int bucketCount = 16, int growCount = 0, int initCount = 0 );
|
|
~CUtlHashDict( );
|
|
|
|
// gets particular elements
|
|
T& Element( unsigned i );
|
|
const T& Element( unsigned i ) const;
|
|
T& operator[]( unsigned i );
|
|
const T& operator[]( unsigned i ) const;
|
|
|
|
// gets element names
|
|
char const *GetElementName( unsigned i ) const;
|
|
|
|
// Number of elements
|
|
int Count() const;
|
|
|
|
// Checks if a node is valid and in the tree
|
|
bool IsValidIndex( unsigned i ) const;
|
|
|
|
// Invalid index
|
|
static unsigned InvalidHandle();
|
|
|
|
// Insert method (inserts in order)
|
|
unsigned Insert( const char *pName, const T &element );
|
|
unsigned Insert( const char *pName );
|
|
|
|
// Find method
|
|
unsigned Find( const char *pName ) const;
|
|
|
|
// Remove methods
|
|
void RemoveAt( unsigned i );
|
|
void Remove( const char *pName );
|
|
void RemoveAll( );
|
|
|
|
// Purge memory
|
|
void Purge();
|
|
void PurgeAndDeleteElements(); // Call delete on each element.
|
|
|
|
// Iteration methods
|
|
unsigned First() const;
|
|
unsigned Next( unsigned i ) const;
|
|
|
|
protected:
|
|
struct Entry_t
|
|
{
|
|
const char *pszSymbol;
|
|
T value;
|
|
};
|
|
|
|
template <bool bCaseIgnore>
|
|
class CCompare
|
|
{
|
|
public:
|
|
CCompare( int ignored ) {}
|
|
|
|
bool operator()( const Entry_t &entry1, const Entry_t &entry2 ) const
|
|
{
|
|
return !( ( bCaseIgnore ) ? stricmp( entry1.pszSymbol, entry2.pszSymbol ) : strcmp( entry1.pszSymbol, entry2.pszSymbol ) );
|
|
}
|
|
};
|
|
|
|
template <bool bCaseIgnore>
|
|
class CHash
|
|
{
|
|
public:
|
|
CHash( int ignored ) {}
|
|
|
|
unsigned operator()( const Entry_t &entry ) const
|
|
{
|
|
return !( ( bCaseIgnore ) ? HashStringCaseless( entry.pszSymbol ) : HashString( entry.pszSymbol ) );
|
|
}
|
|
};
|
|
|
|
typedef CUtlHash<Entry_t, CCompare<bCaseInsensitive>, CHash<bCaseInsensitive> > CHashTable;
|
|
CHashTable m_Elements;
|
|
int m_nCount;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// constructor, destructor
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::CUtlHashDict( int bucketCount = 16, int growCount = 0, int initCount = 0 ) :
|
|
m_Elements( SmallestPowerOfTwoGreaterOrEqual(bucketCount), growCount, initCount )
|
|
{
|
|
Assert( SmallestPowerOfTwoGreaterOrEqual(bucketCount) <= 0xffff );
|
|
}
|
|
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::~CUtlHashDict()
|
|
{
|
|
Purge();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// gets particular elements
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
inline T& CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Element( unsigned i )
|
|
{
|
|
return m_Elements[i].value;
|
|
}
|
|
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
inline const T& CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Element( unsigned i ) const
|
|
{
|
|
return m_Elements[i].value;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// gets element names
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
inline char const *CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::GetElementName( unsigned i ) const
|
|
{
|
|
return m_Elements[i].pszSymbol;
|
|
}
|
|
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
inline T& CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::operator[]( unsigned i )
|
|
{
|
|
return m_Elements[i].value;
|
|
}
|
|
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
inline const T & CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::operator[]( unsigned i ) const
|
|
{
|
|
return m_Elements[i].value;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Num elements
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
inline int CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Count() const
|
|
{
|
|
Assert( m_nCount == m_Elements.Count() );
|
|
return m_nCount;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Checks if a node is valid and in the tree
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
inline bool CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::IsValidIndex( unsigned i ) const
|
|
{
|
|
return m_Elements.IsValidHandle(i);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Invalid index
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
inline unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::InvalidHandle()
|
|
{
|
|
return CHashTable::InvalidHandle();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Delete a node from the tree
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::RemoveAt(unsigned elem)
|
|
{
|
|
if ( bDupeStrings )
|
|
{
|
|
free( (void *)m_Elements[elem].pszSymbol );
|
|
}
|
|
m_Elements.Remove(elem);
|
|
m_nCount--;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// remove a node in the tree
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings> void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Remove( const char *search )
|
|
{
|
|
unsigned node = Find( search );
|
|
if (node != InvalidHandle())
|
|
{
|
|
RemoveAt(node);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Removes all nodes from the tree
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::RemoveAll()
|
|
{
|
|
if ( bDupeStrings )
|
|
{
|
|
UtlHashHandle_t index = m_Elements.GetFirstHandle();
|
|
while ( index != m_Elements.InvalidHandle() )
|
|
{
|
|
free( (void *)m_Elements[index].pszSymbol );
|
|
index = m_Elements.GetNextHandle( index );
|
|
}
|
|
}
|
|
|
|
m_Elements.RemoveAll();
|
|
m_nCount = 0;
|
|
}
|
|
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Purge()
|
|
{
|
|
if ( bDupeStrings )
|
|
{
|
|
UtlHashHandle_t index = m_Elements.GetFirstHandle();
|
|
while ( index != m_Elements.InvalidHandle() )
|
|
{
|
|
free( (void *)m_Elements[index].pszSymbol );
|
|
index = m_Elements.GetNextHandle( index );
|
|
}
|
|
}
|
|
|
|
m_Elements.Purge();
|
|
m_nCount = 0;
|
|
}
|
|
|
|
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
void CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::PurgeAndDeleteElements()
|
|
{
|
|
// Delete all the elements.
|
|
unsigned index = m_Elements.GetFirstHandle();
|
|
while ( index != m_Elements.InvalidHandle() )
|
|
{
|
|
if ( bDupeStrings )
|
|
{
|
|
free( (void *)m_Elements[index].pszSymbol );
|
|
}
|
|
delete m_Elements[index].value;
|
|
index = m_Elements.GetNextHandle( index );
|
|
}
|
|
|
|
m_Elements.RemoveAll();
|
|
m_nCount = 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// inserts a node into the tree
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Insert( const char *pName, const T &element )
|
|
{
|
|
MEM_ALLOC_CREDIT_CLASS();
|
|
m_nCount++;
|
|
Entry_t entry =
|
|
{
|
|
(bDupeStrings) ? strdup( pName ) : pName,
|
|
element
|
|
};
|
|
bool bInserted;
|
|
unsigned result = m_Elements.Insert( entry, &bInserted );
|
|
if ( bDupeStrings && !bInserted )
|
|
{
|
|
free( (void *)entry.pszSymbol );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Insert( const char *pName )
|
|
{
|
|
MEM_ALLOC_CREDIT_CLASS();
|
|
m_nCount++;
|
|
Entry_t entry =
|
|
{
|
|
(bDupeStrings) ? strdup( pName ) : pName
|
|
};
|
|
bool bInserted;
|
|
unsigned result = m_Elements.Insert( entry, &bInserted );
|
|
if ( bDupeStrings && !bInserted )
|
|
{
|
|
free( (void *)entry.pszSymbol );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// finds a node in the tree
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Find( const char *pName ) const
|
|
{
|
|
MEM_ALLOC_CREDIT_CLASS();
|
|
if ( pName )
|
|
return m_Elements.Find( *((Entry_t *)&pName) );
|
|
else
|
|
return InvalidHandle();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Iteration methods
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::First() const
|
|
{
|
|
return m_Elements.GetFirstHandle();
|
|
}
|
|
|
|
template <typename T, bool bCaseInsensitive, bool bDupeStrings>
|
|
unsigned CUtlHashDict<T, bCaseInsensitive, bDupeStrings>::Next( unsigned i ) const
|
|
{
|
|
return m_Elements.GetNextHandle(i);
|
|
}
|
|
|
|
#endif // UTLHASHDICT_H
|