From 16c58ab9738f91d021a8685184054c4270c32f47 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 24 Jun 2014 15:47:26 +0100 Subject: [PATCH] change all the rebalance code to be macros --- include/tr/tree_macros.h | 166 +++++++++++++++++++++++++++++++++++-- src/memory.c | 175 ++------------------------------------- 2 files changed, 164 insertions(+), 177 deletions(-) diff --git a/include/tr/tree_macros.h b/include/tr/tree_macros.h index c114b4f..0cfee33 100644 --- a/include/tr/tree_macros.h +++ b/include/tr/tree_macros.h @@ -41,10 +41,10 @@ #define TR_TREE_GRANDPARENT(node) (TR_TREE_PARENT((node))->parent) -#define TR_TREE_UNCLE(node) \ - ((node)->parent == (node)->parent->parent->left? \ - (node)->parent->parent->right: \ - (node)->parent->parent->left) +#define TR_TREE_UNCLE(node) \ + ((node)->parent == (node)->parent->parent->left \ + ? (node)->parent->parent->right \ + : (node)->parent->parent->left) #define TR_TREE_REPLACE_NODE(root, node1, node2) \ if (NULL != (node1)->parent) { \ @@ -89,16 +89,21 @@ typedef enum {rbBlack=1, rbRed=2} TR_rbColor; -#define TR_TREE_NODE_BLACK(node) (NULL == (node) || rbBlack == (node)->color) -#define TR_TREE_NODE_RED(node) (NULL == (node) || rbRed == (node)->color) -#define TR_TREE_NODE_STRICT_BLACK(node) (NULL != (node) && rbBlack == (node)->color) -#define TR_TREE_NODE_STRICT_RED(node) (NULL != (node) && rbRed == (node)->color) +#define TR_TREE_NODE_BLACK(node) \ + (NULL == (node) || rbBlack == (node)->color) +#define TR_TREE_NODE_RED(node) \ + (NULL == (node) || rbRed == (node)->color) +#define TR_TREE_NODE_STRICT_BLACK(node) \ + (NULL != (node) && rbBlack == (node)->color) +#define TR_TREE_NODE_STRICT_RED(node) \ + (NULL != (node) && rbRed == (node)->color) #define TR_TREE_INORDER_SUCC(node, succ) \ succ = (node)->right; \ while (NULL != succ->left) { \ succ = succ->left; \ } + /* * Find data in a tree. * Attention: This will change node, so normally you need to copy @@ -125,6 +130,151 @@ typedef enum {rbBlack=1, rbRed=2} TR_rbColor; } \ } +#define TR_TREE_BALANCE_DELETE_CASE1(node) \ + if (NULL == TR_TREE_PARENT((node))) { \ + break; \ + } + +#define TR_TREE_BALANCE_DELETE_CASE2(root, node, sibling) \ + if (NULL != (sibling) && rbRed == (sibling)->color) { \ + (node)->parent->color = rbRed; \ + (sibling)->color = rbBlack; \ + if (NULL != (node)->parent->right \ + && (node) != (node)->parent->right) { \ + TR_TREE_ROTATE(left, (root), (node)->parent); \ + } else { \ + TR_TREE_ROTATE(right, (root), (node)->parent); \ + } \ + (sibling) = TR_TREE_SIBLING((node)); \ + } + +#define TR_TREE_BALANCE_DELETE_CASE34(root, node, sibling) \ + if (NULL == (sibling) \ + || (rbBlack == (sibling)->color \ + && TR_TREE_NODE_BLACK((sibling)->left) \ + && TR_TREE_NODE_BLACK((sibling)->right))) { \ + if (NULL != (sibling)) { \ + (sibling)->color = rbRed; \ + } \ + if (rbBlack == (node)->parent->color) { \ + (node) = (node)->parent; \ + continue; \ + } else { \ + (node)->parent->color = rbBlack; \ + break; \ + } \ + } + +/* + * this if statement is trivial, + * due to case 2 (even though case 2 changed the sibling to a + * sibling's child, + * the sibling's child can't be red, since no red parent can + * have a red child). + * + * the following statements just force the red to be on the + * left of the left of the parent, + * or right of the right, so case 6 will rotate correctly. + */ +#define TR_TREE_BALANCE_DELETE_CASE5(root, node, sibling) \ + if (NULL != (sibling) && rbBlack == (sibling)->color) { \ + if ((node) == (node)->parent->left \ + && TR_TREE_NODE_BLACK((sibling)->right) \ + && TR_TREE_NODE_STRICT_RED((sibling)->left)) { \ + (sibling)->color = rbRed; \ + (sibling)->left->color = rbBlack; \ + TR_TREE_ROTATE(right, (root), (sibling)); \ + } else if ((node) == (node)->parent->right \ + && TR_TREE_NODE_BLACK((sibling)->left) \ + && TR_TREE_NODE_STRICT_RED((sibling)->right)) { \ + (sibling)->color = rbRed; \ + (sibling)->right->color = rbBlack; \ + TR_TREE_ROTATE(left, (root), (sibling)); \ + } \ + (sibling) = TR_TREE_SIBLING((node)); \ + } + +#define TR_TREE_BALANCE_DELETE_CASE6(root, node, sibling) \ + if (NULL != (sibling)) { \ + (sibling)->color = (node)->parent->color; \ + } \ + if (NULL != (node) && NULL != (node)->parent) { \ + (node)->parent->color = rbBlack; \ + if (NULL != (node)->parent->right \ + && (node) != (node)->parent->right) { \ + if (NULL != (sibling)->right) { \ + (sibling)->right->color = rbBlack; \ + } \ + TR_TREE_ROTATE(left, (root), (node)->parent); \ + } else { \ + if (NULL != (sibling)->left) { \ + (sibling)->left->color = rbBlack; \ + } \ + TR_TREE_ROTATE(right, (root), (node)->parent); \ + } \ + } + +#define TR_TREE_BALANCE_DELETE(root, node, sibling) \ + while(1) { \ + TR_TREE_BALANCE_DELETE_CASE1((node)) \ + TR_TREE_BALANCE_DELETE_CASE2((root), (node), (sibling)) \ + TR_TREE_BALANCE_DELETE_CASE34((root), (node), (sibling)) \ + TR_TREE_BALANCE_DELETE_CASE5((root), (node), (sibling)) \ + TR_TREE_BALANCE_DELETE_CASE6((root), (node), (sibling)) \ + break; \ + } + +#define TR_TREE_BALANCE_INSERT_CASE1(node) \ + if (NULL == TR_TREE_PARENT((node))) { \ + (node)->color = rbBlack; \ + break; \ + } + +#define TR_TREE_BALANCE_INSERT_CASE2(node) \ + if (rbBlack == (node)->parent->color) { \ + break; \ + } + +#define TR_TREE_BALANCE_INSERT_CASE3(node) \ + if (NULL != TR_TREE_UNCLE(node) \ + && rbRed == TR_TREE_UNCLE(node)->color) { \ + (node)->parent->color = rbBlack; \ + TR_TREE_UNCLE(node)->color = rbBlack; \ + (node)->parent->parent->color = rbRed; \ + (node) = (node)->parent->parent; \ + continue; \ + } + +#define TR_TREE_BALANCE_INSERT_CASE4(root, node) \ + if ((node) == (node)->parent->right \ + && (node)->parent == (node)->parent->parent->left) { \ + TR_TREE_ROTATE(left, (root), (node)->parent); \ + (node) = (node)->left; \ + } else if ((node) == (node)->parent->left \ + && (node)->parent == (node)->parent->parent->right) { \ + TR_TREE_ROTATE(right, (root), (node)->parent); \ + (node) = (node)->right; \ + } + +#define TR_TREE_BALANCE_INSERT_CASE5(root, node) \ + (node)->parent->color = rbBlack; \ + (node)->parent->parent->color = rbRed; \ + if ((node) == (node)->parent->left) { \ + TR_TREE_ROTATE(right, (root), (node)->parent->parent); \ + } else { \ + TR_TREE_ROTATE(left, (root), (node)->parent->parent); \ + } + +#define TR_TREE_BALANCE_INSERT(root, node) \ + while (1) { \ + TR_TREE_BALANCE_INSERT_CASE1((node)) \ + TR_TREE_BALANCE_INSERT_CASE2((node)) \ + TR_TREE_BALANCE_INSERT_CASE3((node)) \ + TR_TREE_BALANCE_INSERT_CASE4((root), (node)) \ + TR_TREE_BALANCE_INSERT_CASE5((root), (node)) \ + break; \ + } + #endif // __TR_TREE_MACROS_H__ // vim: set ts=4 sw=4: diff --git a/src/memory.c b/src/memory.c index ca6491d..d70ff53 100644 --- a/src/memory.c +++ b/src/memory.c @@ -131,8 +131,6 @@ insertElement(struct memSegment ** tree, struct memSegment * element) { struct memSegment * node = *tree; struct memSegment * new_node = NULL; - struct memSegment * u; - struct memSegment * g; int found; element->next = NULL; @@ -173,63 +171,10 @@ insertElement(struct memSegment ** tree, struct memSegment * element) } } - if (NULL != new_node) { - /* - * handle reballancing rb style - */ - while (1) { - // case 1 - if (node->parent == NULL) { - node->color = rbBlack; - // we're done.... :) - break; - } - - // case 2 - if (node->parent->color == rbBlack) { - // Tree is still valid ... wow, again we're done... :) - break; - } - - // case 3 - u = TR_TREE_UNCLE(node); - g = TR_TREE_GRANDPARENT(node); - - if (u != NULL && u->color == rbRed) { - node->parent->color = rbBlack; - u->color = rbBlack; - g->color = rbRed; - - node = g; - continue; - } - - // case 4 - if (node == node->parent->right && node->parent == g->left) { - TR_TREE_ROTATE(left, tree, node->parent); - node = node->left; - } else if (node == node->parent->left && node->parent == g->right) { - - TR_TREE_ROTATE(right, tree, node->parent); - node = node->right; - } - - // case 5 - g = TR_TREE_GRANDPARENT(node); - - node->parent->color = rbBlack; - g->color = rbRed; - - if (node == node->parent->left) { - TR_TREE_ROTATE(right, tree, g); - } else { - TR_TREE_ROTATE(left, tree, g); - } - - // we're done.. - break; - } - } + /* + * handle reballancing rb style + */ + TR_TREE_BALANCE_INSERT(tree, node); return new_node; } @@ -345,116 +290,8 @@ deleteElement(struct memSegment ** tree, size_t size) return del_node; } - // delete and rb rebalance... - while(1) { - // case 1 - if (NULL == node->parent) { - // done again - break; - } - - // case 2 - s = TR_TREE_SIBLING(node); - - if (NULL != s && s->color == rbRed) { - node->parent->color = rbRed; - s->color = rbBlack; - - /* - * detect which child we are...assumption - * if we are not parent->right and parent->right is not - * null we must be left, even if its set to NULL previously - */ - if (NULL != node->parent->right && node != node->parent->right) { - TR_TREE_ROTATE(left, tree, node->parent); - } else { - TR_TREE_ROTATE(right, tree, node->parent); - } - } - - s = TR_TREE_SIBLING(node); - // case 3 / 4 - if (NULL == s || ((s->color == rbBlack) && - (NULL == s->left || s->left->color == rbBlack) && - (NULL == s->right || s->right->color == rbBlack))) { - - if (NULL != s) { - s->color = rbRed; - } - - if (node->parent->color == rbBlack) { - // case 3 - node = node->parent; - continue; - } else { - // case 4 - node->parent->color = rbBlack; - // and done again... - break; - } - } - - // case 5 - if (NULL != s && s->color == rbBlack) { - // this if statement is trivial, - // due to case 2 (even though case 2 changed the sibling to a - // sibling's child, - // the sibling's child can't be red, since no red parent can - // have a red child). - // - // the following statements just force the red to be on the - // left of the left of the parent, - // or right of the right, so case 6 will rotate correctly. - if ((node == node->parent->left) && - (NULL == s->right || s->right->color == rbBlack) && - (NULL != s->left && s->left->color == rbRed)) { - - // this last test is trivial too due to cases 2-4. - s->color = rbRed; - s->left->color = rbBlack; - - TR_TREE_ROTATE(right, tree, s); - } else if ((node == node->parent->right) && - (NULL == s->left || s->left->color == rbBlack) && - (NULL != s->right && s->right->color == rbRed)) { - // this last test is trivial too due to cases 2-4. - s->color = rbRed; - s->right->color = rbBlack; - - TR_TREE_ROTATE(left, tree, s); - } - } - - s = TR_TREE_SIBLING(node); - // case 6 - if (NULL != s) { - s->color = node->parent->color; - } - - if (NULL != node && NULL != node->parent) { - node->parent->color = rbBlack; - - /* - * detect which child we are...assumption - * if we are not parent->right and parent->right is not - * null we must be left, even if its set to NULL previously - */ - if (NULL != node->parent->right && node != node->parent->right) { - if (NULL != s->right) { - s->right->color = rbBlack; - } - TR_TREE_ROTATE(left, tree, node->parent); - } else { - if (NULL != s->left) { - s->left->color = rbBlack; - } - TR_TREE_ROTATE(right, tree, node->parent); - } - } - - // done... - break; - } + s = TR_TREE_SIBLING(node); + TR_TREE_BALANCE_DELETE(tree, node, s); return del_node; }