mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
This ensures that we can never allocate more memory than the maximum value that type could hold, without triggering a compile warning. There was a mention about shorts being slow on PowerPC platforms for utllinkedlist, but the index local type could be overridden (defaults to index storage type). In case it gets used for PowerPC, use 32bit ints as index local types; as the local type gets used for arithmetic operations while storage type is what's getting cached off in memory. This patch had no effect on generated output code, it was mostly implemented to avoid future problems.
364 lines
10 KiB
C++
364 lines
10 KiB
C++
//============ 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 "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( decltype(dictName)::IndexType_t 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 ( decltype(dictName)::IndexType_t 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;
|
|
typedef I IndexType_t;
|
|
|
|
// constructor, destructor
|
|
// Left at growSize = 0, the memory will first allocate 1 element and double in size
|
|
// at each increment.
|
|
CUtlDict( EDictCompareType compareType = k_eDictCompareTypeCaseInsensitive, I growSize = 0, I initSize = 0 );
|
|
~CUtlDict( );
|
|
|
|
void EnsureCapacity( I );
|
|
|
|
// 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
|
|
I 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( EDictCompareType compareType, I growSize, I 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( I 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 I 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
|