The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rb.h
Go to the documentation of this file.
1#pragma once
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18/** Red/black tree implementation
19 *
20 * @file src/lib/util/rb.h
21 *
22 * @copyright 2016 The FreeRADIUS server project
23 */
24RCSIDH(fr_rb_h, "$Id: 0fe56ccec7ab455556b89432090c9e3b46a55766 $")
25
26#ifdef __cplusplus
27extern "C" {
28#endif
29
30#include <freeradius-devel/util/misc.h>
31
32#include <stdbool.h>
33#include <stdint.h>
34
35/* Red-Black tree description */
36typedef enum {
38 RED
40
43 fr_rb_node_t *left; //!< Left child
44 fr_rb_node_t *right; //!< Right child
45 fr_rb_node_t *parent; //!< Parent
46 void *data; //!< data stored in node
47
48 fr_rb_colour_t colour; //!< Node colour (BLACK, RED)
49 bool being_freed; //!< Disable frees if we're currently calling
50 ///< a free function.
51};
52
54
55/** Callback used to alloc rbnodes
56 *
57 * @param[in] tree to allocate the node for.
58 * @param[in] data associated with node.
59 */
60typedef fr_rb_node_t *(* rb_node_alloc_t)(fr_rb_tree_t const *tree, void *data);
61
62/** Callback used to free rbnodes
63 *
64 * @param[in] tree that owns the node.
65 * @param[in] node to free.
66 * @param[in] free_data free user data.
67 */
68typedef void (* rb_node_free_t)(fr_rb_tree_t const *tree, fr_rb_node_t *node, bool free_data);
69
70/** The main red black tree structure
71 *
72 */
74#ifndef NDEBUG
76#endif
77
78 fr_rb_node_t *root; //!< Root of the rbtree.
79
80 TALLOC_CTX *node_ctx; //!< Talloc ctx to allocate nodes in.
81
82 char const *type; //!< Talloc type to check elements against.
83
84 fr_cmp_t data_cmp; //!< Callback to compare node data.
85 fr_free_t data_free; //!< Callback to free node data.
86
87 rb_node_alloc_t node_alloc; //!< Callback to allocate a new node.
88 rb_node_free_t node_free; //!< Callback to free a node.
89
90 /*
91 * Try and pack these more efficiently
92 * by grouping them together.
93 */
94 uint16_t offset; //!< Where's the fr_rb_node_t is located in
95 ///< the structure being inserted.
96 bool being_freed; //!< Prevent double frees in talloc_destructor.
97 uint32_t num_elements; //!< How many elements are inside the tree.
98};
99
100/** Initialises a red black that verifies elements are of a specific talloc type
101 *
102 * This variant allocates an #fr_rb_node_t on the heap. This allows the data
103 * structure to be inserted into multiple trees.
104 *
105 * @param[out] _tree to initialise.
106 * @param[in] _node_ctx to tie tree lifetime to.
107 * If ctx is freed, tree will free any nodes, calling the
108 * free function if set.
109 * @param[in] _type of item being stored in the tree, e.g. fr_value_box_t.
110 * @param[in] _data_cmp Callback to compare node data.
111 * @param[in] _data_free Optional function used to free data if tree nodes are
112 * deleted or replaced.
113 * @return
114 * - A new rbtree on success.
115 * - NULL on failure.
116 */
117#define fr_rb_talloc_init(_tree, _node_ctx, _type, _data_cmp, _data_free) \
118 _fr_rb_init(_tree, _node_ctx, -1, #_type, _data_cmp, _data_free)
119
120/** Initialises a red black tree
121 *
122 * This variant initiates an #fr_rb_node_t on the heap. This allows the data structure
123 * to be inserted into multiple trees.
124 *
125 * @param[out] _tree to initialise.
126 * @param[in] _node_ctx to tie tree lifetime to.
127 * If ctx is freed, tree will free any nodes, calling the
128 * free function if set.
129 * @param[in] _data_cmp Callback to compare node data.
130 * @param[in] _data_free Optional function used to free data if tree nodes are
131 * deleted or replaced.
132 * @return
133 * - A new rbtree on success.
134 * - NULL on failure.
135 */
136#define fr_rb_init(_tree, _node_ctx, _data_cmp, _data_free) \
137 _fr_rb_init(_tree, _node_ctx, -1, NULL, _data_cmp, _data_free)
138
139/** Initialises a red black that verifies elements are of a specific talloc type
140 *
141 * This variant stores #fr_rb_node_t data inline with the data structure to avoid
142 * initiating #fr_rb_node_t on the heap.
143 *
144 * It is suitable for use where the data structure will only be inserted into a
145 * fixed set of trees.
146 *
147 * @param[out] _tree to initialise.
148 * @param[in] _type of item being stored in the tree, e.g. fr_value_box_t.
149 * @param[in] _field Containing the #fr_rb_node_t within item being stored.
150 * @param[in] _data_cmp Callback to compare node data.
151 * @param[in] _data_free Optional function used to free data if tree nodes are
152 * deleted or replaced.
153 * @return
154 * - A new rbtree on success.
155 * - NULL on failure.
156 */
157#define fr_rb_inline_talloc_init(_tree, _type, _field, _data_cmp, _data_free) \
158 _Generic((((_type *)0)->_field), \
159 fr_rb_node_t: _fr_rb_init(_tree, NULL, offsetof(_type, _field), #_type, _data_cmp, _data_free) \
160 )
161
162/** Initialises a red black tree
163 *
164 * This variant stores #fr_rb_node_t data inline with the data structure to avoid
165 * initiating #fr_rb_node_t on the heap.
166 *
167 * It is suitable for use where the data structure will only be inserted into a
168 * fixed set of trees.
169 *
170 * @param[out] _tree to initialise.
171 * @param[in] _type of item being stored in the tree, e.g. fr_value_box_t.
172 * @param[in] _field Containing the #fr_rb_node_t within item being stored.
173 * @param[in] _data_cmp Callback to compare node data.
174 * @param[in] _data_free Optional function used to free data if tree nodes are
175 * deleted or replaced.
176 * @return
177 * - A new rbtree on success.
178 * - NULL on failure.
179 */
180#define fr_rb_inline_init(_tree, _type, _field, _data_cmp, _data_free) \
181 _Generic((((_type *)0)->_field), \
182 fr_rb_node_t: _fr_rb_init(_tree, NULL, offsetof(_type, _field), NULL, _data_cmp, _data_free) \
183 )
184
185int _fr_rb_init(fr_rb_tree_t *tree, TALLOC_CTX *node_ctx,
186 ssize_t offset, char const *type,
187 fr_cmp_t data_cmp, fr_free_t data_free);
188
189/** Allocs a red black that verifies elements are of a specific talloc type
190 *
191 * This variant allocates an #fr_rb_node_t on the heap. This allows the data structure
192 * to be inserted into multiple trees.
193 *
194 * @param[in] _ctx to tie tree lifetime to.
195 * If ctx is freed, tree will free any nodes, calling the
196 * free function if set.
197 * @param[in] _type of item being stored in the tree, e.g. fr_value_box_t.
198 * @param[in] _data_cmp Callback to compare node data.
199 * @param[in] _data_free Optional function used to free data if tree nodes are
200 * deleted or replaced.
201 * @return
202 * - A new rbtree on success.
203 * - NULL on failure.
204 */
205#define fr_rb_talloc_alloc(_ctx, _type, _data_cmp, _data_free) \
206 _fr_rb_alloc(_ctx, -1, #_type, _data_cmp, _data_free)
207
208/** Allocs a red black tree
209 *
210 * This variant allocates an #fr_rb_node_t on the heap. This allows the data structure
211 * to be inserted into multiple trees.
212 *
213 * @param[in] _ctx to tie tree lifetime to.
214 * If ctx is freed, tree will free any nodes, calling the
215 * free function if set.
216 * @param[in] _data_cmp Callback to compare node data.
217 * @param[in] _data_free Optional function used to free data if tree nodes are
218 * deleted or replaced.
219 * @return
220 * - A new rbtree on success.
221 * - NULL on failure.
222 */
223#define fr_rb_alloc(_ctx, _data_cmp, _data_free) \
224 _fr_rb_alloc(_ctx, -1, NULL, _data_cmp, _data_free)
225
226/** Allocs a red black that verifies elements are of a specific talloc type
227 *
228 * This variant stores #fr_rb_node_t data inline with the data structure to avoid
229 * allocating #fr_rb_node_t on the heap.
230 *
231 * It is suitable for use where the data structure will only be inserted into a fixed
232 * set of trees.
233 *
234 * @param[in] _ctx to tie tree lifetime to.
235 * If ctx is freed, tree will free any nodes, calling the
236 * free function if set.
237 * @param[in] _type of item being stored in the tree, e.g. fr_value_box_t.
238 * @param[in] _field Containing the #fr_rb_node_t within item being stored.
239 * @param[in] _data_cmp Callback to compare node data.
240 * @param[in] _data_free Optional function used to free data if tree nodes are
241 * deleted or replaced.
242 * @return
243 * - A new rbtree on success.
244 * - NULL on failure.
245 */
246#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free) \
247 _Generic((((_type *)0)->_field), \
248 fr_rb_node_t: _fr_rb_alloc(_ctx, offsetof(_type, _field), #_type, _data_cmp, _data_free) \
249 )
250
251/** Allocs a red black tree
252 *
253 * This variant stores #fr_rb_node_t data inline with the data structure to avoid
254 * allocating #fr_rb_node_t on the heap.
255 *
256 * It is suitable for use where the data structure will only be inserted into a fixed
257 * set of trees.
258 *
259 * @param[in] _ctx to tie tree lifetime to.
260 * If ctx is freed, tree will free any nodes, calling the
261 * free function if set.
262 * @param[in] _type of item being stored in the tree, e.g. fr_value_box_t.
263 * @param[in] _field Containing the #fr_rb_node_t within item being stored.
264 * @param[in] _data_cmp Callback to compare node data.
265 * @param[in] _data_free Optional function used to free data if tree nodes are
266 * deleted or replaced.
267 * @return
268 * - A new rbtree on success.
269 * - NULL on failure.
270 */
271#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free) \
272 _Generic((((_type *)0)->_field), \
273 fr_rb_node_t: _fr_rb_alloc(_ctx, offsetof(_type, _field), NULL, _data_cmp, _data_free) \
274 )
275
276fr_rb_tree_t *_fr_rb_alloc(TALLOC_CTX *ctx, ssize_t offset, char const *type,
277 fr_cmp_t data_cmp, fr_free_t data_free) CC_HINT(warn_unused_result);
278
279/** @hidecallergraph */
280void *fr_rb_find(fr_rb_tree_t const *tree, void const *data) CC_HINT(nonnull);
281
282int fr_rb_find_or_insert(void **found, fr_rb_tree_t *tree, void const *data) CC_HINT(nonnull(2,3));
283
284bool fr_rb_insert(fr_rb_tree_t *tree, void const *data) CC_HINT(nonnull);
285
286int fr_rb_replace(void **old, fr_rb_tree_t *tree, void const *data) CC_HINT(nonnull(2,3));
287
288void *fr_rb_remove(fr_rb_tree_t *tree, void const *data) CC_HINT(nonnull);
289
291
292bool fr_rb_delete(fr_rb_tree_t *tree, void const *data) CC_HINT(nonnull);
293
295
297
298void *fr_rb_first(fr_rb_tree_t *tree) CC_HINT(nonnull);
299
300void *fr_rb_last(fr_rb_tree_t *tree) CC_HINT(nonnull);
301
302/** Check to see if an item is in a tree by examining its inline #fr_rb_node_t
303 *
304 * This works because we use NIL sentinels to represent the absence of a child
305 * or parent. When the node is initialised all these fields should be NULL
306 * and when it's removed from the tree, the "free" function for inline nodes
307 * also sets all of these back to NULL.
308 *
309 * @param[in] node to check.
310 * @return
311 * - true if node is in the tree.
312 * - talse if node is not in the tree.
313 */
314static inline bool fr_rb_node_inline_in_tree(fr_rb_node_t const *node)
315{
316 return (node->left && node->right && node->parent && !node->being_freed);
317}
318
319/** Iterator structure for in-order traversal of an rbtree
320 */
321typedef struct {
322 fr_rb_tree_t *tree; //!< Tree being iterated over.
323 fr_rb_node_t *node; ///< current node--set to NULL (not NIL) by fr_rb_iter_delete()
324 fr_rb_node_t *next; ///< if non-NULL, next node cached by fr_rb_iter_delete()
326
328
330
332
333#define fr_rb_inorder_foreach(_tree, _type, _iter) \
334{ \
335 fr_rb_iter_inorder_t _state; \
336 for (_type *_iter = fr_rb_iter_init_inorder(&_state, _tree); _iter; _iter = fr_rb_iter_next_inorder(&_state))
337
338/** Iterator structure for pre-order traversal of an rbtree
339 */
340typedef struct {
341 fr_rb_tree_t *tree; //!< Tree being iterated over.
342 fr_rb_node_t *node; ///< current node
344
346
348
349#define fr_rb_preorder_foreach(_tree, _type, _iter) \
350{ \
351 fr_rb_iter_preorder_t _state; \
352 for (_type *_iter = fr_rb_iter_init_preorder(&_state, _tree); _iter; _iter = fr_rb_iter_next_preorder(&_state))
353
354/** Iterator structure for post-order traversal of an rbtree
355 */
356typedef struct {
357 fr_rb_tree_t *tree; //!< Tree being iterated over.
358 fr_rb_node_t *node; ///< current node
360
362
364
365#define fr_rb_postorder_foreach(_tree, _type, _iter) \
366{ \
367 fr_rb_iter_postorder_t _state; \
368 for (_type *_iter = fr_rb_iter_init_postorder(&_state, _tree); _iter; _iter = fr_rb_iter_next_postorder(&_state))
369
370int fr_rb_flatten_inorder(TALLOC_CTX *ctx, void **out[], fr_rb_tree_t *tree);
371
372int fr_rb_flatten_preorder(TALLOC_CTX *ctx, void **out[], fr_rb_tree_t *tree);
373
374int fr_rb_flatten_postorder(TALLOC_CTX *ctx, void **out[], fr_rb_tree_t *tree);
375#ifdef __cplusplus
376}
377#endif
#define RCSIDH(h, id)
Definition build.h:484
unsigned short uint16_t
unsigned int uint32_t
long int ssize_t
int8_t(* fr_cmp_t)(void const *a, void const *b)
Definition misc.h:38
void(* fr_free_t)(void *)
Definition misc.h:39
fr_rb_tree_t * tree
Tree being iterated over.
Definition rb.h:322
fr_rb_node_t * node
current node
Definition rb.h:358
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition rb.c:781
fr_rb_node_t * parent
Parent.
Definition rb.h:45
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
Definition rb.c:824
fr_rb_node_t * left
Left child.
Definition rb.h:43
fr_rb_node_t *(* rb_node_alloc_t)(fr_rb_tree_t const *tree, void *data)
Callback used to alloc rbnodes.
Definition rb.h:60
bool being_freed
Disable frees if we're currently calling a free function.
Definition rb.h:49
int fr_rb_find_or_insert(void **found, fr_rb_tree_t *tree, void const *data))
Attempt to find current data in the tree, if it does not exist insert it.
Definition rb.c:598
fr_rb_node_t * next
if non-NULL, next node cached by fr_rb_iter_delete()
Definition rb.h:324
fr_rb_node_t * node
current node
Definition rb.h:342
void fr_rb_iter_delete_inorder(fr_rb_iter_inorder_t *iter)
Remove the current node from the tree.
Definition rb.c:898
fr_cmp_t data_cmp
Callback to compare node data.
Definition rb.h:84
fr_rb_colour_t
Definition rb.h:36
@ BLACK
Definition rb.h:37
@ RED
Definition rb.h:38
void * fr_rb_remove(fr_rb_tree_t *tree, void const *data)
Remove an entry from the tree, without freeing the data.
Definition rb.c:695
TALLOC_CTX * node_ctx
Talloc ctx to allocate nodes in.
Definition rb.h:80
fr_rb_node_t * right
Right child.
Definition rb.h:44
char const * type
Talloc type to check elements against.
Definition rb.h:82
static bool fr_rb_node_inline_in_tree(fr_rb_node_t const *node)
Check to see if an item is in a tree by examining its inline fr_rb_node_t.
Definition rb.h:314
void * fr_rb_iter_next_preorder(fr_rb_iter_preorder_t *iter)
Return the next node.
Definition rb.c:941
void * fr_rb_iter_init_preorder(fr_rb_iter_preorder_t *iter, fr_rb_tree_t *tree)
Initialise a pre-order iterator.
Definition rb.c:917
void * data
data stored in node
Definition rb.h:46
void(* rb_node_free_t)(fr_rb_tree_t const *tree, fr_rb_node_t *node, bool free_data)
Callback used to free rbnodes.
Definition rb.h:68
uint32_t num_elements
How many elements are inside the tree.
Definition rb.h:97
fr_rb_tree_t * _fr_rb_alloc(TALLOC_CTX *ctx, ssize_t offset, char const *type, fr_cmp_t data_cmp, fr_free_t data_free)
Alloc a new RED-BLACK tree.
Definition rb.c:202
void * fr_rb_iter_init_postorder(fr_rb_iter_postorder_t *iter, fr_rb_tree_t *tree)
Initialise a post-order iterator.
Definition rb.c:994
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
Definition rb.c:850
fr_free_t data_free
Callback to free node data.
Definition rb.h:85
void * fr_rb_iter_next_postorder(fr_rb_iter_postorder_t *iter)
Return the next node.
Definition rb.c:1025
int fr_rb_flatten_preorder(TALLOC_CTX *ctx, void **out[], fr_rb_tree_t *tree)
uint32_t magic
Definition rb.h:75
fr_rb_tree_t * tree
Tree being iterated over.
Definition rb.h:341
void * fr_rb_remove_by_inline_node(fr_rb_tree_t *tree, fr_rb_node_t *node)
Remove an entry from the tree, using the node structure, without freeing the data.
Definition rb.c:722
uint16_t offset
Where's the fr_rb_node_t is located in the structure being inserted.
Definition rb.h:94
bool fr_rb_delete_by_inline_node(fr_rb_tree_t *tree, fr_rb_node_t *node)
Remove node and free data (if a free function was specified)
Definition rb.c:767
int fr_rb_replace(void **old, fr_rb_tree_t *tree, void const *data))
Replace old data with new data, OR insert if there is no old.
Definition rb.c:647
int fr_rb_flatten_postorder(TALLOC_CTX *ctx, void **out[], fr_rb_tree_t *tree)
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
int _fr_rb_init(fr_rb_tree_t *tree, TALLOC_CTX *node_ctx, ssize_t offset, char const *type, fr_cmp_t data_cmp, fr_free_t data_free)
Initialise a new RED-BLACK tree.
Definition rb.c:147
int fr_rb_flatten_inorder(TALLOC_CTX *ctx, void **out[], fr_rb_tree_t *tree)
void * fr_rb_first(fr_rb_tree_t *tree)
Definition rb.c:786
rb_node_free_t node_free
Callback to free a node.
Definition rb.h:88
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
bool being_freed
Prevent double frees in talloc_destructor.
Definition rb.h:96
void * fr_rb_last(fr_rb_tree_t *tree)
Definition rb.c:801
fr_rb_tree_t * tree
Tree being iterated over.
Definition rb.h:357
fr_rb_node_t * node
current nodeā€“set to NULL (not NIL) by fr_rb_iter_delete()
Definition rb.h:323
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
Definition rb.c:741
fr_rb_colour_t colour
Node colour (BLACK, RED)
Definition rb.h:48
rb_node_alloc_t node_alloc
Callback to allocate a new node.
Definition rb.h:87
fr_rb_node_t * root
Root of the rbtree.
Definition rb.h:78
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:321
Iterator structure for post-order traversal of an rbtree.
Definition rb.h:356
Iterator structure for pre-order traversal of an rbtree.
Definition rb.h:340
The main red black tree structure.
Definition rb.h:73
static int8_t data_cmp(const void *one, const void *two)
Definition rlm_stats.c:355
fr_aka_sim_id_type_t type
static fr_slen_t data
Definition value.h:1265
int nonnull(2, 5))
static size_t char ** out
Definition value.h:997