#pragma once #include "Assertions.h" #include "Types.h" namespace AK { template class InlineLinkedListNode { public: InlineLinkedListNode(); void set_prev(T*); void set_next(T*); T* prev() const; T* next() const; }; template inline InlineLinkedListNode::InlineLinkedListNode() { set_prev(0); set_next(0); } template inline void InlineLinkedListNode::set_prev(T* prev) { static_cast(this)->m_prev = prev; } template inline void InlineLinkedListNode::set_next(T* next) { static_cast(this)->m_next = next; } template inline T* InlineLinkedListNode::prev() const { return static_cast(this)->m_prev; } template inline T* InlineLinkedListNode::next() const { return static_cast(this)->m_next; } template class InlineLinkedList { public: InlineLinkedList() {} bool is_empty() const { return !m_head; } size_t size_slow() const; void clear(); T* head() const { return m_head; } T* remove_head(); T* remove_tail(); T* tail() const { return m_tail; } void prepend(T*); void append(T*); void remove(T*); void append(InlineLinkedList&); bool contains_slow(T* value) const { for (T* node = m_head; node; node = node->next()) { if (node == value) return true; } return false; } private: T* m_head { nullptr }; T* m_tail { nullptr }; }; template inline size_t InlineLinkedList::size_slow() const { size_t size = 0; for (T* node = m_head; node; node = node->next()) ++size; return size; } template inline void InlineLinkedList::clear() { m_head = 0; m_tail = 0; } template inline void InlineLinkedList::prepend(T* node) { if (!m_head) { ASSERT(!m_tail); m_head = node; m_tail = node; node->set_prev(0); node->set_next(0); return; } ASSERT(m_tail); m_head->set_prev(node); node->set_next(m_head); node->set_prev(0); m_head = node; } template inline void InlineLinkedList::append(T* node) { if (!m_tail) { ASSERT(!m_head); m_head = node; m_tail = node; node->set_prev(0); node->set_next(0); return; } ASSERT(m_head); m_tail->set_next(node); node->set_prev(m_tail); node->set_next(0); m_tail = node; } template inline void InlineLinkedList::remove(T* node) { if (node->prev()) { ASSERT(node != m_head); node->prev()->set_next(node->next()); } else { ASSERT(node == m_head); m_head = node->next(); } if (node->next()) { ASSERT(node != m_tail); node->next()->set_prev(node->prev()); } else { ASSERT(node == m_tail); m_tail = node->prev(); } } template inline T* InlineLinkedList::remove_head() { T* node = head(); if (node) remove(node); return node; } template inline T* InlineLinkedList::remove_tail() { T* node = tail(); if (node) remove(node); return node; } template inline void InlineLinkedList::append(InlineLinkedList& other) { if (!other.head()) return; if (!head()) { m_head = other.head(); m_tail = other.tail(); other.clear(); return; } ASSERT(tail()); ASSERT(other.head()); T* other_head = other.head(); T* other_tail = other.tail(); other.clear(); ASSERT(!m_tail->next()); m_tail->set_next(other_head); ASSERT(!other_head->prev()); other_head->set_prev(m_tail); m_tail = other_tail; } } using AK::InlineLinkedList; using AK::InlineLinkedListNode;