#pragma once #include "Assertions.h" #include "types.h" template class DoublyLinkedListNode { public: DoublyLinkedListNode(); void setPrev(T*); void setNext(T*); T* prev() const; T* next() const; }; template inline DoublyLinkedListNode::DoublyLinkedListNode() { setPrev(0); setNext(0); } template inline void DoublyLinkedListNode::setPrev(T* prev) { static_cast(this)->m_prev = prev; } template inline void DoublyLinkedListNode::setNext(T* next) { static_cast(this)->m_next = next; } template inline T* DoublyLinkedListNode::prev() const { return static_cast(this)->m_prev; } template inline T* DoublyLinkedListNode::next() const { return static_cast(this)->m_next; } template class DoublyLinkedList { public: DoublyLinkedList() { } bool isEmpty() const { return !m_head; } size_t size() const; void clear(); T* head() const { return m_head; } T* removeHead(); T* tail() const { return m_tail; } void prepend(T*); void append(T*); void remove(T*); void append(DoublyLinkedList&); private: T* m_head { nullptr }; T* m_tail { nullptr }; }; template inline size_t DoublyLinkedList::size() const { size_t size = 0; for (T* node = m_head; node; node = node->next()) ++size; return size; } template inline void DoublyLinkedList::clear() { m_head = 0; m_tail = 0; } template inline void DoublyLinkedList::prepend(T* node) { if (!m_head) { ASSERT(!m_tail); m_head = node; m_tail = node; node->setPrev(0); node->setNext(0); return; } ASSERT(m_tail); m_head->setPrev(node); node->setNext(m_head); node->setPrev(0); m_head = node; } template inline void DoublyLinkedList::append(T* node) { if (!m_tail) { ASSERT(!m_head); m_head = node; m_tail = node; node->setPrev(0); node->setNext(0); return; } ASSERT(m_head); m_tail->setNext(node); node->setPrev(m_tail); node->setNext(0); m_tail = node; } template inline void DoublyLinkedList::remove(T* node) { if (node->prev()) { ASSERT(node != m_head); node->prev()->setNext(node->next()); } else { ASSERT(node == m_head); m_head = node->next(); } if (node->next()) { ASSERT(node != m_tail); node->next()->setPrev(node->prev()); } else { ASSERT(node == m_tail); m_tail = node->prev(); } } template inline T* DoublyLinkedList::removeHead() { T* node = head(); if (node) remove(node); return node; } template inline void DoublyLinkedList::append(DoublyLinkedList& other) { if (!other.head()) return; if (!head()) { m_head = other.head(); m_tail = other.tail(); other.clear(); return; } ASSERT(tail()); ASSERT(other.head()); T* otherHead = other.head(); T* otherTail = other.tail(); other.clear(); ASSERT(!m_tail->next()); m_tail->setNext(otherHead); ASSERT(!otherHead->prev()); otherHead->setPrev(m_tail); m_tail = otherTail; }