// Copyright (C) 2007 Id Software, Inc. // #ifndef __LINKLIST_H__ #define __LINKLIST_H__ /* ============================================================================== idLinkList Circular linked list template ============================================================================== */ template< class type > class idLinkList { public: idLinkList(); ~idLinkList(); bool IsListEmpty( void ) const; bool InList( void ) const; int Num( void ) const; void Clear( void ); void InsertBefore( idLinkList &node ); void InsertAfter( idLinkList &node ); void AddToEnd( idLinkList &node ); void AddToFront( idLinkList &node ); void Remove( void ); type * Next( void ) const; type * Prev( void ) const; type * Owner( void ) const; void SetOwner( type *object ); idLinkList * ListHead( void ) const; idLinkList * NextNode( void ) const; idLinkList * PrevNode( void ) const; private: idLinkList * head; idLinkList * next; idLinkList * prev; type * owner; }; /* ================ idLinkList::idLinkList Node is initialized to be the head of an empty list ================ */ template< class type > idLinkList::idLinkList() { owner = NULL; head = this; next = this; prev = this; } /* ================ idLinkList::~idLinkList Removes the node from the list, or if it's the head of a list, removes all the nodes from the list. ================ */ template< class type > idLinkList::~idLinkList() { Clear(); } /* ================ idLinkList::IsListEmpty Returns true if the list is empty. ================ */ template< class type > bool idLinkList::IsListEmpty( void ) const { return head->next == head; } /* ================ idLinkList::InList Returns true if the node is in a list. If called on the head of a list, will always return false. ================ */ template< class type > bool idLinkList::InList( void ) const { return head != this; } /* ================ idLinkList::Num Returns the number of nodes in the list. ================ */ template< class type > int idLinkList::Num( void ) const { idLinkList *node; int num; num = 0; for( node = head->next; node != head; node = node->next ) { num++; } return num; } /* ================ idLinkList::Clear If node is the head of the list, clears the list. Otherwise it just removes the node from the list. ================ */ template< class type > void idLinkList::Clear( void ) { if ( head == this ) { while( next != this ) { next->Remove(); } } else { Remove(); } } /* ================ idLinkList::Remove Removes node from list ================ */ template< class type > void idLinkList::Remove( void ) { // don't call Remove() on the head element, or head needs to be updated in all the links assert( IsListEmpty() || head != this ); prev->next = next; next->prev = prev; next = this; prev = this; head = this; } /* ================ idLinkList::InsertBefore Places the node before the existing node in the list. If the existing node is the head, then the new node is placed at the end of the list. ================ */ template< class type > void idLinkList::InsertBefore( idLinkList &node ) { Remove(); next = &node; prev = node.prev; node.prev = this; prev->next = this; head = node.head; } /* ================ idLinkList::InsertAfter Places the node after the existing node in the list. If the existing node is the head, then the new node is placed at the beginning of the list. ================ */ template< class type > void idLinkList::InsertAfter( idLinkList &node ) { Remove(); prev = &node; next = node.next; node.next = this; next->prev = this; head = node.head; } /* ================ idLinkList::AddToEnd Adds node at the end of the list ================ */ template< class type > void idLinkList::AddToEnd( idLinkList &node ) { InsertBefore( *node.head ); } /* ================ idLinkList::AddToFront Adds node at the beginning of the list ================ */ template< class type > void idLinkList::AddToFront( idLinkList &node ) { InsertAfter( *node.head ); } /* ================ idLinkList::ListHead Returns the head of the list. If the node isn't in a list, it returns a pointer to itself. ================ */ template< class type > idLinkList *idLinkList::ListHead( void ) const { return head; } /* ================ idLinkList::Next Returns the next object in the list, or NULL if at the end. ================ */ template< class type > type *idLinkList::Next( void ) const { if ( !next || ( next == head ) ) { return NULL; } return next->owner; } /* ================ idLinkList::Prev Returns the previous object in the list, or NULL if at the beginning. ================ */ template< class type > type *idLinkList::Prev( void ) const { if ( !prev || ( prev == head ) ) { return NULL; } return prev->owner; } /* ================ idLinkList::NextNode Returns the next node in the list, or NULL if at the end. ================ */ template< class type > idLinkList *idLinkList::NextNode( void ) const { if ( next == head ) { return NULL; } return next; } /* ================ idLinkList::PrevNode Returns the previous node in the list, or NULL if at the beginning. ================ */ template< class type > idLinkList *idLinkList::PrevNode( void ) const { if ( prev == head ) { return NULL; } return prev; } /* ================ idLinkList::Owner Gets the object that is associated with this node. ================ */ template< class type > type *idLinkList::Owner( void ) const { return owner; } /* ================ idLinkList::SetOwner Sets the object that this node is associated with. ================ */ template< class type > void idLinkList::SetOwner( type *object ) { owner = object; } /* ============ operator==( idLinkList< type >, idLinkList< type > ) ============ */ template< class type > bool operator==( const idLinkList< type >& lhs, const idLinkList< type >& rhs ) { return ( lhs.Owner() == rhs.Owner() && lhs.ListHead() == rhs.ListHead() && lhs.NextNode() == rhs.NextNode() && lhs.PrevNode() == rhs.PrevNode() ); } #endif /* !__LINKLIST_H__ */