// Splay tree utilities -*- C++ -*- // Copyright (C) 2020-2023 Free Software Foundation, Inc. // // This file is part of GCC. // // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . // INDEX is either 0 or 1. If it is 0, return NODE's left child, // otherwise return NODE's right child. template inline typename base_splay_tree::node_type base_splay_tree::get_child (node_type node, unsigned int index) { return Accessors::child (node, index); } // INDEX is either 0 or 1. If it is 0, change NODE's left child to CHILD, // otherwise change NODE's right child to CHILD. If CHILD has a parent // field, record that its parent is now NODE. template inline void base_splay_tree::set_child (node_type node, unsigned int index, node_type child) { Accessors::child (node, index) = child; if (child) set_parent (child, node); } // Rotate the tree to promote child number INDEX of NODE, so that that // child becomes a parent of NODE. Return the promoted node. // // The caller has the responsibility of assigning a correct parent // to the returned node. template inline typename base_splay_tree::node_type base_splay_tree::promote_child (node_type node, unsigned int index) { node_type promoted = get_child (node, index); set_child (node, index, get_child (promoted, 1 - index)); set_child (promoted, 1 - index, node); return promoted; } // Treat child number INDEX of NODE as being CHILD and rotate the tree // so that CHILD becomes a parent of NODE. // // The caller has the responsibility of assigning a correct parent to CHILD. template inline void base_splay_tree::promote_child (node_type node, unsigned int index, node_type child) { set_child (node, index, get_child (child, 1 - index)); set_child (child, 1 - index, node); } // Print NODE to PP, using PRINTER (PP, N) to print the contents of node N. // Prefix each new line with INDENT_STRING. CODE is 'T' if NODE is the root // node, 'L' if NODE is the left child of its parent, or 'R' if NODE is the // right child of its parent. template template void base_splay_tree::print (pretty_printer *pp, node_type node, Printer printer, char code, vec &indent_string) { // In the comments below, PREFIX refers to the incoming contents // of INDENT_STRING. node_type left = get_child (node, 0); node_type right = get_child (node, 1); auto orig_indent_len = indent_string.length (); indent_string.safe_grow (orig_indent_len + 3); char *extra_indent = indent_string.address () + orig_indent_len; // Print [T], [L], or [R]. extra_indent[0] = '['; extra_indent[1] = code; extra_indent[2] = ']'; pp_append_text (pp, extra_indent, indent_string.end ()); pp_space (pp); // Print the node itself, using PREFIX + " | " or PREFIX + " " to indent // new lines under the "[_]" that we just printed. extra_indent[0] = ' '; extra_indent[1] = (left || right ? '|' : ' '); extra_indent[2] = ' '; { pretty_printer sub_pp; printer (&sub_pp, node); const char *text = pp_formatted_text (&sub_pp); while (const char *end = strchr (text, '\n')) { pp_append_text (pp, text, end); pp_newline_and_indent (pp, 0); pp_append_text (pp, indent_string.begin (), indent_string.end ()); text = end + 1; } pp_string (pp, text); } if (left) { // Print PREFIX + " +-" for the first line of the left subtree, // to be followed by "[L]". extra_indent[1] = '+'; extra_indent[2] = '-'; pp_newline_and_indent (pp, 0); pp_append_text (pp, indent_string.begin (), indent_string.end ()); // Print the left subtree, using PREFIX + " | " or PREFIX + " " // to indent under the PREFIX + " +-" that we just printed. extra_indent[1] = right ? '|' : ' '; extra_indent[2] = ' '; print (pp, left, printer, 'L', indent_string); extra_indent = indent_string.address () + orig_indent_len; // If LEFT is not a leaf and we also have a right subtree, use a // PREFIX + " |" line to separate them. if (right && (get_child (left, 0) || get_child (left, 1))) { pp_newline_and_indent (pp, 0); pp_append_text (pp, indent_string.begin (), &extra_indent[2]); } } if (right) { // Print PREFIX + " +-" for the first line of the right subtree, // to be followed by "[R]". extra_indent[1] = '+'; extra_indent[2] = '-'; pp_newline_and_indent (pp, 0); pp_append_text (pp, indent_string.begin (), indent_string.end ()); // Print the right subtree, using PREFIX + " " to indent under the // PREFIX + " +-" that we just printed. extra_indent[1] = ' '; extra_indent[2] = ' '; print (pp, right, printer, 'R', indent_string); } indent_string.truncate (orig_indent_len); } // See the comment above the declaration. template template void base_splay_tree::print (pretty_printer *pp, node_type node, Printer printer) { if (!node) { pp_string (pp, "null"); return; } auto_vec indent_string; print (pp, node, printer, 'T', indent_string); } // If N is 1, splay the last (rightmost) node reachable from START // to the position that START current holds and return the splayed node. // START is not itself the last node. // // If N is 0, splay the first (leftmost) node reachable from START // to the position that START current holds and return the splayed node. // START is not itself the first node. // // The caller has the responsibility of updating the parent of the // returned node. template template typename base_splay_tree::node_type base_splay_tree::splay_limit (node_type start) { // This essentially follows the simpilfied top-down method described // in Sleator and Tarjan's "Self-adjusting Binary Search Trees", but // specialized for the case in which the comparison result is fixed. // The first iteration is peeled to avoid the need for stack temporaries. // // The comments and names reflect the behavior for N == 1, but the // N == 0 case behaves analogously. // Rotate the tree to promote the right child of START to the root. node_type node = promote_child (start, N); if (node_type right = get_child (node, N)) { // Perform the link left step, which for this first iteration // means making NODE the root of the left tree. // // NODE will become left child of the final node. For a right // spine starting at NODE of the form: // // 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> ... -> N // | | | | | | | | // V V V V V V V V // A B C D E F G NL // // the next step is to create a subtree of N whose right spine contains // the odd-numbered nodes, as follows: // // N // | // V // 1 ------> 3 ------> 5 ------> 7 -> .... -> NL // | | | | // V V V V // A 2 -> C 4 -> E 6 -> G // | | | // V V V // B D F // // First record 1 as the left child of the final root (N) and move // on to node 2. node_type final_child = node; node_type new_spine_end = node; node = right; while (node_type right = get_child (node, N)) { // Perform another rotate left step. // // We've built the tree rooted at 1 in the diagram above up to, // but not including, an even-numbered node NODE on the original // right spine. Rotate the tree at NODE to promote the following // odd-numbered node. promote_child (node, N, right); node = right; if (node_type right = get_child (node, N)) { // Perform another link left step. // // Add the promoted odd-numbered node to the right spine of the // tree rooted at 1 and move on to the next even-numbered node. set_child (new_spine_end, N, node); new_spine_end = node; node = right; } } // Perform the assembly step. // // Add NL to the new spine and make N the new root. set_child (new_spine_end, N, get_child (node, 1 - N)); set_child (node, 1 - N, final_child); } return node; } // Remove NODE from its position in the splay tree. If NODE has at least // one child node, return the node that should now hold NODE's position in // the splay tree. If NODE has no children, return null. // // The caller has the responsibility of updating the parent of the // returned node. template inline typename base_splay_tree::node_type base_splay_tree::remove_node_internal (node_type node) { node_type left = get_child (node, 0); node_type right = get_child (node, 1); if (!left) return right; if (!right) return left; if (get_child (left, 1)) { left = splay_limit<1> (left); gcc_checking_assert (!get_child (left, 1)); } set_child (left, 1, right); return left; } // See the comment above the declaration. template inline void base_splay_tree::insert_child (node_type node, unsigned int index, node_type child) { gcc_checking_assert (!get_child (child, 0) && !get_child (child, 1)); set_child (child, index, get_child (node, index)); set_child (node, index, child); } // Implement splay_next_node if N == 1 and splay_prev_node if N == 0. template template bool rooted_splay_tree::splay_neighbor () { node_type node = m_root; node_type new_root = get_child (node, N); if (!new_root) return false; if (get_child (new_root, 1 - N)) { // NEW_ROOT is not itself the required node, so splay the required // node into its place. new_root = parent::template splay_limit<1 - N> (new_root); gcc_checking_assert (!get_child (new_root, 1 - N)); set_child (node, N, node_type ()); set_child (new_root, 1 - N, node); } else promote_child (node, N, new_root); set_parent (new_root, node_type ()); m_root = new_root; return true; } // See the comment above the declaration. template template bool rooted_splay_tree::insert (node_type new_node, Comparator compare) { gcc_checking_assert (!get_child (new_node, 0) && !get_child (new_node, 1)); if (!m_root) { m_root = new_node; return true; } int comparison = lookup (compare); if (comparison == 0) return false; // Insert NEW_NODE before M_ROOT if COMPARISON < 0 and after M_ROOT // otherwise. set_child (new_node, comparison < 0, m_root); set_child (new_node, comparison > 0, get_child (m_root, comparison > 0)); set_child (m_root, comparison > 0, nullptr); m_root = new_node; return true; } // See the comment above the declaration. template inline void rooted_splay_tree::insert_max_node (node_type new_node) { gcc_checking_assert (!get_child (new_node, 0) && !get_child (new_node, 1)); set_child (new_node, 0, m_root); m_root = new_node; } // See the comment above the declaration. template inline void rooted_splay_tree::splice_next_tree (rooted_splay_tree next_tree) { splay_max_node (); set_child (m_root, 1, next_tree.m_root); } // See the comment above the declaration. template inline void rooted_splay_tree::replace_max_node_at_root (node_type new_node) { node_type old_node = m_root; gcc_checking_assert (!get_child (new_node, 0) && !get_child (new_node, 1) && !get_child (old_node, 1)); set_child (new_node, 0, get_child (old_node, 0)); // Clear the links from OLD_NODE. Its parent and right child are // already node_type (). set_child (old_node, 0, node_type ()); m_root = new_node; } // See the comment above the declaration. template inline void rooted_splay_tree::remove_root () { node_type node = m_root; m_root = parent::remove_node_internal (node); if (m_root) set_parent (m_root, node_type ()); // Clear the links from NODE. Its parent is already node_type (). set_child (node, 0, node_type ()); set_child (node, 1, node_type ()); } // See the comment above the declaration. template inline rooted_splay_tree rooted_splay_tree::split_before_root () { node_type new_root = get_child (m_root, 0); set_child (m_root, 0, node_type ()); set_parent (new_root, node_type ()); return new_root; } // See the comment above the declaration. template inline rooted_splay_tree rooted_splay_tree::split_after_root () { node_type new_root = get_child (m_root, 1); set_child (m_root, 1, node_type ()); set_parent (new_root, node_type ()); return new_root; } // See the comment above the declaration. template inline bool rooted_splay_tree::splay_prev_node () { return splay_neighbor<0> (); } // See the comment above the declaration. template inline bool rooted_splay_tree::splay_next_node () { return splay_neighbor<1> (); } // See the comment above the declaration. template inline void rooted_splay_tree::splay_min_node () { if (m_root && get_child (m_root, 0)) { m_root = parent::template splay_limit<0> (m_root); set_parent (m_root, node_type ()); } } // See the comment above the declaration. template inline void rooted_splay_tree::splay_max_node () { if (m_root && get_child (m_root, 1)) { m_root = parent::template splay_limit<1> (m_root); set_parent (m_root, node_type ()); } } // See the comment above the declaration. template inline typename rooted_splay_tree::node_type rooted_splay_tree::min_node () { splay_min_node (); return m_root; } // See the comment above the declaration. template inline typename rooted_splay_tree::node_type rooted_splay_tree::max_node () { splay_max_node (); return m_root; } // See the comment above the declaration. template template auto rooted_splay_tree::lookup (Comparator compare) -> decltype (compare (m_root)) { // This essentially follows the simpilfied top-down method described // in Sleator and Tarjan's "Self-adjusting Binary Search Trees", but // with the complication that the comparisons are done only once. using result_type = decltype (compare (m_root)); // The roots of the left and right trees. node_type link_left_root = node_type (); node_type link_right_root = node_type (); // Where to add new nodes to the left and right trees. node_type *link_left_ptr = &link_left_root; node_type *link_right_ptr = &link_right_root; // The nodes that contain *LINK_LEFT_PTR and *LINK_RIGHT_PTR, // once they no longer point to the roots above. node_type link_left_parent = node_type (); node_type link_right_parent = node_type (); auto link_left = [&](node_type node) { *link_left_ptr = node; link_left_ptr = &Accessors::child (node, 1); set_parent (node, link_left_parent); link_left_parent = node; }; auto link_right = [&](node_type node) { *link_right_ptr = node; link_right_ptr = &Accessors::child (node, 0); set_parent (node, link_right_parent); link_right_parent = node; }; node_type node = m_root; node_type parent = node_type (); result_type result; result_type old_result = 0; while (1) { // OLD_RESULT is 0 if NODE is the root of the middle tree. // Otherwise, PARENT is the root of the middle tree and OLD_RESULT // is how it compared. // // Results are: // < 0 if we want something smaller. // = 0 if we found the right node. // > 0 if we want something bigger. result = compare (node); if (old_result < 0) { if (result < 0) { // SEARCH < NODE < PARENT // // Promote NODE (rotate right). promote_child (parent, 0, node); node_type next = get_child (node, 0); if (!next) break; link_right (node); // NEXT is now the root of the middle tree. node = next; old_result = 0; continue; } // SEARCH >= NODE, NODE < PARENT link_right (parent); } else if (old_result > 0) { if (result > 0) { // SEARCH > NODE > PARENT // // Promote NODE (rotate left). promote_child (parent, 1, node); node_type next = get_child (node, 1); if (!next) break; link_left (node); // NEXT is now the root of the middle tree. node = next; old_result = 0; continue; } // SEARCH <= NODE, NODE > PARENT link_left (parent); } // Microoptimization to allow NODE to be read even if RESULT == 0. node_type next = get_child (node, result >= 0); if (result == 0 || !next) break; // NODE is now the root of the tree. parent = node; node = next; old_result = result; } node_type new_left = link_left_root; node_type new_right = link_right_root; if (new_left) { node_type old_left = get_child (node, 0); *link_left_ptr = old_left; if (old_left) set_parent (old_left, link_left_parent); set_child (node, 0, new_left); } if (new_right) { node_type old_right = get_child (node, 1); *link_right_ptr = old_right; if (old_right) set_parent (old_right, link_right_parent); set_child (node, 1, new_right); } set_parent (node, node_type ()); m_root = node; return result; } // See the comment above the declaration. template template int rooted_splay_tree::lookup (LeftPredicate want_something_smaller, RightPredicate want_something_bigger) { // This essentially follows the simpilfied top-down method described // in Sleator and Tarjan's "Self-adjusting Binary Search Trees" // (and follows it more closely than the single-comparator version above). // The roots of the left and right trees. node_type link_left_root = node_type (); node_type link_right_root = node_type (); // Where to add new nodes to the left and right trees. node_type *link_left_ptr = &link_left_root; node_type *link_right_ptr = &link_right_root; // The nodes that contain *LINK_LEFT_PTR and *LINK_RIGHT_PTR, // once they no longer point to the roots above. node_type link_left_parent = node_type (); node_type link_right_parent = node_type (); node_type node = m_root; int result; for (;;) { // NODE is the root of the middle tree. if (want_something_smaller (node)) { result = -1; node_type next = get_child (node, 0); if (!next) break; if (want_something_smaller (next)) { // Promote NODE (rotate right). promote_child (node, 0, next); node = next; next = get_child (node, 0); if (!next) break; } // Add NODE to the right tree (link right). *link_right_ptr = node; link_right_ptr = &Accessors::child (node, 0); set_parent (node, link_right_parent); link_right_parent = node; node = next; } else if (want_something_bigger (node)) { result = 1; node_type next = get_child (node, 1); if (!next) break; if (want_something_bigger (next)) { // Promote NODE (rotate left). promote_child (node, 1, next); node = next; next = get_child (node, 1); if (!next) break; } // Add NODE to the left tree (link left). *link_left_ptr = node; link_left_ptr = &Accessors::child (node, 1); set_parent (node, link_left_parent); link_left_parent = node; node = next; } else { result = 0; break; } } node_type new_left = link_left_root; node_type new_right = link_right_root; if (new_left) { node_type old_left = get_child (node, 0); *link_left_ptr = old_left; if (old_left) set_parent (old_left, link_left_parent); set_child (node, 0, new_left); } if (new_right) { node_type old_right = get_child (node, 1); *link_right_ptr = old_right; if (old_right) set_parent (old_right, link_right_parent); set_child (node, 1, new_right); } set_parent (node, node_type ()); m_root = node; return result; } // See the comment above the declaration. template template inline void rooted_splay_tree::print (pretty_printer *pp, Printer printer) const { print (pp, m_root, printer); } // Return NODE's current parent. template inline typename rootless_splay_tree::node_type rootless_splay_tree::get_parent (node_type node) { return Accessors::parent (node); } // CHILD is known to be a child of PARENT. Return which index it has. template inline unsigned int rootless_splay_tree::child_index (node_type parent, node_type child) { return get_child (parent, 1) == child; } // If N == 1, implement splay_known_max_node, otherwise implement // splay_known_min_node. template template inline void rootless_splay_tree::splay_known_limit (node_type node) { node_type child = node; node_type parent = get_parent (child); if (!parent) return; do // At this point, NODE conceptually replaces CHILD as a child of // PARENT, but we haven't yet updated PARENT accordingly. if (node_type grandparent = get_parent (parent)) { node_type greatgrandparent = get_parent (grandparent); promote_child (grandparent, N, parent); promote_child (parent, N, node); child = grandparent; parent = greatgrandparent; } else { promote_child (parent, N, node); break; } while (parent); set_parent (node, node_type ()); } // See the comment above the declaration. template typename rootless_splay_tree::node_type rootless_splay_tree::remove_node (node_type node) { node_type replacement = parent::remove_node_internal (node); if (node_type parent = get_parent (node)) set_child (parent, child_index (parent, node), replacement); else if (replacement) set_parent (replacement, node_type ()); // Clear the links from NODE. set_parent (node, node_type ()); set_child (node, 0, node_type ()); set_child (node, 1, node_type ()); return replacement; } // See the comment above the declaration. template void rootless_splay_tree::splay (node_type node) { node_type child = node; node_type parent = get_parent (child); if (!parent) return; do { // At this point, NODE conceptually replaces CHILD as a child of // PARENT, but we haven't yet updated PARENT accordingly. unsigned int index = child_index (parent, child); if (node_type grandparent = get_parent (parent)) { node_type greatgrandparent = get_parent (grandparent); unsigned int parent_index = child_index (grandparent, parent); if (index == parent_index) { promote_child (grandparent, parent_index, parent); promote_child (parent, index, node); } else { promote_child (parent, index, node); promote_child (grandparent, parent_index, node); } child = grandparent; parent = greatgrandparent; } else { promote_child (parent, index, node); break; } } while (parent); set_parent (node, node_type ()); } // See the comment above the declaration. template inline void rootless_splay_tree::splay_known_min_node (node_type node) { splay_known_limit<0> (node); } // See the comment above the declaration. template inline void rootless_splay_tree::splay_known_max_node (node_type node) { splay_known_limit<1> (node); } // See the comment above the declaration. template template auto rootless_splay_tree:: splay_and_search (node_type node, DefaultResult default_result, Predicate predicate) -> decltype (predicate (node, 0)) { using Result = decltype (predicate (node, 0)); node_type child = node; node_type parent = get_parent (child); if (!parent) return default_result; do { // At this point, NODE conceptually replaces CHILD as a child of // PARENT, but we haven't yet updated PARENT accordingly. unsigned int index = child_index (parent, child); if (Result result = predicate (parent, index)) { set_child (parent, index, node); return result; } if (node_type grandparent = get_parent (parent)) { node_type greatgrandparent = get_parent (grandparent); unsigned int parent_index = child_index (grandparent, parent); if (Result result = predicate (grandparent, parent_index)) { set_child (parent, index, node); return result; } if (index == parent_index) { promote_child (grandparent, parent_index, parent); promote_child (parent, index, node); } else { promote_child (parent, index, node); promote_child (grandparent, parent_index, node); } child = grandparent; parent = greatgrandparent; } else { promote_child (parent, index, node); break; } } while (parent); set_parent (node, node_type ()); return default_result; } // Splay NODE1 looking to see if one of its ancestors is NODE2. If it is, // return -1 if NODE1 comes before NODE2 or 1 if NODE1 comes after NODE2. // Return 0 if NODE2 is not an ancestor of NODE1. template int rootless_splay_tree::compare_nodes_one_way (node_type node1, node_type node2) { auto compare = [&](node_type parent, unsigned int index) -> int { if (parent == node2) return index ? 1 : -1; return 0; }; return splay_and_search (node1, 0, compare); } // See the comment above the declaration. template int rootless_splay_tree::compare_nodes (node_type node1, node_type node2) { if (node1 == node2) return 0; // Splay NODE1 looking for NODE2. int cmp = compare_nodes_one_way (node1, node2); if (cmp) return cmp; // That failed, but NODE1 is now the root of the tree. Splay NODE2 // to see on which side of NODE1 it falls. cmp = compare_nodes_one_way (node2, node1); gcc_checking_assert (cmp); return -cmp; }