#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS
#endif /* _WIN32 */
#include "config.h"
#ifdef HAVE_UNUSED_ATTRIBUTE
#define UNUSEDARG __attribute__ ((unused))
#else
#define UNUSEDARG
#endif
#include "stdlib.h" /* for free() */
#ifdef HAVE_STDINT_H
#include <stdint.h> /* For uintptr_t */
#endif /* HAVE_STDINT_H */
#include <stdio.h> /* for printf */
#define Dwarf_Unsigned unsigned long long
#if defined(_WIN32) && defined(HAVE_NONSTANDARD_PRINTF_64_FORMAT)
#define DW_PR_DUx "I64x"
#else
#define DW_PR_DUx "llx"
#endif /* DW_PR defines */
#include "dwarf_tsearch.h"
#define IMPLEMENTD15 1
#ifdef DW_CHECK_CONSISTENCY
struct
ts_entry;
void
dwarf_check_balance(
struct
ts_entry *head,
int
finalprefix);
#endif
struct
ts_entry {
void
*keyptr;
int
balance;
struct
ts_entry * llink;
struct
ts_entry * rlink;
};
static
void
printlevel(
int
level)
{
int
len = 0;
int
targetlen = 4 + level;
int
shownlen = 0;
char
number[40];
len =
sprintf
(number,
"<%d>"
,level);
printf
(
"%s"
,number);
shownlen = len;
while
(shownlen < targetlen) {
putchar
(
' '
);
++shownlen;
}
}
void
*
dwarf_initialize_search_hash(
void
**treeptr,
UNUSEDARG DW_TSHASHTYPE(*hashfunc)(
const
void
*key),
UNUSEDARG unsigned
long
size_estimate)
{
return
*treeptr;
}
static
void
tdump_inner(
struct
ts_entry *t,
char
*(keyprint)(
const
void
*),
const
char
*descr,
int
level)
{
const
char
* keyv =
""
;
if
(!t) {
return
;
}
tdump_inner(t->rlink,keyprint,
"right"
,level+1);
printlevel(level);
if
(t->keyptr) {
keyv = keyprint(t->keyptr);
}
printf
(
"0x%08"
DW_PR_DUx
" <keyptr 0x%08"
DW_PR_DUx
"> "
"<%s %s> <bal %3d> "
"<l 0x%08"
DW_PR_DUx
"> <r 0x%08"
DW_PR_DUx
"> "
"%s\n"
,
(Dwarf_Unsigned)(
uintptr_t
)t,
(Dwarf_Unsigned)(
uintptr_t
)t->keyptr,
t->keyptr?
"key "
:
"null"
,
keyv,
t->balance,
(Dwarf_Unsigned)(
uintptr_t
)t->llink,
(Dwarf_Unsigned)(
uintptr_t
)t->rlink,
descr);
tdump_inner(t->llink,keyprint,
"left "
,level+1);
}
#ifdef DW_CHECK_CONSISTENCY
int
dwarf_check_balance_inner(
struct
ts_entry *t,
int
level,
int
maxdepth,
int
*founderror,
const
char
*prefix)
{
int
l = 0;
int
r = 0;
if
(level > maxdepth) {
printf
(
"%s Likely internal erroneous link loop, got to depth %d.\n"
,
prefix,level);
exit
(1);
}
if
(!t) {
return
0;
}
if
(!t->llink && !t->rlink) {
if
(t->balance != 0) {
printf
(
"%s: Balance at 0x%"
DW_PR_DUx
" should be 0 is %d.\n"
,
prefix,
(Dwarf_Unsigned)(
uintptr_t
)t,
t->balance);
(*founderror)++;
}
return
1;
}
l = dwarf_check_balance_inner(t->llink,level+1,maxdepth,
founderror,prefix);
r = dwarf_check_balance_inner(t->rlink,level+1,maxdepth,
founderror,prefix);
if
(l ==r && t->balance != 0) {
printf
(
"%s Balance at 0x%"
DW_PR_DUx
" d should be 0 is %d.\n"
,
prefix,
(Dwarf_Unsigned)(
uintptr_t
)t,
t->balance);
(*founderror)++;
return
l+1;
}
if
(l > r) {
if
( (l-r) != 1) {
printf
(
"%s depth mismatch at 0x%"
DW_PR_DUx
" l %d r %d.\n"
,
prefix,
(Dwarf_Unsigned)(
uintptr_t
)t,
l,r);
(*founderror)++;
}
if
(t->balance != -1) {
printf
(
"%s Balance at 0x%"
DW_PR_DUx
" should be -1 is %d.\n"
,
prefix,
(Dwarf_Unsigned)(
uintptr_t
)t,
t->balance);
(*founderror)++;
}
return
l+1;
}
if
(r != l) {
if
( (r-l) != 1) {
printf
(
"%s depth mismatch at 0x%"
DW_PR_DUx
" r %d l %d.\n"
,
prefix,
(Dwarf_Unsigned)(
uintptr_t
)t,
r,l);
(*founderror)++;
}
if
(t->balance != 1) {
printf
(
"%s Balance at 0x%"
DW_PR_DUx
" should be 1 is %d.\n"
,
prefix,
(Dwarf_Unsigned)(
uintptr_t
)t,
t->balance);
(*founderror)++;
}
}
else
{
if
(t->balance != 0) {
printf
(
"%s Balance at 0x%"
DW_PR_DUx
" should be 0 is %d.\n"
,
prefix,
(Dwarf_Unsigned)(
uintptr_t
)t,
t->balance);
(*founderror)++;
}
}
return
r+1;
}
void
dwarf_check_balance(
struct
ts_entry *head,
int
finalprefix)
{
const
char
*prefix = 0;
int
maxdepth = 0;
size_t
headdepth = 0;
int
errcount = 0;
int
depth = 0;
struct
ts_entry*root = 0;
if
(finalprefix) {
prefix =
"BalanceError:"
;
}
else
{
prefix =
"BalanceWarn:"
;
}
if
(!head) {
printf
(
"%s check balance null tree ptr\n"
,prefix);
return
;
}
root = head->rlink;
headdepth = head->llink - (
struct
ts_entry *)0;
if
(!root) {
printf
(
"%s check balance null tree ptr\n"
,prefix);
return
;
}
maxdepth = headdepth+10;
headdepth++;
depth = dwarf_check_balance_inner(root,depth,maxdepth,&errcount,prefix);
if
(depth != headdepth) {
printf
(
"%s Head node says depth %lu, it is really %d\n"
,
prefix,
(unsigned
long
)headdepth,
depth);
++errcount;
}
if
(errcount) {
printf
(
"%s error count %d\n"
,prefix,errcount);
}
return
;
}
#endif
void
dwarf_tdump(
const
void
*headp_in,
char
*(*keyprint)(
const
void
*),
const
char
*msg)
{
const
struct
ts_entry *head = (
const
struct
ts_entry *)headp_in;
struct
ts_entry *root = 0;
size_t
headdepth = 0;
if
(!head) {
printf
(
"dumptree null tree ptr : %s\n"
,msg);
return
;
}
headdepth = head->llink - (
struct
ts_entry *)0;
printf
(
"dumptree head ptr : 0x%08"
DW_PR_DUx
" tree-depth %d: %s\n"
,
(Dwarf_Unsigned)(
uintptr_t
)head,
(
int
)headdepth,
msg);
root = head->rlink;
if
(!root) {
printf
(
"Empty tree\n"
);
return
;
}
tdump_inner(root,keyprint,
"top"
,0);
}
static
void
setlink(
struct
ts_entry*t,
int
a,
struct
ts_entry *x)
{
if
(a < 0) {
t->llink = x;
}
else
{
t->rlink = x;
}
}
static
struct
ts_entry*
getlink(
struct
ts_entry*t,
int
a)
{
if
(a < 0) {
return
(t->llink);
}
return
(t->rlink);
}
static
struct
ts_entry *
allocate_ts_entry(
const
void
*key)
{
struct
ts_entry *e = (
struct
ts_entry *)
malloc
(
sizeof
(
struct
ts_entry));
if
(!e) {
return
NULL;
}
e->keyptr = (
void
*)key;
e->balance = 0;
e->llink = 0;
e->rlink = 0;
return
e;
}
static
struct
ts_entry *
tsearch_insert_k(
const
void
*key,
int
kc,
struct
ts_entry *p)
{
struct
ts_entry *q = allocate_ts_entry(key);
if
(!q) {
return
NULL;
}
setlink(p,kc,q);
return
q;
}
static
struct
ts_entry *
tsearch_inner_do_insert(
const
void
*key,
int
kc,
int
* inserted,
struct
ts_entry* p)
{
struct
ts_entry *q = 0;
q = tsearch_insert_k(key,kc,p);
if
(q) {
*inserted = 1;
}
return
q;
}
static
struct
ts_entry *
tsearch_inner(
const
void
*key,
struct
ts_entry* head,
int
(*compar)(
const
void
*,
const
void
*),
int
*inserted,
UNUSEDARG
struct
ts_entry **nullme,
UNUSEDARG
int
* comparres)
{
struct
ts_entry *t = head;
struct
ts_entry *p = head->rlink;
struct
ts_entry *s = p;
struct
ts_entry *r = 0;
struct
ts_entry *q = 0;
int
a = 0;
int
kc = 0;
for
(;;) {
kc = compar(key,p->keyptr);
if
(kc) {
q = getlink(p,kc);
if
(!q) {
q = tsearch_inner_do_insert(key,kc,inserted,p);
if
(!q) {
return
q;
}
break
;
}
if
(q->balance) {
t = p;
s = q;
}
p = q;
continue
;
}
return
p;
}
{
int
kc2 = compar(key,s->keyptr);
if
(kc2 < 0) {
a = -1;
}
else
{
a = 1;
}
r = p = getlink(s,a);
while
(p != q) {
int
kc3 = compar(key,p->keyptr);
if
(kc3 < 0) {
p->balance = -1;
p = p->llink;
}
else
if
(kc3 > 0) {
p->balance = 1;
p = p->rlink;
}
else
{
break
;
}
}
}
{
if
(! s->balance) {
s->balance = a;
head->llink = head->llink + 1;
return
q;
}
if
(s->balance == -a) {
s->balance = 0;
return
q;
}
if
(s->balance == a) {
if
(r->balance == a) {
p = r;
setlink(s,a,getlink(r,-a));
setlink(r,-a,s);
s->balance = 0;
r->balance = 0;
}
else
if
(r->balance == -a) {
p = getlink(r,-a);
setlink(r,-a,getlink(p,a));
setlink(p,a,r);
setlink(s,a,getlink(p,-a));
setlink(p,-a,s);
if
(p->balance == a) {
s->balance = -a;
r->balance = 0;
}
else
if
(p->balance == 0) {
s->balance = 0;
r->balance = 0;
}
else
if
(p->balance == -a) {
s->balance = 0;
r->balance = a;
}
p->balance = 0;
}
else
{
fprintf
(stderr,
"Impossible balanced tree situation!\n"
);
exit
(1);
}
}
else
{
fprintf
(stderr,
"Impossible balanced tree situation!!\n"
);
exit
(1);
}
}
if
(s == t->rlink) {
t->rlink = p;
}
else
{
t->llink = p;
}
#ifdef DW_CHECK_CONSISTENCY
dwarf_check_balance(head,1);
#endif
return
q;
}
void
*
dwarf_tsearch(
const
void
*key,
void
**headin,
int
(*compar)(
const
void
*,
const
void
*))
{
struct
ts_entry **headp = (
struct
ts_entry **)headin;
struct
ts_entry *head = 0;
struct
ts_entry *r = 0;
int
inserted = 0;
int
kcomparv = 0;
struct
ts_entry *nullme = 0;
if
(!headp) {
return
NULL;
}
head = *headp;
if
(!head) {
struct
ts_entry *root = 0;
head = allocate_ts_entry(0);
if
(!head) {
return
NULL;
}
root = allocate_ts_entry(key);
if
(!root) {
free
(head);
return
NULL;
}
head->rlink = root;
*headin = head;
return
(
void
*)(&(root->keyptr));
}
r = tsearch_inner(key,head,compar,&inserted,&nullme,&kcomparv);
if
(!r) {
return
NULL;
}
return
(
void
*)&(r->keyptr);
}
void
*
dwarf_tfind(
const
void
*key,
void
*
const
*rootp,
int
(*compar)(
const
void
*,
const
void
*))
{
struct
ts_entry *
const
*phead = (
struct
ts_entry *
const
*)rootp;
struct
ts_entry *head = 0;
struct
ts_entry *p = 0;
if
(!phead) {
return
NULL;
}
head = *phead;
if
(!head) {
return
NULL;
}
p = head->rlink;
while
(p) {
int
kc = compar(key,p->keyptr);
if
(!kc) {
return
(
void
*)(&(p->keyptr));
}
p = getlink(p,kc);
}
return
NULL;
}
struct
pkrecord {
struct
ts_entry *pk;
int
ak;
};
static
unsigned
rearrange_tree_so_p_llink_null(
struct
pkrecord * pkarray,
unsigned k,
UNUSEDARG
struct
ts_entry *head,
struct
ts_entry *r,
struct
ts_entry *p,
UNUSEDARG
int
pak,
UNUSEDARG
struct
ts_entry *pp,
int
ppak)
{
struct
ts_entry *s = 0;
unsigned k2 = 0;
int
pbalance = p->balance;
k2 = k;
k2++;
r = p->rlink;
pkarray[k2].pk = r;
pkarray[k2].ak = -1;
s = r->llink;
while
(s->llink) {
k2++;
r = s;
s = r->llink;
pkarray[k2].pk = r;
pkarray[k2].ak = -1;
}
{
struct
ts_entry *tmp = 0;
int
sbalance = s->balance;
s->llink = p->llink;
r->llink = p;
p->llink = 0;
tmp = p->rlink;
p->rlink = s->rlink;
s->rlink = tmp;
setlink(pp,ppak,s);
s->balance = pbalance;
p->balance = sbalance;
pkarray[k].pk = s;
pkarray[k].ak = 1;
r->llink = p->rlink;
}
free
(p);
return
k2;
}
static
struct
ts_entry *
tdelete_inner(
const
void
*key,
struct
ts_entry *head,
int
(*compar)(
const
void
*,
const
void
*),
int
*tree_empty,
int
*did_delete
)
{
struct
ts_entry *p = 0;
struct
ts_entry *pp = 0;
struct
pkrecord * pkarray = 0;
size_t
depth = head->llink - (
struct
ts_entry *)0;
unsigned k = 0;
depth = depth + 4;
pkarray =
calloc
(
sizeof
(
struct
pkrecord),depth);
if
(!pkarray) {
return
NULL;
}
k = 0;
pkarray[k].pk=head;
pkarray[k].ak=1;
p = head->rlink;
while
(p) {
int
kc = 0;
k++;
kc = compar(key,p->keyptr);
pkarray[k].pk = p;
pkarray[k].ak = kc;
if
(!kc) {
break
;
}
p = getlink(p,kc);
}
if
(!p) {
free
(pkarray);
return
NULL;
}
{
struct
ts_entry *t = 0;
struct
ts_entry *r = 0;
int
pak = 0;
int
ppak = 0;
p = pkarray[k].pk;
pak = pkarray[k].ak;
pp = pkarray[k-1].pk;
ppak = pkarray[k-1].ak;
t = p;
*did_delete = 1;
if
(!t->rlink) {
if
(k == 1 && !t->llink) {
*tree_empty = 1;
free
(t);
free
(pkarray);
return
NULL;
}
setlink(pp,ppak,t->llink);
k--;
free
(t);
goto
balance;
}
#ifdef IMPLEMENTD15
if
(!t->llink) {
setlink(pp,ppak,t->rlink);
k--;
free
(t);
goto
balance;
}
#endif /* IMPLEMENTD15 */
r = t->rlink;
if
(!r->llink) {
r->llink = t->llink;
setlink(pp,ppak,r);
pkarray[k].pk = r;
pkarray[k].ak = 1;
r->balance = t->balance;
free
(t);
goto
balance;
}
k = rearrange_tree_so_p_llink_null(pkarray,k,
head,r,
p,pak,pp,ppak);
goto
balance;
}
balance:
{
unsigned k2 = k;
for
( ; 1 ; k2--) {
struct
ts_entry *pk = 0;
int
ak = 0;
int
bk = 0;
if
(k2 == 0) {
head->llink--;
goto
cleanup;
}
pk = pkarray[k2].pk;
if
(!pk) {
continue
;
}
ak = pkarray[k2].ak;
bk = pk->balance;
if
(bk == ak) {
pk->balance = 0;
continue
;
}
if
(bk == 0) {
pk->balance = -ak;
goto
cleanup;
}
{
struct
ts_entry *r = 0;
struct
ts_entry *s = 0;
struct
ts_entry *pa = 0;
int
pak = 0;
int
adel = -ak;
s = pk;
r = getlink(s,adel);
pa = pkarray[k2-1].pk;
pak = pkarray[k2-1].ak;
if
(r->balance == adel) {
setlink(s,adel,getlink(r,-adel));
setlink(r,-adel,s);
setlink(pa,pak,r);
s->balance = 0;
r->balance = 0;
continue
;
}
else
if
(r->balance == -adel) {
struct
ts_entry*x = getlink(r,-adel);
setlink(r,-adel,getlink(x,adel));
setlink(x,adel,r);
setlink(s,adel,getlink(x,-adel));
setlink(x,-adel,s);
setlink(pa,pak,x);
if
(x->balance == adel) {
s->balance = -adel;
r->balance = 0;
}
else
if
(x->balance == 0) {
s->balance = 0;
r->balance = 0;
}
else
if
(x->balance == -adel) {
s->balance = 0;
r->balance = adel;
}
x->balance = 0;
continue
;
}
else
{
setlink(s,adel,getlink(r,-adel));
setlink(r,-adel,s);
setlink(pa,pak,r);
r->balance = -adel;
goto
cleanup;
}
}
}
}
cleanup:
free
(pkarray);
#ifdef DW_CHECK_CONSISTENCY
dwarf_check_balance(head,1);
#endif
return
pp;
}
void
*
dwarf_tdelete(
const
void
*key,
void
**rootp,
int
(*compar)(
const
void
*,
const
void
*))
{
struct
ts_entry **phead = (
struct
ts_entry **)rootp;
struct
ts_entry *head = 0;
struct
ts_entry * parentp = 0;
int
tree_empty = 0;
int
did_delete = 0;
if
(!phead) {
return
NULL;
}
head = *phead;
if
(!head) {
return
NULL;
}
if
(!head->rlink) {
return
NULL;
}
parentp = tdelete_inner(key,head,compar,&tree_empty,&did_delete);
if
(tree_empty) {
head->rlink = 0;
head->llink = 0;
free
(head);
*phead = 0;
return
NULL;
}
if
(did_delete) {
if
(!parentp) {
parentp = head->rlink;
}
return
(
void
*)(&(parentp->keyptr));
}
return
NULL;
}
static
void
dwarf_twalk_inner(
struct
ts_entry *p,
void
(*action)(
const
void
*nodep,
const
DW_VISIT which,
const
int
depth),
unsigned level)
{
if
(!p->llink && !p->rlink) {
action((
const
void
*)(&(p->keyptr)),dwarf_leaf,level);
return
;
}
action((
const
void
*)(&(p->keyptr)),dwarf_preorder,level);
if
(p->llink) {
dwarf_twalk_inner(p->llink,action,level+1);
}
action((
const
void
*)(&(p->keyptr)),dwarf_postorder,level);
if
(p->rlink) {
dwarf_twalk_inner(p->rlink,action,level+1);
}
action((
const
void
*)(&(p->keyptr)),dwarf_endorder,level);
}
void
dwarf_twalk(
const
void
*rootp,
void
(*action)(
const
void
*nodep,
const
DW_VISIT which,
const
int
depth))
{
const
struct
ts_entry *head = (
const
struct
ts_entry *)rootp;
struct
ts_entry *root = 0;
if
(!head) {
return
;
}
root = head->rlink;
if
(!root) {
return
;
}
dwarf_twalk_inner(root,action,0);
}
static
void
dwarf_tdestroy_inner(
struct
ts_entry*p,
void
(*free_node)(
void
*nodep),
int
depth)
{
if
(p->llink) {
dwarf_tdestroy_inner(p->llink,free_node,depth+1);
p->llink = 0;
}
if
(p->rlink) {
dwarf_tdestroy_inner(p->rlink,free_node,depth+1);
p->rlink = 0;
}
free_node((
void
*)p->keyptr);
free
(p);
}
void
dwarf_tdestroy(
void
*rootp,
void
(*free_node)(
void
*nodep))
{
struct
ts_entry *head = (
struct
ts_entry *)rootp;
struct
ts_entry *root = 0;
if
(!head) {
return
;
}
root = head->rlink;
if
(root) {
dwarf_tdestroy_inner(root,free_node,0);
}
free
(head);
}