Blame intl/tsearch.c

Packit Service a721b1
/* Copyright (C) 1995, 1996, 1997, 2000, 2006 Free Software Foundation, Inc.
Packit Service a721b1
   Contributed by Bernd Schmidt <crux@Pool.Informatik.RWTH-Aachen.DE>, 1997.
Packit Service a721b1
Packit Service a721b1
   NOTE: The canonical source of this file is maintained with the GNU C
Packit Service a721b1
   Library.  Bugs can be reported to bug-glibc@gnu.org.
Packit Service a721b1
Packit Service a721b1
   This program is free software; you can redistribute it and/or modify it
Packit Service a721b1
   under the terms of the GNU Library General Public License as published
Packit Service a721b1
   by the Free Software Foundation; either version 2, or (at your option)
Packit Service a721b1
   any later version.
Packit Service a721b1
Packit Service a721b1
   This program is distributed in the hope that it will be useful,
Packit Service a721b1
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a721b1
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service a721b1
   Library General Public License for more details.
Packit Service a721b1
Packit Service a721b1
   You should have received a copy of the GNU Library General Public
Packit Service a721b1
   License along with this program; if not, write to the Free Software
Packit Service a721b1
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
Packit Service a721b1
   USA.  */
Packit Service a721b1
Packit Service a721b1
/* Tree search for red/black trees.
Packit Service a721b1
   The algorithm for adding nodes is taken from one of the many "Algorithms"
Packit Service a721b1
   books by Robert Sedgewick, although the implementation differs.
Packit Service a721b1
   The algorithm for deleting nodes can probably be found in a book named
Packit Service a721b1
   "Introduction to Algorithms" by Cormen/Leiserson/Rivest.  At least that's
Packit Service a721b1
   the book that my professor took most algorithms from during the "Data
Packit Service a721b1
   Structures" course...
Packit Service a721b1
Packit Service a721b1
   Totally public domain.  */
Packit Service a721b1
Packit Service a721b1
/* Red/black trees are binary trees in which the edges are colored either red
Packit Service a721b1
   or black.  They have the following properties:
Packit Service a721b1
   1. The number of black edges on every path from the root to a leaf is
Packit Service a721b1
      constant.
Packit Service a721b1
   2. No two red edges are adjacent.
Packit Service a721b1
   Therefore there is an upper bound on the length of every path, it's
Packit Service a721b1
   O(log n) where n is the number of nodes in the tree.  No path can be longer
Packit Service a721b1
   than 1+2*P where P is the length of the shortest path in the tree.
Packit Service a721b1
   Useful for the implementation:
Packit Service a721b1
   3. If one of the children of a node is NULL, then the other one is red
Packit Service a721b1
      (if it exists).
Packit Service a721b1
Packit Service a721b1
   In the implementation, not the edges are colored, but the nodes.  The color
Packit Service a721b1
   interpreted as the color of the edge leading to this node.  The color is
Packit Service a721b1
   meaningless for the root node, but we color the root node black for
Packit Service a721b1
   convenience.  All added nodes are red initially.
Packit Service a721b1
Packit Service a721b1
   Adding to a red/black tree is rather easy.  The right place is searched
Packit Service a721b1
   with a usual binary tree search.  Additionally, whenever a node N is
Packit Service a721b1
   reached that has two red successors, the successors are colored black and
Packit Service a721b1
   the node itself colored red.  This moves red edges up the tree where they
Packit Service a721b1
   pose less of a problem once we get to really insert the new node.  Changing
Packit Service a721b1
   N's color to red may violate rule 2, however, so rotations may become
Packit Service a721b1
   necessary to restore the invariants.  Adding a new red leaf may violate
Packit Service a721b1
   the same rule, so afterwards an additional check is run and the tree
Packit Service a721b1
   possibly rotated.
Packit Service a721b1
Packit Service a721b1
   Deleting is hairy.  There are mainly two nodes involved: the node to be
Packit Service a721b1
   deleted (n1), and another node that is to be unchained from the tree (n2).
Packit Service a721b1
   If n1 has a successor (the node with a smallest key that is larger than
Packit Service a721b1
   n1), then the successor becomes n2 and its contents are copied into n1,
Packit Service a721b1
   otherwise n1 becomes n2.
Packit Service a721b1
   Unchaining a node may violate rule 1: if n2 is black, one subtree is
Packit Service a721b1
   missing one black edge afterwards.  The algorithm must try to move this
Packit Service a721b1
   error upwards towards the root, so that the subtree that does not have
Packit Service a721b1
   enough black edges becomes the whole tree.  Once that happens, the error
Packit Service a721b1
   has disappeared.  It may not be necessary to go all the way up, since it
Packit Service a721b1
   is possible that rotations and recoloring can fix the error before that.
Packit Service a721b1
Packit Service a721b1
   Although the deletion algorithm must walk upwards through the tree, we
Packit Service a721b1
   do not store parent pointers in the nodes.  Instead, delete allocates a
Packit Service a721b1
   small array of parent pointers and fills it while descending the tree.
Packit Service a721b1
   Since we know that the length of a path is O(log n), where n is the number
Packit Service a721b1
   of nodes, this is likely to use less memory.  */
Packit Service a721b1
Packit Service a721b1
/* Tree rotations look like this:
Packit Service a721b1
      A                C
Packit Service a721b1
     / \              / \
Packit Service a721b1
    B   C            A   G
Packit Service a721b1
   / \ / \  -->     / \
Packit Service a721b1
   D E F G         B   F
Packit Service a721b1
                  / \
Packit Service a721b1
                 D   E
Packit Service a721b1
Packit Service a721b1
   In this case, A has been rotated left.  This preserves the ordering of the
Packit Service a721b1
   binary tree.  */
Packit Service a721b1
Packit Service a721b1
#include <config.h>
Packit Service a721b1
Packit Service a721b1
/* Specification.  */
Packit Service a721b1
#ifdef IN_LIBINTL
Packit Service a721b1
# include "tsearch.h"
Packit Service a721b1
#else
Packit Service a721b1
# include <search.h>
Packit Service a721b1
#endif
Packit Service a721b1
Packit Service a721b1
#include <stdlib.h>
Packit Service a721b1
Packit Service a721b1
typedef int (*__compar_fn_t) (const void *, const void *);
Packit Service a721b1
typedef void (*__action_fn_t) (const void *, VISIT, int);
Packit Service a721b1
Packit Service a721b1
#ifndef weak_alias
Packit Service a721b1
# define __tsearch tsearch
Packit Service a721b1
# define __tfind tfind
Packit Service a721b1
# define __tdelete tdelete
Packit Service a721b1
# define __twalk twalk
Packit Service a721b1
#endif
Packit Service a721b1
Packit Service a721b1
#ifndef internal_function
Packit Service a721b1
/* Inside GNU libc we mark some function in a special way.  In other
Packit Service a721b1
   environments simply ignore the marking.  */
Packit Service a721b1
# define internal_function
Packit Service a721b1
#endif
Packit Service a721b1
Packit Service a721b1
typedef struct node_t
Packit Service a721b1
{
Packit Service a721b1
  /* Callers expect this to be the first element in the structure - do not
Packit Service a721b1
     move!  */
Packit Service a721b1
  const void *key;
Packit Service a721b1
  struct node_t *left;
Packit Service a721b1
  struct node_t *right;
Packit Service a721b1
  unsigned int red:1;
Packit Service a721b1
} *node;
Packit Service a721b1
typedef const struct node_t *const_node;
Packit Service a721b1
Packit Service a721b1
#undef DEBUGGING
Packit Service a721b1
Packit Service a721b1
#ifdef DEBUGGING
Packit Service a721b1
Packit Service a721b1
/* Routines to check tree invariants.  */
Packit Service a721b1
Packit Service a721b1
#include <assert.h>
Packit Service a721b1
Packit Service a721b1
#define CHECK_TREE(a) check_tree(a)
Packit Service a721b1
Packit Service a721b1
static void
Packit Service a721b1
check_tree_recurse (node p, int d_sofar, int d_total)
Packit Service a721b1
{
Packit Service a721b1
  if (p == NULL)
Packit Service a721b1
    {
Packit Service a721b1
      assert (d_sofar == d_total);
Packit Service a721b1
      return;
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  check_tree_recurse (p->left, d_sofar + (p->left && !p->left->red), d_total);
Packit Service a721b1
  check_tree_recurse (p->right, d_sofar + (p->right && !p->right->red), d_total);
Packit Service a721b1
  if (p->left)
Packit Service a721b1
    assert (!(p->left->red && p->red));
Packit Service a721b1
  if (p->right)
Packit Service a721b1
    assert (!(p->right->red && p->red));
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
static void
Packit Service a721b1
check_tree (node root)
Packit Service a721b1
{
Packit Service a721b1
  int cnt = 0;
Packit Service a721b1
  node p;
Packit Service a721b1
  if (root == NULL)
Packit Service a721b1
    return;
Packit Service a721b1
  root->red = 0;
Packit Service a721b1
  for(p = root->left; p; p = p->left)
Packit Service a721b1
    cnt += !p->red;
Packit Service a721b1
  check_tree_recurse (root, 0, cnt);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
#else
Packit Service a721b1
Packit Service a721b1
#define CHECK_TREE(a)
Packit Service a721b1
Packit Service a721b1
#endif
Packit Service a721b1
Packit Service a721b1
/* Possibly "split" a node with two red successors, and/or fix up two red
Packit Service a721b1
   edges in a row.  ROOTP is a pointer to the lowest node we visited, PARENTP
Packit Service a721b1
   and GPARENTP pointers to its parent/grandparent.  P_R and GP_R contain the
Packit Service a721b1
   comparison values that determined which way was taken in the tree to reach
Packit Service a721b1
   ROOTP.  MODE is 1 if we need not do the split, but must check for two red
Packit Service a721b1
   edges between GPARENTP and ROOTP.  */
Packit Service a721b1
static void
Packit Service a721b1
maybe_split_for_insert (node *rootp, node *parentp, node *gparentp,
Packit Service a721b1
			int p_r, int gp_r, int mode)
Packit Service a721b1
{
Packit Service a721b1
  node root = *rootp;
Packit Service a721b1
  node *rp, *lp;
Packit Service a721b1
  rp = &(*rootp)->right;
Packit Service a721b1
  lp = &(*rootp)->left;
Packit Service a721b1
Packit Service a721b1
  /* See if we have to split this node (both successors red).  */
Packit Service a721b1
  if (mode == 1
Packit Service a721b1
      || ((*rp) != NULL && (*lp) != NULL && (*rp)->red && (*lp)->red))
Packit Service a721b1
    {
Packit Service a721b1
      /* This node becomes red, its successors black.  */
Packit Service a721b1
      root->red = 1;
Packit Service a721b1
      if (*rp)
Packit Service a721b1
	(*rp)->red = 0;
Packit Service a721b1
      if (*lp)
Packit Service a721b1
	(*lp)->red = 0;
Packit Service a721b1
Packit Service a721b1
      /* If the parent of this node is also red, we have to do
Packit Service a721b1
	 rotations.  */
Packit Service a721b1
      if (parentp != NULL && (*parentp)->red)
Packit Service a721b1
	{
Packit Service a721b1
	  node gp = *gparentp;
Packit Service a721b1
	  node p = *parentp;
Packit Service a721b1
	  /* There are two main cases:
Packit Service a721b1
	     1. The edge types (left or right) of the two red edges differ.
Packit Service a721b1
	     2. Both red edges are of the same type.
Packit Service a721b1
	     There exist two symmetries of each case, so there is a total of
Packit Service a721b1
	     4 cases.  */
Packit Service a721b1
	  if ((p_r > 0) != (gp_r > 0))
Packit Service a721b1
	    {
Packit Service a721b1
	      /* Put the child at the top of the tree, with its parent
Packit Service a721b1
		 and grandparent as successors.  */
Packit Service a721b1
	      p->red = 1;
Packit Service a721b1
	      gp->red = 1;
Packit Service a721b1
	      root->red = 0;
Packit Service a721b1
	      if (p_r < 0)
Packit Service a721b1
		{
Packit Service a721b1
		  /* Child is left of parent.  */
Packit Service a721b1
		  p->left = *rp;
Packit Service a721b1
		  *rp = p;
Packit Service a721b1
		  gp->right = *lp;
Packit Service a721b1
		  *lp = gp;
Packit Service a721b1
		}
Packit Service a721b1
	      else
Packit Service a721b1
		{
Packit Service a721b1
		  /* Child is right of parent.  */
Packit Service a721b1
		  p->right = *lp;
Packit Service a721b1
		  *lp = p;
Packit Service a721b1
		  gp->left = *rp;
Packit Service a721b1
		  *rp = gp;
Packit Service a721b1
		}
Packit Service a721b1
	      *gparentp = root;
Packit Service a721b1
	    }
Packit Service a721b1
	  else
Packit Service a721b1
	    {
Packit Service a721b1
	      *gparentp = *parentp;
Packit Service a721b1
	      /* Parent becomes the top of the tree, grandparent and
Packit Service a721b1
		 child are its successors.  */
Packit Service a721b1
	      p->red = 0;
Packit Service a721b1
	      gp->red = 1;
Packit Service a721b1
	      if (p_r < 0)
Packit Service a721b1
		{
Packit Service a721b1
		  /* Left edges.  */
Packit Service a721b1
		  gp->left = p->right;
Packit Service a721b1
		  p->right = gp;
Packit Service a721b1
		}
Packit Service a721b1
	      else
Packit Service a721b1
		{
Packit Service a721b1
		  /* Right edges.  */
Packit Service a721b1
		  gp->right = p->left;
Packit Service a721b1
		  p->left = gp;
Packit Service a721b1
		}
Packit Service a721b1
	    }
Packit Service a721b1
	}
Packit Service a721b1
    }
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/* Find or insert datum into search tree.
Packit Service a721b1
   KEY is the key to be located, ROOTP is the address of tree root,
Packit Service a721b1
   COMPAR the ordering function.  */
Packit Service a721b1
void *
Packit Service a721b1
__tsearch (const void *key, void **vrootp, __compar_fn_t compar)
Packit Service a721b1
{
Packit Service a721b1
  node q;
Packit Service a721b1
  node *parentp = NULL, *gparentp = NULL;
Packit Service a721b1
  node *rootp = (node *) vrootp;
Packit Service a721b1
  node *nextp;
Packit Service a721b1
  int r = 0, p_r = 0, gp_r = 0; /* No they might not, Mr Compiler.  */
Packit Service a721b1
Packit Service a721b1
  if (rootp == NULL)
Packit Service a721b1
    return NULL;
Packit Service a721b1
Packit Service a721b1
  /* This saves some additional tests below.  */
Packit Service a721b1
  if (*rootp != NULL)
Packit Service a721b1
    (*rootp)->red = 0;
Packit Service a721b1
Packit Service a721b1
  CHECK_TREE (*rootp);
Packit Service a721b1
Packit Service a721b1
  nextp = rootp;
Packit Service a721b1
  while (*nextp != NULL)
Packit Service a721b1
    {
Packit Service a721b1
      node root = *rootp;
Packit Service a721b1
      r = (*compar) (key, root->key);
Packit Service a721b1
      if (r == 0)
Packit Service a721b1
	return root;
Packit Service a721b1
Packit Service a721b1
      maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0);
Packit Service a721b1
      /* If that did any rotations, parentp and gparentp are now garbage.
Packit Service a721b1
	 That doesn't matter, because the values they contain are never
Packit Service a721b1
	 used again in that case.  */
Packit Service a721b1
Packit Service a721b1
      nextp = r < 0 ? &root->left : &root->right;
Packit Service a721b1
      if (*nextp == NULL)
Packit Service a721b1
	break;
Packit Service a721b1
Packit Service a721b1
      gparentp = parentp;
Packit Service a721b1
      parentp = rootp;
Packit Service a721b1
      rootp = nextp;
Packit Service a721b1
Packit Service a721b1
      gp_r = p_r;
Packit Service a721b1
      p_r = r;
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  q = (struct node_t *) malloc (sizeof (struct node_t));
Packit Service a721b1
  if (q != NULL)
Packit Service a721b1
    {
Packit Service a721b1
      *nextp = q;			/* link new node to old */
Packit Service a721b1
      q->key = key;			/* initialize new node */
Packit Service a721b1
      q->red = 1;
Packit Service a721b1
      q->left = q->right = NULL;
Packit Service a721b1
Packit Service a721b1
      if (nextp != rootp)
Packit Service a721b1
	/* There may be two red edges in a row now, which we must avoid by
Packit Service a721b1
	   rotating the tree.  */
Packit Service a721b1
	maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1);
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  return q;
Packit Service a721b1
}
Packit Service a721b1
#ifdef weak_alias
Packit Service a721b1
weak_alias (__tsearch, tsearch)
Packit Service a721b1
#endif
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/* Find datum in search tree.
Packit Service a721b1
   KEY is the key to be located, ROOTP is the address of tree root,
Packit Service a721b1
   COMPAR the ordering function.  */
Packit Service a721b1
void *
Packit Service a721b1
__tfind (key, vrootp, compar)
Packit Service a721b1
     const void *key;
Packit Service a721b1
     void *const *vrootp;
Packit Service a721b1
     __compar_fn_t compar;
Packit Service a721b1
{
Packit Service a721b1
  node *rootp = (node *) vrootp;
Packit Service a721b1
Packit Service a721b1
  if (rootp == NULL)
Packit Service a721b1
    return NULL;
Packit Service a721b1
Packit Service a721b1
  CHECK_TREE (*rootp);
Packit Service a721b1
Packit Service a721b1
  while (*rootp != NULL)
Packit Service a721b1
    {
Packit Service a721b1
      node root = *rootp;
Packit Service a721b1
      int r;
Packit Service a721b1
Packit Service a721b1
      r = (*compar) (key, root->key);
Packit Service a721b1
      if (r == 0)
Packit Service a721b1
	return root;
Packit Service a721b1
Packit Service a721b1
      rootp = r < 0 ? &root->left : &root->right;
Packit Service a721b1
    }
Packit Service a721b1
  return NULL;
Packit Service a721b1
}
Packit Service a721b1
#ifdef weak_alias
Packit Service a721b1
weak_alias (__tfind, tfind)
Packit Service a721b1
#endif
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/* Delete node with given key.
Packit Service a721b1
   KEY is the key to be deleted, ROOTP is the address of the root of tree,
Packit Service a721b1
   COMPAR the comparison function.  */
Packit Service a721b1
void *
Packit Service a721b1
__tdelete (const void *key, void **vrootp, __compar_fn_t compar)
Packit Service a721b1
{
Packit Service a721b1
  node p, q, r, retval;
Packit Service a721b1
  int cmp;
Packit Service a721b1
  node *rootp = (node *) vrootp;
Packit Service a721b1
  node root, unchained;
Packit Service a721b1
  /* Stack of nodes so we remember the parents without recursion.  It's
Packit Service a721b1
     _very_ unlikely that there are paths longer than 40 nodes.  The tree
Packit Service a721b1
     would need to have around 250.000 nodes.  */
Packit Service a721b1
  int stacksize = 100;
Packit Service a721b1
  int sp = 0;
Packit Service a721b1
  node *nodestack[100];
Packit Service a721b1
Packit Service a721b1
  if (rootp == NULL)
Packit Service a721b1
    return NULL;
Packit Service a721b1
  p = *rootp;
Packit Service a721b1
  if (p == NULL)
Packit Service a721b1
    return NULL;
Packit Service a721b1
Packit Service a721b1
  CHECK_TREE (p);
Packit Service a721b1
Packit Service a721b1
  while ((cmp = (*compar) (key, (*rootp)->key)) != 0)
Packit Service a721b1
    {
Packit Service a721b1
      if (sp == stacksize)
Packit Service a721b1
	abort ();
Packit Service a721b1
Packit Service a721b1
      nodestack[sp++] = rootp;
Packit Service a721b1
      p = *rootp;
Packit Service a721b1
      rootp = ((cmp < 0)
Packit Service a721b1
	       ? &(*rootp)->left
Packit Service a721b1
	       : &(*rootp)->right);
Packit Service a721b1
      if (*rootp == NULL)
Packit Service a721b1
	return NULL;
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  /* This is bogus if the node to be deleted is the root... this routine
Packit Service a721b1
     really should return an integer with 0 for success, -1 for failure
Packit Service a721b1
     and errno = ESRCH or something.  */
Packit Service a721b1
  retval = p;
Packit Service a721b1
Packit Service a721b1
  /* We don't unchain the node we want to delete. Instead, we overwrite
Packit Service a721b1
     it with its successor and unchain the successor.  If there is no
Packit Service a721b1
     successor, we really unchain the node to be deleted.  */
Packit Service a721b1
Packit Service a721b1
  root = *rootp;
Packit Service a721b1
Packit Service a721b1
  r = root->right;
Packit Service a721b1
  q = root->left;
Packit Service a721b1
Packit Service a721b1
  if (q == NULL || r == NULL)
Packit Service a721b1
    unchained = root;
Packit Service a721b1
  else
Packit Service a721b1
    {
Packit Service a721b1
      node *parent = rootp, *up = &root->right;
Packit Service a721b1
      for (;;)
Packit Service a721b1
	{
Packit Service a721b1
	  if (sp == stacksize)
Packit Service a721b1
	    abort ();
Packit Service a721b1
	  nodestack[sp++] = parent;
Packit Service a721b1
	  parent = up;
Packit Service a721b1
	  if ((*up)->left == NULL)
Packit Service a721b1
	    break;
Packit Service a721b1
	  up = &(*up)->left;
Packit Service a721b1
	}
Packit Service a721b1
      unchained = *up;
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  /* We know that either the left or right successor of UNCHAINED is NULL.
Packit Service a721b1
     R becomes the other one, it is chained into the parent of UNCHAINED.  */
Packit Service a721b1
  r = unchained->left;
Packit Service a721b1
  if (r == NULL)
Packit Service a721b1
    r = unchained->right;
Packit Service a721b1
  if (sp == 0)
Packit Service a721b1
    *rootp = r;
Packit Service a721b1
  else
Packit Service a721b1
    {
Packit Service a721b1
      q = *nodestack[sp-1];
Packit Service a721b1
      if (unchained == q->right)
Packit Service a721b1
	q->right = r;
Packit Service a721b1
      else
Packit Service a721b1
	q->left = r;
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  if (unchained != root)
Packit Service a721b1
    root->key = unchained->key;
Packit Service a721b1
  if (!unchained->red)
Packit Service a721b1
    {
Packit Service a721b1
      /* Now we lost a black edge, which means that the number of black
Packit Service a721b1
	 edges on every path is no longer constant.  We must balance the
Packit Service a721b1
	 tree.  */
Packit Service a721b1
      /* NODESTACK now contains all parents of R.  R is likely to be NULL
Packit Service a721b1
	 in the first iteration.  */
Packit Service a721b1
      /* NULL nodes are considered black throughout - this is necessary for
Packit Service a721b1
	 correctness.  */
Packit Service a721b1
      while (sp > 0 && (r == NULL || !r->red))
Packit Service a721b1
	{
Packit Service a721b1
	  node *pp = nodestack[sp - 1];
Packit Service a721b1
	  p = *pp;
Packit Service a721b1
	  /* Two symmetric cases.  */
Packit Service a721b1
	  if (r == p->left)
Packit Service a721b1
	    {
Packit Service a721b1
	      /* Q is R's brother, P is R's parent.  The subtree with root
Packit Service a721b1
		 R has one black edge less than the subtree with root Q.  */
Packit Service a721b1
	      q = p->right;
Packit Service a721b1
	      if (q->red)
Packit Service a721b1
		{
Packit Service a721b1
		  /* If Q is red, we know that P is black. We rotate P left
Packit Service a721b1
		     so that Q becomes the top node in the tree, with P below
Packit Service a721b1
		     it.  P is colored red, Q is colored black.
Packit Service a721b1
		     This action does not change the black edge count for any
Packit Service a721b1
		     leaf in the tree, but we will be able to recognize one
Packit Service a721b1
		     of the following situations, which all require that Q
Packit Service a721b1
		     is black.  */
Packit Service a721b1
		  q->red = 0;
Packit Service a721b1
		  p->red = 1;
Packit Service a721b1
		  /* Left rotate p.  */
Packit Service a721b1
		  p->right = q->left;
Packit Service a721b1
		  q->left = p;
Packit Service a721b1
		  *pp = q;
Packit Service a721b1
		  /* Make sure pp is right if the case below tries to use
Packit Service a721b1
		     it.  */
Packit Service a721b1
		  nodestack[sp++] = pp = &q->left;
Packit Service a721b1
		  q = p->right;
Packit Service a721b1
		}
Packit Service a721b1
	      /* We know that Q can't be NULL here.  We also know that Q is
Packit Service a721b1
		 black.  */
Packit Service a721b1
	      if ((q->left == NULL || !q->left->red)
Packit Service a721b1
		  && (q->right == NULL || !q->right->red))
Packit Service a721b1
		{
Packit Service a721b1
		  /* Q has two black successors.  We can simply color Q red.
Packit Service a721b1
		     The whole subtree with root P is now missing one black
Packit Service a721b1
		     edge.  Note that this action can temporarily make the
Packit Service a721b1
		     tree invalid (if P is red).  But we will exit the loop
Packit Service a721b1
		     in that case and set P black, which both makes the tree
Packit Service a721b1
		     valid and also makes the black edge count come out
Packit Service a721b1
		     right.  If P is black, we are at least one step closer
Packit Service a721b1
		     to the root and we'll try again the next iteration.  */
Packit Service a721b1
		  q->red = 1;
Packit Service a721b1
		  r = p;
Packit Service a721b1
		}
Packit Service a721b1
	      else
Packit Service a721b1
		{
Packit Service a721b1
		  /* Q is black, one of Q's successors is red.  We can
Packit Service a721b1
		     repair the tree with one operation and will exit the
Packit Service a721b1
		     loop afterwards.  */
Packit Service a721b1
		  if (q->right == NULL || !q->right->red)
Packit Service a721b1
		    {
Packit Service a721b1
		      /* The left one is red.  We perform the same action as
Packit Service a721b1
			 in maybe_split_for_insert where two red edges are
Packit Service a721b1
			 adjacent but point in different directions:
Packit Service a721b1
			 Q's left successor (let's call it Q2) becomes the
Packit Service a721b1
			 top of the subtree we are looking at, its parent (Q)
Packit Service a721b1
			 and grandparent (P) become its successors. The former
Packit Service a721b1
			 successors of Q2 are placed below P and Q.
Packit Service a721b1
			 P becomes black, and Q2 gets the color that P had.
Packit Service a721b1
			 This changes the black edge count only for node R and
Packit Service a721b1
			 its successors.  */
Packit Service a721b1
		      node q2 = q->left;
Packit Service a721b1
		      q2->red = p->red;
Packit Service a721b1
		      p->right = q2->left;
Packit Service a721b1
		      q->left = q2->right;
Packit Service a721b1
		      q2->right = q;
Packit Service a721b1
		      q2->left = p;
Packit Service a721b1
		      *pp = q2;
Packit Service a721b1
		      p->red = 0;
Packit Service a721b1
		    }
Packit Service a721b1
		  else
Packit Service a721b1
		    {
Packit Service a721b1
		      /* It's the right one.  Rotate P left. P becomes black,
Packit Service a721b1
			 and Q gets the color that P had.  Q's right successor
Packit Service a721b1
			 also becomes black.  This changes the black edge
Packit Service a721b1
			 count only for node R and its successors.  */
Packit Service a721b1
		      q->red = p->red;
Packit Service a721b1
		      p->red = 0;
Packit Service a721b1
Packit Service a721b1
		      q->right->red = 0;
Packit Service a721b1
Packit Service a721b1
		      /* left rotate p */
Packit Service a721b1
		      p->right = q->left;
Packit Service a721b1
		      q->left = p;
Packit Service a721b1
		      *pp = q;
Packit Service a721b1
		    }
Packit Service a721b1
Packit Service a721b1
		  /* We're done.  */
Packit Service a721b1
		  sp = 1;
Packit Service a721b1
		  r = NULL;
Packit Service a721b1
		}
Packit Service a721b1
	    }
Packit Service a721b1
	  else
Packit Service a721b1
	    {
Packit Service a721b1
	      /* Comments: see above.  */
Packit Service a721b1
	      q = p->left;
Packit Service a721b1
	      if (q->red)
Packit Service a721b1
		{
Packit Service a721b1
		  q->red = 0;
Packit Service a721b1
		  p->red = 1;
Packit Service a721b1
		  p->left = q->right;
Packit Service a721b1
		  q->right = p;
Packit Service a721b1
		  *pp = q;
Packit Service a721b1
		  nodestack[sp++] = pp = &q->right;
Packit Service a721b1
		  q = p->left;
Packit Service a721b1
		}
Packit Service a721b1
	      if ((q->right == NULL || !q->right->red)
Packit Service a721b1
		       && (q->left == NULL || !q->left->red))
Packit Service a721b1
		{
Packit Service a721b1
		  q->red = 1;
Packit Service a721b1
		  r = p;
Packit Service a721b1
		}
Packit Service a721b1
	      else
Packit Service a721b1
		{
Packit Service a721b1
		  if (q->left == NULL || !q->left->red)
Packit Service a721b1
		    {
Packit Service a721b1
		      node q2 = q->right;
Packit Service a721b1
		      q2->red = p->red;
Packit Service a721b1
		      p->left = q2->right;
Packit Service a721b1
		      q->right = q2->left;
Packit Service a721b1
		      q2->left = q;
Packit Service a721b1
		      q2->right = p;
Packit Service a721b1
		      *pp = q2;
Packit Service a721b1
		      p->red = 0;
Packit Service a721b1
		    }
Packit Service a721b1
		  else
Packit Service a721b1
		    {
Packit Service a721b1
		      q->red = p->red;
Packit Service a721b1
		      p->red = 0;
Packit Service a721b1
		      q->left->red = 0;
Packit Service a721b1
		      p->left = q->right;
Packit Service a721b1
		      q->right = p;
Packit Service a721b1
		      *pp = q;
Packit Service a721b1
		    }
Packit Service a721b1
		  sp = 1;
Packit Service a721b1
		  r = NULL;
Packit Service a721b1
		}
Packit Service a721b1
	    }
Packit Service a721b1
	  --sp;
Packit Service a721b1
	}
Packit Service a721b1
      if (r != NULL)
Packit Service a721b1
	r->red = 0;
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  free (unchained);
Packit Service a721b1
  return retval;
Packit Service a721b1
}
Packit Service a721b1
#ifdef weak_alias
Packit Service a721b1
weak_alias (__tdelete, tdelete)
Packit Service a721b1
#endif
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/* Walk the nodes of a tree.
Packit Service a721b1
   ROOT is the root of the tree to be walked, ACTION the function to be
Packit Service a721b1
   called at each node.  LEVEL is the level of ROOT in the whole tree.  */
Packit Service a721b1
static void
Packit Service a721b1
internal_function
Packit Service a721b1
trecurse (const void *vroot, __action_fn_t action, int level)
Packit Service a721b1
{
Packit Service a721b1
  const_node root = (const_node) vroot;
Packit Service a721b1
Packit Service a721b1
  if (root->left == NULL && root->right == NULL)
Packit Service a721b1
    (*action) (root, leaf, level);
Packit Service a721b1
  else
Packit Service a721b1
    {
Packit Service a721b1
      (*action) (root, preorder, level);
Packit Service a721b1
      if (root->left != NULL)
Packit Service a721b1
	trecurse (root->left, action, level + 1);
Packit Service a721b1
      (*action) (root, postorder, level);
Packit Service a721b1
      if (root->right != NULL)
Packit Service a721b1
	trecurse (root->right, action, level + 1);
Packit Service a721b1
      (*action) (root, endorder, level);
Packit Service a721b1
    }
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/* Walk the nodes of a tree.
Packit Service a721b1
   ROOT is the root of the tree to be walked, ACTION the function to be
Packit Service a721b1
   called at each node.  */
Packit Service a721b1
void
Packit Service a721b1
__twalk (const void *vroot, __action_fn_t action)
Packit Service a721b1
{
Packit Service a721b1
  const_node root = (const_node) vroot;
Packit Service a721b1
Packit Service a721b1
  CHECK_TREE (root);
Packit Service a721b1
Packit Service a721b1
  if (root != NULL && action != NULL)
Packit Service a721b1
    trecurse (root, action, 0);
Packit Service a721b1
}
Packit Service a721b1
#ifdef weak_alias
Packit Service a721b1
weak_alias (__twalk, twalk)
Packit Service a721b1
#endif
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
#ifdef _LIBC
Packit Service a721b1
Packit Service a721b1
/* The standardized functions miss an important functionality: the
Packit Service a721b1
   tree cannot be removed easily.  We provide a function to do this.  */
Packit Service a721b1
static void
Packit Service a721b1
internal_function
Packit Service a721b1
tdestroy_recurse (node root, __free_fn_t freefct)
Packit Service a721b1
{
Packit Service a721b1
  if (root->left != NULL)
Packit Service a721b1
    tdestroy_recurse (root->left, freefct);
Packit Service a721b1
  if (root->right != NULL)
Packit Service a721b1
    tdestroy_recurse (root->right, freefct);
Packit Service a721b1
  (*freefct) ((void *) root->key);
Packit Service a721b1
  /* Free the node itself.  */
Packit Service a721b1
  free (root);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
void
Packit Service a721b1
__tdestroy (void *vroot, __free_fn_t freefct)
Packit Service a721b1
{
Packit Service a721b1
  node root = (node) vroot;
Packit Service a721b1
Packit Service a721b1
  CHECK_TREE (root);
Packit Service a721b1
Packit Service a721b1
  if (root != NULL)
Packit Service a721b1
    tdestroy_recurse (root, freefct);
Packit Service a721b1
}
Packit Service a721b1
weak_alias (__tdestroy, tdestroy)
Packit Service a721b1
Packit Service a721b1
#endif /* _LIBC */