#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef TESTING_TAVL
#define TESTING_TAVL 0
#endif /* TESTING_TAVL */
#if TESTING_TAVL
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#define MY_AVL_MALLOC(size) \
(marpa__tavl_allocator_default->libavl_malloc(marpa__tavl_allocator_default, (size)))
#define MY_AVL_FREE(p) \
(marpa__tavl_allocator_default->libavl_free(marpa__tavl_allocator_default, (p)))
#else /* not TESTING_TAVL */
#include "config.h"
#include <assert.h>
#include <stdio.h>
#include "marpa.h"
#include "marpa_ami.h"
#define MY_AVL_MALLOC(size) (my_malloc(size))
#define MY_AVL_FREE(p) (my_free(p))
#endif /* TESTING AVL */
#include "marpa_tavl.h"
struct
tavl_table *
marpa__tavl_create (tavl_comparison_func *compare,
void
*param)
{
struct
tavl_table *tree;
assert
(compare != NULL);
tree = MY_AVL_MALLOC(
sizeof
*tree);
tree->tavl_root = NULL;
tree->tavl_compare = compare;
tree->tavl_param = param;
tree->tavl_count = 0;
return
tree;
}
void
*
marpa__tavl_find (
const
struct
tavl_table *tree,
const
void
*item)
{
const
struct
tavl_node *p;
assert
(tree != NULL && item != NULL);
p = tree->tavl_root;
if
(p == NULL)
return
NULL;
for
(;;)
{
int
cmp, dir;
cmp = tree->tavl_compare (item, p->tavl_data, tree->tavl_param);
if
(cmp == 0)
return
p->tavl_data;
dir = cmp > 0;
if
(p->tavl_tag[dir] == TAVL_CHILD)
p = p->tavl_link[dir];
else
return
NULL;
}
}
void
**
marpa__tavl_probe (
struct
tavl_table *tree,
void
*item)
{
struct
tavl_node *y, *z;
struct
tavl_node *p, *q;
struct
tavl_node *n;
struct
tavl_node *w;
int
dir;
unsigned
char
da[TAVL_MAX_HEIGHT];
int
k = 0;
assert
(tree != NULL && item != NULL);
tree->tavl_duplicate_found = 0;
z = (
struct
tavl_node *) &tree->tavl_root;
y = tree->tavl_root;
if
(y != NULL)
{
for
(q = z, p = y; ; q = p, p = p->tavl_link[dir])
{
int
cmp = tree->tavl_compare (item, p->tavl_data, tree->tavl_param);
if
(cmp == 0) {
tree->tavl_duplicate_found = 1;
return
&p->tavl_data;
}
if
(p->tavl_balance != 0)
z = q, y = p, k = 0;
dir = cmp > 0;
da[k++] = (unsigned
char
)dir;
if
(p->tavl_tag[dir] == TAVL_THREAD)
break
;
}
}
else
{
p = z;
dir = 0;
}
n = MY_AVL_MALLOC(
sizeof
*n);
tree->tavl_count++;
n->tavl_data = item;
n->tavl_tag[0] = n->tavl_tag[1] = TAVL_THREAD;
n->tavl_link[dir] = p->tavl_link[dir];
if
(tree->tavl_root != NULL)
{
p->tavl_tag[dir] = TAVL_CHILD;
n->tavl_link[!dir] = p;
}
else
n->tavl_link[1] = NULL;
p->tavl_link[dir] = n;
n->tavl_balance = 0;
if
(tree->tavl_root == n)
return
&n->tavl_data;
for
(p = y, k = 0; p != n; p = p->tavl_link[da[k]], k++)
if
(da[k] == 0)
p->tavl_balance--;
else
p->tavl_balance++;
if
(y->tavl_balance == -2)
{
struct
tavl_node *x = y->tavl_link[0];
if
(x->tavl_balance == -1)
{
w = x;
if
(x->tavl_tag[1] == TAVL_THREAD)
{
x->tavl_tag[1] = TAVL_CHILD;
y->tavl_tag[0] = TAVL_THREAD;
y->tavl_link[0] = x;
}
else
y->tavl_link[0] = x->tavl_link[1];
x->tavl_link[1] = y;
x->tavl_balance = y->tavl_balance = 0;
}
else
{
assert
(x->tavl_balance == +1);
w = x->tavl_link[1];
x->tavl_link[1] = w->tavl_link[0];
w->tavl_link[0] = x;
y->tavl_link[0] = w->tavl_link[1];
w->tavl_link[1] = y;
if
(w->tavl_balance == -1)
x->tavl_balance = 0, y->tavl_balance = +1;
else
if
(w->tavl_balance == 0)
x->tavl_balance = y->tavl_balance = 0;
else
x->tavl_balance = -1, y->tavl_balance = 0;
w->tavl_balance = 0;
if
(w->tavl_tag[0] == TAVL_THREAD)
{
x->tavl_tag[1] = TAVL_THREAD;
x->tavl_link[1] = w;
w->tavl_tag[0] = TAVL_CHILD;
}
if
(w->tavl_tag[1] == TAVL_THREAD)
{
y->tavl_tag[0] = TAVL_THREAD;
y->tavl_link[0] = w;
w->tavl_tag[1] = TAVL_CHILD;
}
}
}
else
if
(y->tavl_balance == +2)
{
struct
tavl_node *x = y->tavl_link[1];
if
(x->tavl_balance == +1)
{
w = x;
if
(x->tavl_tag[0] == TAVL_THREAD)
{
x->tavl_tag[0] = TAVL_CHILD;
y->tavl_tag[1] = TAVL_THREAD;
y->tavl_link[1] = x;
}
else
y->tavl_link[1] = x->tavl_link[0];
x->tavl_link[0] = y;
x->tavl_balance = y->tavl_balance = 0;
}
else
{
assert
(x->tavl_balance == -1);
w = x->tavl_link[0];
x->tavl_link[0] = w->tavl_link[1];
w->tavl_link[1] = x;
y->tavl_link[1] = w->tavl_link[0];
w->tavl_link[0] = y;
if
(w->tavl_balance == +1)
x->tavl_balance = 0, y->tavl_balance = -1;
else
if
(w->tavl_balance == 0)
x->tavl_balance = y->tavl_balance = 0;
else
x->tavl_balance = +1, y->tavl_balance = 0;
w->tavl_balance = 0;
if
(w->tavl_tag[0] == TAVL_THREAD)
{
y->tavl_tag[1] = TAVL_THREAD;
y->tavl_link[1] = w;
w->tavl_tag[0] = TAVL_CHILD;
}
if
(w->tavl_tag[1] == TAVL_THREAD)
{
x->tavl_tag[0] = TAVL_THREAD;
x->tavl_link[0] = w;
w->tavl_tag[1] = TAVL_CHILD;
}
}
}
else
return
&n->tavl_data;
z->tavl_link[y != z->tavl_link[0]] = w;
return
&n->tavl_data;
}
static
struct
tavl_node *
find_parent (
struct
tavl_table *tree,
struct
tavl_node *node)
{
if
(node != tree->tavl_root)
{
struct
tavl_node *x, *y;
for
(x = y = node; ; x = x->tavl_link[0], y = y->tavl_link[1])
if
(y->tavl_tag[1] == TAVL_THREAD)
{
struct
tavl_node *p = y->tavl_link[1];
if
(p == NULL || p->tavl_link[0] != node)
{
while
(x->tavl_tag[0] == TAVL_CHILD)
x = x->tavl_link[0];
p = x->tavl_link[0];
}
return
p;
}
else
if
(x->tavl_tag[0] == TAVL_THREAD)
{
struct
tavl_node *p = x->tavl_link[0];
if
(p == NULL || p->tavl_link[1] != node)
{
while
(y->tavl_tag[1] == TAVL_CHILD)
y = y->tavl_link[1];
p = y->tavl_link[1];
}
return
p;
}
}
else
return
(
struct
tavl_node *) &tree->tavl_root;
}
void
*
marpa__tavl_delete (
struct
tavl_table *tree,
const
void
*item)
{
struct
tavl_node *p;
struct
tavl_node *q;
int
dir;
int
cmp;
assert
(tree != NULL && item != NULL);
if
(tree->tavl_root == NULL)
return
NULL;
q = (
struct
tavl_node *) &tree->tavl_root;
p = tree->tavl_root;
dir = 0;
for
(;;)
{
cmp = tree->tavl_compare (item, p->tavl_data, tree->tavl_param);
if
(cmp == 0)
break
;
dir = cmp > 0;
q = p;
if
(p->tavl_tag[dir] == TAVL_THREAD)
return
NULL;
p = p->tavl_link[dir];
}
item = p->tavl_data;
if
(p->tavl_tag[1] == TAVL_THREAD)
{
if
(p->tavl_tag[0] == TAVL_CHILD)
{
struct
tavl_node *t = p->tavl_link[0];
while
(t->tavl_tag[1] == TAVL_CHILD)
t = t->tavl_link[1];
t->tavl_link[1] = p->tavl_link[1];
q->tavl_link[dir] = p->tavl_link[0];
}
else
{
q->tavl_link[dir] = p->tavl_link[dir];
if
(q != (
struct
tavl_node *) &tree->tavl_root)
q->tavl_tag[dir] = TAVL_THREAD;
}
}
else
{
struct
tavl_node *r = p->tavl_link[1];
if
(r->tavl_tag[0] == TAVL_THREAD)
{
r->tavl_link[0] = p->tavl_link[0];
r->tavl_tag[0] = p->tavl_tag[0];
if
(r->tavl_tag[0] == TAVL_CHILD)
{
struct
tavl_node *t = r->tavl_link[0];
while
(t->tavl_tag[1] == TAVL_CHILD)
t = t->tavl_link[1];
t->tavl_link[1] = r;
}
q->tavl_link[dir] = r;
r->tavl_balance = p->tavl_balance;
q = r;
dir = 1;
}
else
{
struct
tavl_node *s;
for
(;;)
{
s = r->tavl_link[0];
if
(s->tavl_tag[0] == TAVL_THREAD)
break
;
r = s;
}
if
(s->tavl_tag[1] == TAVL_CHILD)
r->tavl_link[0] = s->tavl_link[1];
else
{
r->tavl_link[0] = s;
r->tavl_tag[0] = TAVL_THREAD;
}
s->tavl_link[0] = p->tavl_link[0];
if
(p->tavl_tag[0] == TAVL_CHILD)
{
struct
tavl_node *t = p->tavl_link[0];
while
(t->tavl_tag[1] == TAVL_CHILD)
t = t->tavl_link[1];
t->tavl_link[1] = s;
s->tavl_tag[0] = TAVL_CHILD;
}
s->tavl_link[1] = p->tavl_link[1];
s->tavl_tag[1] = TAVL_CHILD;
q->tavl_link[dir] = s;
s->tavl_balance = p->tavl_balance;
q = r;
dir = 0;
}
}
MY_AVL_FREE( p);
while
(q != (
struct
tavl_node *) &tree->tavl_root)
{
struct
tavl_node *y = q;
q = find_parent (tree, y);
if
(dir == 0)
{
dir = q->tavl_link[0] != y;
y->tavl_balance++;
if
(y->tavl_balance == +1)
break
;
else
if
(y->tavl_balance == +2)
{
struct
tavl_node *x = y->tavl_link[1];
assert
(x != NULL);
if
(x->tavl_balance == -1)
{
struct
tavl_node *w;
assert
(x->tavl_balance == -1);
w = x->tavl_link[0];
x->tavl_link[0] = w->tavl_link[1];
w->tavl_link[1] = x;
y->tavl_link[1] = w->tavl_link[0];
w->tavl_link[0] = y;
if
(w->tavl_balance == +1)
x->tavl_balance = 0, y->tavl_balance = -1;
else
if
(w->tavl_balance == 0)
x->tavl_balance = y->tavl_balance = 0;
else
x->tavl_balance = +1, y->tavl_balance = 0;
w->tavl_balance = 0;
if
(w->tavl_tag[0] == TAVL_THREAD)
{
y->tavl_tag[1] = TAVL_THREAD;
y->tavl_link[1] = w;
w->tavl_tag[0] = TAVL_CHILD;
}
if
(w->tavl_tag[1] == TAVL_THREAD)
{
x->tavl_tag[0] = TAVL_THREAD;
x->tavl_link[0] = w;
w->tavl_tag[1] = TAVL_CHILD;
}
q->tavl_link[dir] = w;
}
else
{
q->tavl_link[dir] = x;
if
(x->tavl_balance == 0)
{
y->tavl_link[1] = x->tavl_link[0];
x->tavl_link[0] = y;
x->tavl_balance = -1;
y->tavl_balance = +1;
break
;
}
else
{
if
(x->tavl_tag[0] == TAVL_CHILD)
y->tavl_link[1] = x->tavl_link[0];
else
{
y->tavl_tag[1] = TAVL_THREAD;
x->tavl_tag[0] = TAVL_CHILD;
}
x->tavl_link[0] = y;
y->tavl_balance = x->tavl_balance = 0;
}
}
}
}
else
{
dir = q->tavl_link[0] != y;
y->tavl_balance--;
if
(y->tavl_balance == -1)
break
;
else
if
(y->tavl_balance == -2)
{
struct
tavl_node *x = y->tavl_link[0];
assert
(x != NULL);
if
(x->tavl_balance == +1)
{
struct
tavl_node *w;
assert
(x->tavl_balance == +1);
w = x->tavl_link[1];
x->tavl_link[1] = w->tavl_link[0];
w->tavl_link[0] = x;
y->tavl_link[0] = w->tavl_link[1];
w->tavl_link[1] = y;
if
(w->tavl_balance == -1)
x->tavl_balance = 0, y->tavl_balance = +1;
else
if
(w->tavl_balance == 0)
x->tavl_balance = y->tavl_balance = 0;
else
x->tavl_balance = -1, y->tavl_balance = 0;
w->tavl_balance = 0;
if
(w->tavl_tag[0] == TAVL_THREAD)
{
x->tavl_tag[1] = TAVL_THREAD;
x->tavl_link[1] = w;
w->tavl_tag[0] = TAVL_CHILD;
}
if
(w->tavl_tag[1] == TAVL_THREAD)
{
y->tavl_tag[0] = TAVL_THREAD;
y->tavl_link[0] = w;
w->tavl_tag[1] = TAVL_CHILD;
}
q->tavl_link[dir] = w;
}
else
{
q->tavl_link[dir] = x;
if
(x->tavl_balance == 0)
{
y->tavl_link[0] = x->tavl_link[1];
x->tavl_link[1] = y;
x->tavl_balance = +1;
y->tavl_balance = -1;
break
;
}
else
{
if
(x->tavl_tag[1] == TAVL_CHILD)
y->tavl_link[0] = x->tavl_link[1];
else
{
y->tavl_tag[0] = TAVL_THREAD;
x->tavl_tag[1] = TAVL_CHILD;
}
x->tavl_link[1] = y;
y->tavl_balance = x->tavl_balance = 0;
}
}
}
}
}
tree->tavl_count--;
return
(
void
*) item;
}
void
marpa__tavl_t_init (
struct
tavl_traverser *trav,
struct
tavl_table *tree)
{
trav->tavl_table = tree;
trav->tavl_node = NULL;
}
void
*
marpa__tavl_t_first (
struct
tavl_traverser *trav,
struct
tavl_table *tree)
{
assert
(tree != NULL && trav != NULL);
trav->tavl_table = tree;
trav->tavl_node = tree->tavl_root;
if
(trav->tavl_node != NULL)
{
while
(trav->tavl_node->tavl_tag[0] == TAVL_CHILD)
trav->tavl_node = trav->tavl_node->tavl_link[0];
return
trav->tavl_node->tavl_data;
}
else
return
NULL;
}
void
*
marpa__tavl_t_last (
struct
tavl_traverser *trav,
struct
tavl_table *tree)
{
assert
(tree != NULL && trav != NULL);
trav->tavl_table = tree;
trav->tavl_node = tree->tavl_root;
if
(trav->tavl_node != NULL)
{
while
(trav->tavl_node->tavl_tag[1] == TAVL_CHILD)
trav->tavl_node = trav->tavl_node->tavl_link[1];
return
trav->tavl_node->tavl_data;
}
else
return
NULL;
}
void
*
marpa__tavl_t_find (
struct
tavl_traverser *trav,
struct
tavl_table *tree,
void
*item)
{
struct
tavl_node *p;
assert
(trav != NULL && tree != NULL && item != NULL);
trav->tavl_table = tree;
trav->tavl_node = NULL;
p = tree->tavl_root;
if
(p == NULL)
return
NULL;
for
(;;)
{
int
cmp, dir;
cmp = tree->tavl_compare (item, p->tavl_data, tree->tavl_param);
if
(cmp == 0)
{
trav->tavl_node = p;
return
p->tavl_data;
}
dir = cmp > 0;
if
(p->tavl_tag[dir] == TAVL_CHILD)
p = p->tavl_link[dir];
else
return
NULL;
}
}
void
*
marpa__tavl_t_insert (
struct
tavl_traverser *trav,
struct
tavl_table *tree,
void
*item)
{
void
**p;
assert
(trav != NULL && tree != NULL && item != NULL);
p = marpa__tavl_probe (tree, item);
if
(p != NULL)
{
trav->tavl_table = tree;
trav->tavl_node =
((
struct
tavl_node *)
((
char
*) p - offsetof (
struct
tavl_node, tavl_data)));
return
*p;
}
else
{
marpa__tavl_t_init (trav, tree);
return
NULL;
}
}
void
*
marpa__tavl_t_copy (
struct
tavl_traverser *trav,
const
struct
tavl_traverser *src)
{
assert
(trav != NULL && src != NULL);
trav->tavl_table = src->tavl_table;
trav->tavl_node = src->tavl_node;
return
trav->tavl_node != NULL ? trav->tavl_node->tavl_data : NULL;
}
void
*
marpa__tavl_t_next (
struct
tavl_traverser *trav)
{
assert
(trav != NULL);
if
(trav->tavl_node == NULL)
return
marpa__tavl_t_first (trav, trav->tavl_table);
else
if
(trav->tavl_node->tavl_tag[1] == TAVL_THREAD)
{
trav->tavl_node = trav->tavl_node->tavl_link[1];
return
trav->tavl_node != NULL ? trav->tavl_node->tavl_data : NULL;
}
else
{
trav->tavl_node = trav->tavl_node->tavl_link[1];
while
(trav->tavl_node->tavl_tag[0] == TAVL_CHILD)
trav->tavl_node = trav->tavl_node->tavl_link[0];
return
trav->tavl_node->tavl_data;
}
}
void
*
marpa__tavl_t_prev (
struct
tavl_traverser *trav)
{
assert
(trav != NULL);
if
(trav->tavl_node == NULL)
return
marpa__tavl_t_last (trav, trav->tavl_table);
else
if
(trav->tavl_node->tavl_tag[0] == TAVL_THREAD)
{
trav->tavl_node = trav->tavl_node->tavl_link[0];
return
trav->tavl_node != NULL ? trav->tavl_node->tavl_data : NULL;
}
else
{
trav->tavl_node = trav->tavl_node->tavl_link[0];
while
(trav->tavl_node->tavl_tag[1] == TAVL_CHILD)
trav->tavl_node = trav->tavl_node->tavl_link[1];
return
trav->tavl_node->tavl_data;
}
}
void
*
marpa__tavl_t_cur (
struct
tavl_traverser *trav)
{
assert
(trav != NULL);
return
trav->tavl_node != NULL ? trav->tavl_node->tavl_data : NULL;
}
void
*
marpa__tavl_t_replace (
struct
tavl_traverser *trav,
void
*
new
)
{
void
*old;
assert
(trav != NULL && trav->tavl_node != NULL &&
new
!= NULL);
old = trav->tavl_node->tavl_data;
trav->tavl_node->tavl_data =
new
;
return
old;
}
static
int
copy_node (
struct
tavl_table *tree,
struct
tavl_node *dst,
int
dir,
const
struct
tavl_node *src, tavl_copy_func *copy)
{
struct
tavl_node *
new
=
MY_AVL_MALLOC(
sizeof
*
new
);
new
->tavl_link[dir] = dst->tavl_link[dir];
new
->tavl_tag[dir] = TAVL_THREAD;
new
->tavl_link[!dir] = dst;
new
->tavl_tag[!dir] = TAVL_THREAD;
dst->tavl_link[dir] =
new
;
dst->tavl_tag[dir] = TAVL_CHILD;
new
->tavl_balance = src->tavl_balance;
if
(copy == NULL)
new
->tavl_data = src->tavl_data;
else
{
new
->tavl_data = copy (src->tavl_data, tree->tavl_param);
if
(
new
->tavl_data == NULL)
return
0;
}
return
1;
}
static
void
copy_error_recovery (
struct
tavl_node *p,
struct
tavl_table *
new
, tavl_item_func *destroy)
{
new
->tavl_root = p;
if
(p != NULL)
{
while
(p->tavl_tag[1] == TAVL_CHILD)
p = p->tavl_link[1];
p->tavl_link[1] = NULL;
}
marpa__tavl_destroy (
new
, destroy);
}
struct
tavl_table *
marpa__tavl_copy (
const
struct
tavl_table *org, tavl_copy_func *copy,
tavl_item_func *destroy)
{
struct
tavl_table *
new
;
const
struct
tavl_node *p;
struct
tavl_node *q;
struct
tavl_node rp, rq;
assert
(org != NULL);
new
= marpa__tavl_create (org->tavl_compare, org->tavl_param);
if
(
new
== NULL)
return
NULL;
new
->tavl_count = org->tavl_count;
if
(
new
->tavl_count == 0)
return
new
;
p = &rp;
rp.tavl_link[0] = org->tavl_root;
rp.tavl_tag[0] = TAVL_CHILD;
q = &rq;
rq.tavl_link[0] = NULL;
rq.tavl_tag[0] = TAVL_THREAD;
for
(;;)
{
if
(p->tavl_tag[0] == TAVL_CHILD)
{
if
(!copy_node (
new
, q, 0, p->tavl_link[0], copy))
{
copy_error_recovery (rq.tavl_link[0],
new
, destroy);
return
NULL;
}
p = p->tavl_link[0];
q = q->tavl_link[0];
}
else
{
while
(p->tavl_tag[1] == TAVL_THREAD)
{
p = p->tavl_link[1];
if
(p == NULL)
{
q->tavl_link[1] = NULL;
new
->tavl_root = rq.tavl_link[0];
return
new
;
}
q = q->tavl_link[1];
}
p = p->tavl_link[1];
q = q->tavl_link[1];
}
if
(p->tavl_tag[1] == TAVL_CHILD)
if
(!copy_node (
new
, q, 1, p->tavl_link[1], copy))
{
copy_error_recovery (rq.tavl_link[0],
new
, destroy);
return
NULL;
}
}
}
void
marpa__tavl_destroy (
struct
tavl_table *tree, tavl_item_func *destroy)
{
struct
tavl_node *p;
struct
tavl_node *n;
p = tree->tavl_root;
if
(p != NULL)
while
(p->tavl_tag[0] == TAVL_CHILD)
p = p->tavl_link[0];
while
(p != NULL)
{
n = p->tavl_link[1];
if
(p->tavl_tag[1] == TAVL_CHILD)
while
(n->tavl_tag[0] == TAVL_CHILD)
n = n->tavl_link[0];
if
(destroy != NULL && p->tavl_data != NULL)
destroy (p->tavl_data, tree->tavl_param);
MY_AVL_FREE( p);
p = n;
}
MY_AVL_FREE( tree);
}
static
void
fatal(
const
char
* message) {
puts
(message);
abort
();
}
static
void
*
tavl_malloc (
struct
libavl_allocator *allocator UNUSED,
size_t
size UNUSED)
{
fatal(
"Internal error: legacy TAVL malloc called"
);
return
NULL;
}
static
void
tavl_free (
struct
libavl_allocator *allocator UNUSED,
void
*block UNUSED)
{
fatal(
"Internal error: legacy TAVL free called"
);
}
struct
libavl_allocator default_allocator =
{
tavl_malloc,
tavl_free
};
struct
libavl_allocator *marpa__tavl_allocator_default = &default_allocator;
#undef NDEBUG
#include <assert.h>
void
(marpa__tavl_assert_insert) (
struct
tavl_table *table,
void
*item)
{
void
**p = marpa__tavl_probe (table, item);
assert
(p != NULL && *p == item);
}
void
*
(marpa__tavl_assert_delete) (
struct
tavl_table *table,
void
*item)
{
void
*p = marpa__tavl_delete (table, item);
assert
(p != NULL);
return
p;
}