/* EQEMu: Everquest Server Emulator Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY except by those people which sell it, which are required to give you total support for your newly bought product; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef LINKEDLIST_H #define LINKEDLIST_H #include "types.h" enum direction{FORWARD,BACKWARD}; template class LinkedListIterator; template class ListElement { private: TYPE data; ListElement* next; ListElement* prev; public: ListElement (); ListElement (const TYPE&); ListElement (const ListElement&); ~ListElement (); ListElement& operator= (const ListElement&); ListElement* GetLast () { ListElement* tmp = this; while (tmp->GetNext()) { tmp = tmp->GetNext(); } return tmp; } ListElement* GetNext () const { return next ; } ListElement* GetPrev () const { return prev ; } inline TYPE& GetData () { return data ; } inline const TYPE& GetData () const { return data ; } void SetData ( const TYPE& d ) { data = d ; } // Quagmire - this may look like a mem leak, but dont change it, this behavior is expected where it's called void SetLastNext ( ListElement* p ) { GetLast()->SetNext(p); } void SetNext (ListElement* n) { next = n ; } void SetPrev (ListElement* p) { prev = p ; } void ReplaceData(const TYPE&); }; template class LinkedList { private: uint32 count; ListElement* first; bool list_destructor_invoked; public: LinkedList(); ~LinkedList(); bool dont_delete; LinkedList& operator= (const LinkedList&); void Append (const TYPE&); void Insert (const TYPE&); TYPE Pop(); TYPE PeekTop(); void Clear(); void LCount() { count--; } void ResetCount() { count=0; } uint32 Count() { return count; } ListElement* GetFirst() { return first; } friend class LinkedListIterator; }; template class LinkedListIterator { private: LinkedList& list; ListElement* current_element; direction dir; public: LinkedListIterator(LinkedList& l,direction d = FORWARD) : list(l), dir(d) {}; void Advance(); const TYPE& GetData(); bool IsFirst() { if (current_element->GetPrev() == 0) return true; else return false; } bool IsLast() { if (current_element->GetNext() == 0) return true; else return false; } bool MoreElements(); void MoveFirst(); void MoveLast(); void RemoveCurrent(bool DeleteData = true); void Replace(const TYPE& new_data); void Reset(); void SetDir(direction); }; template void LinkedListIterator::Advance() { if (current_element == 0) { return; } if (dir == FORWARD) { current_element = current_element->GetNext(); } else { current_element = current_element->GetPrev(); } if (list.list_destructor_invoked) { while(current_element && current_element->GetData() == 0) { // if (current_element == 0) // { // return; // } if (dir == FORWARD) { current_element = current_element->GetNext(); } else { current_element = current_element->GetPrev(); } } } } template bool LinkedListIterator::MoreElements() { if (current_element == 0) return false; return true; } template const TYPE& LinkedListIterator::GetData() { return current_element->GetData(); } template void LinkedListIterator::MoveFirst() { ListElement* prev = current_element->GetPrev(); ListElement* next = current_element->GetNext(); if (prev == 0) { return; } //if (prev != 0) //{ prev->SetNext(next); //} if (next != 0) { next->SetPrev(prev); } current_element->SetPrev(0); current_element->SetNext(list.first); list.first->SetPrev(current_element); list.first = current_element; } template void LinkedListIterator::MoveLast() { ListElement* prev = current_element->GetPrev(); ListElement* next = current_element->GetNext(); if (next == 0) { return; } if (prev != 0) { prev->SetNext(next); } else { list.first = next; } //if (next != 0) //{ next->SetPrev(prev); //} current_element->SetNext(0); current_element->SetPrev(next->GetLast()); next->GetLast()->SetNext(current_element); } template void LinkedListIterator::RemoveCurrent(bool DeleteData) { ListElement* save; if (list.first == current_element) { list.first = current_element->GetNext(); } if (current_element->GetPrev() != 0) { current_element->GetPrev()->SetNext(current_element->GetNext()); } if (current_element->GetNext() != 0) { current_element->GetNext()->SetPrev(current_element->GetPrev()); } if (dir == FORWARD) { save = current_element->GetNext(); } else { save = current_element->GetPrev(); } current_element->SetNext(0); current_element->SetPrev(0); if (!DeleteData) current_element->SetData(0); safe_delete(current_element); current_element = save; list.LCount(); } template void LinkedListIterator::Replace(const TYPE& new_data) { current_element->ReplaceData(new_data); } template void LinkedListIterator::Reset() { if (dir == FORWARD) { current_element = list.first; } else { if (list.first == 0) { current_element = 0; } else { current_element = list.first->GetLast(); } } if (list.list_destructor_invoked) { while(current_element && current_element->GetData() == 0) { // if (current_element == 0) // { // return; // } if (dir == FORWARD) { current_element = current_element->GetNext(); } else { current_element = current_element->GetPrev(); } } } } template void LinkedListIterator::SetDir(direction d) { dir = d; } template ListElement::ListElement(const TYPE& d) { data = d; next = 0; prev = 0; } template ListElement::~ListElement() { // std::cout << "ListElement::~ListElement()" << std::endl; if (data != 0) safe_delete(data); data = 0; if (next != 0) { safe_delete(next); next = 0; } } template void ListElement::ReplaceData(const TYPE& new_data) { if (data != 0) safe_delete(data); data = new_data; } template LinkedList::LinkedList() { list_destructor_invoked = false; first = 0; count = 0; dont_delete = false; } template LinkedList::~LinkedList() { list_destructor_invoked = true; if(!dont_delete) Clear(); } template void LinkedList::Clear() { while (first) { ListElement* tmp = first; first = tmp->GetNext(); tmp->SetNext(0); safe_delete(tmp); } ResetCount(); } template void LinkedList::Append(const TYPE& data) { ListElement* new_element = new ListElement(data); if (first == 0) { first = new_element; } else { new_element->SetPrev(first->GetLast()); first->SetLastNext(new_element); } count++; } template void LinkedList::Insert(const TYPE& data) { ListElement* new_element = new ListElement(data); new_element->SetNext(first); if (first != 0) { first->SetPrev(new_element); } first = new_element; count++; } template TYPE LinkedList::Pop() { TYPE ret = 0; if (first) { ListElement* tmpdel = first; first = tmpdel->GetNext(); if (first) first->SetPrev(0); ret = tmpdel->GetData(); tmpdel->SetData(0); tmpdel->SetNext(0); safe_delete(tmpdel); count--; } return ret; } template TYPE LinkedList::PeekTop() { if (first) return first->GetData(); return 0; } #endif