mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-23 16:20:26 -05:00
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:
parent
aeaa264d37
commit
b48cc913ff
2 changed files with 126 additions and 37 deletions
|
|
@ -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;
|
||||
|
|
|
|||
118
util/rbtree.h
118
util/rbtree.h
|
|
@ -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_ */
|
||||
|
|
|
|||
Loading…
Reference in a new issue