|
Packit |
cdaae3 |
/* Copyright (c) 2013-2017, David Anderson
|
|
Packit |
cdaae3 |
All rights reserved.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
Redistribution and use in source and binary forms, with
|
|
Packit |
cdaae3 |
or without modification, are permitted provided that the
|
|
Packit |
cdaae3 |
following conditions are met:
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
Redistributions of source code must retain the above
|
|
Packit |
cdaae3 |
copyright notice, this list of conditions and the following
|
|
Packit |
cdaae3 |
disclaimer.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
Redistributions in binary form must reproduce the above
|
|
Packit |
cdaae3 |
copyright notice, this list of conditions and the following
|
|
Packit |
cdaae3 |
disclaimer in the documentation and/or other materials
|
|
Packit |
cdaae3 |
provided with the distribution.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
Packit |
cdaae3 |
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
Packit |
cdaae3 |
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
Packit |
cdaae3 |
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit |
cdaae3 |
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
Packit |
cdaae3 |
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
Packit |
cdaae3 |
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
Packit |
cdaae3 |
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
Packit |
cdaae3 |
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
Packit |
cdaae3 |
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
Packit |
cdaae3 |
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
Packit |
cdaae3 |
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
Packit |
cdaae3 |
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
*/
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* The interfaces follow tsearch (See the Single
|
|
Packit |
cdaae3 |
Unix Specification) but the implementation is
|
|
Packit |
cdaae3 |
written without reference to the source of any
|
|
Packit |
cdaae3 |
version of tsearch.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
See http://www.prevanders.net/tsearch.html
|
|
Packit |
cdaae3 |
for information and an example of use.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
Based on Knuth, chapter 6.2.2
|
|
Packit |
cdaae3 |
And based on chapter 6.2.3 Balanced Trees (sometimes
|
|
Packit |
cdaae3 |
call AVL trees) Algorithm A and the sketch on deletion.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
The wikipedia page on AVL trees is also quite useful.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
A Key equation is:
|
|
Packit |
cdaae3 |
bal-factor-node-k =
|
|
Packit |
cdaae3 |
height-left-subtree - height-right-subtree
|
|
Packit |
cdaae3 |
We don't know the absolute height, but we do know the
|
|
Packit |
cdaae3 |
balance factor of the pointed-to subtrees (-1,0, or 1).
|
|
Packit |
cdaae3 |
And we always know if we are adding or deleting a node.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
*/
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
#include "config.h"
|
|
Packit |
cdaae3 |
#include "dwarf_incl.h"
|
|
Packit |
cdaae3 |
#include "stdlib.h" /* for free() */
|
|
Packit |
cdaae3 |
#include <stdio.h> /* for printf */
|
|
Packit |
cdaae3 |
#include "dwarf_tsearch.h"
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
#define IMPLEMENTD15 1
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
#ifdef DW_CHECK_CONSISTENCY
|
|
Packit |
cdaae3 |
struct ts_entry;
|
|
Packit |
cdaae3 |
void dwarf_check_balance(struct ts_entry *head,int finalprefix);
|
|
Packit |
cdaae3 |
#endif
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* head is a special link. rlink points to root node.
|
|
Packit |
cdaae3 |
head-> llink is a tree depth value. Using a pointer.
|
|
Packit |
cdaae3 |
root = head->rlink.
|
|
Packit |
cdaae3 |
The keypointer and balance fields of the head node
|
|
Packit |
cdaae3 |
are not used.
|
|
Packit |
cdaae3 |
Might be sensible to use the head
|
|
Packit |
cdaae3 |
balance field as a tree depth instead of using llink.
|
|
Packit |
cdaae3 |
*/
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
struct ts_entry {
|
|
Packit |
cdaae3 |
/* Keyptr points to a pointer to a record the user saved, the
|
|
Packit |
cdaae3 |
user record contains the user's key itself
|
|
Packit |
cdaae3 |
and perhaps more. */
|
|
Packit |
cdaae3 |
const void *keyptr;
|
|
Packit |
cdaae3 |
int balance; /* Knuth 6.2.3 algorithm A */
|
|
Packit |
cdaae3 |
struct ts_entry * llink;
|
|
Packit |
cdaae3 |
struct ts_entry * rlink;
|
|
Packit |
cdaae3 |
};
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
static void printlevel(int level)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
int len = 0;
|
|
Packit |
cdaae3 |
int targetlen = 4 + level;
|
|
Packit |
cdaae3 |
int shownlen = 0;
|
|
Packit |
cdaae3 |
char number[10];
|
|
Packit |
cdaae3 |
len = snprintf(number,sizeof(number),"<%d>",level);
|
|
Packit |
cdaae3 |
printf("%s",number);
|
|
Packit |
cdaae3 |
shownlen = len;
|
|
Packit |
cdaae3 |
while(shownlen < targetlen) {
|
|
Packit |
cdaae3 |
putchar(' ');
|
|
Packit |
cdaae3 |
++shownlen;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Not needed for this set of functions. */
|
|
Packit |
cdaae3 |
void *
|
|
Packit |
cdaae3 |
dwarf_initialize_search_hash( void **treeptr,
|
|
Packit |
cdaae3 |
UNUSEDARG unsigned long(*hashfunc)(const void *key),
|
|
Packit |
cdaae3 |
UNUSEDARG unsigned long size_estimate)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
return *treeptr;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* For debugging, mainly.
|
|
Packit |
cdaae3 |
We print the tree with the head node unnumbered
|
|
Packit |
cdaae3 |
and the root node called level 0.
|
|
Packit |
cdaae3 |
In Knuth algorithms where we have p[k] when
|
|
Packit |
cdaae3 |
k is zero k refers to the head node. Handy
|
|
Packit |
cdaae3 |
as then the root node is not special at all.
|
|
Packit |
cdaae3 |
But here it just looks better as shown, perhaps.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
The ordering here is so that if you turned an output
|
|
Packit |
cdaae3 |
page with the left side at the top
|
|
Packit |
cdaae3 |
then the tree sort of just shows up nicely in
|
|
Packit |
cdaae3 |
what most think of as a normal way.
|
|
Packit |
cdaae3 |
*/
|
|
Packit |
cdaae3 |
static void
|
|
Packit |
cdaae3 |
tdump_inner(struct ts_entry *t,
|
|
Packit |
cdaae3 |
char *(keyprint)(const void *),
|
|
Packit |
cdaae3 |
const char *descr, int level)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
char * keyv = "";
|
|
Packit |
cdaae3 |
if(!t) {
|
|
Packit |
cdaae3 |
return;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
tdump_inner(t->rlink,keyprint,"right",level+1);
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
printlevel(level);
|
|
Packit |
cdaae3 |
if(t->keyptr) {
|
|
Packit |
cdaae3 |
keyv = keyprint(t->keyptr);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
printf("0x%08lx <keyptr 0x%08lx> <%s %s> <bal %3d> <l 0x%08lx> <r 0x%08lx> %s\n",
|
|
Packit |
cdaae3 |
(unsigned long)t,
|
|
Packit |
cdaae3 |
(unsigned long)t->keyptr,
|
|
Packit |
cdaae3 |
t->keyptr?"key ":"null",
|
|
Packit |
cdaae3 |
keyv,
|
|
Packit |
cdaae3 |
t->balance,
|
|
Packit |
cdaae3 |
(unsigned long)t->llink,(unsigned long)t->rlink,
|
|
Packit |
cdaae3 |
descr);
|
|
Packit |
cdaae3 |
tdump_inner(t->llink,keyprint,"left ",level+1);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
#ifdef DW_CHECK_CONSISTENCY
|
|
Packit |
cdaae3 |
/* Checking that a tree (or sub tree) is in balance.
|
|
Packit |
cdaae3 |
Only meaningful for balanced trees.
|
|
Packit |
cdaae3 |
Returns the depth.
|
|
Packit |
cdaae3 |
*/
|
|
Packit |
cdaae3 |
int
|
|
Packit |
cdaae3 |
dwarf_check_balance_inner(struct ts_entry *t,int level,int maxdepth,int *founderror,const char *prefix)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
int l = 0;
|
|
Packit |
cdaae3 |
int r = 0;
|
|
Packit |
cdaae3 |
if(level > maxdepth) {
|
|
Packit |
cdaae3 |
printf("%s Likely internal erroneous link loop, got to depth %d.\n",
|
|
Packit |
cdaae3 |
prefix,level);
|
|
Packit |
cdaae3 |
exit(1);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if(!t) {
|
|
Packit |
cdaae3 |
return 0;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if(!t->llink && !t->rlink) {
|
|
Packit |
cdaae3 |
if (t->balance != 0) {
|
|
Packit |
cdaae3 |
printf("%s: Balance at 0x%lx should be 0 is %d.\n",
|
|
Packit |
cdaae3 |
prefix,(unsigned long)t,t->balance);
|
|
Packit |
cdaae3 |
(*founderror)++;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
return 1;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
l = dwarf_check_balance_inner(t->llink,level+1,maxdepth,founderror,prefix);
|
|
Packit |
cdaae3 |
r = dwarf_check_balance_inner(t->rlink,level+1,maxdepth,founderror,prefix);
|
|
Packit |
cdaae3 |
if (l ==r && t->balance != 0) {
|
|
Packit |
cdaae3 |
printf("%s Balance at 0x%lx d should be 0 is %d.\n",
|
|
Packit |
cdaae3 |
prefix,(unsigned long)t,t->balance);
|
|
Packit |
cdaae3 |
(*founderror)++;
|
|
Packit |
cdaae3 |
return l+1;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if(l > r) {
|
|
Packit |
cdaae3 |
if( (l-r) != 1) {
|
|
Packit |
cdaae3 |
printf("%s depth mismatch at 0x%lx l %d r %d.\n",
|
|
Packit |
cdaae3 |
prefix,(unsigned long)t,l,r);
|
|
Packit |
cdaae3 |
(*founderror)++;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if (t->balance != -1) {
|
|
Packit |
cdaae3 |
printf("%s Balance at 0x%lx should be -1 is %d.\n",
|
|
Packit |
cdaae3 |
prefix,(unsigned long)t,t->balance);
|
|
Packit |
cdaae3 |
(*founderror)++;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
return l+1;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if(r != l) {
|
|
Packit |
cdaae3 |
if( (r-l) != 1) {
|
|
Packit |
cdaae3 |
printf("%s depth mismatch at 0x%lx r %d l %d.\n",
|
|
Packit |
cdaae3 |
prefix,(unsigned long)t,r,l);
|
|
Packit |
cdaae3 |
(*founderror)++;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if (t->balance != 1) {
|
|
Packit |
cdaae3 |
printf("%s Balance at 0x%lx should be 1 is %d.\n",
|
|
Packit |
cdaae3 |
prefix,(unsigned long)t,t->balance);
|
|
Packit |
cdaae3 |
(*founderror)++;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
} else {
|
|
Packit |
cdaae3 |
if (t->balance != 0) {
|
|
Packit |
cdaae3 |
printf("%s Balance at 0x%lx should be 0 is %d.\n",
|
|
Packit |
cdaae3 |
prefix,(unsigned long)t,t->balance);
|
|
Packit |
cdaae3 |
(*founderror)++;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
return r+1;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
void
|
|
Packit |
cdaae3 |
dwarf_check_balance(struct ts_entry *head,int finalprefix)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
const char *prefix = 0;
|
|
Packit |
cdaae3 |
int maxdepth = 0;
|
|
Packit |
cdaae3 |
int headdepth = 0;
|
|
Packit |
cdaae3 |
int errcount = 0;
|
|
Packit |
cdaae3 |
int depth = 0;
|
|
Packit |
cdaae3 |
struct ts_entry*root = 0;
|
|
Packit |
cdaae3 |
if(finalprefix) {
|
|
Packit |
cdaae3 |
prefix = "BalanceError:";
|
|
Packit |
cdaae3 |
} else {
|
|
Packit |
cdaae3 |
prefix = "BalanceWarn:";
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
if(!head) {
|
|
Packit |
cdaae3 |
printf("%s check balance null tree ptr\n",prefix);
|
|
Packit |
cdaae3 |
return;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
root = head->rlink;
|
|
Packit |
cdaae3 |
headdepth = head->llink - (struct ts_entry *)0;
|
|
Packit |
cdaae3 |
if(!root) {
|
|
Packit |
cdaae3 |
printf("%s check balance null tree ptr\n",prefix);
|
|
Packit |
cdaae3 |
return;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
maxdepth = headdepth+10;
|
|
Packit |
cdaae3 |
/* Counting in levels, not level number of top level. */
|
|
Packit |
cdaae3 |
headdepth++;
|
|
Packit |
cdaae3 |
depth = dwarf_check_balance_inner(root,depth,maxdepth,&errcount,prefix);
|
|
Packit |
cdaae3 |
if (depth != headdepth) {
|
|
Packit |
cdaae3 |
printf("%s Head node says depth %d, it is really %d\n",
|
|
Packit |
cdaae3 |
prefix,
|
|
Packit |
cdaae3 |
headdepth,depth);
|
|
Packit |
cdaae3 |
++errcount;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if(errcount) {
|
|
Packit |
cdaae3 |
printf("%s error count %d\n",prefix,errcount);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
return;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
#endif
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Dumping the tree to stdout. */
|
|
Packit |
cdaae3 |
void
|
|
Packit |
cdaae3 |
dwarf_tdump(const void*headp_in,
|
|
Packit |
cdaae3 |
char *(*keyprint)(const void *),
|
|
Packit |
cdaae3 |
const char *msg)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry *head = (struct ts_entry *)headp_in;
|
|
Packit |
cdaae3 |
struct ts_entry *root = 0;
|
|
Packit |
cdaae3 |
int headdepth = 0;
|
|
Packit |
cdaae3 |
if(!head) {
|
|
Packit |
cdaae3 |
printf("dumptree null tree ptr : %s\n",msg);
|
|
Packit |
cdaae3 |
return;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
headdepth = head->llink - (struct ts_entry *)0;
|
|
Packit |
cdaae3 |
printf("dumptree head ptr : 0x%08lx tree-depth %d: %s\n",
|
|
Packit |
cdaae3 |
(unsigned long)head,
|
|
Packit |
cdaae3 |
headdepth,
|
|
Packit |
cdaae3 |
msg);
|
|
Packit |
cdaae3 |
root = head->rlink;
|
|
Packit |
cdaae3 |
if(!root) {
|
|
Packit |
cdaae3 |
printf("Empty tree\n");
|
|
Packit |
cdaae3 |
return;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
tdump_inner(root,keyprint,"top",0);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
static void
|
|
Packit |
cdaae3 |
setlink(struct ts_entry*t,int a,struct ts_entry *x)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
if(a < 0) {
|
|
Packit |
cdaae3 |
t->llink = x;
|
|
Packit |
cdaae3 |
} else {
|
|
Packit |
cdaae3 |
t->rlink = x;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
static struct ts_entry*
|
|
Packit |
cdaae3 |
getlink(struct ts_entry*t,int a)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
if(a < 0) {
|
|
Packit |
cdaae3 |
return(t->llink);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
return(t->rlink);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
static struct ts_entry *
|
|
Packit |
cdaae3 |
allocate_ts_entry(const void *key)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry *e = (struct ts_entry *)
|
|
Packit |
cdaae3 |
malloc(sizeof(struct ts_entry));
|
|
Packit |
cdaae3 |
if(!e) {
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
e->keyptr = key;
|
|
Packit |
cdaae3 |
e->balance = 0;
|
|
Packit |
cdaae3 |
e->llink = 0;
|
|
Packit |
cdaae3 |
e->rlink = 0;
|
|
Packit |
cdaae3 |
return e;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Knuth step T5, the insert. */
|
|
Packit |
cdaae3 |
static struct ts_entry *
|
|
Packit |
cdaae3 |
tsearch_insert_k(const void *key,int kc,
|
|
Packit |
cdaae3 |
struct ts_entry *p)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry *q = allocate_ts_entry(key);
|
|
Packit |
cdaae3 |
if (!q) {
|
|
Packit |
cdaae3 |
/* out of memory */
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
setlink(p,kc,q);
|
|
Packit |
cdaae3 |
/* Non-NULL means inserted. */
|
|
Packit |
cdaae3 |
return q;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Knuth step T5. */
|
|
Packit |
cdaae3 |
static struct ts_entry *
|
|
Packit |
cdaae3 |
tsearch_inner_do_insert(const void *key,
|
|
Packit |
cdaae3 |
int kc,
|
|
Packit |
cdaae3 |
int * inserted,
|
|
Packit |
cdaae3 |
struct ts_entry* p)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry *q = 0;
|
|
Packit |
cdaae3 |
q = tsearch_insert_k(key,kc,p);
|
|
Packit |
cdaae3 |
if(q) {
|
|
Packit |
cdaae3 |
*inserted = 1;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
return q;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Algorithm A of Knuth 6.2.3, balanced tree.
|
|
Packit |
cdaae3 |
key is pointer to a user data area containing the key
|
|
Packit |
cdaae3 |
and possibly more.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
We could recurse on this routine, but instead we
|
|
Packit |
cdaae3 |
iterate (like Knuth does, but using for(;;) instead
|
|
Packit |
cdaae3 |
of go-to.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
*/
|
|
Packit |
cdaae3 |
static struct ts_entry *
|
|
Packit |
cdaae3 |
tsearch_inner( const void *key, struct ts_entry* head,
|
|
Packit |
cdaae3 |
int (*compar)(const void *, const void *),
|
|
Packit |
cdaae3 |
int*inserted,
|
|
Packit |
cdaae3 |
UNUSEDARG struct ts_entry **nullme,
|
|
Packit |
cdaae3 |
UNUSEDARG int * comparres)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
/* t points to parent of p */
|
|
Packit |
cdaae3 |
struct ts_entry *t = head;
|
|
Packit |
cdaae3 |
/* p moves down tree, p starts as root. */
|
|
Packit |
cdaae3 |
struct ts_entry *p = head->rlink;
|
|
Packit |
cdaae3 |
/* s points where rebalancing may be needed. */
|
|
Packit |
cdaae3 |
struct ts_entry *s = p;
|
|
Packit |
cdaae3 |
struct ts_entry *r = 0;
|
|
Packit |
cdaae3 |
struct ts_entry *q = 0;
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
int a = 0;
|
|
Packit |
cdaae3 |
int kc = 0;
|
|
Packit |
cdaae3 |
for(;;) {
|
|
Packit |
cdaae3 |
/* A2. */
|
|
Packit |
cdaae3 |
kc = compar(key,p->keyptr);
|
|
Packit |
cdaae3 |
if(kc) {
|
|
Packit |
cdaae3 |
/* A3 and A4 handled here. */
|
|
Packit |
cdaae3 |
q = getlink(p,kc);
|
|
Packit |
cdaae3 |
if(!q) {
|
|
Packit |
cdaae3 |
/* Does step A5. */
|
|
Packit |
cdaae3 |
q = tsearch_inner_do_insert(key,kc,inserted,p);
|
|
Packit |
cdaae3 |
if (!q) {
|
|
Packit |
cdaae3 |
/* Out of memory. */
|
|
Packit |
cdaae3 |
return q;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
break; /* to A5. */
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if(q->balance) {
|
|
Packit |
cdaae3 |
t = p;
|
|
Packit |
cdaae3 |
s = q;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
p = q;
|
|
Packit |
cdaae3 |
continue;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
/* K = KEY(P) in Knuth. */
|
|
Packit |
cdaae3 |
/* kc == 0, we found the entry we search for. */
|
|
Packit |
cdaae3 |
return p;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
/* A5: work already done. */
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* A6: */
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
/* Balance factors on nodes betwen S and Q need to be
|
|
Packit |
cdaae3 |
changed from zero to +-1 */
|
|
Packit |
cdaae3 |
int kc2 = compar(key,s->keyptr);
|
|
Packit |
cdaae3 |
if (kc2 < 0) {
|
|
Packit |
cdaae3 |
a = -1;
|
|
Packit |
cdaae3 |
} else {
|
|
Packit |
cdaae3 |
a = 1;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
r = p = getlink(s,a);
|
|
Packit |
cdaae3 |
while (p != q) {
|
|
Packit |
cdaae3 |
int kc3 = compar(key,p->keyptr);
|
|
Packit |
cdaae3 |
if(kc3 < 0) {
|
|
Packit |
cdaae3 |
p->balance = -1;
|
|
Packit |
cdaae3 |
p = p->llink;
|
|
Packit |
cdaae3 |
} else if (kc3 > 0) {
|
|
Packit |
cdaae3 |
p->balance = 1;
|
|
Packit |
cdaae3 |
p = p->rlink;
|
|
Packit |
cdaae3 |
} else {
|
|
Packit |
cdaae3 |
/* ASSERT: p == q */
|
|
Packit |
cdaae3 |
break;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* A7: */
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
if(! s->balance) {
|
|
Packit |
cdaae3 |
/* Tree has grown higher. */
|
|
Packit |
cdaae3 |
s->balance = a;
|
|
Packit |
cdaae3 |
/* Counting in pointers, not integers. Ugh. */
|
|
Packit |
cdaae3 |
head->llink = head->llink + 1;
|
|
Packit |
cdaae3 |
return q;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if(s->balance == -a) {
|
|
Packit |
cdaae3 |
/* Tree is more balanced */
|
|
Packit |
cdaae3 |
s->balance = 0;
|
|
Packit |
cdaae3 |
return q;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if (s->balance == a) {
|
|
Packit |
cdaae3 |
/* Rebalance. */
|
|
Packit |
cdaae3 |
if(r->balance == a) {
|
|
Packit |
cdaae3 |
/* single rotation, step A8. */
|
|
Packit |
cdaae3 |
p = r;
|
|
Packit |
cdaae3 |
setlink(s,a,getlink(r,-a));
|
|
Packit |
cdaae3 |
setlink(r,-a,s);
|
|
Packit |
cdaae3 |
s->balance = 0;
|
|
Packit |
cdaae3 |
r->balance = 0;
|
|
Packit |
cdaae3 |
} else if (r->balance == -a) {
|
|
Packit |
cdaae3 |
/* double rotation, step A9. */
|
|
Packit |
cdaae3 |
p = getlink(r,-a);
|
|
Packit |
cdaae3 |
setlink(r,-a,getlink(p,a));
|
|
Packit |
cdaae3 |
setlink(p,a,r);
|
|
Packit |
cdaae3 |
setlink(s,a,getlink(p,-a));
|
|
Packit |
cdaae3 |
setlink(p,-a,s);
|
|
Packit |
cdaae3 |
if(p->balance == a) {
|
|
Packit |
cdaae3 |
s->balance = -a;
|
|
Packit |
cdaae3 |
r->balance = 0;
|
|
Packit |
cdaae3 |
} else if (p->balance == 0) {
|
|
Packit |
cdaae3 |
s->balance = 0;
|
|
Packit |
cdaae3 |
r->balance = 0;
|
|
Packit |
cdaae3 |
} else if (p->balance == -a) {
|
|
Packit |
cdaae3 |
s->balance = 0;
|
|
Packit |
cdaae3 |
r->balance = a;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
p->balance = 0;
|
|
Packit |
cdaae3 |
} else {
|
|
Packit |
cdaae3 |
fprintf(stderr,"Impossible balanced tree situation!\n");
|
|
Packit |
cdaae3 |
/* Impossible. Cannot be here. */
|
|
Packit |
cdaae3 |
exit(1);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
} else {
|
|
Packit |
cdaae3 |
fprintf(stderr,"Impossible balanced tree situation!!\n");
|
|
Packit |
cdaae3 |
/* Impossible. Cannot be here. */
|
|
Packit |
cdaae3 |
exit(1);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* A10: */
|
|
Packit |
cdaae3 |
if (s == t->rlink) {
|
|
Packit |
cdaae3 |
t->rlink = p;
|
|
Packit |
cdaae3 |
} else {
|
|
Packit |
cdaae3 |
t->llink = p;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
#ifdef DW_CHECK_CONSISTENCY
|
|
Packit |
cdaae3 |
dwarf_check_balance(head,1);
|
|
Packit |
cdaae3 |
#endif
|
|
Packit |
cdaae3 |
return q;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
/* Search and, if missing, insert. */
|
|
Packit |
cdaae3 |
void *
|
|
Packit |
cdaae3 |
dwarf_tsearch(const void *key, void **headin,
|
|
Packit |
cdaae3 |
int (*compar)(const void *, const void *))
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry **headp = (struct ts_entry **)headin;
|
|
Packit |
cdaae3 |
struct ts_entry *head = 0;
|
|
Packit |
cdaae3 |
struct ts_entry *r = 0;
|
|
Packit |
cdaae3 |
int inserted = 0;
|
|
Packit |
cdaae3 |
/* kcomparv should be ignored */
|
|
Packit |
cdaae3 |
int kcomparv = 0;
|
|
Packit |
cdaae3 |
/* nullme won't be set. */
|
|
Packit |
cdaae3 |
struct ts_entry *nullme = 0;
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
if (!headp) {
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
head = *headp;
|
|
Packit |
cdaae3 |
if (!head) {
|
|
Packit |
cdaae3 |
struct ts_entry *root = 0;
|
|
Packit |
cdaae3 |
head = allocate_ts_entry(0);
|
|
Packit |
cdaae3 |
if(!head) {
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
root = allocate_ts_entry(key);
|
|
Packit |
cdaae3 |
if(!root) {
|
|
Packit |
cdaae3 |
free(head);
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
head->rlink = root;
|
|
Packit |
cdaae3 |
/* head->llink is used for the depth, as a count */
|
|
Packit |
cdaae3 |
/* head points to the special head node ... */
|
|
Packit |
cdaae3 |
*headin = head;
|
|
Packit |
cdaae3 |
return (void *)(&(root->keyptr));
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
r = tsearch_inner(key,head,compar,&inserted,&nullme,&kcomparv);
|
|
Packit |
cdaae3 |
if (!r) {
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
return (void *)&(r->keyptr);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Search without insert. */
|
|
Packit |
cdaae3 |
void *
|
|
Packit |
cdaae3 |
dwarf_tfind(const void *key, void *const*rootp,
|
|
Packit |
cdaae3 |
int (*compar)(const void *, const void *))
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry **phead = (struct ts_entry **)rootp;
|
|
Packit |
cdaae3 |
struct ts_entry *head = 0;
|
|
Packit |
cdaae3 |
struct ts_entry *p = 0;
|
|
Packit |
cdaae3 |
if (!phead) {
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
head = *phead;
|
|
Packit |
cdaae3 |
if (!head) {
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
p = head->rlink;
|
|
Packit |
cdaae3 |
while(p) {
|
|
Packit |
cdaae3 |
int kc = compar(key,p->keyptr);
|
|
Packit |
cdaae3 |
if(!kc) {
|
|
Packit |
cdaae3 |
return (void *)(&(p->keyptr));
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
p = getlink(p,kc);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Used for an array of records used in the deletion code.
|
|
Packit |
cdaae3 |
k == 0 for the special head node which is never matched by
|
|
Packit |
cdaae3 |
input.
|
|
Packit |
cdaae3 |
k == 1 etc.
|
|
Packit |
cdaae3 |
*/
|
|
Packit |
cdaae3 |
struct pkrecord {
|
|
Packit |
cdaae3 |
struct ts_entry *pk;
|
|
Packit |
cdaae3 |
int ak; /* Is -1 or +1 */
|
|
Packit |
cdaae3 |
};
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Here we rearrange the tree so the node p to be deleted
|
|
Packit |
cdaae3 |
is a node with a null left link. With that done
|
|
Packit |
cdaae3 |
we can fix pkarray and then we can use the pkarray
|
|
Packit |
cdaae3 |
to rebalance.
|
|
Packit |
cdaae3 |
It's a bit long, so we refactor out the code from
|
|
Packit |
cdaae3 |
where it is called.
|
|
Packit |
cdaae3 |
The rearrangement is Algorithm 6.2.2D in Knuth.
|
|
Packit |
cdaae3 |
PRECONDITION: p,p->rlink, pp non-null.
|
|
Packit |
cdaae3 |
RETURNS: new high index of pkarray.
|
|
Packit |
cdaae3 |
*/
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
static unsigned
|
|
Packit |
cdaae3 |
rearrange_tree_so_p_llink_null( struct pkrecord * pkarray,
|
|
Packit |
cdaae3 |
unsigned k,
|
|
Packit |
cdaae3 |
UNUSEDARG struct ts_entry *head,
|
|
Packit |
cdaae3 |
struct ts_entry *r,
|
|
Packit |
cdaae3 |
struct ts_entry *p,
|
|
Packit |
cdaae3 |
UNUSEDARG int pak,
|
|
Packit |
cdaae3 |
UNUSEDARG struct ts_entry *pp,
|
|
Packit |
cdaae3 |
int ppak)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry *s = 0;
|
|
Packit |
cdaae3 |
unsigned k2 = 0; /* indexing pkarray */
|
|
Packit |
cdaae3 |
int pbalance = p->balance;
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Step D3 */
|
|
Packit |
cdaae3 |
/* Since we are going to modify the tree by
|
|
Packit |
cdaae3 |
movement of a node down the tree a ways,
|
|
Packit |
cdaae3 |
we need to build pkarray with the (not yet
|
|
Packit |
cdaae3 |
found) new next node, in pkarray[k], not
|
|
Packit |
cdaae3 |
p.
|
|
Packit |
cdaae3 |
The deletion will be of p, but by then
|
|
Packit |
cdaae3 |
p will be moved in the tree so it has a null left link.
|
|
Packit |
cdaae3 |
P's possibly-non-null right link
|
|
Packit |
cdaae3 |
*/
|
|
Packit |
cdaae3 |
k2 = k;
|
|
Packit |
cdaae3 |
k2++;
|
|
Packit |
cdaae3 |
r = p->rlink;
|
|
Packit |
cdaae3 |
pkarray[k2].pk = r;
|
|
Packit |
cdaae3 |
pkarray[k2].ak = -1;
|
|
Packit |
cdaae3 |
s = r->llink;
|
|
Packit |
cdaae3 |
/* Move down and left to get a null llink. */
|
|
Packit |
cdaae3 |
while (s->llink) {
|
|
Packit |
cdaae3 |
k2++;
|
|
Packit |
cdaae3 |
r = s;
|
|
Packit |
cdaae3 |
s = r->llink;
|
|
Packit |
cdaae3 |
pkarray[k2].pk = r;
|
|
Packit |
cdaae3 |
pkarray[k2].ak = -1;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
/* Now we move S up in place (in the tree)
|
|
Packit |
cdaae3 |
of the node P we will delete.
|
|
Packit |
cdaae3 |
and p replaces s.
|
|
Packit |
cdaae3 |
Finally winding up with a newly shaped balanced tree.
|
|
Packit |
cdaae3 |
*/
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry *tmp = 0;
|
|
Packit |
cdaae3 |
int sbalance = s->balance;
|
|
Packit |
cdaae3 |
s->llink = p->llink;
|
|
Packit |
cdaae3 |
r->llink = p;
|
|
Packit |
cdaae3 |
p->llink = 0;
|
|
Packit |
cdaae3 |
tmp = p->rlink;
|
|
Packit |
cdaae3 |
p->rlink = s->rlink;
|
|
Packit |
cdaae3 |
s->rlink = tmp;
|
|
Packit |
cdaae3 |
setlink(pp,ppak,s);
|
|
Packit |
cdaae3 |
s->balance = pbalance;
|
|
Packit |
cdaae3 |
p->balance = sbalance;
|
|
Packit |
cdaae3 |
/* Now the tree is rearranged and still in balance. */
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Replace the previous k position entry with S.
|
|
Packit |
cdaae3 |
We trace the right link off of the moved S node. */
|
|
Packit |
cdaae3 |
pkarray[k].pk = s;
|
|
Packit |
cdaae3 |
pkarray[k].ak = 1;
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
r->llink = p->rlink;
|
|
Packit |
cdaae3 |
/* Now p is out of the tree and we start
|
|
Packit |
cdaae3 |
the rebalance at r. pkarray Index k2. */
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
/* Step D4 */
|
|
Packit |
cdaae3 |
free(p);
|
|
Packit |
cdaae3 |
return k2;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Returns deleted node parent unless the head changed.
|
|
Packit |
cdaae3 |
Returns NULL if wanted node not found or the tree
|
|
Packit |
cdaae3 |
is now empty or the head node changed.
|
|
Packit |
cdaae3 |
Sets *did_delete if it found and deleted a node.
|
|
Packit |
cdaae3 |
Sets *tree_empty if there are no more user nodes present.
|
|
Packit |
cdaae3 |
*/
|
|
Packit |
cdaae3 |
static struct ts_entry *
|
|
Packit |
cdaae3 |
tdelete_inner(const void *key,
|
|
Packit |
cdaae3 |
struct ts_entry *head,
|
|
Packit |
cdaae3 |
int (*compar)(const void *, const void *),
|
|
Packit |
cdaae3 |
int *tree_empty,
|
|
Packit |
cdaae3 |
int *did_delete
|
|
Packit |
cdaae3 |
)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry *p = 0;
|
|
Packit |
cdaae3 |
struct ts_entry *pp = 0;
|
|
Packit |
cdaae3 |
struct pkrecord * pkarray = 0;
|
|
Packit |
cdaae3 |
int depth = head->llink - (struct ts_entry *)0;
|
|
Packit |
cdaae3 |
unsigned k = 0;
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Allocate extra, head is on the stack we create
|
|
Packit |
cdaae3 |
here and the depth might increase. */
|
|
Packit |
cdaae3 |
depth = depth + 4;
|
|
Packit |
cdaae3 |
pkarray = calloc(sizeof(struct pkrecord),depth);
|
|
Packit |
cdaae3 |
if(!pkarray) {
|
|
Packit |
cdaae3 |
/* Malloc fails, we could abort... */
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
k = 0;
|
|
Packit |
cdaae3 |
pkarray[k].pk=head;
|
|
Packit |
cdaae3 |
pkarray[k].ak=1;
|
|
Packit |
cdaae3 |
p = head->rlink;
|
|
Packit |
cdaae3 |
while(p) {
|
|
Packit |
cdaae3 |
int kc = 0;
|
|
Packit |
cdaae3 |
k++;
|
|
Packit |
cdaae3 |
kc = compar(key,p->keyptr);
|
|
Packit |
cdaae3 |
pkarray[k].pk = p;
|
|
Packit |
cdaae3 |
pkarray[k].ak = kc;
|
|
Packit |
cdaae3 |
if(!kc) {
|
|
Packit |
cdaae3 |
break;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
p = getlink(p,kc);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if(!p) {
|
|
Packit |
cdaae3 |
/* Node to delete never found. */
|
|
Packit |
cdaae3 |
free(pkarray);
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry *t = 0;
|
|
Packit |
cdaae3 |
struct ts_entry *r = 0;
|
|
Packit |
cdaae3 |
int pak = 0;
|
|
Packit |
cdaae3 |
int ppak = 0;
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
p = pkarray[k].pk;
|
|
Packit |
cdaae3 |
pak = pkarray[k].ak;
|
|
Packit |
cdaae3 |
pp = pkarray[k-1].pk;
|
|
Packit |
cdaae3 |
ppak = pkarray[k-1].ak;
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Found a match. p to be deleted. */
|
|
Packit |
cdaae3 |
t = p;
|
|
Packit |
cdaae3 |
*did_delete = 1;
|
|
Packit |
cdaae3 |
if(!t->rlink) {
|
|
Packit |
cdaae3 |
if(k == 1 && !t->llink) {
|
|
Packit |
cdaae3 |
*tree_empty = 1;
|
|
Packit |
cdaae3 |
/* upper level will fix up head node. */
|
|
Packit |
cdaae3 |
free(t);
|
|
Packit |
cdaae3 |
free(pkarray);
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
/* t->llink might be NULL. */
|
|
Packit |
cdaae3 |
setlink(pp,ppak,t->llink);
|
|
Packit |
cdaae3 |
/* ASSERT: t->llink NULL or t->llink
|
|
Packit |
cdaae3 |
has no children, balance zero and balance
|
|
Packit |
cdaae3 |
of t->llink not changing. */
|
|
Packit |
cdaae3 |
k--;
|
|
Packit |
cdaae3 |
/* Step D4. */
|
|
Packit |
cdaae3 |
free(t);
|
|
Packit |
cdaae3 |
goto balance;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
#ifdef IMPLEMENTD15
|
|
Packit |
cdaae3 |
/* Step D1.5 */
|
|
Packit |
cdaae3 |
if(!t->llink) {
|
|
Packit |
cdaae3 |
setlink(pp,ppak,t->rlink);
|
|
Packit |
cdaae3 |
/* we change the left link off ak */
|
|
Packit |
cdaae3 |
k--;
|
|
Packit |
cdaae3 |
/* Step D4. */
|
|
Packit |
cdaae3 |
free(t);
|
|
Packit |
cdaae3 |
goto balance;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
#endif /* IMPLEMENTD15 */
|
|
Packit |
cdaae3 |
/* Step D2 */
|
|
Packit |
cdaae3 |
r = t->rlink;
|
|
Packit |
cdaae3 |
if (!r->llink) {
|
|
Packit |
cdaae3 |
/* We decrease the height of the right tree. */
|
|
Packit |
cdaae3 |
r->llink = t->llink;
|
|
Packit |
cdaae3 |
setlink(pp,ppak,r);
|
|
Packit |
cdaae3 |
pkarray[k].pk = r;
|
|
Packit |
cdaae3 |
pkarray[k].ak = 1;
|
|
Packit |
cdaae3 |
/* The following essential line not mentioned
|
|
Packit |
cdaae3 |
in Knuth AFAICT. */
|
|
Packit |
cdaae3 |
r->balance = t->balance;
|
|
Packit |
cdaae3 |
/* Step D4. */
|
|
Packit |
cdaae3 |
free(t);
|
|
Packit |
cdaae3 |
goto balance;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
/* Step D3, we rearrange the tree
|
|
Packit |
cdaae3 |
and pkarray so the balance step can work.
|
|
Packit |
cdaae3 |
step D2 is insufficient so not done. */
|
|
Packit |
cdaae3 |
k = rearrange_tree_so_p_llink_null(pkarray,k,
|
|
Packit |
cdaae3 |
head,r,
|
|
Packit |
cdaae3 |
p,pak,pp,ppak);
|
|
Packit |
cdaae3 |
goto balance;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
/* Now use pkarray decide if rebalancing
|
|
Packit |
cdaae3 |
needed and, if needed, to rebalance.
|
|
Packit |
cdaae3 |
k here matches l-1 in Knuth. */
|
|
Packit |
cdaae3 |
balance:
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
unsigned k2 = k;
|
|
Packit |
cdaae3 |
/* We do not want a test in the for() itself. */
|
|
Packit |
cdaae3 |
for( ; 1 ; k2--) {
|
|
Packit |
cdaae3 |
struct ts_entry *pk = 0;
|
|
Packit |
cdaae3 |
int ak = 0;
|
|
Packit |
cdaae3 |
int bk = 0;
|
|
Packit |
cdaae3 |
if (k2 == 0) {
|
|
Packit |
cdaae3 |
/* decreased in height */
|
|
Packit |
cdaae3 |
head->llink--;
|
|
Packit |
cdaae3 |
goto cleanup;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
pk = pkarray[k2].pk;
|
|
Packit |
cdaae3 |
if (!pk) {
|
|
Packit |
cdaae3 |
/* Nothing here to work with. Move up. */
|
|
Packit |
cdaae3 |
continue;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
ak = pkarray[k2].ak;
|
|
Packit |
cdaae3 |
bk = pk->balance;
|
|
Packit |
cdaae3 |
if(bk == ak) {
|
|
Packit |
cdaae3 |
pk->balance = 0;
|
|
Packit |
cdaae3 |
continue;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if(bk == 0) {
|
|
Packit |
cdaae3 |
pk->balance = -ak;
|
|
Packit |
cdaae3 |
goto cleanup;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
/* ASSERT: bk == -ak. We
|
|
Packit |
cdaae3 |
will use bk == adel here (just below). */
|
|
Packit |
cdaae3 |
/* Rebalancing required. Here we use (1) and (2)
|
|
Packit |
cdaae3 |
in 6.2.3 to adjust the nodes */
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
/* Rebalance. We use s for what
|
|
Packit |
cdaae3 |
is called A in Knuth Case 1, Case 2
|
|
Packit |
cdaae3 |
page 461. r For what is called B.
|
|
Packit |
cdaae3 |
So the link movement logic looks similar
|
|
Packit |
cdaae3 |
to the tsearch insert case.*/
|
|
Packit |
cdaae3 |
struct ts_entry *r = 0;
|
|
Packit |
cdaae3 |
struct ts_entry *s = 0;
|
|
Packit |
cdaae3 |
struct ts_entry *pa = 0;
|
|
Packit |
cdaae3 |
int pak = 0;
|
|
Packit |
cdaae3 |
int adel = -ak;
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
s = pk;
|
|
Packit |
cdaae3 |
r = getlink(s,adel);
|
|
Packit |
cdaae3 |
pa = pkarray[k2-1].pk;
|
|
Packit |
cdaae3 |
pak = pkarray[k2-1].ak;
|
|
Packit |
cdaae3 |
if(r->balance == adel) {
|
|
Packit |
cdaae3 |
/* case 1. */
|
|
Packit |
cdaae3 |
setlink(s,adel,getlink(r,-adel));
|
|
Packit |
cdaae3 |
setlink(r,-adel,s);
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* A10 in tsearch. */
|
|
Packit |
cdaae3 |
setlink(pa,pak,r);
|
|
Packit |
cdaae3 |
s->balance = 0;
|
|
Packit |
cdaae3 |
r->balance = 0;
|
|
Packit |
cdaae3 |
continue;
|
|
Packit |
cdaae3 |
} else if (r->balance == -adel) {
|
|
Packit |
cdaae3 |
/* case 2 */
|
|
Packit |
cdaae3 |
/* x plays the role of p in step A9 */
|
|
Packit |
cdaae3 |
struct ts_entry*x = getlink(r,-adel);
|
|
Packit |
cdaae3 |
setlink(r,-adel,getlink(x,adel));
|
|
Packit |
cdaae3 |
setlink(x,adel,r);
|
|
Packit |
cdaae3 |
setlink(s,adel,getlink(x,-adel));
|
|
Packit |
cdaae3 |
setlink(x,-adel,s);
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* A10 in tsearch. */
|
|
Packit |
cdaae3 |
setlink(pa,pak,x);
|
|
Packit |
cdaae3 |
if(x->balance == adel) {
|
|
Packit |
cdaae3 |
s->balance = -adel;
|
|
Packit |
cdaae3 |
r->balance = 0;
|
|
Packit |
cdaae3 |
} else if (x->balance == 0) {
|
|
Packit |
cdaae3 |
s->balance = 0;
|
|
Packit |
cdaae3 |
r->balance = 0;
|
|
Packit |
cdaae3 |
} else if (x->balance == -adel) {
|
|
Packit |
cdaae3 |
s->balance = 0;
|
|
Packit |
cdaae3 |
r->balance = adel;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
x->balance = 0;
|
|
Packit |
cdaae3 |
continue;
|
|
Packit |
cdaae3 |
} else {
|
|
Packit |
cdaae3 |
/* r->balance == 0 case 3
|
|
Packit |
cdaae3 |
we do a single rotation and
|
|
Packit |
cdaae3 |
we are done. */
|
|
Packit |
cdaae3 |
setlink(s,adel,getlink(r,-adel));
|
|
Packit |
cdaae3 |
setlink(r,-adel,s);
|
|
Packit |
cdaae3 |
setlink(pa,pak,r);
|
|
Packit |
cdaae3 |
r->balance = -adel;
|
|
Packit |
cdaae3 |
/*s->balance = r->balance = 0; */
|
|
Packit |
cdaae3 |
goto cleanup;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
cleanup:
|
|
Packit |
cdaae3 |
free(pkarray);
|
|
Packit |
cdaae3 |
#ifdef DW_CHECK_CONSISTENCY
|
|
Packit |
cdaae3 |
dwarf_check_balance(head,1);
|
|
Packit |
cdaae3 |
#endif
|
|
Packit |
cdaae3 |
return pp;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
void *
|
|
Packit |
cdaae3 |
dwarf_tdelete(const void *key, void **rootp,
|
|
Packit |
cdaae3 |
int (*compar)(const void *, const void *))
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry **phead = (struct ts_entry **)rootp;
|
|
Packit |
cdaae3 |
struct ts_entry *head = 0;
|
|
Packit |
cdaae3 |
/* If a leaf is found, we have to null a parent link
|
|
Packit |
cdaae3 |
or the root */
|
|
Packit |
cdaae3 |
struct ts_entry * parentp = 0;
|
|
Packit |
cdaae3 |
int tree_empty = 0;
|
|
Packit |
cdaae3 |
int did_delete = 0;
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
if (!phead) {
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
head = *phead;
|
|
Packit |
cdaae3 |
if (!head) {
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if (!head->rlink) {
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
parentp = tdelete_inner(key,head,compar,&tree_empty,&did_delete);
|
|
Packit |
cdaae3 |
if(tree_empty) {
|
|
Packit |
cdaae3 |
head->rlink = 0;
|
|
Packit |
cdaae3 |
head->llink = 0;
|
|
Packit |
cdaae3 |
free(head);
|
|
Packit |
cdaae3 |
*phead = 0;
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
/* ASSERT: head->rlink non-null. */
|
|
Packit |
cdaae3 |
if(did_delete) {
|
|
Packit |
cdaae3 |
if (!parentp) {
|
|
Packit |
cdaae3 |
parentp = head->rlink;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
return (void *)(&(parentp->keyptr));
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
/* Not deleted */
|
|
Packit |
cdaae3 |
return NULL;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
static void
|
|
Packit |
cdaae3 |
dwarf_twalk_inner(struct ts_entry *p,
|
|
Packit |
cdaae3 |
void (*action)(const void *nodep, const DW_VISIT which, const int depth),
|
|
Packit |
cdaae3 |
unsigned level)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
if (!p->llink && !p->rlink) {
|
|
Packit |
cdaae3 |
action((const void *)(&(p->keyptr)),dwarf_leaf,level);
|
|
Packit |
cdaae3 |
return;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
action((const void *)(&(p->keyptr)),dwarf_preorder,level);
|
|
Packit |
cdaae3 |
if(p->llink) {
|
|
Packit |
cdaae3 |
dwarf_twalk_inner(p->llink,action,level+1);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
action((const void *)(&(p->keyptr)),dwarf_postorder,level);
|
|
Packit |
cdaae3 |
if(p->rlink) {
|
|
Packit |
cdaae3 |
dwarf_twalk_inner(p->rlink,action,level+1);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
action((const void *)(&(p->keyptr)),dwarf_endorder,level);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
void
|
|
Packit |
cdaae3 |
dwarf_twalk(const void *rootp,
|
|
Packit |
cdaae3 |
void (*action)(const void *nodep, const DW_VISIT which, const int depth))
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry *head = (struct ts_entry *)rootp;
|
|
Packit |
cdaae3 |
struct ts_entry *root = 0;
|
|
Packit |
cdaae3 |
if(!head) {
|
|
Packit |
cdaae3 |
return;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
root = head->rlink;
|
|
Packit |
cdaae3 |
if(!root) {
|
|
Packit |
cdaae3 |
return;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
/* Get to actual tree. */
|
|
Packit |
cdaae3 |
dwarf_twalk_inner(root,action,0);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
static void
|
|
Packit |
cdaae3 |
dwarf_tdestroy_inner(struct ts_entry*p,
|
|
Packit |
cdaae3 |
void (*free_node)(void *nodep),
|
|
Packit |
cdaae3 |
int depth)
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
if(p->llink) {
|
|
Packit |
cdaae3 |
dwarf_tdestroy_inner(p->llink,free_node,depth+1);
|
|
Packit |
cdaae3 |
p->llink = 0;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
if(p->rlink) {
|
|
Packit |
cdaae3 |
dwarf_tdestroy_inner(p->rlink,free_node,depth+1);
|
|
Packit |
cdaae3 |
p->rlink = 0;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
free_node((void *)p->keyptr);
|
|
Packit |
cdaae3 |
free(p);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
/* Walk the tree, freeing all space in the tree
|
|
Packit |
cdaae3 |
and calling the user's callback function on each node.
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
It is up to the caller to zero out anything pointing to
|
|
Packit |
cdaae3 |
head (ie, that has the value rootp holds) after this
|
|
Packit |
cdaae3 |
returns.
|
|
Packit |
cdaae3 |
*/
|
|
Packit |
cdaae3 |
void
|
|
Packit |
cdaae3 |
dwarf_tdestroy(void *rootp, void (*free_node)(void *nodep))
|
|
Packit |
cdaae3 |
{
|
|
Packit |
cdaae3 |
struct ts_entry *head = (struct ts_entry *)rootp;
|
|
Packit |
cdaae3 |
struct ts_entry *root = 0;
|
|
Packit |
cdaae3 |
if(!head) {
|
|
Packit |
cdaae3 |
return;
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
root = head->rlink;
|
|
Packit |
cdaae3 |
if(root) {
|
|
Packit |
cdaae3 |
dwarf_tdestroy_inner(root,free_node,0);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
free(head);
|
|
Packit |
cdaae3 |
}
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
|
|
Packit |
cdaae3 |
|