1
1
openmpi/ompi/class/ompi_rb_tree.c
George Bosilca c9e5ab9ed1 Our macros for the OMPI-level free list had one extra argument, a possible return
value to signal that the operation of retrieving the element from the free list
failed. However in this case the returned pointer was set to NULL as well, so the
error code was redundant. Moreover, this was a continuous source of warnings when
the picky mode is on.

The attached parch remove the rc argument from the OMPI_FREE_LIST_GET and
OMPI_FREE_LIST_WAIT macros, and change to check if the item is NULL instead of
using the return code.

This commit was SVN r28722.
2013-07-04 08:34:37 +00:00

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(&(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(&(tree->free_list), node);
if (NULL == node) {
OMPI_FREE_LIST_RETURN(&(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(&(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(&(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(&(tree->free_list), item);
/* free the tree->nill node */
item = (ompi_free_list_item_t *) tree->nill;
OMPI_FREE_LIST_RETURN(&(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(&(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(&(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