Blame dwarfdump/dwarf_tsearchbal.c

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