The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rbmonkey.c
Go to the documentation of this file.
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <netdb.h>
4 
5 #include <freeradius-devel/util/rb.c>
6 #include <freeradius-devel/util/rand.h>
7 
8 typedef struct {
9  uint32_t num;
10  fr_rb_node_t node;
12 
13 static int8_t comp(void const *a, void const *b)
14 {
15  fr_rb_tree_test_node_t const *our_a = a, *our_b = b;
16 
17  return CMP(our_a->num, our_b->num);
18 }
19 
20 static int qsort_comp(void const *a, void const *b)
21 {
22  return comp(a, b);
23 }
24 
25 
26 #if 0
27 static int print_cb(void *i, UNUSED void *uctx)
28 {
29  fprintf(stderr, "%i\n", (fr_rb_tree_test_node_t *)i->num);
30  return 0;
31 }
32 #endif
33 
34 #define MAXSIZE 1024
35 
36 static int cb_stored = 0;
38 
39 static uint32_t mask;
40 
41 static int filter_cb(void *i, void *uctx)
42 {
43  if ((((fr_rb_tree_test_node_t *)i)->num & mask) == (((fr_rb_tree_test_node_t *)uctx)->num & mask)) {
44  return 2;
45  }
46  return 0;
47 }
48 
49 /*
50  * Returns the count of BLACK nodes from root to child leaves, or a
51  * negative number indicating which RED-BLACK rule was broken.
52  */
53 static int rbcount(fr_rb_tree_t *t)
54 {
55  fr_rb_node_t *n;
56  int count, count_expect;
57 
58  count_expect = -1;
59  n = t->root;
60  if (!n || n == NIL) {
61  return 0;
62  }
63  if (n->colour != BLACK) {
64  return -2; /* root not BLACK */
65  }
66  count = 0;
67 descend:
68  while (n->left != NIL) {
69  if (n->colour == RED) {
70  if (n->left->colour != BLACK || n->right->colour != BLACK) {
71  return -4; /* Children of RED nodes must be BLACK */
72  }
73  }
74  else {
75  count++;
76  }
77  n = n->left;
78  }
79  if (n->right != NIL) {
80  if (n->colour == RED) {
81  if (n->left->colour != BLACK || n->right->colour != BLACK) {
82  return -4; /* Children of RED nodes must be BLACK */
83  }
84  }
85  else {
86  count++;
87  }
88  n = n->right;
89  }
90  if ((n->left != NIL) || (n->right != NIL)) {
91  goto descend;
92  }
93  if (count_expect < 0) {
94  count_expect = count + (n->colour == BLACK);
95  }
96  else {
97  if (count_expect != count + (n->colour == BLACK)) {
98  fprintf(stderr,"Expected %i got %i\n", count_expect, count);
99  return -5; /* All paths must traverse the same number of BLACK nodes. */
100  }
101  }
102 ascend:
103  if (n->parent == NIL) return count_expect;
104  while (n->parent->right == n) {
105  n = n->parent;
106  if (!n->parent) return count_expect;
107  if (n->colour == BLACK) {
108  count--;
109  }
110  }
111  if (n->parent->left == n) {
112  if (n->parent->right != NIL) {
113  n = n->parent->right;
114  goto descend;
115  }
116  n = n->parent;
117  if (!n->parent) return count_expect;
118  if (n->colour == BLACK) {
119  count--;
120  }
121  }
122  goto ascend;
123 }
124 
125 #define REPS 10
126 
127 static void freenode(void *data)
128 {
129  talloc_free(data);
130 }
131 
132 int main(UNUSED int argc, UNUSED char *argv[])
133 {
134  fr_rb_tree_t *t;
135  int i, j;
136  fr_rb_tree_test_node_t thresh = {};
137  int n, rep;
140  fr_rb_tree_test_node_t const *node;
141 
142  memset(&vals, 0, sizeof(vals));
143 
144  /* TODO: make starting seed and repetitions a CLI option */
145  rep = REPS;
146 
147 again:
148  if (!--rep) return 0;
149 
150  thresh.num = fr_rand();
151  mask = 0xff >> (fr_rand() & 7);
152  thresh.num &= mask;
153  n = (fr_rand() % MAXSIZE) + 1;
154 
155  fprintf(stderr, "filter = %x mask = %x n = %i\n", thresh.num, mask, n);
156 
158  for (i = 0; i < n; i++) {
160 
161  p = talloc(t, fr_rb_tree_test_node_t); /* Do not use talloc_zero, rbcode should initialise fr_rb_node_t */
162  p->num = fr_rand();
163  vals[i].num = p->num;
164  fr_rb_insert(t, p);
165  }
166 
167  i = rbcount(t);
168  fprintf(stderr,"After insert rbcount is %i\n", i);
169  if (i < 0) return i;
170 
171  qsort(vals, n, sizeof(fr_rb_tree_test_node_t), qsort_comp);
172 
173  /*
174  * For testing deletebydata instead
175 
176  for (i = 0; i < n; i++) {
177  if (filter_cb(&vals[i], &thresh) == 2) fr_rb_delete(t, &vals[i]);
178  }
179 
180  *
181  */
182  for (node = fr_rb_iter_init_inorder(&iter, t);
183  node;
184  node = fr_rb_iter_next_inorder(&iter)) {
185  if ((node->num & mask) == (thresh.num & mask)) fr_rb_iter_delete_inorder(&iter);
186  }
187  i = rbcount(t);
188  fprintf(stderr,"After delete rbcount is %i\n", i);
189  if (i < 0) return i;
190 
191  cb_stored = 0;
192  for (node = fr_rb_iter_init_inorder(&iter, t);
193  node;
194  node = fr_rb_iter_next_inorder(&iter)) {
195  rvals[cb_stored++].num = node->num;
196  }
197 
198  for (j = i = 0; i < n; i++) {
199  if (i && (vals[i-1].num == vals[i].num)) continue;
200  if (!filter_cb(&thresh, &vals[i])) {
201  if (vals[i].num != rvals[j].num) goto bad;
202  j++;
203  }
204  }
205  fprintf(stderr,"matched OK\n");
206  talloc_free(t);
207  goto again;
208 
209 bad:
210  for (j = i = 0; i < n; i++) {
211  if (i && vals[i-1].num == vals[i].num) continue;
212  if (!filter_cb(&thresh, &vals[i])) {
213  fprintf(stderr, "%i: %x %x\n", j, vals[i].num, rvals[j].num);
214  j++;
215  } else {
216  fprintf(stderr, "skipped %x\n", vals[i].num);
217  }
218  }
219  return EXIT_FAILURE;
220 }
221 
int n
Definition: acutest.h:577
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition: build.h:110
#define UNUSED
Definition: build.h:313
talloc_free(reap)
unsigned int uint32_t
Definition: merged_model.c:33
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
#define NIL
Definition: rb.c:29
void fr_rb_iter_delete_inorder(fr_rb_iter_inorder_t *iter)
Remove the current node from the tree.
Definition: rb.c:892
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
Definition: rb.c:844
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_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
Definition: rb.c:818
@ BLACK
Definition: rb.h:37
@ RED
Definition: rb.h:38
#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black tree.
Definition: rb.h:271
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
The main red black tree structure.
Definition: rb.h:73
static int filter_cb(void *i, void *uctx)
Definition: rbmonkey.c:41
#define REPS
Definition: rbmonkey.c:125
#define MAXSIZE
Definition: rbmonkey.c:34
static int8_t comp(void const *a, void const *b)
Definition: rbmonkey.c:13
static fr_rb_tree_test_node_t rvals[MAXSIZE]
Definition: rbmonkey.c:37
static int qsort_comp(void const *a, void const *b)
Definition: rbmonkey.c:20
int main(UNUSED int argc, UNUSED char *argv[])
Definition: rbmonkey.c:132
static int cb_stored
Definition: rbmonkey.c:36
static void freenode(void *data)
Definition: rbmonkey.c:127
static uint32_t mask
Definition: rbmonkey.c:39
static int rbcount(fr_rb_tree_t *t)
Definition: rbmonkey.c:53
return count
Definition: module.c:175
static fr_slen_t data
Definition: value.h:1259