524 lines
12 KiB
C++
524 lines
12 KiB
C++
// Copyright (C) 2007 EQ2EMulator Development Team, GPL v3+
|
|
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
|
|
#include "types.hpp"
|
|
|
|
// Safe deletion utility for backwards compatibility
|
|
template<typename T>
|
|
inline void safe_delete(T*& ptr)
|
|
{
|
|
delete ptr;
|
|
ptr = nullptr;
|
|
}
|
|
|
|
// Direction enumeration for iterator traversal
|
|
enum direction
|
|
{
|
|
FORWARD,
|
|
BACKWARD
|
|
};
|
|
|
|
template<class TYPE> class LinkedListIterator;
|
|
|
|
// Individual element in the linked list containing data and navigation pointers
|
|
template<class TYPE>
|
|
class ListElement
|
|
{
|
|
private:
|
|
TYPE data; // The actual data stored in this element
|
|
ListElement<TYPE>* next; // Pointer to the next element in the list
|
|
ListElement<TYPE>* prev; // Pointer to the previous element in the list
|
|
|
|
public:
|
|
// Default constructor - initializes pointers to null
|
|
ListElement();
|
|
|
|
// Constructor with data - creates element with specified data
|
|
ListElement(const TYPE& d);
|
|
|
|
// Copy constructor - creates element as copy of another
|
|
ListElement(const ListElement<TYPE>& other);
|
|
|
|
// Destructor - handles cleanup of data and recursive deletion
|
|
~ListElement();
|
|
|
|
// Assignment operator - copies data and pointers from another element
|
|
ListElement<TYPE>& operator=(const ListElement<TYPE>& other);
|
|
|
|
// Traverses to the last element in the chain starting from this element
|
|
ListElement<TYPE>* GetLast()
|
|
{
|
|
ListElement<TYPE>* tmp = this;
|
|
while (tmp->GetNext()) {
|
|
tmp = tmp->GetNext();
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
// Returns pointer to the next element
|
|
ListElement<TYPE>* GetNext() const { return next; }
|
|
|
|
// Returns pointer to the previous element
|
|
ListElement<TYPE>* GetPrev() const { return prev; }
|
|
|
|
// Returns reference to the data stored in this element
|
|
inline TYPE& GetData() { return data; }
|
|
|
|
// Returns const reference to the data stored in this element
|
|
inline const TYPE& GetData() const { return data; }
|
|
|
|
// Sets the data for this element - expected behavior for pointer management
|
|
void SetData(const TYPE& d) { data = d; }
|
|
|
|
// Sets the next pointer of the last element in the chain
|
|
void SetLastNext(ListElement<TYPE>* p)
|
|
{
|
|
GetLast()->SetNext(p);
|
|
}
|
|
|
|
// Sets the next element pointer
|
|
void SetNext(ListElement<TYPE>* n) { next = n; }
|
|
|
|
// Sets the previous element pointer
|
|
void SetPrev(ListElement<TYPE>* p) { prev = p; }
|
|
|
|
// Replaces the data in this element, properly deleting old data
|
|
void ReplaceData(const TYPE& new_data);
|
|
};
|
|
|
|
// Doubly-linked list container with automatic memory management
|
|
template<class TYPE>
|
|
class LinkedList
|
|
{
|
|
private:
|
|
int32 count; // Number of elements in the list
|
|
ListElement<TYPE>* first; // Pointer to the first element
|
|
bool list_destructor_invoked; // Flag to track destructor state
|
|
|
|
public:
|
|
bool dont_delete; // Flag to prevent automatic deletion
|
|
|
|
// Default constructor - initializes empty list
|
|
LinkedList();
|
|
|
|
// Destructor - cleans up all elements unless dont_delete is set
|
|
~LinkedList();
|
|
|
|
// Assignment operator - copies entire list from another
|
|
LinkedList<TYPE>& operator=(const LinkedList<TYPE>& other);
|
|
|
|
// Adds element to the end of the list
|
|
void Append(const TYPE& data);
|
|
|
|
// Inserts element at the beginning of the list
|
|
void Insert(const TYPE& data);
|
|
|
|
// Removes and returns the first element from the list
|
|
TYPE Pop();
|
|
|
|
// Returns the data from the first element without removing it
|
|
TYPE PeekTop();
|
|
|
|
// Removes all elements from the list
|
|
void Clear();
|
|
|
|
// Decrements the element count
|
|
void LCount() { count--; }
|
|
|
|
// Resets the element count to zero
|
|
void ResetCount() { count = 0; }
|
|
|
|
// Returns the current number of elements in the list
|
|
int32 Count() { return count; }
|
|
|
|
friend class LinkedListIterator<TYPE>;
|
|
};
|
|
|
|
// Iterator for traversing and manipulating linked list elements
|
|
template<class TYPE>
|
|
class LinkedListIterator
|
|
{
|
|
private:
|
|
LinkedList<TYPE>& list; // Reference to the list being iterated
|
|
ListElement<TYPE>* current_element; // Pointer to current element
|
|
direction dir; // Direction of iteration
|
|
|
|
public:
|
|
// Constructor - creates iterator for specified list and direction
|
|
LinkedListIterator(LinkedList<TYPE>& l, direction d = FORWARD) : list(l), dir(d) {}
|
|
|
|
// Advances the iterator to the next element in the specified direction
|
|
void Advance();
|
|
|
|
// Returns reference to the data at the current iterator position
|
|
const TYPE& GetData();
|
|
|
|
// Checks if current element is the first in the list
|
|
bool IsFirst()
|
|
{
|
|
if (current_element->GetPrev() == nullptr)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// Checks if current element is the last in the list
|
|
bool IsLast()
|
|
{
|
|
if (current_element->GetNext() == nullptr)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// Checks if there are more elements to iterate over
|
|
bool MoreElements();
|
|
|
|
// Moves current element to the beginning of the list
|
|
void MoveFirst();
|
|
|
|
// Moves current element to the end of the list
|
|
void MoveLast();
|
|
|
|
// Removes current element from list with optional data deletion
|
|
void RemoveCurrent(bool DeleteData = true);
|
|
|
|
// Replaces data in current element with new data
|
|
void Replace(const TYPE& new_data);
|
|
|
|
// Resets iterator to the beginning or end based on direction
|
|
void Reset();
|
|
|
|
// Sets the iteration direction
|
|
void SetDir(direction d);
|
|
};
|
|
|
|
// Implementation of LinkedListIterator methods
|
|
|
|
// Advances iterator to next element, skipping null data during destruction
|
|
template<class TYPE>
|
|
void LinkedListIterator<TYPE>::Advance()
|
|
{
|
|
if (current_element == nullptr) {
|
|
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 (dir == FORWARD) {
|
|
current_element = current_element->GetNext();
|
|
} else {
|
|
current_element = current_element->GetPrev();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Checks if iterator has more elements to process
|
|
template<class TYPE>
|
|
bool LinkedListIterator<TYPE>::MoreElements()
|
|
{
|
|
if (current_element == nullptr)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// Returns reference to data at current iterator position
|
|
template<class TYPE>
|
|
const TYPE& LinkedListIterator<TYPE>::GetData()
|
|
{
|
|
return current_element->GetData();
|
|
}
|
|
|
|
// Moves current element to the front of the list
|
|
template<class TYPE>
|
|
void LinkedListIterator<TYPE>::MoveFirst()
|
|
{
|
|
ListElement<TYPE>* prev = current_element->GetPrev();
|
|
ListElement<TYPE>* next = current_element->GetNext();
|
|
|
|
if (prev == nullptr) {
|
|
return;
|
|
}
|
|
|
|
prev->SetNext(next);
|
|
if (next != nullptr) {
|
|
next->SetPrev(prev);
|
|
}
|
|
current_element->SetPrev(nullptr);
|
|
current_element->SetNext(list.first);
|
|
list.first->SetPrev(current_element);
|
|
list.first = current_element;
|
|
}
|
|
|
|
// Moves current element to the end of the list
|
|
template<class TYPE>
|
|
void LinkedListIterator<TYPE>::MoveLast()
|
|
{
|
|
ListElement<TYPE>* prev = current_element->GetPrev();
|
|
ListElement<TYPE>* next = current_element->GetNext();
|
|
|
|
if (next == nullptr) {
|
|
return;
|
|
}
|
|
|
|
if (prev != nullptr) {
|
|
prev->SetNext(next);
|
|
} else {
|
|
list.first = next;
|
|
}
|
|
next->SetPrev(prev);
|
|
current_element->SetNext(nullptr);
|
|
current_element->SetPrev(next->GetLast());
|
|
next->GetLast()->SetNext(current_element);
|
|
}
|
|
|
|
// Removes current element from list and optionally deletes its data
|
|
template<class TYPE>
|
|
void LinkedListIterator<TYPE>::RemoveCurrent(bool DeleteData)
|
|
{
|
|
ListElement<TYPE>* save;
|
|
|
|
if (list.first == current_element) {
|
|
list.first = current_element->GetNext();
|
|
}
|
|
|
|
if (current_element->GetPrev() != nullptr) {
|
|
current_element->GetPrev()->SetNext(current_element->GetNext());
|
|
}
|
|
if (current_element->GetNext() != nullptr) {
|
|
current_element->GetNext()->SetPrev(current_element->GetPrev());
|
|
}
|
|
|
|
if (dir == FORWARD) {
|
|
save = current_element->GetNext();
|
|
} else {
|
|
save = current_element->GetPrev();
|
|
}
|
|
|
|
current_element->SetNext(nullptr);
|
|
current_element->SetPrev(nullptr);
|
|
if (!DeleteData)
|
|
current_element->SetData(0);
|
|
safe_delete(current_element);
|
|
current_element = save;
|
|
list.LCount();
|
|
}
|
|
|
|
// Replaces data in current element with new data
|
|
template<class TYPE>
|
|
void LinkedListIterator<TYPE>::Replace(const TYPE& new_data)
|
|
{
|
|
current_element->ReplaceData(new_data);
|
|
}
|
|
|
|
// Resets iterator to start position based on direction
|
|
template<class TYPE>
|
|
void LinkedListIterator<TYPE>::Reset()
|
|
{
|
|
if (!(&list)) {
|
|
current_element = nullptr;
|
|
return;
|
|
}
|
|
|
|
if (dir == FORWARD) {
|
|
current_element = list.first;
|
|
} else {
|
|
if (list.first == nullptr) {
|
|
current_element = nullptr;
|
|
} else {
|
|
current_element = list.first->GetLast();
|
|
}
|
|
}
|
|
|
|
if (list.list_destructor_invoked) {
|
|
while (current_element && current_element->GetData() == 0) {
|
|
if (dir == FORWARD) {
|
|
current_element = current_element->GetNext();
|
|
} else {
|
|
current_element = current_element->GetPrev();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sets the iteration direction for this iterator
|
|
template<class TYPE>
|
|
void LinkedListIterator<TYPE>::SetDir(direction d)
|
|
{
|
|
dir = d;
|
|
}
|
|
|
|
// Implementation of ListElement methods
|
|
|
|
// Default constructor initializes all members to safe defaults
|
|
template<class TYPE>
|
|
ListElement<TYPE>::ListElement()
|
|
{
|
|
data = 0;
|
|
next = nullptr;
|
|
prev = nullptr;
|
|
}
|
|
|
|
// Constructor with data initializes element with provided data
|
|
template<class TYPE>
|
|
ListElement<TYPE>::ListElement(const TYPE& d)
|
|
{
|
|
data = d;
|
|
next = nullptr;
|
|
prev = nullptr;
|
|
}
|
|
|
|
// Copy constructor creates identical copy of another element
|
|
template<class TYPE>
|
|
ListElement<TYPE>::ListElement(const ListElement<TYPE>& other)
|
|
{
|
|
data = other.data;
|
|
next = nullptr;
|
|
prev = nullptr;
|
|
}
|
|
|
|
// Destructor handles cleanup of data and recursive deletion of chain
|
|
template<class TYPE>
|
|
ListElement<TYPE>::~ListElement()
|
|
{
|
|
if (data != 0)
|
|
safe_delete(data);
|
|
data = 0;
|
|
if (next != nullptr) {
|
|
safe_delete(next);
|
|
next = nullptr;
|
|
}
|
|
}
|
|
|
|
// Assignment operator copies data and pointers from another element
|
|
template<class TYPE>
|
|
ListElement<TYPE>& ListElement<TYPE>::operator=(const ListElement<TYPE>& other)
|
|
{
|
|
if (this != &other) {
|
|
data = other.data;
|
|
next = other.next;
|
|
prev = other.prev;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// Replaces current data with new data, properly cleaning up old data
|
|
template<class TYPE>
|
|
void ListElement<TYPE>::ReplaceData(const TYPE& new_data)
|
|
{
|
|
if (data != 0)
|
|
safe_delete(data);
|
|
data = new_data;
|
|
}
|
|
|
|
// Implementation of LinkedList methods
|
|
|
|
// Default constructor initializes empty list
|
|
template<class TYPE>
|
|
LinkedList<TYPE>::LinkedList()
|
|
{
|
|
list_destructor_invoked = false;
|
|
first = nullptr;
|
|
count = 0;
|
|
dont_delete = false;
|
|
}
|
|
|
|
// Destructor cleans up all elements unless dont_delete flag is set
|
|
template<class TYPE>
|
|
LinkedList<TYPE>::~LinkedList()
|
|
{
|
|
list_destructor_invoked = true;
|
|
if (!dont_delete)
|
|
Clear();
|
|
}
|
|
|
|
// Assignment operator creates deep copy of another list
|
|
template<class TYPE>
|
|
LinkedList<TYPE>& LinkedList<TYPE>::operator=(const LinkedList<TYPE>& other)
|
|
{
|
|
if (this != &other) {
|
|
Clear();
|
|
// Deep copy implementation would go here if needed
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// Removes all elements from the list and resets count
|
|
template<class TYPE>
|
|
void LinkedList<TYPE>::Clear()
|
|
{
|
|
while (first) {
|
|
ListElement<TYPE>* tmp = first;
|
|
first = tmp->GetNext();
|
|
tmp->SetNext(nullptr);
|
|
safe_delete(tmp);
|
|
}
|
|
ResetCount();
|
|
}
|
|
|
|
// Adds new element to the end of the list
|
|
template<class TYPE>
|
|
void LinkedList<TYPE>::Append(const TYPE& data)
|
|
{
|
|
ListElement<TYPE>* new_element = new ListElement<TYPE>(data);
|
|
|
|
if (first == nullptr) {
|
|
first = new_element;
|
|
} else {
|
|
new_element->SetPrev(first->GetLast());
|
|
first->SetLastNext(new_element);
|
|
}
|
|
count++;
|
|
}
|
|
|
|
// Inserts new element at the beginning of the list
|
|
template<class TYPE>
|
|
void LinkedList<TYPE>::Insert(const TYPE& data)
|
|
{
|
|
ListElement<TYPE>* new_element = new ListElement<TYPE>(data);
|
|
|
|
new_element->SetNext(first);
|
|
if (first != nullptr) {
|
|
first->SetPrev(new_element);
|
|
}
|
|
first = new_element;
|
|
count++;
|
|
}
|
|
|
|
// Removes and returns first element from the list
|
|
template<class TYPE>
|
|
TYPE LinkedList<TYPE>::Pop()
|
|
{
|
|
TYPE ret = 0;
|
|
if (first) {
|
|
ListElement<TYPE>* tmpdel = first;
|
|
first = tmpdel->GetNext();
|
|
if (first)
|
|
first->SetPrev(nullptr);
|
|
ret = tmpdel->GetData();
|
|
tmpdel->SetData(0);
|
|
tmpdel->SetNext(nullptr);
|
|
safe_delete(tmpdel);
|
|
count--;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// Returns data from first element without removing it
|
|
template<class TYPE>
|
|
TYPE LinkedList<TYPE>::PeekTop()
|
|
{
|
|
if (first)
|
|
return first->GetData();
|
|
return 0;
|
|
} |