// Splay tree utilities                                             -*- C++ -*-
// Copyright (C) 2020-2022 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
// <http://www.gnu.org/licenses/>.

// INDEX is either 0 or 1.  If it is 0, return NODE's left child,
// otherwise return NODE's right child.
template<typename Accessors>
inline typename base_splay_tree<Accessors>::node_type
base_splay_tree<Accessors>::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<typename Accessors>
inline void
base_splay_tree<Accessors>::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<typename Accessors>
inline typename base_splay_tree<Accessors>::node_type
base_splay_tree<Accessors>::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<typename Accessors>
inline void
base_splay_tree<Accessors>::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<typename Accessors>
template<typename Printer>
void
base_splay_tree<Accessors>::print (pretty_printer *pp, node_type node,
				   Printer printer, char code,
				   vec<char> &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<typename Accessors>
template<typename Printer>
void
base_splay_tree<Accessors>::print (pretty_printer *pp, node_type node,
				   Printer printer)
{
  if (!node)
    {
      pp_string (pp, "null");
      return;
    }
  auto_vec<char, 64> 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<typename Accessors>
template<unsigned int N>
typename base_splay_tree<Accessors>::node_type
base_splay_tree<Accessors>::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<typename Accessors>
inline typename base_splay_tree<Accessors>::node_type
base_splay_tree<Accessors>::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<typename Accessors>
inline void
base_splay_tree<Accessors>::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<typename Accessors>
template<unsigned int N>
bool
rooted_splay_tree<Accessors>::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<typename Accessors>
template<typename Comparator>
bool
rooted_splay_tree<Accessors>::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<typename Accessors>
inline void
rooted_splay_tree<Accessors>::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<typename Accessors>
inline void
rooted_splay_tree<Accessors>::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<typename Accessors>
inline void
rooted_splay_tree<Accessors>::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<typename Accessors>
inline void
rooted_splay_tree<Accessors>::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<typename Accessors>
inline rooted_splay_tree<Accessors>
rooted_splay_tree<Accessors>::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<typename Accessors>
inline rooted_splay_tree<Accessors>
rooted_splay_tree<Accessors>::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<typename Accessors>
inline bool
rooted_splay_tree<Accessors>::splay_prev_node ()
{
  return splay_neighbor<0> ();
}

// See the comment above the declaration.
template<typename Accessors>
inline bool
rooted_splay_tree<Accessors>::splay_next_node ()
{
  return splay_neighbor<1> ();
}

// See the comment above the declaration.
template<typename Accessors>
inline void
rooted_splay_tree<Accessors>::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<typename Accessors>
inline void
rooted_splay_tree<Accessors>::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<typename Accessors>
inline typename rooted_splay_tree<Accessors>::node_type
rooted_splay_tree<Accessors>::min_node ()
{
  splay_min_node ();
  return m_root;
}

// See the comment above the declaration.
template<typename Accessors>
inline typename rooted_splay_tree<Accessors>::node_type
rooted_splay_tree<Accessors>::max_node ()
{
  splay_max_node ();
  return m_root;
}

// See the comment above the declaration.
template<typename Accessors>
template<typename Comparator>
auto
rooted_splay_tree<Accessors>::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<typename Accessors>
template<typename LeftPredicate, typename RightPredicate>
int
rooted_splay_tree<Accessors>::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<typename Accessors>
template<typename Printer>
inline void
rooted_splay_tree<Accessors>::print (pretty_printer *pp, Printer printer) const
{
  print (pp, m_root, printer);
}

// Return NODE's current parent.
template<typename Accessors>
inline typename rootless_splay_tree<Accessors>::node_type
rootless_splay_tree<Accessors>::get_parent (node_type node)
{
  return Accessors::parent (node);
}

// CHILD is known to be a child of PARENT.  Return which index it has.
template<typename Accessors>
inline unsigned int
rootless_splay_tree<Accessors>::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<typename Accessors>
template<unsigned int N>
inline void
rootless_splay_tree<Accessors>::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 Accessors>
typename rootless_splay_tree<Accessors>::node_type
rootless_splay_tree<Accessors>::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<typename Accessors>
void
rootless_splay_tree<Accessors>::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<typename Accessors>
inline void
rootless_splay_tree<Accessors>::splay_known_min_node (node_type node)
{
  splay_known_limit<0> (node);
}

// See the comment above the declaration.
template<typename Accessors>
inline void
rootless_splay_tree<Accessors>::splay_known_max_node (node_type node)
{
  splay_known_limit<1> (node);
}

// See the comment above the declaration.
template<typename Accessors>
template<typename DefaultResult, typename Predicate>
auto
rootless_splay_tree<Accessors>::
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<typename Accessors>
int
rootless_splay_tree<Accessors>::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<typename Accessors>
int
rootless_splay_tree<Accessors>::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;
}