]> git.ozlabs.org Git - ccan/blobdiff - ccan/rbtree/rbtree.c
rbtree: new module from Ronnie.
[ccan] / ccan / rbtree / rbtree.c
diff --git a/ccan/rbtree/rbtree.c b/ccan/rbtree/rbtree.c
new file mode 100644 (file)
index 0000000..a6a7d38
--- /dev/null
@@ -0,0 +1,999 @@
+/*
+   a talloc based red-black tree
+
+   Copyright (C) Ronnie Sahlberg  2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <ccan/rbtree/rbtree.h>
+
+static void
+tree_destructor_traverse_node(TALLOC_CTX *mem_ctx, trbt_node_t *node)
+{
+       talloc_set_destructor(node, NULL);
+       if (node->left) {
+               tree_destructor_traverse_node(mem_ctx, node->left);
+       }
+       if (node->right) {
+               tree_destructor_traverse_node(mem_ctx, node->right);
+       }
+       talloc_steal(mem_ctx, node);
+}
+
+/*
+  destroy a tree and remove all its nodes
+ */
+static int tree_destructor(trbt_tree_t *tree)
+{
+       TALLOC_CTX *tmp_ctx;
+       trbt_node_t *node;
+
+       if (tree == NULL) {
+               return 0;
+       }
+
+       node=tree->root;
+       if (node == NULL) {
+               return 0;
+       }
+
+       /* traverse the tree and remove the node destructor and steal
+          the node to the temporary context.
+          we dont want to use the existing destructor for the node
+          since that will remove the nodes one by one from the tree.
+          since the entire tree will be completely destroyed we dont care
+          if it is inconsistent or unbalanced while freeing the
+          individual nodes
+       */
+       tmp_ctx = talloc_new(NULL);
+       tree_destructor_traverse_node(tmp_ctx, node);
+       talloc_free(tmp_ctx);
+
+       return 0;
+}
+
+
+/* create a red black tree */
+trbt_tree_t *
+trbt_create(TALLOC_CTX *memctx, uint32_t flags)
+{
+       trbt_tree_t *tree;
+
+       tree = talloc_zero(memctx, trbt_tree_t);
+       if (tree == NULL) {
+               fprintf(stderr, "Failed to allocate memory for rb tree\n");
+               return NULL;
+       }
+
+       /* If the tree is freed, we must walk over all entries and steal the
+          node from the stored data pointer and release the node.
+          Note, when we free the tree  we only free the tree and not any of
+          the data stored in the tree.
+       */
+       talloc_set_destructor(tree, tree_destructor);
+       tree->flags = flags;
+
+       return tree;
+}
+
+static inline trbt_node_t *
+trbt_parent(trbt_node_t *node)
+{
+       return node->parent;
+}
+
+static inline trbt_node_t *
+trbt_grandparent(trbt_node_t *node)
+{
+       trbt_node_t *parent;
+
+       parent=trbt_parent(node);
+       if(parent){
+               return parent->parent;
+       }
+       return NULL;
+}
+
+static inline trbt_node_t *
+trbt_uncle(trbt_node_t *node)
+{
+       trbt_node_t *parent, *grandparent;
+
+       parent=trbt_parent(node);
+       if(!parent){
+               return NULL;
+       }
+       grandparent=trbt_parent(parent);
+       if(!grandparent){
+               return NULL;
+       }
+       if(parent==grandparent->left){
+               return grandparent->right;
+       }
+       return grandparent->left;
+}
+
+
+static inline void trbt_insert_case1(trbt_tree_t *tree, trbt_node_t *node);
+static inline void trbt_insert_case2(trbt_tree_t *tree, trbt_node_t *node);
+
+static inline void
+trbt_rotate_left(trbt_node_t *node)
+{
+       trbt_tree_t *tree = node->tree;
+
+       if(node->parent){
+               if(node->parent->left==node){
+                       node->parent->left=node->right;
+               } else {
+                       node->parent->right=node->right;
+               }
+       } else {
+               tree->root=node->right;
+       }
+       node->right->parent=node->parent;
+       node->parent=node->right;
+       node->right=node->right->left;
+       if(node->right){
+               node->right->parent=node;
+       }
+       node->parent->left=node;
+}
+
+static inline void
+trbt_rotate_right(trbt_node_t *node)
+{
+       trbt_tree_t *tree = node->tree;
+
+       if(node->parent){
+               if(node->parent->left==node){
+                       node->parent->left=node->left;
+               } else {
+                       node->parent->right=node->left;
+               }
+       } else {
+               tree->root=node->left;
+       }
+       node->left->parent=node->parent;
+       node->parent=node->left;
+       node->left=node->left->right;
+       if(node->left){
+               node->left->parent=node;
+       }
+       node->parent->right=node;
+}
+
+/* NULL nodes are black by definition */
+static inline int trbt_get_color(trbt_node_t *node)
+{
+       if (node==NULL) {
+               return TRBT_BLACK;
+       }
+       return node->rb_color;
+}
+static inline int trbt_get_color_left(trbt_node_t *node)
+{
+       if (node==NULL) {
+               return TRBT_BLACK;
+       }
+       if (node->left==NULL) {
+               return TRBT_BLACK;
+       }
+       return node->left->rb_color;
+}
+static inline int trbt_get_color_right(trbt_node_t *node)
+{
+       if (node==NULL) {
+               return TRBT_BLACK;
+       }
+       if (node->right==NULL) {
+               return TRBT_BLACK;
+       }
+       return node->right->rb_color;
+}
+/* setting a NULL node to black is a nop */
+static inline void trbt_set_color(trbt_node_t *node, int color)
+{
+       if ( (node==NULL) && (color==TRBT_BLACK) ) {
+               return;
+       }
+       node->rb_color = color;
+}
+static inline void trbt_set_color_left(trbt_node_t *node, int color)
+{
+       if ( ((node==NULL)||(node->left==NULL)) && (color==TRBT_BLACK) ) {
+               return;
+       }
+       node->left->rb_color = color;
+}
+static inline void trbt_set_color_right(trbt_node_t *node, int color)
+{
+       if ( ((node==NULL)||(node->right==NULL)) && (color==TRBT_BLACK) ) {
+               return;
+       }
+       node->right->rb_color = color;
+}
+
+static inline void
+trbt_insert_case5(trbt_node_t *node)
+{
+       trbt_node_t *grandparent;
+       trbt_node_t *parent;
+
+       parent=trbt_parent(node);
+       grandparent=trbt_parent(parent);
+       parent->rb_color=TRBT_BLACK;
+       grandparent->rb_color=TRBT_RED;
+       if( (node==parent->left) && (parent==grandparent->left) ){
+               trbt_rotate_right(grandparent);
+       } else {
+               trbt_rotate_left(grandparent);
+       }
+}
+
+static inline void
+trbt_insert_case4(trbt_node_t *node)
+{
+       trbt_node_t *grandparent;
+       trbt_node_t *parent;
+
+       parent=trbt_parent(node);
+       grandparent=trbt_parent(parent);
+       if(!grandparent){
+               return;
+       }
+       if( (node==parent->right) && (parent==grandparent->left) ){
+               trbt_rotate_left(parent);
+               node=node->left;
+       } else if( (node==parent->left) && (parent==grandparent->right) ){
+               trbt_rotate_right(parent);
+               node=node->right;
+       }
+       trbt_insert_case5(node);
+}
+
+static inline void
+trbt_insert_case3(trbt_tree_t *tree, trbt_node_t *node)
+{
+       trbt_node_t *grandparent;
+       trbt_node_t *parent;
+       trbt_node_t *uncle;
+
+       uncle=trbt_uncle(node);
+       if(uncle && (uncle->rb_color==TRBT_RED)){
+               parent=trbt_parent(node);
+               parent->rb_color=TRBT_BLACK;
+               uncle->rb_color=TRBT_BLACK;
+               grandparent=trbt_grandparent(node);
+               grandparent->rb_color=TRBT_RED;
+               trbt_insert_case1(tree, grandparent);
+       } else {
+               trbt_insert_case4(node);
+       }
+}
+
+static inline void
+trbt_insert_case2(trbt_tree_t *tree, trbt_node_t *node)
+{
+       trbt_node_t *parent;
+
+       parent=trbt_parent(node);
+       /* parent is always non-NULL here */
+       if(parent->rb_color==TRBT_BLACK){
+               return;
+       }
+       trbt_insert_case3(tree, node);
+}
+
+static inline void
+trbt_insert_case1(trbt_tree_t *tree, trbt_node_t *node)
+{
+       trbt_node_t *parent;
+
+       parent=trbt_parent(node);
+       if(!parent){
+               node->rb_color=TRBT_BLACK;
+               return;
+       }
+       trbt_insert_case2(tree, node);
+}
+
+static inline trbt_node_t *
+trbt_sibling(trbt_node_t *node)
+{
+       trbt_node_t *parent;
+
+       parent=trbt_parent(node);
+       if(!parent){
+               return NULL;
+       }
+
+       if (node == parent->left) {
+               return parent->right;
+       } else {
+               return parent->left;
+       }
+}
+
+static inline void
+trbt_delete_case6(trbt_node_t *node)
+{
+       trbt_node_t *sibling, *parent;
+
+       sibling = trbt_sibling(node);
+       parent  = trbt_parent(node);
+
+       trbt_set_color(sibling, parent->rb_color);
+       trbt_set_color(parent, TRBT_BLACK);
+       if (node == parent->left) {
+               trbt_set_color_right(sibling, TRBT_BLACK);
+               trbt_rotate_left(parent);
+       } else {
+               trbt_set_color_left(sibling, TRBT_BLACK);
+               trbt_rotate_right(parent);
+       }
+}
+
+
+static inline void
+trbt_delete_case5(trbt_node_t *node)
+{
+       trbt_node_t *parent, *sibling;
+
+       parent = trbt_parent(node);
+       sibling = trbt_sibling(node);
+       if ( (node == parent->left)
+          &&(trbt_get_color(sibling)        == TRBT_BLACK)
+          &&(trbt_get_color_left(sibling)   == TRBT_RED)
+          &&(trbt_get_color_right(sibling)  == TRBT_BLACK) ){
+               trbt_set_color(sibling, TRBT_RED);
+               trbt_set_color_left(sibling, TRBT_BLACK);
+               trbt_rotate_right(sibling);
+               trbt_delete_case6(node);
+               return;
+       }
+       if ( (node == parent->right)
+          &&(trbt_get_color(sibling)        == TRBT_BLACK)
+          &&(trbt_get_color_right(sibling)  == TRBT_RED)
+          &&(trbt_get_color_left(sibling)   == TRBT_BLACK) ){
+               trbt_set_color(sibling, TRBT_RED);
+               trbt_set_color_right(sibling, TRBT_BLACK);
+               trbt_rotate_left(sibling);
+               trbt_delete_case6(node);
+               return;
+       }
+
+       trbt_delete_case6(node);
+}
+
+static inline void
+trbt_delete_case4(trbt_node_t *node)
+{
+       trbt_node_t *sibling;
+
+       sibling = trbt_sibling(node);
+       if ( (trbt_get_color(node->parent)   == TRBT_RED)
+          &&(trbt_get_color(sibling)        == TRBT_BLACK)
+          &&(trbt_get_color_left(sibling)   == TRBT_BLACK)
+          &&(trbt_get_color_right(sibling)  == TRBT_BLACK) ){
+               trbt_set_color(sibling, TRBT_RED);
+               trbt_set_color(node->parent, TRBT_BLACK);
+       } else {
+               trbt_delete_case5(node);
+       }
+}
+
+static void trbt_delete_case1(trbt_node_t *node);
+
+static inline void
+trbt_delete_case3(trbt_node_t *node)
+{
+       trbt_node_t *sibling;
+
+       sibling = trbt_sibling(node);
+       if ( (trbt_get_color(node->parent)   == TRBT_BLACK)
+          &&(trbt_get_color(sibling)        == TRBT_BLACK)
+          &&(trbt_get_color_left(sibling)   == TRBT_BLACK)
+          &&(trbt_get_color_right(sibling)  == TRBT_BLACK) ){
+               trbt_set_color(sibling, TRBT_RED);
+               trbt_delete_case1(node->parent);
+       } else {
+               trbt_delete_case4(node);
+       }
+}
+       
+static inline void
+trbt_delete_case2(trbt_node_t *node)
+{
+       trbt_node_t *sibling;
+
+       sibling = trbt_sibling(node);
+       if (trbt_get_color(sibling) == TRBT_RED) {
+               trbt_set_color(node->parent, TRBT_RED);
+               trbt_set_color(sibling, TRBT_BLACK);
+               if (node == node->parent->left) {
+                       trbt_rotate_left(node->parent);
+               } else {
+                       trbt_rotate_right(node->parent);
+               }
+       }
+       trbt_delete_case3(node);
+}
+
+static void
+trbt_delete_case1(trbt_node_t *node)
+{
+       if (!node->parent) {
+               return;
+       } else {
+               trbt_delete_case2(node);
+       }
+}
+
+static void
+delete_node(trbt_node_t *node, int from_destructor)
+{
+       trbt_node_t *parent, *child, dc;
+       trbt_node_t *temp = NULL;
+
+       /* This node has two child nodes, then just copy the content
+          from the next smaller node with this node and delete the
+          predecessor instead.
+          The predecessor is guaranteed to have at most one child
+          node since its right arm must be NULL
+          (It must be NULL since we are its sucessor and we are above
+           it in the tree)
+        */
+       if (node->left != NULL && node->right != NULL) {
+               /* This node has two children, just copy the data */
+               /* find the predecessor */
+               temp = node->left;
+
+               while (temp->right != NULL) {
+                       temp = temp->right;
+               }
+
+               /* swap the predecessor data and key with the node to
+                  be deleted.
+                */
+               node->key32 = temp->key32;
+               node->data  = temp->data;
+               /* now we let node hang off the new data */
+               talloc_steal(node->data, node);
+       
+               temp->data  = NULL;
+               temp->key32 = -1;
+               /* then delete the temp node.
+                  this node is guaranteed to have at least one leaf
+                  child */
+               delete_node(temp, from_destructor);
+               goto finished;
+       }
+
+
+       /* There is at most one child to this node to be deleted */
+       child = node->left;
+       if (node->right) {
+               child = node->right;
+       }
+
+       /* If the node to be deleted did not have any child at all we
+          create a temporary dummy node for the child and mark it black.
+          Once the delete of the node is finished, we remove this dummy
+          node, which is simple to do since it is guaranteed that it will
+          still not have any children after the delete operation.
+          This is because we dont represent the leaf-nodes as actual nodes
+          in this implementation.
+        */
+       if (!child) {
+               child = &dc;
+               child->tree = node->tree;
+               child->left=NULL;
+               child->right=NULL;
+               child->rb_color=TRBT_BLACK;
+               child->data=NULL;
+       }
+
+       /* replace node with child */
+       parent = trbt_parent(node);
+       if (parent) {
+               if (parent->left == node) {
+                       parent->left = child;
+               } else {
+                       parent->right = child;
+               }
+       } else {
+               node->tree->root = child;
+       }
+       child->parent = node->parent;
+
+
+       if (node->rb_color == TRBT_BLACK) {
+               if (trbt_get_color(child) == TRBT_RED) {
+                       child->rb_color = TRBT_BLACK;
+               } else {
+                       trbt_delete_case1(child);
+               }
+       }
+
+       /* If we had to create a temporary dummy node to represent a black
+          leaf child we now has to delete it.
+          This is simple since this dummy node originally had no children
+          and we are guaranteed that it will also not have any children
+          after the node has been deleted and any possible rotations
+          have occured.
+
+          The only special case is if this was the last node of the tree
+          in which case we have to reset the root to NULL as well.
+          Othervise it is enough to just unlink the child from its new
+          parent.
+        */
+       if (child == &dc) {
+               if (child->parent == NULL) {
+                       node->tree->root = NULL;
+               } else if (child == child->parent->left) {
+                       child->parent->left = NULL;
+               } else {
+                       child->parent->right = NULL;
+               }
+       }
+
+finished:
+       if (!from_destructor) {
+               talloc_free(node);
+       }
+
+       /* if we came from a destructor and temp!=NULL  this means we
+          did the node-swap but now the tree still contains the old
+          node  which was freed in the destructor. Not good.
+       */
+       if (from_destructor && temp) {
+               temp->key32    = node->key32;
+               temp->rb_color = node->rb_color;
+
+               temp->data = node->data;
+               talloc_steal(temp->data, temp);
+
+               temp->parent = node->parent;
+               if (temp->parent) {
+                       if (temp->parent->left == node) {
+                               temp->parent->left = temp;
+                       } else {
+                               temp->parent->right = temp;
+                       }
+               }
+
+               temp->left = node->left;
+               if (temp->left) {
+                       temp->left->parent = temp;
+               }
+               temp->right = node->right;
+               if (temp->right) {
+                       temp->right->parent = temp;
+               }
+
+               if (temp->tree->root == node) {
+                       temp->tree->root = temp;
+               }
+       }
+
+       if ( (node->tree->flags & TRBT_AUTOFREE)
+       &&   (node->tree->root == NULL) ) {
+               talloc_free(node->tree);
+       }
+
+       return;
+}
+
+/*
+  destroy a node and remove it from its tree
+ */
+static int node_destructor(trbt_node_t *node)
+{
+       delete_node(node, 1);
+
+       return 0;
+}
+
+static inline trbt_node_t *
+trbt_create_node(trbt_tree_t *tree, trbt_node_t *parent, uint32_t key, void *data)
+{
+       trbt_node_t *node;
+
+       node=talloc_zero(tree, trbt_node_t);
+       if (node == NULL) {
+               fprintf(stderr, "Failed to allocate memory for rb node\n");
+               return NULL;
+       }
+
+       node->tree=tree;
+       node->rb_color=TRBT_BLACK;
+       node->parent=parent;
+       node->left=NULL;
+       node->right=NULL;
+       node->key32=key;
+       node->data = data;
+
+       /* let this node hang off data so that it is removed when
+          data is freed
+        */
+       talloc_steal(data, node);
+       talloc_set_destructor(node, node_destructor);
+
+       return node;
+}
+
+/* insert a new node in the tree.
+   if there is already a node with a matching key in the tree
+   we replace it with the new data and return a pointer to the old data
+   in case the caller wants to take any special action
+ */
+void *
+trbt_insert32(trbt_tree_t *tree, uint32_t key, void *data)
+{
+       trbt_node_t *node;
+
+       node=tree->root;
+
+       /* is this the first node ?*/
+       if(!node){
+               node = trbt_create_node(tree, NULL, key, data);
+
+               tree->root=node;
+               return NULL;
+       }
+
+       /* it was not the new root so walk the tree until we find where to
+        * insert this new leaf.
+        */
+       while(1){
+               /* this node already exists, replace data and return the
+                  old data
+                */
+               if(key==node->key32){
+                       void *old_data;
+
+                       old_data = node->data;
+                       node->data  = data;
+                       /* Let the node now be owned by the new data
+                          so the node is freed when the enw data is released
+                       */
+                       talloc_steal(node->data, node);
+
+                       return old_data;
+               }
+               if(key<node->key32) {
+                       if(!node->left){
+                               /* new node to the left */
+                               trbt_node_t *new_node;
+
+                               new_node = trbt_create_node(tree, node, key, data);
+                               node->left=new_node;
+                               node=new_node;
+
+                               break;
+                       }
+                       node=node->left;
+                       continue;
+               }
+               if(key>node->key32) {
+                       if(!node->right){
+                               /* new node to the right */
+                               trbt_node_t *new_node;
+
+                               new_node = trbt_create_node(tree, node, key, data);
+                               node->right=new_node;
+                               node=new_node;
+                               break;
+                       }
+                       node=node->right;
+                       continue;
+               }
+       }
+
+       /* node will now point to the newly created node */
+       node->rb_color=TRBT_RED;
+       trbt_insert_case1(tree, node);
+       return NULL;
+}
+
+void *
+trbt_lookup32(trbt_tree_t *tree, uint32_t key)
+{
+       trbt_node_t *node;
+
+       node=tree->root;
+
+       while(node){
+               if(key==node->key32){
+                       return node->data;
+               }
+               if(key<node->key32){
+                       node=node->left;
+                       continue;
+               }
+               if(key>node->key32){
+                       node=node->right;
+                       continue;
+               }
+       }
+       return NULL;
+}
+
+
+/* This deletes a node from the tree.
+   Note that this does not release the data that the node points to
+*/
+void
+trbt_delete32(trbt_tree_t *tree, uint32_t key)
+{
+       trbt_node_t *node;
+
+       node=tree->root;
+
+       while(node){
+               if(key==node->key32){
+                       delete_node(node, 0);
+                       return;
+               }
+               if(key<node->key32){
+                       node=node->left;
+                       continue;
+               }
+               if(key>node->key32){
+                       node=node->right;
+                       continue;
+               }
+       }
+}
+
+
+void
+trbt_insert32_callback(trbt_tree_t *tree, uint32_t key, void *(*callback)(void *param, void *data), void *param)
+{
+       trbt_node_t *node;
+
+       node=tree->root;
+
+       /* is this the first node ?*/
+       if(!node){
+               node = trbt_create_node(tree, NULL, key,
+                               callback(param, NULL));
+
+               tree->root=node;
+               return;
+       }
+
+       /* it was not the new root so walk the tree until we find where to
+        * insert this new leaf.
+        */
+       while(1){
+               /* this node already exists, replace it
+                */
+               if(key==node->key32){
+                       node->data  = callback(param, node->data);
+                       talloc_steal(node->data, node);
+
+                       return;
+               }
+               if(key<node->key32) {
+                       if(!node->left){
+                               /* new node to the left */
+                               trbt_node_t *new_node;
+
+                               new_node = trbt_create_node(tree, node, key,
+                                               callback(param, NULL));
+                               node->left=new_node;
+                               node=new_node;
+
+                               break;
+                       }
+                       node=node->left;
+                       continue;
+               }
+               if(key>node->key32) {
+                       if(!node->right){
+                               /* new node to the right */
+                               trbt_node_t *new_node;
+
+                               new_node = trbt_create_node(tree, node, key,
+                                               callback(param, NULL));
+                               node->right=new_node;
+                               node=new_node;
+                               break;
+                       }
+                       node=node->right;
+                       continue;
+               }
+       }
+
+       /* node will now point to the newly created node */
+       node->rb_color=TRBT_RED;
+       trbt_insert_case1(tree, node);
+       return;
+}
+
+
+struct trbt_array_param {
+       void *(*callback)(void *param, void *data);
+       void *param;
+       uint32_t keylen;
+       uint32_t *key;
+       trbt_tree_t *tree;
+};
+static void *array_insert_callback(void *p, void *data)
+{
+       struct trbt_array_param *param = (struct trbt_array_param *)p;
+       trbt_tree_t *tree = NULL;
+
+
+       /* if keylen has reached 0 we are done and can call the users
+          callback function with the users parameters
+       */
+       if (param->keylen == 0) {
+               return param->callback(param->param, data);
+       }
+
+
+       /* keylen is not zero yes so we must create/process more subtrees */
+       /* if data is NULL this means we did not yet have a subtree here
+          and we must create one.
+       */
+       if (data == NULL) {
+               /* create a new subtree and hang it off our current tree
+                  set it to autofree so that the tree is freed when
+                  the last node in it has been released.
+               */
+               tree = trbt_create(param->tree, TRBT_AUTOFREE);
+       } else {
+               /* we already have a subtree for this path */
+               tree = (trbt_tree_t *)data;
+       }
+               
+       trbt_insertarray32_callback(tree, param->keylen, param->key, param->callback, param->param);
+
+       /* now return either the old tree we got in *data or the new tree
+          we created to our caller so he can update his pointer in his
+          tree to point to our subtree
+       */
+       return tree;
+}
+
+
+
+/* insert into the tree using an array of uint32 as a key */
+void
+trbt_insertarray32_callback(trbt_tree_t *tree, uint32_t keylen, uint32_t *key, void *(*cb)(void *param, void *data), void *pm)
+{
+       struct trbt_array_param tap;
+
+       /* keylen-1 and key[1]  since the call to insert32 will consume the
+          first part of the key.
+       */
+       tap.callback= cb;
+       tap.param   = pm;
+       tap.keylen  = keylen-1;
+       tap.key     = &key[1];
+       tap.tree    = tree;
+
+       trbt_insert32_callback(tree, key[0], array_insert_callback, &tap);
+}
+
+/* lookup the tree using an array of uint32 as a key */
+void *
+trbt_lookuparray32(trbt_tree_t *tree, uint32_t keylen, uint32_t *key)
+{
+       /* if keylen is 1 we can do a regular lookup and return this to the
+          user
+       */
+       if (keylen == 1) {
+               return trbt_lookup32(tree, key[0]);
+       }
+
+       /* we need to lookup the next subtree */
+       tree = trbt_lookup32(tree, key[0]);
+       if (tree == NULL) {
+               /* the key does not exist, return NULL */
+               return NULL;
+       }
+
+       /* now lookup the next part of the key in our new tree */
+       return trbt_lookuparray32(tree, keylen-1, &key[1]);
+}
+
+
+/* traverse a tree starting at node */
+static void
+trbt_traversearray32_node(trbt_node_t *node, uint32_t keylen,
+       void (*callback)(void *param, void *data),
+       void *param)
+{
+       if (node->left) {
+               trbt_traversearray32_node(node->left, keylen, callback, param);
+       }
+
+       /* this is the smallest node in this subtree
+          if keylen is 0 this means we can just call the callback
+          otherwise we must pull the next subtree and traverse that one as well
+       */
+       if (keylen == 0) {
+               callback(param, node->data);
+       } else {
+               trbt_traversearray32(node->data, keylen, callback, param);
+       }
+
+       if (node->right) {
+               trbt_traversearray32_node(node->right, keylen, callback, param);
+       }
+}
+       
+
+/* traverse the tree using an array of uint32 as a key */
+void
+trbt_traversearray32(trbt_tree_t *tree, uint32_t keylen,
+       void (*callback)(void *param, void *data),
+       void *param)
+{
+       trbt_node_t *node;
+
+       if (tree == NULL) {
+               return;
+       }
+
+       node=tree->root;
+       if (node == NULL) {
+               return;
+       }
+
+       trbt_traversearray32_node(node, keylen-1, callback, param);
+}
+
+
+/* this function will return the first node in a tree where
+   the key is an array of uint32_t
+*/
+void *
+trbt_findfirstarray32(trbt_tree_t *tree, uint32_t keylen)
+{
+       trbt_node_t *node;
+
+       if (keylen < 1) {
+               return NULL;
+       }
+       
+       if (tree == NULL) {
+               return NULL;
+       }
+
+       node=tree->root;
+       if (node == NULL) {
+               return NULL;
+       }
+
+       while (node->left) {
+               node = node->left;
+       }
+
+       /* we found our node so return the data */
+       if (keylen == 1) {
+               return node->data;
+       }
+
+       /* we are still traversing subtrees so find the first node in the
+          next level of trees
+       */
+       return trbt_findfirstarray32(node->data, keylen-1);
+}
+
+