Adding a new class which is a red black tree
-reviewed by Tim adding a small test program for the tree This commit was SVN r1437.
Этот коммит содержится в:
родитель
21ada98b99
Коммит
48f51861d3
@ -16,7 +16,8 @@ headers = \
|
||||
ompi_list.h \
|
||||
ompi_object.h \
|
||||
ompi_pointer_array.h \
|
||||
ompi_value_array.h
|
||||
ompi_value_array.h \
|
||||
ompi_rb_tree.h
|
||||
|
||||
liblfc_la_SOURCES = \
|
||||
$(headers) \
|
||||
@ -26,7 +27,8 @@ liblfc_la_SOURCES = \
|
||||
ompi_object.c \
|
||||
ompi_pointer_array.c \
|
||||
ompi_bitmap.c \
|
||||
ompi_value_array.c
|
||||
ompi_value_array.c \
|
||||
ompi_rb_tree.c
|
||||
|
||||
# Conditionally install the header files
|
||||
|
||||
|
547
src/class/ompi_rb_tree.c
Обычный файл
547
src/class/ompi_rb_tree.c
Обычный файл
@ -0,0 +1,547 @@
|
||||
/*
|
||||
* $HEADER$
|
||||
*/
|
||||
/*
|
||||
* @file
|
||||
*/
|
||||
|
||||
#include "class/ompi_rb_tree.h"
|
||||
|
||||
/* declare the instance of the classes */
|
||||
OBJ_CLASS_INSTANCE(ompi_rb_tree_node_t, ompi_list_item_t, NULL, NULL);
|
||||
OBJ_CLASS_INSTANCE(ompi_rb_tree_t, ompi_object_t, ompi_rb_tree_construct,
|
||||
ompi_rb_tree_destruct);
|
||||
|
||||
/* 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);
|
||||
|
||||
|
||||
|
||||
/* constructor */
|
||||
void ompi_rb_tree_construct(ompi_object_t * object)
|
||||
{
|
||||
ompi_rb_tree_t * tree = (ompi_rb_tree_t *) object;
|
||||
OBJ_CONSTRUCT(&(tree->free_list), ompi_free_list_t);
|
||||
ompi_free_list_init(&(tree->free_list), sizeof(ompi_rb_tree_node_t),
|
||||
OBJ_CLASS(ompi_rb_tree_node_t),
|
||||
0, -1 , 128, NULL);
|
||||
}
|
||||
|
||||
/* the destructor function */
|
||||
void ompi_rb_tree_destruct(ompi_object_t * object)
|
||||
{
|
||||
ompi_rb_tree_destroy((ompi_rb_tree_t *) object);
|
||||
OBJ_DESTRUCT(&(((ompi_rb_tree_t *)object)->free_list));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create the tree */
|
||||
int ompi_rb_tree_init(ompi_rb_tree_t * tree,
|
||||
ompi_rb_tree_comp_fn_t comp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
ompi_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, rc);
|
||||
tree->root_ptr = (ompi_rb_tree_node_t *) node;
|
||||
if (OMPI_SUCCESS != rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
OMPI_FREE_LIST_GET(&(tree->free_list), node, rc);
|
||||
if (OMPI_SUCCESS != rc) {
|
||||
return rc;
|
||||
}
|
||||
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_list_item_t * item;
|
||||
int rc;
|
||||
|
||||
/* get the memory for a node */
|
||||
OMPI_FREE_LIST_GET(&(tree->free_list), item, rc);
|
||||
if (OMPI_SUCCESS != rc) {
|
||||
return rc;
|
||||
}
|
||||
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(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->value);
|
||||
}
|
||||
/* else if it is less than 0, go left, else right */
|
||||
(compvalue < 0) ? (node = node->left) : (node = 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 */
|
||||
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 */
|
||||
(compvalue < 0) ? (node = node->left) : (node = 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_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_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_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_list_item_t *) tree->root_ptr;
|
||||
OMPI_FREE_LIST_RETURN(&(tree->free_list), item);
|
||||
--tree->tree_size;
|
||||
|
||||
/* free the tree->nill node */
|
||||
item = (ompi_list_item_t *) tree->nill;
|
||||
OMPI_FREE_LIST_RETURN(&(tree->free_list), item);
|
||||
return(OMPI_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
/* Find the next inorder successor of a node */
|
||||
|
||||
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 */
|
||||
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;
|
||||
(tree->comp(node->key, n->key) <= 0) ? (n = n->left) : (n = 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 */
|
||||
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 */
|
||||
|
||||
void
|
||||
inorder_destroy(ompi_rb_tree_t *tree, ompi_rb_tree_node_t * node)
|
||||
{
|
||||
ompi_list_item_t * item;
|
||||
|
||||
if (node == tree->nill) {
|
||||
return;
|
||||
}
|
||||
|
||||
inorder_destroy(tree, node->left);
|
||||
|
||||
--tree->tree_size;
|
||||
|
||||
if (node->left != tree->nill) {
|
||||
item = (ompi_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_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 */
|
||||
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 */
|
||||
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 = y;
|
||||
}
|
||||
|
||||
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
|
186
src/class/ompi_rb_tree.h
Обычный файл
186
src/class/ompi_rb_tree.h
Обычный файл
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
/** @file
|
||||
*
|
||||
* A red black tree
|
||||
*/
|
||||
|
||||
#ifndef OMPI_RB_TREE_H
|
||||
#define OMPI_RB_TREE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "include/constants.h"
|
||||
#include "class/ompi_object.h"
|
||||
#include "class/ompi_free_list.h"
|
||||
|
||||
/*
|
||||
* Data structures and datatypes
|
||||
*/
|
||||
|
||||
/**
|
||||
* red and black enum
|
||||
*/
|
||||
typedef enum {RED, BLACK} ompi_rb_tree_nodecolor_t;
|
||||
|
||||
/**
|
||||
* node data structure
|
||||
*/
|
||||
struct ompi_rb_tree_node_t
|
||||
{
|
||||
ompi_list_item_t super; /**< the parent class */
|
||||
ompi_rb_tree_nodecolor_t color; /**< the node color */
|
||||
struct ompi_rb_tree_node_t * parent;/**< the parent node, can be NULL */
|
||||
struct ompi_rb_tree_node_t * left; /**< the left child - can be nill */
|
||||
struct ompi_rb_tree_node_t * right; /**< the right child - can be nill */
|
||||
void *key; /**< a pointer to the key */
|
||||
void *value; /**< a pointer to the value */
|
||||
};
|
||||
typedef struct ompi_rb_tree_node_t ompi_rb_tree_node_t;
|
||||
|
||||
/**
|
||||
* the compare function typedef. This function is used to compare 2 nodes.
|
||||
*/
|
||||
typedef int (*ompi_rb_tree_comp_fn_t)(void *key1, void *key2);
|
||||
|
||||
/**
|
||||
* the data structure that holds all the needed information about the tree.
|
||||
*/
|
||||
struct ompi_rb_tree_t {
|
||||
ompi_object_t parent; /**< the parent class */
|
||||
/* this root pointer doesn't actually point to the root of the tree.
|
||||
* rather, it points to a sentinal node who's left branch is the real
|
||||
* root of the tree. This is done to eliminate special cases */
|
||||
ompi_rb_tree_node_t * root_ptr;/**< a pointer to the root of the tree */
|
||||
ompi_rb_tree_node_t * nill; /**< the nill sentinal node */
|
||||
ompi_rb_tree_comp_fn_t comp; /**< the compare function */
|
||||
ompi_free_list_t free_list; /**< the free list to get the memory from */
|
||||
size_t tree_size; /**< the size of the tree */
|
||||
};
|
||||
typedef struct ompi_rb_tree_t ompi_rb_tree_t;
|
||||
|
||||
/** declare the tree node as a class */
|
||||
OBJ_CLASS_DECLARATION(ompi_rb_tree_node_t);
|
||||
/** declare the tree as a class */
|
||||
OBJ_CLASS_DECLARATION(ompi_rb_tree_t);
|
||||
|
||||
/* Function pointers for map traversal function */
|
||||
/**
|
||||
* this function is used for the ompi_rb_tree_traverse function.
|
||||
* it is passed a pointer to the value for each node and, if it returns
|
||||
* a one, the action function is called on that node. Otherwise, the node is ignored.
|
||||
*/
|
||||
typedef int (*ompi_rb_tree_condition_fn_t)(void *);
|
||||
/**
|
||||
* this function is uused for the user to perform any action on the passed
|
||||
* values. The first argument is the key and the second is the value.
|
||||
* note that this function SHOULD NOT modify the keys, as that would
|
||||
* mess up the tree.
|
||||
*/
|
||||
typedef void (*ompi_rb_tree_action_fn_t)(void *, void *);
|
||||
|
||||
/*
|
||||
* Public function protoypes
|
||||
*/
|
||||
|
||||
/**
|
||||
* the construct function. creates the free list to get the nodes from
|
||||
*
|
||||
* @param object the tree that is to be used
|
||||
*
|
||||
* @retval NONE
|
||||
*/
|
||||
void ompi_rb_tree_construct(ompi_object_t * object);
|
||||
|
||||
/**
|
||||
* the destruct function. tries to free the tree and destroys the free list
|
||||
*
|
||||
* @param object the tree object
|
||||
*/
|
||||
void ompi_rb_tree_destruct(ompi_object_t * object);
|
||||
|
||||
/**
|
||||
* the function creates a new tree
|
||||
*
|
||||
* @param tree a pointer to an allocated area of memory for the main
|
||||
* tree data structure.
|
||||
* @param comp a pointer to the function to use for comaparing 2 nodes
|
||||
*
|
||||
* @retval OMPI_SUCCESS if it is successful
|
||||
* @retval OMPI_ERR_TEMP_OUT_OF_RESOURCE if unsuccessful
|
||||
*/
|
||||
int ompi_rb_tree_init(ompi_rb_tree_t * tree, ompi_rb_tree_comp_fn_t comp);
|
||||
|
||||
|
||||
/**
|
||||
* inserts a node into the tree
|
||||
*
|
||||
* @param tree a pointer to the tree data structure
|
||||
* @param key the key for the node
|
||||
* @param value the value for the node
|
||||
*
|
||||
* @retval OMPI_SUCCESS
|
||||
* @retval OMPI_ERR_TEMP_OUT_OF_RESOURCE if unsuccessful
|
||||
*/
|
||||
int ompi_rb_tree_insert(ompi_rb_tree_t *tree, void * key, void * value);
|
||||
|
||||
/**
|
||||
* finds a value in the tree based on the passed key
|
||||
*
|
||||
* @param tree a pointer to the tree data structure
|
||||
* @param key a pointer to the key
|
||||
*
|
||||
* @retval pointer to the value if found
|
||||
* @retval NULL if not found
|
||||
*/
|
||||
void * ompi_rb_tree_find(ompi_rb_tree_t *tree, void *key);
|
||||
|
||||
/**
|
||||
* deletes a node based on its key
|
||||
*
|
||||
* @param tree a pointer to the tree data structure
|
||||
* @param key a pointer to the key
|
||||
*
|
||||
* @retval OMPI_SUCCESS if the node is found and deleted
|
||||
* @retval OMPI_ERR_NOT_FOUND if the node is not found
|
||||
*/
|
||||
int ompi_rb_tree_delete(ompi_rb_tree_t *tree, void *key);
|
||||
|
||||
/**
|
||||
* frees all the nodes on the tree
|
||||
*
|
||||
* @param tree a pointer to the tree data structure
|
||||
*
|
||||
* @retval OMPI_SUCCESS
|
||||
*/
|
||||
int ompi_rb_tree_destroy(ompi_rb_tree_t *tree);
|
||||
|
||||
/**
|
||||
* traverses the entire tree, performing the cond function on each of the
|
||||
* values and if it returns one it performs the action function on the values
|
||||
*
|
||||
* @param tree a pointer to the tree
|
||||
* @param cond a pointer to the condition function
|
||||
* @param action a pointer to the action function
|
||||
*
|
||||
* @retval OMPI_SUCCESS
|
||||
* @retval OMPI_FAILURE if there is an error
|
||||
*/
|
||||
int ompi_rb_tree_traverse(ompi_rb_tree_t *tree,
|
||||
ompi_rb_tree_condition_fn_t cond,
|
||||
ompi_rb_tree_action_fn_t action);
|
||||
|
||||
/**
|
||||
* returns the size of the tree
|
||||
*
|
||||
* @param tree a pointer to the tree data structure
|
||||
*
|
||||
* @retval int the nuber of items on the tree
|
||||
*/
|
||||
int ompi_rb_tree_size(ompi_rb_tree_t *tree);
|
||||
|
||||
|
||||
#endif /* OMPI_RB_TREE_H */
|
||||
|
@ -11,7 +11,8 @@ noinst_PROGRAMS = \
|
||||
ompi_hash_table \
|
||||
ompi_list \
|
||||
ompi_value_array \
|
||||
ompi_pointer_array
|
||||
ompi_pointer_array \
|
||||
ompi_rb_tree
|
||||
|
||||
ompi_bitmap_SOURCES = ompi_bitmap.c
|
||||
ompi_bitmap_LDADD = \
|
||||
@ -76,4 +77,16 @@ ompi_value_array_LDADD = \
|
||||
$(top_builddir)/test/support/libsupport.la
|
||||
ompi_value_array_DEPENDENCIES = $(ompi_value_array_LDADD)
|
||||
|
||||
|
||||
ompi_rb_tree_SOURCES = ompi_rb_tree.c
|
||||
ompi_rb_tree_LDADD = \
|
||||
$(top_builddir)/test/support/libsupport.la \
|
||||
$(top_builddir)/src/class/ompi_free_list.lo \
|
||||
$(top_builddir)/src/class/ompi_rb_tree.lo \
|
||||
$(top_builddir)/src/class/ompi_object.lo \
|
||||
$(top_builddir)/src/class/ompi_list.lo \
|
||||
$(top_builddir)/src/threads/mutex.lo \
|
||||
$(top_builddir)/src/threads/mutex_pthread.lo \
|
||||
$(top_builddir)/src/threads/mutex_spinlock.lo \
|
||||
$(top_builddir)/src/util/output.lo \
|
||||
$(top_builddir)/src/util/malloc.lo
|
||||
ompi_rb_tree_DEPENDENCIES = $(ompi_rb_tree_LDADD)
|
||||
|
169
test/class/ompi_rb_tree.c
Обычный файл
169
test/class/ompi_rb_tree.c
Обычный файл
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "support.h"
|
||||
#include "class/ompi_rb_tree.h"
|
||||
|
||||
int keys[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7
|
||||
};
|
||||
|
||||
int values[] = {
|
||||
10, 11, 12, 13, 14, 15, 16, 17
|
||||
};
|
||||
|
||||
int comp_fn(void * ele1, void * ele2);
|
||||
|
||||
void test1(void);
|
||||
|
||||
int comp_fn(void * ele1, void * ele2)
|
||||
{
|
||||
if(*((int *) ele1) > *((int *) ele2)) {
|
||||
return(1);
|
||||
}
|
||||
if(*((int *) ele1) < *((int *) ele2)) {
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void test1(void)
|
||||
{
|
||||
ompi_rb_tree_t tree;
|
||||
int rc;
|
||||
void * result;
|
||||
|
||||
OBJ_CONSTRUCT(&tree, ompi_rb_tree_t);
|
||||
rc = ompi_rb_tree_init(&tree, comp_fn);
|
||||
if(!test_verify_int(OMPI_SUCCESS, rc)) {
|
||||
test_failure("failed to properly initialize the tree");
|
||||
}
|
||||
|
||||
rc = ompi_rb_tree_insert(&tree, &keys[0], &values[0]);
|
||||
if(!test_verify_int(OMPI_SUCCESS, rc)) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
result = ompi_rb_tree_find(&tree, &keys[0]);
|
||||
if(NULL == result) {
|
||||
test_failure("lookup returned null!");
|
||||
}
|
||||
if(!test_verify_int(values[0], *((int *) result))) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
|
||||
rc = ompi_rb_tree_insert(&tree, &keys[1], &values[1]);
|
||||
if(!test_verify_int(OMPI_SUCCESS, rc)) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
result = ompi_rb_tree_find(&tree, &keys[1]);
|
||||
if(NULL == result) {
|
||||
test_failure("lookup returned null!");
|
||||
}
|
||||
if(!test_verify_int(values[1], *((int *) result))) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
|
||||
rc = ompi_rb_tree_insert(&tree, &keys[2], &values[2]);
|
||||
if(!test_verify_int(OMPI_SUCCESS, rc)) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
result = ompi_rb_tree_find(&tree, &keys[2]);
|
||||
if(NULL == result) {
|
||||
test_failure("lookup returned null!");
|
||||
}
|
||||
if(!test_verify_int(values[2], *((int *) result))) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
|
||||
rc = ompi_rb_tree_insert(&tree, &keys[3], &values[3]);
|
||||
if(!test_verify_int(OMPI_SUCCESS, rc)) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
result = ompi_rb_tree_find(&tree, &keys[3]);
|
||||
if(NULL == result) {
|
||||
test_failure("lookup returned null!");
|
||||
}
|
||||
if(!test_verify_int(values[3], *((int *) result))) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
|
||||
rc = ompi_rb_tree_insert(&tree, &keys[4], &values[4]);
|
||||
if(!test_verify_int(OMPI_SUCCESS, rc)) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
result = ompi_rb_tree_find(&tree, &keys[4]);
|
||||
if(NULL == result) {
|
||||
test_failure("lookup returned null!");
|
||||
}
|
||||
if(!test_verify_int(values[4], *((int *) result))) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
|
||||
rc = ompi_rb_tree_insert(&tree, &keys[5], &values[5]);
|
||||
if(!test_verify_int(OMPI_SUCCESS, rc)) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
result = ompi_rb_tree_find(&tree, &keys[5]);
|
||||
if(NULL == result) {
|
||||
test_failure("lookup returned null!");
|
||||
}
|
||||
if(!test_verify_int(values[5], *((int *) result))) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
|
||||
rc = ompi_rb_tree_insert(&tree, &keys[6], &values[6]);
|
||||
if(!test_verify_int(OMPI_SUCCESS, rc)) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
result = ompi_rb_tree_find(&tree, &keys[6]);
|
||||
if(NULL == result) {
|
||||
test_failure("lookup returned null!");
|
||||
}
|
||||
if(!test_verify_int(values[6], *((int *) result))) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
|
||||
rc = ompi_rb_tree_insert(&tree, &keys[7], &values[7]);
|
||||
if(!test_verify_int(OMPI_SUCCESS, rc)) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
result = ompi_rb_tree_find(&tree, &keys[7]);
|
||||
if(NULL == result) {
|
||||
test_failure("lookup returned null!");
|
||||
}
|
||||
if(!test_verify_int(values[7], *((int *) result))) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
|
||||
rc = ompi_rb_tree_size(&tree);
|
||||
if(!test_verify_int(8, rc)) {
|
||||
test_failure("failed to properly insert a new node");
|
||||
}
|
||||
|
||||
rc = ompi_rb_tree_delete(&tree, &keys[0]);
|
||||
if(!test_verify_int(OMPI_SUCCESS, rc)) {
|
||||
test_failure("failed to properly delete a node");
|
||||
}
|
||||
result = ompi_rb_tree_find(&tree, &keys[0]);
|
||||
if(NULL != result) {
|
||||
test_failure("lookup returned a value instead of null!");
|
||||
} else {
|
||||
test_success();
|
||||
}
|
||||
|
||||
OBJ_DESTRUCT(&tree);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* local variables */
|
||||
test_init("ompi_rb_tree_t");
|
||||
|
||||
test1();
|
||||
|
||||
return test_finalize();
|
||||
}
|
Загрузка…
x
Ссылка в новой задаче
Block a user