Skip to content

Commit 193f4fe

Browse files
Andy RossAnas Nashif
Andy Ross
authored and
Anas Nashif
committed
lib: Red/Black balanced tree data structure
A balanced tree implementation for Zephyr as we grow into bigger regimes where simpler data structures aren't appropriate. 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. Code size above dlist is about 2-2.5k on most architectures, which is significant by Zephyr standards but probably still worthwhile in many situations. Signed-off-by: Andy Ross <[email protected]>
1 parent e2924ab commit 193f4fe

File tree

4 files changed

+601
-0
lines changed

4 files changed

+601
-0
lines changed

include/misc/rb.h

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright (c) 2018 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @file
9+
* @brief Red/Black balanced tree data structure
10+
*
11+
* This implements an intrusive balanced tree that guarantees
12+
* O(log2(N)) runtime for all operations and amortized O(1) behavior
13+
* for creation and destruction of whole trees. The algorithms and
14+
* naming are conventional per existing academic and didactic
15+
* implementations, c.f.:
16+
*
17+
* https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
18+
*
19+
* The implementation is size-optimized to prioritize runtime memory
20+
* usage. The data structure is intrusive, which is to say the struct
21+
* rbnode handle is intended to be placed in a separate struct the
22+
* same way other such structures (e.g. Zephyr's dlist list) and
23+
* requires no data pointer to be stored in the node. The color bit
24+
* is unioned with a pointer (fairly common for such libraries). Most
25+
* notably, there is no "parent" pointer stored in the node, the upper
26+
* structure of the tree being generated dynamically via a stack as
27+
* the tree is recursed. So the overall memory overhead of a node is
28+
* just two pointers, identical with a doubly-linked list.
29+
*/
30+
31+
#ifndef _RB_H
32+
#define _RB_H
33+
34+
struct rbnode {
35+
struct rbnode *children[2];
36+
};
37+
38+
/**
39+
* @typedef rb_lessthan_t
40+
* @brief Red/black tree comparison predicate
41+
*
42+
* Compares the two nodes and returns 1 if node A is strictly less
43+
* than B according to the tree's sorting criteria, 0 otherwise.
44+
*/
45+
typedef int (*rb_lessthan_t)(struct rbnode *a, struct rbnode *b);
46+
47+
struct rbtree {
48+
struct rbnode *root;
49+
rb_lessthan_t lessthan_fn;
50+
int max_depth;
51+
};
52+
53+
typedef void (*rb_visit_t)(struct rbnode *node, void *cookie);
54+
55+
struct rbnode *_rb_child(struct rbnode *node, int side);
56+
int _rb_is_black(struct rbnode *node);
57+
void _rb_walk(struct rbnode *node, rb_visit_t visit_fn, void *cookie);
58+
struct rbnode *_rb_get_minmax(struct rbtree *tree, int side);
59+
60+
/**
61+
* @brief Insert node into tree
62+
*/
63+
void rb_insert(struct rbtree *tree, struct rbnode *node);
64+
65+
/**
66+
* @brief Remove node from tree
67+
*/
68+
void rb_remove(struct rbtree *tree, struct rbnode *node);
69+
70+
/**
71+
* @brief Returns the lowest-sorted member of the tree
72+
*/
73+
static inline struct rbnode *rb_get_min(struct rbtree *tree)
74+
{
75+
return _rb_get_minmax(tree, 0);
76+
}
77+
78+
/**
79+
* @brief Returns the highest-sorted member of the tree
80+
*/
81+
static inline struct rbnode *rb_get_max(struct rbtree *tree)
82+
{
83+
return _rb_get_minmax(tree, 1);
84+
}
85+
86+
/**
87+
* @brief Walk/enumerate a rbtree
88+
*
89+
* Very simple recursive enumeration implementation. A rather more
90+
* subtle (have to alloca() a stack to manage manually) iterative one
91+
* is possible that uses a FOREACH-style macro API, but this is good
92+
* enough for many purposes and much smaller.
93+
*/
94+
static inline void rb_walk(struct rbtree *tree, rb_visit_t visit_fn,
95+
void *cookie)
96+
{
97+
_rb_walk(tree->root, visit_fn, cookie);
98+
}
99+
100+
#endif /* _RB_H */

lib/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ add_subdirectory_if_kconfig(ring_buffer)
77
add_subdirectory_if_kconfig(base64)
88
add_subdirectory(mempool)
99
add_subdirectory_ifdef(CONFIG_PTHREAD_IPC posix)
10+
add_subdirectory(rbtree)

lib/rbtree/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
zephyr_sources(rb.c)

0 commit comments

Comments
 (0)