Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

358 lines
9.8 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A dictionary mapping from symbol to structure
//
// $Header: $
// $NoKeywords: $
//=============================================================================//
#ifndef UTLDICT_H
#define UTLDICT_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
#include "tier1/utlmap.h"
// Include this because tons of code was implicitly getting utlsymbol or utlvector via utldict.h
#include "tier1/utlsymbol.h"
#include "tier0/memdbgon.h"
enum EDictCompareType
{
k_eDictCompareTypeCaseSensitive=0,
k_eDictCompareTypeCaseInsensitive=1,
k_eDictCompareTypeFilenames // Slashes and backslashes count as the same character..
};
//-----------------------------------------------------------------------------
// A dictionary mapping from symbol to structure
//-----------------------------------------------------------------------------
#define FOR_EACH_DICT( dictName, iteratorName ) \
for( int iteratorName=dictName.First(); iteratorName != dictName.InvalidIndex(); iteratorName = dictName.Next( iteratorName ) )
// faster iteration, but in an unspecified order
#define FOR_EACH_DICT_FAST( dictName, iteratorName ) \
for ( int iteratorName = 0; iteratorName < dictName.MaxElement(); ++iteratorName ) if ( !dictName.IsValidIndex( iteratorName ) ) continue; else
//-----------------------------------------------------------------------------
// A dictionary mapping from symbol to structure
//-----------------------------------------------------------------------------
template <class T, class I = int >
class CUtlDict
{
public:
// constructor, destructor
// Left at growSize = 0, the memory will first allocate 1 element and double in size
// at each increment.
CUtlDict( int compareType = k_eDictCompareTypeCaseInsensitive, int growSize = 0, int initSize = 0 );
~CUtlDict( );
void EnsureCapacity( int );
// gets particular elements
T& Element( I i );
const T& Element( I i ) const;
T& operator[]( I i );
const T& operator[]( I i ) const;
// gets element names
char *GetElementName( I i );
char const *GetElementName( I i ) const;
void SetElementName( I i, char const *pName );
// Number of elements
unsigned int Count() const;
// Number of allocated slots
I MaxElement() const;
// Checks if a node is valid and in the tree
bool IsValidIndex( I i ) const;
// Invalid index
static I InvalidIndex();
// Insert method (inserts in order)
I Insert( const char *pName, const T &element );
I Insert( const char *pName );
// Find method
I Find( const char *pName ) const;
bool HasElement( const char *pName ) const;
// Remove methods
void RemoveAt( I i );
void Remove( const char *pName );
void RemoveAll( );
// Purge memory
void Purge();
void PurgeAndDeleteElements(); // Call delete on each element.
// Iteration methods
I First() const;
I Next( I i ) const;
// Nested typedefs, for code that might need
// to fish out the index type from a given dict
typedef I IndexType_t;
protected:
typedef CUtlMap<const char *, T, I> DictElementMap_t;
DictElementMap_t m_Elements;
};
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
template <class T, class I>
CUtlDict<T, I>::CUtlDict( int compareType, int growSize, int initSize ) : m_Elements( growSize, initSize )
{
if ( compareType == k_eDictCompareTypeFilenames )
{
m_Elements.SetLessFunc( CaselessStringLessThanIgnoreSlashes );
}
else if ( compareType == k_eDictCompareTypeCaseInsensitive )
{
m_Elements.SetLessFunc( CaselessStringLessThan );
}
else
{
m_Elements.SetLessFunc( StringLessThan );
}
}
template <class T, class I>
CUtlDict<T, I>::~CUtlDict()
{
Purge();
}
template <class T, class I>
inline void CUtlDict<T, I>::EnsureCapacity( int num )
{
return m_Elements.EnsureCapacity( num );
}
//-----------------------------------------------------------------------------
// gets particular elements
//-----------------------------------------------------------------------------
template <class T, class I>
inline T& CUtlDict<T, I>::Element( I i )
{
return m_Elements[i];
}
template <class T, class I>
inline const T& CUtlDict<T, I>::Element( I i ) const
{
return m_Elements[i];
}
//-----------------------------------------------------------------------------
// gets element names
//-----------------------------------------------------------------------------
template <class T, class I>
inline char *CUtlDict<T, I>::GetElementName( I i )
{
return (char *)m_Elements.Key( i );
}
template <class T, class I>
inline char const *CUtlDict<T, I>::GetElementName( I i ) const
{
return m_Elements.Key( i );
}
template <class T, class I>
inline T& CUtlDict<T, I>::operator[]( I i )
{
return Element(i);
}
template <class T, class I>
inline const T & CUtlDict<T, I>::operator[]( I i ) const
{
return Element(i);
}
template <class T, class I>
inline void CUtlDict<T, I>::SetElementName( I i, char const *pName )
{
MEM_ALLOC_CREDIT_CLASS();
// TODO: This makes a copy of the old element
// TODO: This relies on the rb tree putting the most recently
// removed element at the head of the insert list
free( (void *)m_Elements.Key( i ) );
m_Elements.Reinsert( strdup( pName ), i );
}
//-----------------------------------------------------------------------------
// Num elements
//-----------------------------------------------------------------------------
template <class T, class I>
inline unsigned int CUtlDict<T, I>::Count() const
{
return m_Elements.Count();
}
//-----------------------------------------------------------------------------
// Number of allocated slots
//-----------------------------------------------------------------------------
template <class T, class I>
inline I CUtlDict<T, I>::MaxElement() const
{
return m_Elements.MaxElement();
}
//-----------------------------------------------------------------------------
// Checks if a node is valid and in the tree
//-----------------------------------------------------------------------------
template <class T, class I>
inline bool CUtlDict<T, I>::IsValidIndex( I i ) const
{
return m_Elements.IsValidIndex(i);
}
//-----------------------------------------------------------------------------
// Invalid index
//-----------------------------------------------------------------------------
template <class T, class I>
inline I CUtlDict<T, I>::InvalidIndex()
{
return DictElementMap_t::InvalidIndex();
}
//-----------------------------------------------------------------------------
// Delete a node from the tree
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlDict<T, I>::RemoveAt(I elem)
{
free( (void *)m_Elements.Key( elem ) );
m_Elements.RemoveAt(elem);
}
//-----------------------------------------------------------------------------
// remove a node in the tree
//-----------------------------------------------------------------------------
template <class T, class I> void CUtlDict<T, I>::Remove( const char *search )
{
I node = Find( search );
if (node != InvalidIndex())
{
RemoveAt(node);
}
}
//-----------------------------------------------------------------------------
// Removes all nodes from the tree
//-----------------------------------------------------------------------------
template <class T, class I>
void CUtlDict<T, I>::RemoveAll()
{
typename DictElementMap_t::IndexType_t index = m_Elements.FirstInorder();
while ( index != m_Elements.InvalidIndex() )
{
free( (void *)m_Elements.Key( index ) );
index = m_Elements.NextInorder( index );
}
m_Elements.RemoveAll();
}
template <class T, class I>
void CUtlDict<T, I>::Purge()
{
RemoveAll();
}
template <class T, class I>
void CUtlDict<T, I>::PurgeAndDeleteElements()
{
// Delete all the elements.
I index = m_Elements.FirstInorder();
while ( index != m_Elements.InvalidIndex() )
{
free( (void *)m_Elements.Key( index ) );
delete m_Elements[index];
index = m_Elements.NextInorder( index );
}
m_Elements.RemoveAll();
}
//-----------------------------------------------------------------------------
// inserts a node into the tree
//-----------------------------------------------------------------------------
template <class T, class I>
I CUtlDict<T, I>::Insert( const char *pName, const T &element )
{
MEM_ALLOC_CREDIT_CLASS();
return m_Elements.Insert( strdup( pName ), element );
}
template <class T, class I>
I CUtlDict<T, I>::Insert( const char *pName )
{
MEM_ALLOC_CREDIT_CLASS();
return m_Elements.Insert( strdup( pName ) );
}
//-----------------------------------------------------------------------------
// finds a node in the tree
//-----------------------------------------------------------------------------
template <class T, class I>
I CUtlDict<T, I>::Find( const char *pName ) const
{
MEM_ALLOC_CREDIT_CLASS();
if ( pName )
return m_Elements.Find( pName );
else
return InvalidIndex();
}
//-----------------------------------------------------------------------------
// returns true if we already have this node
//-----------------------------------------------------------------------------
template <class T, class I>
bool CUtlDict<T, I>::HasElement( const char *pName ) const
{
if ( pName )
return m_Elements.IsValidIndex( m_Elements.Find( pName ) );
else
return false;
}
//-----------------------------------------------------------------------------
// Iteration methods
//-----------------------------------------------------------------------------
template <class T, class I>
I CUtlDict<T, I>::First() const
{
return m_Elements.FirstInorder();
}
template <class T, class I>
I CUtlDict<T, I>::Next( I i ) const
{
return m_Elements.NextInorder(i);
}
#include "tier0/memdbgoff.h"
#endif // UTLDICT_H