|
|
//====== Copyright � 1996-2005, 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
//-----------------------------------------------------------------------------
// This is a useful macro to iterate from start to end in order in a map
#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: typedef const char* KeyType_t; typedef T ElemType_t;
// 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 const_cast< 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( const_cast< char* >( 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( const_cast< char* >( 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() ) { const char* p = m_Elements.Key( index ); free( const_cast< char* >( p ) ); 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() ) { const char* p = m_Elements.Key( index ); free( const_cast< char* >( p ) ); 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
|