From: Peter Johnson Date: Sun, 11 Jun 2006 22:03:50 +0000 (-0000) Subject: Actually bring interval tree implementation into repo. X-Git-Tag: v0.6.0~172^2~20 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=71cdd65edc2a5489a0f0410fbf0ef8cb0db10ffc;p=yasm Actually bring interval tree implementation into repo. svn path=/branches/new-optimizer/; revision=1571 --- diff --git a/Mkfiles/Makefile.dj b/Mkfiles/Makefile.dj index d022b56d..30579cbb 100644 --- a/Mkfiles/Makefile.dj +++ b/Mkfiles/Makefile.dj @@ -32,6 +32,7 @@ LIBYASM_OBJS= \ libyasm/floatnum.o \ libyasm/hamt.o \ libyasm/intnum.o \ + libyasm/inttree.o \ libyasm/linemgr.o \ libyasm/md5.o \ libyasm/mergesort.o \ diff --git a/Mkfiles/Makefile.flat b/Mkfiles/Makefile.flat index 0724f3de..66273855 100644 --- a/Mkfiles/Makefile.flat +++ b/Mkfiles/Makefile.flat @@ -35,6 +35,7 @@ LIBYASM_OBJS= \ libyasm/floatnum.o \ libyasm/hamt.o \ libyasm/intnum.o \ + libyasm/inttree.o \ libyasm/linemgr.o \ libyasm/md5.o \ libyasm/mergesort.o \ diff --git a/Mkfiles/vc/libyasm/libyasm.vcproj b/Mkfiles/vc/libyasm/libyasm.vcproj index bf8aba8b..9c899369 100644 --- a/Mkfiles/vc/libyasm/libyasm.vcproj +++ b/Mkfiles/vc/libyasm/libyasm.vcproj @@ -168,6 +168,9 @@ + + @@ -259,6 +262,9 @@ + + diff --git a/Mkfiles/vc8/libyasm/libyasm.vcproj b/Mkfiles/vc8/libyasm/libyasm.vcproj index adf19d04..8c47c7c1 100644 --- a/Mkfiles/vc8/libyasm/libyasm.vcproj +++ b/Mkfiles/vc8/libyasm/libyasm.vcproj @@ -389,6 +389,10 @@ RelativePath="..\..\..\libyasm\intnum.c" > + + @@ -506,6 +510,10 @@ RelativePath="..\..\..\libyasm\intnum.h" > + + diff --git a/libyasm/Makefile.inc b/libyasm/Makefile.inc index c5b7c766..8d0384bb 100644 --- a/libyasm/Makefile.inc +++ b/libyasm/Makefile.inc @@ -16,6 +16,7 @@ libyasm_a_SOURCES += libyasm/file.c libyasm_a_SOURCES += libyasm/floatnum.c libyasm_a_SOURCES += libyasm/hamt.c libyasm_a_SOURCES += libyasm/intnum.c +libyasm_a_SOURCES += libyasm/inttree.c libyasm_a_SOURCES += libyasm/linemgr.c libyasm_a_SOURCES += libyasm/md5.c libyasm_a_SOURCES += libyasm/mergesort.c @@ -28,8 +29,6 @@ libyasm_a_SOURCES += libyasm/valparam.c libyasm_a_SOURCES += libyasm/value.c libyasm_a_SOURCES += libyasm/xmalloc.c libyasm_a_SOURCES += libyasm/xstrdup.c -libyasm_a_SOURCES += libyasm/stack.c -libyasm_a_SOURCES += libyasm/interval_tree.c libyasm_a_SOURCES += module.c module.c: $(top_srcdir)/libyasm/module.in genmodule$(EXEEXT) Makefile @@ -67,6 +66,7 @@ modinclude_HEADERS += libyasm/file.h modinclude_HEADERS += libyasm/floatnum.h modinclude_HEADERS += libyasm/hamt.h modinclude_HEADERS += libyasm/intnum.h +modinclude_HEADERS += libyasm/inttree.h modinclude_HEADERS += libyasm/linemgr.h modinclude_HEADERS += libyasm/listfmt.h modinclude_HEADERS += libyasm/md5.h @@ -79,8 +79,6 @@ modinclude_HEADERS += libyasm/section.h modinclude_HEADERS += libyasm/symrec.h modinclude_HEADERS += libyasm/valparam.h modinclude_HEADERS += libyasm/value.h -modinclude_HEADERS += libyasm/stack.h -modinclude_HEADERS += libyasm/interval_tree.h EXTRA_DIST += libyasm/tests/Makefile.inc diff --git a/libyasm/inttree.c b/libyasm/inttree.c new file mode 100644 index 00000000..d6816afd --- /dev/null +++ b/libyasm/inttree.c @@ -0,0 +1,884 @@ +#define YASM_LIB_INTERNAL +#include "util.h" +/*@unused@*/ RCSID("$Id$"); + +#include +#include +#include +#include +#include "coretype.h" +#include "inttree.h" + +#define VERIFY(condition) \ +if (!(condition)) { \ +fprintf(stderr, "Assumption \"%s\"\nFailed in file %s: at line:%i\n", \ +#condition,__FILE__,__LINE__); \ +abort();} + +/*#define DEBUG_ASSERT 1*/ + +#ifdef DEBUG_ASSERT +static void Assert(int assertion, const char *error) +{ + if (!assertion) { + fprintf(stderr, "Assertion Failed: %s\n", error); + abort(); + } +} +#endif + +/* If the symbol CHECK_INTERVAL_TREE_ASSUMPTIONS is defined then the + * code does a lot of extra checking to make sure certain assumptions + * are satisfied. This only needs to be done if you suspect bugs are + * present or if you make significant changes and want to make sure + * your changes didn't mess anything up. + */ +/*#define CHECK_INTERVAL_TREE_ASSUMPTIONS 1*/ + +static IntervalTreeNode *ITN_create(long low, long high, void *data); +static void ITN_Print(const IntervalTreeNode *itn, IntervalTreeNode *nil, + IntervalTreeNode *root); + +static void LeftRotate(IntervalTree *, IntervalTreeNode *); +static void RightRotate(IntervalTree *, IntervalTreeNode *); +static void TreeInsertHelp(IntervalTree *, IntervalTreeNode *); +static void TreePrintHelper(const IntervalTree *, IntervalTreeNode *); +static void FixUpMaxHigh(IntervalTree *, IntervalTreeNode *); +static void DeleteFixUp(IntervalTree *, IntervalTreeNode *); +static void CheckMaxHighFields(const IntervalTree *, IntervalTreeNode *); +static int CheckMaxHighFieldsHelper(const IntervalTree *, IntervalTreeNode *y, + const int currentHigh, int match); +static void IT_CheckAssumptions(const IntervalTree *); + +/* define a function to find the maximum of two objects. */ +#define ITMax(a, b) ( (a > b) ? a : b ) + +IntervalTreeNode * +ITN_create(long low, long high, void *data) +{ + IntervalTreeNode *itn = yasm_xmalloc(sizeof(IntervalTreeNode)); + itn->data = data; + itn->low = low; + itn->high = high; + itn->maxHigh = high; + return itn; +} + +IntervalTree * +IT_create(void) +{ + IntervalTree *it = yasm_xmalloc(sizeof(IntervalTree)); + + it->nil = ITN_create(LONG_MIN, LONG_MIN, NULL); + it->nil->left = it->nil; + it->nil->right = it->nil; + it->nil->parent = it->nil; + it->nil->red = 0; + + it->root = ITN_create(LONG_MAX, LONG_MAX, NULL); + it->root->left = it->nil; + it->root->right = it->nil; + it->root->parent = it->nil; + it->root->red = 0; + + /* the following are used for the Enumerate function */ + it->recursionNodeStackSize = 128; + it->recursionNodeStack = (it_recursion_node *) + yasm_xmalloc(it->recursionNodeStackSize*sizeof(it_recursion_node)); + it->recursionNodeStackTop = 1; + it->recursionNodeStack[0].start_node = NULL; + + return it; +} + +/***********************************************************************/ +/* FUNCTION: LeftRotate */ +/**/ +/* INPUTS: the node to rotate on */ +/**/ +/* OUTPUT: None */ +/**/ +/* Modifies Input: this, x */ +/**/ +/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ +/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ +/* makes the parent of x be to the left of x, x the parent of */ +/* its parent before the rotation and fixes other pointers */ +/* accordingly. Also updates the maxHigh fields of x and y */ +/* after rotation. */ +/***********************************************************************/ + +static void +LeftRotate(IntervalTree *it, IntervalTreeNode *x) +{ + IntervalTreeNode *y; + + /* I originally wrote this function to use the sentinel for + * nil to avoid checking for nil. However this introduces a + * very subtle bug because sometimes this function modifies + * the parent pointer of nil. This can be a problem if a + * function which calls LeftRotate also uses the nil sentinel + * and expects the nil sentinel's parent pointer to be unchanged + * after calling this function. For example, when DeleteFixUP + * calls LeftRotate it expects the parent pointer of nil to be + * unchanged. + */ + + y=x->right; + x->right=y->left; + + if (y->left != it->nil) + y->left->parent=x; /* used to use sentinel here */ + /* and do an unconditional assignment instead of testing for nil */ + + y->parent=x->parent; + + /* Instead of checking if x->parent is the root as in the book, we + * count on the root sentinel to implicitly take care of this case + */ + if (x == x->parent->left) + x->parent->left=y; + else + x->parent->right=y; + y->left=x; + x->parent=y; + + x->maxHigh=ITMax(x->left->maxHigh,ITMax(x->right->maxHigh,x->high)); + y->maxHigh=ITMax(x->maxHigh,ITMax(y->right->maxHigh,y->high)); +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not red in ITLeftRotate"); + Assert((it->nil->maxHigh=LONG_MIN), + "nil->maxHigh != LONG_MIN in ITLeftRotate"); +#endif +} + + +/***********************************************************************/ +/* FUNCTION: RightRotate */ +/**/ +/* INPUTS: node to rotate on */ +/**/ +/* OUTPUT: None */ +/**/ +/* Modifies Input?: this, y */ +/**/ +/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ +/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ +/* makes the parent of x be to the left of x, x the parent of */ +/* its parent before the rotation and fixes other pointers */ +/* accordingly. Also updates the maxHigh fields of x and y */ +/* after rotation. */ +/***********************************************************************/ + + +static void +RightRotate(IntervalTree *it, IntervalTreeNode *y) +{ + IntervalTreeNode *x; + + /* I originally wrote this function to use the sentinel for + * nil to avoid checking for nil. However this introduces a + * very subtle bug because sometimes this function modifies + * the parent pointer of nil. This can be a problem if a + * function which calls LeftRotate also uses the nil sentinel + * and expects the nil sentinel's parent pointer to be unchanged + * after calling this function. For example, when DeleteFixUP + * calls LeftRotate it expects the parent pointer of nil to be + * unchanged. + */ + + x=y->left; + y->left=x->right; + + if (it->nil != x->right) + x->right->parent=y; /*used to use sentinel here */ + /* and do an unconditional assignment instead of testing for nil */ + + /* Instead of checking if x->parent is the root as in the book, we + * count on the root sentinel to implicitly take care of this case + */ + x->parent=y->parent; + if (y == y->parent->left) + y->parent->left=x; + else + y->parent->right=x; + x->right=y; + y->parent=x; + + y->maxHigh=ITMax(y->left->maxHigh,ITMax(y->right->maxHigh,y->high)); + x->maxHigh=ITMax(x->left->maxHigh,ITMax(y->maxHigh,x->high)); +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not red in ITRightRotate"); + Assert((it->nil->maxHigh=LONG_MIN), + "nil->maxHigh != LONG_MIN in ITRightRotate"); +#endif +} + +/***********************************************************************/ +/* FUNCTION: TreeInsertHelp */ +/**/ +/* INPUTS: z is the node to insert */ +/**/ +/* OUTPUT: none */ +/**/ +/* Modifies Input: this, z */ +/**/ +/* EFFECTS: Inserts z into the tree as if it were a regular binary tree */ +/* using the algorithm described in _Introduction_To_Algorithms_ */ +/* by Cormen et al. This funciton is only intended to be called */ +/* by the InsertTree function and not by the user */ +/***********************************************************************/ + +static void +TreeInsertHelp(IntervalTree *it, IntervalTreeNode *z) +{ + /* This function should only be called by InsertITTree (see above) */ + IntervalTreeNode* x; + IntervalTreeNode* y; + + z->left=z->right=it->nil; + y=it->root; + x=it->root->left; + while( x != it->nil) { + y=x; + if (x->low > z->low) + x=x->left; + else /* x->low <= z->low */ + x=x->right; + } + z->parent=y; + if ((y == it->root) || (y->low > z->low)) + y->left=z; + else + y->right=z; + +#if defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not red in ITTreeInsertHelp"); + Assert((it->nil->maxHigh=INT_MIN), + "nil->maxHigh != INT_MIN in ITTreeInsertHelp"); +#endif +} + + +/***********************************************************************/ +/* FUNCTION: FixUpMaxHigh */ +/**/ +/* INPUTS: x is the node to start from*/ +/**/ +/* OUTPUT: none */ +/**/ +/* Modifies Input: this */ +/**/ +/* EFFECTS: Travels up to the root fixing the maxHigh fields after */ +/* an insertion or deletion */ +/***********************************************************************/ + +static void +FixUpMaxHigh(IntervalTree *it, IntervalTreeNode *x) +{ + while(x != it->root) { + x->maxHigh=ITMax(x->high,ITMax(x->left->maxHigh,x->right->maxHigh)); + x=x->parent; + } +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#endif +} + +/* Before calling InsertNode the node x should have its key set */ + +/***********************************************************************/ +/* FUNCTION: InsertNode */ +/**/ +/* INPUTS: newInterval is the interval to insert*/ +/**/ +/* OUTPUT: This function returns a pointer to the newly inserted node */ +/* which is guarunteed to be valid until this node is deleted. */ +/* What this means is if another data structure stores this */ +/* pointer then the tree does not need to be searched when this */ +/* is to be deleted. */ +/**/ +/* Modifies Input: tree */ +/**/ +/* EFFECTS: Creates a node node which contains the appropriate key and */ +/* info pointers and inserts it into the tree. */ +/***********************************************************************/ + +IntervalTreeNode * +IT_insert(IntervalTree *it, long low, long high, void *data) +{ + IntervalTreeNode *x, *y, *newNode; + + x = ITN_create(low, high, data); + TreeInsertHelp(it, x); + FixUpMaxHigh(it, x->parent); + newNode = x; + x->red=1; + while(x->parent->red) { /* use sentinel instead of checking for root */ + if (x->parent == x->parent->parent->left) { + y=x->parent->parent->right; + if (y->red) { + x->parent->red=0; + y->red=0; + x->parent->parent->red=1; + x=x->parent->parent; + } else { + if (x == x->parent->right) { + x=x->parent; + LeftRotate(it, x); + } + x->parent->red=0; + x->parent->parent->red=1; + RightRotate(it, x->parent->parent); + } + } else { /* case for x->parent == x->parent->parent->right */ + /* this part is just like the section above with */ + /* left and right interchanged */ + y=x->parent->parent->left; + if (y->red) { + x->parent->red=0; + y->red=0; + x->parent->parent->red=1; + x=x->parent->parent; + } else { + if (x == x->parent->left) { + x=x->parent; + RightRotate(it, x); + } + x->parent->red=0; + x->parent->parent->red=1; + LeftRotate(it, x->parent->parent); + } + } + } + it->root->left->red=0; + +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not red in ITTreeInsert"); + Assert(!it->root->red,"root not red in ITTreeInsert"); + Assert((it->nil->maxHigh=LONG_MIN), + "nil->maxHigh != LONG_MIN in ITTreeInsert"); +#endif + return newNode; +} + +/***********************************************************************/ +/* FUNCTION: GetSuccessorOf */ +/**/ +/* INPUTS: x is the node we want the succesor of */ +/**/ +/* OUTPUT: This function returns the successor of x or NULL if no */ +/* successor exists. */ +/**/ +/* Modifies Input: none */ +/**/ +/* Note: uses the algorithm in _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +IntervalTreeNode * +IT_get_successor(const IntervalTree *it, IntervalTreeNode *x) +{ + IntervalTreeNode *y; + + if (it->nil != (y = x->right)) { /* assignment to y is intentional */ + while(y->left != it->nil) /* returns the minium of the right subtree of x */ + y=y->left; + return y; + } else { + y=x->parent; + while(x == y->right) { /* sentinel used instead of checking for nil */ + x=y; + y=y->parent; + } + if (y == it->root) + return(it->nil); + return y; + } +} + +/***********************************************************************/ +/* FUNCTION: GetPredecessorOf */ +/**/ +/* INPUTS: x is the node to get predecessor of */ +/**/ +/* OUTPUT: This function returns the predecessor of x or NULL if no */ +/* predecessor exists. */ +/**/ +/* Modifies Input: none */ +/**/ +/* Note: uses the algorithm in _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +IntervalTreeNode * +IT_get_predecessor(const IntervalTree *it, IntervalTreeNode *x) +{ + IntervalTreeNode *y; + + if (it->nil != (y = x->left)) { /* assignment to y is intentional */ + while(y->right != it->nil) /* returns the maximum of the left subtree of x */ + y=y->right; + return y; + } else { + y=x->parent; + while(x == y->left) { + if (y == it->root) + return(it->nil); + x=y; + y=y->parent; + } + return y; + } +} + +/***********************************************************************/ +/* FUNCTION: Print */ +/**/ +/* INPUTS: none */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECTS: This function recursively prints the nodes of the tree */ +/* inorder. */ +/**/ +/* Modifies Input: none */ +/**/ +/* Note: This function should only be called from ITTreePrint */ +/***********************************************************************/ + +static void +ITN_print(const IntervalTreeNode *itn, IntervalTreeNode *nil, + IntervalTreeNode *root) +{ + printf(", l=%li, h=%li, mH=%li", itn->low, itn->high, itn->maxHigh); + printf(" l->low="); + if (itn->left == nil) + printf("NULL"); + else + printf("%li", itn->left->low); + printf(" r->low="); + if (itn->right == nil) + printf("NULL"); + else + printf("%li", itn->right->low); + printf(" p->low="); + if (itn->parent == root) + printf("NULL"); + else + printf("%li", itn->parent->low); + printf(" red=%i\n", itn->red); +} + +static void +TreePrintHelper(const IntervalTree *it, IntervalTreeNode *x) +{ + if (x != it->nil) { + TreePrintHelper(it, x->left); + ITN_print(x, it->nil, it->root); + TreePrintHelper(it, x->right); + } +} + +void +IT_destroy(IntervalTree *it) +{ + IntervalTreeNode *x = it->root->left; + SLIST_HEAD(, nodeent) stuffToFree = SLIST_HEAD_INITIALIZER(stuffToFree); + struct nodeent { + SLIST_ENTRY(nodeent) link; + struct IntervalTreeNode *node; + } *np; + + if (x != it->nil) { + if (x->left != it->nil) { + np = yasm_xmalloc(sizeof(struct nodeent)); + np->node = x->left; + SLIST_INSERT_HEAD(&stuffToFree, np, link); + } + if (x->right != it->nil) { + np = yasm_xmalloc(sizeof(struct nodeent)); + np->node = x->right; + SLIST_INSERT_HEAD(&stuffToFree, np, link); + } + yasm_xfree(x); + while (!SLIST_EMPTY(&stuffToFree)) { + np = SLIST_FIRST(&stuffToFree); + x = np->node; + SLIST_REMOVE_HEAD(&stuffToFree, link); + yasm_xfree(np); + + if (x->left != it->nil) { + np = yasm_xmalloc(sizeof(struct nodeent)); + np->node = x->left; + SLIST_INSERT_HEAD(&stuffToFree, np, link); + } + if (x->right != it->nil) { + np = yasm_xmalloc(sizeof(struct nodeent)); + np->node = x->right; + SLIST_INSERT_HEAD(&stuffToFree, np, link); + } + yasm_xfree(x); + } + } + + yasm_xfree(it->nil); + yasm_xfree(it->root); + yasm_xfree(it->recursionNodeStack); + yasm_xfree(it); +} + + +/***********************************************************************/ +/* FUNCTION: Print */ +/**/ +/* INPUTS: none */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECT: This function recursively prints the nodes of the tree */ +/* inorder. */ +/**/ +/* Modifies Input: none */ +/**/ +/***********************************************************************/ + +void +IT_print(const IntervalTree *it) +{ + TreePrintHelper(it, it->root->left); +} + +/***********************************************************************/ +/* FUNCTION: DeleteFixUp */ +/**/ +/* INPUTS: x is the child of the spliced */ +/* out node in DeleteNode. */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECT: Performs rotations and changes colors to restore red-black */ +/* properties after a node is deleted */ +/**/ +/* Modifies Input: this, x */ +/**/ +/* The algorithm from this function is from _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +static void +DeleteFixUp(IntervalTree *it, IntervalTreeNode *x) +{ + IntervalTreeNode *w; + IntervalTreeNode *rootLeft = it->root->left; + + while ((!x->red) && (rootLeft != x)) { + if (x == x->parent->left) { + w=x->parent->right; + if (w->red) { + w->red=0; + x->parent->red=1; + LeftRotate(it, x->parent); + w=x->parent->right; + } + if ( (!w->right->red) && (!w->left->red) ) { + w->red=1; + x=x->parent; + } else { + if (!w->right->red) { + w->left->red=0; + w->red=1; + RightRotate(it, w); + w=x->parent->right; + } + w->red=x->parent->red; + x->parent->red=0; + w->right->red=0; + LeftRotate(it, x->parent); + x=rootLeft; /* this is to exit while loop */ + } + } else { /* the code below is has left and right switched from above */ + w=x->parent->left; + if (w->red) { + w->red=0; + x->parent->red=1; + RightRotate(it, x->parent); + w=x->parent->left; + } + if ((!w->right->red) && (!w->left->red)) { + w->red=1; + x=x->parent; + } else { + if (!w->left->red) { + w->right->red=0; + w->red=1; + LeftRotate(it, w); + w=x->parent->left; + } + w->red=x->parent->red; + x->parent->red=0; + w->left->red=0; + RightRotate(it, x->parent); + x=rootLeft; /* this is to exit while loop */ + } + } + } + x->red=0; + +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not black in ITDeleteFixUp"); + Assert((it->nil->maxHigh=LONG_MIN), + "nil->maxHigh != LONG_MIN in ITDeleteFixUp"); +#endif +} + + +/***********************************************************************/ +/* FUNCTION: DeleteNode */ +/**/ +/* INPUTS: tree is the tree to delete node z from */ +/**/ +/* OUTPUT: returns the Interval stored at deleted node */ +/**/ +/* EFFECT: Deletes z from tree and but don't call destructor */ +/* Then calls FixUpMaxHigh to fix maxHigh fields then calls */ +/* ITDeleteFixUp to restore red-black properties */ +/**/ +/* Modifies Input: z */ +/**/ +/* The algorithm from this function is from _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +void * +IT_delete_node(IntervalTree *it, IntervalTreeNode *z, long *low, long *high) +{ + IntervalTreeNode *x, *y; + void *returnValue = z->data; + if (low) + *low = z->low; + if (high) + *high = z->high; + + y= ((z->left == it->nil) || (z->right == it->nil)) ? + z : IT_get_successor(it, z); + x= (y->left == it->nil) ? y->right : y->left; + if (it->root == (x->parent = y->parent)) + /* assignment of y->p to x->p is intentional */ + it->root->left=x; + else { + if (y == y->parent->left) + y->parent->left=x; + else + y->parent->right=x; + } + if (y != z) { /* y should not be nil in this case */ + +#ifdef DEBUG_ASSERT + Assert( (y!=it->nil),"y is nil in DeleteNode \n"); +#endif + /* y is the node to splice out and x is its child */ + + y->maxHigh = INT_MIN; + y->left=z->left; + y->right=z->right; + y->parent=z->parent; + z->left->parent=z->right->parent=y; + if (z == z->parent->left) + z->parent->left=y; + else + z->parent->right=y; + FixUpMaxHigh(it, x->parent); + if (!(y->red)) { + y->red = z->red; + DeleteFixUp(it, x); + } else + y->red = z->red; + yasm_xfree(z); +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not black in ITDelete"); + Assert((it->nil->maxHigh=LONG_MIN),"nil->maxHigh != LONG_MIN in ITDelete"); +#endif + } else { + FixUpMaxHigh(it, x->parent); + if (!(y->red)) + DeleteFixUp(it, x); + yasm_xfree(y); +#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS + IT_CheckAssumptions(it); +#elif defined(DEBUG_ASSERT) + Assert(!it->nil->red,"nil not black in ITDelete"); + Assert((it->nil->maxHigh=LONG_MIN),"nil->maxHigh != LONG_MIN in ITDelete"); +#endif + } + return returnValue; +} + + +/***********************************************************************/ +/* FUNCTION: Overlap */ +/**/ +/* INPUTS: [a1,a2] and [b1,b2] are the low and high endpoints of two */ +/* closed intervals. */ +/**/ +/* OUTPUT: stack containing pointers to the nodes between [low,high] */ +/**/ +/* Modifies Input: none */ +/**/ +/* EFFECT: returns 1 if the intervals overlap, and 0 otherwise */ +/***********************************************************************/ + +static int +Overlap(int a1, int a2, int b1, int b2) +{ + if (a1 <= b1) + return (b1 <= a2); + else + return (a1 <= b2); +} + + +/***********************************************************************/ +/* FUNCTION: Enumerate */ +/**/ +/* INPUTS: tree is the tree to look for intervals overlapping the */ +/* closed interval [low,high] */ +/**/ +/* OUTPUT: stack containing pointers to the nodes overlapping */ +/* [low,high] */ +/**/ +/* Modifies Input: none */ +/**/ +/* EFFECT: Returns a stack containing pointers to nodes containing */ +/* intervals which overlap [low,high] in O(max(N,k*log(N))) */ +/* where N is the number of intervals in the tree and k is */ +/* the number of overlapping intervals */ +/**/ +/* Note: This basic idea for this function comes from the */ +/* _Introduction_To_Algorithms_ book by Cormen et al, but */ +/* modifications were made to return all overlapping intervals */ +/* instead of just the first overlapping interval as in the */ +/* book. The natural way to do this would require recursive */ +/* calls of a basic search function. I translated the */ +/* recursive version into an interative version with a stack */ +/* as described below. */ +/***********************************************************************/ + + + +/* The basic idea for the function below is to take the IntervalSearch + * function from the book and modify to find all overlapping intervals + * instead of just one. This means that any time we take the left + * branch down the tree we must also check the right branch if and only if + * we find an overlapping interval in that left branch. Note this is a + * recursive condition because if we go left at the root then go left + * again at the first left child and find an overlap in the left subtree + * of the left child of root we must recursively check the right subtree + * of the left child of root as well as the right child of root. + */ +void +IT_enumerate(IntervalTree *it, long low, long high, void *cbd, + void (*callback) (IntervalTreeNode *node, void *cbd)) +{ + IntervalTreeNode *x=it->root->left; + int stuffToDo = (x != it->nil); + + /* Possible speed up: add min field to prune right searches */ + +#ifdef DEBUG_ASSERT + Assert((it->recursionNodeStackTop == 1), + "recursionStack not empty when entering IntervalTree::Enumerate"); +#endif + it->currentParent = 0; + + while (stuffToDo) { + if (Overlap(low,high,x->low,x->high) ) { + callback(x, cbd); + it->recursionNodeStack[it->currentParent].tryRightBranch=1; + } + if(x->left->maxHigh >= low) { /* implies x != nil */ + if (it->recursionNodeStackTop == it->recursionNodeStackSize) { + it->recursionNodeStackSize *= 2; + it->recursionNodeStack = (it_recursion_node *) + yasm_xrealloc(it->recursionNodeStack, + it->recursionNodeStackSize * sizeof(it_recursion_node)); + } + it->recursionNodeStack[it->recursionNodeStackTop].start_node = x; + it->recursionNodeStack[it->recursionNodeStackTop].tryRightBranch = 0; + it->recursionNodeStack[it->recursionNodeStackTop].parentIndex = it->currentParent; + it->currentParent = it->recursionNodeStackTop++; + x = x->left; + } else { + x = x->right; + } + stuffToDo = (x != it->nil); + while (!stuffToDo && (it->recursionNodeStackTop > 1)) { + if (it->recursionNodeStack[--it->recursionNodeStackTop].tryRightBranch) { + x=it->recursionNodeStack[it->recursionNodeStackTop].start_node->right; + it->currentParent=it->recursionNodeStack[it->recursionNodeStackTop].parentIndex; + it->recursionNodeStack[it->currentParent].tryRightBranch=1; + stuffToDo = (x != it->nil); + } + } + } +#ifdef DEBUG_ASSERT + Assert((it->recursionNodeStackTop == 1), + "recursionStack not empty when exiting IntervalTree::Enumerate"); +#endif +} + + +static int +CheckMaxHighFieldsHelper(const IntervalTree *it, IntervalTreeNode *y, + int currentHigh, int match) +{ + if (y != it->nil) { + match = CheckMaxHighFieldsHelper(it, y->left, currentHigh, match) ? + 1 : match; + VERIFY(y->high <= currentHigh); + if (y->high == currentHigh) + match = 1; + match = CheckMaxHighFieldsHelper(it, y->right, currentHigh, match) ? + 1 : match; + } + return match; +} + + + +/* Make sure the maxHigh fields for everything makes sense. * + * If something is wrong, print a warning and exit */ +static void +CheckMaxHighFields(const IntervalTree *it, IntervalTreeNode *x) +{ + if (x != it->nil) { + CheckMaxHighFields(it, x->left); + if(!(CheckMaxHighFieldsHelper(it, x, x->maxHigh, 0) > 0)) { + fprintf(stderr, "error found in CheckMaxHighFields.\n"); + abort(); + } + CheckMaxHighFields(it, x->right); + } +} + +static void +IT_CheckAssumptions(const IntervalTree *it) +{ + VERIFY(it->nil->low == INT_MIN); + VERIFY(it->nil->high == INT_MIN); + VERIFY(it->nil->maxHigh == INT_MIN); + VERIFY(it->root->low == INT_MAX); + VERIFY(it->root->high == INT_MAX); + VERIFY(it->root->maxHigh == INT_MAX); + VERIFY(it->nil->data == NULL); + VERIFY(it->root->data == NULL); + VERIFY(it->nil->red == 0); + VERIFY(it->root->red == 0); + CheckMaxHighFields(it, it->root->left); +} diff --git a/libyasm/inttree.h b/libyasm/inttree.h new file mode 100644 index 00000000..2b754984 --- /dev/null +++ b/libyasm/inttree.h @@ -0,0 +1,59 @@ +/* $Id$ */ +#ifndef YASM_INTTREE_H +#define YASM_INTTREE_H + +/* The interval_tree.h and interval_tree.cc files contain code for + * interval trees implemented using red-black-trees as described in + * the book _Introduction_To_Algorithms_ by Cormen, Leisserson, + * and Rivest. + */ + +typedef struct IntervalTreeNode { + struct IntervalTreeNode *left, *right, *parent; + void *data; + long low; + long high; + long maxHigh; + int red; /* if red=0 then the node is black */ +} IntervalTreeNode; + +typedef struct it_recursion_node { + /* This structure stores the information needed when we take the + * right branch in searching for intervals but possibly come back + * and check the left branch as well. + */ + IntervalTreeNode *start_node; + unsigned int parentIndex; + int tryRightBranch; +} it_recursion_node; + +typedef struct IntervalTree { + /* A sentinel is used for root and for nil. These sentinels are + * created when ITTreeCreate is called. root->left should always + * point to the node which is the root of the tree. nil points to a + * node which should always be black but has aribtrary children and + * parent and no key or info. The point of using these sentinels is so + * that the root and nil nodes do not require special cases in the code + */ + IntervalTreeNode *root; + IntervalTreeNode *nil; + +/*private:*/ + unsigned int recursionNodeStackSize; + it_recursion_node * recursionNodeStack; + unsigned int currentParent; + unsigned int recursionNodeStackTop; +} IntervalTree; + +IntervalTree *IT_create(void); +void IT_destroy(IntervalTree *); +void IT_print(const IntervalTree *); +void *IT_delete_node(IntervalTree *, IntervalTreeNode *, long *low, + long *high); +IntervalTreeNode *IT_insert(IntervalTree *, long low, long high, void *data); +IntervalTreeNode *IT_get_predecessor(const IntervalTree *, IntervalTreeNode *); +IntervalTreeNode *IT_get_successor(const IntervalTree *, IntervalTreeNode *); +void IT_enumerate(IntervalTree *, long low, long high, void *cbd, + void (*callback) (IntervalTreeNode *node, void *cbd)); + +#endif