eq2go/old/common/linked_list.hpp
2025-08-06 19:00:30 -05:00

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;
}