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.
771 lines
20 KiB
771 lines
20 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Multiple linked list container class |
|
// |
|
// $Revision: $ |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#ifndef UTLMULTILIST_H |
|
#define UTLMULTILIST_H |
|
|
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
#include "utllinkedlist.h" |
|
|
|
// memdbgon must be the last include file in a .h file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// class CUtlMultiList: |
|
// description: |
|
// A lovely index-based linked list! T is the class type, I is the index |
|
// type, which usually should be an unsigned short or smaller. |
|
// This list can contain multiple lists |
|
//----------------------------------------------------------------------------- |
|
template <class T, class I> |
|
class CUtlMultiList |
|
{ |
|
protected: |
|
// What the linked list element looks like |
|
struct ListElem_t |
|
{ |
|
T m_Element; |
|
I m_Previous; |
|
I m_Next; |
|
}; |
|
|
|
struct List_t |
|
{ |
|
I m_Head; |
|
I m_Tail; |
|
I m_Count; |
|
}; |
|
|
|
typedef CUtlMemory<ListElem_t> M; // Keep naming similar to CUtlLinkedList |
|
public: |
|
typedef I ListHandle_t; |
|
|
|
// constructor, destructor |
|
CUtlMultiList( int growSize = 0, int initSize = 0 ); |
|
CUtlMultiList( void *pMemory, int memsize ); |
|
~CUtlMultiList( ); |
|
|
|
// gets particular elements |
|
T& Element( I i ); |
|
T const& Element( I i ) const; |
|
T& operator[]( I i ); |
|
T const& operator[]( I i ) const; |
|
|
|
// Make sure we have a particular amount of memory |
|
void EnsureCapacity( int num ); |
|
|
|
// Memory deallocation |
|
void Purge(); |
|
|
|
// List Creation/deletion |
|
ListHandle_t CreateList(); |
|
void DestroyList( ListHandle_t list ); |
|
bool IsValidList( ListHandle_t list ) const; |
|
|
|
// Insertion methods (call default constructor).... |
|
I InsertBefore( ListHandle_t list, I before ); |
|
I InsertAfter( ListHandle_t list, I after ); |
|
I AddToHead( ListHandle_t list ); |
|
I AddToTail( ListHandle_t list ); |
|
|
|
// Insertion methods (call copy constructor).... |
|
I InsertBefore( ListHandle_t list, I before, T const& src ); |
|
I InsertAfter( ListHandle_t list, I after, T const& src ); |
|
I AddToHead( ListHandle_t list, T const& src ); |
|
I AddToTail( ListHandle_t list, T const& src ); |
|
|
|
// Removal methods |
|
void Remove( ListHandle_t list, I elem ); |
|
|
|
// Removes all items in a single list |
|
void RemoveAll( ListHandle_t list ); |
|
|
|
// Removes all items in all lists |
|
void RemoveAll(); |
|
|
|
// Allocation/deallocation methods |
|
// NOTE: To free, it must *not* be in a list! |
|
I Alloc( ); |
|
void Free( I elem ); |
|
|
|
// list modification |
|
void LinkBefore( ListHandle_t list, I before, I elem ); |
|
void LinkAfter( ListHandle_t list, I after, I elem ); |
|
void Unlink( ListHandle_t list, I elem ); |
|
void LinkToHead( ListHandle_t list, I elem ); |
|
void LinkToTail( ListHandle_t list, I elem ); |
|
|
|
// invalid index |
|
static I InvalidIndex() { return (I)~0; } |
|
static bool IndexInRange( int index ); |
|
static size_t ElementSize() { return sizeof(ListElem_t); } |
|
|
|
// list statistics |
|
int Count( ListHandle_t list ) const; |
|
int TotalCount( ) const; |
|
I MaxElementIndex() const; |
|
|
|
// Traversing the list |
|
I Head( ListHandle_t list ) const; |
|
I Tail( ListHandle_t list ) const; |
|
I Previous( I element ) const; |
|
I Next( I element ) const; |
|
|
|
// Are nodes in a list or valid? |
|
bool IsValidIndex( I i ) const; |
|
bool IsInList( I i ) const; |
|
|
|
protected: |
|
// constructs the class |
|
void ConstructList( ); |
|
|
|
// Gets at the list element.... |
|
ListElem_t& InternalElement( I i ) { return m_Memory[i]; } |
|
ListElem_t const& InternalElement( I i ) const { return m_Memory[i]; } |
|
|
|
// A test for debug mode only... |
|
bool IsElementInList( ListHandle_t list, I elem ) const; |
|
|
|
// copy constructors not allowed |
|
CUtlMultiList( CUtlMultiList<T, I> const& list ) { Assert(0); } |
|
|
|
M m_Memory; |
|
CUtlLinkedList<List_t, I> m_List; |
|
I* m_pElementList; |
|
|
|
I m_FirstFree; |
|
I m_TotalElements; |
|
int m_MaxElementIndex; // The number allocated (use int so we can catch overflow) |
|
|
|
void ResetDbgInfo() |
|
{ |
|
m_pElements = m_Memory.Base(); |
|
|
|
#ifdef _DEBUG |
|
// Allocate space for the element list (which list is each element in) |
|
if (m_Memory.NumAllocated() > 0) |
|
{ |
|
if (!m_pElementList) |
|
{ |
|
m_pElementList = (I*)malloc( m_Memory.NumAllocated() * sizeof(I) ); |
|
} |
|
else |
|
{ |
|
m_pElementList = (I*)realloc( m_pElementList, m_Memory.NumAllocated() * sizeof(I) ); |
|
} |
|
} |
|
#endif |
|
} |
|
|
|
// For debugging purposes; |
|
// it's in release builds so this can be used in libraries correctly |
|
ListElem_t *m_pElements; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// constructor, destructor |
|
//----------------------------------------------------------------------------- |
|
|
|
template <class T, class I> |
|
CUtlMultiList<T,I>::CUtlMultiList( int growSize, int initSize ) : |
|
m_Memory(growSize, initSize), m_pElementList(0) |
|
{ |
|
ConstructList(); |
|
} |
|
|
|
template <class T, class I> |
|
CUtlMultiList<T,I>::CUtlMultiList( void* pMemory, int memsize ) : |
|
m_Memory((ListElem_t *)pMemory, memsize/sizeof(ListElem_t)), m_pElementList(0) |
|
{ |
|
ConstructList(); |
|
} |
|
|
|
template <class T, class I> |
|
CUtlMultiList<T,I>::~CUtlMultiList( ) |
|
{ |
|
RemoveAll(); |
|
if (m_pElementList) |
|
free(m_pElementList); |
|
} |
|
|
|
template <class T, class I> |
|
void CUtlMultiList<T,I>::ConstructList( ) |
|
{ |
|
m_FirstFree = InvalidIndex(); |
|
m_TotalElements = 0; |
|
m_MaxElementIndex = 0; |
|
ResetDbgInfo(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// gets particular elements |
|
//----------------------------------------------------------------------------- |
|
template <class T, class I> |
|
inline T& CUtlMultiList<T,I>::Element( I i ) |
|
{ |
|
return m_Memory[i].m_Element; |
|
} |
|
|
|
template <class T, class I> |
|
inline T const& CUtlMultiList<T,I>::Element( I i ) const |
|
{ |
|
return m_Memory[i].m_Element; |
|
} |
|
|
|
template <class T, class I> |
|
inline T& CUtlMultiList<T,I>::operator[]( I i ) |
|
{ |
|
return m_Memory[i].m_Element; |
|
} |
|
|
|
template <class T, class I> |
|
inline T const& CUtlMultiList<T,I>::operator[]( I i ) const |
|
{ |
|
return m_Memory[i].m_Element; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// list creation/destruction |
|
//----------------------------------------------------------------------------- |
|
template <class T, class I> |
|
typename CUtlMultiList<T,I>::ListHandle_t CUtlMultiList<T,I>::CreateList() |
|
{ |
|
ListHandle_t l = m_List.AddToTail(); |
|
m_List[l].m_Head = m_List[l].m_Tail = InvalidIndex(); |
|
m_List[l].m_Count = 0; |
|
return l; |
|
} |
|
|
|
template <class T, class I> |
|
void CUtlMultiList<T,I>::DestroyList( ListHandle_t list ) |
|
{ |
|
Assert( IsValidList(list) ); |
|
RemoveAll( list ); |
|
m_List.Remove(list); |
|
} |
|
|
|
template <class T, class I> |
|
bool CUtlMultiList<T,I>::IsValidList( ListHandle_t list ) const |
|
{ |
|
return m_List.IsValidIndex(list); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// list statistics |
|
//----------------------------------------------------------------------------- |
|
template <class T, class I> |
|
inline int CUtlMultiList<T,I>::TotalCount() const |
|
{ |
|
return m_TotalElements; |
|
} |
|
|
|
template <class T, class I> |
|
inline int CUtlMultiList<T,I>::Count( ListHandle_t list ) const |
|
{ |
|
Assert( IsValidList(list) ); |
|
return m_List[list].m_Count; |
|
} |
|
|
|
template <class T, class I> |
|
inline I CUtlMultiList<T,I>::MaxElementIndex() const |
|
{ |
|
return m_MaxElementIndex; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Traversing the list |
|
//----------------------------------------------------------------------------- |
|
template <class T, class I> |
|
inline I CUtlMultiList<T,I>::Head(ListHandle_t list) const |
|
{ |
|
Assert( IsValidList(list) ); |
|
return m_List[list].m_Head; |
|
} |
|
|
|
template <class T, class I> |
|
inline I CUtlMultiList<T,I>::Tail(ListHandle_t list) const |
|
{ |
|
Assert( IsValidList(list) ); |
|
return m_List[list].m_Tail; |
|
} |
|
|
|
template <class T, class I> |
|
inline I CUtlMultiList<T,I>::Previous( I i ) const |
|
{ |
|
Assert( IsValidIndex(i) ); |
|
return InternalElement(i).m_Previous; |
|
} |
|
|
|
template <class T, class I> |
|
inline I CUtlMultiList<T,I>::Next( I i ) const |
|
{ |
|
Assert( IsValidIndex(i) ); |
|
return InternalElement(i).m_Next; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Are nodes in the list or valid? |
|
//----------------------------------------------------------------------------- |
|
|
|
template <class T, class I> |
|
inline bool CUtlMultiList<T,I>::IndexInRange( int index ) // Static method |
|
{ |
|
// Since I is not necessarily the type returned by M (int), we need to check that M returns |
|
// indices which are representable by I. A common case is 'I === unsigned short', in which case |
|
// case CUtlMemory will have 'InvalidIndex == (int)-1' (which casts to 65535 in I), and will |
|
// happily return elements at index 65535 and above. |
|
|
|
// Do a couple of static checks here: the invalid index should be (I)~0 given how we use m_MaxElementIndex, |
|
// and 'I' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges). |
|
COMPILE_TIME_ASSERT( (I)M::INVALID_INDEX == (I)~0 ); |
|
COMPILE_TIME_ASSERT( ( sizeof(I) > 2 ) || ( ( (I)-1 ) > 0 ) ); |
|
|
|
return ( ( (I)index == index ) && ( (I)index != InvalidIndex() ) ); |
|
} |
|
|
|
template <class T, class I> |
|
inline bool CUtlMultiList<T,I>::IsValidIndex( I i ) const |
|
{ |
|
// GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0). |
|
// We get the warning even if we cast inside the expression. It only goes away if we assign to another variable. |
|
long x = i; |
|
|
|
return (i < m_MaxElementIndex) && (x >= 0) && |
|
((m_Memory[i].m_Previous != i) || (m_Memory[i].m_Next == i)); |
|
} |
|
|
|
template <class T, class I> |
|
inline bool CUtlMultiList<T,I>::IsInList( I i ) const |
|
{ |
|
// GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0). |
|
// We get the warning even if we cast inside the expression. It only goes away if we assign to another variable. |
|
long x = i; |
|
return (i < m_MaxElementIndex) && (x >= 0) && (Previous(i) != i); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Makes sure we have enough memory allocated to store a requested # of elements |
|
//----------------------------------------------------------------------------- |
|
template< class T, class I > |
|
void CUtlMultiList<T, I>::EnsureCapacity( int num ) |
|
{ |
|
m_Memory.EnsureCapacity(num); |
|
ResetDbgInfo(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Deallocate memory |
|
//----------------------------------------------------------------------------- |
|
template <class T, class I> |
|
void CUtlMultiList<T,I>::Purge() |
|
{ |
|
RemoveAll(); |
|
m_List.Purge(); |
|
m_Memory.Purge( ); |
|
m_List.Purge(); |
|
m_FirstFree = InvalidIndex(); |
|
m_TotalElements = 0; |
|
m_MaxElementIndex = 0; |
|
ResetDbgInfo(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Node allocation/deallocation |
|
//----------------------------------------------------------------------------- |
|
template <class T, class I> |
|
I CUtlMultiList<T,I>::Alloc( ) |
|
{ |
|
I elem; |
|
if (m_FirstFree == InvalidIndex()) |
|
{ |
|
// We can overflow before the utlmemory overflows, since we have have I != int |
|
if ( !IndexInRange( m_MaxElementIndex ) ) |
|
{ |
|
// We rarely if ever handle alloc failure. Continuing leads to corruption. |
|
Error( "CUtlMultiList overflow! (exhausted index range)\n" ); |
|
return InvalidIndex(); |
|
} |
|
|
|
// Nothing in the free list; add. |
|
// Since nothing is in the free list, m_TotalElements == total # of elements |
|
// the list knows about. |
|
if (m_MaxElementIndex == m_Memory.NumAllocated()) |
|
{ |
|
m_Memory.Grow(); |
|
ResetDbgInfo(); |
|
|
|
if ( m_MaxElementIndex >= m_Memory.NumAllocated() ) |
|
{ |
|
// We rarely if ever handle alloc failure. Continuing leads to corruption. |
|
Error( "CUtlMultiList overflow! (exhausted memory allocator)\n" ); |
|
return InvalidIndex(); |
|
} |
|
} |
|
|
|
elem = (I)m_MaxElementIndex; |
|
++m_MaxElementIndex; |
|
} |
|
else |
|
{ |
|
elem = m_FirstFree; |
|
m_FirstFree = InternalElement(m_FirstFree).m_Next; |
|
} |
|
|
|
// Mark the element as not being in a list |
|
InternalElement(elem).m_Next = InternalElement(elem).m_Previous = elem; |
|
|
|
++m_TotalElements; |
|
|
|
Construct( &Element(elem) ); |
|
|
|
return elem; |
|
} |
|
|
|
template <class T, class I> |
|
void CUtlMultiList<T,I>::Free( I elem ) |
|
{ |
|
Assert( IsValidIndex(elem) && !IsInList(elem) ); |
|
Destruct( &Element(elem) ); |
|
InternalElement(elem).m_Next = m_FirstFree; |
|
m_FirstFree = elem; |
|
--m_TotalElements; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// A test for debug mode only... |
|
//----------------------------------------------------------------------------- |
|
template <class T, class I> |
|
inline bool CUtlMultiList<T,I>::IsElementInList( ListHandle_t list, I elem ) const |
|
{ |
|
if (!m_pElementList) |
|
return true; |
|
|
|
return m_pElementList[elem] == list; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// list modification |
|
//----------------------------------------------------------------------------- |
|
template <class T, class I> |
|
void CUtlMultiList<T,I>::LinkBefore( ListHandle_t list, I before, I elem ) |
|
{ |
|
Assert( IsValidIndex(elem) && IsValidList(list) ); |
|
|
|
// Unlink it if it's in the list at the moment |
|
Unlink(list, elem); |
|
|
|
ListElem_t& newElem = InternalElement(elem); |
|
|
|
// The element *after* our newly linked one is the one we linked before. |
|
newElem.m_Next = before; |
|
|
|
if (before == InvalidIndex()) |
|
{ |
|
// In this case, we're linking to the end of the list, so reset the tail |
|
newElem.m_Previous = m_List[list].m_Tail; |
|
m_List[list].m_Tail = elem; |
|
} |
|
else |
|
{ |
|
// Here, we're not linking to the end. Set the prev pointer to point to |
|
// the element we're linking. |
|
Assert( IsInList(before) ); |
|
ListElem_t& beforeElem = InternalElement(before); |
|
newElem.m_Previous = beforeElem.m_Previous; |
|
beforeElem.m_Previous = elem; |
|
} |
|
|
|
// Reset the head if we linked to the head of the list |
|
if (newElem.m_Previous == InvalidIndex()) |
|
m_List[list].m_Head = elem; |
|
else |
|
InternalElement(newElem.m_Previous).m_Next = elem; |
|
|
|
// one more element baby |
|
++m_List[list].m_Count; |
|
|
|
// Store the element into the list |
|
if (m_pElementList) |
|
m_pElementList[elem] = list; |
|
} |
|
|
|
template <class T, class I> |
|
void CUtlMultiList<T,I>::LinkAfter( ListHandle_t list, I after, I elem ) |
|
{ |
|
Assert( IsValidIndex(elem) ); |
|
|
|
// Unlink it if it's in the list at the moment |
|
Unlink(list, elem); |
|
|
|
ListElem_t& newElem = InternalElement(elem); |
|
|
|
// The element *before* our newly linked one is the one we linked after |
|
newElem.m_Previous = after; |
|
if (after == InvalidIndex()) |
|
{ |
|
// In this case, we're linking to the head of the list, reset the head |
|
newElem.m_Next = m_List[list].m_Head; |
|
m_List[list].m_Head = elem; |
|
} |
|
else |
|
{ |
|
// Here, we're not linking to the end. Set the next pointer to point to |
|
// the element we're linking. |
|
Assert( IsInList(after) ); |
|
ListElem_t& afterElem = InternalElement(after); |
|
newElem.m_Next = afterElem.m_Next; |
|
afterElem.m_Next = elem; |
|
} |
|
|
|
// Reset the tail if we linked to the tail of the list |
|
if (newElem.m_Next == InvalidIndex()) |
|
m_List[list].m_Tail = elem; |
|
else |
|
InternalElement(newElem.m_Next).m_Previous = elem; |
|
|
|
// one more element baby |
|
++m_List[list].m_Count; |
|
|
|
// Store the element into the list |
|
if (m_pElementList) |
|
m_pElementList[elem] = list; |
|
} |
|
|
|
template <class T, class I> |
|
void CUtlMultiList<T,I>::Unlink( ListHandle_t list, I elem ) |
|
{ |
|
Assert( IsValidIndex(elem) && IsValidList(list) ); |
|
|
|
if (IsInList(elem)) |
|
{ |
|
// Make sure the element is in the right list |
|
Assert( IsElementInList( list, elem ) ); |
|
ListElem_t& oldElem = InternalElement(elem); |
|
|
|
// If we're the first guy, reset the head |
|
// otherwise, make our previous node's next pointer = our next |
|
if (oldElem.m_Previous != InvalidIndex()) |
|
InternalElement(oldElem.m_Previous).m_Next = oldElem.m_Next; |
|
else |
|
m_List[list].m_Head = oldElem.m_Next; |
|
|
|
// If we're the last guy, reset the tail |
|
// otherwise, make our next node's prev pointer = our prev |
|
if (oldElem.m_Next != InvalidIndex()) |
|
InternalElement(oldElem.m_Next).m_Previous = oldElem.m_Previous; |
|
else |
|
m_List[list].m_Tail = oldElem.m_Previous; |
|
|
|
// This marks this node as not in the list, |
|
// but not in the free list either |
|
oldElem.m_Previous = oldElem.m_Next = elem; |
|
|
|
// One less puppy |
|
--m_List[list].m_Count; |
|
|
|
// Store the element into the list |
|
if (m_pElementList) |
|
m_pElementList[elem] = m_List.InvalidIndex(); |
|
} |
|
} |
|
|
|
template <class T, class I> |
|
inline void CUtlMultiList<T,I>::LinkToHead( ListHandle_t list, I elem ) |
|
{ |
|
LinkAfter( list, InvalidIndex(), elem ); |
|
} |
|
|
|
template <class T, class I> |
|
inline void CUtlMultiList<T,I>::LinkToTail( ListHandle_t list, I elem ) |
|
{ |
|
LinkBefore( list, InvalidIndex(), elem ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Insertion methods; allocates and links (uses default constructor) |
|
//----------------------------------------------------------------------------- |
|
template <class T, class I> |
|
I CUtlMultiList<T,I>::InsertBefore( ListHandle_t list, I before ) |
|
{ |
|
// Make a new node |
|
I newNode = Alloc(); |
|
if ( newNode == InvalidIndex() ) |
|
return newNode; |
|
|
|
// Link it in |
|
LinkBefore( list, before, newNode ); |
|
|
|
// Construct the data |
|
Construct( &Element(newNode) ); |
|
|
|
return newNode; |
|
} |
|
|
|
template <class T, class I> |
|
I CUtlMultiList<T,I>::InsertAfter( ListHandle_t list, I after ) |
|
{ |
|
// Make a new node |
|
I newNode = Alloc(); |
|
if ( newNode == InvalidIndex() ) |
|
return newNode; |
|
|
|
// Link it in |
|
LinkAfter( list, after, newNode ); |
|
|
|
// Construct the data |
|
Construct( &Element(newNode) ); |
|
|
|
return newNode; |
|
} |
|
|
|
template <class T, class I> |
|
inline I CUtlMultiList<T,I>::AddToHead( ListHandle_t list ) |
|
{ |
|
return InsertAfter( list, InvalidIndex() ); |
|
} |
|
|
|
template <class T, class I> |
|
inline I CUtlMultiList<T,I>::AddToTail( ListHandle_t list ) |
|
{ |
|
return InsertBefore( list, InvalidIndex() ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Insertion methods; allocates and links (uses copy constructor) |
|
//----------------------------------------------------------------------------- |
|
template <class T, class I> |
|
I CUtlMultiList<T,I>::InsertBefore( ListHandle_t list, I before, T const& src ) |
|
{ |
|
// Make a new node |
|
I newNode = Alloc(); |
|
if ( newNode == InvalidIndex() ) |
|
return newNode; |
|
|
|
// Link it in |
|
LinkBefore( list, before, newNode ); |
|
|
|
// Construct the data |
|
CopyConstruct( &Element(newNode), src ); |
|
|
|
return newNode; |
|
} |
|
|
|
template <class T, class I> |
|
I CUtlMultiList<T,I>::InsertAfter( ListHandle_t list, I after, T const& src ) |
|
{ |
|
// Make a new node |
|
I newNode = Alloc(); |
|
if ( newNode == InvalidIndex() ) |
|
return newNode; |
|
|
|
// Link it in |
|
LinkAfter( list, after, newNode ); |
|
|
|
// Construct the data |
|
CopyConstruct( &Element(newNode), src ); |
|
|
|
return newNode; |
|
} |
|
|
|
template <class T, class I> |
|
inline I CUtlMultiList<T,I>::AddToHead( ListHandle_t list, T const& src ) |
|
{ |
|
return InsertAfter( list, InvalidIndex(), src ); |
|
} |
|
|
|
template <class T, class I> |
|
inline I CUtlMultiList<T,I>::AddToTail( ListHandle_t list, T const& src ) |
|
{ |
|
return InsertBefore( list, InvalidIndex(), src ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Removal methods |
|
//----------------------------------------------------------------------------- |
|
template <class T, class I> |
|
void CUtlMultiList<T,I>::Remove( ListHandle_t list, I elem ) |
|
{ |
|
if (IsInList(elem)) |
|
Unlink(list, elem); |
|
Free( elem ); |
|
} |
|
|
|
// Removes all items in a single list |
|
template <class T, class I> |
|
void CUtlMultiList<T,I>::RemoveAll( ListHandle_t list ) |
|
{ |
|
Assert( IsValidList(list) ); |
|
I i = Head(list); |
|
I next; |
|
while( i != InvalidIndex() ) |
|
{ |
|
next = Next(i); |
|
Remove(list, i); |
|
i = next; |
|
} |
|
} |
|
|
|
|
|
template <class T, class I> |
|
void CUtlMultiList<T,I>::RemoveAll() |
|
{ |
|
if (m_MaxElementIndex == 0) |
|
return; |
|
|
|
// Put everything into the free list |
|
I prev = InvalidIndex(); |
|
for (int i = (int)m_MaxElementIndex; --i >= 0; ) |
|
{ |
|
// Invoke the destructor |
|
if (IsValidIndex((I)i)) |
|
Destruct( &Element((I)i) ); |
|
|
|
// next points to the next free list item |
|
InternalElement((I)i).m_Next = prev; |
|
|
|
// Indicates it's in the free list |
|
InternalElement((I)i).m_Previous = (I)i; |
|
prev = (I)i; |
|
} |
|
|
|
// First free points to the first element |
|
m_FirstFree = 0; |
|
|
|
// Clear everything else out |
|
for (I list = m_List.Head(); list != m_List.InvalidIndex(); list = m_List.Next(list) ) |
|
{ |
|
m_List[list].m_Head = InvalidIndex(); |
|
m_List[list].m_Tail = InvalidIndex(); |
|
m_List[list].m_Count = 0; |
|
} |
|
|
|
m_TotalElements = 0; |
|
} |
|
|
|
|
|
#include "tier0/memdbgoff.h" |
|
|
|
#endif // UTLMULTILIST_H
|
|
|