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: 2f5ea0ab87e701d079421a487b9a647b7d375205 $")
25
26#ifdef __cplusplus
27extern "C" {
28#endif
29
30#include <freeradius-devel/util/misc.h>
31
32
33/* Red-Black tree description */
34typedef enum {
36 RED
38
41 fr_rb_node_t *left; //!< Left child
42 fr_rb_node_t *right; //!< Right child
43 fr_rb_node_t *parent; //!< Parent
44 void *data; //!< data stored in node
45
46 fr_rb_colour_t colour; //!< Node colour (BLACK, RED)
47 bool being_freed; //!< Disable frees if we're currently calling
48 ///< a free function.
49};
50
52
53/** Callback used to alloc rbnodes
54 *
55 * @param[in] tree to allocate the node for.
56 * @param[in] data associated with node.
57 */
58typedef fr_rb_node_t *(* rb_node_alloc_t)(fr_rb_tree_t const *tree, void *data);
59
60/** Callback used to free rbnodes
61 *
62 * @param[in] tree that owns the node.
63 * @param[in] node to free.
64 * @param[in] free_data free user data.
65 */
66typedef void (* rb_node_free_t)(fr_rb_tree_t const *tree, fr_rb_node_t *node, bool free_data);
67
68/** The main red black tree structure
69 *
70 */
72#ifndef NDEBUG
74#endif
75
76 fr_rb_node_t *root; //!< Root of the rbtree.
77
78 TALLOC_CTX *node_ctx; //!< Talloc ctx to allocate nodes in.
79
80 char const *type; //!< Talloc type to check elements against.
81
82 fr_cmp_t data_cmp; //!< Callback to compare node data.
83 fr_free_t data_free; //!< Callback to free node data.
84
85 rb_node_alloc_t node_alloc; //!< Callback to allocate a new node.
86 rb_node_free_t node_free; //!< Callback to free a node.
87
88 /*
89 * Try and pack these more efficiently
90 * by grouping them together.
91 */
92 uint16_t offset; //!< Where's the fr_rb_node_t is located in
93 ///< the structure being inserted.
94 bool being_freed; //!< Prevent double frees in talloc_destructor.
95 uint32_t num_elements; //!< How many elements are inside the tree.
96};
97
98/** Initialises a red black that verifies elements are of a specific talloc type
99 *
100 * This variant allocates an #fr_rb_node_t on the heap. This allows the data
101 * structure to be inserted into multiple trees.
102 *
103 * @param[out] _tree to initialise.
104 * @param[in] _node_ctx to tie tree lifetime to.
105 * If ctx is freed, tree will free any nodes, calling the
106 * free function if set.
107 * @param[in] _type of item being stored in the tree, e.g. fr_value_box_t.
108 * @param[in] _data_cmp Callback to compare node data.
109 * @param[in] _data_free Optional function used to free data if tree nodes are
110 * deleted or replaced.
111 * @return
112 * - A new rbtree on success.
113 * - NULL on failure.
114 */
115#define fr_rb_talloc_init(_tree, _node_ctx, _type, _data_cmp, _data_free) \
116 _fr_rb_init(_tree, _node_ctx, -1, #_type, _data_cmp, _data_free)
117
118/** Initialises a red black tree
119 *
120 * This variant initiates an #fr_rb_node_t on the heap. This allows the data structure
121 * to be inserted into multiple trees.
122 *
123 * @param[out] _tree to initialise.
124 * @param[in] _node_ctx to tie tree lifetime to.
125 * If ctx is freed, tree will free any nodes, calling the
126 * free function if set.
127 * @param[in] _data_cmp Callback to compare node data.
128 * @param[in] _data_free Optional function used to free data if tree nodes are
129 * deleted or replaced.
130 * @return
131 * - A new rbtree on success.
132 * - NULL on failure.
133 */
134#define fr_rb_init(_tree, _node_ctx, _data_cmp, _data_free) \
135 _fr_rb_init(_tree, _node_ctx, -1, NULL, _data_cmp, _data_free)
136
137/** Initialises a red black that verifies elements are of a specific talloc type
138 *
139 * This variant stores #fr_rb_node_t data inline with the data structure to avoid
140 * initiating #fr_rb_node_t on the heap.
141 *
142 * It is suitable for use where the data structure will only be inserted into a
143 * fixed set of trees.
144 *
145 * @param[out] _tree to initialise.
146 * @param[in] _type of item being stored in the tree, e.g. fr_value_box_t.
147 * @param[in] _field Containing the #fr_rb_node_t within item being stored.
148 * @param[in] _data_cmp Callback to compare node data.
149 * @param[in] _data_free Optional function used to free data if tree nodes are
150 * deleted or replaced.
151 * @return
152 * - A new rbtree on success.
153 * - NULL on failure.
154 */
155#define fr_rb_inline_talloc_init(_tree, _type, _field, _data_cmp, _data_free) \
156 _Generic((((_type *)0)->_field), \
157 fr_rb_node_t: _fr_rb_init(_tree, NULL, offsetof(_type, _field), #_type, _data_cmp, _data_free) \
158 )
159
160/** Initialises a red black tree
161 *
162 * This variant stores #fr_rb_node_t data inline with the data structure to avoid
163 * initiating #fr_rb_node_t on the heap.
164 *
165 * It is suitable for use where the data structure will only be inserted into a
166 * fixed set of trees.
167 *
168 * @param[out] _tree to initialise.
169 * @param[in] _type of item being stored in the tree, e.g. fr_value_box_t.
170 * @param[in] _field Containing the #fr_rb_node_t within item being stored.
171 * @param[in] _data_cmp Callback to compare node data.
172 * @param[in] _data_free Optional function used to free data if tree nodes are
173 * deleted or replaced.
174 * @return
175 * - 0 on success.
176 * - -1 on failure.
177 */
178#define fr_rb_inline_init(_tree, _type, _field, _data_cmp, _data_free) \
179 _Generic((((_type *)0)->_field), \
180 fr_rb_node_t: _fr_rb_init(_tree, NULL, offsetof(_type, _field), NULL, _data_cmp, _data_free) \
181 )
182
183int _fr_rb_init(fr_rb_tree_t *tree, TALLOC_CTX *node_ctx,
184 ssize_t offset, char const *type,
185 fr_cmp_t data_cmp, fr_free_t data_free);
186
187/** Allocs a red black that verifies elements are of a specific talloc type
188 *
189 * This variant allocates an #fr_rb_node_t on the heap. This allows the data structure
190 * to be inserted into multiple trees.
191 *
192 * @param[in] _ctx to tie tree lifetime to.
193 * If ctx is freed, tree will free any nodes, calling the
194 * free function if set.
195 * @param[in] _type of item being stored in the tree, e.g. fr_value_box_t.
196 * @param[in] _data_cmp Callback to compare node data.
197 * @param[in] _data_free Optional function used to free data if tree nodes are
198 * deleted or replaced.
199 * @return
200 * - A new rbtree on success.
201 * - NULL on failure.
202 */
203#define fr_rb_talloc_alloc(_ctx, _type, _data_cmp, _data_free) \
204 _fr_rb_alloc(_ctx, -1, #_type, _data_cmp, _data_free)
205
206/** Allocs a red black tree
207 *
208 * This variant allocates an #fr_rb_node_t on the heap. This allows the data structure
209 * to be inserted into multiple trees.
210 *
211 * @param[in] _ctx to tie tree lifetime to.
212 * If ctx is freed, tree will free any nodes, calling the
213 * free function if set.
214 * @param[in] _data_cmp Callback to compare node data.
215 * @param[in] _data_free Optional function used to free data if tree nodes are
216 * deleted or replaced.
217 * @return
218 * - A new rbtree on success.
219 * - NULL on failure.
220 */
221#define fr_rb_alloc(_ctx, _data_cmp, _data_free) \
222 _fr_rb_alloc(_ctx, -1, NULL, _data_cmp, _data_free)
223
224/** Allocs a red black that verifies elements are of a specific talloc type
225 *
226 * This variant stores #fr_rb_node_t data inline with the data structure to avoid
227 * allocating #fr_rb_node_t on the heap.
228 *
229 * It is suitable for use where the data structure will only be inserted into a fixed
230 * set of trees.
231 *
232 * @param[in] _ctx to tie tree lifetime to.
233 * If ctx is freed, tree will free any nodes, calling the
234 * free function if set.
235 * @param[in] _type of item being stored in the tree, e.g. fr_value_box_t.
236 * @param[in] _field Containing the #fr_rb_node_t within item being stored.
237 * @param[in] _data_cmp Callback to compare node data.
238 * @param[in] _data_free Optional function used to free data if tree nodes are
239 * deleted or replaced.
240 * @return
241 * - A new rbtree on success.
242 * - NULL on failure.
243 */
244#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free) \
245 _Generic((((_type *)0)->_field), \
246 fr_rb_node_t: _fr_rb_alloc(_ctx, offsetof(_type, _field), #_type, _data_cmp, _data_free) \
247 )
248
249/** Allocs a red black tree
250 *
251 * This variant stores #fr_rb_node_t data inline with the data structure to avoid
252 * allocating #fr_rb_node_t on the heap.
253 *
254 * It is suitable for use where the data structure will only be inserted into a fixed
255 * set of trees.
256 *
257 * @param[in] _ctx to tie tree lifetime to.
258 * If ctx is freed, tree will free any nodes, calling the
259 * free function if set.
260 * @param[in] _type of item being stored in the tree, e.g. fr_value_box_t.
261 * @param[in] _field Containing the #fr_rb_node_t within item being stored.
262 * @param[in] _data_cmp Callback to compare node data.
263 * @param[in] _data_free Optional function used to free data if tree nodes are
264 * deleted or replaced.
265 * @return
266 * - A new rbtree on success.
267 * - NULL on failure.
268 */
269#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free) \
270 _Generic((((_type *)0)->_field), \
271 fr_rb_node_t: _fr_rb_alloc(_ctx, offsetof(_type, _field), NULL, _data_cmp, _data_free) \
272 )
273
274fr_rb_tree_t *_fr_rb_alloc(TALLOC_CTX *ctx, ssize_t offset, char const *type,
275 fr_cmp_t data_cmp, fr_free_t data_free) CC_HINT(warn_unused_result);
276
277/** @hidecallergraph */
278void *fr_rb_find(fr_rb_tree_t const *tree, void const *data) CC_HINT(nonnull);
279
280int fr_rb_find_or_insert(void **found, fr_rb_tree_t *tree, void const *data) CC_HINT(nonnull(2,3));
281
282bool fr_rb_insert(fr_rb_tree_t *tree, void const *data) CC_HINT(nonnull);
283
284int fr_rb_replace(void **old, fr_rb_tree_t *tree, void const *data) CC_HINT(nonnull(2,3));
285
286void *fr_rb_remove(fr_rb_tree_t *tree, void const *data) CC_HINT(nonnull);
287
289
290bool fr_rb_delete(fr_rb_tree_t *tree, void const *data) CC_HINT(nonnull);
291
293
295
296void *fr_rb_first(fr_rb_tree_t *tree) CC_HINT(nonnull);
297
298void *fr_rb_last(fr_rb_tree_t *tree) CC_HINT(nonnull);
299
300/** Check to see if an item is in a tree by examining its inline #fr_rb_node_t
301 *
302 * This works because we use NIL sentinels to represent the absence of a child
303 * or parent. When the node is initialised all these fields should be NULL
304 * and when it's removed from the tree, the "free" function for inline nodes
305 * also sets all of these back to NULL.
306 *
307 * @param[in] node to check.
308 * @return
309 * - true if node is in the tree.
310 * - talse if node is not in the tree.
311 */
312static inline bool fr_rb_node_inline_in_tree(fr_rb_node_t const *node)
313{
314 return (node->left && node->right && node->parent && !node->being_freed);
315}
316
317/** Iterator structure for in-order traversal of an rbtree
318 */
319typedef struct {
320 fr_rb_node_t *node; ///< current node--set to NULL (not NIL) by fr_rb_iter_delete()
321 fr_rb_node_t *next; ///< if non-NULL, next node cached by fr_rb_iter_delete()
323
325
327
329
330#define fr_rb_inorder_foreach(_tree, _type, _iter) \
331{ \
332 fr_rb_iter_inorder_t _state; \
333 for (_type *_iter = fr_rb_iter_init_inorder(_tree, &_state); _iter; _iter = fr_rb_iter_next_inorder(_tree, &_state))
334
335/** Iterator structure for pre-order traversal of an rbtree
336 */
337typedef struct {
338 fr_rb_node_t *node; ///< current node
340
342
344
345#define fr_rb_preorder_foreach(_tree, _type, _iter) \
346{ \
347 fr_rb_iter_preorder_t _state; \
348 for (_type *_iter = fr_rb_iter_init_preorder(_tree, &_state); _iter; _iter = fr_rb_iter_next_preorder(_tree, &_state))
349
350/** Iterator structure for post-order traversal of an rbtree
351 */
352typedef struct {
353 fr_rb_node_t *node; ///< current node
355
357
359
360#define fr_rb_postorder_foreach(_tree, _type, _iter) \
361{ \
362 fr_rb_iter_postorder_t _state; \
363 for (_type *_iter = fr_rb_iter_init_postorder(_tree, &_state); _iter; _iter = fr_rb_iter_next_postorder(_tree, &_state))
364
365int fr_rb_flatten_inorder(TALLOC_CTX *ctx, void **out[], fr_rb_tree_t *tree);
366
367int fr_rb_flatten_preorder(TALLOC_CTX *ctx, void **out[], fr_rb_tree_t *tree);
368
369int fr_rb_flatten_postorder(TALLOC_CTX *ctx, void **out[], fr_rb_tree_t *tree);
370#ifdef __cplusplus
371}
372#endif
#define RCSIDH(h, id)
Definition build.h:507
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_node_t * node
current node
Definition rb.h:353
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:43
void * fr_rb_iter_init_inorder(fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Initialise an in-order iterator.
Definition rb.c:824
void * fr_rb_iter_next_preorder(fr_rb_tree_t *tree, fr_rb_iter_preorder_t *iter)
fr_rb_node_t * left
Left child.
Definition rb.h:41
fr_rb_node_t *(* rb_node_alloc_t)(fr_rb_tree_t const *tree, void *data)
Callback used to alloc rbnodes.
Definition rb.h:58
void fr_rb_iter_delete_inorder(fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Remove the current node from the tree.
Definition rb.c:899
void * fr_rb_iter_next_postorder(fr_rb_tree_t *tree, fr_rb_iter_postorder_t *iter)
bool being_freed
Disable frees if we're currently calling a free function.
Definition rb.h:47
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
void * fr_rb_iter_init_preorder(fr_rb_tree_t *tree, fr_rb_iter_preorder_t *iter)
Initialise a pre-order iterator.
Definition rb.c:918
fr_rb_node_t * next
if non-NULL, next node cached by fr_rb_iter_delete()
Definition rb.h:321
fr_rb_node_t * node
current node
Definition rb.h:338
fr_cmp_t data_cmp
Callback to compare node data.
Definition rb.h:82
fr_rb_colour_t
Definition rb.h:34
@ BLACK
Definition rb.h:35
@ RED
Definition rb.h:36
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:78
fr_rb_node_t * right
Right child.
Definition rb.h:42
char const * type
Talloc type to check elements against.
Definition rb.h:80
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:312
void * data
data stored in node
Definition rb.h:44
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:66
uint32_t num_elements
How many elements are inside the tree.
Definition rb.h:95
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
fr_free_t data_free
Callback to free node data.
Definition rb.h:83
int fr_rb_flatten_preorder(TALLOC_CTX *ctx, void **out[], fr_rb_tree_t *tree)
uint32_t magic
Definition rb.h:73
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:92
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:86
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:94
void * fr_rb_last(fr_rb_tree_t *tree)
Definition rb.c:801
fr_rb_node_t * node
current node–set to NULL (not NIL) by fr_rb_iter_delete()
Definition rb.h:320
void * fr_rb_iter_init_postorder(fr_rb_tree_t *tree, fr_rb_iter_postorder_t *iter)
Initialise a post-order iterator.
Definition rb.c:995
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:46
rb_node_alloc_t node_alloc
Callback to allocate a new node.
Definition rb.h:85
void * fr_rb_iter_next_inorder(fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
fr_rb_node_t * root
Root of the rbtree.
Definition rb.h:76
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:319
Iterator structure for post-order traversal of an rbtree.
Definition rb.h:352
Iterator structure for pre-order traversal of an rbtree.
Definition rb.h:337
The main red black tree structure.
Definition rb.h:71
static int8_t data_cmp(const void *one, const void *two)
Definition rlm_stats.c:347
fr_aka_sim_id_type_t type
static fr_slen_t data
Definition value.h:1340
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1030