Commit 2c21fdce authored by Kurt Zeilenga's avatar Kurt Zeilenga
Browse files

move AVL routines into -llutil

update misc notices
parent a6bc7469
/* include/portable.h.in. Generated automatically from configure.in by autoheader. */
/* Copyright 1998-2003 The OpenLDAP Foundation
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2003 The OpenLDAP Foundation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......
# Libraries Makefile for OpenLDAP
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2003 The OpenLDAP Foundation.
## All rights reserved.
##
......@@ -16,7 +18,6 @@ SUBDIRS= \
liblber \
liblunicode \
libldap libldap_r \
libavl \
libldbm \
librewrite
# LIBAVL
# $OpenLDAP$
## Copyright 1998-2003 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>.
SRCS = avl.c testavl.c
XSRCS = version.c
OBJS = avl.o
LDAP_INCDIR= ../../include
LDAP_LIBDIR= ../../libraries
LIBRARY = libavl.a
PROGRAMS = testavl
XLIBS = $(LIBRARY) $(LDAP_LIBLBER_LA) $(LDAP_LIBLUTIL_A)
testavl: $(XLIBS) testavl.o
$(LTLINK) -o $@ testavl.o $(LIBS)
/* avl.c - routines to implement an avl tree */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2003 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.
*/
/* This work was originally developed by the University of Michigan
* (as part of U-MICH LDAP).
*/
#include "portable.h"
#include <stdio.h>
#include <ac/stdlib.h>
#ifdef CSRIMALLOC
#define ber_memalloc malloc
#define ber_memrealloc realloc
#define ber_memfree free
#else
#include "lber.h"
#endif
#define AVL_INTERNAL
#include "avl.h"
#define ROTATERIGHT(x) { \
Avlnode *tmp;\
if ( *(x) == NULL || (*(x))->avl_left == NULL ) {\
(void) fputs("RR error\n", stderr); exit( EXIT_FAILURE ); \
}\
tmp = (*(x))->avl_left;\
(*(x))->avl_left = tmp->avl_right;\
tmp->avl_right = *(x);\
*(x) = tmp;\
}
#define ROTATELEFT(x) { \
Avlnode *tmp;\
if ( *(x) == NULL || (*(x))->avl_right == NULL ) {\
(void) fputs("RL error\n", stderr); exit( EXIT_FAILURE ); \
}\
tmp = (*(x))->avl_right;\
(*(x))->avl_right = tmp->avl_left;\
tmp->avl_left = *(x);\
*(x) = tmp;\
}
/*
* ravl_insert - called from avl_insert() to do a recursive insert into
* and balance of an avl tree.
*/
static int
ravl_insert(
Avlnode **iroot,
void* data,
int *taller,
AVL_CMP fcmp, /* comparison function */
AVL_DUP fdup, /* function to call for duplicates */
int depth
)
{
int rc, cmp, tallersub;
Avlnode *l, *r;
if ( *iroot == 0 ) {
if ( (*iroot = (Avlnode *) ber_memalloc( sizeof( Avlnode ) ))
== NULL ) {
return( -1 );
}
(*iroot)->avl_left = 0;
(*iroot)->avl_right = 0;
(*iroot)->avl_bf = 0;
(*iroot)->avl_data = data;
*taller = 1;
return( 0 );
}
cmp = (*fcmp)( data, (*iroot)->avl_data );
/* equal - duplicate name */
if ( cmp == 0 ) {
*taller = 0;
return( (*fdup)( (*iroot)->avl_data, data ) );
}
/* go right */
else if ( cmp > 0 ) {
rc = ravl_insert( &((*iroot)->avl_right), data, &tallersub,
fcmp, fdup, depth );
if ( tallersub )
switch ( (*iroot)->avl_bf ) {
case LH : /* left high - balance is restored */
(*iroot)->avl_bf = EH;
*taller = 0;
break;
case EH : /* equal height - now right heavy */
(*iroot)->avl_bf = RH;
*taller = 1;
break;
case RH : /* right heavy to start - right balance */
r = (*iroot)->avl_right;
switch ( r->avl_bf ) {
case LH : /* double rotation left */
l = r->avl_left;
switch ( l->avl_bf ) {
case LH : (*iroot)->avl_bf = EH;
r->avl_bf = RH;
break;
case EH : (*iroot)->avl_bf = EH;
r->avl_bf = EH;
break;
case RH : (*iroot)->avl_bf = LH;
r->avl_bf = EH;
break;
}
l->avl_bf = EH;
ROTATERIGHT( (&r) )
(*iroot)->avl_right = r;
ROTATELEFT( iroot )
*taller = 0;
break;
case EH : /* This should never happen */
break;
case RH : /* single rotation left */
(*iroot)->avl_bf = EH;
r->avl_bf = EH;
ROTATELEFT( iroot )
*taller = 0;
break;
}
break;
}
else
*taller = 0;
}
/* go left */
else {
rc = ravl_insert( &((*iroot)->avl_left), data, &tallersub,
fcmp, fdup, depth );
if ( tallersub )
switch ( (*iroot)->avl_bf ) {
case LH : /* left high to start - left balance */
l = (*iroot)->avl_left;
switch ( l->avl_bf ) {
case LH : /* single rotation right */
(*iroot)->avl_bf = EH;
l->avl_bf = EH;
ROTATERIGHT( iroot )
*taller = 0;
break;
case EH : /* this should never happen */
break;
case RH : /* double rotation right */
r = l->avl_right;
switch ( r->avl_bf ) {
case LH : (*iroot)->avl_bf = RH;
l->avl_bf = EH;
break;
case EH : (*iroot)->avl_bf = EH;
l->avl_bf = EH;
break;
case RH : (*iroot)->avl_bf = EH;
l->avl_bf = LH;
break;
}
r->avl_bf = EH;
ROTATELEFT( (&l) )
(*iroot)->avl_left = l;
ROTATERIGHT( iroot )
*taller = 0;
break;
}
break;
case EH : /* equal height - now left heavy */
(*iroot)->avl_bf = LH;
*taller = 1;
break;
case RH : /* right high - balance is restored */
(*iroot)->avl_bf = EH;
*taller = 0;
break;
}
else
*taller = 0;
}
return( rc );
}
/*
* avl_insert -- insert a node containing data data into the avl tree
* with root root. fcmp is a function to call to compare the data portion
* of two nodes. it should take two arguments and return <, >, or == 0,
* depending on whether its first argument is <, >, or == its second
* argument (like strcmp, e.g.). fdup is a function to call when a duplicate
* node is inserted. it should return 0, or -1 and its return value
* will be the return value from avl_insert in the case of a duplicate node.
* the function will be called with the original node's data as its first
* argument and with the incoming duplicate node's data as its second
* argument. this could be used, for example, to keep a count with each
* node.
*
* NOTE: this routine may malloc memory
*/
int
avl_insert( Avlnode **root, void* data, AVL_CMP fcmp, AVL_DUP fdup )
{
int taller;
return( ravl_insert( root, data, &taller, fcmp, fdup, 0 ) );
}
/*
* right_balance() - called from delete when root's right subtree has
* been shortened because of a deletion.
*/
static int
right_balance( Avlnode **root )
{
int shorter = -1;
Avlnode *r, *l;
switch( (*root)->avl_bf ) {
case RH: /* was right high - equal now */
(*root)->avl_bf = EH;
shorter = 1;
break;
case EH: /* was equal - left high now */
(*root)->avl_bf = LH;
shorter = 0;
break;
case LH: /* was right high - balance */
l = (*root)->avl_left;
switch ( l->avl_bf ) {
case RH : /* double rotation left */
r = l->avl_right;
switch ( r->avl_bf ) {
case RH :
(*root)->avl_bf = EH;
l->avl_bf = LH;
break;
case EH :
(*root)->avl_bf = EH;
l->avl_bf = EH;
break;
case LH :
(*root)->avl_bf = RH;
l->avl_bf = EH;
break;
}
r->avl_bf = EH;
ROTATELEFT( (&l) )
(*root)->avl_left = l;
ROTATERIGHT( root )
shorter = 1;
break;
case EH : /* right rotation */
(*root)->avl_bf = LH;
l->avl_bf = RH;
ROTATERIGHT( root );
shorter = 0;
break;
case LH : /* single rotation right */
(*root)->avl_bf = EH;
l->avl_bf = EH;
ROTATERIGHT( root )
shorter = 1;
break;
}
break;
}
return( shorter );
}
/*
* left_balance() - called from delete when root's left subtree has
* been shortened because of a deletion.
*/
static int
left_balance( Avlnode **root )
{
int shorter = -1;
Avlnode *r, *l;
switch( (*root)->avl_bf ) {
case LH: /* was left high - equal now */
(*root)->avl_bf = EH;
shorter = 1;
break;
case EH: /* was equal - right high now */
(*root)->avl_bf = RH;
shorter = 0;
break;
case RH: /* was right high - balance */
r = (*root)->avl_right;
switch ( r->avl_bf ) {
case LH : /* double rotation left */
l = r->avl_left;
switch ( l->avl_bf ) {
case LH :
(*root)->avl_bf = EH;
r->avl_bf = RH;
break;
case EH :
(*root)->avl_bf = EH;
r->avl_bf = EH;
break;
case RH :
(*root)->avl_bf = LH;
r->avl_bf = EH;
break;
}
l->avl_bf = EH;
ROTATERIGHT( (&r) )
(*root)->avl_right = r;
ROTATELEFT( root )
shorter = 1;
break;
case EH : /* single rotation left */
(*root)->avl_bf = RH;
r->avl_bf = LH;
ROTATELEFT( root );
shorter = 0;
break;
case RH : /* single rotation left */
(*root)->avl_bf = EH;
r->avl_bf = EH;
ROTATELEFT( root )
shorter = 1;
break;
}
break;
}
return( shorter );
}
/*
* ravl_delete() - called from avl_delete to do recursive deletion of a
* node from an avl tree. It finds the node recursively, deletes it,
* and returns shorter if the tree is shorter after the deletion and
* rebalancing.
*/
static void*
ravl_delete( Avlnode **root, void* data, AVL_CMP fcmp, int *shorter )
{
int shortersubtree = 0;
int cmp;
void* savedata;
Avlnode *minnode, *savenode;
if ( *root == NULLAVL )
return( 0 );
cmp = (*fcmp)( data, (*root)->avl_data );
/* found it! */
if ( cmp == 0 ) {
savenode = *root;
savedata = savenode->avl_data;
/* simple cases: no left child */
if ( (*root)->avl_left == 0 ) {
*root = (*root)->avl_right;
*shorter = 1;
ber_memfree( (char *) savenode );
return( savedata );
/* no right child */
} else if ( (*root)->avl_right == 0 ) {
*root = (*root)->avl_left;
*shorter = 1;
ber_memfree( (char *) savenode );
return( savedata );
}
/*
* avl_getmin will return to us the smallest node greater
* than the one we are trying to delete. deleting this node
* from the right subtree is guaranteed to end in one of the
* simple cases above.
*/
minnode = (*root)->avl_right;
while ( minnode->avl_left != NULLAVL )
minnode = minnode->avl_left;
/* swap the data */
(*root)->avl_data = minnode->avl_data;
minnode->avl_data = savedata;
savedata = ravl_delete( &(*root)->avl_right, data, fcmp,
&shortersubtree );
if ( shortersubtree )
*shorter = right_balance( root );
else
*shorter = 0;
/* go left */
} else if ( cmp < 0 ) {
if ( (savedata = ravl_delete( &(*root)->avl_left, data, fcmp,
&shortersubtree )) == 0 ) {
*shorter = 0;
return( 0 );
}
/* left subtree shorter? */
if ( shortersubtree )
*shorter = left_balance( root );
else
*shorter = 0;
/* go right */
} else {
if ( (savedata = ravl_delete( &(*root)->avl_right, data, fcmp,
&shortersubtree )) == 0 ) {
*shorter = 0;
return( 0 );
}
if ( shortersubtree )
*shorter = right_balance( root );
else
*shorter = 0;
}
return( savedata );
}
/*
* avl_delete() - deletes the node containing data (according to fcmp) from
* the avl tree rooted at root.
*/
void*
avl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
{
int shorter;
return( ravl_delete( root, data, fcmp, &shorter ) );
}
static int
avl_inapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
{
if ( root == 0 )
return( AVL_NOMORE );
if ( root->avl_left != 0 )
if ( avl_inapply( root->avl_left, fn, arg, stopflag )
== stopflag )
return( stopflag );
if ( (*fn)( root->avl_data, arg ) == stopflag )
return( stopflag );
if ( root->avl_right == 0 )
return( AVL_NOMORE );
else
return( avl_inapply( root->avl_right, fn, arg, stopflag ) );
}
static int
avl_postapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
{
if ( root == 0 )
return( AVL_NOMORE );
if ( root->avl_left != 0 )
if ( avl_postapply( root->avl_left, fn, arg, stopflag )
== stopflag )
return( stopflag );
if ( root->avl_right != 0 )
if ( avl_postapply( root->avl_right, fn, arg, stopflag )
== stopflag )
return( stopflag );
return( (*fn)( root->avl_data, arg ) );
}
static int
avl_preapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
{
if ( root == 0 )
return( AVL_NOMORE );
if ( (*fn)( root->avl_data, arg ) == stopflag )
return( stopflag );
if ( root->avl_left != 0 )
if ( avl_preapply( root->avl_left, fn, arg, stopflag )
== stopflag )
return( stopflag );
if ( root->avl_right == 0 )
return( AVL_NOMORE );
else
return( avl_preapply( root->avl_right, fn, arg, stopflag ) );
}
/*
* avl_apply -- avl tree root is traversed, function fn is called with
* arguments arg and the data portion of each node. if fn returns stopflag,
* the traversal is cut short, otherwise it continues. Do not use -6 as
* a stopflag, as this is what is used to indicate the traversal ran out
* of nodes.
*/
int
avl_apply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag, int type )
{
switch ( type ) {
case AVL_INORDER:
return( avl_inapply( root, fn, arg, stopflag ) );
case AVL_PREORDER:
return( avl_preapply( root, fn, arg, stopflag ) );
case AVL_POSTORDER:
return( avl_postapply( root, fn, arg, stopflag ) );
default:
fprintf( stderr, "Invalid traversal type %d\n", type );
return( -1 );
}
/* NOTREACHED */
}
/*
* avl_prefixapply - traverse avl tree root, applying function fprefix
* to any nodes that match. fcmp is called with data as its first arg
* and the current node's data as its second arg. it should return
* 0 if they match, < 0 if data is less, and > 0 if data is greater.
* the idea is to efficiently find all nodes that are prefixes of
* some key... Like avl_apply, this routine also takes a stopflag
* and will return prematurely if fmatch returns this value. Otherwise,
* AVL_NOMORE is returned.
*/
int
avl_prefixapply(
Avlnode *root,
void* data,
AVL_CMP fmatch,
void* marg,
AVL_CMP fcmp,
void* carg,
int stopflag
)
{