/* * Copyright (c) 2019 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Algorithm from: * Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2009). * Introduction to algorithms. MIT press, 3rd Edition, Ch. 13 */ #include static inline void rb_tree_rotate_left (rb_tree_t * rt, rb_node_t * x) { rb_node_t *y, *tmp, *xp; rb_node_index_t xi, yi; xi = rb_node_index (rt, x); yi = x->right; y = rb_node_right (rt, x); x->right = y->left; if (y->left != RBTREE_TNIL_INDEX) { tmp = rb_node_left (rt, y); tmp->parent = xi; } xp = rb_node_parent (rt, x); y->parent = x->parent; if (x->parent == RBTREE_TNIL_INDEX) rt->root = rb_node_index (rt, y); else if (xp->left == xi) xp->left = yi; else xp->right = yi; y->left = xi; x->parent = yi; } static inline void rb_tree_rotate_right (rb_tree_t * rt, rb_node_t * y) { rb_node_index_t yi, xi; rb_node_t *x, *yp; yi = rb_node_index (rt, y); xi = y->left; x = rb_node_left (rt, y); y->left = x->right; if (x->right != RBTREE_TNIL_INDEX) { rb_node_t *tmp = rb_node_right (rt, x); tmp->parent = yi; } yp = rb_node_parent (rt, y); x->parent = y->parent; if (y->parent == RBTREE_TNIL_INDEX) rt->root = rb_node_index (rt, x); else if (yp->right == yi) yp->right = xi; else yp->left = xi; x->right = yi; y->parent = xi; } static inline void rb_tree_fixup_inline (rb_tree_t * rt, rb_node_t * y, rb_node_t * z) { rb_node_t *zpp, *zp; rb_node_index_t zi; while (y->color == RBTREE_RED) { zi = rb_node_index (rt, z); zp = rb_node_parent (rt, z); zpp = rb_node_parent (rt, zp); if (z->parent == zpp->left) { y = rb_node_right (rt, zpp); if (y->color == RBTREE_RED) { zp->color = RBTREE_BLACK; y->color = RBTREE_BLACK; zpp->color = RBTREE_RED; z = zpp; } else { if (zi == zp->right) { z = zp; rb_tree_rotate_left (rt, z); zp = rb_node (rt, z->parent); zpp = rb_node (rt, zp->parent); } zp->color = RBTREE_BLACK; zpp->color = RBTREE_RED; rb_tree_rotate_right (rt, zpp); } } else { y = rb_node (rt, zpp->left); if (y->color == RBTREE_RED) { zp->color = RBTREE_BLACK; y->color = RBTREE_BLACK; zpp->color = RBTREE_RED; z = zpp; } else { if (zi == zp->left) { z = zp; rb_tree_rotate_right (rt, z); zp = rb_node (rt, z->parent); zpp = rb_node (rt, zp->parent); } zp->color = RBTREE_BLACK; zpp->color = RBTREE_RED; rb_tree_rotate_left (rt, zpp); } } } rb_node (rt, rt->root)->color = RBTREE_BLACK; } static void rb_tree_insert (rb_tree_t * rt, rb_node_t * z) { rb_node_index_t yi = 0, xi = rt->root; rb_node_t *y, *x; y = rb_node (rt, RBTREE_TNIL_INDEX); while (xi != RBTREE_TNIL_INDEX) { x = rb_node (rt, xi); y = x; if (z->key < x->key) xi = x->left; else xi = x->right; } yi = rb_node_index (rt, y); z->parent = yi; if (yi == RBTREE_TNIL_INDEX) rt->root = rb_node_index (rt, z); else if (z->key < y->key) y->left = rb_node_index (rt, z); else y->right = rb_node_index (rt, z); /* Tree fixup stage */ rb_tree_fixup_inline (rt, y, z); } rb_node_index_t rb_tree_add (rb_tree_t * rt, u32 key) { rb_node_t *n; pool_get_zero (rt->nodes, n); n->key = key; n->color = RBTREE_RED; rb_tree_insert (rt, n); return rb_node_index (rt, n); } rb_node_index_t rb_tree_add2 (rb_tree_t * rt, u32 key, uword opaque) { rb_node_t *n; pool_get_zero (rt->nodes, n); n->key = key; n->color = RBTREE_RED; n->opaque = opaque; rb_tree_insert (rt, n); return rb_node_index (rt, n); } rb_node_index_t rb_tree_add_custom (rb_tree_t * rt, u32 key, uword opaque, rb_tree_lt_fn ltfn) { rb_node_index_t yi = 0, xi = rt->root; rb_node_t *z, *y, *x; pool_get_zero (rt->nodes, z); z->key = key; z->color = RBTREE_RED; z->opaque = opaque; y = rb_node (rt, RBTREE_TNIL_INDEX); while (xi != RBTREE_TNIL_INDEX) { x = rb_node (rt, xi); y = x; if (ltfn (z->key, x->key)) xi = x->left; else xi = x->right; } yi = rb_node_index (rt, y); z->parent = yi; if (yi == RBTREE_TNIL_INDEX) rt->root = rb_node_index (rt, z); else if (ltfn (z->key, y->key)) y->left = rb_node_index (rt, z); else y->right = rb_node_index (rt, z); rb_tree_fixup_inline (rt, y, z); return rb_node_index (rt, z); } rb_node_t * rb_tree_search_subtree (rb_tree_t * rt, rb_node_t * x, u32 key) { while (rb_node_index (rt, x) != RBTREE_TNIL_INDEX && key != x->key) if (key < x->key) x = rb_node_left (rt, x); else x = rb_node_right (rt, x); return x; } rb_node_t * rb_tree_search_subtree_custom (rb_tree_t * rt, rb_node_t * x, u32 key, rb_tree_lt_fn ltfn) { while (rb_node_index (rt, x) != RBTREE_TNIL_INDEX && key != x->key) if (ltfn (key, x->key)) x = rb_node_left (rt, x); else x = rb_node_right (rt, x); return x; } rb_node_t * rb_tree_min_subtree (rb_tree_t * rt, rb_node_t * x) { while (x->left != RBTREE_TNIL_INDEX) x = rb_node_left (rt, x); return x; } rb_node_t * rb_tree_max_subtree (rb_tree_t * rt, rb_node_t * x) { while (x->right != RBTREE_TNIL_INDEX) x = rb_node_right (rt, x); return x; } rb_node_t * rb_tree_successor (rb_tree_t * rt, rb_node_t * x) { rb_node_t *y; if (x->right != RBTREE_TNIL_INDEX) return rb_tree_min_subtree (rt, rb_node_right (rt, x)); y = rb_node_parent (rt, x); while (!rb_node_is_tnil (rt, y) && y->right == rb_node_index (rt, x)) { x = y; y = rb_node_parent (rt, y); } return y; } rb_node_t * rb_tree_predecessor (rb_tree_t * rt, rb_node_t * x) { rb_node_t *y; if (x->left != RBTREE_TNIL_INDEX) return rb_tree_max_subtree (rt, rb_node_left (rt, x)); y = rb_node_parent (rt, x); while (!rb_node_is_tnil (rt, y) && y->left == rb_node_index (rt, x))