409 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			409 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*========================================================================
 | 
						|
//
 | 
						|
//      rbtree.c
 | 
						|
//
 | 
						|
//      Red Black tree implementation
 | 
						|
//
 | 
						|
//========================================================================
 | 
						|
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
 | 
						|
// -------------------------------------------                              
 | 
						|
// This file is part of eCos, the Embedded Configurable Operating System.   
 | 
						|
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 | 
						|
//
 | 
						|
// eCos 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 2 or (at your option) any later      
 | 
						|
// version.                                                                 
 | 
						|
//
 | 
						|
// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,    
 | 
						|
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
 | 
						|
//
 | 
						|
// As a special exception, if other files instantiate templates or use      
 | 
						|
// macros or inline functions from this file, or you compile this file      
 | 
						|
// and link it with other works to produce a work based on this file,       
 | 
						|
// this file does not by itself cause the resulting work to be covered by   
 | 
						|
// the GNU General Public License. However the source code for this file    
 | 
						|
// must still be made available in accordance with section (3) of the GNU   
 | 
						|
// General Public License v2.                                               
 | 
						|
//
 | 
						|
// This exception does not invalidate any other reasons why a work based    
 | 
						|
// on this file might be covered by the GNU General Public License.         
 | 
						|
// -------------------------------------------                              
 | 
						|
// ####ECOSGPLCOPYRIGHTEND####                                              
 | 
						|
//========================================================================
 | 
						|
//#####DESCRIPTIONBEGIN####
 | 
						|
//
 | 
						|
// Author(s):     Niels Provos/OpenBSD
 | 
						|
// Contributors:  dwmw2
 | 
						|
// Date:          2003-01-21
 | 
						|
// Purpose:       This file provides an implementation of red-black trees.
 | 
						|
// Description:   Derived from OpenBSD src/sys/sys/tree.h
 | 
						|
// Usage:         
 | 
						|
//
 | 
						|
//####DESCRIPTIONEND####
 | 
						|
//
 | 
						|
//======================================================================
 | 
						|
*/
 | 
						|
 | 
						|
/*	$OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $	*/
 | 
						|
/*
 | 
						|
 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer.
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | 
						|
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
						|
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
						|
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
						|
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
						|
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
						|
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
						|
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
						|
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
/* Fields renamed to match Linux ones. */
 | 
						|
#include <linux/rbtree.h>
 | 
						|
 | 
						|
 | 
						|
#define RB_HEAD(head)		(head)->rb_node
 | 
						|
#define RB_LEFT(elm)		(elm)->rb_left
 | 
						|
#define RB_RIGHT(elm)		(elm)->rb_right
 | 
						|
#define RB_PARENT(elm)		(elm)->rb_parent
 | 
						|
#define RB_COLOR(elm)		(elm)->rb_color
 | 
						|
 | 
						|
 | 
						|
#define RB_SET(elm, parent) do {				\
 | 
						|
	RB_PARENT(elm) = parent;				\
 | 
						|
	RB_LEFT(elm) = RB_RIGHT(elm) = NULL;	\
 | 
						|
	RB_COLOR(elm) = RB_RED;				\
 | 
						|
} while (0)
 | 
						|
 | 
						|
#define RB_SET_BLACKRED(black, red) do {			\
 | 
						|
	RB_COLOR(black) = RB_BLACK;				\
 | 
						|
	RB_COLOR(red) = RB_RED;					\
 | 
						|
} while (0)
 | 
						|
 | 
						|
#ifndef RB_AUGMENT
 | 
						|
#define RB_AUGMENT(x)
 | 
						|
#endif
 | 
						|
 | 
						|
#define RB_ROTATE_LEFT(head, elm, tmp) do {			\
 | 
						|
	(tmp) = RB_RIGHT(elm);					\
 | 
						|
	if ((RB_RIGHT(elm) = RB_LEFT(tmp))) {			\
 | 
						|
		RB_PARENT(RB_LEFT(tmp)) = (elm);		\
 | 
						|
	}							\
 | 
						|
	RB_AUGMENT(elm);					\
 | 
						|
	if ((RB_PARENT(tmp) = RB_PARENT(elm))) {		\
 | 
						|
		if ((elm) == RB_LEFT(RB_PARENT(elm)))		\
 | 
						|
			RB_LEFT(RB_PARENT(elm)) = (tmp);	\
 | 
						|
		else						\
 | 
						|
			RB_RIGHT(RB_PARENT(elm)) = (tmp);	\
 | 
						|
	} else							\
 | 
						|
		(head)->rb_node = (tmp);			\
 | 
						|
	RB_LEFT(tmp) = (elm);					\
 | 
						|
	RB_PARENT(elm) = (tmp);					\
 | 
						|
	RB_AUGMENT(tmp);					\
 | 
						|
	if ((RB_PARENT(tmp)))					\
 | 
						|
		RB_AUGMENT(RB_PARENT(tmp));			\
 | 
						|
} while (0)
 | 
						|
 | 
						|
#define RB_ROTATE_RIGHT(head, elm, tmp) do {			\
 | 
						|
	(tmp) = RB_LEFT(elm);					\
 | 
						|
	if ((RB_LEFT(elm) = RB_RIGHT(tmp))) {			\
 | 
						|
		RB_PARENT(RB_RIGHT(tmp)) = (elm);		\
 | 
						|
	}							\
 | 
						|
	RB_AUGMENT(elm);					\
 | 
						|
	if ((RB_PARENT(tmp) = RB_PARENT(elm))) {		\
 | 
						|
		if ((elm) == RB_LEFT(RB_PARENT(elm)))		\
 | 
						|
			RB_LEFT(RB_PARENT(elm)) = (tmp);	\
 | 
						|
		else						\
 | 
						|
			RB_RIGHT(RB_PARENT(elm)) = (tmp);	\
 | 
						|
	} else							\
 | 
						|
		(head)->rb_node = (tmp);			\
 | 
						|
	RB_RIGHT(tmp) = (elm);					\
 | 
						|
	RB_PARENT(elm) = (tmp);					\
 | 
						|
	RB_AUGMENT(tmp);					\
 | 
						|
	if ((RB_PARENT(tmp)))					\
 | 
						|
		RB_AUGMENT(RB_PARENT(tmp));			\
 | 
						|
} while(0)
 | 
						|
 | 
						|
/* Note args swapped to match Linux */
 | 
						|
void rb_insert_color(struct rb_node *elm, struct rb_root *head)
 | 
						|
{
 | 
						|
	struct rb_node *parent, *gparent, *tmp;
 | 
						|
	while ((parent = RB_PARENT(elm)) &&
 | 
						|
	    RB_COLOR(parent) == RB_RED) {
 | 
						|
		gparent = RB_PARENT(parent);
 | 
						|
		if (parent == RB_LEFT(gparent)) {
 | 
						|
			tmp = RB_RIGHT(gparent);
 | 
						|
			if (tmp && RB_COLOR(tmp) == RB_RED) {
 | 
						|
				RB_COLOR(tmp) = RB_BLACK;
 | 
						|
				RB_SET_BLACKRED(parent, gparent);
 | 
						|
				elm = gparent;
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			if (RB_RIGHT(parent) == elm) {
 | 
						|
				RB_ROTATE_LEFT(head, parent, tmp);
 | 
						|
				tmp = parent;
 | 
						|
				parent = elm;
 | 
						|
				elm = tmp;
 | 
						|
			}
 | 
						|
			RB_SET_BLACKRED(parent, gparent);
 | 
						|
			RB_ROTATE_RIGHT(head, gparent, tmp);
 | 
						|
		} else {
 | 
						|
			tmp = RB_LEFT(gparent);
 | 
						|
			if (tmp && RB_COLOR(tmp) == RB_RED) {
 | 
						|
				RB_COLOR(tmp) = RB_BLACK;
 | 
						|
				RB_SET_BLACKRED(parent, gparent);
 | 
						|
				elm = gparent;
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			if (RB_LEFT(parent) == elm) {
 | 
						|
				RB_ROTATE_RIGHT(head, parent, tmp);
 | 
						|
				tmp = parent;
 | 
						|
				parent = elm;
 | 
						|
				elm = tmp;
 | 
						|
			}
 | 
						|
			RB_SET_BLACKRED(parent, gparent);
 | 
						|
			RB_ROTATE_LEFT(head, gparent, tmp);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	RB_COLOR(head->rb_node) = RB_BLACK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void rb_remove_color(struct rb_root *head, struct rb_node *parent,
 | 
						|
			    struct rb_node *elm)
 | 
						|
{
 | 
						|
	struct rb_node *tmp;
 | 
						|
	while ((elm == NULL || RB_COLOR(elm) == RB_BLACK) &&
 | 
						|
	    elm != RB_HEAD(head)) {
 | 
						|
		if (RB_LEFT(parent) == elm) {
 | 
						|
			tmp = RB_RIGHT(parent);
 | 
						|
			if (RB_COLOR(tmp) == RB_RED) {
 | 
						|
				RB_SET_BLACKRED(tmp, parent);
 | 
						|
				RB_ROTATE_LEFT(head, parent, tmp);
 | 
						|
				tmp = RB_RIGHT(parent);
 | 
						|
			}
 | 
						|
			if ((RB_LEFT(tmp) == NULL ||
 | 
						|
			    RB_COLOR(RB_LEFT(tmp)) == RB_BLACK) &&
 | 
						|
			    (RB_RIGHT(tmp) == NULL ||
 | 
						|
			    RB_COLOR(RB_RIGHT(tmp)) == RB_BLACK)) {
 | 
						|
				RB_COLOR(tmp) = RB_RED;
 | 
						|
				elm = parent;
 | 
						|
				parent = RB_PARENT(elm);
 | 
						|
			} else {
 | 
						|
				if (RB_RIGHT(tmp) == NULL ||
 | 
						|
				    RB_COLOR(RB_RIGHT(tmp)) == RB_BLACK) {
 | 
						|
					struct rb_node *oleft;
 | 
						|
					if ((oleft = RB_LEFT(tmp)))
 | 
						|
						RB_COLOR(oleft) = RB_BLACK;
 | 
						|
					RB_COLOR(tmp) = RB_RED;
 | 
						|
					RB_ROTATE_RIGHT(head, tmp, oleft);
 | 
						|
					tmp = RB_RIGHT(parent);
 | 
						|
				}
 | 
						|
				RB_COLOR(tmp) = RB_COLOR(parent);
 | 
						|
				RB_COLOR(parent) = RB_BLACK;
 | 
						|
				if (RB_RIGHT(tmp))
 | 
						|
					RB_COLOR(RB_RIGHT(tmp)) = RB_BLACK;
 | 
						|
				RB_ROTATE_LEFT(head, parent, tmp);
 | 
						|
				elm = RB_HEAD(head);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			tmp = RB_LEFT(parent);
 | 
						|
			if (RB_COLOR(tmp) == RB_RED) {
 | 
						|
				RB_SET_BLACKRED(tmp, parent);
 | 
						|
				RB_ROTATE_RIGHT(head, parent, tmp);
 | 
						|
				tmp = RB_LEFT(parent);
 | 
						|
			}
 | 
						|
			if ((RB_LEFT(tmp) == NULL ||
 | 
						|
			    RB_COLOR(RB_LEFT(tmp)) == RB_BLACK) &&
 | 
						|
			    (RB_RIGHT(tmp) == NULL ||
 | 
						|
			    RB_COLOR(RB_RIGHT(tmp)) == RB_BLACK)) {
 | 
						|
				RB_COLOR(tmp) = RB_RED;
 | 
						|
				elm = parent;
 | 
						|
				parent = RB_PARENT(elm);
 | 
						|
			} else {
 | 
						|
				if (RB_LEFT(tmp) == NULL ||
 | 
						|
				    RB_COLOR(RB_LEFT(tmp)) == RB_BLACK) {
 | 
						|
					struct rb_node *oright;
 | 
						|
					if ((oright = RB_RIGHT(tmp)))
 | 
						|
						RB_COLOR(oright) = RB_BLACK;
 | 
						|
					RB_COLOR(tmp) = RB_RED;
 | 
						|
					RB_ROTATE_LEFT(head, tmp, oright);
 | 
						|
					tmp = RB_LEFT(parent);
 | 
						|
				}
 | 
						|
				RB_COLOR(tmp) = RB_COLOR(parent);
 | 
						|
				RB_COLOR(parent) = RB_BLACK;
 | 
						|
				if (RB_LEFT(tmp))
 | 
						|
					RB_COLOR(RB_LEFT(tmp)) = RB_BLACK;
 | 
						|
				RB_ROTATE_RIGHT(head, parent, tmp);
 | 
						|
				elm = RB_HEAD(head);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (elm)
 | 
						|
		RB_COLOR(elm) = RB_BLACK;
 | 
						|
}
 | 
						|
 | 
						|
/* Note name changed. Guess why :) */
 | 
						|
void rb_erase(struct rb_node *elm, struct rb_root *head)
 | 
						|
{
 | 
						|
	struct rb_node *child, *parent, *old = elm;
 | 
						|
	int color;
 | 
						|
	if (RB_LEFT(elm) == NULL)
 | 
						|
		child = RB_RIGHT(elm);
 | 
						|
	else if (RB_RIGHT(elm) == NULL)
 | 
						|
		child = RB_LEFT(elm);
 | 
						|
	else {
 | 
						|
		struct rb_node *left;
 | 
						|
		elm = RB_RIGHT(elm);
 | 
						|
		while ((left = RB_LEFT(elm)))
 | 
						|
			elm = left;
 | 
						|
		child = RB_RIGHT(elm);
 | 
						|
		parent = RB_PARENT(elm);
 | 
						|
		color = RB_COLOR(elm);
 | 
						|
		if (child)
 | 
						|
			RB_PARENT(child) = parent;
 | 
						|
		if (parent) {
 | 
						|
			if (RB_LEFT(parent) == elm)
 | 
						|
				RB_LEFT(parent) = child;
 | 
						|
			else
 | 
						|
				RB_RIGHT(parent) = child;
 | 
						|
			RB_AUGMENT(parent);
 | 
						|
		} else
 | 
						|
			RB_HEAD(head) = child;
 | 
						|
		if (RB_PARENT(elm) == old)
 | 
						|
			parent = elm;
 | 
						|
		*(elm) = *(old);
 | 
						|
		if (RB_PARENT(old)) {
 | 
						|
			if (RB_LEFT(RB_PARENT(old)) == old)
 | 
						|
				RB_LEFT(RB_PARENT(old)) = elm;
 | 
						|
			else
 | 
						|
				RB_RIGHT(RB_PARENT(old)) = elm;
 | 
						|
			RB_AUGMENT(RB_PARENT(old));
 | 
						|
		} else
 | 
						|
			RB_HEAD(head) = elm;
 | 
						|
		RB_PARENT(RB_LEFT(old)) = elm;
 | 
						|
		if (RB_RIGHT(old))
 | 
						|
			RB_PARENT(RB_RIGHT(old)) = elm;
 | 
						|
		if (parent) {
 | 
						|
			left = parent;
 | 
						|
			do {
 | 
						|
				RB_AUGMENT(left);
 | 
						|
			} while ((left = RB_PARENT(left)));
 | 
						|
		}
 | 
						|
		goto color;
 | 
						|
	}
 | 
						|
	parent = RB_PARENT(elm);
 | 
						|
	color = RB_COLOR(elm);
 | 
						|
	if (child)
 | 
						|
		RB_PARENT(child) = parent;
 | 
						|
	if (parent) {
 | 
						|
		if (RB_LEFT(parent) == elm)
 | 
						|
			RB_LEFT(parent) = child;
 | 
						|
		else
 | 
						|
			RB_RIGHT(parent) = child;
 | 
						|
		RB_AUGMENT(parent);
 | 
						|
	} else
 | 
						|
		RB_HEAD(head) = child;
 | 
						|
color:
 | 
						|
	if (color == RB_BLACK)
 | 
						|
		rb_remove_color(head, parent, child);
 | 
						|
}
 | 
						|
 | 
						|
struct rb_node *rb_next(struct rb_node *elm)
 | 
						|
{
 | 
						|
	if (RB_RIGHT(elm)) {
 | 
						|
		elm = RB_RIGHT(elm);
 | 
						|
		while (RB_LEFT(elm))
 | 
						|
			elm = RB_LEFT(elm);
 | 
						|
	} else {
 | 
						|
		if (RB_PARENT(elm) &&
 | 
						|
		    (elm == RB_LEFT(RB_PARENT(elm))))
 | 
						|
			elm = RB_PARENT(elm);
 | 
						|
		else {
 | 
						|
			while (RB_PARENT(elm) &&
 | 
						|
			    (elm == RB_RIGHT(RB_PARENT(elm))))
 | 
						|
				elm = RB_PARENT(elm);
 | 
						|
			elm = RB_PARENT(elm);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return (elm);
 | 
						|
}
 | 
						|
 | 
						|
struct rb_node *rb_prev(struct rb_node *elm)
 | 
						|
{
 | 
						|
	if (RB_LEFT(elm)) {
 | 
						|
		elm = RB_LEFT(elm);
 | 
						|
		while (RB_RIGHT(elm))
 | 
						|
			elm = RB_RIGHT(elm);
 | 
						|
	} else {
 | 
						|
		if (RB_PARENT(elm) &&
 | 
						|
		    (elm == RB_RIGHT(RB_PARENT(elm))))
 | 
						|
			elm = RB_PARENT(elm);
 | 
						|
		else {
 | 
						|
			while (RB_PARENT(elm) &&
 | 
						|
			    (elm == RB_LEFT(RB_PARENT(elm))))
 | 
						|
				elm = RB_PARENT(elm);
 | 
						|
			elm = RB_PARENT(elm);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return (elm);
 | 
						|
}
 | 
						|
 | 
						|
/* These ones are lifted from Linux -- but that's OK because I
 | 
						|
   wrote them. dwmw2. */
 | 
						|
struct rb_node *rb_first(struct rb_root *root)
 | 
						|
{
 | 
						|
        struct rb_node  *n;
 | 
						|
 | 
						|
        n = root->rb_node;
 | 
						|
        if (!n)
 | 
						|
                return 0;
 | 
						|
        while (n->rb_left)
 | 
						|
                n = n->rb_left;
 | 
						|
        return n;
 | 
						|
}
 | 
						|
 | 
						|
void rb_replace_node(struct rb_node *victim, struct rb_node *new,
 | 
						|
                     struct rb_root *root)
 | 
						|
{
 | 
						|
        struct rb_node *parent = victim->rb_parent;
 | 
						|
 | 
						|
        /* Set the surrounding nodes to point to the replacement */
 | 
						|
        if (parent) {
 | 
						|
                if (victim == parent->rb_left)
 | 
						|
                        parent->rb_left = new;
 | 
						|
                else
 | 
						|
                        parent->rb_right = new;
 | 
						|
        } else {
 | 
						|
                root->rb_node = new;
 | 
						|
        }
 | 
						|
        if (victim->rb_left)
 | 
						|
                victim->rb_left->rb_parent = new;
 | 
						|
        if (victim->rb_right)
 | 
						|
                victim->rb_right->rb_parent = new;
 | 
						|
 | 
						|
        /* Copy the pointers/colour from the victim to the replacement */
 | 
						|
        *new = *victim;
 | 
						|
}
 |