libcstl
Loading...
Searching...
No Matches
rbtree.h
Go to the documentation of this file.
1/*!
2 * @file
3 */
4
5#ifndef CSTL_RBTREE_H
6#define CSTL_RBTREE_H
7
8/*!
9 * @defgroup rbtree Red-black tree
10 * @ingroup bintrees
11 * @brief A self-balancing binary tree
12 *
13 * @internal
14 * The red-black tree algorithm(s) contained herein come from
15 * the book Introduction to Algorithms by Cormen, Leiserson, and
16 * Rivest aka The Big Book of Algorithms.
17 *
18 * There are 4 rules applied to the tree:
19 * 1. Every node is red or black
20 * 2. NULL children are considered leaves and are always black
21 * 3. If a node is red, both children must be black
22 * 4. Every path from a node to a leaf has the same number of blacks
23 * @endinternal
24 */
25/*!
26 * @addtogroup rbtree
27 * @{
28 */
29
30#include "cstl/bintree.h"
31
32/*! @private */
33typedef enum
34{
35 CSTL_RBTREE_COLOR_R,
36 CSTL_RBTREE_COLOR_B,
37} cstl_rbtree_color_t;
38
39/*!
40 * @brief Node to anchor an element within a red-black tree
41 *
42 * Users of the red-black tree object declare this object within another
43 * object as follows:
44 * @code{.c}
45 * struct object {
46 * ...
47 * struct cstl_rbtree_node tree_node;
48 * ...
49 * };
50 * @endcode
51 *
52 * When calling cstl_rbtree_init(), the caller passes the offset of
53 * @p tree_node within their object as the @p off parameter of that
54 * function, e.g.
55 * @code{.c}
56 * offsetof(struct object, tree_node)
57 * @endcode
58 */
60{
61 /*! @privatesection */
62 cstl_rbtree_color_t c;
63 struct cstl_bintree_node n;
64};
65
66/*!
67 * @brief Red-black tree object
68 *
69 * Callers declare or allocate an object of this type to instantiate
70 * a red-black tree. Users are encouraged to declare (and initialize) this
71 * object with the DECLARE_CSTL_RBTREE() macro. Any other declaration or
72 * allocation must be initialized via cstl_rbtree_init().
73 */
75{
76 /*! @privatesection */
77 struct cstl_bintree t;
78
79 size_t off;
80};
81
82/*!
83 * @brief Constant initialization of a cstl_rbtree object
84 *
85 * @param TYPE The type of object that the tree will hold
86 * @param MEMB The name of the @p cstl_rbtree_node member within @p TYPE.
87 * @param CMP A pointer to a function of type @p cstl_compare_func_t that
88 * will be used to compare elements in the tree
89 * @param PRIV A pointer to a private data structure that will be passed
90 * to calls to the @p CMP function
91 *
92 * @see cstl_rbtree_node for a description of the relationship between
93 * @p TYPE and @p MEMB
94 */
95#define CSTL_RBTREE_INITIALIZER(TYPE, MEMB, CMP, PRIV) \
96 { \
97 .t = CSTL_BINTREE_INITIALIZER(TYPE, MEMB.n, CMP, PRIV), \
98 .off = offsetof(TYPE, MEMB), \
99 }
100/*!
101 * @brief (Statically) declare and initialize a red-black tree
102 *
103 * @param NAME The name of the variable being declared
104 * @param TYPE The type of object that the tree will hold
105 * @param MEMB The name of the @p cstl_rbtree_node member within @p TYPE.
106 * @param CMP A pointer to a function of type @p cstl_compare_func_t that
107 * will be used to compare elements in the tree
108 * @param PRIV A pointer to a private data structure that will be passed
109 * to calls to the @p CMP function
110 *
111 * @see cstl_rbtree_node for a description of the relationship between
112 * @p TYPE and @p MEMB
113 */
114#define DECLARE_CSTL_RBTREE(NAME, TYPE, MEMB, CMP, PRIV) \
115 struct cstl_rbtree NAME = \
116 CSTL_RBTREE_INITIALIZER(TYPE, MEMB, CMP, PRIV)
117
118/*!
119 * @brief Initialize a red-black tree object
120 *
121 * @param[in,out] t A pointer to the object to be initialized
122 * @param[in] cmp A function that can compare objects in the tree
123 * @param[in] priv A pointer to private data that will be
124 * passed to the @p cmp function
125 * @param[in] off The offset of the @p cstl_rbtree_node object within the
126 * object(s) that will be stored in the tree
127 */
128static inline void cstl_rbtree_init(struct cstl_rbtree * const t,
129 cstl_compare_func_t * const cmp,
130 void * const priv,
131 const size_t off)
132{
134 &t->t, cmp, priv, off + offsetof(struct cstl_rbtree_node, n));
135 t->off = off;
136}
137
138/*!
139 * @brief Get the number of objects in the tree
140 *
141 * @param[in] t A pointer to the red-black tree
142 *
143 * @return The number of objects in the tree
144 */
145static inline size_t cstl_rbtree_size(const struct cstl_rbtree * const t)
146{
147 return cstl_bintree_size(&t->t);
148}
149
150/*!
151 * @brief Insert a new object into the tree
152 *
153 * @param[in] t A pointer to the red-black tree
154 * @param[in] e A pointer to the object to be inserted
155 * @param[in] p A pointer to the parent of the object to be inserted.
156 * This pointer may be NULL or can be found via
157 * cstl_bintree_find()
158 *
159 * The inserted object does not need to compare as unequal to any/all
160 * other objects already in the tree. If the object is equal to one or
161 * more objects already in the tree, it is up to the caller to distinguish
162 * between them during a find or erase operation.
163 *
164 * The inserted object must not be modified (in such a way as to affect
165 * its comparison with other objects in the tree) as that modification
166 * can cause the assumptions about the ordering of elements within the
167 * tree to become invalid and lead to undefined behavior.
168 */
169void cstl_rbtree_insert(struct cstl_rbtree * t, void * e, void * p);
170
171/*!
172 * @brief Find an element within a tree
173 *
174 * @param[in] t A pointer to the red-black tree
175 * @param[in] e A pointer to an object to compare to those in the tree
176 * @param[out] p The location in which to return a pointer to the parent
177 * of the found element (or where it would be located). This
178 * pointer may be NULL
179 *
180 * The tree will be searched for an element that compares as equal
181 * to the @p e parameter as defined by the @p cmp function provided
182 * when the tree was initialized.
183 *
184 * @return A pointer to the (first) object in the tree that matches
185 * @retval NULL No matching object was found
186 */
187static inline const void * cstl_rbtree_find(
188 const struct cstl_rbtree * const t, const void * const e,
189 const void ** const p)
190{
191 return cstl_bintree_find(&t->t, e, p);
192}
193
194/*!
195 * @brief Remove an element from the tree
196 *
197 * @param[in] t A pointer to the red-black tree
198 * @param[in] e A pointer to an object to compare to those in the tree
199 *
200 * The tree will be searched for an element that compares as equal
201 * to the @p e parameter as defined by the @p cmp function provided
202 * when the tree was initialized. The first element found that matches
203 * will be removed from the tree, and a pointer to that element will
204 * be returned.
205 *
206 * @return A pointer to the removed element
207 * @retval NULL No element was found/removed
208 */
209void * cstl_rbtree_erase(struct cstl_rbtree * t, const void * e);
210
211/*! @private */
212void __cstl_rbtree_erase(struct cstl_rbtree *, struct cstl_rbtree_node *);
213
214/*!
215 * @brief Remove all elements from the tree
216 *
217 * @param[in] t A pointer to the red-black tree
218 * @param[in] clr A pointer to a function to be called for each
219 * element in the tree
220 * @param[in] priv A pointer to be passed to each invocation of @p clr
221 *
222 * All elements are removed from the tree and the @p clr function is
223 * called for each element that was in the tree. The order in which
224 * the elements are removed and @p clr is called is not specified, but
225 * the callee may take ownership of an element at the time that @p clr
226 * is called for that element and not before.
227 *
228 * Upon return from this function, the tree contains no elements, and
229 * is as it was immediately after being initialized. No further operations
230 * on the tree are necessary to make it ready to go out of scope or be
231 * destroyed.
232 */
233static inline void cstl_rbtree_clear(struct cstl_rbtree * const t,
234 cstl_xtor_func_t * const clr,
235 void * const priv)
236{
237 cstl_bintree_clear(&t->t, clr, priv);
238}
239
240/*!
241 * @brief Swap the tree objects at the two given locations
242 *
243 * @param[in,out] a A pointer to a red-black tree
244 * @param[in,out] b A pointer to a(nother) red-black tree
245 *
246 * The trees at the given locations will be swapped such that upon return,
247 * @p a will contain the tree previously pointed to by @p b and vice versa.
248 */
249static inline void cstl_rbtree_swap(
250 struct cstl_rbtree * const a, struct cstl_rbtree * const b)
251{
252 size_t t;
253 cstl_bintree_swap(&a->t, &b->t);
254 cstl_swap(&a->off, &b->off, &t, sizeof(t));
255}
256
257/*!
258 * @brief Visit each element in a tree, calling a user-defined
259 * function for each visit
260 *
261 * @param[in] t A pointer to the red-black tree
262 * @param[in] visit A pointer to a function to be called for each visit
263 * @param[in] priv A pointer to a private data structure that will be passed
264 * to each call to @p visit
265 * @param[in] dir The direction in which to traverse the tree
266 *
267 * The function continues visiting elements in the tree so long as the
268 * given @p visit function returns 0. If the @p visit function returns a
269 * non-zero value, no more elements are visited, and the function returns
270 * the non-zero value that halted visitations.
271 *
272 * @see cstl_bintree_visit_order_t
273 */
274static inline
275int cstl_rbtree_foreach(const struct cstl_rbtree * const t,
277 void * const priv,
279{
280 return cstl_bintree_foreach(&t->t, visit, priv, dir);
281}
282
283/*!
284 * @brief Determine the maximum and minimum heights of a tree
285 *
286 * @param[in] t A pointer to the red-black tree
287 * @param[out] min The length of the shortest path from a root to a leaf
288 * @param[out] max The length of the longest path from the root to a leaf
289 */
290static inline
291void cstl_rbtree_height(const struct cstl_rbtree * const t,
292 size_t * const min, size_t * const max)
293{
294 cstl_bintree_height(&t->t, min, max);
295}
296
297/*!
298 * @}
299 */
300
301#endif
static void cstl_swap(void *const x, void *const y, void *const t, const size_t sz)
Swap values at two memory locations via use of a third.
Definition common.h:137
void cstl_xtor_func_t(void *obj, void *priv)
Type for functions called to construct, clear, or destroy an object.
Definition common.h:97
int cstl_compare_func_t(const void *obj1, const void *obj2, void *priv)
Function type for comparing (in)equality of two objects.
Definition common.h:49
static size_t cstl_bintree_size(const struct cstl_bintree *const bt)
Get the number of objects in the tree.
Definition bintree.h:149
static void cstl_bintree_init(struct cstl_bintree *const bt, cstl_compare_func_t *const cmp, void *const priv, const size_t off)
Initialize a binary tree object.
Definition bintree.h:128
cstl_bintree_foreach_dir_t
Enumeration indicating the order in which elements in a tree are visited during cstl_bintree_foreach(...
Definition bintree.h:275
int cstl_bintree_const_visit_func_t(const void *e, cstl_bintree_visit_order_t ord, void *p)
The type of visit function associated with cstl_bintree_foreach()
Definition bintree.h:299
void cstl_bintree_height(const struct cstl_bintree *bt, size_t *min, size_t *max)
Determine the maximum and minimum heights of a tree.
Definition bintree.c:608
int cstl_bintree_foreach(const struct cstl_bintree *bt, cstl_bintree_const_visit_func_t *visit, void *priv, cstl_bintree_foreach_dir_t dir)
Visit each element in a tree, calling a user-defined function for each visit.
Definition bintree.c:475
const void * cstl_bintree_find(const struct cstl_bintree *bt, const void *e, const void **p)
Find an element within a tree.
Definition bintree.c:93
void cstl_bintree_swap(struct cstl_bintree *a, struct cstl_bintree *b)
Swap the tree objects at the two given locations.
Definition bintree.c:506
void cstl_bintree_clear(struct cstl_bintree *bt, cstl_xtor_func_t *clr, void *priv)
Remove all elements from the tree.
Definition bintree.c:552
static void cstl_rbtree_init(struct cstl_rbtree *const t, cstl_compare_func_t *const cmp, void *const priv, const size_t off)
Initialize a red-black tree object.
Definition rbtree.h:128
static int cstl_rbtree_foreach(const struct cstl_rbtree *const t, cstl_bintree_const_visit_func_t *const visit, void *const priv, const cstl_bintree_foreach_dir_t dir)
Visit each element in a tree, calling a user-defined function for each visit.
Definition rbtree.h:275
void cstl_rbtree_insert(struct cstl_rbtree *t, void *e, void *p)
Insert a new object into the tree.
Definition rbtree.c:98
static const void * cstl_rbtree_find(const struct cstl_rbtree *const t, const void *const e, const void **const p)
Find an element within a tree.
Definition rbtree.h:187
static void cstl_rbtree_swap(struct cstl_rbtree *const a, struct cstl_rbtree *const b)
Swap the tree objects at the two given locations.
Definition rbtree.h:249
static void cstl_rbtree_height(const struct cstl_rbtree *const t, size_t *const min, size_t *const max)
Determine the maximum and minimum heights of a tree.
Definition rbtree.h:291
static void cstl_rbtree_clear(struct cstl_rbtree *const t, cstl_xtor_func_t *const clr, void *const priv)
Remove all elements from the tree.
Definition rbtree.h:233
static size_t cstl_rbtree_size(const struct cstl_rbtree *const t)
Get the number of objects in the tree.
Definition rbtree.h:145
void * cstl_rbtree_erase(struct cstl_rbtree *t, const void *e)
Remove an element from the tree.
Definition rbtree.c:327
Node to anchor an element within a binary tree.
Definition bintree.h:49
Binary tree object.
Definition bintree.h:63
Node to anchor an element within a red-black tree.
Definition rbtree.h:60
Red-black tree object.
Definition rbtree.h:75