//========= Copyright 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 // FIXME: change the name of this to something more specific. typedef struct { } _Position; typedef _Position *Position; template class GList; template class GListIterator; // GListNode: Class decleration and definition template class GListNode { private: T data; GListNode *next; GListNode *prev; GListNode(); GListNode( T item ); friend class GList; friend class GListIterator; }; template GListNode::GListNode() { next = NULL; prev = NULL; } template GListNode::GListNode( T item ) { data = item; next = NULL; prev = NULL; } // GList: Class decleration and definition template 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 *head; GListNode *tail; int numItems; friend class GListIterator; }; template GList::GList() { // Set up a dummy head node and a dummy tail node. head = new GListNode; tail = new GListNode; head->next = tail; head->prev = head; tail->next = tail; tail->prev = head; numItems = 0; } template Position GList::InsertAtHead( T item ) { GListNode *newNode = new GListNode( item ); head->next->prev = newNode; newNode->next = head->next; newNode->prev = head; head->next = newNode; numItems++; return ( Position )( void * )newNode; } template Position GList::InsertAtTail( T item ) { GListNode *newNode = new GListNode( item ); tail->prev->next = newNode; newNode->prev = tail->prev; tail->prev = newNode; newNode->next = tail; numItems++; return ( Position )( void * )newNode; } template T GList::Remove( Position position ) { GListNode *node = ( GListNode * )( void * )position; node->prev->next = node->next; node->next->prev = node->prev; T data = node->data; numItems--; delete node; return data; } template void GList::RemoveAll( void (*DeleteItemFunc)( T ) ) { GListNode *tmpNode; GListNode *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 void GList::RemoveSelectedItems( bool (*NeedsRemovalFunc)( T ), void (*DeleteItemFunc)( T ) ) { GListNode *tmpNode; GListNode *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 Position GList::InsertAfter( T item, Position position ) { GListNode *node = ( GListNode * )( void * )position; GListNode *newNode = new GListNode( item ); newNode->prev = node; newNode->next = node->next; node->next->prev = newNode; node->next = newNode; numItems++; return ( Position )( void * )newNode; } template Position GList::InsertBefore( T item, Position position ) { GListNode *node = ( GListNode * )( void * )position; GListNode *newNode = new GListNode( item ); newNode->prev = node->prev; newNode->next = node; node->prev->next = newNode; node->prev = newNode; numItems++; return ( Position )( void * )newNode; } template bool GList::IsEmpty() { return ( numItems == 0 ); } template int GList::GetNumItems() { return numItems; } template T GList::GetItemAtPosition( Position position ) { return ( ( GListNode * )( void * )position )->data; } template Position GList::GetPositionAtIndex( int index ) { int i; GListNode *node = head->next; for( i = 0; i < index; i++ ) { node = node->next; } return ( Position )( void * )node; } template T GList::GetItemAtIndex( int index ) { return GetItemAtPosition( GetPositionAtIndex( index ) ); } // GListIterator: Class decleration and definition template class GListIterator { public: GListIterator( GList *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 *list; GListNode *currentNode; }; template GListIterator::GListIterator( GList *list ) { this->list = list; GotoHead(); } template void GListIterator::GotoHead() { this->currentNode = list->head->next; } template void GListIterator::GotoTail() { this->currentNode = list->tail->prev; } template void GListIterator::Goto( int index ) { currentNode = ( GListNode * )( void * )list->GetPositionAtIndex( index ); } template void GListIterator::Increment() { currentNode = currentNode->next; } template void GListIterator::Decrement() { currentNode = currentNode->prev; } template T GListIterator::GetCurrentAndIncrement() { T retval = currentNode->data; Increment(); return retval; } template T GListIterator::GetCurrentAndDecrement() { T retval = currentNode->data; Decrement(); return retval; } template T GListIterator::IncrementAndGetCurrent() { Increment(); return GetCurrent(); } template T GListIterator::DecrementAndGetCurrent() { Decrement(); return GetCurrent(); } template T GListIterator::GetCurrent() { return currentNode->data; } template bool GListIterator::AtEnd( void ) { return currentNode->next == currentNode; } template bool GListIterator::AtBeginning( void ) { return currentNode->prev == currentNode; } #endif /* __LIST_H__ */