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;
|
||
|
}
|