summaryrefslogtreecommitdiff
path: root/src/lib/libast/cdt/dttree.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
committerIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
commit3950ffe2a485479f6561c27364d3d7df5a21d124 (patch)
tree468c6e14449d1b1e279222ec32f676b0311917d2 /src/lib/libast/cdt/dttree.c
downloadksh-upstream.tar.gz
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/lib/libast/cdt/dttree.c')
-rw-r--r--src/lib/libast/cdt/dttree.c696
1 files changed, 696 insertions, 0 deletions
diff --git a/src/lib/libast/cdt/dttree.c b/src/lib/libast/cdt/dttree.c
new file mode 100644
index 0000000..2dd31d3
--- /dev/null
+++ b/src/lib/libast/cdt/dttree.c
@@ -0,0 +1,696 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* David Korn <dgk@research.att.com> *
+* Phong Vo <kpv@research.att.com> *
+* *
+***********************************************************************/
+#include "dthdr.h"
+
+/* Ordered set/multiset
+** dt: dictionary being searched
+** obj: the object to look for.
+** type: search type.
+**
+** Written by Kiem-Phong Vo (5/25/96)
+*/
+
+typedef struct _dttree_s
+{ Dtdata_t data;
+ Dtlink_t* root; /* tree root */
+} Dttree_t;
+
+#ifdef CDT_DEBUG
+int dttreeprint(Dt_t* dt, Dtlink_t* here, int lev, char* (*objprintf)(Void_t*) )
+{
+ int k, rv;
+ char *obj, *endb, buf[1024];
+ Dtdisc_t *disc = dt->disc;
+ Dttree_t *tree = (Dttree_t*)dt->data;
+
+ if(!here && !(here = tree->root) )
+ return -1;
+
+ endb = buf; /* indentation */
+ for(k = 0; k < lev; ++k)
+ { *endb++ = ' '; *endb++ = ' '; }
+
+ *endb++ = '(';
+ obj = (*objprintf)(_DTOBJ(disc, here));
+ k = strlen(obj); memcpy(endb, obj, k); endb += k;
+ *endb++ = ')';
+ *endb++ = ':';
+ *endb++ = ' ';
+
+ *endb++ = '<';
+ if(here->_left)
+ obj = (*objprintf)(_DTOBJ(disc,here->_left));
+ else obj = "NIL";
+ k = strlen(obj); memcpy(endb, obj, k); endb += k;
+ *endb++ = '>';
+ *endb++ = ' ';
+
+ *endb++ = '<';
+ if(here->_rght)
+ obj = (*objprintf)(_DTOBJ(disc,here->_rght));
+ else obj = "NIL";
+ k = strlen(obj); memcpy(endb, obj, k); endb += k;
+ *endb++ = '>';
+ *endb++ = '\n';
+ write(2, buf, endb-buf);
+
+ if(here->_left)
+ dttreeprint(dt, here->_left, lev+1, objprintf);
+ if(here->_rght)
+ dttreeprint(dt, here->_rght, lev+1, objprintf);
+
+ return 0;
+}
+#endif
+
+/* terminal object: DT_FIRST|DT_LAST */
+#if __STD_C
+Void_t* tfirstlast(Dt_t* dt, int type)
+#else
+Void_t* tfirstlast(dt, type)
+Dt_t* dt;
+int type;
+#endif
+{
+ Dtlink_t *t, *root;
+ Dtdisc_t *disc = dt->disc;
+ Dttree_t *tree = (Dttree_t*)dt->data;
+
+ if(!(root = tree->root) )
+ return NIL(Void_t*);
+
+ if(type&DT_LAST)
+ { while((t = root->_rght) )
+ LROTATE(root,t);
+ }
+ else /* type&DT_FIRST */
+ { while((t = root->_left) )
+ RROTATE(root,t);
+ }
+ tree->root = root;
+
+ return _DTOBJ(disc, root);
+}
+
+/* DT_CLEAR */
+#if __STD_C
+static Void_t* tclear(Dt_t* dt)
+#else
+static Void_t* tclear(dt)
+Dt_t* dt;
+#endif
+{
+ Dtlink_t *root, *t;
+ Dtdisc_t *disc = dt->disc;
+ Dttree_t *tree = (Dttree_t*)dt->data;
+
+ root = tree->root;
+ tree->root = NIL(Dtlink_t*);
+ tree->data.size = 0;
+
+ if(root && (disc->link < 0 || disc->freef) )
+ { do
+ { while((t = root->_left) )
+ RROTATE(root,t);
+ t = root->_rght;
+ _dtfree(dt, root, DT_DELETE);
+ } while((root = t) );
+ }
+
+ return NIL(Void_t*);
+}
+
+#if __STD_C
+static Void_t* tlist(Dt_t* dt, Dtlink_t* list, int type)
+#else
+static Void_t* tlist(dt, list, type)
+Dt_t* dt;
+Dtlink_t* list;
+int type;
+#endif
+{
+ Void_t *obj;
+ Dtlink_t *last, *r, *t;
+ Dttree_t *tree = (Dttree_t*)dt->data;
+ Dtdisc_t *disc = dt->disc;
+
+ if(type&(DT_FLATTEN|DT_EXTRACT) )
+ { if((list = tree->root) )
+ { while((t = list->_left) ) /* make smallest object root */
+ RROTATE(list, t);
+ for(r = (last = list)->_rght; r; r = (last = r)->_rght)
+ { while((t = r->_left) ) /* no left children */
+ RROTATE(r,t);
+ last->_rght = r;
+ }
+ }
+
+ if(type&DT_FLATTEN)
+ tree->root = list;
+ else
+ { tree->root = NIL(Dtlink_t*);
+ dt->data->size = 0;
+ }
+ }
+ else /* if(type&DT_RESTORE) */
+ { dt->data->size = 0;
+ for(r = list; r; r = t)
+ { t = r->_rght;
+ obj = _DTOBJ(disc,r);
+ if((*dt->meth->searchf)(dt, (Void_t*)r, DT_RELINK) == obj )
+ dt->data->size += 1;
+ }
+ }
+
+ return (Void_t*)list;
+}
+
+#if __STD_C /* compute tree depth and number of nodes */
+static ssize_t tsize(Dtlink_t* root, ssize_t lev, Dtstat_t* st)
+#else
+static ssize_t tsize(root, lev, st)
+Dtlink_t* root;
+ssize_t lev;
+Dtstat_t* st;
+#endif
+{
+ ssize_t size, z;
+
+ if(!root) /* nothing to do */
+ return 0;
+
+ if(lev >= DT_MAXRECURSE) /* avoid blowing the stack */
+ return -1;
+
+ if(st)
+ { st->mlev = lev > st->mlev ? lev : st->mlev;
+ if(lev < DT_MAXSIZE)
+ { st->msize = lev > st->msize ? lev : st->msize;
+ st->lsize[lev] += 1; /* count #objects per level */
+ }
+ }
+
+ size = 1;
+
+ if((z = tsize(root->_left, lev+1, st)) < 0)
+ return -1;
+ else size += z;
+
+ if((z = tsize(root->_rght, lev+1, st)) < 0)
+ return -1;
+ else size += z;
+
+ return size;
+}
+
+#if __STD_C
+static Void_t* tstat(Dt_t* dt, Dtstat_t* st)
+#else
+static Void_t* tstat(dt, st)
+Dt_t* dt;
+Dtstat_t* st;
+#endif
+{
+ ssize_t size;
+ Dttree_t *tree = (Dttree_t*)dt->data;
+
+ if(!st)
+ return (Void_t*)dt->data->size;
+ else
+ { memset(st, 0, sizeof(Dtstat_t));
+ size = tsize(tree->root, 0, st);
+ /**/DEBUG_ASSERT((dt->data->type&DT_SHARE) || size == dt->data->size);
+ st->meth = dt->meth->type;
+ st->size = size;
+ st->space = sizeof(Dttree_t) + (dt->disc->link >= 0 ? 0 : size*sizeof(Dthold_t));
+ return (Void_t*)size;
+ }
+}
+
+#if __STD_C /* make a list into a balanced tree */
+static Dtlink_t* tbalance(Dtlink_t* list, ssize_t size)
+#else
+static Dtlink_t* tbalance(list, size)
+Dtlink_t* list;
+ssize_t size;
+#endif
+{
+ ssize_t n;
+ Dtlink_t *l, *mid;
+
+ if(size <= 2)
+ return list;
+
+ for(l = list, n = size/2 - 1; n > 0; n -= 1)
+ l = l->_rght;
+
+ mid = l->_rght; l->_rght = NIL(Dtlink_t*);
+ mid->_left = tbalance(list, (n = size/2) );
+ mid->_rght = tbalance(mid->_rght, size - (n + 1));
+ return mid;
+}
+
+static void toptimize(Dt_t* dt)
+{
+ ssize_t size;
+ Dtlink_t *l, *list;
+ Dttree_t *tree = (Dttree_t*)dt->data;
+
+ if((list = (Dtlink_t*)tlist(dt, NIL(Void_t*), DT_FLATTEN)) )
+ { for(size = 0, l = list; l; l = l->_rght)
+ size += 1;
+ tree->root = tbalance(list, size);
+ }
+}
+
+static Dtlink_t* troot(Dt_t* dt, Dtlink_t* list, Dtlink_t* link, Void_t* obj, int type)
+{
+ Dtlink_t *root, *last, *t, *r, *l;
+ Void_t *key, *o, *k;
+ Dtdisc_t *disc = dt->disc;
+
+ key = _DTKEY(disc, obj); /* key of object */
+
+ if(type&(DT_ATMOST|DT_ATLEAST) ) /* find the left-most or right-most element */
+ { list->_left = link->_rght;
+ list->_rght = link->_left;
+ if(type&DT_ATMOST)
+ { while((l = list->_left) )
+ { while((r = l->_rght) ) /* get the max elt of left subtree */
+ LROTATE(l,r);
+ list->_left = l;
+
+ o = _DTOBJ(disc,l); k = _DTKEY(disc,o);
+ if(_DTCMP(dt, key, k, disc) != 0 )
+ break;
+ else RROTATE(list,l);
+ }
+ }
+ else
+ { while((r = list->_rght) )
+ { while((l = r->_left) ) /* get the min elt of right subtree */
+ RROTATE(r,l);
+ list->_rght = r;
+
+ o = _DTOBJ(disc,r); k = _DTKEY(disc,o);
+ if(_DTCMP(dt, key, k, disc) != 0 )
+ break;
+ else LROTATE(list,r);
+ }
+ }
+ link->_rght = list->_left;
+ link->_left = list->_rght;
+ return list;
+ }
+
+ last = list; list->_left = list->_rght = NIL(Dtlink_t*);
+ root = NIL(Dtlink_t*);
+
+ while(!root && (t = link->_rght) ) /* link->_rght is the left subtree <= obj */
+ { while((r = t->_rght) ) /* make t the maximum element */
+ LROTATE(t,r);
+
+ o = _DTOBJ(disc,t); k = _DTKEY(disc,o);
+ if(_DTCMP(dt, key, k, disc) != 0 )
+ { link->_rght = t; /* no more of this group in subtree */
+ break;
+ }
+ else if((type & (DT_REMOVE|DT_NEXT|DT_PREV)) && o == obj)
+ { link->_rght = t->_left; /* found the exact object */
+ root = t;
+ }
+ else /* add t to equal list in an order-preserving manner */
+ { link->_rght = t->_left;
+ t->_left = t->_rght = NIL(Dtlink_t*);
+ if(type&DT_NEXT )
+ { last->_left = t; last = t; }
+ else { t->_rght = list; list = t; }
+ }
+ }
+
+ while(!root && (t = link->_left) ) /* link->_left is the right subtree >= obj */
+ { while((l = t->_left) ) /* make t the minimum element */
+ RROTATE(t,l);
+
+ o = _DTOBJ(disc,t); k = _DTKEY(disc,o);
+ if(_DTCMP(dt, key, k, disc) != 0 )
+ { link->_left = t; /* no more of this group in subtree */
+ break;
+ }
+ else if((type & (DT_REMOVE|DT_NEXT|DT_PREV)) && o == obj)
+ { link->_left = t->_rght; /* found the exact object */
+ root = t;
+ }
+ else /* add t to equal list in an order-preserving manner */
+ { link->_left = t->_rght;
+ t->_left = t->_rght = NIL(Dtlink_t*);
+ if(type&DT_NEXT )
+ { t->_left = list; list = t; }
+ else { last->_rght = t; last = t; }
+ }
+ }
+
+ if(!root) /* always set a non-trivial root */
+ { root = list;
+ if(type&DT_NEXT)
+ list = list->_left;
+ else list = list->_rght;
+ }
+
+ if(list) /* add the rest of the equal-list to the proper subtree */
+ { if(type&DT_NEXT)
+ { last->_left = link->_rght;
+ link->_rght = list;
+ }
+ else
+ { last->_rght = link->_left;
+ link->_left = list;
+ }
+ }
+
+ return root;
+}
+
+#if __STD_C
+static Void_t* dttree(Dt_t* dt, Void_t* obj, int type)
+#else
+static Void_t* dttree(dt,obj,type)
+Dt_t* dt;
+Void_t* obj;
+int type;
+#endif
+{
+ int cmp;
+ Void_t *o, *k, *key;
+ Dtlink_t *root, *t, *l, *r, *me, link;
+ Dtdisc_t *disc = dt->disc;
+ Dttree_t *tree = (Dttree_t*)dt->data;
+
+ type = DTTYPE(dt, type); /* map type for upward compatibility */
+ if(!(type&DT_OPERATIONS) )
+ return NIL(Void_t*);
+
+ DTSETLOCK(dt);
+
+ if(type&(DT_FIRST|DT_LAST) )
+ DTRETURN(obj, tfirstlast(dt, type));
+ else if(type&(DT_EXTRACT|DT_RESTORE|DT_FLATTEN))
+ DTRETURN(obj, tlist(dt, (Dtlink_t*)obj, type));
+ else if(type&DT_CLEAR)
+ DTRETURN(obj, tclear(dt));
+ else if(type&DT_STAT)
+ { toptimize(dt); /* balance tree to avoid deep recursion */
+ DTRETURN(obj, tstat(dt, (Dtstat_t*)obj));
+ }
+
+ if(!obj) /* from here on, an object prototype is required */
+ DTRETURN(obj, NIL(Void_t*));
+
+ if(type&DT_RELINK) /* relinking objects after some processing */
+ { me = (Dtlink_t*)obj;
+ obj = _DTOBJ(disc,me);
+ key = _DTKEY(disc,obj);
+ }
+ else
+ { me = NIL(Dtlink_t*);
+ if(type&DT_MATCH) /* no prototype object given, just the key */
+ { key = obj;
+ obj = NIL(Void_t*);
+ }
+ else key = _DTKEY(disc,obj); /* get key from prototype object */
+ }
+
+ memset(&link, 0, sizeof(link));
+ l = r = &link; /* link._rght(_left) will be LEFT(RIGHT) tree after splaying */
+ if((root = tree->root) && _DTOBJ(disc,root) != obj) /* splay-search for a matching object */
+ { while(1)
+ { o = _DTOBJ(disc,root); k = _DTKEY(disc,o);
+ if((cmp = _DTCMP(dt,key,k,disc)) == 0)
+ break;
+ else if(cmp < 0)
+ { if((t = root->_left) )
+ { o = _DTOBJ(disc,t); k = _DTKEY(disc,o);
+ if((cmp = _DTCMP(dt,key,k,disc)) < 0)
+ { rrotate(root,t);
+ rlink(r,t);
+ if(!(root = t->_left) )
+ break;
+ }
+ else if(cmp == 0)
+ { rlink(r,root);
+ root = t;
+ break;
+ }
+ else /* if(cmp > 0) */
+ { llink(l,t);
+ rlink(r,root);
+ if(!(root = t->_rght) )
+ break;
+ }
+ }
+ else
+ { rlink(r,root);
+ root = NIL(Dtlink_t*);
+ break;
+ }
+ }
+ else /* if(cmp > 0) */
+ { if((t = root->_rght) )
+ { o = _DTOBJ(disc,t); k = _DTKEY(disc,o);
+ if((cmp = _DTCMP(dt,key,k,disc)) > 0)
+ { lrotate(root,t);
+ llink(l,t);
+ if(!(root = t->_rght) )
+ break;
+ }
+ else if(cmp == 0)
+ { llink(l,root);
+ root = t;
+ break;
+ }
+ else /* if(cmp < 0) */
+ { rlink(r,t);
+ llink(l,root);
+ if(!(root = t->_left) )
+ break;
+ }
+ }
+ else
+ { llink(l,root);
+ root = NIL(Dtlink_t*);
+ break;
+ }
+ }
+ }
+ }
+ l->_rght = root ? root->_left : NIL(Dtlink_t*);
+ r->_left = root ? root->_rght : NIL(Dtlink_t*);
+
+ if(root)
+ { if(dt->meth->type&DT_OBAG ) /* may need to reset root to the right object */
+ { if((type&(DT_ATLEAST|DT_ATMOST)) ||
+ ((type&(DT_NEXT|DT_PREV|DT_REMOVE)) && _DTOBJ(disc,root) != obj) )
+ root = troot(dt, root, &link, obj, type);
+ }
+
+ if(type&(DT_SEARCH|DT_MATCH|DT_ATMOST|DT_ATLEAST))
+ { has_root: /* reconstitute the tree */
+ root->_left = link._rght;
+ root->_rght = link._left;
+ tree->root = root;
+ DTRETURN(obj, _DTOBJ(disc,root));
+ }
+ else if(type&DT_NEXT)
+ { root->_left = link._rght;
+ root->_rght = NIL(Dtlink_t*);
+ link._rght = root;
+ dt_next:
+ if((root = link._left) )
+ { while((t = root->_left) )
+ RROTATE(root,t);
+ link._left = root->_rght;
+ goto has_root;
+ }
+ else goto no_root;
+ }
+ else if(type&DT_PREV)
+ { root->_rght = link._left;
+ root->_left = NIL(Dtlink_t*);
+ link._left = root;
+ dt_prev:
+ if((root = link._rght) )
+ { while((t = root->_rght) )
+ LROTATE(root,t);
+ link._rght = root->_left;
+ goto has_root;
+ }
+ else goto no_root;
+ }
+ else if(type&DT_REMOVE) /* remove a particular element in the tree */
+ { if(_DTOBJ(disc,root) == obj)
+ goto dt_delete;
+ else
+ { root->_left = link._rght;
+ root->_rght = link._left;
+ tree->root = root;
+ DTRETURN(obj, NIL(Void_t*));
+ }
+ }
+ else if(type&(DT_DELETE|DT_DETACH))
+ { dt_delete: /* remove an object from the dictionary */
+ obj = _DTOBJ(disc,root);
+ _dtfree(dt, root, type);
+ dt->data->size -= 1;
+ goto no_root;
+ }
+ else if(type&(DT_INSERT|DT_APPEND|DT_ATTACH))
+ { if(dt->meth->type&DT_OSET)
+ { type |= DT_SEARCH; /* for announcement */
+ goto has_root;
+ }
+ else
+ { root->_left = NIL(Dtlink_t*);
+ root->_rght = link._left;
+ link._left = root;
+ goto dt_insert;
+ }
+ }
+ else if(type&DT_RELINK) /* a duplicate */
+ { if(dt->meth->type&DT_OSET)
+ _dtfree(dt, me, DT_DELETE);
+ else
+ { me->_left = NIL(Dtlink_t*);
+ me->_rght = link._left;
+ link._left = me;
+ }
+ goto has_root;
+ }
+ }
+ else /* no matching object, tree has been split to LEFT&RIGHT subtrees */
+ { if(type&(DT_SEARCH|DT_MATCH))
+ { no_root:
+ if(!(l = link._rght) ) /* no LEFT subtree */
+ tree->root = link._left; /* tree is RIGHT tree */
+ else
+ { while((t = l->_rght) ) /* maximize root of LEFT tree */
+ { if(t->_rght)
+ LLSHIFT(l,t);
+ else LROTATE(l,t);
+ }
+ l->_rght = link._left; /* hook RIGHT tree to LEFT root */
+ tree->root = l; /* LEFT tree is now the entire tree */
+ }
+
+ if(type&(DT_DELETE|DT_DETACH|DT_REMOVE))
+ DTRETURN(obj, obj);
+ else DTRETURN(obj, NIL(Void_t*));
+ }
+ else if(type&(DT_NEXT|DT_ATLEAST) )
+ goto dt_next;
+ else if(type&(DT_PREV|DT_ATMOST) )
+ goto dt_prev;
+ else if(type&(DT_DELETE|DT_DETACH|DT_REMOVE))
+ { obj = NIL(Void_t*);
+ goto no_root;
+ }
+ else if(type&(DT_INSERT|DT_APPEND|DT_ATTACH))
+ { dt_insert:
+ if(!(root = _dtmake(dt, obj, type)) )
+ { obj = NIL(Void_t*);
+ goto no_root;
+ }
+ else
+ { dt->data->size += 1;
+ goto has_root;
+ }
+ }
+ else if(type&DT_RELINK)
+ { root = me;
+ goto has_root;
+ }
+ }
+ DTRETURN(obj, NIL(Void_t*));
+
+dt_return:
+ DTANNOUNCE(dt,obj,type);
+ DTCLRLOCK(dt);
+ return obj;
+}
+
+static int treeevent(Dt_t* dt, int event, Void_t* arg)
+{
+ Dtlink_t *l, *list;
+ ssize_t size;
+ Dttree_t *tree = (Dttree_t*)dt->data;
+
+ if(event == DT_OPEN)
+ { if(tree) /* already initialized */
+ return 0;
+ if(!(tree = (Dttree_t*)(*dt->memoryf)(dt, 0, sizeof(Dttree_t), dt->disc)) )
+ { DTERROR(dt, "Error in allocating a tree data structure");
+ return -1;
+ }
+ memset(tree, 0, sizeof(Dttree_t));
+ dt->data = (Dtdata_t*)tree;
+ return 1;
+ }
+ else if(event == DT_CLOSE)
+ { if(!tree)
+ return 0;
+ if(tree->root)
+ (void)tclear(dt);
+ (void)(*dt->memoryf)(dt, (Void_t*)tree, 0, dt->disc);
+ dt->data = NIL(Dtdata_t*);
+ return 0;
+ }
+ else if(event == DT_OPTIMIZE) /* balance the search tree */
+ { toptimize(dt);
+ return 0;
+ }
+ else return 0;
+}
+
+#if _UWIN
+
+Void_t* dtfinger(Dt_t* dt)
+{
+ return (dt && dt->meth && (dt->meth->type & DT_ORDERED)) ? (Void_t*)((Dttree_t*)dt->data)->root : NIL(Void_t*);
+}
+
+#endif
+
+/* make this method available */
+static Dtmethod_t _Dtoset = { dttree, DT_OSET, treeevent, "Dtoset" };
+static Dtmethod_t _Dtobag = { dttree, DT_OBAG, treeevent, "Dtobag" };
+__DEFINE__(Dtmethod_t*,Dtoset,&_Dtoset);
+__DEFINE__(Dtmethod_t*,Dtobag,&_Dtobag);
+
+/* backwards compatibility */
+#undef Dttree
+#if defined(__EXPORT__)
+__EXPORT__
+#endif
+__DEFINE__(Dtmethod_t*,Dttree,&_Dtoset);
+
+#ifdef NoF
+NoF(dttree)
+#endif