2018-03-22 04:31:06 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018 Intel Corporation
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* @brief Red/Black balanced tree data structure
|
|
|
|
*
|
|
|
|
* 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 struct
|
|
|
|
* rbnode handle is intended to be placed in a separate struct the
|
|
|
|
* same way other such structures (e.g. Zephyr's dlist list) 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 _RB_H
|
|
|
|
#define _RB_H
|
|
|
|
|
|
|
|
struct rbnode {
|
|
|
|
struct rbnode *children[2];
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @typedef rb_lessthan_t
|
|
|
|
* @brief Red/black tree comparison predicate
|
|
|
|
*
|
|
|
|
* Compares the two nodes and returns 1 if node A is strictly less
|
|
|
|
* than B according to the tree's sorting criteria, 0 otherwise.
|
|
|
|
*/
|
|
|
|
typedef int (*rb_lessthan_t)(struct rbnode *a, struct rbnode *b);
|
|
|
|
|
|
|
|
struct rbtree {
|
|
|
|
struct rbnode *root;
|
|
|
|
rb_lessthan_t lessthan_fn;
|
|
|
|
int max_depth;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef void (*rb_visit_t)(struct rbnode *node, void *cookie);
|
|
|
|
|
|
|
|
struct rbnode *_rb_child(struct rbnode *node, int side);
|
|
|
|
int _rb_is_black(struct rbnode *node);
|
|
|
|
void _rb_walk(struct rbnode *node, rb_visit_t visit_fn, void *cookie);
|
|
|
|
struct rbnode *_rb_get_minmax(struct rbtree *tree, int 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 _rb_get_minmax(tree, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Returns the highest-sorted member of the tree
|
|
|
|
*/
|
|
|
|
static inline struct rbnode *rb_get_max(struct rbtree *tree)
|
|
|
|
{
|
|
|
|
return _rb_get_minmax(tree, 1);
|
|
|
|
}
|
|
|
|
|
2018-04-10 23:54:04 +08:00
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*/
|
|
|
|
int rb_contains(struct rbtree *tree, struct rbnode *node);
|
|
|
|
|
2018-03-22 04:31:06 +08:00
|
|
|
/**
|
|
|
|
* @brief Walk/enumerate a rbtree
|
|
|
|
*
|
|
|
|
* Very simple recursive enumeration implementation. A rather more
|
|
|
|
* subtle (have to alloca() a stack to manage manually) iterative one
|
|
|
|
* is possible that uses a FOREACH-style macro API, but this is good
|
|
|
|
* enough for many purposes and much smaller.
|
|
|
|
*/
|
|
|
|
static inline void rb_walk(struct rbtree *tree, rb_visit_t visit_fn,
|
|
|
|
void *cookie)
|
|
|
|
{
|
|
|
|
_rb_walk(tree->root, visit_fn, cookie);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* _RB_H */
|