| /* SPDX-License-Identifier: BSD-2-Clause */ |
| /* Copyright 1996-2020 The NASM Authors - All Rights Reserved */ |
| |
| /* |
| * rbtree.c |
| * |
| * Simple implementation of a "left-leaning threaded red-black tree" |
| * with 64-bit integer keys. The search operation will return the |
| * highest node <= the key; only search and insert are supported, but |
| * additional standard llrbtree operations can be coded up at will. |
| * |
| * See http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf for |
| * information about left-leaning red-black trees. |
| * |
| * The "threaded" part means that left and right pointers that would |
| * otherwise be NULL are pointers to the in-order predecessor or |
| * successor node. The only pointers that are NULL are the very left- |
| * and rightmost, for which no corresponding side node exists. |
| * |
| * This, among other things, allows for efficient predecessor and |
| * successor operations without requiring dedicated space for a parent |
| * pointer. |
| * |
| * This implementation is robust for identical key values; such keys |
| * will not have their insertion order preserved, and after insertion |
| * of unrelated keys a lookup may return a different node for the |
| * duplicated key, but the prev/next operations will always enumerate |
| * all entries. |
| * |
| * The NULL pointers at the end are considered predecessor/successor |
| * pointers, so if the corresponding flags are clear it is always safe |
| * to access the pointed-to object without an explicit NULL pointer |
| * check. |
| */ |
| |
| #include "rbtree.h" |
| #include "nasmlib.h" |
| |
| struct rbtree *rb_search(const struct rbtree *tree, uint64_t key) |
| { |
| const struct rbtree *best = NULL; |
| |
| if (tree) { |
| while (true) { |
| if (tree->key > key) { |
| if (tree->m.flags & RBTREE_NODE_PRED) |
| break; |
| tree = tree->m.left; |
| } else { |
| best = tree; |
| if (tree->key == key || (tree->m.flags & RBTREE_NODE_SUCC)) |
| break; |
| tree = tree->m.right; |
| } |
| } |
| } |
| return (struct rbtree *)best; |
| } |
| |
| struct rbtree *rb_search_exact(const struct rbtree *tree, uint64_t key) |
| { |
| struct rbtree *rv; |
| |
| rv = rb_search(tree, key); |
| return (rv && rv->key == key) ? rv : NULL; |
| } |
| |
| /* Reds two left in a row? */ |
| static inline bool is_red_left_left(struct rbtree *h) |
| { |
| return !(h->m.flags & RBTREE_NODE_PRED) && |
| !(h->m.left->m.flags & (RBTREE_NODE_BLACK|RBTREE_NODE_PRED)) && |
| !(h->m.left->m.left->m.flags & RBTREE_NODE_BLACK); |
| } |
| |
| /* Node to the right is red? */ |
| static inline bool is_red_right(struct rbtree *h) |
| { |
| return !(h->m.flags & RBTREE_NODE_SUCC) && |
| !(h->m.right->m.flags & RBTREE_NODE_BLACK); |
| } |
| |
| /* Both the left and right hand nodes are red? */ |
| static inline bool is_red_both(struct rbtree *h) |
| { |
| return !(h->m.flags & (RBTREE_NODE_PRED|RBTREE_NODE_SUCC)) |
| && !(h->m.left->m.flags & h->m.right->m.flags & RBTREE_NODE_BLACK); |
| } |
| |
| static inline struct rbtree *rotate_left(struct rbtree *h) |
| { |
| struct rbtree *x = h->m.right; |
| enum rbtree_node_flags hf = h->m.flags; |
| enum rbtree_node_flags xf = x->m.flags; |
| |
| if (xf & RBTREE_NODE_PRED) { |
| h->m.right = x; |
| h->m.flags = (hf & RBTREE_NODE_PRED) | RBTREE_NODE_SUCC; |
| } else { |
| h->m.right = x->m.left; |
| h->m.flags = hf & RBTREE_NODE_PRED; |
| } |
| x->m.flags = (hf & RBTREE_NODE_BLACK) | (xf & RBTREE_NODE_SUCC); |
| x->m.left = h; |
| |
| return x; |
| } |
| |
| static inline struct rbtree *rotate_right(struct rbtree *h) |
| { |
| struct rbtree *x = h->m.left; |
| enum rbtree_node_flags hf = h->m.flags; |
| enum rbtree_node_flags xf = x->m.flags; |
| |
| if (xf & RBTREE_NODE_SUCC) { |
| h->m.left = x; |
| h->m.flags = (hf & RBTREE_NODE_SUCC) | RBTREE_NODE_PRED; |
| } else { |
| h->m.left = x->m.right; |
| h->m.flags = hf & RBTREE_NODE_SUCC; |
| } |
| x->m.flags = (hf & RBTREE_NODE_BLACK) | (xf & RBTREE_NODE_PRED); |
| x->m.right = h; |
| |
| return x; |
| } |
| |
| static inline void color_flip(struct rbtree *h) |
| { |
| h->m.flags ^= RBTREE_NODE_BLACK; |
| h->m.left->m.flags ^= RBTREE_NODE_BLACK; |
| h->m.right->m.flags ^= RBTREE_NODE_BLACK; |
| } |
| |
| static struct rbtree * |
| _rb_insert(struct rbtree *tree, struct rbtree *node); |
| |
| struct rbtree *rb_insert(struct rbtree *tree, struct rbtree *node) |
| { |
| /* Initialize node as if it was the sole member of the tree */ |
| |
| nasm_zero(node->m); |
| node->m.flags = RBTREE_NODE_PRED|RBTREE_NODE_SUCC; |
| |
| if (unlikely(!tree)) |
| return node; |
| |
| return _rb_insert(tree, node); |
| } |
| |
| static struct rbtree * |
| _rb_insert(struct rbtree *tree, struct rbtree *node) |
| { |
| /* Recursive part of the algorithm */ |
| |
| /* Red on both sides? */ |
| if (is_red_both(tree)) |
| color_flip(tree); |
| |
| if (node->key < tree->key) { |
| node->m.right = tree; /* Potential successor */ |
| if (tree->m.flags & RBTREE_NODE_PRED) { |
| node->m.left = tree->m.left; |
| tree->m.flags &= ~RBTREE_NODE_PRED; |
| tree->m.left = node; |
| } else { |
| tree->m.left = _rb_insert(tree->m.left, node); |
| } |
| } else { |
| node->m.left = tree; /* Potential predecessor */ |
| if (tree->m.flags & RBTREE_NODE_SUCC) { |
| node->m.right = tree->m.right; |
| tree->m.flags &= ~RBTREE_NODE_SUCC; |
| tree->m.right = node; |
| } else { |
| tree->m.right = _rb_insert(tree->m.right, node); |
| } |
| } |
| |
| if (is_red_right(tree)) |
| tree = rotate_left(tree); |
| |
| if (is_red_left_left(tree)) |
| tree = rotate_right(tree); |
| |
| return tree; |
| } |
| |
| struct rbtree *rb_first(const struct rbtree *tree) |
| { |
| if (unlikely(!tree)) |
| return NULL; |
| |
| while (!(tree->m.flags & RBTREE_NODE_PRED)) |
| tree = tree->m.left; |
| |
| return (struct rbtree *)tree; |
| } |
| |
| struct rbtree *rb_last(const struct rbtree *tree) |
| { |
| if (unlikely(!tree)) |
| return NULL; |
| |
| while (!(tree->m.flags & RBTREE_NODE_SUCC)) |
| tree = tree->m.right; |
| |
| return (struct rbtree *)tree; |
| } |
| |
| struct rbtree *rb_prev(const struct rbtree *node) |
| { |
| struct rbtree *np = node->m.left; |
| |
| if (node->m.flags & RBTREE_NODE_PRED) |
| return np; |
| else |
| return rb_last(np); |
| } |
| |
| struct rbtree *rb_next(const struct rbtree *node) |
| { |
| struct rbtree *np = node->m.right; |
| |
| if (node->m.flags & RBTREE_NODE_SUCC) |
| return np; |
| else |
| return rb_first(np); |
| } |