#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"
static const int avl_bfs[] = {LH, RH};
int
avl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
{
Avlnode *t, *p, *s, *q, *r;
int a, cmp, ncmp;
if ( *root == NULL ) {
if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
return( -1 );
}
r->avl_link[0] = r->avl_link[1] = NULL;
r->avl_data = data;
r->avl_bf = EH;
*root = r;
return( 0 );
}
t = NULL;
s = p = *root;
while (1) {
cmp = fcmp( data, p->avl_data );
if ( cmp == 0 )
return (*fdup)( p->avl_data, data );
cmp = (cmp > 0);
q = p->avl_link[cmp];
if (q == NULL) {
if (( q = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
return( -1 );
}
q->avl_link[0] = q->avl_link[1] = NULL;
q->avl_data = data;
q->avl_bf = EH;
p->avl_link[cmp] = q;
break;
} else if ( q->avl_bf ) {
t = p;
s = q;
}
p = q;
}
cmp = fcmp( data, s->avl_data ) > 0;
r = p = s->avl_link[cmp];
a = avl_bfs[cmp];
while ( p != q ) {
cmp = fcmp( data, p->avl_data ) > 0;
p->avl_bf = avl_bfs[cmp];
p = p->avl_link[cmp];
}
if ( s->avl_bf == EH ) {
s->avl_bf = a;
return 0;
} else if ( s->avl_bf == -a ) {
s->avl_bf = EH;
return 0;
} else if ( s->avl_bf == a ) {
cmp = (a > 0);
ncmp = !cmp;
if ( r->avl_bf == a ) {
p = r;
s->avl_link[cmp] = r->avl_link[ncmp];
r->avl_link[ncmp] = s;
s->avl_bf = 0;
r->avl_bf = 0;
} else if ( r->avl_bf == -a ) {
p = r->avl_link[ncmp];
r->avl_link[ncmp] = p->avl_link[cmp];
p->avl_link[cmp] = r;
s->avl_link[cmp] = p->avl_link[ncmp];
p->avl_link[ncmp] = s;
if ( p->avl_bf == a ) {
s->avl_bf = -a;
r->avl_bf = 0;
} else if ( p->avl_bf == -a ) {
s->avl_bf = 0;
r->avl_bf = a;
} else {
s->avl_bf = 0;
r->avl_bf = 0;
}
p->avl_bf = 0;
}
if ( t == NULL )
*root = p;
else if ( s == t->avl_right )
t->avl_right = p;
else
t->avl_left = p;
}
return 0;
}
void*
avl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
{
Avlnode *p, *q, *r, *top;
int side, side_bf, shorter, nside;
Avlnode *pptr[sizeof(void *)*8];
unsigned char pdir[sizeof(void *)*8];
int depth = 0;
if ( *root == NULL )
return NULL;
p = *root;
while (1) {
side = fcmp( data, p->avl_data );
if ( !side )
break;
side = ( side > 0 );
pdir[depth] = side;
pptr[depth++] = p;
p = p->avl_link[side];
if ( p == NULL )
return p;
}
data = p->avl_data;
if ( p->avl_link[0] && p->avl_link[1] ) {
q = p->avl_link[0];
side = depth;
pdir[depth++] = 0;
while (q->avl_link[1]) {
pdir[depth] = 1;
pptr[depth++] = q;
q = q->avl_link[1];
}
r = p->avl_link[0];
p->avl_link[0] = q->avl_link[0];
q->avl_link[0] = r;
q->avl_link[1] = p->avl_link[1];
p->avl_link[1] = NULL;
q->avl_bf = p->avl_bf;
pptr[side] = q;
if ( side ) {
r = pptr[side-1];
r->avl_link[pdir[side-1]] = q;
} else {
*root = q;
}
if ( depth-side > 1 ) {
r = pptr[depth-1];
r->avl_link[1] = p;
} else {
q->avl_link[0] = p;
}
}
q = p->avl_link[0] ? p->avl_link[0] : p->avl_link[1];
ber_memfree( p );
if ( !depth ) {
*root = q;
return data;
}
depth--;
p = pptr[depth];
side = pdir[depth];
p->avl_link[side] = q;
top = NULL;
shorter = 1;
while ( shorter ) {
p = pptr[depth];
side = pdir[depth];
nside = !side;
side_bf = avl_bfs[side];
if ( p->avl_bf == EH ) {
p->avl_bf = avl_bfs[nside];
shorter = 0;
} else if ( p->avl_bf == side_bf ) {
p->avl_bf = EH;
} else {
if ( depth )
top = pptr[depth-1];
else
top = NULL;
q = p->avl_link[nside];
if ( q->avl_bf == EH ) {
p->avl_link[nside] = q->avl_link[side];
q->avl_link[side] = p;
shorter = 0;
q->avl_bf = side_bf;
p->avl_bf = (- side_bf);
} else if ( q->avl_bf == p->avl_bf ) {
p->avl_link[nside] = q->avl_link[side];
q->avl_link[side] = p;
shorter = 1;
q->avl_bf = EH;
p->avl_bf = EH;
} else {
r = q->avl_link[side];
q->avl_link[side] = r->avl_link[nside];
r->avl_link[nside] = q;
p->avl_link[nside] = r->avl_link[side];
r->avl_link[side] = p;
if ( r->avl_bf == side_bf ) {
q->avl_bf = (- side_bf);
p->avl_bf = EH;
} else if ( r->avl_bf == (- side_bf)) {
q->avl_bf = EH;
p->avl_bf = side_bf;
} else {
q->avl_bf = EH;
p->avl_bf = EH;
}
r->avl_bf = EH;
q = r;
}
if ( top == NULL ) {
*root = q;
} else if (top->avl_link[0] == p) {
top->avl_link[0] = q;
} else {
top->avl_link[1] = q;
}
p = q;
}
if ( !depth )
break;
depth--;
}
return data;
}
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 ) );
}
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 );
}
}
int
avl_prefixapply(
Avlnode *root,
void* data,
AVL_CMP fmatch,
void* marg,
AVL_CMP fcmp,
void* carg,
int stopflag
)
{
int cmp;
if ( root == 0 )
return( AVL_NOMORE );
cmp = (*fcmp)( data, root->avl_data );
if ( cmp == 0 ) {
if ( (*fmatch)( root->avl_data, marg ) == stopflag )
return( stopflag );
if ( root->avl_left != 0 )
if ( avl_prefixapply( root->avl_left, data, fmatch,
marg, fcmp, carg, stopflag ) == stopflag )
return( stopflag );
if ( root->avl_right != 0 )
return( avl_prefixapply( root->avl_right, data, fmatch,
marg, fcmp, carg, stopflag ) );
else
return( AVL_NOMORE );
} else if ( cmp < 0 ) {
if ( root->avl_left != 0 )
return( avl_prefixapply( root->avl_left, data, fmatch,
marg, fcmp, carg, stopflag ) );
} else {
if ( root->avl_right != 0 )
return( avl_prefixapply( root->avl_right, data, fmatch,
marg, fcmp, carg, stopflag ) );
}
return( AVL_NOMORE );
}
int
avl_free( Avlnode *root, AVL_FREE dfree )
{
int nleft, nright;
if ( root == 0 )
return( 0 );
nleft = nright = 0;
if ( root->avl_left != 0 )
nleft = avl_free( root->avl_left, dfree );
if ( root->avl_right != 0 )
nright = avl_free( root->avl_right, dfree );
if ( dfree )
(*dfree)( root->avl_data );
ber_memfree( root );
return( nleft + nright + 1 );
}
Avlnode *
avl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
{
int cmp;
while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
cmp = cmp > 0;
root = root->avl_link[cmp];
}
return root;
}
void*
avl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
{
int cmp;
while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
cmp = cmp > 0;
root = root->avl_link[cmp];
}
return( root ? root->avl_data : 0 );
}
void*
avl_find_lin( Avlnode *root, const void* data, AVL_CMP fcmp )
{
void* res;
if ( root == 0 )
return( NULL );
if ( (*fcmp)( data, root->avl_data ) == 0 )
return( root->avl_data );
if ( root->avl_left != 0 )
if ( (res = avl_find_lin( root->avl_left, data, fcmp ))
!= NULL )
return( res );
if ( root->avl_right == 0 )
return( NULL );
else
return( avl_find_lin( root->avl_right, data, fcmp ) );
}
static void* *avl_list;
static int avl_maxlist;
static int avl_nextlist;
#define AVL_GRABSIZE 100
static int
avl_buildlist( void* data, void* arg )
{
static int slots;
if ( avl_list == (void* *) 0 ) {
avl_list = (void* *) ber_memalloc(AVL_GRABSIZE * sizeof(void*));
slots = AVL_GRABSIZE;
avl_maxlist = 0;
} else if ( avl_maxlist == slots ) {
slots += AVL_GRABSIZE;
avl_list = (void* *) ber_memrealloc( (char *) avl_list,
(unsigned) slots * sizeof(void*));
}
avl_list[ avl_maxlist++ ] = data;
return( 0 );
}
void*
avl_getfirst( Avlnode *root )
{
if ( avl_list ) {
ber_memfree( (char *) avl_list);
avl_list = (void* *) 0;
}
avl_maxlist = 0;
avl_nextlist = 0;
if ( root == 0 )
return( 0 );
(void) avl_apply( root, avl_buildlist, (void*) 0, -1, AVL_INORDER );
return( avl_list[ avl_nextlist++ ] );
}
void*
avl_getnext( void )
{
if ( avl_list == 0 )
return( 0 );
if ( avl_nextlist == avl_maxlist ) {
ber_memfree( (void*) avl_list);
avl_list = (void* *) 0;
return( 0 );
}
return( avl_list[ avl_nextlist++ ] );
}
int
avl_dup_error( void* left, void* right )
{
return( -1 );
}
int
avl_dup_ok( void* left, void* right )
{
return( 0 );
}