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