/** * Delete a node from one order of a red-black tree * * This function has three parameters: a tree, the node to delete, and * the order from which to delete it. _rb_delete() is an * implementation of the routine RB-DELETE on p. 273 of Cormen et * al. (p. 324 in the paperback version of the 2009 edition). */ HIDDEN void _rb_delete(struct bu_rb_tree *tree, struct bu_rb_node *node, int order) { struct bu_rb_node *y; /* The node to splice out */ struct bu_rb_node *parent; struct bu_rb_node *only_child; BU_CKMAG(tree, BU_RB_TREE_MAGIC, "red-black tree"); BU_CKMAG(node, BU_RB_NODE_MAGIC, "red-black node"); RB_CKORDER(tree, order); if (UNLIKELY(tree->rbt_debug & BU_RB_DEBUG_DELETE)) bu_log("_rb_delete(%p, %p, %d): data=%p\n", (void*)tree, (void*)node, order, RB_DATA(node, order)); if ((RB_LEFT_CHILD(node, order) == RB_NULL(tree)) || (RB_RIGHT_CHILD(node, order) == RB_NULL(tree))) y = node; else y = rb_neighbor(node, order, SENSE_MAX); if (RB_LEFT_CHILD(y, order) == RB_NULL(tree)) only_child = RB_RIGHT_CHILD(y, order); else only_child = RB_LEFT_CHILD(y, order); parent = RB_PARENT(only_child, order) = RB_PARENT(y, order); if (parent == RB_NULL(tree)) RB_ROOT(tree, order) = only_child; else if (y == RB_LEFT_CHILD(parent, order)) RB_LEFT_CHILD(parent, order) = only_child; else RB_RIGHT_CHILD(parent, order) = only_child; /* * Splice y out if it's not node */ if (y != node) { (node->rbn_package)[order] = (y->rbn_package)[order]; ((node->rbn_package)[order]->rbp_node)[order] = node; } if (RB_GET_COLOR(y, order) == RB_BLK) _rb_fixup(tree, only_child, order); if (--(y->rbn_pkg_refs) == 0) rb_free_node(y); }
/* * Recreate the addr tree of vm_map in local memory. */ struct vm_map_entry * load_vm_map_entries(kvm_t *kd, struct vm_map_entry *kptr, struct vm_map_entry *parent) { static struct kbit map_ent; struct vm_map_entry *result; if (kptr == NULL) return NULL; A(&map_ent) = (u_long)kptr; S(&map_ent) = sizeof(struct vm_map_entry); KDEREF(kd, &map_ent); result = malloc(sizeof(*result)); if (result == NULL) err(1, "malloc"); memcpy(result, D(&map_ent, vm_map_entry), sizeof(struct vm_map_entry)); /* * Recurse to download rest of the tree. */ RB_LEFT(result, daddrs.addr_entry) = load_vm_map_entries(kd, RB_LEFT(result, daddrs.addr_entry), result); RB_RIGHT(result, daddrs.addr_entry) = load_vm_map_entries(kd, RB_RIGHT(result, daddrs.addr_entry), result); RB_PARENT(result, daddrs.addr_entry) = parent; return result; }
/* * rb_successor - find the next node of node in ascending order. */ static void* rb_successor(void *node){ void *succ, *left; if((succ = RB_RIGHT(node)) != rb_null){ while((left = RB_LEFT(succ)) != rb_null){ succ = left; } return succ; }else{ succ = RB_PARENT(node); while(RB_RIGHT(succ) == node){ node = succ; succ = RB_PARENT(succ); } if(succ == rb_root) return rb_null; return succ; } }
/* Note args swapped to match Linux */ void rb_insert_color(struct rb_node *elm, struct rb_root *head) { struct rb_node *parent, *gparent, *tmp; while ((parent = RB_PARENT(elm)) && RB_COLOR(parent) == RB_RED) { gparent = RB_PARENT(parent); if (parent == RB_LEFT(gparent)) { tmp = RB_RIGHT(gparent); if (tmp && RB_COLOR(tmp) == RB_RED) { RB_COLOR(tmp) = RB_BLACK; RB_SET_BLACKRED(parent, gparent); elm = gparent; continue; } if (RB_RIGHT(parent) == elm) { RB_ROTATE_LEFT(head, parent, tmp); tmp = parent; parent = elm; elm = tmp; } RB_SET_BLACKRED(parent, gparent); RB_ROTATE_RIGHT(head, gparent, tmp); } else { tmp = RB_LEFT(gparent); if (tmp && RB_COLOR(tmp) == RB_RED) { RB_COLOR(tmp) = RB_BLACK; RB_SET_BLACKRED(parent, gparent); elm = gparent; continue; } if (RB_LEFT(parent) == elm) { RB_ROTATE_RIGHT(head, parent, tmp); tmp = parent; parent = elm; elm = tmp; } RB_SET_BLACKRED(parent, gparent); RB_ROTATE_LEFT(head, gparent, tmp); } } RB_COLOR(head->rb_node) = RB_BLACK; }
void rb_rot_left(struct bu_rb_node *x, int order) { struct bu_rb_node *y; /* x's child to pivot up */ struct bu_rb_node *beta; /* y's child in direction of rot. */ struct bu_rb_node *x_parent; /* x's parent */ struct bu_rb_tree *tree = x->rbn_tree; /* Tree where it all happens */ /* * Set y and check data types of both x and y */ BU_CKMAG(x, BU_RB_NODE_MAGIC, "red-black node"); RB_CKORDER(x->rbn_tree, order); y = RB_RIGHT_CHILD(x, order); if (UNLIKELY(tree->rbt_debug & BU_RB_DEBUG_ROTATE)) bu_log("rb_rot_left(<%p>, %d)...\n", (void*)x, order); RB_RIGHT_CHILD(x, order) = beta = RB_LEFT_CHILD(y, order); if (beta != RB_NULL(tree)) RB_PARENT(beta, order) = x; RB_PARENT(y, order) = x_parent = RB_PARENT(x, order); if (x_parent == RB_NULL(tree)) RB_ROOT(tree, order) = y; else if (x == RB_LEFT_CHILD(x_parent, order)) RB_LEFT_CHILD(x_parent, order) = y; else RB_RIGHT_CHILD(x_parent, order) = y; RB_LEFT_CHILD(y, order) = x; RB_PARENT(x, order) = y; RB_SIZE(y, order) = RB_SIZE(x, order); RB_SIZE(x, order) = RB_SIZE(RB_LEFT_CHILD(x, order), order) + RB_SIZE(RB_RIGHT_CHILD(x, order), order) + 1; if (UNLIKELY(tree->rbt_debug & BU_RB_DEBUG_OS)) bu_log("After rotation, size(%p, %d)=%d, size(%p, %d)=%d\n", (void*)x, order, RB_SIZE(x, order), (void*)y, order, RB_SIZE(y, order)); }
static void wf2q_augment_func(struct bfq_thread_io *node) { struct bfq_thread_io *tmp = node, *tmp2; int min_vd; do{ min_vd = tmp->vd; tmp2 = RB_LEFT(tmp, entry); min_vd = tmp2 ? MIN(tmp2->min_vd, min_vd) : min_vd; tmp2 = RB_RIGHT(tmp, entry); min_vd = tmp2 ? MIN(tmp2->min_vd, min_vd) : min_vd; tmp->min_vd = min_vd; }while((tmp = RB_PARENT(tmp,entry))); }
/** * Restore the red-black properties of a red-black tree after the * splicing out of a node * * This function has three parameters: the tree to be fixed up, the * node where the trouble occurs, and the order. _rb_fixup() is an * implementation of the routine RB-DELETE-FIXUP on p. 274 of Cormen * et al. (p. 326 in the paperback version of the 2009 edition). */ HIDDEN void _rb_fixup(struct bu_rb_tree *tree, struct bu_rb_node *node, int order) { int direction; struct bu_rb_node *parent; struct bu_rb_node *w; BU_CKMAG(tree, BU_RB_TREE_MAGIC, "red-black tree"); BU_CKMAG(node, BU_RB_NODE_MAGIC, "red-black node"); RB_CKORDER(tree, order); while ((node != RB_ROOT(tree, order)) && (RB_GET_COLOR(node, order) == RB_BLK)) { parent = RB_PARENT(node, order); if (node == RB_LEFT_CHILD(parent, order)) direction = RB_LEFT; else direction = RB_RIGHT; w = RB_OTHER_CHILD(parent, order, direction); if (RB_GET_COLOR(w, order) == RB_RED) { RB_SET_COLOR(w, order, RB_BLK); RB_SET_COLOR(parent, order, RB_RED); RB_ROTATE(parent, order, direction); w = RB_OTHER_CHILD(parent, order, direction); } if ((RB_GET_COLOR(RB_CHILD(w, order, direction), order) == RB_BLK) && (RB_GET_COLOR(RB_OTHER_CHILD(w, order, direction), order) == RB_BLK)) { RB_SET_COLOR(w, order, RB_RED); node = parent; } else { if (RB_GET_COLOR(RB_OTHER_CHILD(w, order, direction), order) == RB_BLK) { RB_SET_COLOR(RB_CHILD(w, order, direction), order, RB_BLK); RB_SET_COLOR(w, order, RB_RED); RB_OTHER_ROTATE(w, order, direction); w = RB_OTHER_CHILD(parent, order, direction); } RB_SET_COLOR(w, order, RB_GET_COLOR(parent, order)); RB_SET_COLOR(parent, order, RB_BLK); RB_SET_COLOR(RB_OTHER_CHILD(w, order, direction), order, RB_BLK); RB_ROTATE(parent, order, direction); node = RB_ROOT(tree, order); } } RB_SET_COLOR(node, order, RB_BLK); }
/* * rb_rotate_right - rotate node and children of node to the right */ static void rb_rotate_right(void *node){ void *left; left = RB_LEFT(node); RB_LEFT(node) = RB_RIGHT(left); if(RB_RIGHT(left) != rb_null) RB_PARENT(RB_RIGHT(left)) = node; RB_PARENT(left) = RB_PARENT(node); if(node == RB_LEFT(RB_PARENT(node))){ RB_LEFT(RB_PARENT(node)) = left; }else{ RB_RIGHT(RB_PARENT(node)) = left; } RB_RIGHT(left) = node; RB_PARENT(node) = left; }
/* * rb_rotate_left - rotate node and children of node to the left */ static void rb_rotate_left(void *node){ void *right; right = RB_RIGHT(node); RB_RIGHT(node) = RB_LEFT(right); if(RB_LEFT(right) != rb_null) RB_PARENT(RB_LEFT(right)) = node; RB_PARENT(right) = RB_PARENT(node); if(node == RB_LEFT(RB_PARENT(node))){ RB_LEFT(RB_PARENT(node)) = right; }else{ RB_RIGHT(RB_PARENT(node)) = right; } RB_LEFT(right) = node; RB_PARENT(node) = right; }
static VOID LwRtlRBTreeInsert( PLWRTL_RB_TREE pRBTree, PLWRTL_RB_TREE_NODE pTreeNode ) { PLWRTL_RB_TREE_NODE pParent = pRBTree->pSentinel; PLWRTL_RB_TREE_NODE pCurrent = pRBTree->pRoot; while (!RB_IS_NIL(pRBTree, pCurrent)) { pParent = pCurrent; if (pRBTree->pfnCompare(pTreeNode->pKey, pCurrent->pKey) < 0) { pCurrent = pCurrent->pLeft; } else { pCurrent = pCurrent->pRight; } } RB_SET_PARENT(pTreeNode, pParent); if (RB_IS_NIL(pRBTree, RB_PARENT(pTreeNode))) { pRBTree->pRoot = pTreeNode; } else { if (pRBTree->pfnCompare(pTreeNode->pKey, pParent->pKey) < 0) { pParent->pLeft = pTreeNode; } else { pParent->pRight = pTreeNode; } } }
struct rb_node *rb_prev(struct rb_node *elm) { if (RB_LEFT(elm)) { elm = RB_LEFT(elm); while (RB_RIGHT(elm)) elm = RB_RIGHT(elm); } else { if (RB_PARENT(elm) && (elm == RB_RIGHT(RB_PARENT(elm)))) elm = RB_PARENT(elm); else { while (RB_PARENT(elm) && (elm == RB_LEFT(RB_PARENT(elm)))) elm = RB_PARENT(elm); elm = RB_PARENT(elm); } } return (elm); }
static VOID LwRtlRBTreeFixColors( PLWRTL_RB_TREE pRBTree, PLWRTL_RB_TREE_NODE pTreeNode ) { PLWRTL_RB_TREE_NODE pUncle = NULL; PLWRTL_RB_TREE_NODE pParent = NULL; PLWRTL_RB_TREE_NODE pGrandParent = NULL; while ((pRBTree->pRoot != pTreeNode) && RB_IS_BLACK(pTreeNode)) { pParent = RB_PARENT(pTreeNode); pGrandParent = RB_PARENT(pParent); if (pTreeNode == pParent->pLeft) { pUncle = pParent->pRight; if (!RB_IS_NIL(pRBTree, pUncle) && RB_IS_RED(pUncle)) { RB_COLOR_BLACK(pUncle); RB_COLOR_RED(pParent); LwRtlRBTreeRotateLeft(pRBTree, pParent); pUncle = pParent->pRight; } if (!RB_IS_NIL(pRBTree, pUncle) && RB_IS_BLACK(pUncle->pLeft) && RB_IS_BLACK(pUncle->pRight)) { RB_COLOR_RED(pUncle); pTreeNode = pParent; continue; } if (!RB_IS_NIL(pRBTree, pUncle) && RB_IS_BLACK(pUncle->pRight)) { RB_COLOR_BLACK(pUncle->pLeft); RB_COLOR_RED(pUncle); LwRtlRBTreeRotateRight(pRBTree, pUncle); pUncle = pParent->pRight; } if (!RB_IS_NIL(pRBTree, pUncle)) { RB_COPY_COLOR(pUncle, pParent); } RB_COLOR_BLACK(pParent); if (!RB_IS_NIL(pRBTree, pUncle)) { RB_COLOR_BLACK(pUncle->pRight); LwRtlRBTreeRotateLeft(pRBTree, pParent); } pTreeNode = pRBTree->pRoot; } else { pUncle = pParent->pLeft; if (!RB_IS_NIL(pRBTree, pUncle) && RB_IS_RED(pUncle)) { RB_COLOR_BLACK(pUncle); RB_COLOR_RED(pParent); LwRtlRBTreeRotateRight(pRBTree, pParent); pUncle = pParent->pLeft; } if (!RB_IS_NIL(pRBTree, pUncle) && RB_IS_BLACK(pUncle->pLeft) && RB_IS_BLACK(pUncle->pRight)) { RB_COLOR_RED(pUncle); pTreeNode = pParent; continue; } if (!RB_IS_NIL(pRBTree, pUncle) && RB_IS_BLACK(pUncle->pLeft)) { RB_COLOR_BLACK(pUncle->pRight); RB_COLOR_RED(pUncle); LwRtlRBTreeRotateLeft(pRBTree, pUncle); pUncle = pParent->pLeft; } if (!RB_IS_NIL(pRBTree, pUncle)) { RB_COPY_COLOR(pUncle, pParent); } RB_COLOR_BLACK(pParent); if (!RB_IS_NIL(pRBTree, pUncle)) { RB_COLOR_BLACK(pUncle->pLeft); LwRtlRBTreeRotateRight(pRBTree, pParent); } pTreeNode = pRBTree->pRoot; } } RB_COLOR_BLACK(pTreeNode); }
NTSTATUS LwRtlRBTreeAdd( PLWRTL_RB_TREE pRBTree, PVOID pKey, PVOID pData ) { NTSTATUS ntStatus = 0; PLWRTL_RB_TREE_NODE pTreeNode = NULL; PLWRTL_RB_TREE_NODE pUncle = NULL; PLWRTL_RB_TREE_NODE pParent = NULL; PLWRTL_RB_TREE_NODE pGrandParent = NULL; if (!pKey) { ntStatus = STATUS_INVALID_PARAMETER_2; BAIL_ON_NT_STATUS(ntStatus); } ntStatus = LW_RTL_ALLOCATE( &pTreeNode, LWRTL_RB_TREE_NODE, sizeof(LWRTL_RB_TREE_NODE)); BAIL_ON_NT_STATUS(ntStatus); pTreeNode->pKey = pKey; pTreeNode->pData = pData; pTreeNode->pRight = pRBTree->pSentinel; pTreeNode->pLeft = pRBTree->pSentinel; pTreeNode->pParent = NULL; LwRtlRBTreeInsert(pRBTree, pTreeNode); RB_COLOR_RED(pTreeNode); while ((pTreeNode != pRBTree->pRoot) && RB_IS_RED(pTreeNode->pParent)) { pParent = RB_PARENT(pTreeNode); pGrandParent = RB_PARENT(pParent); if (pParent == pGrandParent->pLeft) { if (!RB_IS_NIL(pRBTree, pGrandParent)) { pUncle = pGrandParent->pRight; if (RB_IS_RED(pUncle)) { RB_COLOR_BLACK(pParent); RB_COLOR_BLACK(pUncle); RB_COLOR_RED(pGrandParent); pTreeNode = pGrandParent; continue; } } if (pTreeNode == pParent->pRight) { pTreeNode = pParent; LwRtlRBTreeRotateLeft(pRBTree, pTreeNode); pParent = RB_PARENT(pTreeNode); } RB_COLOR_BLACK(pParent); if (!RB_IS_NIL(pRBTree, pGrandParent)) { RB_COLOR_RED(pGrandParent); LwRtlRBTreeRotateRight(pRBTree, pGrandParent); } } else { if (!RB_IS_NIL(pRBTree, pGrandParent)) { pUncle = pGrandParent->pLeft; if (RB_IS_RED(pUncle)) { RB_COLOR_BLACK(pParent); RB_COLOR_BLACK(pUncle); RB_COLOR_RED(pGrandParent); pTreeNode = pGrandParent; continue; } } if (pTreeNode == pParent->pLeft) { pTreeNode = pParent; LwRtlRBTreeRotateRight(pRBTree, pTreeNode); pParent = RB_PARENT(pTreeNode); } RB_COLOR_BLACK(pParent); if (!RB_IS_NIL(pRBTree, pGrandParent)) { RB_COLOR_RED(pGrandParent); LwRtlRBTreeRotateLeft(pRBTree, pGrandParent); } } } RB_COLOR_BLACK(pRBTree->pRoot); cleanup: return ntStatus; error: if (pTreeNode) { LwRtlRBTreeFreeNode(pRBTree, pTreeNode); } goto cleanup; }
/* * rb_insert - insert node into Red-black tree */ static void rb_insert(void *node){ void *parent, *child, *sib; RB_LEFT(node) = RB_RIGHT(node) = rb_null; parent = rb_root; child = RB_LEFT(rb_root); while(child != rb_null){ parent = child; if(CUR_SIZE_MASKED(child) > CUR_SIZE_MASKED(node)){ child = RB_LEFT(child); }else if(CUR_SIZE_MASKED(child) == CUR_SIZE_MASKED(node)){ if(child > node){ child = RB_LEFT(child); }else{ child = RB_RIGHT(child); } }else{ child = RB_RIGHT(child); } } RB_PARENT(node) = parent; if(parent == rb_root || CUR_SIZE_MASKED(parent) > CUR_SIZE_MASKED(node)){ RB_LEFT(parent) = node; }else if(CUR_SIZE_MASKED(parent) == CUR_SIZE_MASKED(node)){ if(parent > node){ RB_LEFT(parent) = node; }else{ RB_RIGHT(parent) = node; } }else{ RB_RIGHT(parent) = node; } RB_RED(node) = 1; while(RB_RED(RB_PARENT(node))){ if(RB_PARENT(node) == RB_LEFT(RB_PARENT(RB_PARENT(node)))){ sib = RB_RIGHT(RB_PARENT(RB_PARENT(node))); if(RB_RED(sib)){ RB_RED(RB_PARENT(node)) = 0; RB_RED(sib) = 0; RB_RED(RB_PARENT(RB_PARENT(node))) = 1; node = RB_PARENT(RB_PARENT(node)); }else{ if(node == RB_RIGHT(RB_PARENT(node))){ node = RB_PARENT(node); rb_rotate_left(node); } RB_RED(RB_PARENT(node)) = 0; RB_RED(RB_PARENT(RB_PARENT(node))) = 1; rb_rotate_right(RB_PARENT(RB_PARENT(node))); } }else{ sib = RB_LEFT(RB_PARENT(RB_PARENT(node))); if(RB_RED(sib)){ RB_RED(RB_PARENT(node)) = 0; RB_RED(sib) = 0; RB_RED(RB_PARENT(RB_PARENT(node))) = 1; node = RB_PARENT(RB_PARENT(node)); }else{ if(node == RB_LEFT(RB_PARENT(node))){ node = RB_PARENT(node); rb_rotate_right(node); } RB_RED(RB_PARENT(node)) = 0; RB_RED(RB_PARENT(RB_PARENT(node))) = 1; rb_rotate_left(RB_PARENT(RB_PARENT(node))); } } } RB_RED(RB_LEFT(rb_root)) = 0; }
/* * rb_delete - delete node from Red-black tree */ static void rb_delete(void *node){ void *m, *c; m = RB_LEFT(node) == rb_null || RB_RIGHT(node) == rb_null ? node : rb_successor(node); c = RB_LEFT(m) == rb_null ? RB_RIGHT(m) : RB_LEFT(m); if((RB_PARENT(c) = RB_PARENT(m)) == rb_root){ RB_LEFT(rb_root) = c; }else{ if(RB_LEFT(RB_PARENT(m)) == m){ RB_LEFT(RB_PARENT(m)) = c; }else{ RB_RIGHT(RB_PARENT(m)) = c; } } if(m != node){ if(!RB_RED(m)) rb_fix(c); RB_LEFT(m) = RB_LEFT(node); RB_RIGHT(m) = RB_RIGHT(node); RB_PARENT(m) = RB_PARENT(node); RB_RED(m) = RB_RED(node); RB_PARENT(RB_LEFT(node)) = RB_PARENT(RB_RIGHT(node)) = m; if(node == RB_LEFT(RB_PARENT(node))){ RB_LEFT(RB_PARENT(node)) = m; }else{ RB_RIGHT(RB_PARENT(node)) = m; } }else{ if(!RB_RED(m)) rb_fix(c); } }
/* * rb_fix - restore properties of Red-black tree after deleting */ static void rb_fix(void *node){ void *root, *sib; root = RB_LEFT(rb_root); while(!RB_RED(node) && node != root){ if(node == RB_LEFT(RB_PARENT(node))){ sib = RB_RIGHT(RB_PARENT(node)); if(RB_RED(sib)){ RB_RED(sib) = 0; RB_RED(RB_PARENT(node)) = 1; rb_rotate_left(RB_PARENT(node)); sib = RB_RIGHT(RB_PARENT(node)); } if(!RB_RED(RB_RIGHT(sib)) && !RB_RED(RB_LEFT(sib))){ RB_RED(sib) = 1; node = RB_PARENT(node); }else{ if(!RB_RED(RB_RIGHT(sib))){ RB_RED(RB_LEFT(sib)) = 0; RB_RED(sib) = 1; rb_rotate_right(sib); sib = RB_RIGHT(RB_PARENT(node)); } RB_RED(sib) = RB_RED(RB_PARENT(node)); RB_RED(RB_PARENT(node)) = 0; RB_RED(RB_RIGHT(sib)) = 0; rb_rotate_left(RB_PARENT(node)); node = root; } }else{ sib = RB_LEFT(RB_PARENT(node)); if(RB_RED(sib)){ RB_RED(sib) = 0; RB_RED(RB_PARENT(node)) = 1; rb_rotate_right(RB_PARENT(node)); sib = RB_LEFT(RB_PARENT(node)); } if(!RB_RED(RB_RIGHT(sib)) && !RB_RED(RB_LEFT(sib))){ RB_RED(sib) = 1; node = RB_PARENT(node); }else{ if(!RB_RED(RB_LEFT(sib))){ RB_RED(RB_RIGHT(sib)) = 0; RB_RED(sib) = 1; rb_rotate_left(sib); sib = RB_LEFT(RB_PARENT(node)); } RB_RED(sib) = RB_RED(RB_PARENT(node)); RB_RED(RB_PARENT(node)) = 0; RB_RED(RB_LEFT(sib)) = 0; rb_rotate_right(RB_PARENT(node)); node = root; } } } RB_RED(node) = 0; }
int bu_rb_insert(struct bu_rb_tree *tree, void *data) { int nm_orders; int order; int result = 0; struct bu_rb_node *node; struct bu_rb_package *package; struct bu_rb_list *rblp; BU_CKMAG(tree, BU_RB_TREE_MAGIC, "red-black tree"); nm_orders = tree->rbt_nm_orders; /* * Enforce uniqueness * * NOTE: The approach is that for each order that requires * uniqueness, we look for a match. This is not the most * efficient way to do things, since _rb_insert() is just going to * turn around and search the tree all over again. */ for (order = 0; order < nm_orders; ++order) { if (RB_GET_UNIQUENESS(tree, order) && (bu_rb_search(tree, order, data) != NULL)) { if (UNLIKELY(tree->rbt_debug & BU_RB_DEBUG_UNIQ)) bu_log("bu_rb_insert(<%p>, <%p>, TBD) will return %d\n", (void*)tree, (void*)data, -(order + 1)); return -(order + 1); } } /* * Make a new package and add it to the list of all packages. */ BU_ALLOC(package, struct bu_rb_package); package->rbp_node = (struct bu_rb_node **) bu_malloc(nm_orders * sizeof(struct bu_rb_node *), "red-black package nodes"); BU_ALLOC(rblp, struct bu_rb_list); rblp->rbl_magic = BU_RB_LIST_MAGIC; rblp->rbl_package = package; BU_LIST_PUSH(&(tree->rbt_packages.l), rblp); package->rbp_list_pos = rblp; /* * Make a new node and add it to the list of all nodes. */ node = (struct bu_rb_node *) bu_malloc(sizeof(struct bu_rb_node), "red-black node"); node->rbn_parent = (struct bu_rb_node **) bu_malloc(nm_orders * sizeof(struct bu_rb_node *), "red-black parents"); node->rbn_left = (struct bu_rb_node **) bu_malloc(nm_orders * sizeof(struct bu_rb_node *), "red-black left children"); node->rbn_right = (struct bu_rb_node **) bu_malloc(nm_orders * sizeof(struct bu_rb_node *), "red-black right children"); node->rbn_color = (char *) bu_malloc((size_t) lrint(ceil((double) (nm_orders / 8.0))), "red-black colors"); node->rbn_size = (int *) bu_malloc(nm_orders * sizeof(int), "red-black subtree sizes"); node->rbn_package = (struct bu_rb_package **) bu_malloc(nm_orders * sizeof(struct bu_rb_package *), "red-black packages"); BU_ALLOC(rblp, struct bu_rb_list); rblp->rbl_magic = BU_RB_LIST_MAGIC; rblp->rbl_node = node; BU_LIST_PUSH(&(tree->rbt_nodes.l), rblp); node->rbn_list_pos = rblp; /* * Fill in the package */ package->rbp_magic = BU_RB_PKG_MAGIC; package->rbp_data = data; for (order = 0; order < nm_orders; ++order) (package->rbp_node)[order] = node; /* * Fill in the node */ node->rbn_magic = BU_RB_NODE_MAGIC; node->rbn_tree = tree; for (order = 0; order < nm_orders; ++order) (node->rbn_package)[order] = package; node->rbn_pkg_refs = nm_orders; /* * If the tree was empty, install this node as the root and give * it a null parent and null children */ if (RB_ROOT(tree, 0) == RB_NULL(tree)) { for (order = 0; order < nm_orders; ++order) { RB_ROOT(tree, order) = node; RB_PARENT(node, order) = RB_LEFT_CHILD(node, order) = RB_RIGHT_CHILD(node, order) = RB_NULL(tree); RB_SET_COLOR(node, order, RB_BLK); RB_SIZE(node, order) = 1; if (UNLIKELY(tree->rbt_debug & BU_RB_DEBUG_OS)) bu_log("bu_rb_insert(<%p>, <%p>, <%p>): size(%p, %d)=%d\n", (void*)tree, (void*)data, (void*)node, (void*)node, order, RB_SIZE(node, order)); } } else { /* Otherwise, insert the node into the tree */ for (order = 0; order < nm_orders; ++order) result += _rb_insert(tree, order, node); if (UNLIKELY(tree->rbt_debug & BU_RB_DEBUG_UNIQ)) bu_log("bu_rb_insert(<%p>, <%p>, <%p>) will return %d\n", (void*)tree, (void*)data, (void*)node, result); } ++(tree->rbt_nm_nodes); RB_CURRENT(tree) = node; return result; }
/* Note name changed. Guess why :) */ void rb_erase(struct rb_node *elm, struct rb_root *head) { struct rb_node *child, *parent, *old = elm; int color; if (RB_LEFT(elm) == NULL) { child = RB_RIGHT(elm); } else if (RB_RIGHT(elm) == NULL) { child = RB_LEFT(elm); } else { struct rb_node *left; elm = RB_RIGHT(elm); while ((left = RB_LEFT(elm))) { elm = left; } child = RB_RIGHT(elm); parent = RB_PARENT(elm); color = RB_COLOR(elm); if (child) { RB_PARENT(child) = parent; } if (parent) { if (RB_LEFT(parent) == elm) { RB_LEFT(parent) = child; } else { RB_RIGHT(parent) = child; } RB_AUGMENT(parent); } else { RB_HEAD(head) = child; } if (RB_PARENT(elm) == old) { parent = elm; } *(elm) = *(old); if (RB_PARENT(old)) { if (RB_LEFT(RB_PARENT(old)) == old) { RB_LEFT(RB_PARENT(old)) = elm; } else { RB_RIGHT(RB_PARENT(old)) = elm; } RB_AUGMENT(RB_PARENT(old)); } else { RB_HEAD(head) = elm; } RB_PARENT(RB_LEFT(old)) = elm; if (RB_RIGHT(old)) { RB_PARENT(RB_RIGHT(old)) = elm; } if (parent) { left = parent; do { RB_AUGMENT(left); } while ((left = RB_PARENT(left))); } goto color; } parent = RB_PARENT(elm); color = RB_COLOR(elm); if (child) { RB_PARENT(child) = parent; } if (parent) { if (RB_LEFT(parent) == elm) { RB_LEFT(parent) = child; } else { RB_RIGHT(parent) = child; } RB_AUGMENT(parent); } else { RB_HEAD(head) = child; } color: if (color == RB_BLACK) { rb_remove_color(head, parent, child); } }
static void rb_remove_color(struct rb_root *head, struct rb_node *parent, struct rb_node *elm) { struct rb_node *tmp; while ((elm == NULL || RB_COLOR(elm) == RB_BLACK) && elm != RB_HEAD(head)) { if (RB_LEFT(parent) == elm) { tmp = RB_RIGHT(parent); if (RB_COLOR(tmp) == RB_RED) { RB_SET_BLACKRED(tmp, parent); RB_ROTATE_LEFT(head, parent, tmp); tmp = RB_RIGHT(parent); } if ((RB_LEFT(tmp) == NULL || RB_COLOR(RB_LEFT(tmp)) == RB_BLACK) && (RB_RIGHT(tmp) == NULL || RB_COLOR(RB_RIGHT(tmp)) == RB_BLACK)) { RB_COLOR(tmp) = RB_RED; elm = parent; parent = RB_PARENT(elm); } else { if (RB_RIGHT(tmp) == NULL || RB_COLOR(RB_RIGHT(tmp)) == RB_BLACK) { struct rb_node *oleft; if ((oleft = RB_LEFT(tmp))) RB_COLOR(oleft) = RB_BLACK; RB_COLOR(tmp) = RB_RED; RB_ROTATE_RIGHT(head, tmp, oleft); tmp = RB_RIGHT(parent); } RB_COLOR(tmp) = RB_COLOR(parent); RB_COLOR(parent) = RB_BLACK; if (RB_RIGHT(tmp)) RB_COLOR(RB_RIGHT(tmp)) = RB_BLACK; RB_ROTATE_LEFT(head, parent, tmp); elm = RB_HEAD(head); break; } } else { tmp = RB_LEFT(parent); if (RB_COLOR(tmp) == RB_RED) { RB_SET_BLACKRED(tmp, parent); RB_ROTATE_RIGHT(head, parent, tmp); tmp = RB_LEFT(parent); } if ((RB_LEFT(tmp) == NULL || RB_COLOR(RB_LEFT(tmp)) == RB_BLACK) && (RB_RIGHT(tmp) == NULL || RB_COLOR(RB_RIGHT(tmp)) == RB_BLACK)) { RB_COLOR(tmp) = RB_RED; elm = parent; parent = RB_PARENT(elm); } else { if (RB_LEFT(tmp) == NULL || RB_COLOR(RB_LEFT(tmp)) == RB_BLACK) { struct rb_node *oright; if ((oright = RB_RIGHT(tmp))) RB_COLOR(oright) = RB_BLACK; RB_COLOR(tmp) = RB_RED; RB_ROTATE_LEFT(head, tmp, oright); tmp = RB_LEFT(parent); } RB_COLOR(tmp) = RB_COLOR(parent); RB_COLOR(parent) = RB_BLACK; if (RB_LEFT(tmp)) RB_COLOR(RB_LEFT(tmp)) = RB_BLACK; RB_ROTATE_RIGHT(head, parent, tmp); elm = RB_HEAD(head); break; } } } if (elm) RB_COLOR(elm) = RB_BLACK; }
/** * Insert a node into one linear order of a red-black tree * * This function has three parameters: the tree and linear order into * which to insert the new node and the new node itself. If the node * is equal (modulo the linear order) to a node already in the tree, * _rb_insert() returns 1. Otherwise, it returns 0. */ HIDDEN int _rb_insert(struct bu_rb_tree *tree, int order, struct bu_rb_node *new_node) { struct bu_rb_node *node; struct bu_rb_node *parent; struct bu_rb_node *grand_parent; struct bu_rb_node *y; int (*compare)(const void *, const void *); int comparison = 0xdeadbeef; int direction; int result = 0; BU_CKMAG(tree, BU_RB_TREE_MAGIC, "red-black tree"); RB_CKORDER(tree, order); BU_CKMAG(new_node, BU_RB_NODE_MAGIC, "red-black node"); /* * Initialize the new node */ RB_PARENT(new_node, order) = RB_LEFT_CHILD(new_node, order) = RB_RIGHT_CHILD(new_node, order) = RB_NULL(tree); RB_SIZE(new_node, order) = 1; if (UNLIKELY(tree->rbt_debug & BU_RB_DEBUG_OS)) bu_log("_rb_insert(%p): size(%p, %d)=%d\n", (void*)new_node, (void*)new_node, order, RB_SIZE(new_node, order)); /* * Perform vanilla-flavored binary-tree insertion */ parent = RB_NULL(tree); node = RB_ROOT(tree, order); compare = RB_COMPARE_FUNC(tree, order); while (node != RB_NULL(tree)) { parent = node; ++RB_SIZE(parent, order); if (UNLIKELY(tree->rbt_debug & BU_RB_DEBUG_OS)) bu_log("_rb_insert(%p): size(%p, %d)=%d\n", (void*)new_node, (void*)parent, order, RB_SIZE(parent, order)); comparison = compare(RB_DATA(new_node, order), RB_DATA(node, order)); if (comparison < 0) { if (UNLIKELY(tree->rbt_debug & BU_RB_DEBUG_INSERT)) bu_log("_rb_insert(%p): <_%d <%p>, going left\n", (void*)new_node, order, (void*)node); node = RB_LEFT_CHILD(node, order); } else { if (UNLIKELY(tree->rbt_debug & BU_RB_DEBUG_INSERT)) bu_log("_rb_insert(%p): >=_%d <%p>, going right\n", (void*)new_node, order, (void*)node); node = RB_RIGHT_CHILD(node, order); if (comparison == 0) result = 1; } } RB_PARENT(new_node, order) = parent; if (parent == RB_NULL(tree)) RB_ROOT(tree, order) = new_node; else if ((compare(RB_DATA(new_node, order), RB_DATA(parent, order))) < 0) RB_LEFT_CHILD(parent, order) = new_node; else RB_RIGHT_CHILD(parent, order) = new_node; /* * Reestablish the red-black properties, as necessary */ RB_SET_COLOR(new_node, order, RB_RED); node = new_node; parent = RB_PARENT(node, order); grand_parent = RB_PARENT(parent, order); while ((node != RB_ROOT(tree, order)) && (RB_GET_COLOR(parent, order) == RB_RED)) { if (parent == RB_LEFT_CHILD(grand_parent, order)) direction = RB_LEFT; else direction = RB_RIGHT; y = RB_OTHER_CHILD(grand_parent, order, direction); if (RB_GET_COLOR(y, order) == RB_RED) { RB_SET_COLOR(parent, order, RB_BLK); RB_SET_COLOR(y, order, RB_BLK); RB_SET_COLOR(grand_parent, order, RB_RED); node = grand_parent; parent = RB_PARENT(node, order); grand_parent = RB_PARENT(parent, order); } else { if (node == RB_OTHER_CHILD(parent, order, direction)) { node = parent; RB_ROTATE(node, order, direction); parent = RB_PARENT(node, order); grand_parent = RB_PARENT(parent, order); } RB_SET_COLOR(parent, order, RB_BLK); RB_SET_COLOR(grand_parent, order, RB_RED); RB_OTHER_ROTATE(grand_parent, order, direction); } } RB_SET_COLOR(RB_ROOT(tree, order), order, RB_BLK); if (UNLIKELY(tree->rbt_debug & BU_RB_DEBUG_INSERT)) bu_log("_rb_insert(%p): comparison = %d, returning %d\n", (void*)new_node, comparison, result); return result; }