/* * Copyright (c) 2018-2020, Andreas Kling * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include #include #include #include #include namespace Web { template class TreeNode : public Weakable { public: void ref() { ASSERT(!m_in_removed_last_ref); ASSERT(m_ref_count); ++m_ref_count; } void unref() { ASSERT(!m_in_removed_last_ref); ASSERT(m_ref_count); if (!--m_ref_count) { if constexpr (IsBaseOf::value) { m_in_removed_last_ref = true; static_cast(this)->removed_last_ref(); } else { delete static_cast(this); } return; } } 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; } int child_count() const { int count = 0; for (auto* child = first_child(); child; child = child->next_sibling()) ++count; return count; } T* child_at_index(int index) { int count = 0; for (auto* child = first_child(); child; child = child->next_sibling()) { if (count == index) return child; ++count; } return nullptr; } const T* child_at_index(int index) const { return const_cast(this)->child_at_index(index); } bool is_ancestor_of(const TreeNode&) const; void prepend_child(NonnullRefPtr node); void append_child(NonnullRefPtr node, bool notify = true); void insert_before(NonnullRefPtr node, RefPtr child, bool notify = true); NonnullRefPtr remove_child(NonnullRefPtr node); void remove_all_children(); bool is_child_allowed(const T&) const { return true; } T* next_in_pre_order() { if (first_child()) return first_child(); T* node; if (!(node = next_sibling())) { node = parent(); while (node && !node->next_sibling()) node = node->parent(); if (node) node = node->next_sibling(); } return node; } const T* next_in_pre_order() const { return const_cast(this)->next_in_pre_order(); } bool is_before(const T& other) const { if (this == &other) return false; for (auto* node = this; node; node = node->next_in_pre_order()) { if (node == &other) return true; } return false; } template IterationDecision for_each_in_subtree(Callback callback) const { if (callback(static_cast(*this)) == IterationDecision::Break) return IterationDecision::Break; for (auto* child = first_child(); child; child = child->next_sibling()) { if (child->for_each_in_subtree(callback) == IterationDecision::Break) return IterationDecision::Break; } return IterationDecision::Continue; } template IterationDecision for_each_in_subtree(Callback callback) { if (callback(static_cast(*this)) == IterationDecision::Break) return IterationDecision::Break; for (auto* child = first_child(); child; child = child->next_sibling()) { if (child->for_each_in_subtree(callback) == IterationDecision::Break) return IterationDecision::Break; } return IterationDecision::Continue; } template IterationDecision for_each_in_subtree_of_type(Callback callback) { if (is(static_cast(*this))) { if (callback(static_cast(*this)) == IterationDecision::Break) return IterationDecision::Break; } for (auto* child = first_child(); child; child = child->next_sibling()) { if (child->template for_each_in_subtree_of_type(callback) == IterationDecision::Break) return IterationDecision::Break; } return IterationDecision::Continue; } template IterationDecision for_each_in_subtree_of_type(Callback callback) const { if (is(static_cast(*this))) { if (callback(static_cast(*this)) == IterationDecision::Break) return IterationDecision::Break; } for (auto* child = first_child(); child; child = child->next_sibling()) { if (child->template for_each_in_subtree_of_type(callback) == IterationDecision::Break) return IterationDecision::Break; } return IterationDecision::Continue; } template void for_each_child(Callback callback) const { return const_cast(this)->template for_each_child(move(callback)); } template void for_each_child(Callback callback) { for (auto* node = first_child(); node; node = node->next_sibling()) callback(*node); } template void for_each_child_of_type(Callback callback) { for (auto* node = first_child(); node; node = node->next_sibling()) { if (is(node)) callback(downcast(*node)); } } template void for_each_child_of_type(Callback callback) const { return const_cast(this)->template for_each_child_of_type(move(callback)); } template const U* next_sibling_of_type() const { return const_cast(this)->template next_sibling_of_type(); } template inline U* next_sibling_of_type() { for (auto* sibling = next_sibling(); sibling; sibling = sibling->next_sibling()) { if (is(*sibling)) return &downcast(*sibling); } return nullptr; } template const U* previous_sibling_of_type() const { return const_cast(this)->template previous_sibling_of_type(); } template U* previous_sibling_of_type() { for (auto* sibling = previous_sibling(); sibling; sibling = sibling->previous_sibling()) { if (is(*sibling)) return &downcast(*sibling); } return nullptr; } template const U* first_child_of_type() const { return const_cast(this)->template first_child_of_type(); } template const U* last_child_of_type() const { return const_cast(this)->template last_child_of_type(); } template U* first_child_of_type() { for (auto* child = first_child(); child; child = child->next_sibling()) { if (is(*child)) return &downcast(*child); } return nullptr; } template U* last_child_of_type() { for (auto* child = last_child(); child; child = child->previous_sibling()) { if (is(*child)) return &downcast(*child); } return nullptr; } template const U* first_ancestor_of_type() const { return const_cast(this)->template first_ancestor_of_type(); } template U* first_ancestor_of_type() { for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { if (is(*ancestor)) return &downcast(*ancestor); } return nullptr; } protected: TreeNode() { } bool m_deletion_has_begun { false }; bool m_in_removed_last_ref { false }; 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::remove_all_children() { while (RefPtr child = first_child()) remove_child(child.release_nonnull()); } template inline NonnullRefPtr TreeNode::remove_child(NonnullRefPtr node) { ASSERT(node->m_parent == this); if (m_first_child == node) m_first_child = node->m_next_sibling; if (m_last_child == node) m_last_child = node->m_previous_sibling; if (node->m_next_sibling) node->m_next_sibling->m_previous_sibling = node->m_previous_sibling; if (node->m_previous_sibling) node->m_previous_sibling->m_next_sibling = node->m_next_sibling; node->m_next_sibling = nullptr; node->m_previous_sibling = nullptr; node->m_parent = nullptr; node->removed_from(static_cast(*this)); node->unref(); static_cast(this)->children_changed(); return node; } template inline void TreeNode::append_child(NonnullRefPtr node, bool notify) { ASSERT(!node->m_parent); if (!static_cast(this)->is_child_allowed(*node)) return; 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 (notify) node->inserted_into(static_cast(*this)); [[maybe_unused]] auto& rc = node.leak_ref(); if (notify) static_cast(this)->children_changed(); } template inline void TreeNode::insert_before(NonnullRefPtr node, RefPtr child, bool notify) { if (!child) return append_child(move(node), notify); ASSERT(!node->m_parent); ASSERT(child->parent() == this); if (!static_cast(this)->is_child_allowed(*node)) return; node->m_previous_sibling = child->m_previous_sibling; node->m_next_sibling = child; if (child->m_previous_sibling) child->m_previous_sibling->m_next_sibling = node; if (m_first_child == child) m_first_child = node; child->m_previous_sibling = node; if (m_first_child == child) m_first_child = node; node->m_parent = static_cast(this); if (notify) node->inserted_into(static_cast(*this)); [[maybe_unused]] auto& rc = node.leak_ref(); if (notify) static_cast(this)->children_changed(); } template inline void TreeNode::prepend_child(NonnullRefPtr node) { ASSERT(!node->m_parent); if (!static_cast(this)->is_child_allowed(*node)) return; 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; node->inserted_into(static_cast(*this)); [[maybe_unused]] auto& rc = node.leak_ref(); static_cast(this)->children_changed(); } 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; } }