summaryrefslogtreecommitdiff
path: root/lib/libmalloc/sptree.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libmalloc/sptree.c')
-rw-r--r--lib/libmalloc/sptree.c763
1 files changed, 763 insertions, 0 deletions
diff --git a/lib/libmalloc/sptree.c b/lib/libmalloc/sptree.c
new file mode 100644
index 000000000000..e7d28f00ab26
--- /dev/null
+++ b/lib/libmalloc/sptree.c
@@ -0,0 +1,763 @@
+/*
+ * This file contains a few splay tree routines snarfed from David
+ * Brower's package, with globals renamed to keep them internal to the
+ * malloc, and not clash with similar routines that the application may
+ * use. The comments have been left with the original names - most of
+ * the renaming just involved prepending an __ before the name -
+ * spinstall got remapped to __spadd. Function prototypes added for
+ * external declarations. - Mark Moraes.
+ */
+/*
+ * spdaveb.c -- daveb's new splay tree functions.
+ *
+ * The functions in this file provide an interface that is nearly
+ * the same as the hash library I swiped from mkmf, allowing
+ * replacement of one by the other. Hey, it worked for me!
+ *
+ * splookup() -- given a key, find a node in a tree.
+ * spinstall() -- install an item in the tree, overwriting existing value.
+ * spfhead() -- fast (non-splay) find the first node in a tree.
+ * spscan() -- forward scan tree from the head.
+ * spfnext() -- non-splaying next.
+ * spstats() -- make char string of stats for a tree.
+ *
+ * Written by David Brower, daveb@rtech.uucp 1/88.
+ */
+/*LINTLIBRARY*/
+
+#if defined(__STDC__) && defined(ANSI_TYPES)
+#include <stddef.h>
+#endif
+#include <stdio.h>
+
+#include "defs.h"
+
+# define COMPARE(a,b) (((char *) (a)) - ((char *) (b)))
+
+# include "sptree.h"
+
+/* insert item into the tree */
+static SPBLK * spenq proto((SPBLK *, SPTREE *));
+/* return and remove lowest item in subtree */
+static SPBLK * spdeq proto((SPBLK **));
+/* reorganize tree */
+static void splay proto((SPBLK *, SPTREE *));
+/* fast non-splaying head */
+static SPBLK * spfhead proto((SPTREE *));
+/* fast non-splaying next */
+static SPBLK * spfnext proto((SPBLK *));
+
+/* USER SUPPLIED! */
+
+extern univptr_t emalloc proto((size_t));
+
+
+/*----------------
+ *
+ * splookup() -- given key, find a node in a tree.
+ *
+ * Splays the found node to the root.
+ */
+SPBLK *
+__splookup( key, q )
+REGISTER univptr_t key;
+REGISTER SPTREE *q;
+
+{
+ REGISTER SPBLK * n;
+ REGISTER int Sct;
+ REGISTER int c;
+
+ /* find node in the tree */
+ n = q->root;
+ c = ++(q->lkpcmps);
+ q->lookups++;
+ while( n && (Sct = COMPARE( key, n->key ) ) )
+ {
+ c++;
+ n = ( Sct < 0 ) ? n->leftlink : n->rightlink;
+ }
+ q->lkpcmps = c;
+
+ /* reorganize tree around this node */
+ if( n != NULL )
+ splay( n, q );
+
+ return( n );
+}
+
+
+
+/*----------------
+ *
+ * spinstall() -- install an entry in a tree, overwriting any existing node.
+ *
+ * If the node already exists, replace its contents.
+ * If it does not exist, then allocate a new node and fill it in.
+ */
+
+SPBLK *
+__spadd( key, data, datb, q )
+
+REGISTER univptr_t key;
+REGISTER univptr_t data;
+REGISTER univptr_t datb;
+REGISTER SPTREE *q;
+
+{
+ REGISTER SPBLK *n;
+
+ if( NULL == ( n = __splookup( key, q ) ) )
+ {
+ n = (SPBLK *) emalloc( sizeof( *n ) );
+ n->key = (univptr_t) key;
+ n->leftlink = NULL;
+ n->rightlink = NULL;
+ n->uplink = NULL;
+ (void) spenq( n, q );
+ }
+
+ n->data = data;
+ n->datb = datb;
+
+ return( n );
+}
+
+
+
+
+/*----------------
+ *
+ * spfhead() -- return the "lowest" element in the tree.
+ *
+ * returns a reference to the head event in the event-set q.
+ * avoids splaying but just searches for and returns a pointer to
+ * the bottom of the left branch.
+ */
+static SPBLK *
+spfhead( q )
+
+REGISTER SPTREE * q;
+
+{
+ REGISTER SPBLK * x;
+
+ if( NULL != ( x = q->root ) )
+ while( x->leftlink != NULL )
+ x = x->leftlink;
+
+ return( x );
+
+} /* spfhead */
+
+
+
+/*----------------
+ *
+ * spscan() -- apply a function to nodes in ascending order.
+ *
+ * if n is given, start at that node, otherwise start from
+ * the head.
+ */
+void
+__spscan( f, n, q )
+REGISTER void (*f)();
+REGISTER SPBLK * n;
+REGISTER SPTREE * q;
+{
+ REGISTER SPBLK * x;
+
+ for( x = n != NULL ? n : spfhead( q ); x != NULL ; x = spfnext( x ) )
+ (*f)( x );
+}
+
+
+/*----------------
+ *
+ * spfnext() -- fast return next higer item in the tree, or NULL.
+ *
+ * return the successor of n in q, represented as a splay tree.
+ * This is a fast (on average) version that does not splay.
+ */
+static SPBLK *
+spfnext( n )
+
+REGISTER SPBLK * n;
+
+{
+ REGISTER SPBLK * next;
+ REGISTER SPBLK * x;
+
+ /* a long version, avoids splaying for fast average,
+ * poor amortized bound
+ */
+
+ if( n == NULL )
+ return( n );
+
+ x = n->rightlink;
+ if( x != NULL )
+ {
+ while( x->leftlink != NULL )
+ x = x->leftlink;
+ next = x;
+ }
+ else /* x == NULL */
+ {
+ x = n->uplink;
+ next = NULL;
+ while( x != NULL )
+ {
+ if( x->leftlink == n )
+ {
+ next = x;
+ x = NULL;
+ }
+ else
+ {
+ n = x;
+ x = n->uplink;
+ }
+ }
+ }
+
+ return( next );
+
+} /* spfnext */
+
+
+char *
+__spstats( q )
+SPTREE *q;
+{
+ static char buf[ 128 ];
+ float llen;
+ float elen;
+ float sloops;
+
+ if( q == NULL )
+ return("");
+
+ llen = q->lookups ? (float)q->lkpcmps / q->lookups : 0;
+ elen = q->enqs ? (float)q->enqcmps/q->enqs : 0;
+ sloops = q->splays ? (float)q->splayloops/q->splays : 0;
+
+ (void) sprintf(buf, "f(%d %4.2f) i(%d %4.2f) s(%d %4.2f)",
+ q->lookups, llen, q->enqs, elen, q->splays, sloops );
+
+ return buf;
+}
+
+/*
+ spaux.c: This code implements the following operations on an event-set
+ or priority-queue implemented using splay trees:
+
+ spdelete( n, q ) n is removed from q.
+
+ In the above, n and np are pointers to single items (type
+ SPBLK *); q is an event-set (type SPTREE *),
+ The type definitions for these are taken
+ from file sptree.h. All of these operations rest on basic
+ splay tree operations from file sptree.c.
+
+ The basic splay tree algorithms were originally presented in:
+
+ Self Adjusting Binary Trees,
+ by D. D. Sleator and R. E. Tarjan,
+ Proc. ACM SIGACT Symposium on Theory
+ of Computing (Boston, Apr 1983) 235-245.
+
+ The operations in this package supplement the operations from
+ file splay.h to provide support for operations typically needed
+ on the pending event set in discrete event simulation. See, for
+ example,
+
+ Introduction to Simula 67,
+ by Gunther Lamprecht, Vieweg & Sohn, Braucschweig, Wiesbaden, 1981.
+ (Chapter 14 contains the relevant discussion.)
+
+ Simula Begin,
+ by Graham M. Birtwistle, et al, Studentlitteratur, Lund, 1979.
+ (Chapter 9 contains the relevant discussion.)
+
+ Many of the routines in this package use the splay procedure,
+ for bottom-up splaying of the queue. Consequently, item n in
+ delete and item np in all operations listed above must be in the
+ event-set prior to the call or the results will be
+ unpredictable (eg: chaos will ensue).
+
+ Note that, in all cases, these operations can be replaced with
+ the corresponding operations formulated for a conventional
+ lexicographically ordered tree. The versions here all use the
+ splay operation to ensure the amortized bounds; this usually
+ leads to a very compact formulation of the operations
+ themselves, but it may slow the average performance.
+
+ Alternative versions based on simple binary tree operations are
+ provided (commented out) for head, next, and prev, since these
+ are frequently used to traverse the entire data structure, and
+ the cost of traversal is independent of the shape of the
+ structure, so the extra time taken by splay in this context is
+ wasted.
+
+ This code was written by:
+ Douglas W. Jones with assistance from Srinivas R. Sataluri
+
+ Translated to C by David Brower, daveb@rtech.uucp
+
+ Thu Oct 6 12:11:33 PDT 1988 (daveb) Fixed spdeq, which was broken
+ handling one-node trees. I botched the pascal translation of
+ a VAR parameter. Changed interface, so callers must also be
+ corrected to pass the node by address rather than value.
+ Mon Apr 3 15:18:32 PDT 1989 (daveb)
+ Apply fix supplied by Mark Moraes <moraes@csri.toronto.edu> to
+ spdelete(), which dropped core when taking out the last element
+ in a subtree -- that is, when the right subtree was empty and
+ the leftlink was also null, it tried to take out the leftlink's
+ uplink anyway.
+ */
+/*----------------
+ *
+ * spdelete() -- Delete node from a tree.
+ *
+ * n is deleted from q; the resulting splay tree has been splayed
+ * around its new root, which is the successor of n
+ *
+ */
+void
+__spdelete( n, q )
+
+REGISTER SPBLK * n;
+REGISTER SPTREE * q;
+
+{
+ REGISTER SPBLK * x;
+
+ splay( n, q );
+ x = spdeq( &q->root->rightlink );
+ if( x == NULL ) /* empty right subtree */
+ {
+ q->root = q->root->leftlink;
+ if (q->root) q->root->uplink = NULL;
+ }
+ else /* non-empty right subtree */
+ {
+ x->uplink = NULL;
+ x->leftlink = q->root->leftlink;
+ x->rightlink = q->root->rightlink;
+ if( x->leftlink != NULL )
+ x->leftlink->uplink = x;
+ if( x->rightlink != NULL )
+ x->rightlink->uplink = x;
+ q->root = x;
+ }
+
+} /* spdelete */
+
+
+/*
+ *
+ * sptree.c: The following code implements the basic operations on
+ * an event-set or priority-queue implemented using splay trees:
+ *
+ * SPTREE *spinit( compare ) Make a new tree
+ * SPBLK *spenq( n, q ) Insert n in q after all equal keys.
+ * SPBLK *spdeq( np ) Return first key under *np, removing it.
+ * void splay( n, q ) n (already in q) becomes the root.
+ *
+ * In the above, n points to an SPBLK type, while q points to an
+ * SPTREE.
+ *
+ * The implementation used here is based on the implementation
+ * which was used in the tests of splay trees reported in:
+ *
+ * An Empirical Comparison of Priority-Queue and Event-Set Implementations,
+ * by Douglas W. Jones, Comm. ACM 29, 4 (Apr. 1986) 300-311.
+ *
+ * The changes made include the addition of the enqprior
+ * operation and the addition of up-links to allow for the splay
+ * operation. The basic splay tree algorithms were originally
+ * presented in:
+ *
+ * Self Adjusting Binary Trees,
+ * by D. D. Sleator and R. E. Tarjan,
+ * Proc. ACM SIGACT Symposium on Theory
+ * of Computing (Boston, Apr 1983) 235-245.
+ *
+ * The enq and enqprior routines use variations on the
+ * top-down splay operation, while the splay routine is bottom-up.
+ * All are coded for speed.
+ *
+ * Written by:
+ * Douglas W. Jones
+ *
+ * Translated to C by:
+ * David Brower, daveb@rtech.uucp
+ *
+ * Thu Oct 6 12:11:33 PDT 1988 (daveb) Fixed spdeq, which was broken
+ * handling one-node trees. I botched the pascal translation of
+ * a VAR parameter.
+ */
+/*----------------
+ *
+ * spinit() -- initialize an empty splay tree
+ *
+ */
+SPTREE *
+__spinit()
+{
+ REGISTER SPTREE * q;
+
+ q = (SPTREE *) emalloc( sizeof( *q ) );
+
+ q->lookups = 0;
+ q->lkpcmps = 0;
+ q->enqs = 0;
+ q->enqcmps = 0;
+ q->splays = 0;
+ q->splayloops = 0;
+ q->root = NULL;
+ return( q );
+}
+
+/*----------------
+ *
+ * spenq() -- insert item in a tree.
+ *
+ * put n in q after all other nodes with the same key; when this is
+ * done, n will be the root of the splay tree representing q, all nodes
+ * in q with keys less than or equal to that of n will be in the
+ * left subtree, all with greater keys will be in the right subtree;
+ * the tree is split into these subtrees from the top down, with rotations
+ * performed along the way to shorten the left branch of the right subtree
+ * and the right branch of the left subtree
+ */
+static SPBLK *
+spenq( n, q )
+REGISTER SPBLK * n;
+REGISTER SPTREE * q;
+{
+ REGISTER SPBLK * left; /* the rightmost node in the left tree */
+ REGISTER SPBLK * right; /* the leftmost node in the right tree */
+ REGISTER SPBLK * next; /* the root of the unsplit part */
+ REGISTER SPBLK * temp;
+
+ REGISTER univptr_t key;
+
+ q->enqs++;
+ n->uplink = NULL;
+ next = q->root;
+ q->root = n;
+ if( next == NULL ) /* trivial enq */
+ {
+ n->leftlink = NULL;
+ n->rightlink = NULL;
+ }
+ else /* difficult enq */
+ {
+ key = n->key;
+ left = n;
+ right = n;
+
+ /* n's left and right children will hold the right and left
+ splayed trees resulting from splitting on n->key;
+ note that the children will be reversed! */
+
+ q->enqcmps++;
+ if ( COMPARE( next->key, key ) > 0 )
+ goto two;
+
+ one: /* assert next->key <= key */
+
+ do /* walk to the right in the left tree */
+ {
+ temp = next->rightlink;
+ if( temp == NULL )
+ {
+ left->rightlink = next;
+ next->uplink = left;
+ right->leftlink = NULL;
+ goto done; /* job done, entire tree split */
+ }
+
+ q->enqcmps++;
+ if( COMPARE( temp->key, key ) > 0 )
+ {
+ left->rightlink = next;
+ next->uplink = left;
+ left = next;
+ next = temp;
+ goto two; /* change sides */
+ }
+
+ next->rightlink = temp->leftlink;
+ if( temp->leftlink != NULL )
+ temp->leftlink->uplink = next;
+ left->rightlink = temp;
+ temp->uplink = left;
+ temp->leftlink = next;
+ next->uplink = temp;
+ left = temp;
+ next = temp->rightlink;
+ if( next == NULL )
+ {
+ right->leftlink = NULL;
+ goto done; /* job done, entire tree split */
+ }
+
+ q->enqcmps++;
+
+ } while( COMPARE( next->key, key ) <= 0 ); /* change sides */
+
+ two: /* assert next->key > key */
+
+ do /* walk to the left in the right tree */
+ {
+ temp = next->leftlink;
+ if( temp == NULL )
+ {
+ right->leftlink = next;
+ next->uplink = right;
+ left->rightlink = NULL;
+ goto done; /* job done, entire tree split */
+ }
+
+ q->enqcmps++;
+ if( COMPARE( temp->key, key ) <= 0 )
+ {
+ right->leftlink = next;
+ next->uplink = right;
+ right = next;
+ next = temp;
+ goto one; /* change sides */
+ }
+ next->leftlink = temp->rightlink;
+ if( temp->rightlink != NULL )
+ temp->rightlink->uplink = next;
+ right->leftlink = temp;
+ temp->uplink = right;
+ temp->rightlink = next;
+ next->uplink = temp;
+ right = temp;
+ next = temp->leftlink;
+ if( next == NULL )
+ {
+ left->rightlink = NULL;
+ goto done; /* job done, entire tree split */
+ }
+
+ q->enqcmps++;
+
+ } while( COMPARE( next->key, key ) > 0 ); /* change sides */
+
+ goto one;
+
+ done: /* split is done, branches of n need reversal */
+
+ temp = n->leftlink;
+ n->leftlink = n->rightlink;
+ n->rightlink = temp;
+ }
+
+ return( n );
+
+} /* spenq */
+
+
+/*----------------
+ *
+ * spdeq() -- return and remove head node from a subtree.
+ *
+ * remove and return the head node from the node set; this deletes
+ * (and returns) the leftmost node from q, replacing it with its right
+ * subtree (if there is one); on the way to the leftmost node, rotations
+ * are performed to shorten the left branch of the tree
+ */
+static SPBLK *
+spdeq( np )
+
+SPBLK **np; /* pointer to a node pointer */
+
+{
+ REGISTER SPBLK * deq; /* one to return */
+ REGISTER SPBLK * next; /* the next thing to deal with */
+ REGISTER SPBLK * left; /* the left child of next */
+ REGISTER SPBLK * farleft; /* the left child of left */
+ REGISTER SPBLK * farfarleft; /* the left child of farleft */
+
+ if( np == NULL || *np == NULL )
+ {
+ deq = NULL;
+ }
+ else
+ {
+ next = *np;
+ left = next->leftlink;
+ if( left == NULL )
+ {
+ deq = next;
+ *np = next->rightlink;
+
+ if( *np != NULL )
+ (*np)->uplink = NULL;
+
+ }
+ else for(;;) /* left is not null */
+ {
+ /* next is not it, left is not NULL, might be it */
+ farleft = left->leftlink;
+ if( farleft == NULL )
+ {
+ deq = left;
+ next->leftlink = left->rightlink;
+ if( left->rightlink != NULL )
+ left->rightlink->uplink = next;
+ break;
+ }
+
+ /* next, left are not it, farleft is not NULL, might be it */
+ farfarleft = farleft->leftlink;
+ if( farfarleft == NULL )
+ {
+ deq = farleft;
+ left->leftlink = farleft->rightlink;
+ if( farleft->rightlink != NULL )
+ farleft->rightlink->uplink = left;
+ break;
+ }
+
+ /* next, left, farleft are not it, rotate */
+ next->leftlink = farleft;
+ farleft->uplink = next;
+ left->leftlink = farleft->rightlink;
+ if( farleft->rightlink != NULL )
+ farleft->rightlink->uplink = left;
+ farleft->rightlink = left;
+ left->uplink = farleft;
+ next = farleft;
+ left = farfarleft;
+ }
+ }
+
+ return( deq );
+
+} /* spdeq */
+
+
+/*----------------
+ *
+ * splay() -- reorganize the tree.
+ *
+ * the tree is reorganized so that n is the root of the
+ * splay tree representing q; results are unpredictable if n is not
+ * in q to start with; q is split from n up to the old root, with all
+ * nodes to the left of n ending up in the left subtree, and all nodes
+ * to the right of n ending up in the right subtree; the left branch of
+ * the right subtree and the right branch of the left subtree are
+ * shortened in the process
+ *
+ * this code assumes that n is not NULL and is in q; it can sometimes
+ * detect n not in q and complain
+ */
+
+static void
+splay( n, q )
+
+REGISTER SPBLK * n;
+SPTREE * q;
+
+{
+ REGISTER SPBLK * up; /* points to the node being dealt with */
+ REGISTER SPBLK * prev; /* a descendent of up, already dealt with */
+ REGISTER SPBLK * upup; /* the parent of up */
+ REGISTER SPBLK * upupup; /* the grandparent of up */
+ REGISTER SPBLK * left; /* the top of left subtree being built */
+ REGISTER SPBLK * right; /* the top of right subtree being built */
+
+ left = n->leftlink;
+ right = n->rightlink;
+ prev = n;
+ up = prev->uplink;
+
+ q->splays++;
+
+ while( up != NULL )
+ {
+ q->splayloops++;
+
+ /* walk up the tree towards the root, splaying all to the left of
+ n into the left subtree, all to right into the right subtree */
+
+ upup = up->uplink;
+ if( up->leftlink == prev ) /* up is to the right of n */
+ {
+ if( upup != NULL && upup->leftlink == up ) /* rotate */
+ {
+ upupup = upup->uplink;
+ upup->leftlink = up->rightlink;
+ if( upup->leftlink != NULL )
+ upup->leftlink->uplink = upup;
+ up->rightlink = upup;
+ upup->uplink = up;
+ if( upupup == NULL )
+ q->root = up;
+ else if( upupup->leftlink == upup )
+ upupup->leftlink = up;
+ else
+ upupup->rightlink = up;
+ up->uplink = upupup;
+ upup = upupup;
+ }
+ up->leftlink = right;
+ if( right != NULL )
+ right->uplink = up;
+ right = up;
+
+ }
+ else /* up is to the left of n */
+ {
+ if( upup != NULL && upup->rightlink == up ) /* rotate */
+ {
+ upupup = upup->uplink;
+ upup->rightlink = up->leftlink;
+ if( upup->rightlink != NULL )
+ upup->rightlink->uplink = upup;
+ up->leftlink = upup;
+ upup->uplink = up;
+ if( upupup == NULL )
+ q->root = up;
+ else if( upupup->rightlink == upup )
+ upupup->rightlink = up;
+ else
+ upupup->leftlink = up;
+ up->uplink = upupup;
+ upup = upupup;
+ }
+ up->rightlink = left;
+ if( left != NULL )
+ left->uplink = up;
+ left = up;
+ }
+ prev = up;
+ up = upup;
+ }
+
+# ifdef SPLAYDEBUG
+ if( q->root != prev )
+ {
+/* fprintf(stderr, " *** bug in splay: n not in q *** " ); */
+ abort();
+ }
+# endif
+
+ n->leftlink = left;
+ n->rightlink = right;
+ if( left != NULL )
+ left->uplink = n;
+ if( right != NULL )
+ right->uplink = n;
+ q->root = n;
+ n->uplink = NULL;
+
+} /* splay */
+