/* Plzip - A parallel version of the lzip data compressor
Copyright (C) 2009 Laszlo Ersek.
Copyright (C) 2009 Antonio Diaz Diaz.
This program 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 of the License, or
(at your option) any later version.
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 General Public License
along with this program. If not, see .
*/
#define _FILE_OFFSET_BITS 64
#include
#include "lacos_rbtree.h"
enum lacos_rbtree_color {
LACOS_RBTREE_RED,
LACOS_RBTREE_BLACK
};
struct lacos_rbtree_node {
void *data;
lacos_rbtree_node *parent,
*left,
*right;
lacos_rbtree_color color;
};
lacos_rbtree_node *
lacos_rbtree_find( lacos_rbtree_node *root, const void *key,
int (*cmp)(const void *cmp_key, const void *cmp_data))
{
int cmp_res;
while (root && (cmp_res = (*cmp)(key, root->data)))
root = cmp_res < 0 ? root->left : root->right;
return root;
}
lacos_rbtree_node *
lacos_rbtree_min( lacos_rbtree_node *root)
{
lacos_rbtree_node *tmp;
if (!root)
return 0;
while ((tmp = root->left))
root = tmp;
return root;
}
lacos_rbtree_node *
lacos_rbtree_max( lacos_rbtree_node *root)
{
lacos_rbtree_node *tmp;
if (!root)
return 0;
while ((tmp = root->right))
root = tmp;
return root;
}
lacos_rbtree_node *
lacos_rbtree_next( lacos_rbtree_node *current)
{
lacos_rbtree_node *tmp;
if (!current)
return 0;
if ((tmp = current->right)) {
while ((current = tmp->left))
tmp = current;
return tmp;
}
while ((tmp = current->parent) && current == tmp->right)
current = tmp;
return tmp;
}
lacos_rbtree_node *
lacos_rbtree_prev( lacos_rbtree_node *current)
{
lacos_rbtree_node *tmp;
if (!current)
return 0;
if ((tmp = current->left)) {
while ((current = tmp->right))
tmp = current;
return tmp;
}
while ((tmp = current->parent) && current == tmp->left)
current = tmp;
return tmp;
}
static void
lacos_rbtree_rotate_left( lacos_rbtree_node **new_root,
lacos_rbtree_node *rotation_root)
{
lacos_rbtree_node
*parent = rotation_root->parent,
*rc = rotation_root->right,
*rlc = rc->left;
rotation_root->right = rlc;
if (rlc)
rlc->parent = rotation_root;
rc->parent = parent;
if (parent)
if (rotation_root == parent->left)
parent->left = rc;
else
parent->right = rc;
else
*new_root = rc;
rc->left = rotation_root;
rotation_root->parent = rc;
}
static void
lacos_rbtree_rotate_right( lacos_rbtree_node **new_root,
lacos_rbtree_node *rotation_root)
{
lacos_rbtree_node
*parent = rotation_root->parent,
*lc = rotation_root->left,
*lrc = lc->right;
rotation_root->left = lrc;
if (lrc)
lrc->parent = rotation_root;
lc->parent = parent;
if (parent)
if (rotation_root == parent->left)
parent->left = lc;
else
parent->right = lc;
else
*new_root = lc;
lc->right = rotation_root;
rotation_root->parent = lc;
}
int
lacos_rbtree_insert( lacos_rbtree_node **new_root,
lacos_rbtree_node **new_node, void *new_data,
int (*cmp)(const void *cmp_new_data, const void *cmp_data),
void *(*alloc)(size_t size, void *alloc_ctl), void *alloc_ctl)
{
int cmp_res = 0;
lacos_rbtree_node *tmp = *new_root, *parent = 0;
while (tmp && (cmp_res = (*cmp)(new_data, tmp->data))) {
parent = tmp;
tmp = cmp_res < 0 ? tmp->left : tmp->right;
}
if (tmp) {
*new_node = tmp;
return -1;
}
if (!(*new_node = tmp = (lacos_rbtree_node *)(*alloc)(sizeof(lacos_rbtree_node),
alloc_ctl)))
return -1;
tmp->data = new_data;
tmp->parent = parent;
tmp->left = 0;
tmp->right = 0;
if (parent)
if (cmp_res < 0)
parent->left = tmp;
else
parent->right = tmp;
else {
*new_root = tmp;
tmp->color = LACOS_RBTREE_BLACK;
return 0;
}
{
lacos_rbtree_node *root = *new_root, *grandparent, *uncle;
tmp->color = LACOS_RBTREE_RED;
while (tmp != root && LACOS_RBTREE_RED == parent->color) {
grandparent = parent->parent;
if (parent == grandparent->left) {
uncle = grandparent->right;
if (uncle && LACOS_RBTREE_RED == uncle->color) {
parent->color = LACOS_RBTREE_BLACK;
uncle->color = LACOS_RBTREE_BLACK;
grandparent->color = LACOS_RBTREE_RED;
tmp = grandparent;
parent = tmp->parent;
}
else {
if (tmp == parent->right) {
tmp = parent;
lacos_rbtree_rotate_left(&root, tmp);
parent = tmp->parent;
grandparent = parent->parent;
}
parent->color = LACOS_RBTREE_BLACK;
grandparent->color = LACOS_RBTREE_RED;
lacos_rbtree_rotate_right(&root, grandparent);
}
}
else {
uncle = grandparent->left;
if (uncle && LACOS_RBTREE_RED == uncle->color) {
parent->color = LACOS_RBTREE_BLACK;
uncle->color = LACOS_RBTREE_BLACK;
grandparent->color = LACOS_RBTREE_RED;
tmp = grandparent;
parent = tmp->parent;
}
else {
if (tmp == parent->left) {
tmp = parent;
lacos_rbtree_rotate_right(&root, tmp);
parent = tmp->parent;
grandparent = parent->parent;
}
parent->color = LACOS_RBTREE_BLACK;
grandparent->color = LACOS_RBTREE_RED;
lacos_rbtree_rotate_left(&root, grandparent);
}
}
}
root->color = LACOS_RBTREE_BLACK;
*new_root = root;
}
return 0;
}
void
lacos_rbtree_delete( lacos_rbtree_node **new_root,
lacos_rbtree_node *old_node, void **old_data,
void (*dealloc)(void *ptr, void *alloc_ctl), void *alloc_ctl)
{
lacos_rbtree_node *child, *parent, *root = *new_root,
*old_node_left = old_node->left,
*old_node_right = old_node->right,
*old_node_parent = old_node->parent;
lacos_rbtree_color color_of_firstly_unlinked;
if (old_data)
*old_data = old_node->data;
if (old_node_left && old_node_right) {
lacos_rbtree_node
*to_relink = old_node_right,
*tmp = to_relink->left;
if (tmp) {
do {
to_relink = tmp;
tmp = tmp->left;
} while (tmp);
parent = to_relink->parent;
child = to_relink->right;
parent->left = child;
if (child)
child->parent = parent;
to_relink->right = old_node_right;
old_node_right->parent = to_relink;
}
else {
parent = old_node_right;
child = old_node_right->right;
}
to_relink->left = old_node_left;
old_node_left->parent = to_relink;
color_of_firstly_unlinked = to_relink->color;
to_relink->color = old_node->color;
to_relink->parent = old_node_parent;
if (old_node_parent)
if (old_node == old_node_parent->left)
old_node_parent->left = to_relink;
else
old_node_parent->right = to_relink;
else
root = to_relink;
}
else {
parent = old_node_parent;
child = old_node_left ? old_node_left : old_node_right;
color_of_firstly_unlinked = old_node->color;
if (child)
child->parent = parent;
if (old_node_parent)
if (old_node == old_node_parent->left)
old_node_parent->left = child;
else
old_node_parent->right = child;
else
root = child;
}
(*dealloc)(old_node, alloc_ctl);
if (LACOS_RBTREE_BLACK == color_of_firstly_unlinked) {
lacos_rbtree_node *brother, *left_nephew, *right_nephew;
int left_black, right_black;
while (child != root && (!child || LACOS_RBTREE_BLACK == child->color))
if (child == parent->left) {
brother = parent->right;
if (LACOS_RBTREE_RED == brother->color) {
brother->color = LACOS_RBTREE_BLACK;
parent->color = LACOS_RBTREE_RED;
lacos_rbtree_rotate_left(&root, parent);
brother = parent->right;
}
left_nephew = brother->left;
right_nephew = brother->right;
right_black = !right_nephew
|| LACOS_RBTREE_BLACK == right_nephew->color;
if ((!left_nephew || LACOS_RBTREE_BLACK == left_nephew->color)
&& right_black) {
brother->color = LACOS_RBTREE_RED;
child = parent;
parent = parent->parent;
}
else {
if (right_black) {
left_nephew->color = LACOS_RBTREE_BLACK;
brother->color = LACOS_RBTREE_RED;
lacos_rbtree_rotate_right(&root, brother);
brother = parent->right;
right_nephew = brother->right;
}
brother->color = parent->color;
parent->color = LACOS_RBTREE_BLACK;
right_nephew->color = LACOS_RBTREE_BLACK;
lacos_rbtree_rotate_left(&root, parent);
child = root;
break;
}
}
else {
brother = parent->left;
if (LACOS_RBTREE_RED == brother->color) {
brother->color = LACOS_RBTREE_BLACK;
parent->color = LACOS_RBTREE_RED;
lacos_rbtree_rotate_right(&root, parent);
brother = parent->left;
}
right_nephew = brother->right;
left_nephew = brother->left;
left_black = !left_nephew || LACOS_RBTREE_BLACK == left_nephew->color;
if ((!right_nephew || LACOS_RBTREE_BLACK == right_nephew->color)
&& left_black) {
brother->color = LACOS_RBTREE_RED;
child = parent;
parent = parent->parent;
}
else {
if (left_black) {
right_nephew->color = LACOS_RBTREE_BLACK;
brother->color = LACOS_RBTREE_RED;
lacos_rbtree_rotate_left(&root, brother);
brother = parent->left;
left_nephew = brother->left;
}
brother->color = parent->color;
parent->color = LACOS_RBTREE_BLACK;
left_nephew->color = LACOS_RBTREE_BLACK;
lacos_rbtree_rotate_right(&root, parent);
child = root;
break;
}
}
if (child)
child->color = LACOS_RBTREE_BLACK;
}
*new_root = root;
}