All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rbtree.c
Go to the documentation of this file.
1 /*
2  * rbtree.c RED-BLACK balanced binary trees.
3  *
4  * Version: $Id: edabff93dfbad2f9046310a1c74bd841b2e8f524 $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2004,2006 The FreeRADIUS server project
21  */
22 
23 RCSID("$Id: edabff93dfbad2f9046310a1c74bd841b2e8f524 $")
24 
25 #include <freeradius-devel/libradius.h>
26 
27 #ifdef HAVE_PTHREAD_H
28 #include <pthread.h>
29 
30 #define PTHREAD_MUTEX_LOCK(_x) if (_x->lock) pthread_mutex_lock(&((_x)->mutex))
31 #define PTHREAD_MUTEX_UNLOCK(_x) if (_x->lock) pthread_mutex_unlock(&((_x)->mutex))
32 #else
33 #define PTHREAD_MUTEX_LOCK(_x)
34 #define PTHREAD_MUTEX_UNLOCK(_x)
35 #endif
36 
37 /* Red-Black tree description */
38 typedef enum {
42 
43 struct rbnode_t {
44  rbnode_t *left; //!< Left child
45  rbnode_t *right; //!< Right child
46  rbnode_t *parent; //!< Parent
47  node_colour_t colour; //!< Node colour (BLACK, RED)
48  void *data; //!< data stored in node
49 };
50 
51 #define NIL &sentinel /* all leafs are sentinels */
52 static rbnode_t sentinel = { NIL, NIL, NULL, BLACK, NULL};
53 
54 struct rbtree_t {
55 #ifndef NDEBUG
56  uint32_t magic;
57 #endif
62  bool replace;
63 #ifdef HAVE_PTHREAD_H
64  bool lock;
65  pthread_mutex_t mutex;
66 #endif
67 };
68 #define RBTREE_MAGIC (0x5ad09c42)
69 
70 /** Walks the tree to delete all nodes Does NOT re-balance it!
71  *
72  */
73 static void free_walker(rbtree_t *tree, rbnode_t *x)
74 {
75  (void) talloc_get_type_abort(x, rbnode_t);
76 
77  if (x->left != NIL) free_walker(tree, x->left);
78  if (x->right != NIL) free_walker(tree, x->right);
79 
80  if (tree->free) tree->free(x->data);
81  talloc_free(x);
82 }
83 
84 void rbtree_free(rbtree_t *tree)
85 {
86  if (!tree) return;
87 
88  PTHREAD_MUTEX_LOCK(tree);
89 
90  /*
91  * walk the tree, deleting the nodes...
92  */
93  if (tree->root != NIL) free_walker(tree, tree->root);
94 
95 #ifndef NDEBUG
96  tree->magic = 0;
97 #endif
98  tree->root = NULL;
99 
100  PTHREAD_MUTEX_UNLOCK(tree);
101 
102 #ifdef HAVE_PTHREAD_H
103  if (tree->lock) pthread_mutex_destroy(&tree->mutex);
104 #endif
105 
106  talloc_free(tree);
107 }
108 
109 /** Create a new RED-BLACK tree
110  *
111  */
112 rbtree_t *rbtree_create(TALLOC_CTX *ctx, rb_comparator_t compare, rb_free_t node_free, int flags)
113 {
114  rbtree_t *tree;
115 
116  if (!compare) return NULL;
117 
118  tree = talloc_zero(ctx, rbtree_t);
119  if (!tree) return NULL;
120 
121 #ifndef NDEBUG
122  tree->magic = RBTREE_MAGIC;
123 #endif
124  tree->root = NIL;
125  tree->compare = compare;
126  tree->replace = (flags & RBTREE_FLAG_REPLACE) != 0 ? true : false;
127 #ifdef HAVE_PTHREAD_H
128  tree->lock = (flags & RBTREE_FLAG_LOCK) != 0 ? true : false;
129  if (tree->lock) {
130  pthread_mutex_init(&tree->mutex, NULL);
131  }
132 #endif
133  tree->free = node_free;
134 
135  return tree;
136 }
137 
138 /** Rotate Node x to left
139  *
140  */
141 static void rotate_left(rbtree_t *tree, rbnode_t *x)
142 {
143 
144  rbnode_t *y = x->right;
145 
146  /* establish x->right link */
147  x->right = y->left;
148  if (y->left != NIL) y->left->parent = x;
149 
150  /* establish y->parent link */
151  if (y != NIL) y->parent = x->parent;
152  if (x->parent) {
153  if (x == x->parent->left) {
154  x->parent->left = y;
155  } else {
156  x->parent->right = y;
157  }
158  } else {
159  tree->root = y;
160  }
161 
162  /* link x and y */
163  y->left = x;
164  if (x != NIL) x->parent = y;
165 }
166 
167 /** Rotate Node x to right
168  *
169  */
170 static void rotate_right(rbtree_t *tree, rbnode_t *x)
171 {
172  rbnode_t *y = x->left;
173 
174  /* establish x->left link */
175  x->left = y->right;
176  if (y->right != NIL) y->right->parent = x;
177 
178  /* establish y->parent link */
179  if (y != NIL) y->parent = x->parent;
180  if (x->parent) {
181  if (x == x->parent->right) {
182  x->parent->right = y;
183  } else {
184  x->parent->left = y;
185  }
186  } else {
187  tree->root = y;
188  }
189 
190  /* link x and y */
191  y->right = x;
192  if (x != NIL) x->parent = y;
193 }
194 
195 /** Maintain red-black tree balance after inserting node x
196  *
197  */
198 static void insert_fixup(rbtree_t *tree, rbnode_t *x)
199 {
200  /* check RED-BLACK properties */
201  while ((x != tree->root) && (x->parent->colour == RED)) {
202  /* we have a violation */
203  if (x->parent == x->parent->parent->left) {
204  rbnode_t *y = x->parent->parent->right;
205  if (y->colour == RED) {
206 
207  /* uncle is RED */
208  x->parent->colour = BLACK;
209  y->colour = BLACK;
210  x->parent->parent->colour = RED;
211  x = x->parent->parent;
212  } else {
213 
214  /* uncle is BLACK */
215  if (x == x->parent->right) {
216  /* make x a left child */
217  x = x->parent;
218  rotate_left(tree, x);
219  }
220 
221  /* recolour and rotate */
222  x->parent->colour = BLACK;
223  x->parent->parent->colour = RED;
224  rotate_right(tree, x->parent->parent);
225  }
226  } else {
227 
228  /* mirror image of above code */
229  rbnode_t *y = x->parent->parent->left;
230  if (y->colour == RED) {
231 
232  /* uncle is RED */
233  x->parent->colour = BLACK;
234  y->colour = BLACK;
235  x->parent->parent->colour = RED;
236  x = x->parent->parent;
237  } else {
238 
239  /* uncle is BLACK */
240  if (x == x->parent->left) {
241  x = x->parent;
242  rotate_right(tree, x);
243  }
244  x->parent->colour = BLACK;
245  x->parent->parent->colour = RED;
246  rotate_left(tree, x->parent->parent);
247  }
248  }
249  }
250 
251  tree->root->colour = BLACK;
252 }
253 
254 
255 /** Insert an element into the tree
256  *
257  */
259 {
260  rbnode_t *current, *parent, *x;
261 
262  PTHREAD_MUTEX_LOCK(tree);
263 
264  /* find where node belongs */
265  current = tree->root;
266  parent = NULL;
267  while (current != NIL) {
268  int result;
269 
270  /*
271  * See if two entries are identical.
272  */
273  result = tree->compare(data, current->data);
274  if (result == 0) {
275  /*
276  * Don't replace the entry.
277  */
278  if (!tree->replace) {
279  PTHREAD_MUTEX_UNLOCK(tree);
280  return NULL;
281  }
282 
283  /*
284  * Do replace the entry.
285  */
286  if (tree->free) tree->free(current->data);
287  current->data = data;
288  PTHREAD_MUTEX_UNLOCK(tree);
289  return current;
290  }
291 
292  parent = current;
293  current = (result < 0) ? current->left : current->right;
294  }
295 
296  /* setup new node */
297  x = talloc_zero(tree, rbnode_t);
298  if (!x) {
299  fr_strerror_printf("No memory for new rbtree node");
300  PTHREAD_MUTEX_UNLOCK(tree);
301  return NULL;
302  }
303 
304  x->data = data;
305  x->parent = parent;
306  x->left = NIL;
307  x->right = NIL;
308  x->colour = RED;
309 
310  /* insert node in tree */
311  if (parent) {
312  if (tree->compare(data, parent->data) <= 0) {
313  parent->left = x;
314  } else {
315  parent->right = x;
316  }
317  } else {
318  tree->root = x;
319  }
320 
321  insert_fixup(tree, x);
322 
323  tree->num_elements++;
324 
325  PTHREAD_MUTEX_UNLOCK(tree);
326  return x;
327 }
328 
329 bool rbtree_insert(rbtree_t *tree, void *data)
330 {
331  if (rbtree_insert_node(tree, data)) return true;
332  return false;
333 }
334 
335 /** Maintain RED-BLACK tree balance after deleting node x
336  *
337  */
338 static void delete_fixup(rbtree_t *tree, rbnode_t *x, rbnode_t *parent)
339 {
340 
341  while (x != tree->root && x->colour == BLACK) {
342  if (x == parent->left) {
343  rbnode_t *w = parent->right;
344  if (w->colour == RED) {
345  w->colour = BLACK;
346  parent->colour = RED; /* parent != NIL? */
347  rotate_left(tree, parent);
348  w = parent->right;
349  }
350  if ((w->left->colour == BLACK) && (w->right->colour == BLACK)) {
351  if (w != NIL) w->colour = RED;
352  x = parent;
353  parent = x->parent;
354  } else {
355  if (w->right->colour == BLACK) {
356  if (w->left != NIL) w->left->colour = BLACK;
357  w->colour = RED;
358  rotate_right(tree, w);
359  w = parent->right;
360  }
361  w->colour = parent->colour;
362  if (parent != NIL) parent->colour = BLACK;
363  if (w->right->colour != BLACK) {
364  w->right->colour = BLACK;
365  }
366  rotate_left(tree, parent);
367  x = tree->root;
368  }
369  } else {
370  rbnode_t *w = parent->left;
371  if (w->colour == RED) {
372  w->colour = BLACK;
373  parent->colour = RED; /* parent != NIL? */
374  rotate_right(tree, parent);
375  w = parent->left;
376  }
377  if ((w->right->colour == BLACK) && (w->left->colour == BLACK)) {
378  if (w != NIL) w->colour = RED;
379  x = parent;
380  parent = x->parent;
381  } else {
382  if (w->left->colour == BLACK) {
383  if (w->right != NIL) w->right->colour = BLACK;
384  w->colour = RED;
385  rotate_left(tree, w);
386  w = parent->left;
387  }
388  w->colour = parent->colour;
389  if (parent != NIL) parent->colour = BLACK;
390  if (w->left->colour != BLACK) {
391  w->left->colour = BLACK;
392  }
393  rotate_right(tree, parent);
394  x = tree->root;
395  }
396  }
397  }
398  if (x != NIL) x->colour = BLACK; /* Avoid cache-dirty on NIL */
399 }
400 
401 /** Delete an element (z) from the tree
402  *
403  */
404 static void rbtree_delete_internal(rbtree_t *tree, rbnode_t *z, bool skiplock)
405 {
406  rbnode_t *x, *y;
407  rbnode_t *parent;
408 
409  if (!z || z == NIL) return;
410 
411  if (!skiplock) {
412  PTHREAD_MUTEX_LOCK(tree);
413  }
414 
415  if (z->left == NIL || z->right == NIL) {
416  /* y has a NIL node as a child */
417  y = z;
418  } else {
419  /* find tree successor with a NIL node as a child */
420  y = z->right;
421  while (y->left != NIL) y = y->left;
422  }
423 
424  /* x is y's only child */
425  if (y->left != NIL) {
426  x = y->left;
427  } else {
428  x = y->right; /* may be NIL! */
429  }
430 
431  /* remove y from the parent chain */
432  parent = y->parent;
433  if (x != NIL) x->parent = parent;
434 
435  if (parent) {
436  if (y == parent->left) {
437  parent->left = x;
438  } else {
439  parent->right = x;
440  }
441  } else {
442  tree->root = x;
443  }
444 
445  if (y != z) {
446  if (tree->free) tree->free(z->data);
447  z->data = y->data;
448  y->data = NULL;
449 
450  if ((y->colour == BLACK) && parent) {
451  delete_fixup(tree, x, parent);
452  }
453 
454  /*
455  * The user structure in y->data MAy include a
456  * pointer to y. In that case, we CANNOT delete
457  * y. Instead, we copy z (which is now in the
458  * tree) to y, and fix up the parent/child
459  * pointers.
460  */
461  memcpy(y, z, sizeof(*y));
462 
463  if (!y->parent) {
464  tree->root = y;
465  } else {
466  if (y->parent->left == z) y->parent->left = y;
467  if (y->parent->right == z) y->parent->right = y;
468  }
469  if (y->left->parent == z) y->left->parent = y;
470  if (y->right->parent == z) y->right->parent = y;
471 
472  talloc_free(z);
473 
474  } else {
475  if (tree->free) tree->free(y->data);
476 
477  if (y->colour == BLACK)
478  delete_fixup(tree, x, parent);
479 
480  talloc_free(y);
481  }
482 
483  tree->num_elements--;
484  if (!skiplock) {
485  PTHREAD_MUTEX_UNLOCK(tree);
486  }
487 }
488 void rbtree_delete(rbtree_t *tree, rbnode_t *z) {
489  rbtree_delete_internal(tree, z, false);
490 }
491 
492 /** Delete a node from the tree, based on given data, which MUST have come from rbtree_finddata().
493  *
494  *
495  */
496 bool rbtree_deletebydata(rbtree_t *tree, void const *data)
497 {
498  rbnode_t *node = rbtree_find(tree, data);
499 
500  if (!node) return false;
501 
502  rbtree_delete(tree, node);
503 
504  return true;
505 }
506 
507 
508 /** Find an element in the tree, returning the data, not the node
509  *
510  */
511 rbnode_t *rbtree_find(rbtree_t *tree, void const *data)
512 {
513  rbnode_t *current;
514 
515  PTHREAD_MUTEX_LOCK(tree);
516  current = tree->root;
517 
518  while (current != NIL) {
519  int result = tree->compare(data, current->data);
520 
521  if (result == 0) {
522  PTHREAD_MUTEX_UNLOCK(tree);
523  return current;
524  } else {
525  current = (result < 0) ?
526  current->left : current->right;
527  }
528  }
529 
530  PTHREAD_MUTEX_UNLOCK(tree);
531  return NULL;
532 }
533 
534 /** Find the user data.
535  *
536  */
537 void *rbtree_finddata(rbtree_t *tree, void const *data)
538 {
539  rbnode_t *x;
540 
541  x = rbtree_find(tree, data);
542  if (!x) return NULL;
543 
544  return x->data;
545 }
546 
547 /** Walk the tree, Pre-order
548  *
549  * We call ourselves recursively for each function, but that's OK,
550  * as the stack is only log(N) deep, which is ~12 entries deep.
551  */
552 static int walk_node_pre_order(rbnode_t *x, rb_walker_t compare, void *context)
553 {
554  int rcode;
555  rbnode_t *left, *right;
556 
557  left = x->left;
558  right = x->right;
559 
560  rcode = compare(context, x->data);
561  if (rcode != 0) return rcode;
562 
563  if (left != NIL) {
564  rcode = walk_node_pre_order(left, compare, context);
565  if (rcode != 0) return rcode;
566  }
567 
568  if (right != NIL) {
569  rcode = walk_node_pre_order(right, compare, context);
570  if (rcode != 0) return rcode;
571  }
572 
573  return 0; /* we know everything returned zero */
574 }
575 
576 /** rbtree_in_order
577  *
578  */
579 static int walk_node_in_order(rbnode_t *x, rb_walker_t compare, void *context)
580 {
581  int rcode;
582  rbnode_t *right;
583 
584  if (x->left != NIL) {
585  rcode = walk_node_in_order(x->left, compare, context);
586  if (rcode != 0) return rcode;
587  }
588 
589  right = x->right;
590 
591  rcode = compare(context, x->data);
592  if (rcode != 0) return rcode;
593 
594  if (right != NIL) {
595  rcode = walk_node_in_order(right, compare, context);
596  if (rcode != 0) return rcode;
597  }
598 
599  return 0; /* we know everything returned zero */
600 }
601 
602 
603 /** rbtree_post_order
604  *
605  */
606 static int walk_node_post_order(rbnode_t *x, rb_walker_t compare, void *context)
607 {
608  int rcode;
609 
610  if (x->left != NIL) {
611  rcode = walk_node_post_order(x->left, compare, context);
612  if (rcode != 0) return rcode;
613  }
614 
615  if (x->right != NIL) {
616  rcode = walk_node_post_order(x->right, compare, context);
617  if (rcode != 0) return rcode;
618  }
619 
620  rcode = compare(context, x->data);
621  if (rcode != 0) return rcode;
622 
623  return 0; /* we know everything returned zero */
624 }
625 
626 
627 /** rbtree_delete_order
628  *
629  * This executes an rbtree_in_order-like walk that adapts to changes in the
630  * tree above it, which may occur because we allow the compare to
631  * tell us to delete the current node.
632  *
633  * The compare should return:
634  *
635  * < 0 - on error
636  * 0 - continue walking, don't delete the node
637  * 1 - delete the node and stop walking
638  * 2 - delete the node and continue walking
639  */
640 static int walk_delete_order(rbtree_t *tree, rb_walker_t compare, void *context)
641 {
642  rbnode_t *solid, *x;
643  int rcode = 0;
644 
645  /* Keep track of last node that refused deletion. */
646  solid = NIL;
647  while (solid == NIL) {
648  x = tree->root;
649  if (x == NIL) break;
650  descend:
651  while (x->left != NIL) {
652  x = x->left;
653  }
654  visit:
655  rcode = compare(context, x->data);
656  if (rcode < 0) {
657  return rcode;
658  }
659  if (rcode) {
660  rbtree_delete_internal(tree, x, true);
661  if (rcode != 2) {
662  return rcode;
663  }
664  } else {
665  solid = x;
666  }
667  }
668  if (solid != NIL) {
669  x = solid;
670  if (x->right != NIL) {
671  x = x->right;
672  goto descend;
673  }
674  while (x->parent) {
675  if (x->parent->left == x) {
676  x = x->parent;
677  goto visit;
678  }
679  x = x->parent;
680  }
681  }
682  return rcode;
683 }
684 
685 
686 /*
687  * walk the entire tree. The compare function CANNOT modify
688  * the tree.
689  *
690  * The compare function should return 0 to continue walking.
691  * Any other value stops the walk, and is returned.
692  */
693 int rbtree_walk(rbtree_t *tree, rb_order_t order, rb_walker_t compare, void *context)
694 {
695  int rcode;
696 
697  if (tree->root == NIL) return 0;
698 
699  PTHREAD_MUTEX_LOCK(tree);
700 
701  switch (order) {
702  case RBTREE_PRE_ORDER:
703  rcode = walk_node_pre_order(tree->root, compare, context);
704  break;
705 
706  case RBTREE_IN_ORDER:
707  rcode = walk_node_in_order(tree->root, compare, context);
708  break;
709 
710  case RBTREE_POST_ORDER:
711  rcode = walk_node_post_order(tree->root, compare, context);
712  break;
713 
714  case RBTREE_DELETE_ORDER:
715  rcode = walk_delete_order(tree, compare, context);
716  break;
717 
718  default:
719  rcode = -1;
720  break;
721  }
722 
723  PTHREAD_MUTEX_UNLOCK(tree);
724  return rcode;
725 }
726 
728 {
729  if (!tree) return 0;
730 
731  return tree->num_elements;
732 }
733 
734 /*
735  * Given a Node, return the data.
736  */
738 {
739  if (!node) return NULL;
740 
741  return node->data;
742 }
static void free_walker(rbtree_t *tree, rbnode_t *x)
Walks the tree to delete all nodes Does NOT re-balance it!
Definition: rbtree.c:73
uint32_t magic
Definition: rbtree.c:56
void rbtree_delete(rbtree_t *tree, rbnode_t *z)
Definition: rbtree.c:488
rbnode_t * left
Left child.
Definition: rbtree.c:44
void * data
data stored in node
Definition: rbtree.c:48
#define pthread_mutex_init(_x, _y)
Definition: rlm_eap.h:75
rbnode_t * root
Definition: rbtree.c:58
static void rotate_left(rbtree_t *tree, rbnode_t *x)
Rotate Node x to left.
Definition: rbtree.c:141
rb_comparator_t compare
Definition: rbtree.c:60
int(* rb_comparator_t)(void const *ctx, void const *data)
Definition: libradius.h:529
#define UNUSED
Definition: libradius.h:134
Definition: rbtree.c:40
void rbtree_free(rbtree_t *tree)
Definition: rbtree.c:84
#define RBTREE_FLAG_REPLACE
Definition: libradius.h:526
rbnode_t * parent
Parent.
Definition: rbtree.c:46
rb_order_t
Definition: libradius.h:518
bool replace
Definition: rbtree.c:62
Definition: rbtree.c:39
static int walk_node_pre_order(rbnode_t *x, rb_walker_t compare, void *context)
Walk the tree, Pre-order.
Definition: rbtree.c:552
#define PTHREAD_MUTEX_LOCK(_x)
Definition: rbtree.c:33
static void delete_fixup(rbtree_t *tree, rbnode_t *x, rbnode_t *parent)
Maintain RED-BLACK tree balance after deleting node x.
Definition: rbtree.c:338
static int walk_node_post_order(rbnode_t *x, rb_walker_t compare, void *context)
rbtree_post_order
Definition: rbtree.c:606
static int walk_node_in_order(rbnode_t *x, rb_walker_t compare, void *context)
rbtree_in_order
Definition: rbtree.c:579
static void insert_fixup(rbtree_t *tree, rbnode_t *x)
Maintain red-black tree balance after inserting node x.
Definition: rbtree.c:198
void * rbtree_node2data(UNUSED rbtree_t *tree, rbnode_t *node)
Definition: rbtree.c:737
int rbtree_walk(rbtree_t *tree, rb_order_t order, rb_walker_t compare, void *context)
Definition: rbtree.c:693
int(* rb_walker_t)(void *ctx, void *data)
Definition: libradius.h:530
rbtree_t * rbtree_create(TALLOC_CTX *ctx, rb_comparator_t compare, rb_free_t node_free, int flags)
Create a new RED-BLACK tree.
Definition: rbtree.c:112
void * rbtree_finddata(rbtree_t *tree, void const *data)
Find the user data.
Definition: rbtree.c:537
uint32_t rbtree_num_elements(rbtree_t *tree)
Definition: rbtree.c:727
void(* rb_free_t)(void *data)
Definition: libradius.h:531
static rbnode_t sentinel
Definition: rbtree.c:52
uint8_t data[]
Definition: eap_pwd.h:625
#define RBTREE_MAGIC
Definition: rbtree.c:68
node_colour_t
Definition: rbtree.c:38
#define NIL
Definition: rbtree.c:51
rbnode_t * rbtree_find(rbtree_t *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition: rbtree.c:511
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
#define RBTREE_FLAG_LOCK
Definition: libradius.h:527
rbnode_t * right
Right child.
Definition: rbtree.c:45
static void rotate_right(rbtree_t *tree, rbnode_t *x)
Rotate Node x to right.
Definition: rbtree.c:170
node_colour_t colour
Node colour (BLACK, RED)
Definition: rbtree.c:47
static void rbtree_delete_internal(rbtree_t *tree, rbnode_t *z, bool skiplock)
Delete an element (z) from the tree.
Definition: rbtree.c:404
#define pthread_mutex_destroy(_x)
Definition: rlm_eap.h:76
#define RCSID(id)
Definition: build.h:135
rb_free_t free
Definition: rbtree.c:61
#define PTHREAD_MUTEX_UNLOCK(_x)
Definition: rbtree.c:34
static int walk_delete_order(rbtree_t *tree, rb_walker_t compare, void *context)
rbtree_delete_order
Definition: rbtree.c:640
bool rbtree_insert(rbtree_t *tree, void *data)
Definition: rbtree.c:329
bool rbtree_deletebydata(rbtree_t *tree, void const *data)
Delete a node from the tree, based on given data, which MUST have come from rbtree_finddata().
Definition: rbtree.c:496
rbnode_t * rbtree_insert_node(rbtree_t *tree, void *data)
Insert an element into the tree.
Definition: rbtree.c:258
int num_elements
Definition: rbtree.c:59