/* EQ2Emulator: Everquest II Server Emulator Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net) This file is part of EQ2Emulator. EQ2Emulator 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, either version 3 of the License, or (at your option) any later version. EQ2Emulator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see . */ #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: int32 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; } int32 Count() { return count; } 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 (!(&list)) { current_element=0; return; } 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() { // cout << "ListElement::~ListElement()" << 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