From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by sourceware.org (Postfix) with ESMTP id BE9133A1B41B for ; Fri, 13 Nov 2020 08:15:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org BE9133A1B41B Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 7C166142F for ; Fri, 13 Nov 2020 00:15:30 -0800 (PST) Received: from localhost (e121540-lin.manchester.arm.com [10.32.98.126]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id DF77A3F718 for ; Fri, 13 Nov 2020 00:15:29 -0800 (PST) From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@arm.com Subject: [08/23] Add an alternative splay tree implementation References: Date: Fri, 13 Nov 2020 08:15:28 +0000 In-Reply-To: (Richard Sandiford's message of "Fri, 13 Nov 2020 08:10:54 +0000") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Status: No, score=-12.6 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 13 Nov 2020 08:15:36 -0000 We already have two splay tree implementations: the old C one in libiberty and a templated reimplementation of it in typed-splay-tree.h. However, they have some drawbacks: - They hard-code the assumption that nodes should have both a key and a value, which isn't always true. - They use the two-phase method of lookup, and so nodes need to store a temporary back pointer. We can avoid that overhead by using the top-down method (as e.g. the bitmap tree code already does). - The tree node has to own the key and the value. For some use cases it's more convenient to embed the tree links in the value instead. Also, a later patch wants to use splay trees to represent an adaptive total order: the splay tree itself records whether node N1 is less than node N2, and (in the worst case) comparing nodes is a splay operation. This patch therefore adds an alternative implementation. The main features are: - Nodes can optionally point back to their parents. - An Accessors class abstracts accessing child nodes and (where applicable) parent nodes, so that the information can be embedded in larger data structures. - There is no fixed comparison function at the class level. Instead, individual functions that do comparisons take a comparison function argument. - There are two styles of comparison function, optimised for different use cases. (See the comments in the patch for details.) - It's possible to do some operations directly on a given node, without knowing whether it's the root. This includes the comparison use case described above. This of course has its own set of drawbacks. It's really providing splay utility functions rather than a true ADT, and so is more low-level than the existing routines. It's mostly geared for cases in which the client code wants to participate in the splay operations to some extent. gcc/ * Makefile.in (OBJS): Add splay-tree-utils.o. * system.h: Include when INCLUDE_ARRAY is defined. * selftest.h (splay_tree_cc_tests): Declare. * selftest-run-tests.c (selftest::run_tests): Run splay_tree_cc_tests. * splay-tree-utils.h: New file. * splay-tree-utils.tcc: Likewise. * splay-tree-utils.cc: Likewise. --- gcc/Makefile.in | 1 + gcc/selftest-run-tests.c | 1 + gcc/selftest.h | 1 + gcc/splay-tree-utils.cc | 264 +++++++++++ gcc/splay-tree-utils.h | 491 ++++++++++++++++++++ gcc/splay-tree-utils.tcc | 960 +++++++++++++++++++++++++++++++++++++++ gcc/system.h | 3 + 7 files changed, 1721 insertions(+) create mode 100644 gcc/splay-tree-utils.cc create mode 100644 gcc/splay-tree-utils.h create mode 100644 gcc/splay-tree-utils.tcc diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 978a08f7b04..900bf11b0ba 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1540,6 +1540,7 @@ OBJS = \ sparseset.o \ spellcheck.o \ spellcheck-tree.o \ + splay-tree-utils.o \ sreal.o \ stack-ptr-mod.o \ statistics.o \ diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c index 7a89b2df5bd..c0c18ad17ca 100644 --- a/gcc/selftest-run-tests.c +++ b/gcc/selftest-run-tests.c @@ -79,6 +79,7 @@ selftest::run_tests () optinfo_emit_json_cc_tests (); opt_problem_cc_tests (); ordered_hash_map_tests_cc_tests (); + splay_tree_cc_tests (); /* Mid-level data structures. */ input_c_tests (); diff --git a/gcc/selftest.h b/gcc/selftest.h index 963e074b4d2..b6e4345b19f 100644 --- a/gcc/selftest.h +++ b/gcc/selftest.h @@ -256,6 +256,7 @@ extern void selftest_c_tests (); extern void simplify_rtx_c_tests (); extern void spellcheck_c_tests (); extern void spellcheck_tree_c_tests (); +extern void splay_tree_cc_tests (); extern void sreal_c_tests (); extern void store_merging_c_tests (); extern void tree_c_tests (); diff --git a/gcc/splay-tree-utils.cc b/gcc/splay-tree-utils.cc new file mode 100644 index 00000000000..4b2007b8414 --- /dev/null +++ b/gcc/splay-tree-utils.cc @@ -0,0 +1,264 @@ +// Splay tree utilities -*- C++ -*- +// Copyright (C) 2020 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 +// . + +#define INCLUDE_ALGORITHM +#define INCLUDE_ARRAY +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "pretty-print.h" +#include "splay-tree-utils.h" +#include "selftest.h" + +#if CHECKING_P +namespace { +// A simple test node for rootless_splay_tree. +struct rootless_test_node +{ + int data; + rootless_test_node *m_parent; + rootless_test_node *m_children[2]; +}; +} + +namespace selftest { + +// Random input data. +static const size_t MAX_DATA = 32768; +static const int data[] = { + 1379, 14643, 30579, 28160, 31750, 22280, 5502, 4720, 30075, 27595, + 8395, 19410, 518, 19709, 29694, 19865, 25372, 11752, 15485, 21547, + 25153, 25072, 10146, 3341, 15625, 3038, 10189, 19943, 1322, 11762, + 807, 430, 11284, 11841, 23965, 32008, 4547, 8087, 13225, 23054, + 22284, 13756, 2182, 26450, 30482, 32502, 23348, 20265, 29509, 3290, + 10807, 1242, 3212, 32178, 25354, 22032, 30509, 16157, 22432, 1295, + 8348, 23342, 24678, 193, 31016, 10316, 3872, 13521, 19211, 30594, + 12229, 4794, 25083, 16098, 28144, 27896, 4801, 20689, 31450, 15614, + 19597, 13731, 30309, 24846, 11042, 31929, 18306, 28520, 16907, 12488, + 15001, 18487, 3438, 1706, 4829, 20892, 6226, 18204, 15776, 30717, + 19398, 2480, 19434, 2838, 2605, 3994, 22538, 12269, 6486, 1314, + 30301, 9919, 31405, 30847, 25000, 24013, 22196, 30220, 31415, 14630, + 26319, 4880, 21292, 20217, 20078, 14679, 25686, 28675, 13883, 14853, + 2872, 2428, 3636, 14131, 2952, 2133, 4470, 25808, 12576, 31395, + 5938, 28393, 14553, 4494, 14928, 24310, 17394, 17436, 23385, 22792, + 9785, 13118, 22338, 23320, 27059, 17663, 16434, 14954, 16962, 31088, + 22247, 22600, 7980, 1344, 15635, 13611, 32739, 3283, 12924, 17904, + 28216, 7542, 9212, 28308, 18873, 3912, 5473, 4666, 11900, 21420, + 20072, 27662, 16445, 29848, 24444, 31668, 30664, 14287, 13754, 29276, + 21462, 25517, 17632, 8105, 32510, 16677, 11162, 20734, 26873, 5097 +}; + +// Look up VALUE in TREE using the single-comparator lookup function. +static int +lookup1 (splay_tree &tree, int value) +{ + auto compare = [&](splay_tree_node *node) + { + return value - node->value (); + }; + return tree.lookup (compare); +} + +// Look up VALUE in TREE using the double-comparator lookup function. +static int +lookup2 (splay_tree &tree, int value) +{ + auto want_something_smaller = [&](splay_tree_node *node) + { + return value < node->value (); + }; + auto want_something_bigger = [&](splay_tree_node *node) + { + return value > node->value (); + }; + return tree.lookup (want_something_smaller, want_something_bigger); +} + +// Test printing TREE to a pretty printer. Don't check the output against +// anything; just make sure that it doesn't crash. +static void +test_print (splay_tree &tree) +{ + auto print_node = [](pretty_printer *pp, splay_tree_node *node) + { + pp_decimal_int (pp, node->value ()); + }; + pretty_printer pp; + tree.print (&pp, print_node); +} + +// Test various lookups on TREE using LOOKUP, where lookup returns the +// same kind of value as the rooted_splay_tree lookup functions. +static void +test_lookup (splay_tree &tree, int (*lookup) (splay_tree &, int)) +{ + // Look up values that are known to exist. + for (int value : data) + ASSERT_EQ (lookup (tree, value), 0); + + // Look up values that are 1 less than values that are known to exist. + for (int value : data) + { + int result = lookup (tree, value - 1); + if (result == 0) + ASSERT_EQ (tree->value (), value - 1); + else if (result < 0) + // VALUE - 1 is less than the root. + ASSERT_EQ (tree->value (), value); + else if (result > 0) + { + // VALUE - 1 is greater than the root. + ASSERT_TRUE (tree->value () < value - 1); + if (tree.splay_next_node ()) + ASSERT_EQ (tree->value (), value); + } + } + + // Look up values that are 1 greater than values that are known to exist. + for (int value : data) + { + int result = lookup (tree, value + 1); + if (result == 0) + ASSERT_EQ (tree->value (), value + 1); + else if (result < 0) + { + // VALUE + 1 is less than the root. + ASSERT_TRUE (tree->value () > value + 1); + if (tree.splay_prev_node ()) + ASSERT_EQ (tree->value (), value); + } + else if (result > 0) + // VALUE + 1 is greater than the root. + ASSERT_EQ (tree->value (), value); + } +} + +// Run all tests for this module. +void +splay_tree_cc_tests () +{ + obstack ob; + gcc_obstack_init (&ob); + + // Build up the splay tree. + splay_tree tree; + for (int value : data) + { + auto *node = XOBNEW (&ob, splay_tree_node); + new (node) splay_tree_node (value); + auto compare = [&](splay_tree_node *other_node) + { + return value - other_node->value (); + }; + bool inserted = tree.insert (node, compare); + ASSERT_TRUE (inserted); + } + + // Test the single-comparator lookup function. + test_lookup (tree, lookup1); + + // Sort the input data. + std::array sorted; + std::copy (data, data + ARRAY_SIZE (data), sorted.begin ()); + std::sort (sorted.begin (), sorted.end ()); + + // Iterate over the tree in ascending order. + tree.splay_min_node (); + bool result = true; + for (int value : sorted) + { + ASSERT_TRUE (result); + ASSERT_EQ (tree->value (), value); + result = tree.splay_next_node (); + } + ASSERT_FALSE (result); + ASSERT_EQ (tree.min_node ()->value (), sorted.front ()); + + // Test the double-comparator lookup function. + test_lookup (tree, lookup2); + + // Test printing the tree now, while it's still bushy. + test_print (tree); + + // Iterate over the tree in descending order. + tree.splay_max_node (); + result = true; + for (auto it = sorted.rbegin (); it != sorted.rend (); ++it) + { + ASSERT_TRUE (result); + ASSERT_EQ (tree->value (), *it); + result = tree.splay_prev_node (); + } + ASSERT_FALSE (result); + ASSERT_EQ (tree.max_node ()->value (), sorted.back ()); + + // Try splitting the tree into three. + int mid_min = sorted[sorted.size () / 3]; + int mid_max = sorted[sorted.size () * 2 / 3]; + ASSERT_EQ (lookup1 (tree, mid_min), 0); + splay_tree left = tree.split_before_root (); + ASSERT_EQ (lookup1 (tree, mid_max), 0); + splay_tree right = tree.split_after_root (); + + // Test removing all the nodes from their respective trees. + for (int value : data) + { + splay_tree &t = (value < mid_min ? left + : value > mid_max ? right : tree); + ASSERT_EQ (lookup1 (t, value), 0); + t.remove_root (); + } + ASSERT_EQ (left.root (), nullptr); + ASSERT_EQ (tree.root (), nullptr); + ASSERT_EQ (right.root (), nullptr); + + using rootless = default_rootless_splay_tree; + + // Build a tree in ascending order with the lowest element as the root. + auto *nodes = XOBNEWVEC (&ob, rootless_test_node *, MAX_DATA); + rootless_test_node *parent = nullptr; + for (int data : sorted) + { + auto *node = XOBNEW (&ob, rootless_test_node); + new (node) rootless_test_node (); + node->data = data; + nodes[data] = node; + if (parent) + rootless::insert_child (parent, 1, node); + parent = node; + } + + // Try comparing nodes to make sure that their order matches the data. + for (size_t i = 1; i < ARRAY_SIZE (data); ++i) + { + int data1 = data[i - 1]; + int data2 = data[i]; + int comparison = rootless::compare_nodes (nodes[data1], nodes[data2]); + if (data1 < data2) + ASSERT_TRUE (comparison < 0); + else if (data1 > data2) + ASSERT_TRUE (comparison > 0); + else + ASSERT_EQ (comparison, 0); + } + + obstack_free (&ob, nullptr); +} +} +#endif // CHECKING_P diff --git a/gcc/splay-tree-utils.h b/gcc/splay-tree-utils.h new file mode 100644 index 00000000000..dfb2a4a0478 --- /dev/null +++ b/gcc/splay-tree-utils.h @@ -0,0 +1,491 @@ +// Splay tree utilities -*- C++ -*- +// Copyright (C) 2020 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 +// . + +// Implement splay tree node accessors for a class that stores its +// two child nodes in a member variable of the form: +// +// Node m_children[2]; +template +class default_splay_tree_accessors +{ +public: + using node_type = Node; + + static auto + child (node_type node, unsigned int index) + -> decltype (node->m_children[index]) & + { + return node->m_children[index]; + } +}; + +// Implement splay tree node accessors for a class that stores its +// two child nodes in a member variable of the form: +// +// Node m_children[2]; +// +// and also stores its parent node in a member variable of the form: +// +// Node m_parent; +template +class default_splay_tree_accessors_with_parent + : public default_splay_tree_accessors +{ +public: + using node_type = Node; + + static auto + parent (node_type node) -> decltype (node->m_parent) & + { + return node->m_parent; + } +}; + +// Base is a splay tree accessor class for nodes that have no parent field. +// Base therefore provides a Base::child method but does not provide a +// Base::parent method. Extend Base with dummy routines for setting the +// parent, which is a no-op when the parent is not stored. +template +class splay_tree_accessors_without_parent : public Base +{ +public: + using typename Base::node_type; + + static void set_parent (node_type, node_type) {} +}; + +// Base is splay tree accessor class for nodes that have a parent field. +// Base therefore provides both Base::child and Base::parent methods. +// Extend Base with routines for setting the parent. +template +class splay_tree_accessors_with_parent : public Base +{ +public: + using typename Base::node_type; + + // Record that NODE's parent is now NEW_PARENT. + static void + set_parent (node_type node, node_type new_parent) + { + Base::parent (node) = new_parent; + } +}; + +// A base class that provides some splay tree operations that are common +// to both rooted_splay_tree and rootless_splay_tree. +// +// Nodes in the splay tree have type Accessors::node_type; this is +// usually a pointer type. The Accessors class provides the following +// static member functions for accessing nodes: +// +// - Accessors::child (NODE, INDEX) +// INDEX is guaranteed to be 0 or 1. If INDEX is 0, return a reference +// to where NODE's left child is stored, otherwise return a reference +// to where NODE's right child is stored. +// +// - Accessors::set_parent (NODE, PARENT) +// Record that NODE's parent node is now PARENT. +template +class base_splay_tree : protected Accessors +{ +public: + using typename Accessors::node_type; + + // INDEX is either 0 or 1. If INDEX is 0, insert CHILD immediately + // before NODE, otherwise insert CHILD immediately after NODE. + // + // Complexity: O(1). + static void insert_child (node_type node, unsigned int index, + node_type child); + + // Print NODE and its child nodes to PP for debugging purposes, + // using PRINTER (PP, N) to print the data for node N. + template + static void print (pretty_printer *pp, node_type node, Printer printer); + +protected: + using Accessors::set_parent; + + static node_type get_child (node_type, unsigned int); + static void set_child (node_type, unsigned int, node_type); + static node_type promote_child (node_type, unsigned int); + static void promote_child (node_type, unsigned int, node_type); + + template + static node_type splay_limit (node_type); + + static node_type remove_node_internal (node_type); + + template + static void print (pretty_printer *pp, node_type node, Printer printer, + char, vec &); +}; + +// This class provides splay tree routines for cases in which the root +// of the splay tree is known. It works with both nodes that store +// their parent node and nodes that don't. +// +// The class is lightweight: it only contains a single root node. +template +class rooted_splay_tree : public base_splay_tree +{ + using parent = base_splay_tree; + +public: + using typename Accessors::node_type; + +protected: + // The root of the splay tree, or node_type () if the tree is empty. + node_type m_root; + +public: + rooted_splay_tree () : m_root () {} + + // Construct a tree with the specified root node. + rooted_splay_tree (node_type root) : m_root (root) {} + + // Return the root of the tree. + node_type root () const { return m_root; } + + // Return true if the tree contains any nodes. + explicit operator bool () const { return m_root; } + + // Dereference the root node. + node_type operator-> () { return m_root; } + + // Insert NEW_NODE into the splay tree, if no equivalent node already + // exists. For a given node N, COMPARE (N) should return: + // + // - a negative value if NEW_NODE should come before N + // - zero if NEW_NODE and N are the same + // - a positive value if NEW_NODE should come after N + // + // Return true if NEW_NODE was inserted. + // + // On return, NEW_NODE or its equivalent is the root of the tree. + // + // Complexity: amortized O(C log N), worst-cast O(C N), where C is + // the complexity of the comparison. + template + bool insert (node_type new_node, Comparator compare); + + // Insert NEW_NODE into the splay tree, given that NEW_NODE is the + // maximum node of the new tree. On return, NEW_NODE is also the + // root of the tree. + // + // Complexity: O(1). + void insert_max_node (node_type new_node); + + // Splice NEXT_TREE onto this one, given that all nodes in NEXT_TREE + // are greater than the maximum node in this tree. NEXT_TREE should + // not be used afterwards. + // + // Complexity: O(1) if the root of the splay tree is already the maximum + // node. Otherwise amortized O(log N), worst-cast O(N). + void splice_next_tree (rooted_splay_tree next_tree); + + // The root of the tree is currently the maximum node. Replace it + // with NEW_NODE. + // + // Complexity: O(1). + void replace_max_node_at_root (node_type new_node); + + // Remove the root node of the splay tree. + // + // Complexity: O(1) if removing the maximum or minimum node. + // Otherwise amortized O(log N), worst-cast O(N). + void remove_root (); + + // Split the left child of the current root out into a separate tree + // and return the new tree. + rooted_splay_tree split_before_root (); + + // Split the right child of the current root out into a separate tree + // and return the new tree. + rooted_splay_tree split_after_root (); + + // If the root is not the minimum node of the splay tree, bring the previous + // node to the root and return true, otherwise return false. + // + // Complexity: amortized O(log N), worst-cast O(N). + bool splay_prev_node (); + + // If the root is not the maximum node of the splay tree, bring the next + // node to the root and return true, otherwise return false. + // + // Complexity: amortized O(log N), worst-cast O(N). + bool splay_next_node (); + + // Bring the minimum node of the splay tree to the root. + // + // Complexity: amortized O(log N), worst-cast O(N). + void splay_min_node (); + + // Bring the maximum node of the splay tree to the root. + // + // Complexity: amortized O(log N), worst-cast O(N). + void splay_max_node (); + + // Return the minimum node of the splay tree, or node_type () if the + // tree is empty. On return, the minimum node (if any) is also the + // root of the tree. + // + // Complexity: amortized O(log N), worst-cast O(N). + node_type min_node (); + + // Return the maximum node of the splay tree, or node_type () if the + // tree is empty. On return, the maximum node (if any) is also the + // root of the tree. + // + // Complexity: amortized O(log N), worst-cast O(N). + node_type max_node (); + + // Search the splay tree. For a given node N, COMPARE (N) should return: + // + // - a negative value if N is bigger than the node being searched for + // - zero if N is the node being searched for + // - a positive value if N is smaller than the node being searched for + // + // If the node that COMPARE is looking for exists, install it as the root + // node of the splay tree. Otherwise, arbitrarily pick either: + // + // - the maximum node that is smaller than the node being searched for or + // - the minimum node that is bigger than the node being searched for + // + // and install that node as the root instead. + // + // Return the result of COMPARE for the new root. + // + // This form of lookup is intended for cases in which both the following + // are true: + // + // (a) The work that COMPARE needs to do to detect if a node is too big + // is the same as the work that COMPARE needs to do to detect if a + // node is too small. (This is not true of range comparisons, + // for example.) + // + // (b) COMPARE is (or might be) relatively complex. + // + // This form of lookup is also useful if the items being compared naturally + // provide a <=>-style comparison result, without the result having to be + // forced by the equivalent of a ?: expression. + // + // The implementation only invokes COMPARE once per node. + // + // Complexity: amortized O(C log N), worst-cast O(C N), where C is + // the complexity of the comparison. + template + auto lookup (Comparator compare) -> decltype (compare (m_root)); + + // Search the splay tree. For a given node N, WANT_SOMETHING_SMALLER (N) + // is true if N is too big and WANT_SOMETHING_BIGGER (N) is true if N + // is too small. Both functions return false if N is the node being + // searched for. + // + // If the node that is being searched for exists, install it as the root + // node of the splay tree and return 0. Otherwise, arbitrarily choose + // between these two options: + // + // - Install the maximum node that is smaller than the node being + // searched for as the root of the splay tree and return 1. + // + // - Install the minimum node that is bigger than the node being + // searched for and return -1. + // + // This form of lookup is intended for cases in which either of the + // following are true: + // + // (a) WANT_SOMETHING_SMALLER and WANT_SOMETHING_BIGGER test different + // parts of the node's data. For example, when comparing ranges, + // WANT_SOMETHING_SMALLER would test the lower limit of the given + // node's range while WANT_SOMETHING_BIGGER would test the upper + // limit of the given node's range. + // + // (b) There is no significant overhead to calling both + // WANT_SOMETHING_SMALLER and WANT_SOMETHING_BIGGER for the same node. + // + // Complexity: amortized O(C log N), worst-cast O(C N), where C is + // the complexity of the comparisons. + template + int lookup (LeftPredicate want_something_smaller, + RightPredicate want_something_bigger); + + // Keep the ability to print subtrees. + using parent::print; + + // Print the tree to PP for debugging purposes, using PRINTER (PP, N) + // to print the data for node N. + template + void print (pretty_printer *pp, Printer printer) const; + +protected: + using parent::get_child; + using parent::set_child; + using parent::promote_child; + + using parent::set_parent; + + template + bool splay_neighbor (); +}; + +// Provide splay tree routines for nodes of type Accessors::node_type, +// which doesn't have a parent field. Use Accessors::child to access +// the children of a node. +template +using splay_tree_without_parent + = rooted_splay_tree>; + +// A splay tree for nodes of type Node, which is usually a pointer type. +// The child nodes are stored in a member variable: +// +// Node m_children[2]; +// +// Node does not have a parent field. +template +using default_splay_tree + = splay_tree_without_parent>; + +// A simple splay tree node that stores a value of type T. +template +class splay_tree_node +{ + friend class default_splay_tree_accessors; + +public: + splay_tree_node () = default; + splay_tree_node (T value) : m_value (value), m_children () {} + + T &value () { return m_value; } + const T &value () const { return m_value; } + +private: + T m_value; + splay_tree_node *m_children[2]; +}; + +// A splay tree whose nodes hold values of type T. +template +using splay_tree = default_splay_tree *>; + +// Provide splay tree routines for cases in which the root of the tree +// is not explicitly stored. +// +// The nodes of the tree have type Accessors::node_type, which is usually +// a pointer type. The nodes have a link back to their parent. +// +// The Accessors class provides the following static member functions: +// +// - Accessors::child (NODE, INDEX) +// INDEX is guaranteed to be 0 or 1. If INDEX is 0, return a reference +// to where NODE's left child is stored, otherwise return a reference +// to where NODE's right child is stored. +// +// - Accessors::parent (NODE) +// Return a reference to where NODE's parent is stored. +template +class rootless_splay_tree + : public base_splay_tree> +{ + using full_accessors = splay_tree_accessors_with_parent; + using parent = base_splay_tree; + +public: + using rooted = rooted_splay_tree; + + using typename Accessors::node_type; + + // Remove NODE from the splay tree. Return the node that replaces it, + // or null if NODE had no children. + // + // Complexity: O(1) if removing the maximum or minimum node. + // Otherwise amortized O(log N), worst-cast O(N). + static node_type remove_node (node_type node); + + // Splay NODE so that it becomes the root of the splay tree. + // + // Complexity: amortized O(log N), worst-cast O(N). + static void splay (node_type node); + + // Like splay, but take advantage of the fact that NODE is known to be + // the minimum node in the tree. + // + // Complexity: amortized O(log N), worst-cast O(N). + static void splay_known_min_node (node_type node); + + // Like splay, but take advantage of the fact that NODE is known to be + // the maximum node in the tree. + // + // Complexity: amortized O(log N), worst-cast O(N). + static void splay_known_max_node (node_type node); + + // Splay NODE while looking for an ancestor node N for which PREDICATE (N) + // is true. If such an ancestor node exists, stop the splay operation + // early and return PREDICATE (N). Otherwise, complete the splay operation + // and return DEFAULT_RESULT. In the latter case, NODE is now the root of + // the splay tree. + // + // Note that this routine only examines nodes that happen to be ancestors + // of NODE. It does not search the full tree. + // + // Complexity: amortized O(P log N), worst-cast O(P N), where P is the + // complexity of the predicate. + template + static auto splay_and_search (node_type node, DefaultResult default_result, + Predicate predicate) + -> decltype (predicate (node, 0)); + + // NODE1 and NODE2 are known to belong to the same splay tree. Return: + // + // -1 if NODE1 < NODE2 + // 0 if NODE1 == NODE2 + // 1 if NODE1 > NODE2 + // + // Complexity: amortized O(log N), worst-cast O(N). + static int compare_nodes (node_type node1, node_type node2); + +protected: + using parent::get_child; + using parent::set_child; + using parent::promote_child; + + static node_type get_parent (node_type); + using parent::set_parent; + + static unsigned int child_index (node_type, node_type); + + static int compare_nodes_one_way (node_type, node_type); + + template + static void splay_known_limit (node_type); +}; + +// Provide rootless splay tree routines for nodes of type Node. +// The child nodes are stored in a member variable: +// +// Node m_children[2]; +// +// and the parent node is stored in a member variable: +// +// Node m_parent; +template +using default_rootless_splay_tree + = rootless_splay_tree>; + +#include "splay-tree-utils.tcc" diff --git a/gcc/splay-tree-utils.tcc b/gcc/splay-tree-utils.tcc new file mode 100644 index 00000000000..5c9c859d0bd --- /dev/null +++ b/gcc/splay-tree-utils.tcc @@ -0,0 +1,960 @@ +// Splay tree utilities -*- C++ -*- +// Copyright (C) 2020 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; +} diff --git a/gcc/system.h b/gcc/system.h index b0f3f1dd019..d4e29e53ee3 100644 --- a/gcc/system.h +++ b/gcc/system.h @@ -232,6 +232,9 @@ extern int errno; #ifdef INCLUDE_VECTOR # include #endif +#ifdef INCLUDE_ARRAY +# include +#endif # include # include # include -- 2.17.1