#pragma once #include #include template class TreeNode { public: void ref() { ASSERT(m_ref_count); ++m_ref_count; } void deref() { ASSERT(m_ref_count); if (!--m_ref_count) { if (m_next_sibling) m_next_sibling->m_previous_sibling = m_previous_sibling; if (m_previous_sibling) m_previous_sibling->m_next_sibling = m_next_sibling; T* next_child; for (auto* child = m_first_child; child; child = next_child) { next_child = child->m_next_sibling; child->m_parent = nullptr; child->deref(); } delete static_cast(this); } } int ref_count() const { return m_ref_count; } T* parent() { return m_parent; } const T* parent() const { return m_parent; } bool has_children() const { return m_first_child; } T* next_sibling() { return m_next_sibling; } T* previous_sibling() { return m_previous_sibling; } T* first_child() { return m_first_child; } T* last_child() { return m_last_child; } const T* next_sibling() const { return m_next_sibling; } const T* previous_sibling() const { return m_previous_sibling; } const T* first_child() const { return m_first_child; } const T* last_child() const { return m_last_child; } bool is_ancestor_of(const TreeNode&) const; void prepend_child(NonnullRefPtr node, bool call_inserted_into = true); void append_child(NonnullRefPtr node, bool call_inserted_into = true); void donate_all_children_to(T& node); protected: TreeNode() { } private: int m_ref_count { 1 }; T* m_parent { nullptr }; T* m_first_child { nullptr }; T* m_last_child { nullptr }; T* m_next_sibling { nullptr }; T* m_previous_sibling { nullptr }; }; template inline void TreeNode::append_child(NonnullRefPtr node, bool call_inserted_into) { ASSERT(!node->m_parent); if (m_last_child) m_last_child->m_next_sibling = node.ptr(); node->m_previous_sibling = m_last_child; node->m_parent = static_cast(this); m_last_child = node.ptr(); if (!m_first_child) m_first_child = m_last_child; if (call_inserted_into) node->inserted_into(static_cast(*this)); (void)node.leak_ref(); } template inline void TreeNode::prepend_child(NonnullRefPtr node, bool call_inserted_into) { ASSERT(!node->m_parent); if (m_first_child) m_first_child->m_previous_sibling = node.ptr(); node->m_next_sibling = m_first_child; node->m_parent = static_cast(this); m_first_child = node.ptr(); if (!m_last_child) m_last_child = m_first_child; if (call_inserted_into) node->inserted_into(static_cast(*this)); (void)node.leak_ref(); } template inline void TreeNode::donate_all_children_to(T& node) { for (T* child = m_first_child; child != nullptr;) { T* next_child = child->m_next_sibling; child->m_parent = nullptr; child->m_next_sibling = nullptr; child->m_previous_sibling = nullptr; node.append_child(adopt(*child)); child = next_child; } m_first_child = nullptr; m_last_child = nullptr; } template inline bool TreeNode::is_ancestor_of(const TreeNode& other) const { for (auto* ancestor = other.parent(); ancestor; ancestor = ancestor->parent()) { if (ancestor == this) return true; } return false; }