diff src/redblack.c @ 125:e413158cae13

Add ushare project files.
author naoyan@johnstown.minaminoshima.org
date Sun, 03 Oct 2010 11:35:19 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/redblack.c	Sun Oct 03 11:35:19 2010 +0900
@@ -0,0 +1,1140 @@
+static char rcsid[]="$Id: redblack.c,v 1.9 2003/10/24 01:31:21 damo Exp $";
+
+/*
+   Redblack balanced tree algorithm
+   Copyright (C) Damian Ivereigh 2000
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
+   (at your option) any later version. See the file COPYING for details.
+
+   This program 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 Lesser General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Implement the red/black tree structure. It is designed to emulate
+** the standard tsearch() stuff. i.e. the calling conventions are
+** exactly the same
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "redblack.h"
+
+#define assert(expr)
+
+/* Uncomment this if you would rather use a raw sbrk to get memory
+** (however the memory is never released again (only re-used). Can't
+** see any point in using this these days.
+*/
+/* #define USE_SBRK */
+
+enum nodecolour { BLACK, RED };
+
+struct RB_ENTRY(node)
+{
+	struct RB_ENTRY(node) *left;		/* Left down */
+	struct RB_ENTRY(node) *right;		/* Right down */
+	struct RB_ENTRY(node) *up;		/* Up */
+	enum nodecolour colour;		/* Node colour */
+#ifdef RB_INLINE
+	RB_ENTRY(data_t) key;		/* User's key (and data) */
+#define RB_GET(x,y)		&x->y
+#define RB_SET(x,y,v)		x->y = *(v)
+#else
+	const RB_ENTRY(data_t) *key;	/* Pointer to user's key (and data) */
+#define RB_GET(x,y)		x->y
+#define RB_SET(x,y,v)		x->y = v
+#endif /* RB_INLINE */
+};
+
+/* Dummy (sentinel) node, so that we can make X->left->up = X
+** We then use this instead of NULL to mean the top or bottom
+** end of the rb tree. It is a black node.
+**
+** Initialization of the last field in this initializer is left implicit
+** because it could be of any type.  We count on the compiler to zero it.
+*/
+struct RB_ENTRY(node) RB_ENTRY(_null)={&RB_ENTRY(_null), &RB_ENTRY(_null), &RB_ENTRY(_null), BLACK, &RB_ENTRY(_null)};
+#define RBNULL (&RB_ENTRY(_null))
+
+#if defined(USE_SBRK)
+
+static struct RB_ENTRY(node) *RB_ENTRY(_alloc)();
+static void RB_ENTRY(_free)(struct RB_ENTRY(node) *);
+
+#else
+
+static struct RB_ENTRY(node) *RB_ENTRY(_alloc)() {return (struct RB_ENTRY(node) *) malloc(sizeof(struct RB_ENTRY(node)));}
+static void RB_ENTRY(_free)(struct RB_ENTRY(node) *x) {free(x);}
+
+#endif
+
+/* These functions are always needed */
+static void RB_ENTRY(_left_rotate)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *);
+static void RB_ENTRY(_right_rotate)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *);
+static struct RB_ENTRY(node) *RB_ENTRY(_successor)(const struct RB_ENTRY(node) *);
+static struct RB_ENTRY(node) *RB_ENTRY(_predecessor)(const struct RB_ENTRY(node) *);
+static struct RB_ENTRY(node) *RB_ENTRY(_traverse)(int, const RB_ENTRY(data_t) * , struct RB_ENTRY(tree) *);
+
+/* These functions may not be needed */
+#ifndef no_lookup
+static struct RB_ENTRY(node) *RB_ENTRY(_lookup)(int, const RB_ENTRY(data_t) * , struct RB_ENTRY(tree) *);
+#endif
+
+#ifndef no_destroy
+static void RB_ENTRY(_destroy)(struct RB_ENTRY(node) *);
+#endif
+
+#ifndef no_delete
+static void RB_ENTRY(_delete)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *);
+static void RB_ENTRY(_delete_fix)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *);
+#endif
+
+#ifndef no_walk
+static void RB_ENTRY(_walk)(const struct RB_ENTRY(node) *, void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *, int);
+#endif
+
+#ifndef no_readlist
+static RBLIST *RB_ENTRY(_openlist)(const struct RB_ENTRY(node) *);
+static const RB_ENTRY(data_t) * RB_ENTRY(_readlist)(RBLIST *);
+static void RB_ENTRY(_closelist)(RBLIST *);
+#endif
+
+/*
+** OK here we go, the balanced tree stuff. The algorithm is the
+** fairly standard red/black taken from "Introduction to Algorithms"
+** by Cormen, Leiserson & Rivest. Maybe one of these days I will
+** fully understand all this stuff.
+**
+** Basically a red/black balanced tree has the following properties:-
+** 1) Every node is either red or black (colour is RED or BLACK)
+** 2) A leaf (RBNULL pointer) is considered black
+** 3) If a node is red then its children are black
+** 4) Every path from a node to a leaf contains the same no
+**    of black nodes
+**
+** 3) & 4) above guarantee that the longest path (alternating
+** red and black nodes) is only twice as long as the shortest
+** path (all black nodes). Thus the tree remains fairly balanced.
+*/
+
+/*
+ * Initialise a tree. Identifies the comparison routine and any config
+ * data that must be sent to it when called.
+ * Returns a pointer to the top of the tree.
+ */
+#ifndef RB_CUSTOMIZE
+RB_STATIC struct RB_ENTRY(tree) *
+rbinit(int (*cmp)(const void *, const void *, const void *), const void *config)
+#else
+RB_STATIC struct RB_ENTRY(tree) *RB_ENTRY(init)(void)
+#endif /* RB_CUSTOMIZE */
+{
+	struct RB_ENTRY(tree) *retval;
+	char c;
+
+	c=rcsid[0]; /* This does nothing but shutup the -Wall */
+
+	if ((retval=(struct RB_ENTRY(tree) *) malloc(sizeof(struct RB_ENTRY(tree))))==NULL)
+		return(NULL);
+
+#ifndef RB_CUSTOMIZE
+	retval->rb_cmp=cmp;
+	retval->rb_config=config;
+#endif /* RB_CUSTOMIZE */
+	retval->rb_root=RBNULL;
+
+	return(retval);
+}
+
+#ifndef no_destroy
+RB_STATIC void
+RB_ENTRY(destroy)(struct RB_ENTRY(tree) *rbinfo)
+{
+	if (rbinfo==NULL)
+		return;
+
+	if (rbinfo->rb_root!=RBNULL)
+		RB_ENTRY(_destroy)(rbinfo->rb_root);
+
+	free(rbinfo);
+}
+#endif /* no_destroy */
+
+#ifndef no_search
+RB_STATIC const RB_ENTRY(data_t) *
+RB_ENTRY(search)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
+{
+	struct RB_ENTRY(node) *x;
+
+	if (rbinfo==NULL)
+		return(NULL);
+
+	x=RB_ENTRY(_traverse)(1, key, rbinfo);
+
+	return((x==RBNULL) ? NULL : RB_GET(x, key));
+}
+#endif /* no_search */
+
+#ifndef no_find
+RB_STATIC const RB_ENTRY(data_t) * 
+RB_ENTRY(find)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
+{
+	struct RB_ENTRY(node) *x;
+
+	if (rbinfo==NULL)
+		return(NULL);
+
+	/* If we have a NULL root (empty tree) then just return */
+	if (rbinfo->rb_root==RBNULL)
+		return(NULL);
+
+	x=RB_ENTRY(_traverse)(0, key, rbinfo);
+
+	return((x==RBNULL) ? NULL : RB_GET(x, key));
+}
+#endif /* no_find */
+
+#ifndef no_delete
+RB_STATIC const RB_ENTRY(data_t) * 
+RB_ENTRY(delete)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
+{
+	struct RB_ENTRY(node) *x;
+	const RB_ENTRY(data_t) * y;
+
+	if (rbinfo==NULL)
+		return(NULL);
+
+	x=RB_ENTRY(_traverse)(0, key, rbinfo);
+
+	if (x==RBNULL)
+	{
+		return(NULL);
+	}
+	else
+	{
+		y=RB_GET(x, key);
+		RB_ENTRY(_delete)(&rbinfo->rb_root, x);
+
+		return(y);
+	}
+}
+#endif /* no_delete */
+
+#ifndef no_walk
+RB_STATIC void
+RB_ENTRY(walk)(const struct RB_ENTRY(tree) *rbinfo, void (*action)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *arg)
+{
+	if (rbinfo==NULL)
+		return;
+
+	RB_ENTRY(_walk)(rbinfo->rb_root, action, arg, 0);
+}
+#endif /* no_walk */
+
+#ifndef no_readlist
+RB_STATIC RBLIST *
+RB_ENTRY(openlist)(const struct RB_ENTRY(tree) *rbinfo)
+{
+	if (rbinfo==NULL)
+		return(NULL);
+
+	return(RB_ENTRY(_openlist)(rbinfo->rb_root));
+}
+
+RB_STATIC const RB_ENTRY(data_t) * 
+RB_ENTRY(readlist)(RBLIST *rblistp)
+{
+	if (rblistp==NULL)
+		return(NULL);
+
+	return(RB_ENTRY(_readlist)(rblistp));
+}
+
+RB_STATIC void
+RB_ENTRY(closelist)(RBLIST *rblistp)
+{
+	if (rblistp==NULL)
+		return;
+
+	RB_ENTRY(_closelist)(rblistp);
+}
+#endif /* no_readlist */
+
+#ifndef no_lookup
+RB_STATIC const RB_ENTRY(data_t) * 
+RB_ENTRY(lookup)(int mode, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
+{
+	struct RB_ENTRY(node) *x;
+
+	/* If we have a NULL root (empty tree) then just return NULL */
+	if (rbinfo==NULL || rbinfo->rb_root==NULL)
+		return(NULL);
+
+	x=RB_ENTRY(_lookup)(mode, key, rbinfo);
+
+	return((x==RBNULL) ? NULL : RB_GET(x, key));
+}
+#endif /* no_lookup */
+
+/* --------------------------------------------------------------------- */
+
+/* Search for and if not found and insert is true, will add a new
+** node in. Returns a pointer to the new node, or the node found
+*/
+static struct RB_ENTRY(node) *
+RB_ENTRY(_traverse)(int insert, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
+{
+	struct RB_ENTRY(node) *x,*y,*z;
+	int cmp;
+	int found=0;
+	int cmpmods();
+
+	y=RBNULL; /* points to the parent of x */
+	x=rbinfo->rb_root;
+
+	/* walk x down the tree */
+	while(x!=RBNULL && found==0)
+	{
+		y=x;
+		/* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */
+#ifndef RB_CUSTOMIZE
+		cmp=RB_CMP(key, RB_GET(x, key), rbinfo->rb_config);
+#else
+		cmp=RB_CMP(key, RB_GET(x, key));
+#endif /* RB_CUSTOMIZE */
+
+		if (cmp<0)
+			x=x->left;
+		else if (cmp>0)
+			x=x->right;
+		else
+			found=1;
+	}
+
+	if (found || !insert)
+		return(x);
+
+	if ((z=RB_ENTRY(_alloc)())==NULL)
+	{
+		/* Whoops, no memory */
+		return(RBNULL);
+	}
+
+	RB_SET(z, key, key);
+	z->up=y;
+	if (y==RBNULL)
+	{
+		rbinfo->rb_root=z;
+	}
+	else
+	{
+#ifndef RB_CUSTOMIZE
+		cmp=RB_CMP(RB_GET(z, key), RB_GET(y, key), rbinfo->rb_config);
+#else
+		cmp=RB_CMP(RB_GET(z, key), RB_GET(y, key));
+#endif /* RB_CUSTOMIZE */
+		if (cmp<0)
+			y->left=z;
+		else
+			y->right=z;
+	}
+
+	z->left=RBNULL;
+	z->right=RBNULL;
+
+	/* colour this new node red */
+	z->colour=RED;
+
+	/* Having added a red node, we must now walk back up the tree balancing
+	** it, by a series of rotations and changing of colours
+	*/
+	x=z;
+
+	/* While we are not at the top and our parent node is red
+	** N.B. Since the root node is garanteed black, then we
+	** are also going to stop if we are the child of the root
+	*/
+
+	while(x != rbinfo->rb_root && (x->up->colour == RED))
+	{
+		/* if our parent is on the left side of our grandparent */
+		if (x->up == x->up->up->left)
+		{
+			/* get the right side of our grandparent (uncle?) */
+			y=x->up->up->right;
+			if (y->colour == RED)
+			{
+				/* make our parent black */
+				x->up->colour = BLACK;
+				/* make our uncle black */
+				y->colour = BLACK;
+				/* make our grandparent red */
+				x->up->up->colour = RED;
+
+				/* now consider our grandparent */
+				x=x->up->up;
+			}
+			else
+			{
+				/* if we are on the right side of our parent */
+				if (x == x->up->right)
+				{
+					/* Move up to our parent */
+					x=x->up;
+					RB_ENTRY(_left_rotate)(&rbinfo->rb_root, x);
+				}
+
+				/* make our parent black */
+				x->up->colour = BLACK;
+				/* make our grandparent red */
+				x->up->up->colour = RED;
+				/* right rotate our grandparent */
+				RB_ENTRY(_right_rotate)(&rbinfo->rb_root, x->up->up);
+			}
+		}
+		else
+		{
+			/* everything here is the same as above, but
+			** exchanging left for right
+			*/
+
+			y=x->up->up->left;
+			if (y->colour == RED)
+			{
+				x->up->colour = BLACK;
+				y->colour = BLACK;
+				x->up->up->colour = RED;
+
+				x=x->up->up;
+			}
+			else
+			{
+				if (x == x->up->left)
+				{
+					x=x->up;
+					RB_ENTRY(_right_rotate)(&rbinfo->rb_root, x);
+				}
+
+				x->up->colour = BLACK;
+				x->up->up->colour = RED;
+				RB_ENTRY(_left_rotate)(&rbinfo->rb_root, x->up->up);
+			}
+		}
+	}
+
+	/* Set the root node black */
+	(rbinfo->rb_root)->colour = BLACK;
+
+	return(z);
+}
+
+#ifndef no_lookup
+/* Search for a key according to mode (see redblack.h)
+*/
+static struct RB_ENTRY(node) *
+RB_ENTRY(_lookup)(int mode, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
+{
+	struct RB_ENTRY(node) *x,*y;
+	int cmp=0;
+	int found=0;
+
+	y=RBNULL; /* points to the parent of x */
+	x=rbinfo->rb_root;
+
+	if (mode==RB_LUFIRST)
+	{
+		/* Keep going left until we hit a NULL */
+		while(x!=RBNULL)
+		{
+			y=x;
+			x=x->left;
+		}
+
+		return(y);
+	}
+	else if (mode==RB_LULAST)
+	{
+		/* Keep going right until we hit a NULL */
+		while(x!=RBNULL)
+		{
+			y=x;
+			x=x->right;
+		}
+
+		return(y);
+	}
+
+	/* walk x down the tree */
+	while(x!=RBNULL && found==0)
+	{
+		y=x;
+		/* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */
+#ifndef RB_CUSTOMIZE
+		cmp=RB_CMP(key, RB_GET(x, key), rbinfo->rb_config);
+#else
+		cmp=RB_CMP(key, RB_GET(x, key));
+#endif /* RB_CUSTOMIZE */
+
+
+		if (cmp<0)
+			x=x->left;
+		else if (cmp>0)
+			x=x->right;
+		else
+			found=1;
+	}
+
+	if (found && (mode==RB_LUEQUAL || mode==RB_LUGTEQ || mode==RB_LULTEQ))
+		return(x);
+
+	if (!found && (mode==RB_LUEQUAL || mode==RB_LUNEXT || mode==RB_LUPREV))
+		return(RBNULL);
+
+	if (mode==RB_LUGTEQ || (!found && mode==RB_LUGREAT))
+	{
+		if (cmp>0)
+			return(RB_ENTRY(_successor)(y));
+		else
+			return(y);
+	}
+
+	if (mode==RB_LULTEQ || (!found && mode==RB_LULESS))
+	{
+		if (cmp<0)
+			return(RB_ENTRY(_predecessor)(y));
+		else
+			return(y);
+	}
+
+	if (mode==RB_LUNEXT || (found && mode==RB_LUGREAT))
+		return(RB_ENTRY(_successor)(x));
+
+	if (mode==RB_LUPREV || (found && mode==RB_LULESS))
+		return(RB_ENTRY(_predecessor)(x));
+
+	/* Shouldn't get here */
+	return(RBNULL);
+}
+#endif /* no_lookup */
+
+#ifndef no_destroy
+/*
+ * Destroy all the elements blow us in the tree
+ * only useful as part of a complete tree destroy.
+ */
+static void
+RB_ENTRY(_destroy)(struct RB_ENTRY(node) *x)
+{
+	if (x!=RBNULL)
+	{
+		if (x->left!=RBNULL)
+			RB_ENTRY(_destroy)(x->left);
+		if (x->right!=RBNULL)
+			RB_ENTRY(_destroy)(x->right);
+		RB_ENTRY(_free)(x);
+	}
+}
+#endif /* no_destroy */
+
+/*
+** Rotate our tree thus:-
+**
+**             X        rb_left_rotate(X)--->            Y
+**           /   \                                     /   \
+**          A     Y     <---rb_right_rotate(Y)        X     C
+**              /   \                               /   \
+**             B     C                             A     B
+**
+** N.B. This does not change the ordering.
+**
+** We assume that neither X or Y is NULL
+*/
+
+static void
+RB_ENTRY(_left_rotate)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *x)
+{
+	struct RB_ENTRY(node) *y;
+
+	assert(x!=RBNULL);
+	assert(x->right!=RBNULL);
+
+	y=x->right; /* set Y */
+
+	/* Turn Y's left subtree into X's right subtree (move B)*/
+	x->right = y->left;
+
+	/* If B is not null, set it's parent to be X */
+	if (y->left != RBNULL)
+		y->left->up = x;
+
+	/* Set Y's parent to be what X's parent was */
+	y->up = x->up;
+
+	/* if X was the root */
+	if (x->up == RBNULL)
+	{
+		*rootp=y;
+	}
+	else
+	{
+		/* Set X's parent's left or right pointer to be Y */
+		if (x == x->up->left)
+		{
+			x->up->left=y;
+		}
+		else
+		{
+			x->up->right=y;
+		}
+	}
+
+	/* Put X on Y's left */
+	y->left=x;
+
+	/* Set X's parent to be Y */
+	x->up = y;
+}
+
+static void
+RB_ENTRY(_right_rotate)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *y)
+{
+	struct RB_ENTRY(node) *x;
+
+	assert(y!=RBNULL);
+	assert(y->left!=RBNULL);
+
+	x=y->left; /* set X */
+
+	/* Turn X's right subtree into Y's left subtree (move B) */
+	y->left = x->right;
+
+	/* If B is not null, set it's parent to be Y */
+	if (x->right != RBNULL)
+		x->right->up = y;
+
+	/* Set X's parent to be what Y's parent was */
+	x->up = y->up;
+
+	/* if Y was the root */
+	if (y->up == RBNULL)
+	{
+		*rootp=x;
+	}
+	else
+	{
+		/* Set Y's parent's left or right pointer to be X */
+		if (y == y->up->left)
+		{
+			y->up->left=x;
+		}
+		else
+		{
+			y->up->right=x;
+		}
+	}
+
+	/* Put Y on X's right */
+	x->right=y;
+
+	/* Set Y's parent to be X */
+	y->up = x;
+}
+
+/* Return a pointer to the smallest key greater than x
+*/
+static struct RB_ENTRY(node) *
+RB_ENTRY(_successor)(const struct RB_ENTRY(node) *x)
+{
+	struct RB_ENTRY(node) *y;
+
+	if (x->right!=RBNULL)
+	{
+		/* If right is not NULL then go right one and
+		** then keep going left until we find a node with
+		** no left pointer.
+		*/
+		for (y=x->right; y->left!=RBNULL; y=y->left);
+	}
+	else
+	{
+		/* Go up the tree until we get to a node that is on the
+		** left of its parent (or the root) and then return the
+		** parent.
+		*/
+		y=x->up;
+		while(y!=RBNULL && x==y->right)
+		{
+			x=y;
+			y=y->up;
+		}
+	}
+	return(y);
+}
+
+/* Return a pointer to the largest key smaller than x
+*/
+static struct RB_ENTRY(node) *
+RB_ENTRY(_predecessor)(const struct RB_ENTRY(node) *x)
+{
+	struct RB_ENTRY(node) *y;
+
+	if (x->left!=RBNULL)
+	{
+		/* If left is not NULL then go left one and
+		** then keep going right until we find a node with
+		** no right pointer.
+		*/
+		for (y=x->left; y->right!=RBNULL; y=y->right);
+	}
+	else
+	{
+		/* Go up the tree until we get to a node that is on the
+		** right of its parent (or the root) and then return the
+		** parent.
+		*/
+		y=x->up;
+		while(y!=RBNULL && x==y->left)
+		{
+			x=y;
+			y=y->up;
+		}
+	}
+	return(y);
+}
+
+#ifndef no_delete
+/* Delete the node z, and free up the space
+*/
+static void
+RB_ENTRY(_delete)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *z)
+{
+	struct RB_ENTRY(node) *x, *y;
+
+	if (z->left == RBNULL || z->right == RBNULL)
+		y=z;
+	else
+		y=RB_ENTRY(_successor)(z);
+
+	if (y->left != RBNULL)
+		x=y->left;
+	else
+		x=y->right;
+
+	x->up = y->up;
+
+	if (y->up == RBNULL)
+	{
+		*rootp=x;
+	}
+	else
+	{
+		if (y==y->up->left)
+			y->up->left = x;
+		else
+			y->up->right = x;
+	}
+
+	if (y!=z)
+	{
+		RB_SET(z, key, RB_GET(y, key));
+	}
+
+	if (y->colour == BLACK)
+		RB_ENTRY(_delete_fix)(rootp, x);
+
+	RB_ENTRY(_free)(y);
+}
+
+/* Restore the reb-black properties after a delete */
+static void
+RB_ENTRY(_delete_fix)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *x)
+{
+	struct RB_ENTRY(node) *w;
+
+	while (x!=*rootp && x->colour==BLACK)
+	{
+		if (x==x->up->left)
+		{
+			w=x->up->right;
+			if (w->colour==RED)
+			{
+				w->colour=BLACK;
+				x->up->colour=RED;
+				rb_left_rotate(rootp, x->up);
+				w=x->up->right;
+			}
+
+			if (w->left->colour==BLACK && w->right->colour==BLACK)
+			{
+				w->colour=RED;
+				x=x->up;
+			}
+			else
+			{
+				if (w->right->colour == BLACK)
+				{
+					w->left->colour=BLACK;
+					w->colour=RED;
+					RB_ENTRY(_right_rotate)(rootp, w);
+					w=x->up->right;
+				}
+
+
+				w->colour=x->up->colour;
+				x->up->colour = BLACK;
+				w->right->colour = BLACK;
+				RB_ENTRY(_left_rotate)(rootp, x->up);
+				x=*rootp;
+			}
+		}
+		else
+		{
+			w=x->up->left;
+			if (w->colour==RED)
+			{
+				w->colour=BLACK;
+				x->up->colour=RED;
+				RB_ENTRY(_right_rotate)(rootp, x->up);
+				w=x->up->left;
+			}
+
+			if (w->right->colour==BLACK && w->left->colour==BLACK)
+			{
+				w->colour=RED;
+				x=x->up;
+			}
+			else
+			{
+				if (w->left->colour == BLACK)
+				{
+					w->right->colour=BLACK;
+					w->colour=RED;
+					RB_ENTRY(_left_rotate)(rootp, w);
+					w=x->up->left;
+				}
+
+				w->colour=x->up->colour;
+				x->up->colour = BLACK;
+				w->left->colour = BLACK;
+				RB_ENTRY(_right_rotate)(rootp, x->up);
+				x=*rootp;
+			}
+		}
+	}
+
+	x->colour=BLACK;
+}
+#endif /* no_delete */
+
+#ifndef no_walk
+static void
+RB_ENTRY(_walk)(const struct RB_ENTRY(node) *x, void (*action)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *arg, int level)
+{
+	if (x==RBNULL)
+		return;
+
+	if (x->left==RBNULL && x->right==RBNULL)
+	{
+		/* leaf */
+		(*action)(RB_GET(x, key), leaf, level, arg);
+	}
+	else
+	{
+		(*action)(RB_GET(x, key), preorder, level, arg);
+
+		RB_ENTRY(_walk)(x->left, action, arg, level+1);
+
+		(*action)(RB_GET(x, key), postorder, level, arg);
+
+		RB_ENTRY(_walk)(x->right, action, arg, level+1);
+
+		(*action)(RB_GET(x, key), endorder, level, arg);
+	}
+}
+#endif /* no_walk */
+
+#ifndef no_readlist
+static RBLIST *
+RB_ENTRY(_openlist)(const struct RB_ENTRY(node) *rootp)
+{
+	RBLIST *rblistp;
+
+	rblistp=(RBLIST *) malloc(sizeof(RBLIST));
+	if (!rblistp)
+		return(NULL);
+
+	rblistp->rootp=rootp;
+	rblistp->nextp=rootp;
+
+	if (rootp!=RBNULL)
+	{
+		while(rblistp->nextp->left!=RBNULL)
+		{
+			rblistp->nextp=rblistp->nextp->left;
+		}
+	}
+
+	return(rblistp);
+}
+
+static const RB_ENTRY(data_t) * 
+RB_ENTRY(_readlist)(RBLIST *rblistp)
+{
+	const RB_ENTRY(data_t) *key=NULL;
+
+	if (rblistp!=NULL && rblistp->nextp!=RBNULL)
+	{
+		key=RB_GET(rblistp->nextp, key);
+		rblistp->nextp=RB_ENTRY(_successor)(rblistp->nextp);
+	}
+
+	return(key);
+}
+
+static void
+rb_closelist(RBLIST *rblistp)
+{
+	if (rblistp)
+		free(rblistp);
+}
+#endif /* no_readlist */
+
+#if defined(RB_USE_SBRK)
+/* Allocate space for our nodes, allowing us to get space from
+** sbrk in larger chucks.
+*/
+static struct RB_ENTRY(node) *rbfreep=NULL;
+
+#define RB_ENTRY(NODE)ALLOC_CHUNK_SIZE 1000
+static struct RB_ENTRY(node) *
+RB_ENTRY(_alloc)()
+{
+	struct RB_ENTRY(node) *x;
+	int i;
+
+	if (rbfreep==NULL)
+	{
+		/* must grab some more space */
+		rbfreep=(struct RB_ENTRY(node) *) sbrk(sizeof(struct RB_ENTRY(node)) * RB_ENTRY(NODE)ALLOC_CHUNK_SIZE);
+
+		if (rbfreep==(struct RB_ENTRY(node) *) -1)
+		{
+			return(NULL);
+		}
+
+		/* tie them together in a linked list (use the up pointer) */
+		for (i=0, x=rbfreep; i<RB_ENTRY(NODE)ALLOC_CHUNK_SIZE-1; i++, x++)
+		{
+			x->up = (x+1);
+		}
+		x->up=NULL;
+	}
+
+	x=rbfreep;
+	rbfreep = rbfreep->up;
+#ifdef RB_ALLOC
+ 	RB_ALLOC(ACCESS(x, key));
+#endif /* RB_ALLOC */
+	return(x);
+}
+
+/* free (dealloc) an RB_ENTRY(node) structure - add it onto the front of the list
+** N.B. RB_ENTRY(node) need not have been allocated through rb_alloc()
+*/
+static void
+RB_ENTRY(_free)(struct RB_ENTRY(node) *x)
+{
+#ifdef RB_FREE
+ 	RB_FREE(ACCESS(x, key));
+#endif /* RB_FREE */
+	x->up=rbfreep;
+	rbfreep=x;
+}
+
+#endif
+
+#if 0
+int
+RB_ENTRY(_check)(struct RB_ENTRY(node) *rootp)
+{
+	if (rootp==NULL || rootp==RBNULL)
+		return(0);
+
+	if (rootp->up!=RBNULL)
+	{
+		fprintf(stderr, "Root up pointer not RBNULL");
+		dumptree(rootp, 0);
+		return(1);
+	}
+
+	if (RB_ENTRY(_check)1(rootp))
+	{
+		RB_ENTRY(dumptree)(rootp, 0);
+		return(1);
+	}
+
+	if (RB_ENTRY(count_black)(rootp)==-1)
+	{
+		RB_ENTRY(dumptree)(rootp, 0);
+		return(-1);
+	}
+
+	return(0);
+}
+
+int
+RB_ENTRY(_check1)(struct RB_ENTRY(node) *x)
+{
+	if (x->left==NULL || x->right==NULL)
+	{
+		fprintf(stderr, "Left or right is NULL");
+		return(1);
+	}
+
+	if (x->colour==RED)
+	{
+		if (x->left->colour!=BLACK && x->right->colour!=BLACK)
+		{
+			fprintf(stderr, "Children of red node not both black, x=%ld", x);
+			return(1);
+		}
+	}
+
+	if (x->left != RBNULL)
+	{
+		if (x->left->up != x)
+		{
+			fprintf(stderr, "x->left->up != x, x=%ld", x);
+			return(1);
+		}
+
+		if (rb_check1(x->left))
+			return(1);
+	}		
+
+	if (x->right != RBNULL)
+	{
+		if (x->right->up != x)
+		{
+			fprintf(stderr, "x->right->up != x, x=%ld", x);
+			return(1);
+		}
+
+		if (rb_check1(x->right))
+			return(1);
+	}		
+	return(0);
+}
+
+RB_ENTRY(count_black)(struct RB_ENTRY(node) *x)
+{
+	int nleft, nright;
+
+	if (x==RBNULL)
+		return(1);
+
+	nleft=RB_ENTRY(count_black)(x->left);
+	nright=RB_ENTRY(count_black)(x->right);
+
+	if (nleft==-1 || nright==-1)
+		return(-1);
+
+	if (nleft != nright)
+	{
+		fprintf(stderr, "Black count not equal on left & right, x=%ld", x);
+		return(-1);
+	}
+
+	if (x->colour == BLACK)
+	{
+		nleft++;
+	}
+
+	return(nleft);
+}
+
+RB_ENTRY(dumptree)(struct RB_ENTRY(node) *x, int n)
+{
+	char *prkey();
+
+	if (x!=NULL && x!=RBNULL)
+	{
+		n++;
+		fprintf(stderr, "Tree: %*s %ld: left=%ld, right=%ld, colour=%s, key=%s",
+			n,
+			"",
+			x,
+			x->left,
+			x->right,
+			(x->colour==BLACK) ? "BLACK" : "RED",
+			prkey(RB_GET(x, key)));
+
+		RB_ENTRY(dumptree)(x->left, n);
+		RB_ENTRY(dumptree)(x->right, n);
+	}	
+}
+#endif
+
+/*
+ * $Log: redblack.c,v $
+ * Revision 1.9  2003/10/24 01:31:21  damo
+ * Patches from Eric Raymond: %prefix is implemented.  Various other small
+ * changes avoid stepping on global namespaces and improve the documentation.
+ *
+ * Revision 1.8  2002/08/26 05:33:47  damo
+ * Some minor fixes:-
+ * Stopped ./configure warning about stuff being in the wrong order
+ * Fixed compiler warning about const (not sure about this)
+ * Changed directory of redblack.c in documentation
+ *
+ * Revision 1.7  2002/08/26 03:11:40  damo
+ * Fixed up a bunch of compiler warnings when compiling example4
+ *
+ * Tidies up the Makefile.am & Specfile.
+ *
+ * Renamed redblack to rbgen
+ *
+ * Revision 1.6  2002/08/26 01:03:35  damo
+ * Patch from Eric Raymond to change the way the library is used:-
+ *
+ * Eric's idea is to convert libredblack into a piece of in-line code
+ * generated by another program. This should be faster, smaller and easier
+ * to use.
+ *
+ * This is the first check-in of his code before I start futzing with it!
+ *
+ * Revision 1.5  2002/01/30 07:54:53  damo
+ * Fixed up the libtool versioning stuff (finally)
+ * Fixed bug 500600 (not detecting a NULL return from malloc)
+ * Fixed bug 509485 (no longer needs search.h)
+ * Cleaned up debugging section
+ * Allow multiple inclusions of redblack.h
+ * Thanks to Matthias Andree for reporting (and fixing) these
+ *
+ * Revision 1.4  2000/06/06 14:43:43  damo
+ * Added all the rbwalk & rbopenlist stuff. Fixed up malloc instead of sbrk.
+ * Added two new examples
+ *
+ * Revision 1.3  2000/05/24 06:45:27  damo
+ * Converted everything over to using const
+ * Added a new example1.c file to demonstrate the worst case scenario
+ * Minor fixups of the spec file
+ *
+ * Revision 1.2  2000/05/24 06:17:10  damo
+ * Fixed up the License (now the LGPL)
+ *
+ * Revision 1.1  2000/05/24 04:15:53  damo
+ * Initial import of files. Versions are now all over the place. Oh well
+ *
+ */
+