/// \file /// \brief \b [Internal] Straightforward linked list data structure. /// /// This file is part of RakNet Copyright 2003 Kevin Jenkins. /// /// Usage of RakNet is subject to the appropriate license agreement. /// Creative Commons Licensees are subject to the /// license found at /// http://creativecommons.org/licenses/by-nc/2.5/ /// Single application licensees are subject to the license found at /// http://www.jenkinssoftware.com/SingleApplicationLicense.html /// Custom license users are subject to the terms therein. /// GPL license users are subject to the GNU General Public /// License as published by the Free /// Software Foundation; either version 2 of the License, or (at your /// option) any later version. #ifndef __LINKED_LIST_H #define __LINKED_LIST_H #include "Export.h" #include "RakMemoryOverride.h" #ifdef _MSC_VER #pragma warning( push ) #endif /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. namespace DataStructures { // Prototype to prevent error in CircularLinkedList class when a reference is made to a LinkedList class template class RAK_DLL_EXPORT LinkedList; /** * \brief (Circular) Linked List ADT (Doubly Linked Pointer to Node Style) - * * By Kevin Jenkins (http://www.rakkar.org) * Initilize with the following command * LinkedList * OR * CircularLinkedList * * Has the following member functions * - size: returns number of elements in the linked list * - insert(item): inserts @em item at the current position in * the LinkedList. * - add(item): inserts @em item after the current position in * the LinkedList. Does not increment the position * - replace(item): replaces the element at the current position @em item. * - peek: returns the element at the current position * - pop: returns the element at the current position and deletes it * - del: deletes the current element. Does nothing for an empty list. * - clear: empties the LinkedList and returns storage * - bool IsInitem): Does a linear search for @em item. Does not set * the position to it, only returns true on item found, false otherwise * - bool find(item): Does a linear search for @em item and sets the current * position to point to it if and only if the item is found. Returns true * on item found, false otherwise * - sort: Sorts the elements of the list with a mergesort and sets the * current pointer to the first element * - concatenate(list L): This appends L to the current list * - ++(prefix): moves the pointer one element up in the list and returns the * appropriate copy of the element in the list * - --(prefix): moves the pointer one element back in the list and returns * the appropriate copy of the element in the list * - beginning - moves the pointer to the start of the list. For circular * linked lists this is first 'position' created. You should call this * after the sort function to read the first value. * - end - moves the pointer to the end of the list. For circular linked * lists this is one less than the first 'position' created * The assignment and copy constructor operators are defined * * \note * 1. LinkedList and CircularLinkedList are exactly the same except LinkedList * won't let you wrap around the root and lets you jump to two positions * relative to the root/ * 2. Postfix ++ and -- can be used but simply call the prefix versions. * * * EXAMPLE: * @code * LinkedList A; // Creates a Linked List of integers called A * CircularLinkedList B; // Creates a Circular Linked List of * // integers called B * * A.Insert(20); // Adds 20 to A. A: 20 - current is 20 * A.Insert(5); // Adds 5 to A. A: 5 20 - current is 5 * A.Insert(1); // Adds 1 to A. A: 1 5 20 - current is 1 * * A.IsIn1); // returns true * A.IsIn200); // returns false * A.Find(5); // returns true and sets current to 5 * A.Peek(); // returns 5 * A.Find(1); // returns true and sets current to 1 * * (++A).Peek(); // Returns 5 * A.Peek(); // Returns 5 * * A.Replace(10); // Replaces 5 with 10. * A.Peek(); // Returns 10 * * A.Beginning(); // Current points to the beginning of the list at 1 * * (++A).Peek(); // Returns 5 * A.Peek(); // Returns 10 * * A.Del(); // Deletes 10. Current points to the next element, which is 20 * A.Peek(); // Returns 20 * * A.Beginning(); // Current points to the beginning of the list at 1 * * (++A).Peek(); // Returns 5 * A.Peek(); // Returns 20 * * A.Clear(); // Deletes all nodes in A * * A.Insert(5); // A: 5 - current is 5 * A.Insert(6); // A: 6 5 - current is 6 * A.Insert(7); // A: 7 6 5 - current is 7 * * A.Clear(); * B.Clear(); * * B.Add(10); * B.Add(20); * B.Add(30); * B.Add(5); * B.Add(2); * B.Add(25); * // Sorts the numbers in the list and sets the current pointer to the * // first element * B.sort(); * * // Postfix ++ just calls the prefix version and has no functional * // difference. * B.Peek(); // Returns 2 * B++; * B.Peek(); // Returns 5 * B++; * B.Peek(); // Returns 10 * B++; * B.Peek(); // Returns 20 * B++; * B.Peek(); // Returns 25 * B++; * B.Peek(); // Returns 30 * @endcode */ template class CircularLinkedList : public RakNet::RakMemoryOverride { public: struct node { CircularLinkedListType item; node* previous; node* next; }; CircularLinkedList(); ~CircularLinkedList(); CircularLinkedList( const CircularLinkedList& original_copy ); // CircularLinkedList(LinkedList original_copy) {CircularLinkedList(original_copy);} // Converts linked list to circular type bool operator= ( const CircularLinkedList& original_copy ); CircularLinkedList& operator++(); // CircularLinkedList A; ++A; CircularLinkedList& operator++( int ); // Circular_Linked List A; A++; CircularLinkedList& operator--(); // CircularLinkedList A; --A; CircularLinkedList& operator--( int ); // Circular_Linked List A; A--; bool IsIn( const CircularLinkedListType& input ); bool Find( const CircularLinkedListType& input ); void Insert( const CircularLinkedListType& input ); CircularLinkedListType& Add ( const CircularLinkedListType& input ) ; // Adds after the current position void Replace( const CircularLinkedListType& input ); void Del( void ); unsigned int Size( void ); CircularLinkedListType& Peek( void ); CircularLinkedListType Pop( void ); void Clear( void ); void Sort( void ); void Beginning( void ); void End( void ); void Concatenate( const CircularLinkedList& L ); protected: unsigned int list_size; node *root; node *position; node* FindPointer( const CircularLinkedListType& input ); private: CircularLinkedList Merge( CircularLinkedList L1, CircularLinkedList L2 ); CircularLinkedList Mergesort( const CircularLinkedList& L ); }; template class LinkedList : public CircularLinkedList { public: LinkedList() {} LinkedList( const LinkedList& original_copy ); ~LinkedList(); bool operator= ( const LinkedList& original_copy ); LinkedList& operator++(); // LinkedList A; ++A; LinkedList& operator++( int ); // Linked List A; A++; LinkedList& operator--(); // LinkedList A; --A; LinkedList& operator--( int ); // Linked List A; A--; private: LinkedList Merge( LinkedList L1, LinkedList L2 ); LinkedList Mergesort( const LinkedList& L ); }; template inline void CircularLinkedList::Beginning( void ) { if ( this->root ) this->position = this->root; } template inline void CircularLinkedList::End( void ) { if ( this->root ) this->position = this->root->previous; } template bool LinkedList::operator= ( const LinkedList& original_copy ) { typename LinkedList::node * original_copy_pointer, *last, *save_position; if ( ( &original_copy ) != this ) { this->Clear(); if ( original_copy.list_size == 0 ) { this->root = 0; this->position = 0; this->list_size = 0; } else if ( original_copy.list_size == 1 ) { this->root = new typename LinkedList::node; // root->item = new LinkedListType; this->root->next = this->root; this->root->previous = this->root; this->list_size = 1; this->position = this->root; // *(root->item)=*((original_copy.root)->item); this->root->item = original_copy.root->item; } else { // Setup the first part of the root node original_copy_pointer = original_copy.root; this->root = new typename LinkedList::node; // root->item = new LinkedListType; this->position = this->root; // *(root->item)=*((original_copy.root)->item); this->root->item = original_copy.root->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; do { // Save the current element last = this->position; // Point to the next node in the source list original_copy_pointer = original_copy_pointer->next; // Create a new node and point position to it this->position = new typename LinkedList::node; // position->item = new LinkedListType; // Copy the item to the new node // *(position->item)=*(original_copy_pointer->item); this->position->item = original_copy_pointer->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; // Set the previous pointer for the new node ( this->position->previous ) = last; // Set the next pointer for the old node to the new node ( last->next ) = this->position; } while ( ( original_copy_pointer->next ) != ( original_copy.root ) ); // Complete the circle. Set the next pointer of the newest node to the root and the previous pointer of the root to the newest node this->position->next = this->root; this->root->previous = this->position; this->list_size = original_copy.list_size; this->position = save_position; } } return true; } template CircularLinkedList::CircularLinkedList() { this->root = 0; this->position = 0; this->list_size = 0; } template CircularLinkedList::~CircularLinkedList() { this->Clear(); } template LinkedList::~LinkedList() { this->Clear(); } template LinkedList::LinkedList( const LinkedList& original_copy ) { typename LinkedList::node * original_copy_pointer, *last, *save_position; if ( original_copy.list_size == 0 ) { this->root = 0; this->position = 0; this->list_size = 0; return ; } else if ( original_copy.list_size == 1 ) { this->root = new typename LinkedList::node; // root->item = new CircularLinkedListType; this->root->next = this->root; this->root->previous = this->root; this->list_size = 1; this->position = this->root; // *(root->item) = *((original_copy.root)->item); this->root->item = original_copy.root->item; } else { // Setup the first part of the root node original_copy_pointer = original_copy.root; this->root = new typename LinkedList::node; // root->item = new CircularLinkedListType; this->position = this->root; // *(root->item)=*((original_copy.root)->item); this->root->item = original_copy.root->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; do { // Save the current element last = this->position; // Point to the next node in the source list original_copy_pointer = original_copy_pointer->next; // Create a new node and point position to it this->position = new typename LinkedList::node; // position->item = new CircularLinkedListType; // Copy the item to the new node // *(position->item)=*(original_copy_pointer->item); this->position->item = original_copy_pointer->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; // Set the previous pointer for the new node ( this->position->previous ) = last; // Set the next pointer for the old node to the new node ( last->next ) = this->position; } while ( ( original_copy_pointer->next ) != ( original_copy.root ) ); // Complete the circle. Set the next pointer of the newest node to the root and the previous pointer of the root to the newest node this->position->next = this->root; this->root->previous = this->position; this->list_size = original_copy.list_size; this->position = save_position; } } #ifdef _MSC_VER #pragma warning( disable : 4701 ) // warning C4701: local variable may be used without having been initialized #endif template CircularLinkedList::CircularLinkedList( const CircularLinkedList& original_copy ) { node * original_copy_pointer; node *last; node *save_position; if ( original_copy.list_size == 0 ) { this->root = 0; this->position = 0; this->list_size = 0; return ; } else if ( original_copy.list_size == 1 ) { this->root = new typename CircularLinkedList::node; // root->item = new CircularLinkedListType; this->root->next = this->root; this->root->previous = this->root; this->list_size = 1; this->position = this->root; // *(root->item) = *((original_copy.root)->item); this->root->item = original_copy.root->item; } else { // Setup the first part of the root node original_copy_pointer = original_copy.root; this->root = new typename CircularLinkedList::node; // root->item = new CircularLinkedListType; this->position = this->root; // *(root->item)=*((original_copy.root)->item); this->root->item = original_copy.root->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; do { // Save the current element last = this->position; // Point to the next node in the source list original_copy_pointer = original_copy_pointer->next; // Create a new node and point position to it this->position = new typename CircularLinkedList::node; // position->item = new CircularLinkedListType; // Copy the item to the new node // *(position->item)=*(original_copy_pointer->item); this->position->item = original_copy_pointer->item; if ( original_copy_pointer == original_copy.position ) save_position = position; // Set the previous pointer for the new node ( this->position->previous ) = last; // Set the next pointer for the old node to the new node ( last->next ) = this->position; } while ( ( original_copy_pointer->next ) != ( original_copy.root ) ); // Complete the circle. Set the next pointer of the newest node to the root and the previous pointer of the root to the newest node this->position->next = this->root; this->root->previous = position; this->list_size = original_copy.list_size; this->position = save_position; } } #ifdef _MSC_VER #pragma warning( disable : 4701 ) // warning C4701: local variable may be used without having been initialized #endif template bool CircularLinkedList::operator= ( const CircularLinkedList& original_copy ) { node * original_copy_pointer; node *last; node *save_position; if ( ( &original_copy ) != this ) { this->Clear(); if ( original_copy.list_size == 0 ) { this->root = 0; this->position = 0; this->list_size = 0; } else if ( original_copy.list_size == 1 ) { this->root = new typename CircularLinkedList::node; // root->item = new CircularLinkedListType; this->root->next = this->root; this->root->previous = this->root; this->list_size = 1; this->position = this->root; // *(root->item)=*((original_copy.root)->item); this->root->item = original_copy.root->item; } else { // Setup the first part of the root node original_copy_pointer = original_copy.root; this->root = new typename CircularLinkedList::node; // root->item = new CircularLinkedListType; this->position = this->root; // *(root->item)=*((original_copy.root)->item); this->root->item = original_copy.root->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; do { // Save the current element last = this->position; // Point to the next node in the source list original_copy_pointer = original_copy_pointer->next; // Create a new node and point position to it this->position = new typename CircularLinkedList::node; // position->item = new CircularLinkedListType; // Copy the item to the new node // *(position->item)=*(original_copy_pointer->item); this->position->item = original_copy_pointer->item; if ( original_copy_pointer == original_copy.position ) save_position = this->position; // Set the previous pointer for the new node ( this->position->previous ) = last; // Set the next pointer for the old node to the new node ( last->next ) = this->position; } while ( ( original_copy_pointer->next ) != ( original_copy.root ) ); // Complete the circle. Set the next pointer of the newest node to the root and the previous pointer of the root to the newest node this->position->next = this->root; this->root->previous = this->position; this->list_size = original_copy.list_size; this->position = save_position; } } return true; } template void CircularLinkedList::Insert( const CircularLinkedListType& input ) { node * new_node; if ( list_size == 0 ) { this->root = new typename CircularLinkedList::node; // root->item = new CircularLinkedListType; //*(root->item)=input; this->root->item = input; this->root->next = this->root; this->root->previous = this->root; this->list_size = 1; this->position = this->root; } else if ( list_size == 1 ) { this->position = new typename CircularLinkedList::node; // position->item = new CircularLinkedListType; this->root->next = this->position; this->root->previous = this->position; this->position->previous = this->root; this->position->next = this->root; // *(position->item)=input; this->position->item = input; this->root = this->position; // Since we're inserting into a 1 element list the old root is now the second item this->list_size = 2; } else { /* B | A --- C position->previous=A new_node=B position=C Note that the order of the following statements is important */ new_node = new typename CircularLinkedList::node; // new_node->item = new CircularLinkedListType; // *(new_node->item)=input; new_node->item = input; // Point next of A to B ( this->position->previous ) ->next = new_node; // Point last of B to A new_node->previous = this->position->previous; // Point last of C to B this->position->previous = new_node; // Point next of B to C new_node->next = this->position; // Since the root pointer is bound to a node rather than an index this moves it back if you insert an element at the root if ( this->position == this->root ) { this->root = new_node; this->position = this->root; } // Increase the recorded size of the list by one this->list_size++; } } template CircularLinkedListType& CircularLinkedList::Add ( const CircularLinkedListType& input ) { node * new_node; if ( this->list_size == 0 ) { this->root = new typename CircularLinkedList::node; // root->item = new CircularLinkedListType; // *(root->item)=input; this->root->item = input; this->root->next = this->root; this->root->previous = this->root; this->list_size = 1; this->position = this->root; // return *(position->item); return this->position->item; } else if ( list_size == 1 ) { this->position = new typename CircularLinkedList::node; // position->item = new CircularLinkedListType; this->root->next = this->position; this->root->previous = this->position; this->position->previous = this->root; this->position->next = this->root; // *(position->item)=input; this->position->item = input; this->list_size = 2; this->position = this->root; // Don't move the position from the root // return *(position->item); return this->position->item; } else { /* B | A --- C new_node=B position=A position->next=C Note that the order of the following statements is important */ new_node = new typename CircularLinkedList::node; // new_node->item = new CircularLinkedListType; // *(new_node->item)=input; new_node->item = input; // Point last of B to A new_node->previous = this->position; // Point next of B to C new_node->next = ( this->position->next ); // Point last of C to B ( this->position->next ) ->previous = new_node; // Point next of A to B ( this->position->next ) = new_node; // Increase the recorded size of the list by one this->list_size++; // return *(new_node->item); return new_node->item; } } template inline void CircularLinkedList::Replace( const CircularLinkedListType& input ) { if ( this->list_size > 0 ) // *(position->item)=input; this->position->item = input; } template void CircularLinkedList::Del() { node * new_position; if ( this->list_size == 0 ) return ; else if ( this->list_size == 1 ) { // delete root->item; delete this->root; this->root = this->position = 0; this->list_size = 0; } else { ( this->position->previous ) ->next = this->position->next; ( this->position->next ) ->previous = this->position->previous; new_position = this->position->next; if ( this->position == this->root ) this->root = new_position; // delete position->item; delete this->position; this->position = new_position; this->list_size--; } } template bool CircularLinkedList::IsIn(const CircularLinkedListType& input ) { node * return_value, *old_position; old_position = this->position; return_value = FindPointer( input ); this->position = old_position; if ( return_value != 0 ) return true; else return false; // Can't find the item don't do anything } template bool CircularLinkedList::Find( const CircularLinkedListType& input ) { node * return_value; return_value = FindPointer( input ); if ( return_value != 0 ) { this->position = return_value; return true; } else return false; // Can't find the item don't do anything } template typename CircularLinkedList::node* CircularLinkedList::FindPointer( const CircularLinkedListType& input ) { node * current; if ( this->list_size == 0 ) return 0; current = this->root; // Search for the item starting from the root node and incrementing the pointer after every check // If you wind up pointing at the root again you looped around the list so didn't find the item, in which case return 0 do { // if (*(current->item) == input) return current; if ( current->item == input ) return current; current = current->next; } while ( current != this->root ); return 0; } template inline unsigned int CircularLinkedList::Size( void ) { return this->list_size; } template inline CircularLinkedListType& CircularLinkedList::Peek( void ) { // return *(position->item); return this->position->item; } template CircularLinkedListType CircularLinkedList::Pop( void ) { CircularLinkedListType element; element = Peek(); Del(); return CircularLinkedListType( element ); // return temporary } // Prefix template CircularLinkedList& CircularLinkedList::operator++() { if ( this->list_size != 0 ) position = position->next; return *this; } /* // Postfix template CircularLinkedList& CircularLinkedList::operator++(int) { CircularLinkedList before; before=*this; operator++(); return before; } */ template CircularLinkedList& CircularLinkedList::operator++( int ) { return this->operator++(); } // Prefix template CircularLinkedList& CircularLinkedList::operator--() { if ( this->list_size != 0 ) this->position = this->position->previous; return *this; } /* // Postfix template CircularLinkedList& CircularLinkedList::operator--(int) { CircularLinkedList before; before=*this; operator--(); return before; } */ template CircularLinkedList& CircularLinkedList::operator--( int ) { return this->operator--(); } template void CircularLinkedList::Clear( void ) { if ( this->list_size == 0 ) return ; else if ( this->list_size == 1 ) // {delete root->item; delete root;} { delete this->root; } else { node* current; node* temp; current = this->root; do { temp = current; current = current->next; // delete temp->item; delete temp; } while ( current != this->root ); } this->list_size = 0; this->root = 0; this->position = 0; } template inline void CircularLinkedList::Concatenate( const CircularLinkedList& L ) { unsigned int counter; node* ptr; if ( L.list_size == 0 ) return ; if ( this->list_size == 0 ) * this = L; ptr = L.root; this->position = this->root->previous; // Cycle through each element in L and add it to the current list for ( counter = 0; counter < L.list_size; counter++ ) { // Add item after the current item pointed to // add(*(ptr->item)); Add ( ptr->item ); // Update pointers. Moving ptr keeps the current pointer at the end of the list since the add function does not move the pointer ptr = ptr->next; this->position = this->position->next; } } template inline void CircularLinkedList::Sort( void ) { if ( this->list_size <= 1 ) return ; // Call equal operator to assign result of mergesort to current object *this = Mergesort( *this ); this->position = this->root; } template CircularLinkedList CircularLinkedList::Mergesort( const CircularLinkedList& L ) { unsigned int counter; node* location; CircularLinkedList L1; CircularLinkedList L2; location = L.root; // Split the list into two equal size sublists, L1 and L2 for ( counter = 0; counter < L.list_size / 2; counter++ ) { // L1.add (*(location->item)); L1.Add ( location->item ); location = location->next; } for ( ;counter < L.list_size; counter++ ) { // L2.Add(*(location->item)); L2.Add ( location->item ); location = location->next; } // Recursively sort the sublists if ( L1.list_size > 1 ) L1 = Mergesort( L1 ); if ( L2.list_size > 1 ) L2 = Mergesort( L2 ); // Merge the two sublists return Merge( L1, L2 ); } template CircularLinkedList CircularLinkedList::Merge( CircularLinkedList L1, CircularLinkedList L2 ) { CircularLinkedList X; CircularLinkedListType element; L1.position = L1.root; L2.position = L2.root; // While neither list is empty while ( ( L1.list_size != 0 ) && ( L2.list_size != 0 ) ) { // Compare the first items of L1 and L2 // Remove the smaller of the two items from the list if ( ( ( L1.root ) ->item ) < ( ( L2.root ) ->item ) ) // if ((*((L1.root)->item)) < (*((L2.root)->item))) { // element = *((L1.root)->item); element = ( L1.root ) ->item; L1.Del(); } else { // element = *((L2.root)->item); element = ( L2.root ) ->item; L2.Del(); } // Add this item to the end of X X.Add( element ); X++; } // Add the remaining list to X if ( L1.list_size != 0 ) X.Concatenate( L1 ); else X.Concatenate( L2 ); return X; } template LinkedList LinkedList::Mergesort( const LinkedList& L ) { unsigned int counter; typename LinkedList::node* location; LinkedList L1; LinkedList L2; location = L.root; // Split the list into two equal size sublists, L1 and L2 for ( counter = 0; counter < L.LinkedList_size / 2; counter++ ) { // L1.add (*(location->item)); L1.Add ( location->item ); location = location->next; } for ( ;counter < L.LinkedList_size; counter++ ) { // L2.Add(*(location->item)); L2.Add ( location->item ); location = location->next; } // Recursively sort the sublists if ( L1.list_size > 1 ) L1 = Mergesort( L1 ); if ( L2.list_size > 1 ) L2 = Mergesort( L2 ); // Merge the two sublists return Merge( L1, L2 ); } template LinkedList LinkedList::Merge( LinkedList L1, LinkedList L2 ) { LinkedList X; LinkedListType element; L1.position = L1.root; L2.position = L2.root; // While neither list is empty while ( ( L1.LinkedList_size != 0 ) && ( L2.LinkedList_size != 0 ) ) { // Compare the first items of L1 and L2 // Remove the smaller of the two items from the list if ( ( ( L1.root ) ->item ) < ( ( L2.root ) ->item ) ) // if ((*((L1.root)->item)) < (*((L2.root)->item))) { element = ( L1.root ) ->item; // element = *((L1.root)->item); L1.Del(); } else { element = ( L2.root ) ->item; // element = *((L2.root)->item); L2.Del(); } // Add this item to the end of X X.Add( element ); } // Add the remaining list to X if ( L1.LinkedList_size != 0 ) X.concatenate( L1 ); else X.concatenate( L2 ); return X; } // Prefix template LinkedList& LinkedList::operator++() { if ( ( this->list_size != 0 ) && ( this->position->next != this->root ) ) this->position = this->position->next; return *this; } /* // Postfix template LinkedList& LinkedList::operator++(int) { LinkedList before; before=*this; operator++(); return before; } */ // Postfix template LinkedList& LinkedList::operator++( int ) { return this->operator++(); } // Prefix template LinkedList& LinkedList::operator--() { if ( ( this->list_size != 0 ) && ( this->position != this->root ) ) this->position = this->position->previous; return *this; } /* // Postfix template LinkedList& LinkedList::operator--(int) { LinkedList before; before=*this; operator--(); return before; } */ // Postfix template LinkedList& LinkedList::operator--( int ) { return this->operator--(); } } // End namespace #ifdef _MSC_VER #pragma warning( pop ) #endif #endif