]> git.sur5r.net Git - openldap/commitdiff
Add testtavl, add tavl_end and tavl_next. tavl_delete still needs work.
authorHoward Chu <hyc@openldap.org>
Wed, 21 Sep 2005 14:45:35 +0000 (14:45 +0000)
committerHoward Chu <hyc@openldap.org>
Wed, 21 Sep 2005 14:45:35 +0000 (14:45 +0000)
libraries/liblutil/Makefile.in
libraries/liblutil/tavl.c
libraries/liblutil/testtavl.c [new file with mode: 0644]

index f846c20106d0e366fc5a025ca7c60860362310da..65fae592db4505849ecd64fb1ee0e08188a7837f 100644 (file)
@@ -41,6 +41,9 @@ OBJS  = base64.o csn.o entropy.o sasl.o signal.o hash.o passfile.o \
 testavl: $(XLIBS) testavl.o
        (LTLINK) -o $@ testavl.o $(LIBS)
 
+testtavl: $(XLIBS) testtavl.o
+       (LTLINK) -o $@ testtavl.o $(LIBS)
+
 # These rules are for a Mingw32 build, specifically.
 # It's ok for them to be here because the clean rule is harmless, and
 # slapdmsg.res won't get built unless it's declared in OBJS.
index de5df0baa368ea37e1c045b3e9b70ac86af607e5..73ab46984d05305d754b139e97a09ced14a8db9b 100644 (file)
@@ -185,8 +185,8 @@ tavl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
 void*
 tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
 {
-       Avlnode *p, *q, *r, *top;
-       int side, side_bf, shorter, cmp;
+       Avlnode *p, *q, *r, *s, *top;
+       int side, side_bf, shorter, nside;
 
        /* parent stack */
        Avlnode *pptr[sizeof(void *)*8];
@@ -199,24 +199,24 @@ tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
        p = *root;
 
        while (1) {
-               cmp = fcmp( data, p->avl_data );
-               if ( !cmp )
+               side = fcmp( data, p->avl_data );
+               if ( !side )
                        break;
-               cmp = ( cmp > 0 );
-               pdir[depth] = cmp;
+               side = ( side > 0 );
+               pdir[depth] = side;
                pptr[depth++] = p;
 
-               p = avl_child( p, cmp );
-               if ( p == NULL )
+               if ( p->avl_bits[side] == AVL_THREAD )
                        return NULL;
+               p = p->avl_link[side];
        }
+       data = p->avl_data;
 
        /* If this node has two children, swap so we are deleting a node with
         * at most one child.
         */
        if ( p->avl_bits[0] == AVL_CHILD && p->avl_bits[1] == AVL_CHILD &&
                p->avl_link[0] && p->avl_link[1] ) {
-               void *temp;
 
                /* find the immediate predecessor <q> */
                q = p->avl_link[0];
@@ -228,22 +228,25 @@ tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
                        q = q->avl_link[1];
                }
                /* swap */
-               temp = p->avl_data;
                p->avl_data = q->avl_data;
-               q->avl_data = temp;
                p = q;
        }
 
        /* now <p> has at most one child, get it */
        if ( p->avl_link[0] && p->avl_bits[0] == AVL_CHILD ) {
                q = p->avl_link[0];
+               /* Preserve thread continuity */
+               r = p->avl_link[1];
+               nside = 1;
        } else if ( p->avl_link[1] && p->avl_bits[1] == AVL_CHILD ) {
                q = p->avl_link[1];
+               r = p->avl_link[0];
+               nside = 0;
        } else {
                q = NULL;
+               /* No children, no thread to preserve */
        }
 
-       data = p->avl_data;
        ber_memfree( p );
 
        if ( !depth ) {
@@ -256,23 +259,27 @@ tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
        side = pdir[depth];
        p = pptr[depth];
        p->avl_link[side] = q;
-       side_bf = avl_bfs[side];
-       top = NULL;
 
        /* Update child thread */
        if ( q ) {
-               while ( q->avl_bits[!side] == AVL_CHILD )
-                       q = q->avl_link[!side];
-               q->avl_link[!side] = p;
+               for ( ; q->avl_bits[nside] == AVL_CHILD && q->avl_link[nside];
+                       q = q->avl_link[nside] ) ;
+               q->avl_link[nside] = r;
+       } else {
+               /* NULL links are always threads */
+               p->avl_bits[side] = AVL_THREAD;
        }
 
+       side_bf = avl_bfs[side];
+       top = NULL;
        shorter = 1;
+       nside = !side;
   
        while ( shorter ) {
                /* case 1: height unchanged */
                if ( p->avl_bf == EH ) {
                        /* Tree is now heavier on opposite side */
-                       p->avl_bf = avl_bfs[!side];
+                       p->avl_bf = avl_bfs[nside];
                        shorter = 0;
                  
                } else if ( p->avl_bf == side_bf ) {
@@ -285,14 +292,14 @@ tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
                        else
                                top = NULL;
                        /* set <q> to the taller of the two subtrees of <p> */
-                       q = p->avl_link[!side];
+                       q = p->avl_link[nside];
                        if ( q->avl_bf == EH ) {
                                /* case 3a: height unchanged, single rotate */
                                if ( q->avl_bits[side] == AVL_THREAD ) {
                                        q->avl_bits[side] = AVL_CHILD;
-                                       p->avl_bits[!side] = AVL_THREAD;
+                                       p->avl_bits[nside] = AVL_THREAD;
                                } else {
-                                       p->avl_link[!side] = q->avl_link[side];
+                                       p->avl_link[nside] = q->avl_link[side];
                                        q->avl_link[side] = p;
                                }
                                shorter = 0;
@@ -303,9 +310,9 @@ tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
                                /* case 3b: height reduced, single rotate */
                                if ( q->avl_bits[side] == AVL_THREAD ) {
                                        q->avl_bits[side] = AVL_CHILD;
-                                       p->avl_bits[!side] = AVL_THREAD;
+                                       p->avl_bits[nside] = AVL_THREAD;
                                } else {
-                                       p->avl_link[!side] = q->avl_link[side];
+                                       p->avl_link[nside] = q->avl_link[side];
                                        q->avl_link[side] = p;
                                }
                                shorter = 1;
@@ -315,20 +322,20 @@ tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
                        } else {
                                /* case 3c: height reduced, balance factors opposite */
                                r = q->avl_link[side];
-                               if ( r->avl_bits[!side] == AVL_THREAD ) {
-                                       r->avl_bits[!side] = AVL_CHILD;
+                               if ( r->avl_bits[nside] == AVL_THREAD ) {
+                                       r->avl_bits[nside] = AVL_CHILD;
                                        q->avl_bits[side] = AVL_THREAD;
                                } else {
-                                       q->avl_link[side] = r->avl_link[!side];
-                                       r->avl_link[!side] = q;
+                                       q->avl_link[side] = r->avl_link[nside];
+                                       r->avl_link[nside] = q;
                                }
 
                                if ( r->avl_bits[side] == AVL_THREAD ) {
                                        r->avl_bits[side] = AVL_CHILD;
-                                       p->avl_bits[!side] = AVL_THREAD;
-                                       p->avl_link[!side] = r;
+                                       p->avl_bits[nside] = AVL_THREAD;
+                                       p->avl_link[nside] = r;
                                } else {
-                                       p->avl_link[!side] = r->avl_link[side];
+                                       p->avl_link[nside] = r->avl_link[side];
                                        r->avl_link[side] = p;
                                }
 
@@ -407,10 +414,8 @@ tavl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
        int     cmp;
 
        while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
-               if ( cmp < 0 )
-                       root = avl_lchild( root );
-               else
-                       root = avl_rchild( root );
+               cmp = cmp > 0;
+               root = avl_child( root, cmp );
        }
        return root;
 }
@@ -421,11 +426,37 @@ tavl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
        int     cmp;
 
        while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
-               if ( cmp < 0 )
-                       root = avl_lchild( root );
-               else
-                       root = avl_rchild( root );
+               cmp = cmp > 0;
+               root = avl_child( root, cmp );
        }
 
        return( root ? root->avl_data : 0 );
 }
+
+/* Return the leftmost or rightmost node in the tree */
+Avlnode *
+tavl_end( Avlnode *root, int dir )
+{
+       if ( root ) {
+               while ( root->avl_bits[dir] == AVL_CHILD )
+                       root = root->avl_link[dir];
+       }
+       return root;
+}
+
+/* Return the next node in the given direction */
+Avlnode *
+tavl_next( Avlnode *root, int dir )
+{
+       if ( root ) {
+               int c = root->avl_bits[dir];
+
+               root = root->avl_link[dir];
+               if ( c == AVL_CHILD ) {
+                       dir ^= 1;
+                       while ( root->avl_bits[dir] == AVL_CHILD )
+                               root = root->avl_link[dir];
+               }
+       }
+       return root;
+}
diff --git a/libraries/liblutil/testtavl.c b/libraries/liblutil/testtavl.c
new file mode 100644 (file)
index 0000000..90710ae
--- /dev/null
@@ -0,0 +1,158 @@
+/* testavl.c - Test Tim Howes AVL code */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2005 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was originally developed by the University of Michigan
+ * (as part of U-MICH LDAP). Additional contributors include
+ *   Howard Chu
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/stdlib.h>
+#include <ac/string.h>
+
+#define AVL_INTERNAL
+#include "avl.h"
+
+static void ravl_print LDAP_P(( Avlnode *root, int depth, int thread ));
+static void myprint LDAP_P(( Avlnode *root ));
+static int avl_strcmp LDAP_P(( const void *s, const void *t ));
+
+int
+main( int argc, char **argv )
+{
+       Avlnode *tree = NULL, *n;
+       char    command[ 10 ];
+       char    name[ 80 ];
+       char    *p;
+
+       printf( "> " );
+       while ( fgets( command, sizeof( command ), stdin ) != NULL ) {
+               switch( *command ) {
+               case 'n':       /* new tree */
+                       ( void ) tavl_free( tree, free );
+                       tree = NULL;
+                       break;
+               case 'p':       /* print */
+                       ( void ) myprint( tree );
+                       break;
+               case 't':       /* traverse with first, next */
+                       printf( "***\n" );
+                       for ( n = tavl_end( tree, TAVL_DIR_LEFT );
+                           n != NULL;
+                               n = tavl_next( n, TAVL_DIR_RIGHT ))
+                               printf( "%s\n", n->avl_data );
+                       printf( "***\n" );
+                       break;
+               case 'f':       /* find */
+                       printf( "data? " );
+                       if ( fgets( name, sizeof( name ), stdin ) == NULL )
+                               exit( EXIT_SUCCESS );
+                       name[ strlen( name ) - 1 ] = '\0';
+                       if ( (p = (char *) tavl_find( tree, name, avl_strcmp ))
+                           == NULL )
+                               printf( "Not found.\n\n" );
+                       else
+                               printf( "%s\n\n", p );
+                       break;
+               case 'i':       /* insert */
+                       printf( "data? " );
+                       if ( fgets( name, sizeof( name ), stdin ) == NULL )
+                               exit( EXIT_SUCCESS );
+                       name[ strlen( name ) - 1 ] = '\0';
+                       if ( tavl_insert( &tree, strdup( name ), avl_strcmp, 
+                           avl_dup_error ) != 0 )
+                               printf( "\nNot inserted!\n" );
+                       break;
+               case 'd':       /* delete */
+                       printf( "data? " );
+                       if ( fgets( name, sizeof( name ), stdin ) == NULL )
+                               exit( EXIT_SUCCESS );
+                       name[ strlen( name ) - 1 ] = '\0';
+                       if ( tavl_delete( &tree, name, avl_strcmp ) == NULL )
+                               printf( "\nNot found!\n" );
+                       break;
+               case 'q':       /* quit */
+                       exit( EXIT_SUCCESS );
+                       break;
+               case '\n':
+                       break;
+               default:
+                       printf("Commands: insert, delete, print, new, quit\n");
+               }
+
+               printf( "> " );
+       }
+
+       return( 0 );
+}
+
+static const char bfc_array[] = "\\-/";
+static const char *bfcs = bfc_array+1;
+
+static void ravl_print( Avlnode *root, int depth, int thread )
+{
+       int     i;
+
+       if ( root && !thread )
+       ravl_print( root->avl_link[1], depth+1, root->avl_bits[1] == AVL_THREAD );
+
+       for ( i = 0; i < depth; i++ )
+               printf( "   " );
+       if ( thread )
+               printf( "~" );
+       else if ( root )
+               printf( "%c", bfcs[root->avl_bf] );
+       else
+               printf( " " );
+       if ( !root) {
+               printf( ".\n" );
+               return;
+       }
+       printf( "%s\n", (char *) root->avl_data );
+
+       if ( !thread )
+       ravl_print( root->avl_link[0], depth+1, root->avl_bits[0] == AVL_THREAD );
+}
+
+static void myprint( Avlnode *root )
+{
+       printf( "********\n" );
+
+       if ( root == 0 )
+               printf( "\tNULL\n" );
+       else
+               ravl_print( root, 0, 0 );
+
+       printf( "********\n" );
+}
+
+static int avl_strcmp( const void *s, const void *t )
+{
+       return strcmp( s, t );
+}