/* * Copyright (c) 2018 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @defgroup rbtree_apis Balanced Red/Black Tree * @ingroup datastructure_apis * * @brief Balanced Red/Black Tree implementation * * This implements an intrusive balanced tree that guarantees * O(log2(N)) runtime for all operations and amortized O(1) behavior * for creation and destruction of whole trees. The algorithms and * naming are conventional per existing academic and didactic * implementations, c.f.: * * https://en.wikipedia.org/wiki/Red%E2%80%93black_tree * * The implementation is size-optimized to prioritize runtime memory * usage. The data structure is intrusive, which is to say the @ref * rbnode handle is intended to be placed in a separate struct, in the * same way as with other such structures (e.g. Zephyr's @ref * doubly-linked-list_apis), and requires no data pointer to be stored * in the node. The color bit is unioned with a pointer (fairly common * for such libraries). Most notably, there is no "parent" pointer * stored in the node, the upper structure of the tree being generated * dynamically via a stack as the tree is recursed. So the overall * memory overhead of a node is just two pointers, identical with a * doubly-linked list. * * @{ */ #ifndef ZEPHYR_INCLUDE_SYS_RB_H_ #define ZEPHYR_INCLUDE_SYS_RB_H_ #include #include /* Our SDK/toolchains integration seems to be inconsistent about * whether they expose alloca.h or not. On gcc it's a moot point as * it's always builtin. */ #ifdef __GNUC__ #ifndef alloca #define alloca __builtin_alloca #endif #else #include #endif /** * @brief Balanced red/black tree node structure */ struct rbnode { /** @cond INTERNAL_HIDDEN */ struct rbnode *children[2]; /** @endcond */ }; /* Theoretical maximum depth of tree based on pointer size. If memory * is filled with 2-pointer nodes, and the tree can be twice as a * packed binary tree, plus root... Works out to 59 entries for 32 * bit pointers and 121 at 64 bits. */ #define Z_TBITS(t) ((sizeof(t)) < 8 ? 2 : 3) #define Z_PBITS(t) (8 * sizeof(t)) #define Z_MAX_RBTREE_DEPTH (2 * (Z_PBITS(int *) - Z_TBITS(int *) - 1) + 1) /** * @typedef rb_lessthan_t * @brief Red/black tree comparison predicate * * Compares the two nodes and returns true if node A is strictly less * than B according to the tree's sorting criteria, false otherwise. * * Note that during insert, the new node being inserted will always be * "A", where "B" is the existing node within the tree against which * it is being compared. This trait can be used (with care!) to * implement "most/least recently added" semantics between nodes which * would otherwise compare as equal. */ typedef bool (*rb_lessthan_t)(struct rbnode *a, struct rbnode *b); /** * @brief Balanced red/black tree structure */ struct rbtree { /** Root node of the tree */ struct rbnode *root; /** Comparison function for nodes in the tree */ rb_lessthan_t lessthan_fn; /** @cond INTERNAL_HIDDEN */ int max_depth; #ifdef CONFIG_MISRA_SANE struct rbnode *iter_stack[Z_MAX_RBTREE_DEPTH]; unsigned char iter_left[Z_MAX_RBTREE_DEPTH]; #endif /** @endcond */ }; /** * @brief Prototype for node visitor callback. * @param node Node being visited * @param cookie User-specified data */ typedef void (*rb_visit_t)(struct rbnode *node, void *cookie); struct rbnode *z_rb_child(struct rbnode *node, uint8_t side); int z_rb_is_black(struct rbnode *node); #ifndef CONFIG_MISRA_SANE void z_rb_walk(struct rbnode *node, rb_visit_t visit_fn, void *cookie); #endif struct rbnode *z_rb_get_minmax(struct rbtree *tree, uint8_t side); /** * @brief Insert node into tree */ void rb_insert(struct rbtree *tree, struct rbnode *node); /** * @brief Remove node from tree */ void rb_remove(struct rbtree *tree, struct rbnode *node); /** * @brief Returns the lowest-sorted member of the tree */ static inline struct rbnode *rb_get_min(struct rbtree *tree) { return z_rb_get_minmax(tree, 0U); } /** * @brief Returns the highest-sorted member of the tree */ static inline struct rbnode *rb_get_max(struct rbtree *tree) { return z_rb_get_minmax(tree, 1U); } /** * @brief Returns true if the given node is part of the tree * * Note that this does not internally dereference the node pointer * (though the tree's lessthan callback might!), it just tests it for * equality with items in the tree. So it's feasible to use this to * implement a "set" construct by simply testing the pointer value * itself. */ bool rb_contains(struct rbtree *tree, struct rbnode *node); #ifndef CONFIG_MISRA_SANE /** * @brief Walk/enumerate a rbtree * * Very simple recursive enumeration. Low code size, but requiring a * separate function can be clumsy for the user and there is no way to * break out of the loop early. See RB_FOR_EACH for an iterative * implementation. */ static inline void rb_walk(struct rbtree *tree, rb_visit_t visit_fn, void *cookie) { z_rb_walk(tree->root, visit_fn, cookie); } #endif struct _rb_foreach { struct rbnode **stack; uint8_t *is_left; int32_t top; }; #ifdef CONFIG_MISRA_SANE #define _RB_FOREACH_INIT(tree, node) { \ .stack = &(tree)->iter_stack[0], \ .is_left = &(tree)->iter_left[0], \ .top = -1 \ } #else #define _RB_FOREACH_INIT(tree, node) { \ .stack = (struct rbnode **) \ alloca((tree)->max_depth * sizeof(struct rbnode *)), \ .is_left = (uint8_t *)alloca((tree)->max_depth * sizeof(uint8_t)),\ .top = -1 \ } #endif struct rbnode *z_rb_foreach_next(struct rbtree *tree, struct _rb_foreach *f); /** * @brief Walk a tree in-order without recursing * * While @ref rb_walk() is very simple, recursing on the C stack can * be clumsy for some purposes and on some architectures wastes * significant memory in stack frames. This macro implements a * non-recursive "foreach" loop that can iterate directly on the tree, * at a moderate cost in code size. * * Note that the resulting loop is not safe against modifications to * the tree. Changes to the tree structure during the loop will * produce incorrect results, as nodes may be skipped or duplicated. * Unlike linked lists, no _SAFE variant exists. * * Note also that the macro expands its arguments multiple times, so * they should not be expressions with side effects. * * @param tree A pointer to a struct rbtree to walk * @param node The symbol name of a local struct rbnode* variable to * use as the iterator */ #define RB_FOR_EACH(tree, node) \ for (struct _rb_foreach __f = _RB_FOREACH_INIT(tree, node); \ (node = z_rb_foreach_next(tree, &__f)); \ /**/) /** * @brief Loop over rbtree with implicit container field logic * * As for RB_FOR_EACH(), but "node" can have an arbitrary type * containing a struct rbnode. * * @param tree A pointer to a struct rbtree to walk * @param node The symbol name of a local iterator * @param field The field name of a struct rbnode inside node */ #define RB_FOR_EACH_CONTAINER(tree, node, field) \ for (struct _rb_foreach __f = _RB_FOREACH_INIT(tree, node); \ ({struct rbnode *n = z_rb_foreach_next(tree, &__f); \ node = n ? CONTAINER_OF(n, __typeof__(*(node)), \ field) : NULL; }) != NULL; \ /**/) /** @} */ #endif /* ZEPHYR_INCLUDE_SYS_RB_H_ */