Support tunneling IPv6 on Solaris.
[tinc] / lib / splay_tree.c
1 /*
2     splay_tree.c -- splay tree and linked list convenience
3     Copyright (C) 2004 Guus Sliepen <guus@tinc-vpn.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19     $Id: splay_tree.c 1374 2004-03-21 14:21:22Z guus $
20 */
21
22 #include "system.h"
23
24 #include "splay_tree.h"
25 #include "xalloc.h"
26
27 /* Splay operation */
28
29 static splay_node_t *splay_top_down(splay_tree_t *tree, const void *data, int *result) {
30         splay_node_t left = {0}, right = {0};
31         splay_node_t *leftbottom = &left, *rightbottom = &right, *child;
32         splay_node_t *node = tree->root;
33         int c;
34
35         while((c = tree->compare(data, node->data))) {
36                 if(c < 0) {
37                         child = node->left;
38
39                         if(child) {
40                                 c = tree->compare(data, child->data);
41                                 
42                                 if(c < 0) {
43                                         rightbottom->left = child;
44                                         child->parent = rightbottom;
45                                         rightbottom = child;
46
47                                         node->left = child->right;
48                                         child->right = node;
49                                         node->parent = child;
50                                         node = child->left;
51                                         child->left = NULL;
52                                 } else if (c > 0) {
53                                         if(!child->right)
54                                                 break;
55
56                                         leftbottom->right = child;
57                                         child->parent = leftbottom;
58                                         leftbottom = child;
59
60                                         rightbottom->left = node;
61                                         node->parent = rightbottom;
62                                         rightbottom = node;
63
64                                         node->left = NULL;
65                                         node = child->right;
66                                         child->right = NULL;
67                                 } else {
68                                         rightbottom->left = node;
69                                         node->parent = rightbottom;
70                                         rightbottom = node;
71
72                                         node->left = NULL;
73                                         child->parent = NULL;
74                                         node = child;
75                                         break;
76                                 }
77                         } else {
78                                 break;
79                         }
80                 } else {
81                         child = node->right;
82
83                         if(child) {
84                                 c = tree->compare(data, child->data);
85                                 
86                                 if(c > 0) {
87                                         leftbottom->right = child;
88                                         child->parent = leftbottom;
89                                         leftbottom = child;
90
91                                         node->right = child->left;
92                                         child->left = node;
93                                         node->parent = child;
94                                         node = child->right;
95                                         child->right = NULL;
96                                 } else if (c < 0) {
97                                         if(!child->left)
98                                                 break;
99
100                                         rightbottom->left = child;
101                                         child->parent = rightbottom;
102                                         rightbottom = child;
103
104                                         leftbottom->right = node;
105                                         node->parent = leftbottom;
106                                         leftbottom = node;
107
108                                         node->right = NULL;
109                                         node = child->left;
110                                         child->left = NULL;
111                                 } else {
112                                         leftbottom->right = node;
113                                         node->parent = leftbottom;
114                                         leftbottom = node;
115
116                                         node->right = NULL;
117                                         child->parent = NULL;
118                                         node = child;
119                                         break;
120                                 }
121                         } else {
122                                 break;
123                         }
124                 }
125         }
126
127         tree->root = node;
128
129         /* Merge trees */
130
131         if(left.right) {
132                 if(node->left) {
133                         leftbottom->right = node->left;
134                         node->left->parent = leftbottom;
135                 }
136                 node->left = left.right;
137                 left.right->parent = node;
138         }
139
140         if(right.left) {
141                 if(node->right) {
142                         rightbottom->left = node->right;
143                         node->right->parent = rightbottom;
144                 }
145                 node->right = right.left;
146                 right.left->parent = node;
147         }
148
149         if(result)
150                 *result = c;
151
152         return node;
153 }
154                                 
155                 
156 static void splay_bottom_up(splay_tree_t *tree, splay_node_t *node) {
157         splay_node_t *parent, *grandparent;
158
159         while(node->parent) {
160                 parent = node->parent;
161                 grandparent = node->parent->parent;
162
163                 if(!grandparent) { /* zig */
164                         if(node == parent->left) {
165                                 parent->left = node->right;
166                                 node->right = parent;
167                         } else {
168                                 parent->right = node->left;
169                                 node->left = parent;
170                         }
171
172                         parent->parent = node;
173                         node->parent = NULL;
174                 } else {
175                         if(node == grandparent->left->left) { /* left zig-zig */
176                                 grandparent->left = parent->right;
177                                 parent->right = grandparent;
178                                 grandparent->parent = parent;
179
180                                 parent->left = node->right;
181                                 node->right = parent;
182                                 parent->parent = node;
183
184                         } else if(node == grandparent->right->right) { /* right zig-zig */
185                                 grandparent->right = parent->left;
186                                 parent->left = grandparent;
187                                 grandparent->parent = parent;
188
189                                 parent->right = node->left;
190                                 node->left = parent;
191                                 parent->parent = node;
192
193                         } else if(node == grandparent->left->right) { /* left-right zig-zag */
194                                 parent->right = node->left;
195                                 node->left = parent;
196                                 parent->parent = node;
197
198                                 grandparent->left = node->right;
199                                 node->right = grandparent;
200                                 grandparent->parent = node;
201
202                         } else { /* right-left zig-zag */
203                                 parent->left = node->right;
204                                 node->right = parent;
205                                 parent->parent = node;
206
207                                 grandparent->right = node->left;
208                                 node->left = grandparent;
209                                 grandparent->parent = node;
210                         }
211
212                         node->parent = grandparent->parent;
213
214                         if(node->parent) {
215                                 if(grandparent == node->parent->left)
216                                         node->parent->left = node;
217                                 else
218                                         node->parent->right = node;
219                         }
220                 }
221         }
222
223         tree->root = node;
224 }
225
226 /* (De)constructors */
227
228 splay_tree_t *splay_alloc_tree(splay_compare_t compare, splay_action_t delete) {
229         splay_tree_t *tree;
230
231         tree = xmalloc_and_zero(sizeof(splay_tree_t));
232         tree->compare = compare;
233         tree->delete = delete;
234
235         return tree;
236 }
237
238 void splay_free_tree(splay_tree_t *tree) {
239         free(tree);
240 }
241
242 splay_node_t *splay_alloc_node(void) {
243         return xmalloc_and_zero(sizeof(splay_node_t));
244 }
245
246 void splay_free_node(splay_tree_t *tree, splay_node_t *node) {
247         if(node->data && tree->delete)
248                 tree->delete(node->data);
249
250         free(node);
251 }
252
253 /* Searching */
254
255 void *splay_search(splay_tree_t *tree, const void *data) {
256         splay_node_t *node;
257
258         node = splay_search_node(tree, data);
259
260         return node ? node->data : NULL;
261 }
262
263 void *splay_search_closest(splay_tree_t *tree, const void *data, int *result) {
264         splay_node_t *node;
265
266         node = splay_search_closest_node(tree, data, result);
267
268         return node ? node->data : NULL;
269 }
270
271 void *splay_search_closest_smaller(splay_tree_t *tree, const void *data) {
272         splay_node_t *node;
273
274         node = splay_search_closest_smaller_node(tree, data);
275
276         return node ? node->data : NULL;
277 }
278
279 void *splay_search_closest_greater(splay_tree_t *tree, const void *data) {
280         splay_node_t *node;
281
282         node = splay_search_closest_greater_node(tree, data);
283
284         return node ? node->data : NULL;
285 }
286
287 splay_node_t *splay_search_node(splay_tree_t *tree, const void *data) {
288         splay_node_t *node;
289         int result;
290
291         node = splay_search_closest_node(tree, data, &result);
292
293         return result ? NULL : node;
294 }
295
296 splay_node_t *splay_search_closest_node_nosplay(const splay_tree_t *tree, const void *data, int *result) {
297         splay_node_t *node;
298         int c;
299
300         node = tree->root;
301
302         if(!node) {
303                 if(result)
304                         *result = 0;
305                 return NULL;
306         }
307
308         for(;;) {
309                 c = tree->compare(data, node->data);
310
311                 if(c < 0) {
312                         if(node->left)
313                                 node = node->left;
314                         else {
315                                 if(result)
316                                         *result = -1;
317                                 break;
318                         }
319                 } else if(c > 0) {
320                         if(node->right)
321                                 node = node->right;
322                         else {
323                                 if(result)
324                                         *result = 1;
325                                 break;
326                         }
327                 } else {
328                         if(result)
329                                 *result = 0;
330                         break;
331                 }
332         }
333
334         return node;
335 }
336
337 splay_node_t *splay_search_closest_node(splay_tree_t *tree, const void *data, int *result) {
338         return splay_top_down(tree, data, result);
339 }
340
341 splay_node_t *splay_search_closest_smaller_node(splay_tree_t *tree, const void *data) {
342         splay_node_t *node;
343         int result;
344
345         node = splay_search_closest_node(tree, data, &result);
346
347         if(result < 0)
348                 node = node->prev;
349
350         return node;
351 }
352
353 splay_node_t *splay_search_closest_greater_node(splay_tree_t *tree, const void *data) {
354         splay_node_t *node;
355         int result;
356
357         node = splay_search_closest_node(tree, data, &result);
358
359         if(result > 0)
360                 node = node->next;
361
362         return node;
363 }
364
365 /* Insertion and deletion */
366
367 splay_node_t *splay_insert(splay_tree_t *tree, void *data) {
368         splay_node_t *closest, *new;
369         int result;
370
371         if(!tree->root) {
372                 new = splay_alloc_node();
373                 new->data = data;
374                 splay_insert_top(tree, new);
375         } else {
376                 closest = splay_search_closest_node_nosplay(tree, data, &result);
377
378                 if(!result)
379                         return NULL;
380
381                 new = splay_alloc_node();
382                 new->data = data;
383                 
384                 if(result < 0)
385                         splay_insert_before(tree, closest, new);
386                 else
387                         splay_insert_after(tree, closest, new);
388         }                       
389
390         return new;
391 }
392
393 splay_node_t *splay_insert_node(splay_tree_t *tree, splay_node_t *node) {
394         splay_node_t *closest;
395         int result;
396
397         if(!tree->root)
398                 splay_insert_top(tree, node);
399         else {
400                 closest = splay_search_closest_node_nosplay(tree, node->data, &result);
401                 
402                 if(!result)
403                         return NULL;
404
405                 if(result < 0)
406                         splay_insert_before(tree, closest, node);
407                 else
408                         splay_insert_after(tree, closest, node);
409         }
410
411         return node;
412 }
413
414 void splay_insert_top(splay_tree_t *tree, splay_node_t *node) {
415         node->prev = node->next = node->parent = NULL;
416         tree->head = tree->tail = tree->root = node;
417 }
418
419 void splay_insert_before(splay_tree_t *tree, splay_node_t *before, splay_node_t *node) {
420         if(!before) {
421                 if(tree->tail)
422                         splay_insert_after(tree, tree->tail, node);
423                 else
424                         splay_insert_top(tree, node);
425                 return;
426         }
427
428         node->next = before;
429         node->parent = before;
430         node->prev = before->prev;
431
432         if(before->left) {
433                 splay_insert_after(tree, before->prev, node);
434                 return;
435         }
436
437         if(before->prev)
438                 before->prev->next = node;
439         else
440                 tree->head = node;
441
442         before->prev = node;
443         before->left = node;
444
445         splay_bottom_up(tree, node);
446 }
447
448 void splay_insert_after(splay_tree_t *tree, splay_node_t *after, splay_node_t *node) {
449         if(!after) {
450                 if(tree->head)
451                         splay_insert_before(tree, tree->head, node);
452                 else
453                         splay_insert_top(tree, node);
454                 return;
455         }
456
457         if(after->right) {
458                 splay_insert_before(tree, after->next, node);
459                 return;
460         }
461
462         node->prev = after;
463         node->parent = after;
464         node->next = after->next;
465
466         if(after->next)
467                 after->next->prev = node;
468         else
469                 tree->tail = node;
470
471         after->next = node;
472         after->right = node;
473
474         splay_bottom_up(tree, node);
475 }
476
477 splay_node_t *splay_unlink(splay_tree_t *tree, void *data) {
478         splay_node_t *node;
479         int result;
480
481         node = splay_search_closest_node_nosplay(tree, data, &result);
482
483         if(node && !result)
484                 splay_unlink_node(tree, node);
485
486         return node;
487 }
488
489 void splay_unlink_node(splay_tree_t *tree, splay_node_t *node) {
490         if(node->prev)
491                 node->prev->next = node->next;
492         else
493                 tree->head = node->next;
494
495         if(node->next)
496                 node->next->prev = node->prev;
497         else
498                 tree->tail = node->prev;
499
500         if(node->left) {
501                 node->left->parent = NULL;
502                 tree->root = node->left;
503
504                 if(node->right) {
505                         splay_bottom_up(tree, node->prev);
506                         node->prev->right = node->right;
507                         node->right->parent = node->prev;
508                 }
509         } else {
510                 node->right->parent = NULL;
511                 tree->root = node->right;
512         }
513 }
514
515 void splay_delete_node(splay_tree_t *tree, splay_node_t *node) {
516         splay_unlink_node(tree, node);
517         splay_free_node(tree, node);
518 }
519
520 void splay_delete(splay_tree_t *tree, void *data) {
521         splay_node_t *node;
522
523         node = splay_search_node(tree, data);
524
525         if(node)
526                 splay_delete_node(tree, node);
527 }
528
529 /* Fast tree cleanup */
530
531 void splay_delete_tree(splay_tree_t *tree) {
532         splay_node_t *node, *next;
533
534         for(node = tree->root; node; node = next) {
535                 next = node->next;
536                 splay_free_node(tree, node);
537         }
538
539         splay_free_tree(tree);
540 }
541
542 /* Tree walking */
543
544 void splay_foreach(const splay_tree_t *tree, splay_action_t action) {
545         splay_node_t *node, *next;
546
547         for(node = tree->head; node; node = next) {
548                 next = node->next;
549                 action(node->data);
550         }
551 }
552
553 void splay_foreach_node(const splay_tree_t *tree, splay_action_t action) {
554         splay_node_t *node, *next;
555
556         for(node = tree->head; node; node = next) {
557                 next = node->next;
558                 action(node);
559         }
560 }