The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rb.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /** Red/black tree implementation
18  *
19  * @file src/lib/util/rb.c
20  *
21  * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
22  * @copyright 2004,2006 The FreeRADIUS server project
23  */
24 RCSID("$Id: a94d2f630d9dc8356150a9729c6dc6c686a9bedd $")
25 
26 #include <freeradius-devel/util/rb.h>
27 #include <freeradius-devel/util/strerror.h>
28 
29 #define NIL &sentinel /* all leafs are sentinels */
30 static fr_rb_node_t sentinel = { NIL, NIL, NULL, NULL, BLACK, false };
31 
32 #ifndef NDEBUG
33 # define RB_MAGIC (0x5ad09c42)
34 #endif
35 
36 static int insert_node(fr_rb_node_t **existing, fr_rb_tree_t *tree, void *data) CC_HINT(nonnull(2,3));
37 
38 static inline CC_HINT(always_inline) void node_data_free(fr_rb_tree_t const *tree, fr_rb_node_t *node)
39 {
40  if (!tree->data_free || unlikely(node->being_freed)) return;
41 
42  node->being_freed = true;
43  tree->data_free(node->data);
44 }
45 
46 /** Return the fr_rb_node_t that was allocated as part of the data structure
47  */
48 static fr_rb_node_t *_node_inline_alloc(fr_rb_tree_t const *tree, void *data)
49 {
50  return (fr_rb_node_t *)((uintptr_t)data + tree->offset);
51 }
52 
53 /** Clear the fr_rb_node_t that was allocated as part of the data structure
54  */
55 static void _node_inline_free(fr_rb_tree_t const *tree, fr_rb_node_t *node, bool free_data)
56 {
57  if (free_data && tree->data_free) {
58  node_data_free(tree, node);
59  } else {
60  memset(node, 0, sizeof(fr_rb_node_t)); /* makes "still in tree?" checks easier */
61  }
62 }
63 
64 /** Allocate a new fr_rb_node_t on the heap
65  */
67 {
68  return talloc_zero(tree->node_ctx, fr_rb_node_t);
69 }
70 
71 /** Clear the fr_rb_node_t that was allocated as part of the data structure
72  */
73 static void _node_heap_free(fr_rb_tree_t const *tree, fr_rb_node_t *node, bool free_data)
74 {
75  if (free_data) node_data_free(tree, node);
76  talloc_free(node);
77 }
78 
79 /** Walks the tree to delete all nodes Does NOT re-balance it!
80  *
81  */
82 static void free_walker(fr_rb_tree_t *tree, fr_rb_node_t *x)
83 {
84  if (x->left != NIL) free_walker(tree, x->left);
85  if (x->right != NIL) free_walker(tree, x->right);
86 
87  tree->node_free(tree, x, true);
88 }
89 
90 /** Free the rbtree cleaning up any nodes
91  *
92  * Walk the tree deleting nodes, then free any children of the tree.
93  *
94  * @note If the destructor of a talloc descendent needs to lookup any
95  * information in the tree, it will be unavailable at the point
96  * of freeing. We could fix this by introducing a pre-free callback
97  * which gets called before any of the nodes are deleted.
98  *
99  * @param[in] tree to tree.
100  * @return
101  * - 0 if tree was freed.
102  * - -1 if tree is already being freed.
103  */
104 static int _tree_free(fr_rb_tree_t *tree)
105 {
106  /*
107  * Prevent duplicate frees
108  */
109  if (unlikely(tree->being_freed)) return -1;
110  tree->being_freed = true;
111 
112  /*
113  * walk the tree, deleting the nodes...
114  */
115  if ((tree->root != NIL) && tree->data_free) free_walker(tree, tree->root);
116 
117 #ifndef NDEBUG
118  tree->magic = 0;
119 #endif
120  tree->root = NIL;
121  tree->num_elements = 0;
122 
123  /*
124  * Ensure all dependents on the tree run their
125  * destructors. The tree at this point should
126  * and any tree operations should be empty.
127  */
128  talloc_free_children(tree);
129 
130  return 0;
131 }
132 
133 /** Initialise a new RED-BLACK tree
134  *
135  * @param[out] tree to initialise.
136  * @param[in] node_ctx the ctx used to allocate #fr_rb_node_t if the
137  * tree isn't using inline #fr_rb_node_t.
138  * @param[in] offset offsetof the #fr_rb_node_t field in the data being inserted.
139  * If < 0, nodes will be allocated on the heap.
140  * @param[in] type Talloc type of structures being inserted, may be NULL.
141  * @param[in] data_cmp Comparator function for ordering data in the tree.
142  * @param[in] data_free Free function to call whenever data is deleted or replaced.
143  * @return
144  * - -1 on error.
145  * - 0 on success.
146  */
147 int _fr_rb_init(fr_rb_tree_t *tree, TALLOC_CTX *node_ctx,
148  ssize_t offset, char const *type,
149  fr_cmp_t data_cmp, fr_free_t data_free)
150 {
151 
152  if (unlikely(offset >= UINT16_MAX)) {
153  fr_strerror_printf("Inline fr_rb_node_t offset too large. "
154  "Expected <= %u, got %zd", UINT16_MAX, offset);
155  return -1;
156  }
157 
158  *tree = (fr_rb_tree_t) {
159 #ifndef NDEBUG
160  .magic = RB_MAGIC,
161 #endif
162  .root = NIL,
163  .node_ctx = node_ctx,
164  .offset = offset < 0 ? 0 : (uint16_t)offset,
165  .type = type,
166  .data_cmp = data_cmp,
167  .data_free = data_free,
168  };
169 
170  /*
171  * Use inline nodes
172  */
173  if (offset >= 0) {
176  /*
177  * Allocate node data on the heap
178  */
179  } else {
181  tree->node_free = _node_heap_free;
182  }
183 
184  return 0;
185 }
186 
187 /** Alloc a new RED-BLACK tree
188  *
189  * @param[in] ctx to allocate the tree in.
190  * Only the tree is allocated in this context, the memory
191  * for the #fr_rb_node_t is allocated as part of the data
192  * being inserted into the tree.
193  * @param[in] offset offsetof the #fr_rb_node_t field in the data being inserted.
194  * If < 0, nodes will be allocated on the heap.
195  * @param[in] type Talloc type of structures being inserted, may be NULL.
196  * @param[in] data_cmp Comparator function for ordering data in the tree.
197  * @param[in] data_free Free function to call whenever data is deleted or replaced.
198  * @return
199  * - A new tree on success.
200  * - NULL on failure.
201  */
202 fr_rb_tree_t *_fr_rb_alloc(TALLOC_CTX *ctx,
203  ssize_t offset, char const *type,
204  fr_cmp_t data_cmp, fr_free_t data_free)
205 {
206  fr_rb_tree_t *tree;
207 
208  tree = talloc(ctx, fr_rb_tree_t);
209  if (unlikely(!tree)) return NULL;
210 
211  if (unlikely(_fr_rb_init(tree, tree, offset, type, data_cmp, data_free) < 0)) {
212  talloc_free(tree);
213  return NULL;
214  }
215 
216  talloc_set_destructor(tree, _tree_free);
217 
218  return tree;
219 }
220 
221 /** Rotate Node x to left
222  *
223  */
224 static inline CC_HINT(always_inline) void rotate_left(fr_rb_tree_t *tree, fr_rb_node_t *x)
225 {
226 
227  fr_rb_node_t *y = x->right;
228 
229  /* establish x->right link */
230  x->right = y->left;
231  if (y->left != NIL) y->left->parent = x;
232 
233  /* establish y->parent link */
234  if (y != NIL) y->parent = x->parent;
235  if (x->parent != NIL) {
236  if (x == x->parent->left) {
237  x->parent->left = y;
238  } else {
239  x->parent->right = y;
240  }
241  } else {
242  tree->root = y;
243  }
244 
245  /* link x and y */
246  y->left = x;
247  if (x != NIL) x->parent = y;
248 }
249 
250 /** Rotate Node x to right
251  *
252  */
253 static inline CC_HINT(always_inline) void rotate_right(fr_rb_tree_t *tree, fr_rb_node_t *x)
254 {
255  fr_rb_node_t *y = x->left;
256 
257  /* establish x->left link */
258  x->left = y->right;
259  if (y->right != NIL) y->right->parent = x;
260 
261  /* establish y->parent link */
262  if (y != NIL) y->parent = x->parent;
263  if (x->parent != NIL) {
264  if (x == x->parent->right) {
265  x->parent->right = y;
266  } else {
267  x->parent->left = y;
268  }
269  } else {
270  tree->root = y;
271  }
272 
273  /* link x and y */
274  y->right = x;
275  if (x != NIL) x->parent = y;
276 }
277 
278 /** Maintain red-black tree balance after inserting node x
279  *
280  */
281 static inline CC_HINT(always_inline) void insert_fixup(fr_rb_tree_t *tree, fr_rb_node_t *x)
282 {
283  /* check RED-BLACK properties */
284  while ((x != tree->root) && (x->parent->colour == RED)) {
285  /* we have a violation */
286  if (x->parent == x->parent->parent->left) {
287  fr_rb_node_t *y = x->parent->parent->right;
288  if (y->colour == RED) {
289  /* uncle is RED */
290  x->parent->colour = BLACK;
291  y->colour = BLACK;
292  x->parent->parent->colour = RED;
293  x = x->parent->parent;
294  } else {
295  /* uncle is BLACK */
296  if (x == x->parent->right) {
297  /* make x a left child */
298  x = x->parent;
299  rotate_left(tree, x);
300  }
301 
302  /* recolour and rotate */
303  x->parent->colour = BLACK;
304  x->parent->parent->colour = RED;
305  rotate_right(tree, x->parent->parent);
306  }
307  } else {
308  /* mirror image of above code */
309  fr_rb_node_t *y = x->parent->parent->left;
310  if (y->colour == RED) {
311  /* uncle is RED */
312  x->parent->colour = BLACK;
313  y->colour = BLACK;
314  x->parent->parent->colour = RED;
315  x = x->parent->parent;
316  } else {
317  /* uncle is BLACK */
318  if (x == x->parent->left) {
319  x = x->parent;
320  rotate_right(tree, x);
321  }
322 
323  x->parent->colour = BLACK;
324  x->parent->parent->colour = RED;
325  rotate_left(tree, x->parent->parent);
326  }
327  }
328  }
329 
330  tree->root->colour = BLACK;
331 }
332 
333 
334 /** Insert an element into the tree
335  *
336  * @param[out] existing if a node exists, and existing is not NULL
337  * this will be populated with the node.
338  * @param[in] tree to search in.
339  * @param[in] data to search for.
340  * @return
341  * - 1 on existing (with existing populated).
342  * - 0 on success.
343  * - -1 on failure.
344  */
345 static int insert_node(fr_rb_node_t **existing, fr_rb_tree_t *tree, void *data)
346 {
347  fr_rb_node_t *current, *parent, *x;
348 
349  if (unlikely(tree->being_freed)) return -1;
350 
351 #ifndef TALLOC_GET_TYPE_ABORT_NOOP
352  if (tree->type) (void)_talloc_get_type_abort(data, tree->type, __location__);
353 #endif
354 
355  /* find where node belongs */
356  current = tree->root;
357  parent = NIL;
358  while (current != NIL) {
359  int result;
360 
361  /*
362  * See if two entries are identical.
363  */
364  result = tree->data_cmp(data, current->data);
365  if (result == 0) {
366  if (existing) *existing = current;
367  return 1;
368  }
369 
370  parent = current;
371  current = (result < 0) ? current->left : current->right;
372  }
373 
374  /* setup new node */
375  x = tree->node_alloc(tree, data);
376  if (unlikely(!x)) return -1;
377 
378  *x = (fr_rb_node_t){
379  .data = data,
380  .parent = parent,
381  .left = NIL,
382  .right = NIL,
383  .colour = RED
384  };
385 
386  /* insert node in tree */
387  if (parent != NIL) {
388  if (tree->data_cmp(data, parent->data) <= 0) {
389  parent->left = x;
390  } else {
391  parent->right = x;
392  }
393  } else {
394  tree->root = x;
395  }
396 
397  insert_fixup(tree, x);
398 
399  tree->num_elements++;
400 
401  return 0;
402 }
403 
404 /** Maintain RED-BLACK tree balance after deleting node x
405  *
406  */
408 {
409  while (x != tree->root && x->colour == BLACK) {
410  if (x == parent->left) {
411  fr_rb_node_t *w = parent->right;
412  if (w->colour == RED) {
413  w->colour = BLACK;
414  parent->colour = RED; /* parent != NIL? */
415  rotate_left(tree, parent);
416  w = parent->right;
417  }
418  if ((w->left->colour == BLACK) && (w->right->colour == BLACK)) {
419  if (w != NIL) w->colour = RED;
420  x = parent;
421  parent = x->parent;
422  } else {
423  if (w->right->colour == BLACK) {
424  if (w->left != NIL) w->left->colour = BLACK;
425  w->colour = RED;
426  rotate_right(tree, w);
427  w = parent->right;
428  }
429  w->colour = parent->colour;
430  if (parent != NIL) parent->colour = BLACK;
431  if (w->right->colour != BLACK) {
432  w->right->colour = BLACK;
433  }
434  rotate_left(tree, parent);
435  x = tree->root;
436  }
437  } else {
438  fr_rb_node_t *w = parent->left;
439  if (w->colour == RED) {
440  w->colour = BLACK;
441  parent->colour = RED; /* parent != NIL? */
442  rotate_right(tree, parent);
443  w = parent->left;
444  }
445  if ((w->right->colour == BLACK) && (w->left->colour == BLACK)) {
446  if (w != NIL) w->colour = RED;
447  x = parent;
448  parent = x->parent;
449  } else {
450  if (w->left->colour == BLACK) {
451  if (w->right != NIL) w->right->colour = BLACK;
452  w->colour = RED;
453  rotate_left(tree, w);
454  w = parent->left;
455  }
456  w->colour = parent->colour;
457  if (parent != NIL) parent->colour = BLACK;
458  if (w->left->colour != BLACK) {
459  w->left->colour = BLACK;
460  }
461  rotate_right(tree, parent);
462  x = tree->root;
463  }
464  }
465  }
466  if (x != NIL) x->colour = BLACK; /* Avoid cache-dirty on NIL */
467 }
468 
469 /** Delete an element (z) from the tree
470  *
471  */
472 static void delete_internal(fr_rb_tree_t *tree, fr_rb_node_t *z, bool free_data)
473 {
474  fr_rb_node_t *x, *y;
476 
477  if (!z || z == NIL) return;
478 
479  if (z->left == NIL || z->right == NIL) {
480  /* y has a NIL node as a child */
481  y = z;
482  } else {
483  /* find tree successor with a NIL node as a child */
484  y = z->right;
485  while (y->left != NIL) y = y->left;
486  }
487 
488  /* x is y's only child */
489  if (y->left != NIL) {
490  x = y->left;
491  } else {
492  x = y->right; /* may be NIL! */
493  }
494 
495  /* remove y from the parent chain */
496  parent = y->parent;
497  if (x != NIL) x->parent = parent;
498 
499  if (parent != NIL) {
500  if (y == parent->left) {
501  parent->left = x;
502  } else {
503  parent->right = x;
504  }
505  } else {
506  tree->root = x;
507  }
508 
509  if (y != z) {
510  void *y_data = y->data;
511 
512  if ((y->colour == BLACK) && parent) delete_fixup(tree, x, parent);
513 
514  /*
515  * The user structure in y->data May include a
516  * pointer to y. In that case, we CANNOT delete
517  * y. Instead, we copy z (which is now in the
518  * tree) to y, and fix up the parent/child
519  * pointers.
520  */
521  memcpy(y, z, sizeof(*y));
522  y->data = y_data;
523 
524  if (y->parent == NIL) {
525  tree->root = y;
526  } else {
527  if (y->parent->left == z) y->parent->left = y;
528  if (y->parent->right == z) y->parent->right = y;
529  }
530  if (y->left->parent == z) y->left->parent = y;
531  if (y->right->parent == z) y->right->parent = y;
532 
533  tree->node_free(tree, z, free_data);
534  } else {
535  if (y->colour == BLACK) delete_fixup(tree, x, parent);
536 
537  tree->node_free(tree, y, free_data);
538  }
539 
540  tree->num_elements--;
541 }
542 
543 
544 /* Find user data, returning the node
545  *
546  */
547 static inline CC_HINT(always_inline) fr_rb_node_t *find_node(fr_rb_tree_t const *tree, void const *data)
548 {
550 
551  if (unlikely(tree->being_freed)) return NULL;
552 
553  current = tree->root;
554 
555  while (current != NIL) {
556  int result = tree->data_cmp(data, current->data);
557 
558  if (result == 0) return current;
559 
560  current = (result < 0) ? current->left : current->right;
561  }
562 
563  return NULL;
564 }
565 
566 /** Find an element in the tree, returning the data, not the node
567  *
568  * @param[in] tree to search in.
569  * @param[in] data to find.
570  * @return
571  * - User data matching the data passed in.
572  * - NULL if nothing matched passed data.
573  *
574  * @hidecallergraph
575  */
576 void *fr_rb_find(fr_rb_tree_t const *tree, void const *data)
577 {
578  fr_rb_node_t *x;
579 
580  if (unlikely(tree->being_freed)) return NULL;
581  x = find_node(tree, data);
582  if (!x) return NULL;
583 
584  return x->data;
585 }
586 
587 /** Attempt to find current data in the tree, if it does not exist insert it
588  *
589  * @param[out] found Pre-existing data we found.
590  * @param[in] tree to search/insert into.
591  * @param[in] data to find.
592  * @return
593  * - 1 if existing data was found, found will be populated.
594  * - 0 if no existing data was found.
595  * - -1 on insert error.
596  */
597 int fr_rb_find_or_insert(void **found, fr_rb_tree_t *tree, void const *data)
598 {
599  fr_rb_node_t *existing;
600 
601  switch (insert_node(&existing, tree, UNCONST(void *, data))) {
602  case 1:
603  if (found) *found = existing->data;
604  return 1;
605 
606  case 0:
607  if (found) *found = NULL;
608  return 0;
609 
610  default:
611  if (found) *found = NULL;
612  return -1;
613  }
614 }
615 
616 /** Insert data into a tree
617  *
618  * @param[in] tree to insert data into.
619  * @param[in] data to insert.
620  * @return
621  * - true if data was inserted.
622  * - false if data already existed and was not inserted.
623  */
624 bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
625 {
626  if (insert_node(NULL, tree, UNCONST(void *, data)) == 0) return true;
627 
628  return false;
629 }
630 
631 /** Replace old data with new data, OR insert if there is no old
632  *
633  * @param[out] old data that was replaced. If this argument
634  * is not NULL, then the old data will not
635  * be freed, even if a free function is
636  * configured.
637  * @param[in] tree to insert data into.
638  * @param[in] data to replace.
639  * @return
640  * - 1 if data was replaced.
641  * - 0 if data was inserted.
642  * - -1 if we failed to replace data
643  */
644 int fr_rb_replace(void **old, fr_rb_tree_t *tree, void const *data)
645 {
646  fr_rb_node_t *node;
647 
648  switch (insert_node(&node, tree, UNCONST(void *, data))) {
649  case 1: /* Something exists */
650  {
651  void *old_data = node->data;
652 
653  /*
654  * If the fr_node_t is inline with the
655  * data structure, we need to delete
656  * the old node out of the tree, and
657  * perform a normal insert operation.
658  */
659  if (tree->node_alloc == _node_inline_alloc) {
660  delete_internal(tree, node, false);
661  insert_node(NULL, tree, UNCONST(void *, data));
662  } else {
663  node->data = UNCONST(void *, data);
664  }
665 
666  if (old) {
667  *old = old_data;
668  } else if (tree->data_free) {
669  tree->data_free(old_data);
670  }
671  return 1;
672  }
673  case 0: /* New node was inserted - There was no pre-existing node */
674  if (old) *old = NULL;
675  return 0;
676 
677  default:
678  if (old) *old = NULL;
679  return -1;
680  }
681 }
682 
683 /** Remove an entry from the tree, without freeing the data
684  *
685  * @param[in] tree to remove data from.
686  * @param[in] data to remove.
687  * @return
688  * - The user data we removed.
689  * - NULL if we couldn't find any matching data.
690  */
691 void *fr_rb_remove(fr_rb_tree_t *tree, void const *data)
692 {
693  fr_rb_node_t *node;
694  void *node_data;
695 
696  if (unlikely(tree->being_freed)) return false;
697  node = find_node(tree, data);
698  if (!node) return NULL;
699 
700  if (unlikely(node->being_freed)) return node->data;
701 
702  node_data = node->data;
703  delete_internal(tree, node, false); /* nullified node->data */
704  return node_data;
705 }
706 
707 /** Remove an entry from the tree, using the node structure, without freeing the data
708  *
709  * This function can help where multiple items may be in the
710  * tree with the same comparator value.
711  *
712  * @param[in] tree to remove data from.
713  * @param[in] node to remove.
714  * @return
715  * - The user data we removed.
716  * - NULL if the user data wasn't in the tree.
717  */
719 {
720  void *node_data;
721 
722  if (!fr_rb_node_inline_in_tree(node)) return NULL;
723  node_data = node->data;
724  delete_internal(tree, node, false); /* nullified node->data */
725  return node_data;
726 }
727 
728 /** Remove node and free data (if a free function was specified)
729  *
730  * @param[in] tree to remove data from.
731  * @param[in] data to remove/free.
732  * @return
733  * - true if we removed data.
734  * - false if we couldn't find any matching data.
735  */
736 bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
737 {
738  fr_rb_node_t *node;
739 
740  if (unlikely(tree->being_freed)) return false;
741  node = find_node(tree, data);
742  if (!node) return false;
743 
744  if (unlikely(node->being_freed)) return true;
745 
746  delete_internal(tree, node, true);
747 
748  return true;
749 }
750 
751 /** Remove node and free data (if a free function was specified)
752  *
753  * This function can help where multiple items may be in the
754  * tree with the same comparator value.
755  *
756  * @param[in] tree to remove data from.
757  * @param[in] node to remove/free.
758  * @return
759  * - true if we removed data.
760  * - false if we couldn't find any matching data.
761  */
763 {
764  if (!fr_rb_node_inline_in_tree(node)) return false;
765 
766  delete_internal(tree, node, true);
767 
768  return true;
769 }
770 
771 /** Return how many nodes there are in a tree
772  *
773  * @param[in] tree to return node count for.
774  */
776 {
777  return tree->num_elements;
778 }
779 
781 {
782  fr_rb_node_t *x = tree->root;
783 
784  if (x == NIL) return NULL;
785 
786  /*
787  * First node is the leftmost
788  */
789  while (x->left != NIL) x = x->left;
790 
791  return x->data;
792 }
793 
794 
796 {
797  fr_rb_node_t *x = tree->root;
798 
799  if (x == NIL) return NULL;
800 
801  /*
802  * Last node is the rightmost
803  */
804  while (x->right != NIL) x = x->right;
805 
806  return x->data;
807 }
808 
809 
810 /** Initialise an in-order iterator
811  *
812  * @param[out] iter to initialise.
813  * @param[in] tree to iterate over.
814  * @return
815  * - The first node. Mutex will be held.
816  * - NULL if the tree is empty.
817  */
819 {
820  fr_rb_node_t *x = tree->root;
821 
822  if (x == NIL) return NULL;
823 
824  /*
825  * First node is the leftmost
826  */
827  while (x->left != NIL) x = x->left;
828 
829  *iter = (fr_rb_iter_inorder_t){
830  .tree = tree,
831  .node = x
832  };
833 
834  return x->data;
835 }
836 
837 /** Return the next node
838  *
839  * @param[in] iter previously initialised with #fr_rb_iter_init_inorder
840  * @return
841  * - The next node.
842  * - NULL if no more nodes remain.
843  */
845 {
846  fr_rb_node_t *x = iter->node, *y;
847 
848  /*
849  * Catch callers repeatedly calling iterator
850  * at the end.
851  */
852  if (unlikely(iter->node == NIL)) return NULL;
853 
854  /*
855  * fr_rb_iter_delete() has already deleted this node,
856  * and saved the next one for us. (We check for NULL;
857  * NIL just means we're at the end.)
858  */
859  if (!iter->node) {
860  iter->node = iter->next;
861  iter->next = NULL;
862  return iter->node->data;
863  }
864 
865  if (x->right != NIL) {
866  x = x->right;
867 
868  while (x->left != NIL) x = x->left;
869  iter->node = x;
870 
871  return x->data;
872  }
873 
874  y = x;
875  x = x->parent;
876  while ((x != NIL) && (y == x->right)) {
877  y = x;
878  x = x->parent;
879  }
880 
881  iter->node = x;
882 
883  return x->data;
884 }
885 
886 /** Remove the current node from the tree
887  *
888  * @note Only makes sense for in-order traversals.
889  *
890  * @param[in] iter previously initialised with #fr_rb_iter_init_inorder
891  */
893 {
894  fr_rb_node_t *x = iter->node;
895 
896  if (unlikely(x == NIL)) return;
897  (void) fr_rb_iter_next_inorder(iter);
898  iter->next = iter->node;
899  iter->node = NULL;
900  delete_internal(iter->tree, x, true);
901 }
902 
903 /** Initialise a pre-order iterator
904  *
905  * @param[out] iter to initialise.
906  * @param[in] tree to iterate over.
907  * @return
908  * - The first node. Mutex will be held.
909  * - NULL if the tree is empty.
910  */
912 {
913  fr_rb_node_t *x = tree->root;
914 
915  if (x == NIL) return NULL;
916 
917  /*
918  * First, the root.
919  */
920  *iter = (fr_rb_iter_preorder_t){
921  .tree = tree,
922  .node = x
923  };
924 
925  return x->data;
926 }
927 
928 /** Return the next node
929  *
930  * @param[in] iter previously initialised with #fr_rb_iter_init_preorder
931  * @return
932  * - The next node.
933  * - NULL if no more nodes remain.
934  */
936 {
937  fr_rb_node_t *x = iter->node, *y;
938 
939  /*
940  * Catch callers repeatedly calling iterator
941  * at the end.
942  */
943  if (unlikely(iter->node == NIL)) return NULL;
944 
945  /*
946  * Next is a child of the just-returned node, if it has one.
947  * (Left child first.)
948  */
949  if (x->left != NIL) {
950  x = x->left;
951  iter->node = x;
952  return x->data;
953  }
954  if (x->right != NIL) {
955  x = x->right;
956  iter->node = x;
957  return x->data;
958  }
959 
960  /*
961  * Otherwise, the nearest ancestor's unreturned right
962  * child, if one exists.
963  */
964  for (; (y = x->parent) != NIL; x = y) {
965  if (y->right != NIL && y->right != x) {
966  x = y->right;
967  iter->node = x;
968  return x->data;
969  }
970  }
971 
972  /*
973  * None of the above? We're done.
974  */
975  iter->node = NIL;
976 
977  return NULL;
978 }
979 
980 /** Initialise a post-order iterator
981  *
982  * @param[out] iter to initialise.
983  * @param[in] tree to iterate over.
984  * @return
985  * - The first node.
986  * - NULL if the tree is empty.
987  */
989 {
990  fr_rb_node_t *x = tree->root;
991 
992  if (x == NIL) return NULL;
993 
994  /*
995  * First: the deepest leaf to the left (jogging to the
996  * right if there's a right child but no left).
997  */
998  for (;;) {
999  for (; x->left != NIL; x = x->left) ;
1000  if (x->right == NIL) break;
1001  x = x->right;
1002  }
1003 
1004  *iter = (fr_rb_iter_postorder_t){
1005  .tree = tree,
1006  .node = x
1007  };
1008 
1009  return x->data;
1010 }
1011 
1012 /** Return the next node
1013  *
1014  * @param[in] iter previously initialised with #fr_rb_iter_init_postorder
1015  * @return
1016  * - The next node.
1017  * - NULL if no more nodes remain.
1018  */
1020 {
1021  fr_rb_node_t *x = iter->node, *y;
1022 
1023  /*
1024  * Catch callers repeatedly calling iterator
1025  * at the end.
1026  */
1027  if (unlikely(iter->node == NIL)) return NULL;
1028 
1029  /*
1030  * This is postorder, so a just-returned node's
1031  * descendants have all been returned. If there
1032  * is another node, it's an ancestor or one of
1033  * its not-yet-returned descendants...but if
1034  * we're at the root, we're done.
1035  */
1036  y = x->parent;
1037  if (y == NIL) {
1038  iter->node = NIL;
1039  return NULL;
1040  }
1041 
1042  /*
1043  * Return the parent if it has no right child, or it has one but
1044  * it's been returned.
1045  */
1046  if (y->right == NIL || y->right == x) {
1047  iter->node = y;
1048  return y->data;
1049  }
1050 
1051  /*
1052  * Otherwise, it's as if we're starting over with the right child.
1053  */
1054  x = y->right;
1055  for (;;) {
1056  for (; x->left != NIL; x = x->left) ;
1057  if (x->right == NIL) break;
1058  x = x->right;
1059  }
1060 
1061  iter->node = x;
1062  return x->data;
1063 }
1064 
1065 #define DEF_RB_FLATTEN_FUNC(_order) \
1066 int fr_rb_flatten_##_order(TALLOC_CTX *ctx, void **out[], fr_rb_tree_t *tree) \
1067 { \
1068  uint32_t num = fr_rb_num_elements(tree), i; \
1069  fr_rb_iter_##_order##_t iter; \
1070  void *item, **list; \
1071  if (unlikely(!(list = talloc_array(ctx, void *, num)))) return -1; \
1072  for (item = fr_rb_iter_init_##_order(&iter, tree), i = 0; \
1073  item; \
1074  item = fr_rb_iter_next_##_order(&iter), i++) list[i] = item; \
1075  *out = list; \
1076  return 0; \
1077 }
1078 DEF_RB_FLATTEN_FUNC(preorder)
1079 DEF_RB_FLATTEN_FUNC(postorder)
1080 DEF_RB_FLATTEN_FUNC(inorder)
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define RCSID(id)
Definition: build.h:444
#define unlikely(_x)
Definition: build.h:378
#define UNUSED
Definition: build.h:313
size_t y
Definition: dbuff.c:67
talloc_free(reap)
unsigned short uint16_t
Definition: merged_model.c:31
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
int8_t(* fr_cmp_t)(void const *a, void const *b)
Definition: misc.h:38
void(* fr_free_t)(void *)
Definition: misc.h:39
static rc_request_t * current
Definition: radclient-ng.c:97
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:911
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition: rb.c:775
void * fr_rb_first(fr_rb_tree_t *tree)
Definition: rb.c:780
static fr_rb_node_t sentinel
Definition: rb.c:30
#define RB_MAGIC
Definition: rb.c:33
#define NIL
Definition: rb.c:29
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:988
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:597
void fr_rb_iter_delete_inorder(fr_rb_iter_inorder_t *iter)
Remove the current node from the tree.
Definition: rb.c:892
#define DEF_RB_FLATTEN_FUNC(_order)
Definition: rb.c:1065
static fr_rb_node_t * find_node(fr_rb_tree_t const *tree, void const *data)
Definition: rb.c:547
static int insert_node(fr_rb_node_t **existing, fr_rb_tree_t *tree, void *data))
Insert an element into the tree.
Definition: rb.c:345
static void delete_fixup(fr_rb_tree_t *tree, fr_rb_node_t *x, fr_rb_node_t *parent)
Maintain RED-BLACK tree balance after deleting node x.
Definition: rb.c:407
static void delete_internal(fr_rb_tree_t *tree, fr_rb_node_t *z, bool free_data)
Delete an element (z) from the tree.
Definition: rb.c:472
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:644
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
Definition: rb.c:844
static fr_rb_node_t * _node_inline_alloc(fr_rb_tree_t const *tree, void *data)
Return the fr_rb_node_t that was allocated as part of the data structure.
Definition: rb.c:48
static fr_rb_node_t * _node_heap_alloc(fr_rb_tree_t const *tree, UNUSED void *data)
Allocate a new fr_rb_node_t on the heap.
Definition: rb.c:66
void * fr_rb_iter_next_preorder(fr_rb_iter_preorder_t *iter)
Return the next node.
Definition: rb.c:935
static void free_walker(fr_rb_tree_t *tree, fr_rb_node_t *x)
Walks the tree to delete all nodes Does NOT re-balance it!
Definition: rb.c:82
static void node_data_free(fr_rb_tree_t const *tree, fr_rb_node_t *node)
Definition: rb.c:38
static int _tree_free(fr_rb_tree_t *tree)
Free the rbtree cleaning up any nodes.
Definition: rb.c:104
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:691
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:762
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
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_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:718
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition: rb.c:624
void * fr_rb_iter_next_postorder(fr_rb_iter_postorder_t *iter)
Return the next node.
Definition: rb.c:1019
void * fr_rb_last(fr_rb_tree_t *tree)
Definition: rb.c:795
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:736
static void rotate_right(fr_rb_tree_t *tree, fr_rb_node_t *x)
Rotate Node x to right.
Definition: rb.c:253
static void _node_heap_free(fr_rb_tree_t const *tree, fr_rb_node_t *node, bool free_data)
Clear the fr_rb_node_t that was allocated as part of the data structure.
Definition: rb.c:73
static void _node_inline_free(fr_rb_tree_t const *tree, fr_rb_node_t *node, bool free_data)
Clear the fr_rb_node_t that was allocated as part of the data structure.
Definition: rb.c:55
static void rotate_left(fr_rb_tree_t *tree, fr_rb_node_t *x)
Rotate Node x to left.
Definition: rb.c:224
static void insert_fixup(fr_rb_tree_t *tree, fr_rb_node_t *x)
Maintain red-black tree balance after inserting node x.
Definition: rb.c:281
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:818
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:576
fr_rb_tree_t * tree
Tree being iterated over.
Definition: rb.h:322
fr_rb_node_t * node
current node
Definition: rb.h:358
fr_rb_node_t * parent
Parent.
Definition: rb.h:45
struct fr_rb_node_s fr_rb_node_t
Definition: rb.h:41
fr_rb_node_t * left
Left child.
Definition: rb.h:43
bool being_freed
Disable frees if we're currently calling a free function.
Definition: rb.h:49
struct fr_rb_tree_s fr_rb_tree_t
Definition: rb.h:53
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
fr_cmp_t data_cmp
Callback to compare node data.
Definition: rb.h:84
@ BLACK
Definition: rb.h:37
@ RED
Definition: rb.h:38
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 * data
data stored in node
Definition: rb.h:46
uint32_t num_elements
How many elements are inside the tree.
Definition: rb.h:97
fr_free_t data_free
Callback to free node data.
Definition: rb.h:85
uint32_t magic
Definition: rb.h:75
fr_rb_tree_t * tree
Tree being iterated over.
Definition: rb.h:341
uint16_t offset
Where's the fr_rb_node_t is located in the structure being inserted.
Definition: rb.h:94
rb_node_free_t node_free
Callback to free a node.
Definition: rb.h:88
bool being_freed
Prevent double frees in talloc_destructor.
Definition: rb.h:96
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
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:350
fr_aka_sim_id_type_t type
static fr_slen_t parent
Definition: pair.h:844
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
static fr_slen_t data
Definition: value.h:1259
int nonnull(2, 5))