// SList.h #ifndef SListh #define SListh #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 /*>>>>>>>>>>>>>>>>>>>>>> Singly Linked List <<<<<<<<<<<<<<<<<<<<<<<< This implements a fast and neat singly linked list which may be used for insertion sort or data or for Queues etc. The implementation uses a circular list with a dummy Node (with NULL Data pointer) acting as a Terminator at head and tail. The classes are template-based to allow any type of Data. Appending to the list is as fast as Adding to the start of the list. A Count of Nodes is maintained since the overhead during Insertion or deletion is negligible compared to the memory allocation time. The Iterator class is normally used to access the data in the List class, though access is available to the First Node which is useful for rotating lists or queues. Nodes may be quickly moved from one list to another with the Iterator's MoveTo and InsertInto methods. One list may hold pointers to data held in another list if it calls DropAll before it is deleted (preventing it from deleting the Data it points to when its destructor is called). The test classes give usage examples. */ template class CSListIterator; template class CSListConstIterator; template class CSList { // Singly Linked List (Circular and ,optionally, sorted). friend class CSListIterator; friend class CSListConstIterator; protected: struct Node { T* Data; Node* Next; Node() : Data(0) {Next=this;} Node(T* Data) : Data(0) {Next=this; Insert(Data, this);} Node(T* Data, Node* Next) : Data(Data), Next(Next) {} ~Node() {try{delete Data;}catch(...){ASSERT(0);}} bool IsEmpty() const {return Next==this;} }; Node* First; // Points to the Dummy Head/Tail node with Data=0 Node* Last; // Points to the node which points to First. unsigned Count; public: CSList() : First(new Node), Last(First), Count(0) {} CSList(T* Data) : First(new Node), Last(First), Count(0) {Insert(Data, First);} virtual ~CSList() {try{Empty();}catch(...){ASSERT(0);} try{delete First;}catch(...){ASSERT(0);} First=Last=0;} bool Add (T* Data) {return Insert(Data, First);} // Add a new Data at the beginning of the List bool Append (T* Data) {return Insert(Data, Last );} // Add a new Data at the end of the List bool Insert (T* Data) {return Insert(Data, GetInsertPos(*Data));} // Add a new Data in its sorted position bool Insert1(T* Data, bool AutoDelete=true) {return InsertUnique(Data, AutoDelete)->Next->Data==Data;} // Insert only one: Don't insert if it already exists in the list. AutoDeletes the Data!!! void Add(CSList& List) { // Move a List to the beginning of this List if(List.IsEmpty()) return; List.Last->Next=First; First->Next=List.First->Next; Count+=List.Count; List.Last=List.First->Next=List.First; // Empty the List List.Count=0; } void Append(CSList& List) { // Move a List to the end of this List if(List.IsEmpty()) return; Last->Next=List.First->Next; Last=List.Last; Last->Next=First; Count+=List.Count; List.Last=List.First->Next=List.First; // Empty the List List.Count=0; } bool Find (const T* Data) const {return Find(*Data);} // Find a matching Data bool Find (const T& Data) const {return GetPos(Data)!=0;} // Find a matching Data bool Delete(const T& Data) {return Delete(GetPos(Data));} // Delete a specific Node and its Data (iterators pointing at this Data (which are looking at the next Data) will become invalid and won't know it)! bool Drop (const T& Data) {return Drop (GetPos(Data));} // Delete a specific Node but NOT its Data (iterators pointing at this Data (which are looking at the next Data) will become invalid and won't know it)! unsigned GetCount() const {return Count;} bool IsEmpty() const {return First->IsEmpty();} void Empty() {DropAll(false);} // if Empty is called, iterators to this list that aren't pointing at the First Data become invalid and there are no checks for this! void DropAll(bool Drop=true) { // if DropAll is called, iterators to this list that aren't pointing at the First Data become invalid and there are no checks for this! for(Node* it=First->Next; it!=First; it=First->Next) { First->Next=it->Next; if(Drop) it->Data=0; delete it; } Count=0; Last=First; } void SetFirst(T* Data) {First->Next->Data=Data;} void SetLast (T* Data) {Last->Data=Data;} T* GetFirst () const {return First->Next->Data;} T* GetLast () const {return Last->Data;} T* operator->() const {return GetFirst();} T& operator* () const {return *GetFirst();} T* operator[](unsigned i) const {return GetAt(i);} // Provides array access T* GetAt(unsigned i) const { // Provides array access if(i>=Count) return 0; for(Node* it=First; it!=Last; it=it->Next) if(i--==0) return it->Next->Data; return 0; } bool DeleteFirst() {return Delete(First );} // Delete the First Node and its Data (iterators pointing at this Data (which are looking at the next Data) will become invalid and won't know it)! bool DeleteLast () {return Delete(GetPrev(Last));} // Delete the Last Node and its Data (iterators pointing at this Data (which are looking at the next Data) will become invalid and won't know it)! bool DropFirst() {return Drop (First );} // Delete the First Node but NOT its Data (iterators pointing at this Data (which are looking at the next Data) will become invalid and won't know it)! bool DropLast () {return Drop (GetPrev(Last));} // Delete the Last Node but NOT its Data (iterators pointing at this Data (which are looking at the next Data) will become invalid and won't know it)! bool Rotate() { // Make the First Node become the Last Node: if(Count<2) return false; // No change! First->Data=First->Next->Data; // Moves the Data Pointers rather than all the links... First->Next->Data=0; First=First->Next; Last=Last->Next; return true; } bool Reverse() { if(Count<2) return false; // No Change! Node* it=Last=First->Next; // Current node First->Next=First; // Means The above iterator is its own list now. This list is emptied and so nodes must me moved to it. while(it!=First) { Node* n=First->Next; // Next node First->Next=it; it=it->Next; First->Next->Next=n; } return true; } CSList& operator=(CSList& List) { // MOVES data to this list Empty(); CSList::Node* t=First; // Use this empty First for List First=List.First; Last =List.Last; Count=List.Count; List.Last=List.First->Next=List.First=t; List.Count=0; return *this; } protected: bool SetFirst(Node*& it) { // Rotates the list so that it is the First Node in the List: if((Count<2)||(it==First)||(it==Last)) return false; Last->Next=First->Next; First->Next=it->Next; it->Next=First; Last=it; it=First; return true; } bool Insert(T* Data, Node* Prev) { if(!Prev) return false; if((Prev->Next=new Node(Data, Prev->Next))==0) return false; if(Prev==Last) Last=Prev->Next; // Maintain Last & Count: ++Count; return true; } Node* GetPrev(const Node* Me) const { for(Node* it=First; it->Next!=First; it=it->Next) if(it->Next==Me) return it; return 0; } /* Insert only one: Don't insert if it already exists in the list. If it's already in the list it AutoDeletes the Data!!! Returns a pointer to the node previous to the found or inserted node. Returns 0 if out of memory. */ Node* InsertUnique(T* Data, bool AutoDelete=true) { Node* Pos=GetInsertPos(*Data); if(IsEmpty()) return Add(Data) ? Pos : 0; // if it's to be the first entry or the list is empty, just Add it. if((Pos==Last) || Pos->Next->Data->Compare(*Data)) return Insert(Data, Pos) ? Pos : 0; // Add a new Data in its sorted position if(AutoDelete) delete Data; return Pos; } Node* GetInsertPos(const T& Data) const { // Goes through the list until it finds a larger Data, returns previous Node or 0 on failure. Node* it=First; while((it!=Last) && (it->Next->Data->Compare(Data)<0)) it=it->Next; return it; } Node* GetPos(const T& Data) const { // Looks for a specific Data. Returns previous Node on success, 0 on failure. Node* it=First; while((it!=Last) && it->Next->Data->Compare(Data)) it=it->Next; return it!=Last ? it : 0; } bool Drop(Node* Prev) { Prev->Next->Data=0; return Delete(Prev); } bool Delete(Node* Prev) { if(Prev==0) return false; Node* it=Prev->Next; if(it==First) return false; if(it==Last) Last=Prev; Prev->Next=it->Next; // It's a circular list so Prev is guaranteed to have a Next->Next delete it; --Count; return true; } }; #ifdef Assert static struct CSListTester : Tester, CSList { CSListTester() { Assert( IsEmpty()); Assert( Add (new CString("one" ))); // one Assert(!IsEmpty()); Assert( GetCount()==1); Assert(*GetFirst()=="one"); Assert( Add (new CString("two" ))); // two one Assert( GetCount()==2); Assert( Insert (new CString("four" ))); // four two one Assert( GetCount()==3); Assert(!Insert1(new CString("four" ))); // four two one Assert( GetCount()==3); Assert( Insert1(new CString("three"))); // four three two one Assert( GetCount()==4); Assert( Find ("one" )); Assert( Find ("two" )); Assert( Find ("three")); Assert( Find ("four" )); Assert(!Find ("five" )); Assert(!Delete ("five" )); Assert( GetCount()==4); Assert(*operator[](0)=="four" ); Assert(*operator[](1)=="three" ); Assert(*operator[](2)=="two"); Assert(*operator[](3)=="one" ); Assert( operator[](4)==0); Reverse(); Assert( GetCount()==4); Assert(*GetFirst()=="one"); // Cyclic List test: Rotate(); Assert(*GetFirst()=="two"); Rotate(); Assert(*GetFirst()=="three"); Rotate(); Assert(*GetFirst()=="four"); Rotate(); Assert(*GetFirst()=="one"); Reverse(); Assert( GetCount()==4); Assert( Find ("two" )); Assert( Delete ("two" )); Assert( GetCount()==3); Assert(!Find ("two" )); CString* s=new CString("five"); Assert( Append (s)); // four three one five Assert( GetCount()==4); Assert( Find ("five")); Assert( Drop ("five")); // four three one Assert( GetCount()==3); Assert(!Find ("five")); Assert(*s=="five"); delete s; Reverse(); // one three four Assert(*First->Next->Data=="one"); Assert(*First->Next->Next->Data=="three"); Assert(*First->Next->Next->Next->Data=="four"); Empty(); Assert( IsEmpty()); } } SListTester; #endif // def Assert /*>>>>>>>>>>>>>>>>>>>>>> List Iterator <<<<<<<<<<<<<<<<<<<<<<<< CRTP: template struct CSListIteratorBase { const T& Me() const {return static_cast(*this);} T& Me() {return static_cast< T&>(*this);} void method1() {this->Me().method1();} }; */ template class CSListConstIterator { const CSList* List; typename const CSList::Node* it; // 'typename' here is just a helper for the compiler. public: CSListConstIterator(const CSList* List) : List( List), it(List->First) {} CSListConstIterator(const CSList& List) : List(&List), it(List. First) {} CSListConstIterator(const CSListConstIterator& Iterator, bool Home=false) : List(Iterator.List), it(Home ? Iterator.List->First : Iterator.it) {} void Set(const CSList& _List) {List=&_List; it=_List.First;} unsigned GetCount() const {return List->Count;} T* GetPrevData() const {return it->Data;} T* GetData() const {return it->Next->Data;} T* GetNextData() const {return it->Next->Next->Data;} bool IsFirst() const {return it==List->First;} bool IsLast () const {return it==List->Last ;} bool AtEnd () const {return GetData()==0;} bool IsValid() const {return !AtEnd();} bool IsEmpty() const {return List->IsEmpty();} void Home () {it=List->First;} void End () {it=List->Last ;} bool Next () {return AtEnd() ? false : (it=it->Next)!=List->Last;} T* operator[](unsigned i) { // Provides array access if(i>=List->Count) return 0; for(it=List->First; it!=List->Last; it=it->Next) if(i--==0) return it->Next->Data; return 0; // AtEnd() and IsLast() are true if we exit here. } bool operator==(const CSListIterator& _it) const {return it==_it.it;} bool operator!=(const CSListIterator& _it) const {return it!=_it.it;} // operators to allow the iterator to be accessed as if it were the data: // operator T*() const {return GetData();} // Would mean you don't need to write .GetData() everywhere, but you'd also need to override every other operator to ASSERT + - -- etc. // Leads to ambiguity operator T&() const {return *GetData();} // No need to ASSERT, it'll break if it==0 T& operator *() const {return *GetData();} // No need to ASSERT, it'll break if it==0 T* operator ->() const {return GetData();} T** operator &() const {return &(it->Next->Data);} operator bool() const {return GetData()!=0;} bool operator !() const {return GetData()==0;} // Iteration operators: const CSListConstIterator& operator ++() {Next(); return *this;} const CSListConstIterator operator ++(int) {CSListConstIterator tit(*this); Next(); return tit;} // Comparison operators to use the iterator as if it were the data type: bool operator==(const T& data) const {return GetData()->Compare(*data)==0;} bool operator!=(const T& data) const {return GetData()->Compare(*data)!=0;} bool operator< (const T& data) const {return GetData()->Compare(*data)< 0;} bool operator> (const T& data) const {return GetData()->Compare(*data)> 0;} bool operator<=(const T& data) const {return GetData()->Compare(*data)<=0;} bool operator>=(const T& data) const {return GetData()->Compare(*data)>=0;} bool Find (const T& data) { const CSList::Node* ptr=List->GetPos(data); if(ptr) it=ptr; // Move to it if we found it. return ptr!=0; } }; template class CSListIteratorAndList; template class CSListIterator { friend class CSListIteratorAndList; CSList* List; typename CSList::Node* it; public: CSListIterator(CSList* List) : List( List), it(List->First) {} CSListIterator(CSList& List) : List(&List), it(List. First) {} CSListIterator(const CSListIterator& Iterator, bool Home=false) : List(Iterator.List), it(Home ? Iterator.List->First : Iterator.it) {} void Set(CSList& _List) {List=&_List; it=_List.First;} bool SetFirst() {return List->SetFirst(it);} // Rotates the list so that it is the First Node in the List: bool Add (T* Data) {return List->Insert(Data,it);} bool Append (T* Data) {CSList::Node* Pos=List->Last; bool OK=List->Insert(Data,Pos); if(OK) it=Pos; return OK;} bool Insert (T* Data) {CSList::Node* Pos=List->GetInsertPos(*Data); bool OK=List->Insert(Data,Pos); if(OK) it=Pos; return OK;} bool Insert1(T* Data, bool AutoDelete=true) {return ((it=List->InsertUnique(Data, AutoDelete))!=0) ? true : (Home(), false);} // false if out of memory. unsigned GetCount() const {return List->Count;} T* GetPrevData() const {return it->Data;} T* GetData() const {return it->Next->Data;} T* GetNextData() const {return it->Next->Next->Data;} bool IsFirst() const {return it==List->First;} bool IsLast () const {return it==List->Last ;} bool AtEnd () const {return GetData()==0;} bool IsValid() const {return !AtEnd();} bool IsEmpty() const {return List->IsEmpty();} void Empty () {List->Empty(); it=List->First;} // if Empty is called, iterators to this list that aren't pointing at the First Data become invalid and there are no checks for this! void Home () {it=List->First;} void End () {it=List->Last ;} bool Next () {return AtEnd() ? false : (it=it->Next)!=List->Last;} bool Delete () {return List->Delete (it);} bool Drop () {return List->Drop (it);} void DropAll() { List->DropAll(it);} T* Unlink() { // unlinks an entry from the list and returns a pointer to the data (which must be deleted when you've finished with it, since it was created with "new"). T* Data=GetData(); it->Next->Data=0; if(Data) Delete(); // Don't delete the sentinel. return Data; } void MoveTo(CSListIterator& _it) { // Move a node to another iterator. if(List->Last==it->Next) List->Last=it; // Maintain Last CSList::Node* t=it->Next; it->Next=t->Next; t->Next=_it.it->Next; _it.it->Next=t; if(List==_it.List) return; if(_it.List->Last==_it.it) _it.List->Last=t; // Maintain Last -- List->Count; // If we're moving a node from one list to a different one then we must update the List Node Counts ++_it.List->Count; } void InsertInto(CSListIterator& _it) {InsertInto(*(_it.List));} // Insert a node in sorted order to another iterator. void InsertInto(CSList& L) { // Insert a node in sorted order TO another List. ASSERT(GetData()); // Trying to move the sentinel if(List->Last==it->Next) List->Last=it; // Maintain Last CSList::Node* src=it->Next; it->Next=src->Next; // Unlink CSList::Node* dst=L.GetInsertPos(*(src->Data)); src->Next=dst->Next; dst->Next=src; // Link if(List==&L) return; if(L.Last==dst) L.Last=src; // Maintain Last --List->Count; // If we're moving a node from one list to a different one then we must update the List Node Counts ++L .Count; } T* operator[](unsigned i) { // Provides array access if(i>=List->Count) return 0; for(it=List->First; it!=List->Last; it=it->Next) if(i--==0) return it->Next->Data; return 0; // AtEnd() and IsLast() are true if we exit here. } bool operator==(const CSListIterator& _it) const {return it==_it.it;} bool operator!=(const CSListIterator& _it) const {return it!=_it.it;} // operators to allow the iterator to be accessed as if it were the data: // operator T*() const {return GetData();} // Would mean you don't need to write .GetData() everywhere, but you'd also need to override every other operator to ASSERT + - -- etc. // Leads to ambiguity operator T&() const {return *GetData();} // No need to ASSERT, it's going to do that anyway if it==0 T& operator *() const {return *GetData();} // No need to ASSERT, it's going to do that anyway if it==0 T* operator ->() const {return GetData();} T** operator &() const {return &(it->Next->Data);} operator bool() const {return GetData()!=0;} bool operator !() const {return GetData()==0;} // Iteration operators: const CSListIterator& operator ++() {Next(); return *this;} const CSListIterator operator ++(int) {CSListIterator tit(*this); Next(); return tit;} // Comparison operators to use the iterator as if it were the data type: bool operator==(const T& data) const {return GetData()->Compare(*data)==0;} bool operator!=(const T& data) const {return GetData()->Compare(*data)!=0;} bool operator< (const T& data) const {return GetData()->Compare(*data)< 0;} bool operator> (const T& data) const {return GetData()->Compare(*data)> 0;} bool operator<=(const T& data) const {return GetData()->Compare(*data)<=0;} bool operator>=(const T& data) const {return GetData()->Compare(*data)>=0;} bool Find (const T& data) { CSList::Node* ptr=List->GetPos(data); if(ptr) it=ptr; // Move to it if we found it. return ptr!=0; } }; #ifdef Assert static struct CSListIteratorTester : Tester { CSListIteratorTester() { CSList List(new CString("ONE")); // ONE Assert( List.Add (new CString("TWO"))); // TWO ONE Assert( List.Insert (new CString("FOUR"))); // FOUR TWO ONE CSListIterator it(List); // Now you're using an Iterator you mustn't use the List until you've finished with the Iterator! Assert(!it.Find("THREE")); // Test when Find should fail Assert( it.Insert (new CString("THREE"))); // Test Sorted Insertion: FOUR THREE TWO ONE Assert( it.Find("FOUR")); // Test when Find should succeed Assert(*it++=="FOUR"); // Test found returned the correct Data Assert(*it=="THREE"); // Test Insert put the "THREE" in the right place Assert(it.Delete()); // Test Delete: FOUR TWO ONE Assert(*it++=="TWO"); // Make sure it left us on the next Data Assert(!it.AtEnd()); // Test when AtEnd should fail Assert(it); Assert(*it++=="ONE"); Assert( it.AtEnd()); // Test when AtEnd should succeed it.Home(); Assert(!it.AtEnd()); it.End(); Assert( it.AtEnd()); Assert(!it); Assert(!it.Find("THREE")); // Make sure it deleted the Data CString* S=it.Unlink(); // Test when Unlink should fail Assert(S==0); Assert(it.Find("TWO")); S=it.Unlink(); // Test when Unlink should succeed Assert(!it.Find("TWO"));// FOUR ONE Assert(*S=="TWO"); delete S; CSList List2(new CString("TWO")); // TWO Assert( List2.Add (new CString("THREE"))); // THREE TWO Assert( List2.Insert (new CString("FIVE"))); // FIVE THREE TWO CSList List1; // We'll make this list a list of pointers to existing nodes in another List: for(CSListIterator it1(List2); it1; ++it1) List1.Insert1(it1.GetData(),false); // Create the list of pointers Assert(List1.GetCount()==List2.GetCount()); Assert(List1.GetFirst()==List2.GetFirst()); List1.DropAll(); Assert(List1.IsEmpty()); Assert(List2.GetCount()==3); Assert(*List2.GetFirst()=="FIVE"); CSListIterator it2(List2); Assert(it2.Find("THREE")); // Move a middle node it2.MoveTo(it); Assert(!it2.Find("THREE")); Assert(*it=="THREE"); Assert(it2.Find("FIVE")); // Move a last node it2.MoveTo(it); Assert(!it2.Find("FIVE")); Assert(*it=="FIVE"); Assert(it2.Find("TWO")); // Move a first node it2.MoveTo(it); Assert(!it2.Find("TWO")); Assert(*it=="TWO"); ++it; Assert(it.SetFirst()); Assert(*it=="FIVE"); List.Empty(); // obviously if you empty the list all ListIterators that aren't at the First Data become invalid. There are no tests for this as it would slow everything down, and you won't do anything that silly anyway :-) } } SListIteratorTester; #endif // def Assert // CSListIteratorAndList is an Iterator with its own List. Useful as a simple list that you use only one iterator on. template class CSListIteratorAndList : public CSListIterator { protected: CSList List; public: CSListIteratorAndList() : CSListIterator(List) {Home();} // Home called after List is initialised (which is after the Iterator is initialised). virtual ~CSListIteratorAndList() {} bool Rotate () {return List.Rotate ();} // Give access to List-only methods: bool Reverse() {return List.Reverse();} bool Append (T* Data) {return CSListIterator::Append(Data);} void Append(CSListIterator& it) {List.Append(*(it.List));} T* GetFirst() const {return List.GetFirst();} T* GetLast () const {return List.GetLast ();} CSListIteratorAndList& operator=(CSList & L) {Set(List=L ); return *this;} // MOVES data to this list CSListIteratorAndList& operator=(CSListIteratorAndList& L) {Set(List=L.List); return *this;} // MOVES data to this list }; // Node Class often useful: struct CInteger { int i; CInteger(int i) : i(i) {} int Compare(const CInteger& j) const {return i-j.i;} }; #endif // ndef SListh