326 lines
10 KiB
C++
326 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 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
|