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