353 lines
7.2 KiB
C++
353 lines
7.2 KiB
C++
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//
|
|
//=============================================================================//
|
|
#ifndef __LIST_H__
|
|
#define __LIST_H__
|
|
|
|
// TODO:
|
|
// GetPositionAtIndex needs to keep a cache of the previous call so
|
|
// that it doesn't do a linear search every time.
|
|
|
|
#include <stdlib.h>
|
|
|
|
// FIXME: change the name of this to something more specific.
|
|
typedef struct
|
|
{
|
|
} _Position;
|
|
typedef _Position *Position;
|
|
|
|
template <class T> class GList;
|
|
template <class T> class GListIterator;
|
|
|
|
// GListNode: Class decleration and definition
|
|
template <class T> class GListNode
|
|
{
|
|
private:
|
|
T data;
|
|
GListNode<T> *next;
|
|
GListNode<T> *prev;
|
|
GListNode();
|
|
GListNode( T item );
|
|
friend class GList<T>;
|
|
friend class GListIterator<T>;
|
|
};
|
|
|
|
template <class T>
|
|
GListNode<T>::GListNode()
|
|
{
|
|
next = NULL;
|
|
prev = NULL;
|
|
}
|
|
|
|
template <class T>
|
|
GListNode<T>::GListNode( T item )
|
|
{
|
|
data = item;
|
|
next = NULL;
|
|
prev = NULL;
|
|
}
|
|
|
|
// GList: Class decleration and definition
|
|
template <class T> class GList
|
|
{
|
|
public:
|
|
// Contructors/destructors
|
|
GList();
|
|
|
|
//
|
|
Position InsertAtHead( T );
|
|
Position InsertAtTail( T );
|
|
T Remove( Position position );
|
|
void RemoveAll( void (*DeleteItem)( T ) );
|
|
void RemoveSelectedItems( bool (*NeedsRemovalFunc)( T ), void (*DeleteItemFunc)( T ) );
|
|
Position InsertAfter( T item, Position position );
|
|
Position InsertBefore( T item, Position position );
|
|
bool IsEmpty();
|
|
int GetNumItems();
|
|
T GetItemAtPosition( Position position );
|
|
Position GetPositionAtIndex( int index );
|
|
T GetItemAtIndex( int index );
|
|
|
|
protected:
|
|
GListNode<T> *head;
|
|
GListNode<T> *tail;
|
|
int numItems;
|
|
friend class GListIterator<T>;
|
|
};
|
|
|
|
template<class T>
|
|
GList<T>::GList()
|
|
{
|
|
// Set up a dummy head node and a dummy tail node.
|
|
head = new GListNode<T>;
|
|
tail = new GListNode<T>;
|
|
head->next = tail;
|
|
head->prev = head;
|
|
tail->next = tail;
|
|
tail->prev = head;
|
|
numItems = 0;
|
|
}
|
|
|
|
template<class T>
|
|
Position GList<T>::InsertAtHead( T item )
|
|
{
|
|
GListNode<T> *newNode = new GListNode<T>( item );
|
|
head->next->prev = newNode;
|
|
newNode->next = head->next;
|
|
newNode->prev = head;
|
|
head->next = newNode;
|
|
numItems++;
|
|
return ( Position )( void * )newNode;
|
|
}
|
|
|
|
template<class T>
|
|
Position GList<T>::InsertAtTail( T item )
|
|
{
|
|
GListNode<T> *newNode = new GListNode<T>( item );
|
|
tail->prev->next = newNode;
|
|
newNode->prev = tail->prev;
|
|
tail->prev = newNode;
|
|
newNode->next = tail;
|
|
numItems++;
|
|
return ( Position )( void * )newNode;
|
|
}
|
|
|
|
template<class T>
|
|
T GList<T>::Remove( Position position )
|
|
{
|
|
GListNode<T> *node = ( GListNode<T> * )( void * )position;
|
|
node->prev->next = node->next;
|
|
node->next->prev = node->prev;
|
|
T data = node->data;
|
|
numItems--;
|
|
delete node;
|
|
return data;
|
|
}
|
|
|
|
template<class T>
|
|
void GList<T>::RemoveAll( void (*DeleteItemFunc)( T ) )
|
|
{
|
|
GListNode<T> *tmpNode;
|
|
GListNode<T> *node = head->next;
|
|
while( node != tail )
|
|
{
|
|
if( DeleteItemFunc )
|
|
{
|
|
DeleteItemFunc( node->data );
|
|
}
|
|
tmpNode = node->next;
|
|
delete node;
|
|
node = tmpNode;
|
|
}
|
|
head->next = tail;
|
|
head->prev = head;
|
|
tail->next = tail;
|
|
tail->prev = head;
|
|
numItems = 0;
|
|
}
|
|
|
|
template<class T>
|
|
void GList<T>::RemoveSelectedItems( bool (*NeedsRemovalFunc)( T ), void (*DeleteItemFunc)( T ) )
|
|
{
|
|
GListNode<T> *tmpNode;
|
|
GListNode<T> *node = head->next;
|
|
while( node != tail )
|
|
{
|
|
if( NeedsRemovalFunc( node->data ) )
|
|
{
|
|
DeleteItemFunc( node->data );
|
|
node->prev->next = node->next;
|
|
node->next->prev = node->prev;
|
|
tmpNode = node;
|
|
node = node->next;
|
|
delete tmpNode;
|
|
numItems--;
|
|
}
|
|
else
|
|
{
|
|
node = node->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<class T>
|
|
Position GList<T>::InsertAfter( T item, Position position )
|
|
{
|
|
GListNode<T> *node = ( GListNode<T> * )( void * )position;
|
|
GListNode<T> *newNode = new GListNode<T>( item );
|
|
newNode->prev = node;
|
|
newNode->next = node->next;
|
|
node->next->prev = newNode;
|
|
node->next = newNode;
|
|
numItems++;
|
|
return ( Position )( void * )newNode;
|
|
}
|
|
|
|
template<class T>
|
|
Position GList<T>::InsertBefore( T item, Position position )
|
|
{
|
|
GListNode<T> *node = ( GListNode<T> * )( void * )position;
|
|
GListNode<T> *newNode = new GListNode<T>( item );
|
|
newNode->prev = node->prev;
|
|
newNode->next = node;
|
|
node->prev->next = newNode;
|
|
node->prev = newNode;
|
|
numItems++;
|
|
return ( Position )( void * )newNode;
|
|
}
|
|
|
|
template<class T>
|
|
bool GList<T>::IsEmpty()
|
|
{
|
|
return ( numItems == 0 );
|
|
}
|
|
|
|
template <class T>
|
|
int GList<T>::GetNumItems()
|
|
{
|
|
return numItems;
|
|
}
|
|
|
|
template<class T>
|
|
T GList<T>::GetItemAtPosition( Position position )
|
|
{
|
|
return ( ( GListNode<T> * )( void * )position )->data;
|
|
}
|
|
|
|
template<class T>
|
|
Position GList<T>::GetPositionAtIndex( int index )
|
|
{
|
|
int i;
|
|
GListNode<T> *node = head->next;
|
|
for( i = 0; i < index; i++ )
|
|
{
|
|
node = node->next;
|
|
}
|
|
return ( Position )( void * )node;
|
|
}
|
|
|
|
template<class T>
|
|
T GList<T>::GetItemAtIndex( int index )
|
|
{
|
|
return GetItemAtPosition( GetPositionAtIndex( index ) );
|
|
}
|
|
|
|
// GListIterator: Class decleration and definition
|
|
template<class T> class GListIterator
|
|
{
|
|
public:
|
|
GListIterator( GList<T> *GList );
|
|
void GotoHead( void );
|
|
void GotoTail( void );
|
|
void Goto( int index );
|
|
void Increment();
|
|
void Decrement();
|
|
T GetCurrentAndIncrement();
|
|
T GetCurrentAndDecrement();
|
|
T IncrementAndGetCurrent();
|
|
T DecrementAndGetCurrent();
|
|
// postfix
|
|
T operator++( int ) { return GetCurrentAndIncrement(); }
|
|
T operator--( int ) { return GetCurrentAndDecrement(); }
|
|
// prefix
|
|
T operator++() { return IncrementAndGetCurrent(); }
|
|
T operator--() { return DecrementAndGetCurrent(); }
|
|
T GetCurrent();
|
|
bool AtEnd( void );
|
|
bool AtBeginning( void );
|
|
protected:
|
|
GList<T> *list;
|
|
GListNode<T> *currentNode;
|
|
};
|
|
|
|
template<class T>
|
|
GListIterator<T>::GListIterator( GList<T> *list )
|
|
{
|
|
this->list = list;
|
|
GotoHead();
|
|
}
|
|
|
|
template<class T>
|
|
void GListIterator<T>::GotoHead()
|
|
{
|
|
this->currentNode = list->head->next;
|
|
}
|
|
|
|
template<class T>
|
|
void GListIterator<T>::GotoTail()
|
|
{
|
|
this->currentNode = list->tail->prev;
|
|
}
|
|
|
|
template<class T>
|
|
void GListIterator<T>::Goto( int index )
|
|
{
|
|
currentNode = ( GListNode<T> * )( void * )list->GetPositionAtIndex( index );
|
|
}
|
|
|
|
template<class T>
|
|
void GListIterator<T>::Increment()
|
|
{
|
|
currentNode = currentNode->next;
|
|
}
|
|
|
|
template<class T>
|
|
void GListIterator<T>::Decrement()
|
|
{
|
|
currentNode = currentNode->prev;
|
|
}
|
|
|
|
template<class T>
|
|
T GListIterator<T>::GetCurrentAndIncrement()
|
|
{
|
|
T retval = currentNode->data;
|
|
Increment();
|
|
return retval;
|
|
}
|
|
|
|
template<class T>
|
|
T GListIterator<T>::GetCurrentAndDecrement()
|
|
{
|
|
T retval = currentNode->data;
|
|
Decrement();
|
|
return retval;
|
|
}
|
|
|
|
template<class T>
|
|
T GListIterator<T>::IncrementAndGetCurrent()
|
|
{
|
|
Increment();
|
|
return GetCurrent();
|
|
}
|
|
|
|
template<class T>
|
|
T GListIterator<T>::DecrementAndGetCurrent()
|
|
{
|
|
Decrement();
|
|
return GetCurrent();
|
|
}
|
|
|
|
template<class T>
|
|
T GListIterator<T>::GetCurrent()
|
|
{
|
|
return currentNode->data;
|
|
}
|
|
|
|
template<class T>
|
|
bool GListIterator<T>::AtEnd( void )
|
|
{
|
|
return currentNode->next == currentNode;
|
|
}
|
|
|
|
template<class T>
|
|
bool GListIterator<T>::AtBeginning( void )
|
|
{
|
|
return currentNode->prev == currentNode;
|
|
}
|
|
|
|
#endif /* __LIST_H__ */
|