fixed: was potentially storing stack-allocated name strings in the trackmap
[andemo] / src / rbtree.c
1 /*
2 rbtree - simple balanced binary search tree (red-black tree) library.
3 Copyright (C) 2011-2014  John Tsiombikas <nuclear@member.fsf.org>
4
5 rbtree is free software, feel free to use, modify, and redistribute it, under
6 the terms of the 3-clause BSD license. See COPYING for details.
7 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdint.h>
11 #include <string.h>
12 #include "rbtree.h"
13
14 #define INT2PTR(x)      ((void*)(intptr_t)(x))
15 #define PTR2INT(x)      ((int)(intptr_t)(x))
16
17 struct rbtree {
18         struct rbnode *root;
19
20         rb_alloc_func_t alloc;
21         rb_free_func_t free;
22
23         rb_cmp_func_t cmp;
24         rb_del_func_t del;
25         void *del_cls;
26
27         struct rbnode *rstack, *iter;
28 };
29
30 static int cmpaddr(const void *ap, const void *bp);
31 static int cmpint(const void *ap, const void *bp);
32
33 static int count_nodes(struct rbnode *node);
34 static void del_tree(struct rbnode *node, void (*delfunc)(struct rbnode*, void*), void *cls);
35 static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data);
36 static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key);
37 /*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key);*/
38 static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls);
39
40 struct rbtree *rb_create(rb_cmp_func_t cmp_func)
41 {
42         struct rbtree *rb;
43
44         if(!(rb = malloc(sizeof *rb))) {
45                 return 0;
46         }
47         if(rb_init(rb, cmp_func) == -1) {
48                 free(rb);
49                 return 0;
50         }
51         return rb;
52 }
53
54 void rb_free(struct rbtree *rb)
55 {
56         rb_destroy(rb);
57         free(rb);
58 }
59
60
61 int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func)
62 {
63         memset(rb, 0, sizeof *rb);
64
65         if(!cmp_func) {
66                 rb->cmp = cmpaddr;
67         } else if(cmp_func == RB_KEY_INT) {
68                 rb->cmp = cmpint;
69         } else if(cmp_func == RB_KEY_STRING) {
70                 rb->cmp = (rb_cmp_func_t)strcmp;
71         } else {
72                 rb->cmp = cmp_func;
73         }
74
75         rb->alloc = malloc;
76         rb->free = free;
77         return 0;
78 }
79
80 void rb_destroy(struct rbtree *rb)
81 {
82         del_tree(rb->root, rb->del, rb->del_cls);
83 }
84
85 void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free)
86 {
87         rb->alloc = alloc;
88         rb->free = free;
89 }
90
91
92 void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func)
93 {
94         rb->cmp = func;
95 }
96
97 void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls)
98 {
99         rb->del = func;
100         rb->del_cls = cls;
101 }
102
103
104 void rb_clear(struct rbtree *rb)
105 {
106         del_tree(rb->root, rb->del, rb->del_cls);
107         rb->root = 0;
108 }
109
110 int rb_copy(struct rbtree *dest, struct rbtree *src)
111 {
112         struct rbnode *node;
113
114         rb_clear(dest);
115         rb_begin(src);
116         while((node = rb_next(src))) {
117                 if(rb_insert(dest, node->key, node->data) == -1) {
118                         return -1;
119                 }
120         }
121         return 0;
122 }
123
124 int rb_size(struct rbtree *rb)
125 {
126         return count_nodes(rb->root);
127 }
128
129 int rb_insert(struct rbtree *rb, void *key, void *data)
130 {
131 #ifndef NDEBUG
132         int stack_var;
133         if(abs((uintptr_t)&stack_var - (uintptr_t)key) < 0x80000) {
134                 fprintf(stderr, "rb_insert warning: key seems to point to the stack\n");
135         }
136 #endif
137         rb->root = insert(rb, rb->root, key, data);
138         rb->root->red = 0;
139         return 0;
140 }
141
142 int rb_inserti(struct rbtree *rb, int key, void *data)
143 {
144         rb->root = insert(rb, rb->root, INT2PTR(key), data);
145         rb->root->red = 0;
146         return 0;
147 }
148
149
150 int rb_delete(struct rbtree *rb, void *key)
151 {
152         if((rb->root = delete(rb, rb->root, key))) {
153                 rb->root->red = 0;
154         }
155         return 0;
156 }
157
158 int rb_deletei(struct rbtree *rb, int key)
159 {
160         if((rb->root = delete(rb, rb->root, INT2PTR(key)))) {
161                 rb->root->red = 0;
162         }
163         return 0;
164 }
165
166
167 struct rbnode *rb_find(struct rbtree *rb, void *key)
168 {
169         struct rbnode *node = rb->root;
170
171         while(node) {
172                 int cmp = rb->cmp(key, node->key);
173                 if(cmp == 0) {
174                         return node;
175                 }
176                 node = cmp < 0 ? node->left : node->right;
177         }
178         return 0;
179 }
180
181 struct rbnode *rb_findi(struct rbtree *rb, int key)
182 {
183         return rb_find(rb, INT2PTR(key));
184 }
185
186
187 void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls)
188 {
189         traverse(rb->root, func, cls);
190 }
191
192
193 struct rbnode *rb_root(struct rbtree *rb)
194 {
195         return rb->root;
196 }
197
198 void rb_begin(struct rbtree *rb)
199 {
200         rb->rstack = 0;
201         rb->iter = rb->root;
202 }
203
204 #define push(sp, x)             ((x)->next = (sp), (sp) = (x))
205 #define pop(sp)                 ((sp) = (sp)->next)
206 #define top(sp)                 (sp)
207
208 struct rbnode *rb_next(struct rbtree *rb)
209 {
210         struct rbnode *res = 0;
211
212         while(rb->rstack || rb->iter) {
213                 if(rb->iter) {
214                         push(rb->rstack, rb->iter);
215                         rb->iter = rb->iter->left;
216                 } else {
217                         rb->iter = top(rb->rstack);
218                         pop(rb->rstack);
219                         res = rb->iter;
220                         rb->iter = rb->iter->right;
221                         break;
222                 }
223         }
224         return res;
225 }
226
227 void *rb_node_key(struct rbnode *node)
228 {
229         return node ? node->key : 0;
230 }
231
232 int rb_node_keyi(struct rbnode *node)
233 {
234         return node ? PTR2INT(node->key) : 0;
235 }
236
237 void *rb_node_data(struct rbnode *node)
238 {
239         return node ? node->data : 0;
240 }
241
242 void rb_node_setdata(struct rbnode *node, void *data)
243 {
244         node->data = data;
245 }
246
247 static int cmpaddr(const void *ap, const void *bp)
248 {
249         return ap < bp ? -1 : (ap > bp ? 1 : 0);
250 }
251
252 static int cmpint(const void *ap, const void *bp)
253 {
254         return PTR2INT(ap) - PTR2INT(bp);
255 }
256
257
258 /* ---- left-leaning 2-3 red-black implementation ---- */
259
260 /* helper prototypes */
261 static int is_red(struct rbnode *tree);
262 static void color_flip(struct rbnode *tree);
263 static struct rbnode *rot_left(struct rbnode *a);
264 static struct rbnode *rot_right(struct rbnode *a);
265 static struct rbnode *find_min(struct rbnode *tree);
266 static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree);
267 /*static struct rbnode *move_red_right(struct rbnode *tree);*/
268 static struct rbnode *move_red_left(struct rbnode *tree);
269 static struct rbnode *fix_up(struct rbnode *tree);
270
271 static int count_nodes(struct rbnode *node)
272 {
273         if(!node)
274                 return 0;
275
276         return 1 + count_nodes(node->left) + count_nodes(node->right);
277 }
278
279 static void del_tree(struct rbnode *node, rb_del_func_t delfunc, void *cls)
280 {
281         if(!node)
282                 return;
283
284         del_tree(node->left, delfunc, cls);
285         del_tree(node->right, delfunc, cls);
286
287         if(delfunc) {
288                 delfunc(node, cls);
289         }
290         free(node);
291 }
292
293 static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data)
294 {
295         int cmp;
296
297         if(!tree) {
298                 struct rbnode *node = rb->alloc(sizeof *node);
299                 node->red = 1;
300                 node->key = key;
301                 node->data = data;
302                 node->left = node->right = 0;
303                 return node;
304         }
305
306         cmp = rb->cmp(key, tree->key);
307
308         if(cmp < 0) {
309                 tree->left = insert(rb, tree->left, key, data);
310         } else if(cmp > 0) {
311                 tree->right = insert(rb, tree->right, key, data);
312         } else {
313                 if(rb->del) {
314                         /* The key passed in was allocated in a way that would be cleaned by the
315                          * user-supplied delete function. We can't just assign the data and ignore
316                          * key in this case, or we'll leak memory. But we also can't make a dummy
317                          * node and pass that to rb->del, because it might also expect to free data.
318                          * So we must instead delete the existing node's contents, and use the new ones.
319                          */
320                         rb->del(tree, rb->del_cls);
321                         tree->key = key;
322                 }
323                 tree->data = data;
324         }
325
326         /* fix right-leaning reds */
327         if(is_red(tree->right)) {
328                 tree = rot_left(tree);
329         }
330         /* fix two reds in a row */
331         if(is_red(tree->left) && is_red(tree->left->left)) {
332                 tree = rot_right(tree);
333         }
334
335         /* if 4-node, split it by color inversion */
336         if(is_red(tree->left) && is_red(tree->right)) {
337                 color_flip(tree);
338         }
339
340         return tree;
341 }
342
343 static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key)
344 {
345         int cmp;
346
347         if(!tree) {
348                 return 0;
349         }
350
351         cmp = rb->cmp(key, tree->key);
352
353         if(cmp < 0) {
354                 if(!is_red(tree->left) && !is_red(tree->left->left)) {
355                         tree = move_red_left(tree);
356                 }
357                 tree->left = delete(rb, tree->left, key);
358         } else {
359                 /* need reds on the right */
360                 if(is_red(tree->left)) {
361                         tree = rot_right(tree);
362                 }
363
364                 /* found it at the bottom (XXX what certifies left is null?) */
365                 if(cmp == 0 && !tree->right) {
366                         if(rb->del) {
367                                 rb->del(tree, rb->del_cls);
368                         }
369                         rb->free(tree);
370                         return 0;
371                 }
372
373                 if(!is_red(tree->right) && !is_red(tree->right->left)) {
374                         tree = move_red_left(tree);
375                 }
376
377                 if(key == tree->key) {
378                         struct rbnode *rmin = find_min(tree->right);
379                         tree->key = rmin->key;
380                         tree->data = rmin->data;
381                         tree->right = del_min(rb, tree->right);
382                 } else {
383                         tree->right = delete(rb, tree->right, key);
384                 }
385         }
386
387         return fix_up(tree);
388 }
389
390 /*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key)
391 {
392         int cmp;
393
394         if(!node)
395                 return 0;
396
397         if((cmp = rb->cmp(key, node->key)) == 0) {
398                 return node;
399         }
400         return find(rb, cmp < 0 ? node->left : node->right, key);
401 }*/
402
403 static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls)
404 {
405         if(!node)
406                 return;
407
408         traverse(node->left, func, cls);
409         func(node, cls);
410         traverse(node->right, func, cls);
411 }
412
413 /* helpers */
414
415 static int is_red(struct rbnode *tree)
416 {
417         return tree && tree->red;
418 }
419
420 static void color_flip(struct rbnode *tree)
421 {
422         tree->red = !tree->red;
423         tree->left->red = !tree->left->red;
424         tree->right->red = !tree->right->red;
425 }
426
427 static struct rbnode *rot_left(struct rbnode *a)
428 {
429         struct rbnode *b = a->right;
430         a->right = b->left;
431         b->left = a;
432         b->red = a->red;
433         a->red = 1;
434         return b;
435 }
436
437 static struct rbnode *rot_right(struct rbnode *a)
438 {
439         struct rbnode *b = a->left;
440         a->left = b->right;
441         b->right = a;
442         b->red = a->red;
443         a->red = 1;
444         return b;
445 }
446
447 static struct rbnode *find_min(struct rbnode *tree)
448 {
449         if(!tree)
450                 return 0;
451
452         while(tree->left) {
453                 tree = tree->left;
454         }
455         return tree;
456 }
457
458 static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree)
459 {
460         if(!tree->left) {
461                 if(rb->del) {
462                         rb->del(tree->left, rb->del_cls);
463                 }
464                 rb->free(tree->left);
465                 return 0;
466         }
467
468         /* make sure we've got red (3/4-nodes) at the left side so we can delete at the bottom */
469         if(!is_red(tree->left) && !is_red(tree->left->left)) {
470                 tree = move_red_left(tree);
471         }
472         tree->left = del_min(rb, tree->left);
473
474         /* fix right-reds, red-reds, and split 4-nodes on the way up */
475         return fix_up(tree);
476 }
477
478 #if 0
479 /* push a red link on this node to the right */
480 static struct rbnode *move_red_right(struct rbnode *tree)
481 {
482         /* flipping it makes both children go red, so we have a red to the right */
483         color_flip(tree);
484
485         /* if after the flip we've got a red-red situation to the left, fix it */
486         if(is_red(tree->left->left)) {
487                 tree = rot_right(tree);
488                 color_flip(tree);
489         }
490         return tree;
491 }
492 #endif
493
494 /* push a red link on this node to the left */
495 static struct rbnode *move_red_left(struct rbnode *tree)
496 {
497         /* flipping it makes both children go red, so we have a red to the left */
498         color_flip(tree);
499
500         /* if after the flip we've got a red-red on the right-left, fix it */
501         if(is_red(tree->right->left)) {
502                 tree->right = rot_right(tree->right);
503                 tree = rot_left(tree);
504                 color_flip(tree);
505         }
506         return tree;
507 }
508
509 static struct rbnode *fix_up(struct rbnode *tree)
510 {
511         /* fix right-leaning */
512         if(is_red(tree->right)) {
513                 tree = rot_left(tree);
514         }
515         /* change invalid red-red pairs into a proper 4-node */
516         if(is_red(tree->left) && is_red(tree->left->left)) {
517                 tree = rot_right(tree);
518         }
519         /* split 4-nodes */
520         if(is_red(tree->left) && is_red(tree->right)) {
521                 color_flip(tree);
522         }
523         return tree;
524 }