/* * Copyright (c) 2019 LK Trusty Authors. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include /** * bst_node_rank - Internal helper function * @node: Node to check. * * Return: Rank of @node or 0 if @node is %NULL. */ static size_t bst_node_rank(struct bst_node *node) { return node ? node->rank : 0; } /** * bst_is_right_child - Internal helper function * @node: Node to check. * * Return: %true if @node is the right child of @node->parent. %false if * @node->parent is %NULL or if @node is the left child of * @node->parent. */ static bool bst_is_right_child(struct bst_node *node) { DEBUG_ASSERT(node); DEBUG_ASSERT(!node->parent || node->parent->child[0] == node || node->parent->child[1] == node); return node->parent && node->parent->child[1] == node; } /** * bst_parent_ptr - Internal helper function * @root: Tree. * @node: Node in @root. * * Return: Pointer where @node is linked in the tree. If @node is the root node * this is &root->root, otherwise it is the address of child pointer in the * parent node of @node that points to @node. */ static struct bst_node **bst_parent_ptr(struct bst_root *root, struct bst_node *node) { DEBUG_ASSERT(root); DEBUG_ASSERT(node); struct bst_node **parent_ptr = node->parent ? &node->parent->child[bst_is_right_child(node)] : &root->root; DEBUG_ASSERT(*parent_ptr == node); return parent_ptr; } /** * bst_link_node - Internal helper function * @parent: Target node. * @is_right_child: Index of child to set. * @child: New child node. * * Set child node in @parent. If @child is not %NULL, update it to point to * @parent. */ static void bst_link_node(struct bst_node *parent, bool is_right_child, struct bst_node *child) { parent->child[is_right_child] = child; if (child) { child->parent = parent; } } /** * bst_move_node - Internal helper function * @root: Tree. * @old_node: Node to unlink. * @new_node: Node to link where @old_node was. * * Replace node in @root at @old_node with @new_node. */ static void bst_move_node(struct bst_root *root, struct bst_node *old_node, struct bst_node *new_node) { DEBUG_ASSERT(root); DEBUG_ASSERT(old_node); *bst_parent_ptr(root, old_node) = new_node; if (new_node) { new_node->parent = old_node->parent; } old_node->parent = NULL; } /** * bst_rotate - Internal helper function * @root: Tree. * @up: Node to move up. * @down: Node to move down. * @up_was_right_child: %true if @up was the right child of @down. * * Swap nodes @up and @down (pictured for up_was_right_child==false): * * down up * / \ / \ * up C A down * / \ / \ * A B B C * * Caller is responsible for updating the rank of the moved nodes. */ static void bst_rotate(struct bst_root *root, struct bst_node *up, struct bst_node *down, bool up_was_right_child) { DEBUG_ASSERT(down->child[up_was_right_child] == up); struct bst_node *move_subtree = up->child[!up_was_right_child]; bst_move_node(root, down, up); bst_link_node(down, up_was_right_child, move_subtree); bst_link_node(up, !up_was_right_child, down); } /** * bst_rotate_insert - Internal helper function * @root: Tree. * @up1: Node to move up if a single rotate is enough. * @down: Node to move down. * @up_was_right_child: %true if @up1 was the right child of @down. * * Rotate sub-tree (once or twice) after insert and update ranks. */ static void bst_rotate_insert(struct bst_root *root, struct bst_node *up1, struct bst_node *down, bool up_was_right_child) { DEBUG_ASSERT(down->child[up_was_right_child] == up1); DEBUG_ASSERT(up1->rank == down->rank); DEBUG_ASSERT(down->rank >= bst_node_rank(down->child[!up_was_right_child]) + 2); struct bst_node *up2 = up1->child[!up_was_right_child]; if (bst_node_rank(up2) >= down->rank - 1) { DEBUG_ASSERT(bst_node_rank(up2) == down->rank - 1); /* * Swap nodes @up2 and @up1 then @up2 and @down * (pictured for up_was_right_child==false): * * down down up2 * / \ / \ / \ * up1 D up2 D up1 down * / \ / \ / \ / \ * A up2 up1 C A B C D * / \ / \ * B C A B */ up2->rank++; DEBUG_ASSERT(up1->rank == up2->rank); bst_rotate(root, up2, up1, !up_was_right_child); up1->rank--; bst_rotate(root, up2, down, up_was_right_child); down->rank--; } else { /* * Swap nodes @up1 and @down (pictured for up_was_right_child==false): * * down up1 * / \ / \ * up1 C A down * / \ / \ * A B B C */ bst_rotate(root, up1, down, up_was_right_child); down->rank--; } } /** * bst_update_rank_insert - Internal helper function * @root: Tree. * @node: Node to start scan at. * * Promote nodes and/or rotate sub-trees to make @root a valid WAVL tree again. */ void bst_update_rank_insert(struct bst_root *root, struct bst_node *node) { size_t rank; DEBUG_ASSERT(root); DEBUG_ASSERT(node); DEBUG_ASSERT(node->rank == 1); /* Inserted node must have rank 1 */ while (node) { bool is_right_child = bst_is_right_child(node); /* * At this point the rank of @node is 1 greater than it was before the * insert. * * For the tree to be valid, the parent of any node is allowed to a * rank 1 or 2 greater than its child nodes. Assuming the tree was valid * before the insert, the @node->parent currently has the same rank as * @node or it has a rank one grater than the rank of @node. Incremeting * the rank @node->parent to be 2 greater than the rank of @node would * be unnecessary as it could not have had that rank already. Leaving * the rank of @node->parent at the same rank as @node would result in * en invalid tree. That means that the rank of @node->parent should now * be 1 greater than the rank of @node (if that is possible). */ rank = node->rank + 1; node = node->parent; if (!node || node->rank >= rank) { DEBUG_ASSERT(!node || node->rank == rank); /* * Stop updating if we have reached the root, or a node that already * has a rank greater than the node child node we inserted or * updated as the tree is now valid. */ return; } DEBUG_ASSERT(node->rank + 1 == rank); if (bst_node_rank(node->child[!is_right_child]) + 2 < rank) { /* * Rank of @node cannot be incremented. This means it can be moved * down and demoted instead. * * The tree can be rotated as pictured below. (a is @node which * could not be promoted. Numbers are known relative ranks.) * * If rank of c is 2 less than the rank of a (b is inserted or * promoted node): * * a2 b2 * / \ / \ * b2 D0 => A a1 * / \ / \ * A c0 c0 D0 * / \ / \ * B C B C * * If rank of c is 1 less than the rank of a (b is promoted node, c * is inserted or promoted node): * a2 a2 __c2__ * / \ / \ / \ * b2 D0 c2 D0 b1 a1 * / \ => / \ => / \ / \ * A0 c1 b1 C A0 B C D0 * / \ / \ * B C A0 B */ bst_rotate_insert(root, node->child[is_right_child], node, is_right_child); return; } node->rank = rank; } } /** * bst_rotate_delete - Internal helper function * @root: Tree. * @up1: Node to move up if a single rotate is enough. * @down: Node to move down. * @up_was_right_child: %true if @up1 was the right child of @down. * * Rotate sub-tree (once or twice) after delete and update ranks. */ static void bst_rotate_delete(struct bst_root *root, struct bst_node *up1, struct bst_node *down, bool up_was_right_child) { DEBUG_ASSERT(down->child[up_was_right_child] == up1); DEBUG_ASSERT(up1->rank == down->rank - 1); DEBUG_ASSERT(down->rank == bst_node_rank(down->child[!up_was_right_child]) + 3); struct bst_node *up2 = up1->child[!up_was_right_child]; if (bst_node_rank(up1->child[up_was_right_child]) <= down->rank - 3) { DEBUG_ASSERT(bst_node_rank(up2) == down->rank - 2); /* * Swap nodes @up2 and @up1 then @up2 and @down * (pictured for up_was_right_child==false): * * down(0) down up2(0) * / \ / \ / \ * up1(-1) D(-3) up2 D up1(-2) down(-2) * / \ / \ / \ / \ * A(-3) up2(-2) up1 C A(-3) B C D(-3) * / \ / \ * B C A(-3) B */ DEBUG_ASSERT(up1->rank == down->rank - 1); DEBUG_ASSERT(up2->rank == down->rank - 2); bst_rotate(root, up2, up1, !up_was_right_child); bst_rotate(root, up2, down, up_was_right_child); up2->rank += 2; up1->rank--; down->rank -= 2; } else { /* * Swap nodes @up1 and @down (pictured for up_was_right_child==false): * * down(0) up1(0) * / \ / \ * up1(-1) C(-3) A(-2) down(-1) * / \ / \ * A(-2) B(-2/-3) B(-2/-3) C(-3) */ bst_rotate(root, up1, down, up_was_right_child); up1->rank++; down->rank--; if (bst_node_rank(down->child[0]) == down->rank - 2 && bst_node_rank(down->child[1]) == down->rank - 2) { /* Demote down if possible. (Required if down is a leaf node) */ down->rank--; } } } /** * bst_update_rank_delete - Internal helper function * @root: Tree. * @node: Node to start scan at. This is the parent of the node that * was removed from the tree. Note that the removed node will * be a different node than the node passed to bst_delete if * that node had two children. * @is_right_child: %true if the right child of @node was deleted. * * Demote nodes and/or rotate sub-trees to make @root a valid WAVL tree again. */ static void bst_update_rank_delete(struct bst_root *root, struct bst_node *node, bool is_right_child) { DEBUG_ASSERT(root); DEBUG_ASSERT(node); DEBUG_ASSERT(bst_node_rank(node->child[is_right_child]) <= bst_node_rank(node->child[!is_right_child])); while (node) { DEBUG_ASSERT(node->rank > bst_node_rank(node->child[!is_right_child])); DEBUG_ASSERT(node->rank - 1 > bst_node_rank(node->child[is_right_child])); DEBUG_ASSERT(node->rank <= bst_node_rank(node->child[!is_right_child]) + 2); /* * At this point the rank of @node->child[is_right_child] has been * decremented. We may need to also decrement the rank of @node. */ if (!node->child[0] && !node->child[1]) { /* Always demote leaf node (from 2 to 1) */ /* We should not be in this function if the rank is alrady 1 */ DEBUG_ASSERT(node->rank == 2); } else if (node->rank <= bst_node_rank(node->child[is_right_child]) + 2) { /* * If rank of @node does not need to change then we now have a valid * tree. */ return; } DEBUG_ASSERT(node->rank > 1); node->rank--; if (node->rank <= bst_node_rank(node->child[!is_right_child])) { /* We demoted @node, but it is now invalid on the other side */ DEBUG_ASSERT(node->rank == bst_node_rank(node->child[!is_right_child])); if (bst_node_rank(node->child[!is_right_child]->child[0]) == node->rank - 2 && bst_node_rank(node->child[!is_right_child]->child[1]) == node->rank - 2) { /* If the other child can be demoted, demote it and move up */ node->child[!is_right_child]->rank--; } else { /* * If the other child can not be demoted, rotate instead. This * will produce a valid tree without changing the rank of the * node linked at the current spot @node in the tree. * * Undo demotion as current bst_rotate_delete implemention * assumes node rank is unchanged. */ node->rank++; bst_rotate_delete(root, node->child[!is_right_child], node, !is_right_child); return; } } is_right_child = bst_is_right_child(node); node = node->parent; } } /** * bst_find_edge - Internal helper function * @node: Node to start search at. * @edge: Direction if search. * * Return: leftmost (if @edge is %false) or rightmost (if @edge is %true) node * in subtree with @node as root. */ static struct bst_node *bst_find_edge(struct bst_node *node, bool edge) { struct bst_node *saved_node; DEBUG_ASSERT(node); do { saved_node = node; node = node->child[edge]; } while (node); return saved_node; } /** * bst_delete_all_helper - Internal helper function * @root: Tree. * @node: Node to delete (most be the leftmost node in @root). * * Helper function to delete leftmost node in @root, assuming all other nodes * will be deleted next. */ void bst_delete_all_helper(struct bst_root *root, struct bst_node *node) { DEBUG_ASSERT(root); DEBUG_ASSERT(node); DEBUG_ASSERT(!node->child[0]); bst_move_node(root, node, node->child[1]); } void bst_delete(struct bst_root *root, struct bst_node *node) { DEBUG_ASSERT(root); DEBUG_ASSERT(node); struct bst_node *new_child; bool node_is_right_child = bst_is_right_child(node); struct bst_node *update_rank_start = node->parent; bool update_rank_is_right_child = node_is_right_child; if (!node->child[0]) { /* * If @node has no left child, link its right child in its place. (The * right child could be %NULL in this case) */ new_child = node->child[1]; } else if (!node->child[1]) { /* * If @node has no right child, link its left child in its place. */ DEBUG_ASSERT(node->child[0]); new_child = node->child[0]; } else { /* * If @node has both left and right children, delete (from the tree * structure point of view) the left-most node in the right sub-tree or * the right-most node in the left sub-tree instead. Either side would * work. */ struct bst_node *edge_node = bst_find_edge( node->child[!node_is_right_child], node_is_right_child); struct bst_node *edge_child = edge_node->child[!node_is_right_child]; update_rank_start = edge_node->parent; update_rank_is_right_child = bst_is_right_child(edge_node); if (update_rank_start == node) { update_rank_start = edge_node; update_rank_is_right_child = !node_is_right_child; } DEBUG_ASSERT(update_rank_start); bst_move_node(root, edge_node, edge_child); new_child = edge_node; DEBUG_ASSERT(new_child); bst_link_node(new_child, 0, node->child[0]); bst_link_node(new_child, 1, node->child[1]); new_child->rank = node->rank; } bst_move_node(root, node, new_child); node->rank = 0; if (update_rank_start) { bst_update_rank_delete(root, update_rank_start, update_rank_is_right_child); } } /** * bst_prev_next - Internal helper function * @root: Tree. * @node: Node to move from. * @dir_next: Directon to move. * * Return: If @node is %NULL and @dir_next is %false, right-most node in @root. * If @node is %NULL and @dir_next is %true, left-most node in @root. * If @node is not %NULL and @dir_next is %false, right-most node to the * left of @node. * If @node is not %NULL and @dir_next is %true, left-most node to the * right of @node. * %NULL if the node described above does not exist. */ static struct bst_node *bst_prev_next(const struct bst_root *root, struct bst_node *node, bool dir_next) { DEBUG_ASSERT(root); struct bst_node *next_child = node ? node->child[dir_next] : root->root; if (!node && !next_child) { return NULL; /* Empty tree */ } /* * Comments below assume @dir_next is %true. For the @dir_next is %false * case, swap left and right. */ if (next_child) { /* There is a right child, return the left-most node in that subtree */ return bst_find_edge(next_child, !dir_next); } else { /* No right child, next node is the first right parent */ struct bst_node *next_parent = node; while (bst_is_right_child(next_parent) == dir_next) { next_parent = next_parent->parent; if (!next_parent) { return NULL; } } return next_parent->parent; } } struct bst_node *bst_prev(struct bst_root *root, struct bst_node *node) { return bst_prev_next(root, node, false); } struct bst_node *bst_next(const struct bst_root *root, struct bst_node *node) { return bst_prev_next(root, node, true); }