Massively cleaned up #include's, so they're in a consistent
[freeradius.git] / src / lib / rbtree.c
index 0aac679..f656b9a 100644 (file)
  *
  *   You should have received a copy of the GNU Lesser General Public
  *   License along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
- *  Copyright 2004  The FreeRADIUS server project
+ *  Copyright 2004,2006  The FreeRADIUS server project
  */
 
-static const char rcsid[] = "$Id$";
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
 
-#include "autoconf.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "libradius.h"
+#include <freeradius-devel/libradius.h>
 
 /* red-black tree description */
 typedef enum { Black, Red } NodeColor;
@@ -75,7 +71,7 @@ void rbtree_free(rbtree_t *tree)
        /*
         *      Walk the tree, deleting the nodes...
         */
-       if (tree->Root != NULL) FreeWalker(tree, tree->Root);
+       if (tree->Root != NIL) FreeWalker(tree, tree->Root);
 
 #ifndef NDEBUG
        tree->magic = 0;
@@ -116,13 +112,13 @@ static void RotateLeft(rbtree_t *tree, rbnode_t *X)
        /**************************
         *  rotate Node X to left *
         **************************/
-       
+
        rbnode_t *Y = X->Right;
-       
+
        /* establish X->Right link */
        X->Right = Y->Left;
        if (Y->Left != NIL) Y->Left->Parent = X;
-       
+
        /* establish Y->Parent link */
        if (Y != NIL) Y->Parent = X->Parent;
        if (X->Parent) {
@@ -133,7 +129,7 @@ static void RotateLeft(rbtree_t *tree, rbnode_t *X)
        } else {
                tree->Root = Y;
        }
-       
+
        /* link X and Y */
        Y->Left = X;
        if (X != NIL) X->Parent = Y;
@@ -144,13 +140,13 @@ static void RotateRight(rbtree_t *tree, rbnode_t *X)
        /****************************
         *  rotate Node X to right  *
         ****************************/
-       
+
        rbnode_t *Y = X->Left;
-       
+
        /* establish X->Left link */
        X->Left = Y->Right;
        if (Y->Right != NIL) Y->Right->Parent = X;
-       
+
        /* establish Y->Parent link */
        if (Y != NIL) Y->Parent = X->Parent;
        if (X->Parent) {
@@ -161,7 +157,7 @@ static void RotateRight(rbtree_t *tree, rbnode_t *X)
        } else {
                tree->Root = Y;
        }
-       
+
        /* link X and Y */
        Y->Right = X;
        if (X != NIL) X->Parent = Y;
@@ -173,46 +169,46 @@ static void InsertFixup(rbtree_t *tree, rbnode_t *X)
         *  maintain red-black tree balance  *
         *  after inserting node X           *
         *************************************/
-       
+
        /* check red-black properties */
        while (X != tree->Root && X->Parent->Color == Red) {
                /* we have a violation */
                if (X->Parent == X->Parent->Parent->Left) {
                        rbnode_t *Y = X->Parent->Parent->Right;
                        if (Y->Color == Red) {
-                               
+
                                /* uncle is red */
                                X->Parent->Color = Black;
                                Y->Color = Black;
                                X->Parent->Parent->Color = Red;
                                X = X->Parent->Parent;
                        } else {
-                               
+
                                /* uncle is black */
                                if (X == X->Parent->Right) {
                                        /* make X a left child */
                                        X = X->Parent;
                                        RotateLeft(tree, X);
                                }
-                               
+
                                /* recolor and rotate */
                                X->Parent->Color = Black;
                                X->Parent->Parent->Color = Red;
                                RotateRight(tree, X->Parent->Parent);
                        }
                } else {
-                       
+
                        /* mirror image of above code */
                        rbnode_t *Y = X->Parent->Parent->Left;
                        if (Y->Color == Red) {
-                               
+
                                /* uncle is red */
                                X->Parent->Color = Black;
                                Y->Color = Black;
                                X->Parent->Parent->Color = Red;
                                X = X->Parent->Parent;
                        } else {
-                               
+
                                /* uncle is black */
                                if (X == X->Parent->Left) {
                                        X = X->Parent;
@@ -235,11 +231,11 @@ static void InsertFixup(rbtree_t *tree, rbnode_t *X)
 int rbtree_insert(rbtree_t *tree, void *Data)
 {
        rbnode_t *Current, *Parent, *X;
-       
+
        /***********************************************
         *  allocate node for Data and insert in tree  *
         ***********************************************/
-       
+
        /* find where node belongs */
        Current = tree->Root;
        Parent = NULL;
@@ -261,6 +257,7 @@ int rbtree_insert(rbtree_t *tree, void *Data)
                        /*
                         *      Do replace the entry.
                         */
+                       if (tree->freeNode) tree->freeNode(Current->Data);
                        Current->Data = Data;
                        return 1;
                }
@@ -268,10 +265,10 @@ int rbtree_insert(rbtree_t *tree, void *Data)
                Parent = Current;
                Current = (result < 0) ? Current->Left : Current->Right;
        }
-       
+
        /* setup new node */
        if ((X = malloc (sizeof(*X))) == NULL) {
-               exit(1);
+               exit(1);        /* FIXME! */
        }
 
        X->Data = Data;
@@ -279,7 +276,7 @@ int rbtree_insert(rbtree_t *tree, void *Data)
        X->Left = NIL;
        X->Right = NIL;
        X->Color = Red;
-       
+
        /* insert node in tree */
        if (Parent) {
                if (tree->Compare(Data, Parent->Data) <= 0)
@@ -289,7 +286,7 @@ int rbtree_insert(rbtree_t *tree, void *Data)
        } else {
                tree->Root = X;
        }
-       
+
        InsertFixup(tree, X);
 
        tree->num_elements++;
@@ -297,61 +294,66 @@ int rbtree_insert(rbtree_t *tree, void *Data)
        return 1;
 }
 
-
-static void DeleteFixup(rbtree_t *tree, rbnode_t *X)
+static void DeleteFixup(rbtree_t *tree, rbnode_t *X, rbnode_t *Parent)
 {
        /*************************************
         *  maintain red-black tree balance  *
         *  after deleting node X            *
         *************************************/
-       
+
        while (X != tree->Root && X->Color == Black) {
-               if (X == X->Parent->Left) {
-                       rbnode_t *W = X->Parent->Right;
+               if (X == Parent->Left) {
+                       rbnode_t *W = Parent->Right;
                        if (W->Color == Red) {
                                W->Color = Black;
-                               X->Parent->Color = Red;
-                               RotateLeft(tree, X->Parent);
-                               W = X->Parent->Right;
+                               Parent->Color = Red; /* Parent != NIL? */
+                               RotateLeft(tree, Parent);
+                               W = Parent->Right;
                        }
                        if (W->Left->Color == Black && W->Right->Color == Black) {
-                               W->Color = Red;
-                               X = X->Parent;
+                               if (W != NIL) W->Color = Red;
+                               X = Parent;
+                               Parent = X->Parent;
                        } else {
                                if (W->Right->Color == Black) {
-                                       W->Left->Color = Black;
+                                       if (W->Left != NIL) W->Left->Color = Black;
                                        W->Color = Red;
                                        RotateRight(tree, W);
-                                       W = X->Parent->Right;
+                                       W = Parent->Right;
                                }
-                               W->Color = X->Parent->Color;
-                               X->Parent->Color = Black;
-                               W->Right->Color = Black;
-                               RotateLeft(tree, X->Parent);
+                               W->Color = Parent->Color;
+                               if (Parent != NIL) Parent->Color = Black;
+                               if (W->Right->Color != Black) {
+                                       W->Right->Color = Black;
+                               }
+                               RotateLeft(tree, Parent);
                                X = tree->Root;
                        }
                } else {
-                       rbnode_t *W = X->Parent->Left;
+                       rbnode_t *W = Parent->Left;
                        if (W->Color == Red) {
                                W->Color = Black;
-                               X->Parent->Color = Red;
-                               RotateRight(tree, X->Parent);
-                               W = X->Parent->Left;
+                               Parent->Color = Red; /* Parent != NIL? */
+                               RotateRight(tree, Parent);
+                               W = Parent->Left;
                        }
                        if (W->Right->Color == Black && W->Left->Color == Black) {
-                               W->Color = Red;
-                               X = X->Parent;
+                               if (W != NIL) W->Color = Red;
+                               X = Parent;
+                               Parent = X->Parent;
                        } else {
                                if (W->Left->Color == Black) {
-                                       W->Right->Color = Black;
+                                       if (W->Right != NIL) W->Right->Color = Black;
                                        W->Color = Red;
                                        RotateLeft(tree, W);
-                                       W = X->Parent->Left;
+                                       W = Parent->Left;
                                }
-                               W->Color = X->Parent->Color;
-                               X->Parent->Color = Black;
-                               W->Left->Color = Black;
-                               RotateRight(tree, X->Parent);
+                               W->Color = Parent->Color;
+                               if (Parent != NIL) Parent->Color = Black;
+                               if (W->Left->Color != Black) {
+                                       W->Left->Color = Black;
+                               }
+                               RotateRight(tree, Parent);
                                X = tree->Root;
                        }
                }
@@ -365,13 +367,14 @@ static void DeleteFixup(rbtree_t *tree, rbnode_t *X)
 void rbtree_delete(rbtree_t *tree, rbnode_t *Z)
 {
        rbnode_t *X, *Y;
-       
+       rbnode_t *Parent;
+
        /*****************************
         *  delete node Z from tree  *
         *****************************/
-       
+
        if (!Z || Z == NIL) return;
-       
+
        if (Z->Left == NIL || Z->Right == NIL) {
                /* Y has a NIL node as a child */
                Y = Z;
@@ -380,23 +383,25 @@ void rbtree_delete(rbtree_t *tree, rbnode_t *Z)
                Y = Z->Right;
                while (Y->Left != NIL) Y = Y->Left;
        }
-       
+
        /* X is Y's only child */
        if (Y->Left != NIL)
                X = Y->Left;
        else
-               X = Y->Right;
-       
+               X = Y->Right;   /* may be NIL! */
+
        /* remove Y from the parent chain */
-       X->Parent = Y->Parent;
-       if (Y->Parent)
-               if (Y == Y->Parent->Left)
-                       Y->Parent->Left = X;
+       Parent = Y->Parent;
+       if (X != NIL) X->Parent = Parent;
+
+       if (Parent)
+               if (Y == Parent->Left)
+                       Parent->Left = X;
                else
-                       Y->Parent->Right = X;
+                       Parent->Right = X;
        else
                tree->Root = X;
-       
+
        if (Y != Z) {
                /*
                 *      Move the child's data to here, and then
@@ -408,8 +413,9 @@ void rbtree_delete(rbtree_t *tree, rbnode_t *Z)
        } else if (tree->freeNode) {
                tree->freeNode(Z->Data);
        }
-       if (Y->Color == Black)
-               DeleteFixup(tree, X);
+
+       if (Y->Color == Black && X != NIL)
+               DeleteFixup(tree, X, Parent);
 
        free(Y);
 
@@ -417,14 +423,30 @@ void rbtree_delete(rbtree_t *tree, rbnode_t *Z)
 }
 
 /*
+ *     Delete a node from the tree, based on given data, which MUST
+ *     have come from rbtree_finddata().
+ */
+int rbtree_deletebydata(rbtree_t *tree, const void *data)
+{
+       rbnode_t *node = rbtree_find(tree, data);
+       
+       if (!node) return 0;    /* false */
+
+       rbtree_delete(tree, node);
+
+       return 1;
+}
+
+
+/*
  *     Find an element in the tree, returning the data, not the node.
  */
-rbnode_t *rbtree_find(rbtree_t *tree, void *Data)
+rbnode_t *rbtree_find(rbtree_t *tree, const void *Data)
 {
        /*******************************
         *  find node containing Data  *
         *******************************/
-       
+
        rbnode_t *Current = tree->Root;
 
        while (Current != NIL) {
@@ -443,7 +465,7 @@ rbnode_t *rbtree_find(rbtree_t *tree, void *Data)
 /*
  *     Find the user data.
  */
-void *rbtree_finddata(rbtree_t *tree, void *Data)
+void *rbtree_finddata(rbtree_t *tree, const void *Data)
 {
        rbnode_t *X;
 
@@ -459,20 +481,21 @@ void *rbtree_finddata(rbtree_t *tree, void *Data)
  *     We call ourselves recursively for each function, but that's OK,
  *     as the stack is only log(N) deep, which is ~12 entries deep.
  */
-static int WalkNodePreOrder(rbnode_t *X, int (*callback)(void *))
+static int WalkNodePreOrder(rbnode_t *X,
+                           int (*callback)(void *, void *), void *context)
 {
        int rcode;
 
-       rcode = callback(X->Data);
+       rcode = callback(context, X->Data);
        if (rcode != 0) return rcode;
 
        if (X->Left != NIL) {
-               rcode = WalkNodePreOrder(X->Left, callback);
+               rcode = WalkNodePreOrder(X->Left, callback, context);
                if (rcode != 0) return rcode;
        }
 
        if (X->Right != NIL) {
-               rcode = WalkNodePreOrder(X->Right, callback);
+               rcode = WalkNodePreOrder(X->Right, callback, context);
                if (rcode != 0) return rcode;
        }
 
@@ -482,20 +505,21 @@ static int WalkNodePreOrder(rbnode_t *X, int (*callback)(void *))
 /*
  *     Inorder
  */
-static int WalkNodeInOrder(rbnode_t *X, int (*callback)(void *))
+static int WalkNodeInOrder(rbnode_t *X,
+                          int (*callback)(void *, void *), void *context)
 {
        int rcode;
 
        if (X->Left != NIL) {
-               rcode = WalkNodeInOrder(X->Left, callback);
+               rcode = WalkNodeInOrder(X->Left, callback, context);
                if (rcode != 0) return rcode;
        }
 
-       rcode = callback(X->Data);
+       rcode = callback(context, X->Data);
        if (rcode != 0) return rcode;
 
        if (X->Right != NIL) {
-               rcode = WalkNodeInOrder(X->Right, callback);
+               rcode = WalkNodeInOrder(X->Right, callback, context);
                if (rcode != 0) return rcode;
        }
 
@@ -506,21 +530,22 @@ static int WalkNodeInOrder(rbnode_t *X, int (*callback)(void *))
 /*
  *     PostOrder
  */
-static int WalkNodePostOrder(rbnode_t *X, int (*callback)(void *))
+static int WalkNodePostOrder(rbnode_t *X,
+                            int (*callback)(void *, void*), void *context)
 {
        int rcode;
 
        if (X->Left != NIL) {
-               rcode = WalkNodeInOrder(X->Left, callback);
+               rcode = WalkNodeInOrder(X->Left, callback, context);
                if (rcode != 0) return rcode;
        }
 
        if (X->Right != NIL) {
-               rcode = WalkNodeInOrder(X->Right, callback);
+               rcode = WalkNodeInOrder(X->Right, callback, context);
                if (rcode != 0) return rcode;
        }
 
-       rcode = callback(X->Data);
+       rcode = callback(context, X->Data);
        if (rcode != 0) return rcode;
 
        return 0;               /* we know everything returned zero */
@@ -533,15 +558,16 @@ static int WalkNodePostOrder(rbnode_t *X, int (*callback)(void *))
  *     The callback function should return 0 to continue walking.
  *     Any other value stops the walk, and is returned.
  */
-int rbtree_walk(rbtree_t *tree, int (*callback)(void *), RBTREE_ORDER order)
+int rbtree_walk(rbtree_t *tree, RBTREE_ORDER order,
+               int (*callback)(void *, void *), void *context)
 {
        switch (order) {
-       case PreOrder:          
-               return WalkNodePreOrder(tree->Root, callback);
-       case InOrder:           
-               return WalkNodeInOrder(tree->Root, callback);
-       case PostOrder:         
-               return WalkNodePostOrder(tree->Root, callback);
+       case PreOrder:
+               return WalkNodePreOrder(tree->Root, callback, context);
+       case InOrder:
+               return WalkNodeInOrder(tree->Root, callback, context);
+       case PostOrder:
+               return WalkNodePostOrder(tree->Root, callback, context);
 
        default:
                break;
@@ -563,6 +589,8 @@ int rbtree_num_elements(rbtree_t *tree)
  */
 void *rbtree_node2data(rbtree_t *tree, rbnode_t *node)
 {
+       tree = tree;            /* -Wunused */
+
        if (!node) return NULL;
 
        return node->Data;