/* pyavl -- File "avl.c" */
/* AVL trees with RANK field and parent pointers */
#include "avl.h"
#ifdef AVL_SHOW_ERROR_ON
#define AVL_SHOW_ERROR(fmt,arg) fprintf(stderr, "! avl.c: " fmt, arg)
#else
#define AVL_SHOW_ERROR(fmt,arg) (void) (fmt), (void) (arg)
#endif
const void *
avl_default_item_copy (const void *item)
{
return (const void *) item;
}
void *
avl_default_item_dispose (void *item)
{
(void)item; /* for -Wall */
return (void *) NULL;
}
#ifndef MPW_C
typedef uint32_t rbal_t; /* integral type to encode rank and skew bits */
#else
typedef UInt32 rbal_t;
#endif
/*
* avl_node structure
*/
typedef struct avl_node
{
struct avl_node *sub[2];
struct avl_node *up;
rbal_t rbal;
void *item;
}
avl_node;
/*
* avl_tree structure
*/
struct avl_tree_
{
avl_node *root;
avl_size_t count; /* how many nodes in tree rooted at [root] */
avl_compare_func compare; /* compare items */
avl_item_copy_func copy;
avl_item_dispose_func dispose;
avl_alloc_func alloc; /* to allocate memory (same signature as malloc) */
avl_dealloc_func dealloc; /* to deallocate memory (same signature as free) */
void *param;
};
#define Item_Compare(cmp, tree, item1, item2)\
(*cmp)(tree->param, item1, item2)
/* patches (November 2004) */
#if AVL_CMPERR != 0
#define CMPERR_CHECK__FIND(param) if (avl_errcmp_occurred(param)) return NULL
#define CMPERR_CHECK__INDEX(param) if (avl_errcmp_occurred(param)) return 0
#define CMPERR_CHECK__SPAN(param) if (avl_errcmp_occurred(param)) return -2
#define CMPERR_CHECK__INS(param) if (avl_errcmp_occurred(param)) return -2
#define CMPERR_CHECK__DEL(param) (avl_errcmp_occurred(param) ? -2 : 0)
#define CMPERR_CHECK__SPLIT(param) if (avl_errcmp_occurred(param)) return -2
#define CMPERR_CHECK__VERIFY(param) && (!avl_errcmp_occurred(param))
#else
#define CMPERR_CHECK__FIND(param) (void) param
#define CMPERR_CHECK__INDEX(param) (void) param
#define CMPERR_CHECK__SPAN(param) (void) param
#define CMPERR_CHECK__INS(param) (void) param
#define CMPERR_CHECK__DEL(param) 0
#define CMPERR_CHECK__SPLIT(param) (void) param
#define CMPERR_CHECK__VERIFY(param) /* nothing */
#endif
#define sub_left(a) (a)->sub[0]
#define sub_right(a) (a)->sub[1]
#define get_item(a) (a)->item
/* RANK(a) = size of left subtree + 1 */
#define rbal(a)\
(a)->rbal
#define rzero(a)\
( rbal(a) & ~3 )
#define get_bal(a)\
( rbal(a) & 3 )
#define is_lskew(a)\
( rbal(a) & 1 )
#define is_rskew(a)\
( rbal(a)>>1 & 1)
#define set_lskew(a)\
( rbal(a) |= 1 )
#define set_rskew(a)\
( rbal(a) |= 2 )
#define set_skew(a,d)\
( rbal(a) |= (1 << d) )
#define unset_lskew(a)\
( rbal(a) &= ~1 )
#define unset_rskew(a)\
( rbal(a) &= ~2 )
#define get_rank(a)\
( rbal(a) >> 2 )
#define set_rank(a,r)\
( rbal(a) = (r<<2 | get_bal(a)) )
#define incr_rank(a,r)\
( rbal(a) += r<<2 )
#define decr_rank(a,r)\
( rbal(a) -= r<<2 )
#define AVL_MIN_DEPTH 0
/*** Node management ***/
#define DETACH_FUNC 1 /* nonzero to use function not macro */
/* helper structure */
typedef enum
{
OP_BACKUP, OP_DETACH, OP_FREE
}
whichop_t;
struct ptr_handler
{
whichop_t whichop;
void *ptr;
};
#define ini_ptr_handler(h,op) struct ptr_handler h = { OP_##op, NULL }
#define clear_node(a) \
sub_left(a) = NULL; \
sub_right(a) = NULL; \
(a)->up = NULL; \
rbal(a) = 4u
/* Called by 'avl_ins', 'avl_dup', 'node_slice' */
static avl_node *
new_node (void *item, avl_node * up, avl_tree t)
{
avl_node *a = (*t->alloc) (sizeof (avl_node));
if (a != NULL)
{
sub_left (a) = NULL;
sub_right (a) = NULL;
a->up = up;
a->rbal = 4u;
a->item = (*t->copy) (item);
}
return a;
}
static void
free_node (avl_node * a, avl_tree t)
{
a->item = (*t->dispose) (a->item);
(*t->dealloc) (a);
}
#define backup_item(backup,item,t) if (backup == NULL) ; else *backup = (*t->copy)(item)
#if ! DETACH_FUNC
/* macro to detach node [a] from tree [t] */
#define detach_node(a,t,h) { struct ptr_handler *ch = h; \
clear_node(a); \
do { \
if (ch == NULL) ; \
else if (ch->whichop == OP_DETACH){ \
ch->ptr = a; \
break; \
} else if (ch->whichop == OP_BACKUP){ \
ch->ptr = (*t->copy)(a->item); \
} \
free_node(a, t); \
} while (0);} \
t->count--
#else
/* function to detach node [a] from tree [t] */
static void
detach_node (avl_node * a, avl_tree t, struct ptr_handler *h)
{
clear_node (a);
do
{
if (h == NULL);
else if (h->whichop == OP_DETACH)
{
h->ptr = a;
break;
}
else if (h->whichop == OP_BACKUP)
{
h->ptr = (*t->copy) (a->item);
}
free_node (a, t);
}
while (0);
t->count--;
}
#endif /* DETACH_FUNC */
/*** Tree methods ***/
avl_tree
avl_create (avl_compare_func compare, avl_item_copy_func copy,
avl_item_dispose_func dispose, avl_alloc_func alloc,
avl_dealloc_func dealloc, void *param)
{
avl_tree t = (*alloc) (sizeof (struct avl_tree_));
if (t == NULL)
AVL_SHOW_ERROR ("%s\n", "couldn't create new handle in avl_create()");
else
{
t->root = NULL;
t->count = 0;
t->param = param;
t->compare = compare;
t->copy = copy;
t->dispose = dispose;
t->alloc = alloc;
t->dealloc = dealloc;
}
return t;
}
/* Empty the tree, using rotations */
static void
node_empty (avl_tree t)
{
avl_node *a, *p;
for (a = t->root; a != NULL;)
{
p = a;
if (sub_right (a) == NULL)
a = sub_left (a);
else
{
while (sub_left (a) != NULL)
{
/* rotR(a) */
a = sub_left (a);
sub_left (p) = sub_right (a);
sub_right (a) = p;
p = a;
}
a = sub_right (p);
}
free_node (p, t);
t->count--;
}
t->root = NULL;
}
/* [t] is an existing tree handle */
/* this function invokes node_empty() */
void
avl_reset (avl_tree t,
avl_compare_func compare,
avl_item_copy_func copy,
avl_item_dispose_func dispose,
avl_alloc_func alloc, avl_dealloc_func dealloc)
{
if (t == NULL)
return;
node_empty (t);
t->compare = compare;
t->copy = copy;
t->dispose = dispose;
t->alloc = alloc;
t->dealloc = dealloc;
}
void
avl_empty (avl_tree t)
{
if (t != NULL)
node_empty (t);
}
/* Destroy nodes, free handle */
void
avl_destroy (avl_tree t)
{
#ifndef AVL_NULLCHECKS
if (t == NULL)
return;
#endif
node_empty (t);
(*t->dealloc) (t);
}
avl_tree
avl_dup (avl_tree t, void *param)
{
#ifndef AVL_NULLCHECKS
if (t == NULL)
return NULL;
#endif
{
avl_tree tt = avl_create (
/*(avl_compare_func) */ t->compare,
/*(avl_item_copy_func) */ t->copy,
/*(avl_item_dispose_func) */ t->dispose,
/*(avl_alloc_func) */ t->alloc,
/*(avl_dealloc_func) */ t->dealloc,
param);
if (tt == NULL)
{
AVL_SHOW_ERROR ("%s\n", "couldn't create new handle in avl_dup()");
return NULL;
}
tt->count = t->count;
if (t->root == NULL)
return tt;
{
avl_node *a, *c, *s;
a = t->root;
tt->root = c = new_node (get_item (a), NULL, t);
if (c == NULL)
goto abort;
sub_right (c) = NULL; /*!!! */
rbal (c) = rbal (a);
while (1)
{
while (sub_left (a) != NULL)
{
a = sub_left (a);
sub_left (c) = s = new_node (get_item (a), NULL, t);
if (s == NULL)
goto recover;
s->up = c;
sub_right (s) = c;
c = s;
rbal (c) = rbal (a);
}
sub_left (c) = NULL;
while (sub_right (a) == NULL)
{
s = sub_right (c);
sub_right (c) = NULL;
c = s;
/* Find successor of [a] in original tree */
do
{
s = a;
a = s->up;
if (a == NULL)
return tt;
}
while (s != sub_left (a));
}
a = sub_right (a);
s = new_node (get_item (a), NULL, t);
if (s == NULL)
goto recover;
sub_right (s) = sub_right (c);
sub_right (c) = s;
s->up = c;
c = s;
rbal (c) = rbal (a);
}
/* recovery code */
recover:
while (1)
{
s = sub_right (c);
sub_right (c) = NULL;
if (s == NULL)
break;
c = s;
}
node_empty (tt);
abort:
(*t->dealloc) (tt);
AVL_SHOW_ERROR ("%s\n", "couldn't allocate node in avl_dup()");
return NULL;
}
}
}
avl_bool_t
avl_isempty (avl_tree t)
{
#ifndef AVL_NULLCHECKS
return t == NULL || t->root == NULL;
#else
return t->root == NULL;
#endif
}
avl_size_t
avl_size (avl_tree t)
{
#ifndef AVL_NULLCHECKS
return t == NULL ? 0 : t->count;
#else
return t->count;
#endif
}
static int
depth (avl_node * a)
{
int h = AVL_MIN_DEPTH;
for (; a != NULL; ++h)
a = a->sub[is_rskew (a)];
return h;
}
static avl_node *
node_first (avl_node * a)
{
while (sub_left (a) != NULL)
a = sub_left (a);
return a;
}
static avl_node *
node_last (avl_node * a)
{
while (sub_right (a) != NULL)
a = sub_right (a);
return a;
}
/* [a] : non-null */
static avl_node *
node_next (avl_node * a)
{
if (sub_right (a) != NULL)
return node_first (sub_right (a));
{
avl_node *p;
do
{
p = a;
a = p->up;
}
while (a != NULL && sub_right (a) == p);
return a;
}
}
/* [a] : non-null */
static avl_node *
node_prev (avl_node * a)
{
if (sub_left (a) != NULL)
return node_last (sub_left (a));
{
avl_node *p;
do
{
p = a;
a = p->up;
}
while (a != NULL && sub_left (a) == p);
return a;
}
}
static avl_node *
node_find (const void *item, avl_tree t)
{
avl_node *a = t->root;
avl_compare_func cmp = t->compare;
int c;
while (a != NULL)
{
c = Item_Compare (cmp, t, item, get_item (a));
CMPERR_CHECK__FIND (t->param);
if (c < 0)
a = a->sub[0];
else if (c)
a = a->sub[1];
else
break;
}
return a;
}
#if 0==1
static avl_node **
avl_search (const void *item, avl_tree t, int *dir)
{
if (t->root == NULL)
return &t->root;
{
avl_node **r = &t->root;
avl_node *a = *r;
avl_compare_func cmp = t->compare;
int c;
while (1)
{
c = Item_Compare (cmp, t, item, get_item (a));
if (!c)
break;
r = &a->sub[c = c > 0];
if (*r == NULL)
{
*dir = c;
break;
}
a = *r;
}
return r;
}
}
#endif
static avl_size_t
get_index (avl_node * a)
{
avl_size_t n = get_rank (a);
avl_node *p;
while ((p = a->up) != NULL)
{
if (a != sub_left (p))
n += get_rank (p);
a = p;
}
return n;
}
/* Find item by index */
static avl_node *
node_find_index (avl_size_t idx, avl_tree t)
{
avl_node *a = t->root;
int c;
if (idx == 0 || idx > t->count)
return NULL;
if (idx == 1)
return node_first (a);
if (idx == t->count)
return node_last (a);
while ((c = (int)(idx - get_rank (a))) != 0)
{
if (c < 0)
a = sub_left (a);
else
{
idx = (avl_size_t)c;
a = sub_right (a);
}
}
return a;
}
/* Rebalance starting from node [a] where a->sub[d_]
* is deeper post-insertion
*/
static avl_code_t
rebalance_ins (avl_node * a, int dir, avl_tree t)
{
if (a != NULL)
{
avl_node *p;
while (1)
{
incr_rank (a, (rbal_t)(!dir));
if (get_bal (a))
break;
set_skew (a, dir);
p = a->up;
if (p == NULL)
return 2;
dir = a != sub_left (p);
a = p;
}
/* Now bal(a) == -1 or +1 */
/* Rotate if need be */
if (0 == dir)
{
if (is_rskew (a))
unset_rskew (a);
else
{
avl_node *u = a->up;
avl_node **r =
u != NULL ? &u->sub[a != sub_left (u)] : &t->root;
p = a;
if (is_lskew (sub_left (p)))
{
/* rotR(p) */
a = sub_left (p);
sub_left (p) = sub_right (a);
if (sub_right (a) != NULL)
sub_right (a)->up = p;
sub_right (a) = p;
unset_lskew (p);
rbal (p) -= rzero (a);
}
else
{
/* rotLR(p) */
a = sub_right (sub_left (p));
sub_right (sub_left (p)) = sub_left (a);
if (sub_left (a) != NULL)
sub_left (a)->up = sub_left (p);
sub_left (p)->up = a;
sub_left (a) = sub_left (p);
sub_left (p) = sub_right (a);
if (sub_right (a) != NULL)
sub_right (a)->up = p;
sub_right (a) = p;
switch (get_bal (a))
{
case 0: /* not skewed */
unset_lskew (p);
unset_rskew (sub_left (a));
break;
case 1: /* left skew */
unset_lskew (p);
set_rskew (p);
unset_rskew (sub_left (a));
break;
case 2: /* right skew */
unset_lskew (p);
unset_rskew (sub_left (a));
set_lskew (sub_left (a));
} /* switch */
rbal (a) += rzero (sub_left (a));
rbal (p) -= rzero (a);
} /* which rot */
rbal (a) &= ~3;
a->up = u;
p->up = a;
*r = a;
} /* rot or no rot ? */
}
else
{
/* direction == 1 */
if (is_lskew (a))
unset_lskew (a);
else
{
avl_node *u = a->up;
avl_node **r =
u != NULL ? &u->sub[a != sub_left (u)] : &t->root;
p = a;
if (is_rskew (sub_right (p)))
{
/* rotL(p) */
a = sub_right (p);
sub_right (p) = sub_left (a);
if (sub_left (a) != NULL)
sub_left (a)->up = p;
sub_left (a) = p;
unset_rskew (p);
rbal (a) += rzero (p);
}
else
{
/* rotRL(p) */
a = sub_left (sub_right (p));
sub_left (sub_right (p)) = sub_right (a);
if (sub_right (a) != NULL)
sub_right (a)->up = sub_right (p);
sub_right (p)->up = a;
sub_right (a) = sub_right (p);
sub_right (p) = sub_left (a);
if (sub_left (a) != NULL)
sub_left (a)->up = p;
sub_left (a) = p;
switch (get_bal (a))
{
case 0: /* not skewed */
unset_rskew (p);
unset_lskew (sub_right (a));
break;
case 1: /* left skew */
unset_rskew (p);
unset_lskew (sub_right (a));
set_rskew (sub_right (a));
break;
case 2: /* right skew */
unset_rskew (p);
set_lskew (p);
unset_lskew (sub_right (a));
} /* switch */
rbal (sub_right (a)) -= rzero (a);
rbal (a) += rzero (p);
} /* which rot */
rbal (a) &= ~3;
a->up = u;
p->up = a;
*r = a;
} /* rot or not rot ? */
} /* if 0==dir */
/* The tree rooted at 'a' is now valid */
/* Finish adjusting ranks */
while ((p = a->up) != NULL)
{
incr_rank (p, (rbal_t)(a == sub_left (p)));
a = p;
}
return 1;
} /* if a != 0 */
return 2;
}
/* detach [p] : non-null */
/* only the linkage is tweaked */
static avl_code_t
rebalance_del (avl_node * p, avl_tree t, void **backup)
{
avl_node **r, *a, *c;
rbal_t bal;
int dir = 0;
a = p->up;
if (a == NULL)
r = &t->root;
else
r = &a->sub[dir = p != sub_left (a)];
c = sub_right (p);
if (c == NULL && sub_left (p) == NULL)
*r = NULL;
else if (c == NULL || sub_left (p) == NULL)
{
*r = c != NULL ? c : sub_left (p);
(*r)->up = a;
}
else
{
if (sub_left (c) == NULL)
{
a = c;
dir = 1;
}
else
{
do
c = sub_left (c);
while (sub_left (c) != NULL);
a = c->up;
dir = 0;
sub_left (a) = sub_right (c);
if (sub_right (c) != NULL)
sub_right (c)->up = a;
sub_right (c) = sub_right (p);
sub_right (c)->up = c;
}
sub_left (c) = sub_left (p);
sub_left (c)->up = c;
c->up = p->up;
rbal (c) = rbal (p);
*r = c;
}
backup_item (backup, p->item, t);
detach_node (p, t, NULL);
/* Start backtracking : subtree of [a] in direction [dir] is less deep */
for (;; a = (*r)->up)
{
if (a == NULL)
return 2;
decr_rank (a, (rbal_t)(!dir));
bal = get_bal (a);
if (0 == dir)
{
if (bal == 0)
{
set_rskew (a);
break;
}
if (a->up == NULL)
r = &t->root;
else
{
dir = a != sub_left (a->up);
r = &a->up->sub[dir];
}
if (bal & 1)
unset_lskew (a);
if (get_bal (a))
{
p = a;
bal = get_bal (sub_right (p));
if (!(bal & 1))
{
/* bal = 0 or +1 */
/* rotL(p) */
a = sub_right (p);
sub_right (p) = sub_left (a);
if (sub_left (a) != NULL)
sub_left (a)->up = p;
sub_left (a) = p;
if (bal)
{
unset_rskew (p);
unset_rskew (a);
}
else
set_lskew (a);
rbal (a) += rzero (p);
}
else
{
/* rotRL(p) */
a = sub_left (sub_right (p));
sub_left (sub_right (p)) = sub_right (a);
if (sub_right (a) != NULL)
sub_right (a)->up = sub_right (p);
sub_right (p)->up = a;
sub_right (a) = sub_right (p);
sub_right (p) = sub_left (a);
if (sub_left (a) != NULL)
sub_left (a)->up = p;
sub_left (a) = p;
switch (get_bal (a))
{
case 0: /* not skewed */
unset_rskew (p);
unset_lskew (sub_right (a));
break;
case 1: /* left skew */
unset_rskew (p);
unset_lskew (sub_right (a));
set_rskew (sub_right (a));
break;
case 2: /* right skew */
unset_rskew (p);
set_lskew (p);
unset_lskew (sub_right (a));
} /* switch */
rbal (a) &= ~3;
rbal (sub_right (a)) -= rzero (a);
rbal (a) += rzero (p);
} /* which rot */
a->up = p->up;
p->up = a;
/* Done with rotation */
*r = a;
if (bal == 0)
break;
} /* if getbal(a) */
}
else
{
/* dir == 1 */
if (bal == 0)
{
set_lskew (a);
break;
}
if (a->up == NULL)
r = &t->root;
else
{
dir = a != sub_left (a->up);
r = &a->up->sub[dir];
}
if (bal & 2)
unset_rskew (a);
if (get_bal (a))
{
p = a;
bal = get_bal (sub_left (p));
if (!(bal & 2))
{
/* bal = 0 or -1 */
/* rotR(p) */
a = sub_left (p);
sub_left (p) = sub_right (a);
if (sub_right (a) != NULL)
sub_right (a)->up = p;
sub_right (a) = p;
if (bal)
{
unset_lskew (p);
unset_lskew (a);
}
else
set_rskew (a);
rbal (p) -= rzero (a);
}
else
{
/* rotLR(p) */
a = sub_right (sub_left (p));
sub_right (sub_left (p)) = sub_left (a);
if (sub_left (a) != NULL)
sub_left (a)->up = sub_left (p);
sub_left (p)->up = a;
sub_left (a) = sub_left (p);
sub_left (p) = sub_right (a);
if (sub_right (a) != NULL)
sub_right (a)->up = p;
sub_right (a) = p;
switch (get_bal (a))
{
case 0: /* not skewed */
unset_lskew (p);
unset_rskew (sub_left (a));
break;
case 1: /* left skew */
unset_lskew (p);
set_rskew (p);
unset_rskew (sub_left (a));
break;
case 2: /* right skew */
unset_lskew (p);
unset_rskew (sub_left (a));
set_lskew (sub_left (a));
} /* switch */
rbal (a) &= ~3;
rbal (a) += rzero (sub_left (a));
rbal (p) -= rzero (a);
} /* which rot */
a->up = p->up;
p->up = a;
/* Done with rotation */
*r = a;
if (bal == 0)
break;
} /* if getbal(a) */
} /* if dir==0 else 1 */
} /* for */
/* Finish adjusting ranks */
while ((p = a->up) != NULL)
{
decr_rank (p, (rbal_t)(a == sub_left (p)));
a = p;
}
return 1;
}
void *
avl_first (avl_tree t)
{
#ifndef AVL_NULLCHECKS
if (t == NULL || t->root == NULL)
#else
if (t->root == NULL)
#endif
return NULL;
return get_item (node_first (t->root));
}
void *
avl_last (avl_tree t)
{
#ifndef AVL_NULLCHECKS
if (t == NULL || t->root == NULL)
#else
if (t->root == NULL)
#endif
return NULL;
return get_item (node_last (t->root));
}
void *
avl_find (const void *item, avl_tree t)
{
avl_node *a;
#ifndef AVL_NULLCHECKS
if (t == NULL)
return NULL;
#endif
a = node_find (item, t);
return a != NULL ? get_item (a) : NULL;
}
/*
* Return smallest index i in [1:len] s.t. tree[i] matches [item],
* or zero if not found
*/
avl_size_t
avl_index (const void *item, avl_tree t)
{
#ifndef AVL_NULLCHECKS
if (item == NULL || t == NULL || t->root == NULL)
#else
if (t->root == NULL)
#endif
return 0;
{
avl_compare_func cmp = t->compare;
avl_node *a, *p;
avl_size_t idx = 0, n = 0;
int c;
for (a = t->root;;)
{
c = Item_Compare (cmp, t, item, get_item (a));
CMPERR_CHECK__INDEX (t->param);
if (!c)
idx = n + get_rank (a);
else if (c > 0)
n += get_rank (a);
p = a->sub[c > 0];
if (p == NULL)
return idx;
a = p;
}
}
}
/* (lo,hi) where
* lo smallest index s.t. t[lo] >= lo_item, or t->count+1 and
* hi greatest index s.t. t[hi] <= hi_item, or 0
*/
avl_code_t
avl_span (const void *lo_item,
const void *hi_item,
avl_tree t, avl_size_t * lo_idx, avl_size_t * hi_idx)
{
*lo_idx = t->count + 1;
*hi_idx = 0;
#ifndef AVL_NULLCHECKS
if (t == NULL || t->root == NULL)
#else
if (t->root == NULL)
#endif
return -1;
{
avl_compare_func cmp = t->compare;
avl_node *a;
avl_size_t n = 0;
int c;
c = Item_Compare (cmp, t, lo_item, hi_item) > 0;
CMPERR_CHECK__SPAN (t->param);
if (c > 0)
{
const void *temp = lo_item;
lo_item = hi_item;
hi_item = temp;
}
a = t->root;
do
{
c = Item_Compare (cmp, t, lo_item, get_item (a));
CMPERR_CHECK__SPAN (t->param);
if (c > 0)
{
n += get_rank (a);
a = sub_right (a);
}
else
{
*lo_idx = n + get_rank (a);
a = sub_left (a);
}
}
while (a);
a = t->root;
do
{
c = Item_Compare (cmp, t, hi_item, get_item (a));
CMPERR_CHECK__SPAN (t->param);
if (c < 0)
{
a = sub_left (a);
}
else
{
*hi_idx += get_rank (a);
a = sub_right (a);
}
}
while (a);
return 0;
}
}
/*
* Find the smallest item in tree [t] that is GEQ the passed item
*/
void *
avl_find_atleast (const void *item, avl_tree t)
{
#ifndef AVL_NULLCHECKS
if (t == NULL || t->root == NULL)
#else
if (t->root == NULL)
#endif
return NULL;
{
avl_compare_func cmp = t->compare;
avl_node *a = t->root;
void *p = NULL;
int c;
do
{
c = Item_Compare (cmp, t, item, get_item (a));
CMPERR_CHECK__FIND (t->param);
if (c > 0)
{
a = sub_right (a);
}
else
{
p = get_item (a);
a = sub_left (a);
}
}
while (a);
return p;
}
}
/*
* Find the greatest item in tree [t] that is LEQ the passed item
*/
void *
avl_find_atmost (const void *item, avl_tree t)
{
#ifndef AVL_NULLCHECKS
if (t == NULL || t->root == NULL)
#else
if (t->root == NULL)
#endif
return NULL;
{
avl_compare_func cmp = t->compare;
avl_node *a = t->root;
void *p = NULL;
int c;
do
{
c = Item_Compare (cmp, t, item, get_item (a));
CMPERR_CHECK__FIND (t->param);
if (c < 0)
{
a = sub_left (a);
}
else
{
p = get_item (a);
a = sub_right (a);
}
}
while (a);
return p;
}
}
/* Retrieve item of index [idx] in tree [t] */
void *
avl_find_index (avl_size_t idx, avl_tree t)
{
avl_node *a;
#ifndef AVL_NULLCHECKS
if (t == NULL)
return NULL;
#endif
a = node_find_index (idx, t);
return a != NULL ? get_item (a) : NULL;
}
#define attach_node(ptr,up,t)\
ptr = new_node(item, up, t);\
if (ptr == NULL){\
AVL_SHOW_ERROR("%s\n", "couldn't allocate node");\
return -1;\
}\
t->count++
/* Iterative insertion */
avl_code_t
avl_ins (void *item, avl_tree t, avl_bool_t allow_duplicates)
{
#ifndef AVL_NULLCHECKS
if (t == NULL)
return NULL;
{
#endif
avl_compare_func cmp = t->compare;
avl_node **r, *a;
int dir = 0;
for (r = &t->root, a = NULL; *r != NULL; r = &a->sub[dir = dir > 0])
{
a = *r;
dir = Item_Compare (cmp, t, item, get_item (a));
CMPERR_CHECK__INS (t->param);
if (!dir && !allow_duplicates)
return 0;
}
attach_node (*r, a, t);
return rebalance_ins (a, dir, t);
#ifndef AVL_NULLCHECKS
} /* end if non-empty tree */
#endif
}
avl_code_t
avl_del (void *item, avl_tree t, void **backup)
{
#ifndef AVL_NULLCHECKS
if (t == NULL || t->root == NULL)
#else
if (t->root == NULL)
#endif
return 0;
{
avl_node *a = node_find (item, t);
if (a == NULL)
return CMPERR_CHECK__DEL (t->param);
return rebalance_del (a, t, backup);
}
}
/* helper function */
static avl_code_t
node_del_first (avl_tree t, struct ptr_handler *h)
{
avl_node *p, *a, *c;
rbal_t bal;
p = node_first (t->root);
a = p->up;
if (sub_right (p) != NULL)
sub_right (p)->up = a;
if (a == NULL)
t->root = sub_right (p);
else
sub_left (a) = sub_right (p);
detach_node (p, t, h);
/* Start backtracking : subtree of [a] in direction [0] is less deep */
for (;; a = c)
{
if (a == NULL)
return 2;
decr_rank (a, 1);
bal = get_bal (a);
if (bal == 0)
{
set_rskew (a);
break;
}
if (bal & 1)
unset_lskew (a);
c = a->up;
if (get_bal (a))
{
p = a;
bal = get_bal (sub_right (p));
if (!(bal & 1))
{
/* bal = 0 or +1 */
/* rotL(p) */
a = sub_right (p);
sub_right (p) = sub_left (a);
if (sub_left (a) != NULL)
sub_left (a)->up = p;
sub_left (a) = p;
if (bal)
{
unset_rskew (p);
unset_rskew (a);
}
else
set_lskew (a);
rbal (a) += rzero (p);
}
else
{
/* rotRL(p) */
a = sub_left (sub_right (p));
sub_left (sub_right (p)) = sub_right (a);
if (sub_right (a) != NULL)
sub_right (a)->up = sub_right (p);
sub_right (p)->up = a;
sub_right (a) = sub_right (p);
sub_right (p) = sub_left (a);
if (sub_left (a) != NULL)
sub_left (a)->up = p;
sub_left (a) = p;
switch (get_bal (a))
{
case 0: /* not skewed */
unset_rskew (p);
unset_lskew (sub_right (a));
break;
case 1: /* left skew */
unset_rskew (p);
unset_lskew (sub_right (a));
set_rskew (sub_right (a));
break;
case 2: /* right skew */
unset_rskew (p);
set_lskew (p);
unset_lskew (sub_right (a));
} /* switch */
rbal (a) &= ~3;
rbal (sub_right (a)) -= rzero (a);
rbal (a) += rzero (p);
} /* which rot */
a->up = p->up;
p->up = a;
/* Done with rotation */
if (c != NULL)
sub_left (c) = a;
else
t->root = a;
if (bal == 0)
break;
} /* if getbal(a) */
} /* for */
/* Finish adjusting ranks */
while ((a = a->up) != NULL)
{
decr_rank (a, 1);
}
return 1;
}
/* helper function */
static avl_code_t
node_del_last (avl_tree t, struct ptr_handler *h)
{
avl_node *p, *a, *c;
rbal_t bal;
p = node_last (t->root);
a = p->up;
if (sub_left (p) != NULL)
sub_left (p)->up = a;
if (a == NULL)
t->root = sub_left (p);
else
sub_right (a) = sub_left (p);
detach_node (p, t, h);
/* Start backtracking : subtree of [a] in direction [1] is less deep */
for (;; a = c)
{
if (a == NULL)
return 2;
bal = get_bal (a);
if (bal == 0)
{
set_lskew (a);
break;
}
if (bal & 2)
unset_rskew (a);
c = a->up;
if (get_bal (a))
{
p = a;
bal = get_bal (sub_left (p));
if (!(bal & 2))
{
/* bal = 0 or -1 */
/* rotR(p) */
a = sub_left (p);
sub_left (p) = sub_right (a);
if (sub_right (a) != NULL)
sub_right (a)->up = p;
sub_right (a) = p;
if (bal)
{
unset_lskew (p);
unset_lskew (a);
}
else
set_rskew (a);
rbal (p) -= rzero (a);
}
else
{
/* rotLR(p) */
a = sub_right (sub_left (p));
sub_right (sub_left (p)) = sub_left (a);
if (sub_left (a) != NULL)
sub_left (a)->up = sub_left (p);
sub_left (p)->up = a;
sub_left (a) = sub_left (p);
sub_left (p) = sub_right (a);
if (sub_right (a) != NULL)
sub_right (a)->up = p;
sub_right (a) = p;
switch (get_bal (a))
{
case 0: /* not skewed */
unset_lskew (p);
unset_rskew (sub_left (a));
break;
case 1: /* left skew */
unset_lskew (p);
set_rskew (p);
unset_rskew (sub_left (a));
break;
case 2: /* right skew */
unset_lskew (p);
unset_rskew (sub_left (a));
set_lskew (sub_left (a));
} /* switch */
rbal (a) &= ~3;
rbal (a) += rzero (sub_left (a));
rbal (p) -= rzero (a);
} /* which rot */
a->up = p->up;
p->up = a;
/* Done with rotation */
if (c != NULL)
sub_right (c) = a;
else
t->root = a;
if (bal == 0)
break;
} /* if getbal(a) */
} /* for */
return 1;
}
/* [p] : juncture node (zeroed out) */
/* [n] : rank of [p] in resulting tree */
/* [delta] = depth_1 - depth_0 */
static avl_code_t
join_left (avl_node * p, avl_node ** r0, avl_node * r1, int delta, int n)
{
avl_node *a = NULL, **r = r0;
if (r1 == NULL)
{
while (*r != NULL)
{
a = *r;
n -= (int)get_rank (a);
r = &sub_right (a);
}
}
else
{
while (delta < -1)
{
a = *r;
delta += (int)(is_lskew (a) + 1);
n -= (int)get_rank (a);
r = &sub_right (a);
}
r1->up = p;
if (*r != NULL)
(*r)->up = p;
if (delta)
set_lskew (p);
}
/* at this point bal(*r) = -1 or 0 */
sub_left (p) = *r;
sub_right (p) = r1;
p->up = a;
set_rank (p, n);
*r = p;
for (;;)
{
if (a == NULL)
return 2;
if (get_bal (a))
break;
set_rskew (a);
a = a->up;
}
/* Rotate if need be */
/* No (+2,0) rotation to do */
if (is_lskew (a))
unset_lskew (a);
else
{
avl_node *p = a;
if (is_rskew (sub_right (p)))
{
/* rotL(p) */
a = sub_right (p);
sub_right (p) = sub_left (a);
if (sub_left (a) != NULL)
sub_left (a)->up = p;
sub_left (a) = p;
unset_rskew (p);
rbal (a) += rzero (p);
}
else
{
/* rotRL(p) */
a = sub_left (sub_right (p));
sub_left (sub_right (p)) = sub_right (a);
if (sub_right (a) != NULL)
sub_right (a)->up = sub_right (p);
sub_right (p)->up = a;
sub_right (a) = sub_right (p);
sub_right (p) = sub_left (a);
if (sub_left (a) != NULL)
sub_left (a)->up = p;
sub_left (a) = p;
switch (get_bal (a))
{
case 0: /* not skewed */
unset_rskew (p);
unset_lskew (sub_right (a));
break;
case 1: /* left skew */
unset_rskew (p);
unset_lskew (sub_right (a));
set_rskew (sub_right (a));
break;
case 2: /* right skew */
unset_rskew (p);
set_lskew (p);
unset_lskew (sub_right (a));
} /* switch */
rbal (sub_right (a)) -= rzero (a);
rbal (a) += rzero (p);
} /* which rot */
rbal (a) &= ~3;
a->up = p->up;
p->up = a;
if (a->up != NULL)
sub_right (a->up) = a;
else
*r0 = a;
} /* rot or not rot */
return 1;
}
/* [p] : juncture node */
/* [n] : rank of [p] in resulting tree */
static avl_code_t
join_right (avl_node * p, avl_node * r0, avl_node ** r1, int delta, int n)
{
avl_node *a = NULL, **r = r1;
if (r0 == NULL)
{
while (*r != NULL)
{
a = *r;
incr_rank (a, (rbal_t)n);
r = &sub_left (a);
}
n = 1;
}
else
{
while (delta > +1)
{
a = *r;
delta -= (int)(is_rskew (a) + 1);
incr_rank (a, (rbal_t)n);
r = &sub_left (a);
}
r0->up = p;
if (*r != NULL)
(*r)->up = p;
if (delta)
set_rskew (p);
}
/* at this point bal(*r) = +1 or 0 */
sub_left (p) = r0;
sub_right (p) = *r;
set_rank (p, n);
p->up = a;
*r = p;
for (;;)
{
if (a == NULL)
return 2;
if (get_bal (a))
break;
set_lskew (a);
a = a->up;
}
/* Rotate if need be */
/* No (-2,0) rotation to do */
if (is_rskew (a))
unset_rskew (a);
else
{
avl_node *p = a;
if (is_lskew (sub_left (p)))
{
/* rotR(p) */
a = sub_left (p);
sub_left (p) = sub_right (a);
if (sub_right (a) != NULL)
sub_right (a)->up = p;
sub_right (a) = p;
unset_lskew (p);
rbal (p) -= rzero (a);
}
else
{
/* rotLR(p) */
a = sub_right (sub_left (p));
sub_right (sub_left (p)) = sub_left (a);
if (sub_left (a) != NULL)
sub_left (a)->up = sub_left (p);
sub_left (p)->up = a;
sub_left (a) = sub_left (p);
sub_left (p) = sub_right (a);
if (sub_right (a) != NULL)
sub_right (a)->up = p;
sub_right (a) = p;
switch (get_bal (a))
{
case 0: /* not skewed */
unset_lskew (p);
unset_rskew (sub_left (a));
break;
case 1: /* left skew */
unset_lskew (p);
set_rskew (p);
unset_rskew (sub_left (a));
break;
case 2: /* right skew */
unset_lskew (p);
unset_rskew (sub_left (a));
set_lskew (sub_left (a));
} /* end switch */
rbal (a) += rzero (sub_left (a));
rbal (p) -= rzero (a);
} /* end which rot */
rbal (a) &= ~3;
a->up = p->up;
p->up = a;
if (a->up != NULL)
sub_left (a->up) = a;
else
*r1 = a;
} /* end rot or not rot */
return 1;
}
avl_code_t
avl_del_first (avl_tree t, void **backup)
{
#ifndef AVL_NULLCHECKS
if (t == NULL || t->root == NULL)
#else
if (t->root == NULL)
#endif
return 0;
{
avl_code_t rv;
if (backup == NULL)
{
rv = node_del_first (t, NULL);
}
else
{
ini_ptr_handler (h, BACKUP);
rv = node_del_first (t, &h);
*backup = h.ptr;
}
return rv;
}
}
avl_code_t
avl_del_last (avl_tree t, void **backup)
{
#ifndef AVL_NULLCHECKS
if (t == NULL || t->root == NULL)
#else
if (t->root == NULL)
#endif
return 0;
{
avl_code_t rv;
if (backup == NULL)
{
rv = node_del_last (t, NULL);
}
else
{
ini_ptr_handler (h, BACKUP);
rv = node_del_last (t, &h);
*backup = h.ptr;
}
return rv;
}
}
avl_code_t
avl_ins_index (void *item, avl_size_t idx, avl_tree t)
{
avl_node *p;
if (idx == 0 || t == NULL || idx > t->count + 1)
return 0;
attach_node (p, NULL, t);
/* Note: 'attach_node' macro increments t->count */
if (idx == 1)
{
return join_right (p, (avl_node *) NULL, &t->root, /*delta= */ 0, 1);
}
else if (idx == t->count)
{
return
join_left (p, &t->root, (avl_node *) NULL, /*delta= */ 0, (int)t->count);
}
else
{
avl_node *a = node_find_index (idx - 1, t);
int dir;
if (sub_right (a) != NULL)
{
a = node_first (sub_right (a));
sub_left (a) = p;
dir = 0;
}
else
{
sub_right (a) = p;
dir = 1;
}
p->up = a;
return rebalance_ins (a, dir, t);
}
}
avl_code_t
avl_del_index (avl_size_t idx, avl_tree t, void **backup)
{
#ifndef AVL_NULLCHECKS
if (t == NULL)
return 0;
#endif
if (idx == 0 || idx > t->count)
return 0;
if (idx == 1)
return avl_del_first (t, backup);
if (idx == t->count)
return avl_del_last (t, backup);
{
avl_node *a = node_find_index (idx, t);
return rebalance_del (a, t, backup);
}
}
/*
* Outcome: [t0] handles the concatenation of [t0] and [t1]
*/
void
avl_cat (avl_tree t0, avl_tree t1)
{
#ifndef AVL_NULLCHECKS
if (t0 == NULL || t1 == NULL || t1->root == NULL)
#else
if (t1->root == NULL)
#endif
return;
if (t0->root == NULL)
{
t0->root = t1->root;
t0->count = t1->count;
t1->root = NULL;
t1->count = 0;
}
else
{
int delta = depth (t1->root) - depth (t0->root);
ini_ptr_handler (h, DETACH);
if (delta <= 0)
{
if (node_del_first (t1, &h) == 2)
--delta;
(void) join_left ((avl_node *) h.ptr, &t0->root, t1->root, delta,
(int)(t0->count + 1));
}
else
{
if (node_del_last (t0, &h) == 2)
++delta;
(void) join_right ((avl_node *) h.ptr, t0->root, &t1->root, delta,
(int)(t0->count + 1));
t0->root = t1->root;
}
t1->root = NULL;
t0->count += t1->count + 1;
t1->count = 0;
}
}
/*
* - [t0] and [t1] are existing handles
* - See Donald Knuth, TAOCP Vol.3 "Sorting and searching"
*/
avl_code_t
avl_split (const void *item, avl_tree t, avl_tree t0, avl_tree t1)
{
#ifndef AVL_NULLCHECKS
if (t == NULL || t->root == NULL)
#else
if (t->root == NULL)
#endif /* AVL_NULLCHECKS */
return 0;
t0->root = NULL;
t1->root = NULL;
t0->count = 0;
t1->count = 0;
{
avl_compare_func cmp = t->compare;
avl_node *a, *p, *sn; /* sn: split node */
int d_, k, na, an[AVL_STACK_CAPACITY];
/* invariant: [na]= size of tree rooted at [a] plus one */
for (a = t->root, na = (int)(t->count + 1), k = 0;;)
{
d_ = Item_Compare (cmp, t, item, get_item (a));
CMPERR_CHECK__SPLIT (t->param);
if (!d_)
break;
p = a->sub[d_ = d_ > 0];
if (p == NULL)
return 0;
an[k++] = na;
if (d_)
na -= (int)get_rank (a);
else
na = (int)get_rank (a);
a = p;
}
/* record split node */
sn = a;
if (k == 0)
{
t0->root = sub_left (a);
t1->root = sub_right (a);
if (t0->root != NULL)
t0->root->up = NULL;
if (t1->root != NULL)
t1->root->up = NULL;
t0->count = get_rank (a) - 1;
t1->count = t->count - get_rank (a);
}
else
{
avl_node *r[2], *rr;
int h[2], ha, hh;
avl_size_t n[2], nn;
r[0] = sub_left (a);
r[1] = sub_right (a);
if (r[0] != NULL)
r[0]->up = NULL;
if (r[1] != NULL)
r[1]->up = NULL;
ha = depth (a);
h[0] = ha - (is_rskew (a) ? 2 : 1);
h[1] = ha - (is_lskew (a) ? 2 : 1);
n[0] = get_rank (a); /* size of r[0] plus one */
n[1] = (avl_size_t)na - n[0]; /* size of r[1] plus one */
for (p = a->up, d_ = a != sub_left (p);;)
{
a = p; /* a: juncture node */
p = a->up;
if (d_ == 0)
{
hh = h[1];
ha += (is_rskew (a) ? 2 : 1);
h[1] = ha - (is_lskew (a) ? 2 : 1);
nn = n[1];
n[1] += (avl_size_t)(an[k - 1] - (int)get_rank (a));
if (p != NULL)
d_ = a != sub_left (p);
rbal (a) = 0;
if (h[1] >= hh)
{
rr = r[1];
r[1] = sub_right (a);
if (r[1] != NULL)
r[1]->up = NULL;
h[1] += (2 == join_right (a, rr, r + 1, h[1] - hh, (int)nn));
}
else
{
h[1] =
hh + (2 ==
join_left (a, r + 1, sub_right (a), h[1] - hh,
(int)nn));
}
}
else
{
hh = h[0];
ha += (is_lskew (a) ? 2 : 1);
h[0] = ha - (is_rskew (a) ? 2 : 1);
nn = get_rank (a);
n[0] += nn;
if (p != NULL)
d_ = a != sub_left (p);
rbal (a) = 0;
if (h[0] >= hh)
{
rr = r[0];
r[0] = sub_left (a);
if (r[0] != NULL)
r[0]->up = NULL;
h[0] += (2 == join_left (a, r, rr, hh - h[0], (int)nn));
}
else
{
h[0] =
hh + (2 ==
join_right (a, sub_left (a), r, hh - h[0], (int)nn));
}
}
if (--k == 0)
break;
} /* for p */
t0->root = r[0];
t1->root = r[1];
t0->count = n[0] - 1;
t1->count = n[1] - 1;
} /* if k==0 */
/* Detach split node */
detach_node (sn, t, NULL);
t->root = NULL;
t->count = 0;
return 1;
}
}
/* Inorder traversal */
void
avl_walk (avl_tree t, avl_item_func proc, void *param)
{
#ifndef AVL_NULLCHECKS
if (t == NULL || t->root == NULL)
#else
if (t->root == NULL)
#endif
return;
{
avl_node *a = t->root, *p;
while (1)
{
while (sub_left (a) != NULL)
a = sub_left (a);
while (1)
{
(*proc) (get_item (a), param);
if (sub_right (a) != NULL)
break;
do
{
p = a;
a = p->up;
if (a == NULL)
return;
}
while (p != sub_left (a));
}
a = sub_right (a);
}
}
}
/* recursive helper for 'avl_slice' */
static int
node_slice (avl_node ** root, avl_node ** cur, avl_tree tree, avl_size_t len)
{
avl_size_t mid = len / 2;
if (mid == 0)
{
if ((*root = new_node ((*cur)->item, /*parent */ NULL, tree)) == NULL)
return -1;
sub_left (*root) = NULL;
sub_right (*root) = NULL;
rbal (*root) = 4;
*cur = node_next (*cur);
return 0;
}
else if ((*root = new_node (NULL, /*parent */ NULL, tree)) == NULL)
{
return -1;
}
else
{
avl_node *p = *root;
int h0, h1 = -1;
rbal (p) = (mid + 1) << 2;
if ((h0 = node_slice (&sub_left (p), cur, tree, mid)) < 0)
return -1;
p->item = (*tree->copy) ((*cur)->item);
sub_left (p)->up = p;
*cur = node_next (*cur);
if (len -= mid + 1)
{
if ((h1 = node_slice (&sub_right (p), cur, tree, len)) < 0)
return -1;
sub_right (p)->up = p;
}
if (h0 > h1)
set_lskew (p);
else if (h0 < h1)
{
set_rskew (p);
return 1 + h1;
}
return 1 + h0;
}
}
/* Return a slice t[lo,hi) as a new tree */
avl_tree
avl_slice (avl_tree t, avl_size_t lo_idx, avl_size_t hi_idx, void *param)
{
#ifndef AVL_NULLCHECKS
if (t == NULL)
return NULL;
#endif /* AVL_NULLCHECKS */
if (lo_idx > hi_idx || lo_idx > t->count)
return NULL;
if (lo_idx < 1)
lo_idx = 1;
if (hi_idx > t->count + 1)
hi_idx = t->count + 1;
{
avl_tree tt = avl_create (t->compare,
t->copy,
t->dispose,
t->alloc,
t->dealloc,
param);
if (tt == NULL)
{
AVL_SHOW_ERROR ("%s\n",
"couldn't allocate new handle in avl_slice()");
return NULL;
}
if (lo_idx < hi_idx)
{
avl_node *cur = node_find_index (lo_idx, t);
if (node_slice (&tt->root, &cur, t, tt->count = hi_idx - lo_idx) < 0)
{
AVL_SHOW_ERROR ("%s\n", "couldn't allocate node in avl_slice()");
node_empty (tt);
(*t->dealloc) (tt);
return NULL;
}
tt->root->up = NULL;
}
return tt;
}
}
/* recursive helper for 'avl_xload' */
static int
node_load (avl_node ** root, avl_itersource cur, void **pres, avl_tree desc,
avl_size_t len)
{
avl_size_t mid = len / 2;
if (mid == 0)
{
if (0 != (*cur->f) (cur, pres)
|| (*root = new_node (*pres, /*parent */ NULL, desc)) == NULL)
return -1;
sub_left (*root) = NULL;
sub_right (*root) = NULL;
rbal (*root) = 4;
return 0;
}
else if ((*root = new_node (NULL, /*parent */ NULL, desc)) == NULL)
{
return -1;
}
else
{
avl_node *p = *root;
int h0, h1 = -1;
rbal (p) = (mid + 1) << 2;
if ((h0 = node_load (&sub_left (p), cur, pres, desc, mid)) < 0)
return -1;
if (0 != (*cur->f) (cur, pres))
return -1;
p->item = (*desc->copy) (*pres);
sub_left (p)->up = p;
if (len -= mid + 1)
{
if ((h1 = node_load (&sub_right (p), cur, pres, desc, len)) < 0)
return -1;
sub_right (p)->up = p;
}
if (h0 > h1)
set_lskew (p);
else if (h0 < h1)
{
set_rskew (p);
return 1 + h1;
}
return 1 + h0;
}
}
/* Load 'len' items from itersource */
avl_tree
avl_xload (avl_itersource src, void **pres, avl_size_t len, avl_config conf,
void *tree_param)
{
#ifndef AVL_NULLCHECKS
if (src == NULL)
return NULL;
{
#endif /* AVL_NULLCHECKS */
avl_tree tt = avl_create (conf->compare,
conf->copy,
conf->dispose,
conf->alloc,
conf->dealloc,
tree_param);
if (tt == NULL)
{
AVL_SHOW_ERROR ("%s\n", "couldn't allocate new handle in avl_load()");
return NULL;
}
if (len)
{
if (node_load (&tt->root, src, pres, tt, tt->count = len) < 0)
{
AVL_SHOW_ERROR ("%s\n", "couldn't allocate node in avl_load()");
node_empty (tt);
(*tt->dealloc) (tt);
return NULL;
}
tt->root->up = NULL;
}
return tt;
#ifndef AVL_NULLCHECKS
}
#endif
}
#ifdef HAVE_AVL_VERIFY
/* Verification routine */
typedef enum
{
okay = 0,
bad_parent = 1,
bad_rank = 2,
out_of_balance = 3,
out_of_order = 4,
diff_mismatch = 5,
count_mismatch = 6
}
avl_verify_code;
static avl_bool_t
avl_error (avl_verify_code err)
{
static char *errmess[] = {
"Bad parent link",
"Rank error",
"Out of balance",
"Out of order",
"Differential mismatch",
"Count mismatch"
};
AVL_SHOW_ERROR ("Invalid avl_tree: %s\n", errmess[err - 1]);
return avl_false;
}
static int bals[] = { 1, 0, 2 };
/*
helper for recursive 'avl_verify' function
return 0 iff okay
*/
static avl_verify_code
node_verify (avl_node * root, avl_tree tree, int *h, avl_size_t * c,
avl_node * up)
{
avl_verify_code err = okay;
if (root == NULL)
*h = AVL_MIN_DEPTH, *c = 0;
else
{
#define AVL_ASSERT(expr,n) if (expr) ; else { err = n; break; }
#define CHECK(err) if (err) break
avl_node *left, *right;
avl_size_t c_[2];
int h_[2], delta;
left = sub_left (root);
right = sub_right (root);
do
{
AVL_ASSERT (root->up == up, bad_parent);
CHECK (err = node_verify (left, tree, h_, c_, root));
AVL_ASSERT (get_rank (root) == *c_ + 1, bad_rank);
CHECK (err = node_verify (right, tree, h_ + 1, c_ + 1, root));
delta = h_[1] - h_[0];
AVL_ASSERT (delta >= -1 && delta <= +1, out_of_balance);
AVL_ASSERT (get_bal (root) == bals[delta + 1], diff_mismatch);
AVL_ASSERT (left == NULL
|| (Item_Compare (tree->compare, tree, get_item (left),
get_item (root)) <=
0 CMPERR_CHECK__VERIFY (tree->param)),
out_of_order);
AVL_ASSERT (right == NULL
||
(Item_Compare
(tree->compare, tree, get_item (root),
get_item (right)) <=
0 CMPERR_CHECK__VERIFY (tree->param)), out_of_order);
*h = 1 + (h_[0] > h_[1] ? h_[0] : h_[1]);
*c = 1 + c_[0] + c_[1];
}
while (0);
}
return err;
}
avl_bool_t
avl_verify (avl_tree t)
{
#ifndef AVL_NULLCHECKS
if (t == NULL)
return avl_false;
#endif /* AVL_NULLCHECKS */
{
int h;
avl_size_t c;
avl_verify_code err;
err = node_verify (t->root, t, &h, &c, (avl_node *) NULL);
if (err)
return avl_error (err);
if (c != t->count)
return avl_error (count_mismatch);
return avl_true;
}
}
#endif /* HAVE_AVL_VERIFY */
/****************
* *
* ITERATORS *
* *
****************/
typedef enum
{
AVL_ITERATOR_PRE,
AVL_ITERATOR_POST,
AVL_ITERATOR_INTREE
}
avl_status_t;
struct avl_iterator_
{
avl_node *pos;
avl_tree tree;
avl_status_t status;
};
#define get_root(i) i->tree->root
#define is_pre(i) i->status == AVL_ITERATOR_PRE
#define is_post(i) i->status == AVL_ITERATOR_POST
#define set_pre_iterator(i) i->status = AVL_ITERATOR_PRE
#define set_post_iterator(i) i->status = AVL_ITERATOR_POST
#define set_in_iterator(i) i->status = AVL_ITERATOR_INTREE
/* Position existing iterator [iter] at node matching [item] in its own tree,
* if it exists ; otherwise do nothing
*/
void
avl_iterator_seek (const void *item, avl_iterator iter)
{
avl_node *p = node_find (item, iter->tree);
if (p != NULL)
{
set_in_iterator (iter);
iter->pos = p;
}
}
void
avl_iterator_seek_index (avl_size_t idx, avl_iterator iter)
{
avl_node *p = node_find_index (idx, iter->tree);
if (p != NULL)
{
set_in_iterator (iter);
iter->pos = p;
}
}
/* Return item pointer at current position */
void *
avl_iterator_cur (avl_iterator iter)
{
return iter->pos != NULL ? get_item (iter->pos) : NULL;
}
avl_size_t
avl_iterator_count (avl_iterator iter)
{
return iter->tree->count;
}
avl_size_t
avl_iterator_index (avl_iterator iter)
{
if (iter->pos != NULL)
return get_index (iter->pos);
else if (is_pre (iter))
return 0;
else
return iter->tree->count + 1;
}
/* Rustic: */
avl_iterator
avl_iterator_new (avl_tree t, avl_ini_t ini, ...)
{
va_list args;
avl_iterator iter = NULL;
va_start (args, ini);
if (t == NULL)
goto finish;
if ((iter = (*t->alloc) (sizeof (struct avl_iterator_))) == NULL)
{
AVL_SHOW_ERROR ("%s\n", "couldn't create iterator");
goto finish;
}
iter->pos = NULL;
iter->tree = t;
if (ini != AVL_ITERATOR_INI_INTREE)
{
iter->status =
(ini == AVL_ITERATOR_INI_PRE) ? AVL_ITERATOR_PRE : AVL_ITERATOR_POST;
}
else
{
const void *item = NULL;
item = va_arg (args, const void *);
set_pre_iterator (iter);
if (item == NULL)
AVL_SHOW_ERROR ("%s\n", "missing argument to avl_iterator_new()");
else
avl_iterator_seek (item, iter);
}
finish:
va_end (args);
return iter;
}
/*
* The following used to write to memory after it was freed.
* Corrected by: David Turner <
[email protected]>
*/
void
avl_iterator_kill (avl_iterator iter)
{
if (iter != NULL)
{
avl_dealloc_func dealloc = iter->tree->dealloc;
iter->pos = NULL;
iter->tree = NULL;
(*dealloc) (iter);
}
}
void *
avl_iterator_next (avl_iterator iter)
{
avl_node *a = iter->pos;
if (is_post (iter))
return NULL;
if (is_pre (iter))
{
a = get_root (iter);
if (a != NULL)
{
a = node_first (a);
set_in_iterator (iter);
}
}
else
{
a = node_next (a);
if (a == NULL)
set_post_iterator (iter);
}
iter->pos = a;
return a != NULL ? get_item (a) : NULL;
}
void *
avl_iterator_prev (avl_iterator iter)
{
avl_node *a = iter->pos;
if (is_pre (iter))
return NULL;
if (is_post (iter))
{
a = get_root (iter);
if (a != NULL)
{
a = node_last (a);
set_in_iterator (iter);
}
}
else
{
a = node_prev (a);
if (a == NULL)
set_pre_iterator (iter);
}
iter->pos = a;
return a != NULL ? get_item (a) : NULL;
}
/* Remove node at current position */
/* Move cursor to next position */
avl_code_t
avl_iterator_del (avl_iterator iter, void **backup)
{
if (iter == NULL || iter->pos == NULL)
return 0;
{
avl_node *a = iter->pos, *p;
p = node_next (a);
if (p == NULL)
set_post_iterator (iter);
iter->pos = p;
return rebalance_del (a, iter->tree, backup);
}
}