From: W. Trevor King Date: Wed, 16 Jul 2008 19:26:56 +0000 (+0000) Subject: Added interpolating lookup table files. They are from my interp_table package X-Git-Tag: v0.5~24 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=096bee5a323ba5347e0517a02740971a4adaaff9;p=sawsim.git Added interpolating lookup table files. They are from my interp_table package (a GNU libavl spinoff), so they aren't included in sawsim.nw. git-svn-id: svn://abax.physics.drexel.edu/sawsim/trunk@5 865a22a6-13cc-4084-8aa6-876098d8aa20 --- diff --git a/interp.c b/interp.c new file mode 100644 index 0000000..c04b402 --- /dev/null +++ b/interp.c @@ -0,0 +1,95 @@ +/* A full-fledged interpolating lookup table implementation. */ + +#include /* malloc, free */ +#include /* printf */ +#include /* sin */ +#include /* assert */ +#include "tavl.h" /* tavl_* */ +#include "interp.h" + +typedef struct evaluated_func_struct { + double x; + double f_of_x; +} evaluated_func_t; + +/* Comparison function for pointers to |evaluated_func_t|s. + |param| is not used. */ +/* adjusted from compare_ints in test.c */ +int +compare_evaluated_func_ts (const void *pa, const void *pb, void *param) +{ + const evaluated_func_t *a = pa; + const evaluated_func_t *b = pb; + + if (a->x < b->x) + return -1; + else if (a->x > b->x) + return +1; + else + return 0; +} + +void *allocate_evaluated_func_t (double x, double f_of_x) +{ + evaluated_func_t *eft=NULL; + eft = (evaluated_func_t *)malloc(sizeof(evaluated_func_t)); + assert(eft != NULL); + eft->x = x; + eft->f_of_x = f_of_x; + return eft; +} + +void free_evaluated_func_t (void *tavl_item, void *tavl_param) +{ + free(tavl_item); +} + + +interp_table_t *interp_table_allocate (interp_fn_t *fn, interp_tol_fn_t *tol) +{ + interp_table_t *itable=NULL; + itable = (interp_table_t *)malloc(sizeof(interp_table_t)); + assert(itable != NULL); + itable->table = (void *)tavl_create(&compare_evaluated_func_ts, NULL, NULL); + itable->fn = fn; + itable->tol = tol; + return itable; +} + +void interp_table_free (interp_table_t *itable) +{ + tavl_destroy((struct tavl_table *)itable->table, &free_evaluated_func_t); + free(itable); +} + +double interp_table_eval (interp_table_t *itable, void *params, double x) +{ + struct tavl_table *table = (struct tavl_table *)itable->table; + const evaluated_func_t *a, *b, *c; + double y, weight; + + /* attempt to look up the x variable */ + a = tavl_bracket(table, &x, (const void **)&b, (const void **)&c); + if (a != NULL) /* direct hit */ + y = a->f_of_x; + else { + if (c == NULL || b == NULL) { /* out of interpolation range, run an actual eval */ + y = (*itable->fn)(x, params); + tavl_insert(table, allocate_evaluated_func_t (x,y) ); + } else { + //printf("bracketed x=%g with %g, %g\n", x, b->x, c->x); + /* should we interpolate? */ + if ( (*itable->tol)(b->x, b->f_of_x, c->x, c->f_of_x) == 0 ) { + /* interpolate */ + weight = (x - b->x) / (c->x - b->x); + y = b->f_of_x + (c->f_of_x - b->f_of_x)*weight; + //printf("interpolated f(%g) ~= %g\n", x, y); + //fprintf(stderr, "%g\t%g\n", x, y); + } else { /* tolerance exceeded, run an actual eval */ + y = (*itable->fn)(x, params); + tavl_insert(table, allocate_evaluated_func_t (x,y) ); + } + } + } + return y; +} diff --git a/interp.h b/interp.h new file mode 100644 index 0000000..67090bf --- /dev/null +++ b/interp.h @@ -0,0 +1,16 @@ +/* A full-fledged linear interpolating lookup table interface. */ + +/* the type of functions we'll interpolate for */ +typedef double interp_fn_t (double x, void *params); +/* 0: acceptable tolerance, or 1: unacceptable? */ +typedef int interp_tol_fn_t(double xA, double yA, double xB, double yB); + +typedef struct interp_table { + void *table; + interp_fn_t *fn; + interp_tol_fn_t *tol; +} interp_table_t; + +extern interp_table_t *interp_table_allocate (interp_fn_t *fn, interp_tol_fn_t *tol); +extern void interp_table_free (interp_table_t *itable); +extern double interp_table_eval (interp_table_t *itable, void *params, double x); diff --git a/tavl.c b/tavl.c new file mode 100644 index 0000000..65af70b --- /dev/null +++ b/tavl.c @@ -0,0 +1,1036 @@ +/* Produced by texiweb from libavl.w. */ + +/* libavl - library for manipulation of binary trees. + Copyright (C) 1998-2002, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + + The author may be contacted at on the Internet, or + write to Ben Pfaff, Stanford University, Computer Science Dept., 353 + Serra Mall, Stanford CA 94305, USA. +*/ + +#include +#include +#include +#include "tavl.h" + +/* Creates and returns a new table + with comparison function |compare| using parameter |param| + and memory allocator |allocator|. + Returns |NULL| if memory allocation failed. */ +struct tavl_table * +tavl_create (tavl_comparison_func *compare, void *param, + struct libavl_allocator *allocator) +{ + struct tavl_table *tree; + + assert (compare != NULL); + + if (allocator == NULL) + allocator = &tavl_allocator_default; + + tree = allocator->libavl_malloc (allocator, sizeof *tree); + if (tree == NULL) + return NULL; + + tree->tavl_root = NULL; + tree->tavl_compare = compare; + tree->tavl_param = param; + tree->tavl_alloc = allocator; + tree->tavl_count = 0; + + return tree; +} + +/* Search |tree| for an item matching |item|, and return it if found. + Otherwise return |NULL|. */ +void * +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; + } +} + +/* Search |tree| for an item matching |item|, and return it if found. + Otherwise return |NULL| and set predecessor and successor to point to + the relevant nodes. */ +void * +tavl_bracket (const struct tavl_table *tree, const void *item, const void **predecessor, const void **successor) +{ + const struct tavl_node *p; + + assert (tree != NULL && item != NULL); + + *predecessor = NULL; + *successor = 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 /* no match, bracket */ + { + if (dir) /* match would have been above p */ + { + *predecessor = p->tavl_data; + p = p->tavl_link[dir]; /* follow thread up */ + if (p != NULL) + *successor = p->tavl_data; + } + else /* match would have been below p */ + { + *successor = p->tavl_data; + p = p->tavl_link[dir]; /* follow thread down */ + if (p != NULL) + *predecessor = p->tavl_data; + } + return NULL; + } + } +} + +/* Inserts |item| into |tree| and returns a pointer to |item|'s address. + If a duplicate item is found in the tree, + returns a pointer to the duplicate without inserting |item|. + Returns |NULL| in case of memory allocation failure. */ +void ** +tavl_probe (struct tavl_table *tree, void *item) +{ + struct tavl_node *y, *z; /* Top node to update balance factor, and parent. */ + struct tavl_node *p, *q; /* Iterator, and parent. */ + struct tavl_node *n; /* Newly inserted node. */ + struct tavl_node *w; /* New root of rebalanced subtree. */ + int dir; /* Direction to descend. */ + + unsigned char da[TAVL_MAX_HEIGHT]; /* Cached comparison results. */ + int k = 0; /* Number of cached results. */ + + assert (tree != NULL && item != NULL); + + 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) + return &p->tavl_data; + + if (p->tavl_balance != 0) + z = q, y = p, k = 0; + da[k++] = dir = cmp > 0; + + if (p->tavl_tag[dir] == TAVL_THREAD) + break; + } + } + else + { + p = z; + dir = 0; + } + + n = tree->tavl_alloc->libavl_malloc (tree->tavl_alloc, sizeof *n); + if (n == NULL) + return NULL; + + 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 /* |w->tavl_balance == +1| */ + 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 /* |w->tavl_balance == -1| */ + 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; +} + +/* Inserts |item| into |table|. + Returns |NULL| if |item| was successfully inserted + or if a memory allocation error occurred. + Otherwise, returns the duplicate item. */ +void * +tavl_insert (struct tavl_table *table, void *item) +{ + void **p = tavl_probe (table, item); + return p == NULL || *p == item ? NULL : *p; +} + +/* Inserts |item| into |table|, replacing any duplicate item. + Returns |NULL| if |item| was inserted without replacing a duplicate, + or if a memory allocation error occurred. + Otherwise, returns the item that was replaced. */ +void * +tavl_replace (struct tavl_table *table, void *item) +{ + void **p = tavl_probe (table, item); + if (p == NULL || *p == item) + return NULL; + else + { + void *r = *p; + *p = item; + return r; + } +} + +/* Returns the parent of |node| within |tree|, + or a pointer to |tavl_root| if |s| is the root of the tree. */ +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; +} + +/* Deletes from |tree| and returns an item matching |item|. + Returns a null pointer if no matching item found. */ +void * +tavl_delete (struct tavl_table *tree, const void *item) +{ + struct tavl_node *p; /* Traverses tree to find node to delete. */ + struct tavl_node *q; /* Parent of |p|. */ + int dir; /* Index into |q->tavl_link[]| to get |p|. */ + int cmp; /* Result of comparison between |item| and |p|. */ + + 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; + } + } + + tree->tavl_alloc->libavl_free (tree->tavl_alloc, 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 /* |w->tavl_balance == -1| */ + 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 /* |x->tavl_balance == +1| */ + { + 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 /* |w->tavl_balance == +1| */ + 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 /* |x->tavl_balance == -1| */ + { + 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; +} + +/* Initializes |trav| for use with |tree| + and selects the null node. */ +void +tavl_t_init (struct tavl_traverser *trav, struct tavl_table *tree) +{ + trav->tavl_table = tree; + trav->tavl_node = NULL; +} + +/* Initializes |trav| for |tree|. + Returns data item in |tree| with the least value, + or |NULL| if |tree| is empty. */ +void * +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; +} + +/* Initializes |trav| for |tree|. + Returns data item in |tree| with the greatest value, + or |NULL| if |tree| is empty. */ +void * +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; +} + +/* Searches for |item| in |tree|. + If found, initializes |trav| to the item found and returns the item + as well. + If there is no matching item, initializes |trav| to the null item + and returns |NULL|. */ +void * +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; + } +} + +/* Attempts to insert |item| into |tree|. + If |item| is inserted successfully, it is returned and |trav| is + initialized to its location. + If a duplicate is found, it is returned and |trav| is initialized to + its location. No replacement of the item occurs. + If a memory allocation failure occurs, |NULL| is returned and |trav| + is initialized to the null item. */ +void * +tavl_t_insert (struct tavl_traverser *trav, + struct tavl_table *tree, void *item) +{ + void **p; + + assert (trav != NULL && tree != NULL && item != NULL); + + p = 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 + { + tavl_t_init (trav, tree); + return NULL; + } +} + +/* Initializes |trav| to have the same current node as |src|. */ +void * +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; +} + +/* Returns the next data item in inorder + within the tree being traversed with |trav|, + or if there are no more data items returns |NULL|. */ +void * +tavl_t_next (struct tavl_traverser *trav) +{ + assert (trav != NULL); + + if (trav->tavl_node == NULL) + return 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; + } +} + +/* Returns the previous data item in inorder + within the tree being traversed with |trav|, + or if there are no more data items returns |NULL|. */ +void * +tavl_t_prev (struct tavl_traverser *trav) +{ + assert (trav != NULL); + + if (trav->tavl_node == NULL) + return 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; + } +} + +/* Returns |trav|'s current item. */ +void * +tavl_t_cur (struct tavl_traverser *trav) +{ + assert (trav != NULL); + + return trav->tavl_node != NULL ? trav->tavl_node->tavl_data : NULL; +} + +/* Replaces the current item in |trav| by |new| and returns the item replaced. + |trav| must not have the null item selected. + The new item must not upset the ordering of the tree. */ +void * +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; +} + +/* Creates a new node as a child of |dst| on side |dir|. + Copies data and |tavl_balance| from |src| into the new node, + applying |copy()|, if non-null. + Returns nonzero only if fully successful. + Regardless of success, integrity of the tree structure is assured, + though failure may leave a null pointer in a |tavl_data| member. */ +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 = + tree->tavl_alloc->libavl_malloc (tree->tavl_alloc, sizeof *new); + if (new == NULL) + return 0; + + 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; +} + +/* Destroys |new| with |tavl_destroy (new, destroy)|, + first initializing the right link in |new| that has + not yet been initialized. */ +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; + } + tavl_destroy (new, destroy); +} + +/* Copies |org| to a newly created tree, which is returned. + If |copy != NULL|, each data item in |org| is first passed to |copy|, + and the return values are inserted into the tree, + with |NULL| return values taken as indications of failure. + On failure, destroys the partially created new tree, + applying |destroy|, if non-null, to each item in the new tree so far, + and returns |NULL|. + If |allocator != NULL|, it is used for allocation in the new tree. + Otherwise, the same allocator used for |org| is used. */ +struct tavl_table * +tavl_copy (const struct tavl_table *org, tavl_copy_func *copy, + tavl_item_func *destroy, struct libavl_allocator *allocator) +{ + struct tavl_table *new; + + const struct tavl_node *p; + struct tavl_node *q; + struct tavl_node rp, rq; + + assert (org != NULL); + new = tavl_create (org->tavl_compare, org->tavl_param, + allocator != NULL ? allocator : org->tavl_alloc); + 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; + } + } +} + +/* Frees storage allocated for |tree|. + If |destroy != NULL|, applies it to each data item in inorder. */ +void +tavl_destroy (struct tavl_table *tree, tavl_item_func *destroy) +{ + struct tavl_node *p; /* Current node. */ + struct tavl_node *n; /* Next node. */ + + 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); + tree->tavl_alloc->libavl_free (tree->tavl_alloc, p); + + p = n; + } + + tree->tavl_alloc->libavl_free (tree->tavl_alloc, tree); +} + +/* Allocates |size| bytes of space using |malloc()|. + Returns a null pointer if allocation fails. */ +void * +tavl_malloc (struct libavl_allocator *allocator, size_t size) +{ + assert (allocator != NULL && size > 0); + return malloc (size); +} + +/* Frees |block|. */ +void +tavl_free (struct libavl_allocator *allocator, void *block) +{ + assert (allocator != NULL && block != NULL); + free (block); +} + +/* Default memory allocator that uses |malloc()| and |free()|. */ +struct libavl_allocator tavl_allocator_default = + { + tavl_malloc, + tavl_free + }; + +#undef NDEBUG +#include + +/* Asserts that |tavl_insert()| succeeds at inserting |item| into |table|. */ +void +(tavl_assert_insert) (struct tavl_table *table, void *item) +{ + void **p = tavl_probe (table, item); + assert (p != NULL && *p == item); +} + +/* Asserts that |tavl_delete()| really removes |item| from |table|, + and returns the removed item. */ +void * +(tavl_assert_delete) (struct tavl_table *table, void *item) +{ + void *p = tavl_delete (table, item); + assert (p != NULL); + return p; +} + diff --git a/tavl.h b/tavl.h new file mode 100644 index 0000000..35f9c97 --- /dev/null +++ b/tavl.h @@ -0,0 +1,121 @@ +/* Produced by texiweb from libavl.w. */ + +/* libavl - library for manipulation of binary trees. + Copyright (C) 1998-2002, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + + The author may be contacted at on the Internet, or + write to Ben Pfaff, Stanford University, Computer Science Dept., 353 + Serra Mall, Stanford CA 94305, USA. +*/ + +#ifndef TAVL_H +#define TAVL_H 1 + +#include + +/* Function types. */ +typedef int tavl_comparison_func (const void *tavl_a, const void *tavl_b, + void *tavl_param); +typedef void tavl_item_func (void *tavl_item, void *tavl_param); +typedef void *tavl_copy_func (void *tavl_item, void *tavl_param); + +#ifndef LIBAVL_ALLOCATOR +#define LIBAVL_ALLOCATOR +/* Memory allocator. */ +struct libavl_allocator + { + void *(*libavl_malloc) (struct libavl_allocator *, size_t libavl_size); + void (*libavl_free) (struct libavl_allocator *, void *libavl_block); + }; +#endif + +/* Default memory allocator. */ +extern struct libavl_allocator tavl_allocator_default; +void *tavl_malloc (struct libavl_allocator *, size_t); +void tavl_free (struct libavl_allocator *, void *); + +/* Maximum TAVL height. */ +#ifndef TAVL_MAX_HEIGHT +#define TAVL_MAX_HEIGHT 32 +#endif + +/* Tree data structure. */ +struct tavl_table + { + struct tavl_node *tavl_root; /* Tree's root. */ + tavl_comparison_func *tavl_compare; /* Comparison function. */ + void *tavl_param; /* Extra argument to |tavl_compare|. */ + struct libavl_allocator *tavl_alloc; /* Memory allocator. */ + size_t tavl_count; /* Number of items in tree. */ + }; + +/* Characterizes a link as a child pointer or a thread. */ +enum tavl_tag + { + TAVL_CHILD, /* Child pointer. */ + TAVL_THREAD /* Thread. */ + }; + +/* An TAVL tree node. */ +struct tavl_node + { + struct tavl_node *tavl_link[2]; /* Subtrees. */ + void *tavl_data; /* Pointer to data. */ + unsigned char tavl_tag[2]; /* Tag fields. */ + signed char tavl_balance; /* Balance factor. */ + }; + +/* TAVL traverser structure. */ +struct tavl_traverser + { + struct tavl_table *tavl_table; /* Tree being traversed. */ + struct tavl_node *tavl_node; /* Current node in tree. */ + }; + +/* Table functions. */ +struct tavl_table *tavl_create (tavl_comparison_func *, void *, + struct libavl_allocator *); +struct tavl_table *tavl_copy (const struct tavl_table *, tavl_copy_func *, + tavl_item_func *, struct libavl_allocator *); +void tavl_destroy (struct tavl_table *, tavl_item_func *); +void **tavl_probe (struct tavl_table *, void *); +void *tavl_insert (struct tavl_table *, void *); +void *tavl_replace (struct tavl_table *, void *); +void *tavl_delete (struct tavl_table *, const void *); +void *tavl_find (const struct tavl_table *, const void *); +void tavl_assert_insert (struct tavl_table *, void *); +void *tavl_assert_delete (struct tavl_table *, void *); + +#define tavl_count(table) ((size_t) (table)->tavl_count) + +/* Table traverser functions. */ +void tavl_t_init (struct tavl_traverser *, struct tavl_table *); +void *tavl_t_first (struct tavl_traverser *, struct tavl_table *); +void *tavl_t_last (struct tavl_traverser *, struct tavl_table *); +void *tavl_t_find (struct tavl_traverser *, struct tavl_table *, void *); +void *tavl_t_insert (struct tavl_traverser *, struct tavl_table *, void *); +void *tavl_t_copy (struct tavl_traverser *, const struct tavl_traverser *); +void *tavl_t_next (struct tavl_traverser *); +void *tavl_t_prev (struct tavl_traverser *); +void *tavl_t_cur (struct tavl_traverser *); +void *tavl_t_replace (struct tavl_traverser *, void *); +void *tavl_bracket (const struct tavl_table *tree, const void *item, const void **predecessor, const void **successor); + + + +#endif /* tavl.h */