/*
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