📄 rbt.c
字号:
node = oldtable[i]; while (node != NULL) { hash = HASHVAL(node) % rbt->hashsize; oldtable[i] = HASHNEXT(node); HASHNEXT(node) = rbt->hashtable[hash]; rbt->hashtable[hash] = node; node = oldtable[i]; } } isc_mem_put(rbt->mctx, oldtable, oldsize * sizeof(dns_rbtnode_t *));}static inline voidhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) { REQUIRE(DNS_RBTNODE_VALID(node)); if (rbt->nodecount >= (rbt->hashsize *3)) rehash(rbt); hash_add_node(rbt, node);}static inline voidunhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) { unsigned int bucket; dns_rbtnode_t *bucket_node; REQUIRE(DNS_RBTNODE_VALID(node)); if (rbt->hashtable != NULL) { bucket = HASHVAL(node) % rbt->hashsize; bucket_node = rbt->hashtable[bucket]; if (bucket_node == node) rbt->hashtable[bucket] = HASHNEXT(node); else { while (HASHNEXT(bucket_node) != node) { INSIST(HASHNEXT(bucket_node) != NULL); bucket_node = HASHNEXT(bucket_node); } HASHNEXT(bucket_node) = HASHNEXT(node); } }}#endif /* DNS_RBT_USEHASH */static inline voidrotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp) { dns_rbtnode_t *child; REQUIRE(DNS_RBTNODE_VALID(node)); REQUIRE(rootp != NULL); child = RIGHT(node); INSIST(child != NULL); RIGHT(node) = LEFT(child); if (LEFT(child) != NULL) PARENT(LEFT(child)) = node; LEFT(child) = node; if (child != NULL) PARENT(child) = PARENT(node); if (IS_ROOT(node)) { *rootp = child; child->is_root = 1; node->is_root = 0; } else { if (LEFT(PARENT(node)) == node) LEFT(PARENT(node)) = child; else RIGHT(PARENT(node)) = child; } PARENT(node) = child;}static inline voidrotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp) { dns_rbtnode_t *child; REQUIRE(DNS_RBTNODE_VALID(node)); REQUIRE(rootp != NULL); child = LEFT(node); INSIST(child != NULL); LEFT(node) = RIGHT(child); if (RIGHT(child) != NULL) PARENT(RIGHT(child)) = node; RIGHT(child) = node; if (child != NULL) PARENT(child) = PARENT(node); if (IS_ROOT(node)) { *rootp = child; child->is_root = 1; node->is_root = 0; } else { if (LEFT(PARENT(node)) == node) LEFT(PARENT(node)) = child; else RIGHT(PARENT(node)) = child; } PARENT(node) = child;}/* * This is the real workhorse of the insertion code, because it does the * true red/black tree on a single level. */static voiddns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order, dns_rbtnode_t **rootp){ dns_rbtnode_t *child, *root, *parent, *grandparent; dns_name_t add_name, current_name; dns_offsets_t add_offsets, current_offsets; REQUIRE(rootp != NULL); REQUIRE(DNS_RBTNODE_VALID(node) && LEFT(node) == NULL && RIGHT(node) == NULL); REQUIRE(current != NULL); root = *rootp; if (root == NULL) { /* * First node of a level. */ MAKE_BLACK(node); node->is_root = 1; PARENT(node) = current; *rootp = node; return; } child = root; dns_name_init(&add_name, add_offsets); NODENAME(node, &add_name); dns_name_init(¤t_name, current_offsets); NODENAME(current, ¤t_name); if (order < 0) { INSIST(LEFT(current) == NULL); LEFT(current) = node; } else { INSIST(RIGHT(current) == NULL); RIGHT(current) = node; } INSIST(PARENT(node) == NULL); PARENT(node) = current; MAKE_RED(node); while (node != root && IS_RED(PARENT(node))) { /* * XXXDCL could do away with separate parent and grandparent * variables. They are vestiges of the days before parent * pointers. However, they make the code a little clearer. */ parent = PARENT(node); grandparent = PARENT(parent); if (parent == LEFT(grandparent)) { child = RIGHT(grandparent); if (child != NULL && IS_RED(child)) { MAKE_BLACK(parent); MAKE_BLACK(child); MAKE_RED(grandparent); node = grandparent; } else { if (node == RIGHT(parent)) { rotate_left(parent, &root); node = parent; parent = PARENT(node); grandparent = PARENT(parent); } MAKE_BLACK(parent); MAKE_RED(grandparent); rotate_right(grandparent, &root); } } else { child = LEFT(grandparent); if (child != NULL && IS_RED(child)) { MAKE_BLACK(parent); MAKE_BLACK(child); MAKE_RED(grandparent); node = grandparent; } else { if (node == LEFT(parent)) { rotate_right(parent, &root); node = parent; parent = PARENT(node); grandparent = PARENT(parent); } MAKE_BLACK(parent); MAKE_RED(grandparent); rotate_left(grandparent, &root); } } } MAKE_BLACK(root); ENSURE(IS_ROOT(root)); *rootp = root; return;}/* * This is the real workhorse of the deletion code, because it does the * true red/black tree on a single level. */static voiddns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) { dns_rbtnode_t *child, *sibling, *parent; dns_rbtnode_t *successor; REQUIRE(delete != NULL); /* * Verify that the parent history is (apparently) correct. */ INSIST((IS_ROOT(delete) && *rootp == delete) || (! IS_ROOT(delete) && (LEFT(PARENT(delete)) == delete || RIGHT(PARENT(delete)) == delete))); child = NULL; if (LEFT(delete) == NULL) { if (RIGHT(delete) == NULL) { if (IS_ROOT(delete)) { /* * This is the only item in the tree. */ *rootp = NULL; return; } } else /* * This node has one child, on the right. */ child = RIGHT(delete); } else if (RIGHT(delete) == NULL) /* * This node has one child, on the left. */ child = LEFT(delete); else { dns_rbtnode_t holder, *tmp = &holder; /* * This node has two children, so it cannot be directly * deleted. Find its immediate in-order successor and * move it to this location, then do the deletion at the * old site of the successor. */ successor = RIGHT(delete); while (LEFT(successor) != NULL) successor = LEFT(successor); /* * The successor cannot possibly have a left child; * if there is any child, it is on the right. */ if (RIGHT(successor) != NULL) child = RIGHT(successor); /* * Swap the two nodes; it would be simpler to just replace * the value being deleted with that of the successor, * but this rigamarole is done so the caller has complete * control over the pointers (and memory allocation) of * all of nodes. If just the key value were removed from * the tree, the pointer to the node would be unchanged. */ /* * First, put the successor in the tree location of the * node to be deleted. Save its existing tree pointer * information, which will be needed when linking up * delete to the successor's old location. */ memcpy(tmp, successor, sizeof(dns_rbtnode_t)); if (IS_ROOT(delete)) { *rootp = successor; successor->is_root = ISC_TRUE; delete->is_root = ISC_FALSE; } else if (LEFT(PARENT(delete)) == delete) LEFT(PARENT(delete)) = successor; else RIGHT(PARENT(delete)) = successor; PARENT(successor) = PARENT(delete); LEFT(successor) = LEFT(delete); RIGHT(successor) = RIGHT(delete); COLOR(successor) = COLOR(delete); if (LEFT(successor) != NULL) PARENT(LEFT(successor)) = successor; if (RIGHT(successor) != successor) PARENT(RIGHT(successor)) = successor; /* * Now relink the node to be deleted into the * successor's previous tree location. PARENT(tmp) * is the successor's original parent. */ INSIST(! IS_ROOT(delete)); if (PARENT(tmp) == delete) { /* * Node being deleted was successor's parent. */ RIGHT(successor) = delete; PARENT(delete) = successor; } else { LEFT(PARENT(tmp)) = delete; PARENT(delete) = PARENT(tmp); } /* * Original location of successor node has no left. */ LEFT(delete) = NULL; RIGHT(delete) = RIGHT(tmp); COLOR(delete) = COLOR(tmp); } /* * Remove the node by removing the links from its parent. */ if (! IS_ROOT(delete)) { if (LEFT(PARENT(delete)) == delete) LEFT(PARENT(delete)) = child; else RIGHT(PARENT(delete)) = child; if (child != NULL) PARENT(child) = PARENT(delete); } else { /* * This is the root being deleted, and at this point * it is known to have just one child. */ *rootp = child; child->is_root = 1; PARENT(child) = PARENT(delete); } /* * Fix color violations. */ if (IS_BLACK(delete)) { parent = PARENT(delete); while (child != *rootp && IS_BLACK(child)) { INSIST(child == NULL || ! IS_ROOT(child)); if (LEFT(parent) == child) { sibling = RIGHT(parent); if (IS_RED(sibling)) { MAKE_BLACK(sibling); MAKE_RED(parent); rotate_left(parent, rootp); sibling = RIGHT(parent); } if (IS_BLACK(LEFT(sibling)) && IS_BLACK(RIGHT(sibling))) { MAKE_RED(sibling); child = parent; } else { if (IS_BLACK(RIGHT(sibling))) { MAKE_BLACK(LEFT(sibling)); MAKE_RED(sibling); rotate_right(sibling, rootp); sibling = RIGHT(parent); } COLOR(sibling) = COLOR(parent); MAKE_BLACK(parent); MAKE_BLACK(RIGHT(sibling)); rotate_left(parent, rootp); child = *rootp; } } else { /* * Child is parent's right child. * Everything is doen the same as above, * except mirrored. */ sibling = LEFT(parent); if (IS_RED(sibling)) { MAKE_BLACK(sibling); MAKE_RED(parent); rotate_right(parent, rootp); sibling = LEFT(parent); } if (IS_BLACK(LEFT(sibling)) && IS_BLACK(RIGHT(sibling))) { MAKE_RED(sibling); child = parent; } else { if (IS_BLACK(LEFT(sibling))) { MAKE_BLACK(RIGHT(sibling)); MAKE_RED(sibling); rotate_left(sibling, rootp); sibling = LEFT(parent); } COLOR(sibling) = COLOR(parent); MAKE_BLACK(parent); MAKE_BLACK(LEFT(sibling)); rotate_right(parent, rootp); child = *rootp; } } parent = PARENT(child); } if (IS_RED(child)) MAKE_BLACK(child); }}/* * This should only be used on the root of a tree, because no color fixup * is done at all. * * NOTE: No root pointer maintenance is done, because the function is only * used for two cases: * + deleting everything DOWN from a node that is itself being deleted, and * + deleting the entire tree of trees from dns_rbt_destroy. * In each case, the root pointer is no longer relevant, so there * is no need for a root parameter to this function. * * If the function is ever intended to be used to delete something where * a pointer needs to be told that this tree no longer exists, * this function would need to adjusted accordingly. */static isc_result_tdns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node) { isc_result_t result = ISC_R_SUCCESS; REQUIRE(VALID_RBT(rbt)); if (node == NULL) return (result); if (LEFT(node) != NULL) { result = dns_rbt_deletetree(rbt, LEFT(node)); if (result != ISC_R_SUCCESS) goto done; LEFT(node) = NULL; } if (RIGHT(node) != NULL) { result = dns_rbt_deletetree(rbt, RIGHT(node)); if (result != ISC_R_SUCCESS) goto done; RIGHT(node) = NULL; } if (DOWN(node) != NULL) { result = dns_rbt_deletetree(rbt, DOWN(node)); if (result != ISC_R_SUCCESS) goto done; DOWN(node) = NULL; } done: if (result != ISC_R_SUCCESS) return (result); if (rbt->quantum != 0 && --rbt->quantum == 0) return (ISC_R_QUOTA); if (DATA(node) != NULL && rbt->data_deleter != NULL) rbt->data_deleter(DATA(node), rbt->deleter_arg); unhash_node(rbt, node);#if DNS_RBT_USEMAGIC node->magic = 0;#endif isc_mem_put(rbt->mctx, node, NODE_SIZE(node)); rbt->nodecount--; return (result);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -