Rework rbtree to fit into unbound, doxygen comments.

git-svn-id: file:///svn/unbound/trunk@47 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-01-31 12:25:06 +00:00
parent aeaa264d37
commit b48cc913ff
2 changed files with 126 additions and 37 deletions

View file

@ -36,16 +36,21 @@
*
*/
#include <config.h>
/**
* \file
* Implementation of a redblack tree.
*/
#include <assert.h>
#include <stdlib.h>
#include "rbtree.h"
#include "config.h"
#include "log.h"
#include "util/rbtree.h"
/** Node colour black */
#define BLACK 0
/** Node colour red */
#define RED 1
/** the NULL node, global alloc */
rbnode_t rbtree_null_node = {
RBTREE_NULL, /* Parent. */
RBTREE_NULL, /* Left. */
@ -54,9 +59,13 @@ rbnode_t rbtree_null_node = {
BLACK /* Color. */
};
/** rotate subtree left (to preserve redblack property). */
static void rbtree_rotate_left(rbtree_t *rbtree, rbnode_t *node);
/** rotate subtree right (to preserve redblack property). */
static void rbtree_rotate_right(rbtree_t *rbtree, rbnode_t *node);
/** Fixup node colours when insert happened */
static void rbtree_insert_fixup(rbtree_t *rbtree, rbnode_t *node);
/** Fixup node colours when delete happened */
static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* child_parent);
/*
@ -66,12 +75,12 @@ static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* chi
*
*/
rbtree_t *
rbtree_create (region_type *region, int (*cmpf)(const void *, const void *))
rbtree_create (int (*cmpf)(const void *, const void *))
{
rbtree_t *rbtree;
/* Allocate memory for it */
rbtree = (rbtree_t *) region_alloc(region, sizeof(rbtree_t));
rbtree = (rbtree_t *) malloc(sizeof(rbtree_t));
if (!rbtree) {
return NULL;
}
@ -79,7 +88,6 @@ rbtree_create (region_type *region, int (*cmpf)(const void *, const void *))
/* Initialize it */
rbtree->root = RBTREE_NULL;
rbtree->count = 0;
rbtree->region = region;
rbtree->cmp = cmpf;
return rbtree;
@ -273,34 +281,37 @@ rbtree_search (rbtree_t *rbtree, const void *key)
}
}
/* helpers for delete */
/** helpers for delete: swap node colours */
static void swap_int8(uint8_t* x, uint8_t* y)
{
uint8_t t = *x; *x = *y; *y = t;
}
/** helpers for delete: swap node pointers */
static void swap_np(rbnode_t** x, rbnode_t** y)
{
rbnode_t* t = *x; *x = *y; *y = t;
}
/** Update parent pointers of child trees of 'parent'. */
static void change_parent_ptr(rbtree_t* rbtree, rbnode_t* parent, rbnode_t* old, rbnode_t* new)
{
if(parent == RBTREE_NULL)
{
assert(rbtree->root == old);
log_assert(rbtree->root == old);
if(rbtree->root == old) rbtree->root = new;
return;
}
assert(parent->left == old || parent->right == old
log_assert(parent->left == old || parent->right == old
|| parent->left == new || parent->right == new);
if(parent->left == old) parent->left = new;
if(parent->right == old) parent->right = new;
}
/** Update parent pointer of a node 'child'. */
static void change_child_ptr(rbnode_t* child, rbnode_t* old, rbnode_t* new)
{
if(child == RBTREE_NULL) return;
assert(child->parent == old || child->parent == new);
log_assert(child->parent == old || child->parent == new);
if(child->parent == old) child->parent = new;
}
@ -354,7 +365,7 @@ rbtree_delete(rbtree_t *rbtree, const void *key)
/* now delete to_delete (which is at the location where the smright previously was) */
}
assert(to_delete->left == RBTREE_NULL || to_delete->right == RBTREE_NULL);
log_assert(to_delete->left == RBTREE_NULL || to_delete->right == RBTREE_NULL);
if(to_delete->left != RBTREE_NULL) child = to_delete->left;
else child = to_delete->right;
@ -439,7 +450,7 @@ static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* chi
child_parent->color = BLACK;
return;
}
assert(sibling != RBTREE_NULL);
log_assert(sibling != RBTREE_NULL);
/* get a new sibling, by rotating at sibling. See which child
of sibling is red */
@ -473,13 +484,13 @@ static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* chi
child_parent->color = BLACK;
if(child_parent->right == child)
{
assert(sibling->left->color == RED);
log_assert(sibling->left->color == RED);
sibling->left->color = BLACK;
rbtree_rotate_right(rbtree, child_parent);
}
else
{
assert(sibling->right->color == RED);
log_assert(sibling->right->color == RED);
sibling->right->color = BLACK;
rbtree_rotate_left(rbtree, child_parent);
}
@ -491,7 +502,7 @@ rbtree_find_less_equal(rbtree_t *rbtree, const void *key, rbnode_t **result)
int r;
rbnode_t *node;
assert(result);
log_assert(result);
/* We start at root... */
node = rbtree->root;

View file

@ -36,70 +36,148 @@
*
*/
#ifndef _RBTREE_H_
#define _RBTREE_H_
/**
* Red black tree. Implementation taken from NSD 3.0.5, adjusted for use
* in unbound (memory allocation, logging and so on).
*/
#include "region-allocator.h"
#ifndef UTIL_RBTREE_H_
#define UTIL_RBTREE_H_
/*
/**
* This structure must be the first member of the data structure in
* the rbtree. This allows easy casting between an rbnode_t and the
* user data (poor man's inheritance).
*/
typedef struct rbnode_t rbnode_t;
/**
* The rbnore_t struct definition.
*/
struct rbnode_t {
/** parent in rbtree, RBTREE_NULL for root */
rbnode_t *parent;
/** left node (smaller items) */
rbnode_t *left;
/** right node (larger items) */
rbnode_t *right;
/** pointer to sorting key */
const void *key;
/** colour of this node */
uint8_t color;
};
/** The nullpointer, points to empty node */
#define RBTREE_NULL &rbtree_null_node
/** the global empty node */
extern rbnode_t rbtree_null_node;
/** An entire red black tree */
typedef struct rbtree_t rbtree_t;
/** definition for tree struct */
struct rbtree_t {
region_type *region;
/* The root of the red-black tree */
/** The root of the red-black tree */
rbnode_t *root;
/* The number of the nodes in the tree */
/** The number of the nodes in the tree */
size_t count;
/* Current node for walks... */
/** Current node for walks... */
rbnode_t *_node;
/* Key compare function. <0,0,>0 like strcmp. Return 0 on two NULL ptrs. */
/**
* Key compare function. <0,0,>0 like strcmp.
* Return 0 on two NULL ptrs.
*/
int (*cmp) (const void *, const void *);
};
/* rbtree.c */
rbtree_t *rbtree_create(region_type *region, int (*cmpf)(const void *, const void *));
/**
* Create new tree (malloced) with given key compare function.
* @param cmpf: compare function (like strcmp) takes pointers to two keys.
* @return: new tree, empty.
*/
rbtree_t *rbtree_create(int (*cmpf)(const void *, const void *));
/**
* Insert data into the tree.
* @param rbtree: tree to insert to.
* @param data: element to insert.
* @return: data ptr or NULL if key already present.
*/
rbnode_t *rbtree_insert(rbtree_t *rbtree, rbnode_t *data);
/* returns node that is now unlinked from the tree. User to delete it.
* returns 0 if node not present */
/**
* Delete element from tree.
* @param rbtree: tree to delete from.
* @param key: key of item to delete.
* @return: node that is now unlinked from the tree. User to delete it.
* returns 0 if node not present
*/
rbnode_t *rbtree_delete(rbtree_t *rbtree, const void *key);
/**
* Find key in tree. Returns NULL if not found.
* @param rbtree: tree to find in.
* @param key: key that must match.
* @return: node that fits or NULL.
*/
rbnode_t *rbtree_search(rbtree_t *rbtree, const void *key);
/* returns true if exact match in result. Else result points to <= element,
or NULL if key is smaller than the smallest key. */
int rbtree_find_less_equal(rbtree_t *rbtree, const void *key, rbnode_t **result);
/**
* Find, but match does not have to be exact.
* @param rbtree: tree to find in.
* @param key: key to find position of.
* @param result: set to the exact node if present, otherwise to element that
* precedes the position of key in the tree. NULL if no smaller element.
* @return: true if exact match in result. Else result points to <= element,
* or NULL if key is smaller than the smallest key.
*/
int rbtree_find_less_equal(rbtree_t *rbtree, const void *key,
rbnode_t **result);
/**
* Returns first (smallest) node in the tree
* @param rbtree: tree
* @return: smallest element or NULL if tree empty.
*/
rbnode_t *rbtree_first(rbtree_t *rbtree);
/**
* Returns last (largest) node in the tree
* @param rbtree: tree
* @return: largest element or NULL if tree empty.
*/
rbnode_t *rbtree_last(rbtree_t *rbtree);
/**
* Returns next larger node in the tree
* @param rbtree: tree
* @return: next larger element or NULL if no larger in tree.
*/
rbnode_t *rbtree_next(rbnode_t *rbtree);
/**
* Returns previous smaller node in the tree
* @param rbtree: tree
* @return: previous smaller element or NULL if no previous in tree.
*/
rbnode_t *rbtree_previous(rbnode_t *rbtree);
/**
* Macro to walk through the tree, sets k to key, d to data, for every element.
*/
#define RBTREE_WALK(rbtree, k, d) \
for((rbtree)->_node = rbtree_first(rbtree);\
(rbtree)->_node != RBTREE_NULL && ((k) = (rbtree)->_node->key) && \
((d) = (void *) (rbtree)->_node); (rbtree)->_node = rbtree_next((rbtree)->_node))
/* call with node=variable of struct* with rbnode_t as first element.
with type is the type of a pointer to that struct. */
/**
* call with node=variable of struct* with rbnode_t as first element.
* with type is the type of a pointer to that struct.
*/
#define RBTREE_FOR(node, type, rbtree) \
for(node=(type)rbtree_first(rbtree); \
(rbnode_t*)node != RBTREE_NULL; \
node = (type)rbtree_next((rbnode_t*)node))
#endif /* _RBTREE_H_ */
#endif /* UTIL_RBTREE_H_ */