]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Copied over rbtree. literally now, will adjust.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Wed, 31 Jan 2007 11:57:22 +0000 (11:57 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Wed, 31 Jan 2007 11:57:22 +0000 (11:57 +0000)
git-svn-id: file:///svn/unbound/trunk@46 be551aaa-1e26-0410-a405-d3ace91eadb9

daemon/worker.c
doc/Changelog
util/rbtree.c [new file with mode: 0644]
util/rbtree.h [new file with mode: 0644]

index 2aff3bb63a84c39bb2ebb66a9b14e96f776b8bc7..ca2b5f43a67b3fa33cb848b460889e2d6c84681f 100644 (file)
@@ -52,7 +52,9 @@ static void worker_process_query(struct worker* worker)
        
 }
 
-/** check request sanity. Returns error code, 0 OK, or -1 discard. */
+/** check request sanity. Returns error code, 0 OK, or -1 discard. 
+ * @param pkt: the wire packet to examine for sanity.
+*/
 static int worker_check_request(ldns_buffer* pkt)
 {
        if(ldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
index c620816e4e13ac120e21e5dfdd1e412c40777dcf..31a420d35ca0a2e9e31b4f229ec18d078f98c151 100644 (file)
@@ -4,6 +4,7 @@
        - Added UDP recv to netevent, worker callback for udp.
        - netevent communication reply storage structure.
        - minimal query header sanity checking for worker.
+       - copied over rbtree implementation from NSD (BSD licensed too).
 
 30 January 2007: Wouter
        - links in example/ldns-testpkts.c and .h for premade packet support.
diff --git a/util/rbtree.c b/util/rbtree.c
new file mode 100644 (file)
index 0000000..aaca1a0
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ * rbtree.c -- generic red black tree
+ *
+ * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ * 
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "rbtree.h"
+
+#define        BLACK   0
+#define        RED     1
+
+rbnode_t       rbtree_null_node = {
+       RBTREE_NULL,            /* Parent.  */
+       RBTREE_NULL,            /* Left.  */
+       RBTREE_NULL,            /* Right.  */
+       NULL,                   /* Key.  */
+       BLACK                   /* Color.  */
+};
+
+static void rbtree_rotate_left(rbtree_t *rbtree, rbnode_t *node);
+static void rbtree_rotate_right(rbtree_t *rbtree, rbnode_t *node);
+static void rbtree_insert_fixup(rbtree_t *rbtree, rbnode_t *node);
+static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* child_parent);
+
+/*
+ * Creates a new red black tree, intializes and returns a pointer to it.
+ *
+ * Return NULL on failure.
+ *
+ */
+rbtree_t *
+rbtree_create (region_type *region, int (*cmpf)(const void *, const void *))
+{
+       rbtree_t *rbtree;
+
+       /* Allocate memory for it */
+       rbtree = (rbtree_t *) region_alloc(region, sizeof(rbtree_t));
+       if (!rbtree) {
+               return NULL;
+       }
+
+       /* Initialize it */
+       rbtree->root = RBTREE_NULL;
+       rbtree->count = 0;
+       rbtree->region = region;
+       rbtree->cmp = cmpf;
+
+       return rbtree;
+}
+
+/*
+ * Rotates the node to the left.
+ *
+ */
+static void
+rbtree_rotate_left(rbtree_t *rbtree, rbnode_t *node)
+{
+       rbnode_t *right = node->right;
+       node->right = right->left;
+       if (right->left != RBTREE_NULL)
+               right->left->parent = node;
+
+       right->parent = node->parent;
+
+       if (node->parent != RBTREE_NULL) {
+               if (node == node->parent->left) {
+                       node->parent->left = right;
+               } else  {
+                       node->parent->right = right;
+               }
+       } else {
+               rbtree->root = right;
+       }
+       right->left = node;
+       node->parent = right;
+}
+
+/*
+ * Rotates the node to the right.
+ *
+ */
+static void
+rbtree_rotate_right(rbtree_t *rbtree, rbnode_t *node)
+{
+       rbnode_t *left = node->left;
+       node->left = left->right;
+       if (left->right != RBTREE_NULL)
+               left->right->parent = node;
+
+       left->parent = node->parent;
+
+       if (node->parent != RBTREE_NULL) {
+               if (node == node->parent->right) {
+                       node->parent->right = left;
+               } else  {
+                       node->parent->left = left;
+               }
+       } else {
+               rbtree->root = left;
+       }
+       left->right = node;
+       node->parent = left;
+}
+
+static void
+rbtree_insert_fixup(rbtree_t *rbtree, rbnode_t *node)
+{
+       rbnode_t        *uncle;
+
+       /* While not at the root and need fixing... */
+       while (node != rbtree->root && node->parent->color == RED) {
+               /* If our parent is left child of our grandparent... */
+               if (node->parent == node->parent->parent->left) {
+                       uncle = node->parent->parent->right;
+
+                       /* If our uncle is red... */
+                       if (uncle->color == RED) {
+                               /* Paint the parent and the uncle black... */
+                               node->parent->color = BLACK;
+                               uncle->color = BLACK;
+
+                               /* And the grandparent red... */
+                               node->parent->parent->color = RED;
+
+                               /* And continue fixing the grandparent */
+                               node = node->parent->parent;
+                       } else {                                /* Our uncle is black... */
+                               /* Are we the right child? */
+                               if (node == node->parent->right) {
+                                       node = node->parent;
+                                       rbtree_rotate_left(rbtree, node);
+                               }
+                               /* Now we're the left child, repaint and rotate... */
+                               node->parent->color = BLACK;
+                               node->parent->parent->color = RED;
+                               rbtree_rotate_right(rbtree, node->parent->parent);
+                       }
+               } else {
+                       uncle = node->parent->parent->left;
+
+                       /* If our uncle is red... */
+                       if (uncle->color == RED) {
+                               /* Paint the parent and the uncle black... */
+                               node->parent->color = BLACK;
+                               uncle->color = BLACK;
+
+                               /* And the grandparent red... */
+                               node->parent->parent->color = RED;
+
+                               /* And continue fixing the grandparent */
+                               node = node->parent->parent;
+                       } else {                                /* Our uncle is black... */
+                               /* Are we the right child? */
+                               if (node == node->parent->left) {
+                                       node = node->parent;
+                                       rbtree_rotate_right(rbtree, node);
+                               }
+                               /* Now we're the right child, repaint and rotate... */
+                               node->parent->color = BLACK;
+                               node->parent->parent->color = RED;
+                               rbtree_rotate_left(rbtree, node->parent->parent);
+                       }
+               }
+       }
+       rbtree->root->color = BLACK;
+}
+
+
+/*
+ * Inserts a node into a red black tree.
+ *
+ * Returns NULL on failure or the pointer to the newly added node
+ * otherwise.
+ */
+rbnode_t *
+rbtree_insert (rbtree_t *rbtree, rbnode_t *data)
+{
+       /* XXX Not necessary, but keeps compiler quiet... */
+       int r = 0;
+
+       /* We start at the root of the tree */
+       rbnode_t        *node = rbtree->root;
+       rbnode_t        *parent = RBTREE_NULL;
+
+       /* Lets find the new parent... */
+       while (node != RBTREE_NULL) {
+               /* Compare two keys, do we have a duplicate? */
+               if ((r = rbtree->cmp(data->key, node->key)) == 0) {
+                       return NULL;
+               }
+               parent = node;
+
+               if (r < 0) {
+                       node = node->left;
+               } else {
+                       node = node->right;
+               }
+       }
+
+       /* Initialize the new node */
+       data->parent = parent;
+       data->left = data->right = RBTREE_NULL;
+       data->color = RED;
+       rbtree->count++;
+
+       /* Insert it into the tree... */
+       if (parent != RBTREE_NULL) {
+               if (r < 0) {
+                       parent->left = data;
+               } else {
+                       parent->right = data;
+               }
+       } else {
+               rbtree->root = data;
+       }
+
+       /* Fix up the red-black properties... */
+       rbtree_insert_fixup(rbtree, data);
+
+       return data;
+}
+
+/*
+ * Searches the red black tree, returns the data if key is found or NULL otherwise.
+ *
+ */
+rbnode_t *
+rbtree_search (rbtree_t *rbtree, const void *key)
+{
+       rbnode_t *node;
+
+       if (rbtree_find_less_equal(rbtree, key, &node)) {
+               return node;
+       } else {
+               return NULL;
+       }
+}
+
+/* helpers for delete */
+static void swap_int8(uint8_t* x, uint8_t* y) 
+{ 
+       uint8_t t = *x; *x = *y; *y = t; 
+}
+
+static void swap_np(rbnode_t** x, rbnode_t** y) 
+{
+       rbnode_t* t = *x; *x = *y; *y = t; 
+}
+
+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);
+               if(rbtree->root == old) rbtree->root = new;
+               return;
+       }
+       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;
+}
+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);
+       if(child->parent == old) child->parent = new;
+}
+
+rbnode_t* 
+rbtree_delete(rbtree_t *rbtree, const void *key)
+{
+       rbnode_t *to_delete;
+       rbnode_t *child;
+       if((to_delete = rbtree_search(rbtree, key)) == 0) return 0;
+       rbtree->count--;
+
+       /* make sure we have at most one non-leaf child */
+       if(to_delete->left != RBTREE_NULL && to_delete->right != RBTREE_NULL)
+       {
+               /* swap with smallest from right subtree (or largest from left) */
+               rbnode_t *smright = to_delete->right;
+               while(smright->left != RBTREE_NULL)
+                       smright = smright->left;
+               /* swap the smright and to_delete elements in the tree,
+                * but the rbnode_t is first part of user data struct
+                * so cannot just swap the keys and data pointers. Instead
+                * readjust the pointers left,right,parent */
+
+               /* swap colors - colors are tied to the position in the tree */
+               swap_int8(&to_delete->color, &smright->color);
+
+               /* swap child pointers in parents of smright/to_delete */
+               change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
+               if(to_delete->right != smright)
+                       change_parent_ptr(rbtree, smright->parent, smright, to_delete);
+
+               /* swap parent pointers in children of smright/to_delete */
+               change_child_ptr(smright->left, smright, to_delete);
+               change_child_ptr(smright->left, smright, to_delete);
+               change_child_ptr(smright->right, smright, to_delete);
+               change_child_ptr(smright->right, smright, to_delete);
+               change_child_ptr(to_delete->left, to_delete, smright);
+               if(to_delete->right != smright)
+                       change_child_ptr(to_delete->right, to_delete, smright);
+               if(to_delete->right == smright)
+               {
+                       /* set up so after swap they work */
+                       to_delete->right = to_delete;
+                       smright->parent = smright;
+               }
+
+               /* swap pointers in to_delete/smright nodes */
+               swap_np(&to_delete->parent, &smright->parent);
+               swap_np(&to_delete->left, &smright->left);
+               swap_np(&to_delete->right, &smright->right);
+
+               /* 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);
+
+       if(to_delete->left != RBTREE_NULL) child = to_delete->left;
+       else child = to_delete->right;
+
+       /* unlink to_delete from the tree, replace to_delete with child */
+       change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
+       change_child_ptr(child, to_delete, to_delete->parent);
+
+       if(to_delete->color == RED)
+       {
+               /* if node is red then the child (black) can be swapped in */
+       }
+       else if(child->color == RED)
+       {
+               /* change child to BLACK, removing a RED node is no problem */
+               if(child!=RBTREE_NULL) child->color = BLACK;
+       }
+       else rbtree_delete_fixup(rbtree, child, to_delete->parent);
+
+       /* unlink completely */
+       to_delete->parent = RBTREE_NULL;
+       to_delete->left = RBTREE_NULL;
+       to_delete->right = RBTREE_NULL;
+       to_delete->color = BLACK;
+       return to_delete;
+}
+
+static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* child_parent)
+{
+       rbnode_t* sibling;
+       int go_up = 1;
+
+       /* determine sibling to the node that is one-black short */
+       if(child_parent->right == child) sibling = child_parent->left;
+       else sibling = child_parent->right;
+
+       while(go_up)
+       {
+               if(child_parent == RBTREE_NULL)
+               {
+                       /* removed parent==black from root, every path, so ok */
+                       return;
+               }
+
+               if(sibling->color == RED)
+               {       /* rotate to get a black sibling */
+                       child_parent->color = RED;
+                       sibling->color = BLACK;
+                       if(child_parent->right == child)
+                               rbtree_rotate_right(rbtree, child_parent);
+                       else    rbtree_rotate_left(rbtree, child_parent);
+                       /* new sibling after rotation */
+                       if(child_parent->right == child) sibling = child_parent->left;
+                       else sibling = child_parent->right;
+               }
+
+               if(child_parent->color == BLACK 
+                       && sibling->color == BLACK
+                       && sibling->left->color == BLACK
+                       && sibling->right->color == BLACK)
+               {       /* fixup local with recolor of sibling */
+                       if(sibling != RBTREE_NULL)
+                               sibling->color = RED;
+
+                       child = child_parent;
+                       child_parent = child_parent->parent;
+                       /* prepare to go up, new sibling */
+                       if(child_parent->right == child) sibling = child_parent->left;
+                       else sibling = child_parent->right;
+               }
+               else go_up = 0;
+       }
+
+       if(child_parent->color == RED
+               && sibling->color == BLACK
+               && sibling->left->color == BLACK
+               && sibling->right->color == BLACK) 
+       {
+               /* move red to sibling to rebalance */
+               if(sibling != RBTREE_NULL)
+                       sibling->color = RED;
+               child_parent->color = BLACK;
+               return;
+       }
+       assert(sibling != RBTREE_NULL);
+
+       /* get a new sibling, by rotating at sibling. See which child
+          of sibling is red */
+       if(child_parent->right == child
+               && sibling->color == BLACK
+               && sibling->right->color == RED
+               && sibling->left->color == BLACK)
+       {
+               sibling->color = RED;
+               sibling->right->color = BLACK;
+               rbtree_rotate_left(rbtree, sibling);
+               /* new sibling after rotation */
+               if(child_parent->right == child) sibling = child_parent->left;
+               else sibling = child_parent->right;
+       }
+       else if(child_parent->left == child
+               && sibling->color == BLACK
+               && sibling->left->color == RED
+               && sibling->right->color == BLACK)
+       {
+               sibling->color = RED;
+               sibling->left->color = BLACK;
+               rbtree_rotate_right(rbtree, sibling);
+               /* new sibling after rotation */
+               if(child_parent->right == child) sibling = child_parent->left;
+               else sibling = child_parent->right;
+       }
+
+       /* now we have a black sibling with a red child. rotate and exchange colors. */
+       sibling->color = child_parent->color;
+       child_parent->color = BLACK;
+       if(child_parent->right == child)
+       {
+               assert(sibling->left->color == RED);
+               sibling->left->color = BLACK;
+               rbtree_rotate_right(rbtree, child_parent);
+       }
+       else
+       {
+               assert(sibling->right->color == RED);
+               sibling->right->color = BLACK;
+               rbtree_rotate_left(rbtree, child_parent);
+       }
+}
+
+int
+rbtree_find_less_equal(rbtree_t *rbtree, const void *key, rbnode_t **result)
+{
+       int r;
+       rbnode_t *node;
+
+       assert(result);
+       
+       /* We start at root... */
+       node = rbtree->root;
+
+       *result = NULL;
+       
+       /* While there are children... */
+       while (node != RBTREE_NULL) {
+               r = rbtree->cmp(key, node->key);
+               if (r == 0) {
+                       /* Exact match */
+                       *result = node;
+                       return 1;
+               } 
+               if (r < 0) {
+                       node = node->left;
+               } else {
+                       /* Temporary match */
+                       *result = node;
+                       node = node->right;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Finds the first element in the red black tree
+ *
+ */
+rbnode_t *
+rbtree_first (rbtree_t *rbtree)
+{
+       rbnode_t *node;
+
+       for (node = rbtree->root; node->left != RBTREE_NULL; node = node->left);
+       return node;
+}
+
+rbnode_t *
+rbtree_last (rbtree_t *rbtree)
+{
+       rbnode_t *node;
+
+       for (node = rbtree->root; node->right != RBTREE_NULL; node = node->right);
+       return node;
+}
+
+/*
+ * Returns the next node...
+ *
+ */
+rbnode_t *
+rbtree_next (rbnode_t *node)
+{
+       rbnode_t *parent;
+
+       if (node->right != RBTREE_NULL) {
+               /* One right, then keep on going left... */
+               for (node = node->right; node->left != RBTREE_NULL; node = node->left);
+       } else {
+               parent = node->parent;
+               while (parent != RBTREE_NULL && node == parent->right) {
+                       node = parent;
+                       parent = parent->parent;
+               }
+               node = parent;
+       }
+       return node;
+}
+
+rbnode_t *
+rbtree_previous(rbnode_t *node)
+{
+       rbnode_t *parent;
+
+       if (node->left != RBTREE_NULL) {
+               /* One left, then keep on going right... */
+               for (node = node->left; node->right != RBTREE_NULL; node = node->right);
+       } else {
+               parent = node->parent;
+               while (parent != RBTREE_NULL && node == parent->left) {
+                       node = parent;
+                       parent = parent->parent;
+               }
+               node = parent;
+       }
+       return node;
+}
diff --git a/util/rbtree.h b/util/rbtree.h
new file mode 100644 (file)
index 0000000..c95f243
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * rbtree.h -- generic red-black tree
+ *
+ * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ * 
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _RBTREE_H_
+#define        _RBTREE_H_
+
+#include "region-allocator.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;
+struct rbnode_t {
+       rbnode_t   *parent;
+       rbnode_t   *left;
+       rbnode_t   *right;
+       const void *key;
+       uint8_t     color;
+};
+
+#define        RBTREE_NULL &rbtree_null_node
+extern rbnode_t        rbtree_null_node;
+
+typedef struct rbtree_t rbtree_t;
+struct rbtree_t {
+       region_type *region;
+       
+       /* The root of the red-black tree */
+       rbnode_t    *root;
+
+       /* The number of the nodes in the tree */
+       size_t       count;
+
+       /* Current node for walks... */
+       rbnode_t    *_node;
+
+       /* 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 *));
+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 */
+rbnode_t *rbtree_delete(rbtree_t *rbtree, const void *key);
+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);
+rbnode_t *rbtree_first(rbtree_t *rbtree);
+rbnode_t *rbtree_last(rbtree_t *rbtree);
+rbnode_t *rbtree_next(rbnode_t *rbtree);
+rbnode_t *rbtree_previous(rbnode_t *rbtree);
+
+#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. */
+#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_ */