e1066143a4
This commit was SVN r28734.
572 строки
16 KiB
C
572 строки
16 KiB
C
/*
|
|
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
|
* University Research and Technology
|
|
* Corporation. All rights reserved.
|
|
* Copyright (c) 2004-2013 The University of Tennessee and The University
|
|
* of Tennessee Research Foundation. All rights
|
|
* reserved.
|
|
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
|
* University of Stuttgart. All rights reserved.
|
|
* Copyright (c) 2004-2005 The Regents of the University of California.
|
|
* All rights reserved.
|
|
* $COPYRIGHT$
|
|
*
|
|
* Additional copyrights may follow
|
|
*
|
|
* $HEADER$
|
|
*/
|
|
/*
|
|
* @file
|
|
*/
|
|
|
|
#include "ompi_config.h"
|
|
|
|
#include "ompi/class/ompi_rb_tree.h"
|
|
|
|
/* Private functions */
|
|
static void btree_insert(ompi_rb_tree_t *tree, ompi_rb_tree_node_t * node);
|
|
static void btree_delete_fixup(ompi_rb_tree_t *tree, ompi_rb_tree_node_t * x);
|
|
static ompi_rb_tree_node_t * btree_successor(ompi_rb_tree_t * tree,
|
|
ompi_rb_tree_node_t * node);
|
|
static ompi_rb_tree_node_t * ompi_rb_tree_find_node(ompi_rb_tree_t *tree, void *key);
|
|
static void left_rotate(ompi_rb_tree_t *tree, ompi_rb_tree_node_t * x);
|
|
static void right_rotate(ompi_rb_tree_t *tree, ompi_rb_tree_node_t * x);
|
|
static void inorder_destroy(ompi_rb_tree_t *tree, ompi_rb_tree_node_t * node);
|
|
static void inorder_traversal(ompi_rb_tree_t *tree,
|
|
ompi_rb_tree_condition_fn_t cond,
|
|
ompi_rb_tree_action_fn_t action,
|
|
ompi_rb_tree_node_t * node);
|
|
|
|
|
|
/**
|
|
* the constructor function. creates the free list to get the nodes from
|
|
*
|
|
* @param object the tree that is to be used
|
|
*
|
|
* @retval NONE
|
|
*/
|
|
static void ompi_rb_tree_construct(opal_object_t * object)
|
|
{
|
|
ompi_rb_tree_t * tree = (ompi_rb_tree_t *) object;
|
|
tree->root_ptr = NULL;
|
|
OBJ_CONSTRUCT(&(tree->free_list), ompi_free_list_t);
|
|
ompi_free_list_init_new(&(tree->free_list), sizeof(ompi_rb_tree_node_t),
|
|
opal_cache_line_size, OBJ_CLASS(ompi_rb_tree_node_t),
|
|
0,opal_cache_line_size,
|
|
0, -1 , 128, NULL);
|
|
}
|
|
|
|
/**
|
|
* the destructor function. Free the tree and destroys the free list.
|
|
*
|
|
* @param object the tree object
|
|
*/
|
|
static void ompi_rb_tree_destruct(opal_object_t * object)
|
|
{
|
|
if(NULL != ((ompi_rb_tree_t *)object)->root_ptr) {
|
|
ompi_rb_tree_destroy((ompi_rb_tree_t *) object);
|
|
}
|
|
OBJ_DESTRUCT(&(((ompi_rb_tree_t *)object)->free_list));
|
|
return;
|
|
}
|
|
|
|
/* declare the instance of the classes */
|
|
OBJ_CLASS_INSTANCE(ompi_rb_tree_node_t, ompi_free_list_item_t, NULL, NULL);
|
|
OBJ_CLASS_INSTANCE(ompi_rb_tree_t, opal_object_t, ompi_rb_tree_construct,
|
|
ompi_rb_tree_destruct);
|
|
|
|
/* Create the tree */
|
|
int ompi_rb_tree_init(ompi_rb_tree_t * tree,
|
|
ompi_rb_tree_comp_fn_t comp)
|
|
{
|
|
ompi_free_list_item_t * node;
|
|
/* we need to get memory for the root pointer from the free list */
|
|
OMPI_FREE_LIST_GET_MT(&(tree->free_list), node);
|
|
tree->root_ptr = (ompi_rb_tree_node_t *) node;
|
|
if (NULL == node) {
|
|
return OMPI_ERR_OUT_OF_RESOURCE;
|
|
}
|
|
|
|
OMPI_FREE_LIST_GET_MT(&(tree->free_list), node);
|
|
if (NULL == node) {
|
|
OMPI_FREE_LIST_RETURN_MT(&(tree->free_list), (ompi_free_list_item_t*)tree->root_ptr);
|
|
return OMPI_ERR_OUT_OF_RESOURCE;
|
|
}
|
|
tree->nill = (ompi_rb_tree_node_t *) node;
|
|
/* initialize tree->nill */
|
|
tree->nill->color = BLACK;
|
|
tree->nill->left = tree->nill;
|
|
tree->nill->right = tree->nill;
|
|
tree->nill->parent = tree->nill;
|
|
|
|
/* initialize the 'root' pointer */
|
|
tree->root_ptr->left = tree->nill;
|
|
tree->root_ptr->right = tree->nill;
|
|
tree->root_ptr->parent = tree->nill;
|
|
tree->root_ptr->color = BLACK;
|
|
|
|
tree->comp = comp;
|
|
|
|
/* set the tree size to zero */
|
|
tree->tree_size = 0;
|
|
|
|
return(OMPI_SUCCESS);
|
|
}
|
|
|
|
|
|
/* This inserts a node into the tree based on the passed values. */
|
|
int ompi_rb_tree_insert(ompi_rb_tree_t *tree, void * key, void * value)
|
|
{
|
|
ompi_rb_tree_node_t * y;
|
|
ompi_rb_tree_node_t * node;
|
|
ompi_free_list_item_t * item;
|
|
|
|
/* get the memory for a node */
|
|
OMPI_FREE_LIST_GET_MT(&(tree->free_list), item);
|
|
if (NULL == item) {
|
|
return OMPI_ERR_OUT_OF_RESOURCE;
|
|
}
|
|
node = (ompi_rb_tree_node_t *) item;
|
|
/* insert the data into the node */
|
|
node->key = key;
|
|
node->value = value;
|
|
|
|
/* insert the node into the tree */
|
|
btree_insert(tree, node);
|
|
|
|
/*do the rotations */
|
|
/* usually one would have to check for NULL, but because of the sentinal,
|
|
* we don't have to */
|
|
while (node->parent->color == RED) {
|
|
if (node->parent == node->parent->parent->left) {
|
|
y = node->parent->parent->right;
|
|
if (y->color == RED) {
|
|
node->parent->color = BLACK;
|
|
y->color = BLACK;
|
|
node->parent->parent->color = RED;
|
|
node = node->parent->parent;
|
|
} else {
|
|
if (node == node->parent->right) {
|
|
node = node->parent;
|
|
left_rotate(tree, node);
|
|
}
|
|
node->parent->color = BLACK;
|
|
node->parent->parent->color = RED;
|
|
right_rotate(tree, node->parent->parent);
|
|
}
|
|
} else {
|
|
y = node->parent->parent->left;
|
|
if (y->color == RED) {
|
|
node->parent->color = BLACK;
|
|
y->color = BLACK;
|
|
node->parent->parent->color = RED;
|
|
node = node->parent->parent;
|
|
} else {
|
|
if (node == node->parent->left) {
|
|
node = node->parent;
|
|
right_rotate(tree, node);
|
|
}
|
|
node->parent->color = BLACK;
|
|
node->parent->parent->color = RED;
|
|
left_rotate(tree, node->parent->parent);
|
|
}
|
|
}
|
|
}
|
|
/* after the rotations the root is black */
|
|
tree->root_ptr->left->color = BLACK;
|
|
return OMPI_SUCCESS;
|
|
}
|
|
|
|
/* Finds the node in the tree based on the key */
|
|
void * ompi_rb_tree_find_with(ompi_rb_tree_t *tree, void *key,
|
|
ompi_rb_tree_comp_fn_t compfn)
|
|
{
|
|
ompi_rb_tree_node_t * node;
|
|
int compvalue;
|
|
|
|
node = tree->root_ptr->left;
|
|
while (node != tree->nill) {
|
|
compvalue = compfn(key, node->key);
|
|
/* if the result of the comparison function is 0, we found it */
|
|
if (compvalue == 0) {
|
|
return(node->value);
|
|
}
|
|
/* else if it is less than 0, go left, else right */
|
|
node = ((compvalue < 0) ? node->left : node->right);
|
|
}
|
|
/* if we didn't find anything, return NULL */
|
|
return(NULL);
|
|
}
|
|
|
|
/* Finds the node in the tree based on the key and returns a pointer
|
|
* to the node. This is a bit a code duplication, but this has to be fast
|
|
* so we go ahead with the duplication */
|
|
static ompi_rb_tree_node_t * ompi_rb_tree_find_node(ompi_rb_tree_t *tree, void *key)
|
|
{
|
|
ompi_rb_tree_node_t * node;
|
|
int compvalue;
|
|
|
|
node = tree->root_ptr->left;
|
|
while (node != tree->nill) {
|
|
compvalue = tree->comp(key, node->key);
|
|
/* if the result of the comparison function is 0, we found it */
|
|
if (compvalue == 0) {
|
|
return(node);
|
|
}
|
|
/* else if it is less than 0, go left, else right */
|
|
node = ((compvalue < 0) ? node->left : node->right);
|
|
}
|
|
/* if we didn't find anything, return NULL */
|
|
return(NULL);
|
|
}
|
|
|
|
/* Delete a node from the tree based on the key */
|
|
int ompi_rb_tree_delete(ompi_rb_tree_t *tree, void *key)
|
|
{
|
|
ompi_rb_tree_node_t * p;
|
|
ompi_rb_tree_node_t * todelete;
|
|
ompi_rb_tree_node_t * y;
|
|
ompi_free_list_item_t * item;
|
|
|
|
p = ompi_rb_tree_find_node(tree, key);
|
|
if (NULL == p) {
|
|
return(OMPI_ERR_NOT_FOUND);
|
|
}
|
|
if ((p->left == tree->nill) || (p->right == tree->nill)) {
|
|
todelete = p;
|
|
} else {
|
|
todelete = btree_successor(tree, p);
|
|
}
|
|
|
|
if (todelete->left == tree->nill) {
|
|
y = todelete->right;
|
|
} else {
|
|
y = todelete->left;
|
|
}
|
|
|
|
y->parent = todelete->parent;
|
|
|
|
if (y->parent == tree->root_ptr) {
|
|
tree->root_ptr->left = y;
|
|
} else {
|
|
if (todelete == todelete->parent->left) {
|
|
todelete->parent->left = y;
|
|
} else {
|
|
todelete->parent->right = y;
|
|
}
|
|
}
|
|
|
|
if (todelete != p) {
|
|
p->key = todelete->key;
|
|
p->value = todelete->value;
|
|
}
|
|
|
|
if (todelete->color == BLACK) {
|
|
btree_delete_fixup(tree, y);
|
|
}
|
|
item = (ompi_free_list_item_t *) todelete;
|
|
OMPI_FREE_LIST_RETURN_MT(&(tree->free_list), item);
|
|
--tree->tree_size;
|
|
return(OMPI_SUCCESS);
|
|
}
|
|
|
|
|
|
/* Destroy the hashmap */
|
|
int ompi_rb_tree_destroy(ompi_rb_tree_t *tree)
|
|
{
|
|
ompi_free_list_item_t * item;
|
|
/* Recursive inorder traversal for delete */
|
|
|
|
inorder_destroy(tree, tree->root_ptr);
|
|
/* Now free the root -- root does not get free'd in the above
|
|
* inorder destroy */
|
|
item = (ompi_free_list_item_t *) tree->root_ptr;
|
|
OMPI_FREE_LIST_RETURN_MT(&(tree->free_list), item);
|
|
|
|
/* free the tree->nill node */
|
|
item = (ompi_free_list_item_t *) tree->nill;
|
|
OMPI_FREE_LIST_RETURN_MT(&(tree->free_list), item);
|
|
return(OMPI_SUCCESS);
|
|
}
|
|
|
|
|
|
/* Find the next inorder successor of a node */
|
|
|
|
static ompi_rb_tree_node_t * btree_successor(ompi_rb_tree_t * tree, ompi_rb_tree_node_t * node)
|
|
{
|
|
ompi_rb_tree_node_t * p;
|
|
|
|
if (node->right == tree->nill) {
|
|
p = node->parent;
|
|
while (node == p->right) {
|
|
node = p;
|
|
p = p->parent;
|
|
}
|
|
if(p == tree->root_ptr) {
|
|
return(tree->nill);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
p = node->right;
|
|
while(p->left != tree->nill) {
|
|
p = p->left;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
|
|
/* Insert an element in the normal binary search tree fashion */
|
|
/* this function goes through the tree and finds the leaf where
|
|
* the node will be inserted */
|
|
static void btree_insert(ompi_rb_tree_t *tree, ompi_rb_tree_node_t * node)
|
|
{
|
|
ompi_rb_tree_node_t * parent = tree->root_ptr;
|
|
ompi_rb_tree_node_t * n = parent->left; /* the real root of the tree */
|
|
|
|
/* set up initial values for the node */
|
|
node->color = RED;
|
|
node->parent = NULL;
|
|
node->left = tree->nill;
|
|
node->right = tree->nill;
|
|
|
|
/* find the leaf where we will insert the node */
|
|
while (n != tree->nill) {
|
|
parent = n;
|
|
n = ((tree->comp(node->key, n->key) <= 0) ? n->left : n->right);
|
|
}
|
|
|
|
/* place it on either the left or the right */
|
|
if((parent == tree->root_ptr) || (tree->comp(node->key, parent->key) <= 0)) {
|
|
parent->left = node;
|
|
} else {
|
|
parent->right = node;
|
|
}
|
|
|
|
/* set its parent and children */
|
|
node->parent = parent;
|
|
node->left = tree->nill;
|
|
node->right = tree->nill;
|
|
++(tree->tree_size);
|
|
return;
|
|
}
|
|
|
|
/* Fixup the balance of the btree after deletion */
|
|
static void btree_delete_fixup(ompi_rb_tree_t *tree, ompi_rb_tree_node_t * x)
|
|
{
|
|
ompi_rb_tree_node_t * w;
|
|
ompi_rb_tree_node_t * root = tree->root_ptr->left;
|
|
while ((x != root) && (x->color == BLACK)) {
|
|
if (x == x->parent->left) {
|
|
w = x->parent->right;
|
|
if (w->color == RED) {
|
|
w->color = BLACK;
|
|
x->parent->color = RED;
|
|
left_rotate(tree, x->parent);
|
|
w = x->parent->right;
|
|
}
|
|
if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
|
|
w->color = RED;
|
|
x = x->parent;
|
|
} else {
|
|
if (w->right->color == BLACK) {
|
|
w->left->color = BLACK;
|
|
w->color = RED;
|
|
right_rotate(tree, w);
|
|
w = x->parent->right;
|
|
}
|
|
w->color = x->parent->color;
|
|
x->parent->color = BLACK;
|
|
w->right->color = BLACK;
|
|
left_rotate(tree, x->parent);
|
|
x = root;
|
|
}
|
|
} else { /* right */
|
|
|
|
w = x->parent->left;
|
|
if (w->color == RED) {
|
|
w->color = BLACK;
|
|
x->parent->color = RED;
|
|
right_rotate(tree, x->parent);
|
|
w = x->parent->left;
|
|
}
|
|
if ((w->right->color == BLACK) && (w->left->color == BLACK)) {
|
|
w->color = RED;
|
|
x = x->parent;
|
|
} else {
|
|
if (w->left->color == BLACK) {
|
|
w->right->color = BLACK;
|
|
w->color = RED;
|
|
left_rotate(tree, w);
|
|
w = x->parent->left;
|
|
}
|
|
w->color = x->parent->color;
|
|
x->parent->color = BLACK;
|
|
w->left->color = BLACK;
|
|
right_rotate(tree, x->parent);
|
|
x = root;
|
|
}
|
|
}
|
|
}
|
|
|
|
x->color = BLACK;
|
|
return;
|
|
}
|
|
|
|
|
|
/* Free the nodes in inorder fashion */
|
|
|
|
static void
|
|
inorder_destroy(ompi_rb_tree_t *tree, ompi_rb_tree_node_t * node)
|
|
{
|
|
ompi_free_list_item_t * item;
|
|
|
|
if (node == tree->nill) {
|
|
return;
|
|
}
|
|
|
|
inorder_destroy(tree, node->left);
|
|
|
|
if (node->left != tree->nill) {
|
|
item = (ompi_free_list_item_t *) node->left;
|
|
--tree->tree_size;
|
|
OMPI_FREE_LIST_RETURN_MT(&(tree->free_list), item);
|
|
}
|
|
|
|
inorder_destroy(tree, node->right);
|
|
if (node->right != tree->nill) {
|
|
item = (ompi_free_list_item_t *) node->right;
|
|
--tree->tree_size;
|
|
OMPI_FREE_LIST_RETURN_MT(&(tree->free_list), item);
|
|
}
|
|
}
|
|
|
|
/* Try to access all the elements of the hashmap conditionally */
|
|
|
|
int ompi_rb_tree_traverse(ompi_rb_tree_t *tree,
|
|
ompi_rb_tree_condition_fn_t cond,
|
|
ompi_rb_tree_action_fn_t action)
|
|
{
|
|
if ((cond == NULL) || (action == NULL)) {
|
|
return(OMPI_ERROR);
|
|
}
|
|
|
|
inorder_traversal(tree, cond, action, tree->root_ptr->left);
|
|
|
|
return(OMPI_SUCCESS);
|
|
}
|
|
|
|
|
|
static void inorder_traversal(ompi_rb_tree_t *tree,
|
|
ompi_rb_tree_condition_fn_t cond,
|
|
ompi_rb_tree_action_fn_t action,
|
|
ompi_rb_tree_node_t * node)
|
|
{
|
|
if (node == tree->nill) {
|
|
return;
|
|
}
|
|
|
|
inorder_traversal(tree, cond, action, node->left);
|
|
|
|
if (cond(node->value)) {
|
|
action(node->key, node->value);
|
|
}
|
|
|
|
inorder_traversal(tree, cond, action, node->right);
|
|
}
|
|
|
|
/* Left rotate the tree */
|
|
/* basically what we want to do is to make x be the left child
|
|
* of its right child */
|
|
static void left_rotate(ompi_rb_tree_t *tree, ompi_rb_tree_node_t * x)
|
|
{
|
|
ompi_rb_tree_node_t * y;
|
|
|
|
y = x->right;
|
|
/* make the left child of y's parent be x if it is not the sentinal node*/
|
|
if (y->left != tree->nill) {
|
|
y->left->parent=x;
|
|
}
|
|
|
|
/* normlly we would have to check to see if we are at the root.
|
|
* however, the root sentinal takes care of it for us */
|
|
if (x == x->parent->left) {
|
|
x->parent->left = y;
|
|
} else {
|
|
x->parent->right = y;
|
|
}
|
|
/* the old parent of x is now y's parent */
|
|
y->parent = x->parent;
|
|
/* x's parent is y */
|
|
x->parent = y;
|
|
x->right = y->left;
|
|
y->left = x;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* Right rotate the tree */
|
|
/* basically what we want to do is to make x be the right child
|
|
* of its left child */
|
|
static void right_rotate(ompi_rb_tree_t *tree, ompi_rb_tree_node_t * x)
|
|
{
|
|
ompi_rb_tree_node_t * y;
|
|
|
|
y = x->left;
|
|
|
|
if(y->right != tree->nill) {
|
|
y->right->parent = x;
|
|
}
|
|
|
|
if (x == x->parent->left) {
|
|
x->parent->left = y;
|
|
} else {
|
|
x->parent->right = y;
|
|
}
|
|
|
|
y->parent = x->parent;
|
|
x->parent = y;
|
|
x->left = y->right;
|
|
y->right = x;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* returns the size of the tree */
|
|
int ompi_rb_tree_size(ompi_rb_tree_t *tree)
|
|
{
|
|
return(tree->tree_size);
|
|
}
|
|
|
|
/* below are a couple of debugging functions */
|
|
#if 0
|
|
#include <stdio.h>
|
|
static void inorder(ompi_rb_tree_t * tree, ompi_rb_tree_node_t * node);
|
|
static void print_inorder(ompi_rb_tree_t * tree);
|
|
|
|
void inorder(ompi_rb_tree_t * tree, ompi_rb_tree_node_t * node)
|
|
{
|
|
static int level = 0;
|
|
if (node == tree->nill) {
|
|
printf("nill\n");
|
|
return;
|
|
}
|
|
level++;
|
|
inorder(tree, node->left);
|
|
level--;
|
|
printf("%d, level: %d\n", *((int *)node->value), level);
|
|
level++;
|
|
inorder(tree, node->right);
|
|
level--;
|
|
}
|
|
|
|
|
|
void print_inorder(ompi_rb_tree_t *tree)
|
|
{
|
|
inorder(tree, tree->root_ptr->left);
|
|
}
|
|
|
|
#endif
|