source: mainline/common/adt/odict.c@ 0437dd5

Last change on this file since 0437dd5 was ad9178bf, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 20 months ago

Deduplicate ADT

  • Property mode set to 100644
File size: 24.0 KB
Line 
1/*
2 * Copyright (c) 2016 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup kernel_generic_adt
30 * @{
31 */
32
33/** @file Ordered dictionary.
34 *
35 * Implementation based on red-black trees.
36 * Note that non-data ('leaf') nodes are implemented as NULLs, not
37 * as actual nodes.
38 */
39
40#include <adt/list.h>
41#include <adt/odict.h>
42#include <assert.h>
43#include <errno.h>
44#include <stdbool.h>
45#include <stddef.h>
46#include <stdio.h>
47
48static void odict_pgu(odlink_t *, odlink_t **, odict_child_sel_t *,
49 odlink_t **, odict_child_sel_t *, odlink_t **);
50
51static void odict_rotate_left(odlink_t *);
52static void odict_rotate_right(odlink_t *);
53static void odict_swap_node(odlink_t *, odlink_t *);
54static void odict_replace_subtree(odlink_t *, odlink_t *);
55static void odict_unlink(odlink_t *);
56static void odict_link_child_a(odlink_t *, odlink_t *);
57static void odict_link_child_b(odlink_t *, odlink_t *);
58static void odict_sibling(odlink_t *, odlink_t *, odict_child_sel_t *,
59 odlink_t **);
60static odlink_t *odict_search_start_node(odict_t *, void *, odlink_t *);
61
62/** Print subtree.
63 *
64 * Print subtree rooted at @a cur
65 *
66 * @param cur Root of tree to print
67 */
68static void odict_print_tree(odlink_t *cur)
69{
70 if (cur == NULL) {
71 printf("0");
72 return;
73 }
74
75 printf("[%p/%c", cur, cur->color == odc_red ? 'r' : 'b');
76 if (cur->a != NULL || cur->b != NULL) {
77 printf(" ");
78 odict_print_tree(cur->a);
79 printf(" ");
80 odict_print_tree(cur->b);
81 }
82 printf("]");
83}
84
85/** Validate ordered dictionary subtree.
86 *
87 * Verify that red-black tree properties are satisfied.
88 *
89 * @param cur Root of tree to verify
90 * @param rbd Place to store black depth of the subtree
91 *
92 * @return EOK on success, EINVAL on failure
93 */
94static errno_t odict_validate_tree(odlink_t *cur, int *rbd)
95{
96 errno_t rc;
97 int bd_a, bd_b;
98 int cur_d;
99
100 if (cur->up == NULL) {
101 /* Verify root pointer */
102 if (cur->odict->root != cur) {
103 printf("cur->up == NULL and yet cur != root\n");
104 return EINVAL;
105 }
106
107 /* Verify root color */
108 if (cur->color != odc_black) {
109 printf("Root is not black\n");
110 return EINVAL;
111 }
112 }
113
114 if (cur->a != NULL) {
115 /* Verify symmetry of a - up links */
116 if (cur->a->up != cur) {
117 printf("cur->a->up != cur\n");
118 return EINVAL;
119 }
120
121 /* Verify that if a node is red, its left child is red */
122 if (cur->a->color == odc_red && cur->color == odc_red) {
123 printf("cur->a is red, cur is red\n");
124 return EINVAL;
125 }
126
127 /* Recurse to left child */
128 rc = odict_validate_tree(cur->a, &bd_a);
129 if (rc != EOK)
130 return rc;
131 } else {
132 bd_a = -1;
133 }
134
135 if (cur->b != NULL) {
136 /* Verify symmetry of b - up links */
137 if (cur->b->up != cur) {
138 printf("cur->b->up != cur\n");
139 return EINVAL;
140 }
141
142 /* Verify that if a node is red, its right child is red */
143 if (cur->b->color == odc_red && cur->color == odc_red) {
144 printf("cur->b is red, cur is red\n");
145 return EINVAL;
146 }
147
148 /* Recurse to right child */
149 rc = odict_validate_tree(cur->b, &bd_b);
150 if (rc != EOK)
151 return rc;
152 } else {
153 bd_b = -1;
154 }
155
156 /* Verify that black depths of both children are equal */
157 if (bd_a >= 0 && bd_b >= 0) {
158 if (bd_a != bd_b) {
159 printf("Black depth %d != %d\n", bd_a, bd_b);
160 return EINVAL;
161 }
162 }
163
164 cur_d = cur->color == odc_black ? 1 : 0;
165 if (bd_a >= 0)
166 *rbd = bd_a + cur_d;
167 else if (bd_b >= 0)
168 *rbd = bd_b + cur_d;
169 else
170 *rbd = cur_d;
171
172 return EOK;
173}
174
175/** Validate ordered dictionary properties.
176 *
177 * @param odict Ordered dictionary
178 */
179errno_t odict_validate(odict_t *odict)
180{
181 int bd;
182 errno_t rc;
183
184 if (odict->root == NULL)
185 return EOK;
186
187 rc = odict_validate_tree(odict->root, &bd);
188 if (rc != EOK)
189 odict_print_tree(odict->root);
190
191 return rc;
192}
193
194/** Initialize ordered dictionary.
195 *
196 * @param odict Ordered dictionary
197 * @param getkey Function to get key
198 * @param cmp Function to compare entries
199 */
200void odict_initialize(odict_t *odict, odgetkey_t getkey, odcmp_t cmp)
201{
202 odict->root = NULL;
203 list_initialize(&odict->entries);
204 odict->getkey = getkey;
205 odict->cmp = cmp;
206}
207
208/** Finalize ordered dictionary.
209 *
210 * @param odict Ordered dictionary (must be empty)
211 */
212void odict_finalize(odict_t *odict)
213{
214 assert(odict->root == NULL);
215}
216
217/** Initialize ordered dictionary link.
218 *
219 * @param odlink Ordered dictionary link
220 */
221void odlink_initialize(odlink_t *odlink)
222{
223 odlink->odict = NULL;
224 odlink->up = NULL;
225 odlink->a = NULL;
226 odlink->b = NULL;
227 link_initialize(&odlink->lentries);
228}
229
230/** Insert entry in ordered dictionary.
231 *
232 * Insert entry in ordered dictionary, placing it after other entries
233 * with the same key.
234 *
235 * @param odlink New entry
236 * @param odict Ordered dictionary
237 * @param hint An entry that might be near the new entry or @c NULL
238 */
239void odict_insert(odlink_t *odlink, odict_t *odict, odlink_t *hint)
240{
241 int d;
242 odlink_t *cur;
243 odlink_t *p;
244 odlink_t *g;
245 odlink_t *u;
246 odict_child_sel_t pcs, gcs;
247
248 assert(!odlink_used(odlink));
249
250 if (odict->root == NULL) {
251 /* odlink is the root node */
252 odict->root = odlink;
253 odlink->odict = odict;
254 odlink->color = odc_black;
255 list_append(&odlink->lentries, &odict->entries);
256 return;
257 }
258
259 cur = odict_search_start_node(odict, odict->getkey(odlink), hint);
260 while (true) {
261 d = odict->cmp(odict->getkey(odlink), odict->getkey(cur));
262 if (d < 0) {
263 if (cur->a == NULL) {
264 odict_link_child_a(odlink, cur);
265 break;
266 }
267 cur = cur->a;
268 } else {
269 if (cur->b == NULL) {
270 odict_link_child_b(odlink, cur);
271 break;
272 }
273 cur = cur->b;
274 }
275 }
276
277 odlink->color = odc_red;
278
279 while (true) {
280 /* Fix up odlink and its parent potentially being red */
281 if (odlink->up == NULL) {
282 odlink->color = odc_black;
283 break;
284 }
285
286 if (odlink->up->color == odc_black)
287 break;
288
289 /* Get parent, grandparent, uncle */
290 odict_pgu(odlink, &p, &pcs, &g, &gcs, &u);
291
292 if (g == NULL) {
293 p->color = odc_black;
294 break;
295 }
296
297 if (p->color == odc_red && u != NULL && u->color == odc_red) {
298 /* Parent and uncle are both red */
299 p->color = odc_black;
300 u->color = odc_black;
301 g->color = odc_red;
302 odlink = g;
303 continue;
304 }
305
306 /* Parent is red but uncle is black, odlink-P-G is trans */
307 if (pcs != gcs) {
308 if (gcs == odcs_a) {
309 /* odlink is right child of P */
310 /* P is left child of G */
311 odict_rotate_left(p);
312 } else {
313 /* odlink is left child of P */
314 /* P is right child of G */
315 odict_rotate_right(p);
316 }
317
318 odlink = p;
319 odict_pgu(odlink, &p, &pcs, &g, &gcs, &u);
320 }
321
322 /* odlink-P-G is now cis */
323 assert(pcs == gcs);
324 if (pcs == odcs_a) {
325 /* odlink is left child of P */
326 /* P is left child of G */
327 odict_rotate_right(g);
328 } else {
329 /* odlink is right child of P */
330 /* P is right child of G */
331 odict_rotate_left(g);
332 }
333
334 p->color = odc_black;
335 g->color = odc_red;
336 break;
337 }
338}
339
340/** Remove entry from ordered dictionary.
341 *
342 * @param odlink Ordered dictionary link
343 */
344void odict_remove(odlink_t *odlink)
345{
346 odlink_t *n;
347 odlink_t *c;
348 odlink_t *p;
349 odlink_t *s;
350 odlink_t *sc, *st;
351 odict_child_sel_t pcs;
352
353 if (odlink->a != NULL && odlink->b != NULL) {
354 n = odict_next(odlink, odlink->odict);
355 assert(n != NULL);
356
357 odict_swap_node(odlink, n);
358 }
359
360 /* odlink has at most one child */
361 if (odlink->a != NULL) {
362 assert(odlink->b == NULL);
363 c = odlink->a;
364 } else {
365 c = odlink->b;
366 }
367
368 if (odlink->color == odc_red) {
369 /* We can remove it harmlessly */
370 assert(c == NULL);
371 odict_unlink(odlink);
372 return;
373 }
374
375 /* odlink->color == odc_black */
376 if (c != NULL && c->color == odc_red) {
377 /* Child is red: swap colors of S and C */
378 c->color = odc_black;
379 odict_replace_subtree(c, odlink);
380 odlink->up = odlink->a = odlink->b = NULL;
381 odlink->odict = NULL;
382 list_remove(&odlink->lentries);
383 return;
384 }
385
386 /* There cannot be one black child */
387 assert(c == NULL);
388
389 n = NULL;
390 p = odlink->up;
391 odict_unlink(odlink);
392 /* We removed one black node, creating imbalance */
393again:
394 /* Case 1: N is the new root */
395 if (p == NULL)
396 return;
397
398 odict_sibling(n, p, &pcs, &s);
399
400 /* Paths through N have one less black node than paths through S */
401
402 /* Case 2: S is red */
403 if (s->color == odc_red) {
404 assert(p->color == odc_black);
405 p->color = odc_red;
406 s->color = odc_black;
407 if (n == p->a)
408 odict_rotate_left(p);
409 else
410 odict_rotate_right(p);
411 odict_sibling(n, p, &pcs, &s);
412 /* Now S is black */
413 assert(s->color == odc_black);
414 }
415
416 /* Case 3: P, S and S's children are black */
417 if (p->color == odc_black &&
418 s->color == odc_black &&
419 (s->a == NULL || s->a->color == odc_black) &&
420 (s->b == NULL || s->b->color == odc_black)) {
421 /*
422 * Changing S to red means all paths through S or N have one
423 * less black node than they should. So redo the same for P.
424 */
425 s->color = odc_red;
426 n = p;
427 p = n->up;
428 goto again;
429 }
430
431 /* Case 4: P is red, S and S's children are black */
432 if (p->color == odc_red &&
433 s->color == odc_black &&
434 (s->a == NULL || s->a->color == odc_black) &&
435 (s->b == NULL || s->b->color == odc_black)) {
436 /* Swap colors of S and P */
437 s->color = odc_red;
438 p->color = odc_black;
439 return;
440 }
441
442 /* N is the left child */
443 if (pcs == odcs_a) {
444 st = s->a;
445 sc = s->b;
446 } else {
447 st = s->b;
448 sc = s->a;
449 }
450
451 /* Case 5: S is black and S's trans child is red, S's cis child is black */
452 if (s->color == odc_black &&
453 (st != NULL && st->color == odc_red) &&
454 (sc == NULL || sc->color == odc_black)) {
455 /* N is the left child */
456 if (pcs == odcs_a)
457 odict_rotate_right(s);
458 else
459 odict_rotate_left(s);
460 s->color = odc_red;
461 s->up->color = odc_black;
462 /* Now N has a black sibling whose cis child is red */
463 odict_sibling(n, p, &pcs, &s);
464 /* N is the left child */
465 if (pcs == odcs_a) {
466 st = s->a;
467 sc = s->b;
468 } else {
469 st = s->b;
470 sc = s->a;
471 }
472 }
473
474 /* Case 6: S is black, S's cis child is red */
475 assert(s->color == odc_black);
476 assert(sc != NULL);
477 assert(sc->color == odc_red);
478
479 if (pcs == odcs_a)
480 odict_rotate_left(p);
481 else
482 odict_rotate_right(p);
483
484 s->color = p->color;
485 p->color = odc_black;
486 sc->color = odc_black;
487}
488
489/** Update dictionary after entry key has been changed.
490 *
491 * After the caller modifies the key of an entry, they need to call
492 * this function so that the dictionary can update itself accordingly.
493 *
494 * @param odlink Ordered dictionary entry
495 * @param odict Ordered dictionary
496 */
497void odict_key_update(odlink_t *odlink, odict_t *odict)
498{
499 odlink_t *n;
500
501 n = odict_next(odlink, odict);
502 odict_remove(odlink);
503 odict_insert(odlink, odict, n);
504}
505
506/** Return true if entry is in a dictionary.
507 *
508 * @param odlink Ordered dictionary entry
509 * @return @c true if entry is in a dictionary, @c false otherwise
510 */
511bool odlink_used(odlink_t *odlink)
512{
513 return odlink->odict != NULL;
514}
515
516/** Return true if ordered dictionary is empty.
517 *
518 * @param odict Ordered dictionary
519 * @return @c true if @a odict is emptry, @c false otherwise
520 */
521bool odict_empty(odict_t *odict)
522{
523 return odict->root == NULL;
524}
525
526/** Return the number of entries in @a odict.
527 *
528 * @param odict Ordered dictionary
529 */
530unsigned long odict_count(odict_t *odict)
531{
532 unsigned long cnt;
533 odlink_t *cur;
534
535 cnt = 0;
536 cur = odict_first(odict);
537 while (cur != NULL) {
538 ++cnt;
539 cur = odict_next(cur, odict);
540 }
541
542 return cnt;
543}
544
545/** Return first entry in a list or @c NULL if list is empty.
546 *
547 * @param odict Ordered dictionary
548 * @return First entry
549 */
550odlink_t *odict_first(odict_t *odict)
551{
552 link_t *link;
553
554 link = list_first(&odict->entries);
555 if (link == NULL)
556 return NULL;
557
558 return list_get_instance(link, odlink_t, lentries);
559}
560
561/** Return last entry in a list or @c NULL if list is empty
562 *
563 * @param odict Ordered dictionary
564 * @return Last entry
565 */
566odlink_t *odict_last(odict_t *odict)
567{
568 link_t *link;
569
570 link = list_last(&odict->entries);
571 if (link == NULL)
572 return NULL;
573
574 return list_get_instance(link, odlink_t, lentries);
575}
576
577/** Return previous entry in list or @c NULL if @a link is the first one.
578 *
579 * @param odlink Entry
580 * @param odict Ordered dictionary
581 * @return Previous entry
582 */
583odlink_t *odict_prev(odlink_t *odlink, odict_t *odict)
584{
585 link_t *link;
586
587 link = list_prev(&odlink->lentries, &odlink->odict->entries);
588 if (link == NULL)
589 return NULL;
590
591 return list_get_instance(link, odlink_t, lentries);
592}
593
594/** Return next entry in dictionary or @c NULL if @a odlink is the last one
595 *
596 * @param odlink Entry
597 * @param odict Ordered dictionary
598 * @return Next entry
599 */
600odlink_t *odict_next(odlink_t *odlink, odict_t *odict)
601{
602 link_t *link;
603
604 link = list_next(&odlink->lentries, &odlink->odict->entries);
605 if (link == NULL)
606 return NULL;
607
608 return list_get_instance(link, odlink_t, lentries);
609}
610
611/** Find first entry whose key is equal to @a key/
612 *
613 * @param odict Ordered dictionary
614 * @param key Key
615 * @param hint Nearby entry
616 * @return Pointer to entry on success, @c NULL on failure
617 */
618odlink_t *odict_find_eq(odict_t *odict, void *key, odlink_t *hint)
619{
620 odlink_t *geq;
621
622 geq = odict_find_geq(odict, key, hint);
623 if (geq == NULL)
624 return NULL;
625
626 if (odict->cmp(odict->getkey(geq), key) == 0)
627 return geq;
628 else
629 return NULL;
630}
631
632/** Find last entry whose key is equal to @a key/
633 *
634 * @param odict Ordered dictionary
635 * @param key Key
636 * @param hint Nearby entry
637 * @return Pointer to entry on success, @c NULL on failure
638 */
639odlink_t *odict_find_eq_last(odict_t *odict, void *key, odlink_t *hint)
640{
641 odlink_t *leq;
642
643 leq = odict_find_leq(odict, key, hint);
644 if (leq == NULL)
645 return NULL;
646
647 if (odict->cmp(odict->getkey(leq), key) == 0)
648 return leq;
649 else
650 return NULL;
651}
652
653/** Find first entry whose key is greater than or equal to @a key
654 *
655 * @param odict Ordered dictionary
656 * @param key Key
657 * @param hint Nearby entry
658 * @return Pointer to entry on success, @c NULL on failure
659 */
660odlink_t *odict_find_geq(odict_t *odict, void *key, odlink_t *hint)
661{
662 odlink_t *cur;
663 odlink_t *next;
664 int d;
665
666 cur = odict_search_start_node(odict, key, hint);
667 if (cur == NULL)
668 return NULL;
669
670 while (true) {
671 d = odict->cmp(odict->getkey(cur), key);
672 if (d >= 0)
673 next = cur->a;
674 else
675 next = cur->b;
676
677 if (next == NULL)
678 break;
679
680 cur = next;
681 }
682
683 if (d >= 0) {
684 return cur;
685 } else {
686 return odict_next(cur, odict);
687 }
688}
689
690/** Find last entry whose key is greater than @a key.
691 *
692 * @param odict Ordered dictionary
693 * @param key Key
694 * @param hint Nearby entry
695 * @return Pointer to entry on success, @c NULL on failure
696 */
697odlink_t *odict_find_gt(odict_t *odict, void *key, odlink_t *hint)
698{
699 odlink_t *leq;
700
701 leq = odict_find_leq(odict, key, hint);
702 if (leq != NULL)
703 return odict_next(leq, odict);
704 else
705 return odict_first(odict);
706}
707
708/** Find last entry whose key is less than or equal to @a key
709 *
710 * @param odict Ordered dictionary
711 * @param key Key
712 * @param hint Nearby entry
713 * @return Pointer to entry on success, @c NULL on failure
714 */
715odlink_t *odict_find_leq(odict_t *odict, void *key, odlink_t *hint)
716{
717 odlink_t *cur;
718 odlink_t *next;
719 int d;
720
721 cur = odict_search_start_node(odict, key, hint);
722 if (cur == NULL)
723 return NULL;
724
725 while (true) {
726 d = odict->cmp(key, odict->getkey(cur));
727 if (d >= 0)
728 next = cur->b;
729 else
730 next = cur->a;
731
732 if (next == NULL)
733 break;
734
735 cur = next;
736 }
737
738 if (d >= 0) {
739 return cur;
740 } else {
741 return odict_prev(cur, odict);
742 }
743}
744
745/** Find last entry whose key is less than @a key.
746 *
747 * @param odict Ordered dictionary
748 * @param key Key
749 * @param hint Nearby entry
750 * @return Pointer to entry on success, @c NULL on failure
751 */
752odlink_t *odict_find_lt(odict_t *odict, void *key, odlink_t *hint)
753{
754 odlink_t *geq;
755
756 geq = odict_find_geq(odict, key, hint);
757 if (geq != NULL)
758 return odict_prev(geq, odict);
759 else
760 return odict_last(odict);
761}
762
763/** Return parent, grandparent and uncle.
764 *
765 * @param n Node
766 * @param p Place to store pointer to parent of @a n
767 * @param pcs Place to store position of @a n w.r.t. @a p
768 * @param g Place to store pointer to grandparent of @a n
769 * @param gcs Place to store position of @a p w.r.t. @a g
770 * @param u Place to store pointer to uncle of @a n
771 */
772static void odict_pgu(odlink_t *n, odlink_t **p, odict_child_sel_t *pcs,
773 odlink_t **g, odict_child_sel_t *gcs, odlink_t **u)
774{
775 *p = n->up;
776
777 if (*p == NULL) {
778 /* No parent */
779 *g = NULL;
780 *u = NULL;
781 return;
782 }
783
784 if ((*p)->a == n) {
785 *pcs = odcs_a;
786 } else {
787 assert((*p)->b == n);
788 *pcs = odcs_b;
789 }
790
791 *g = (*p)->up;
792 if (*g == NULL) {
793 /* No grandparent */
794 *u = NULL;
795 return;
796 }
797
798 if ((*g)->a == *p) {
799 *gcs = odcs_a;
800 *u = (*g)->b;
801 } else {
802 assert((*g)->b == *p);
803 *gcs = odcs_b;
804 *u = (*g)->a;
805 }
806}
807
808/** Return sibling and parent w.r.t. parent.
809 *
810 * @param n Node
811 * @param p Parent of @ an
812 * @param pcs Place to store position of @a n w.r.t. @a p.
813 * @param rs Place to strore pointer to sibling
814 */
815static void odict_sibling(odlink_t *n, odlink_t *p, odict_child_sel_t *pcs,
816 odlink_t **rs)
817{
818 if (p->a == n) {
819 *pcs = odcs_a;
820 *rs = p->b;
821 } else {
822 *pcs = odcs_b;
823 *rs = p->a;
824 }
825}
826
827/** Ordered dictionary left rotation.
828 *
829 * Q P
830 * P C <- A Q
831 * A B B C
832 *
833 */
834static void odict_rotate_left(odlink_t *p)
835{
836 odlink_t *q;
837
838 q = p->b;
839 assert(q != NULL);
840
841 /* Replace P with Q as the root of the subtree */
842 odict_replace_subtree(q, p);
843
844 /* Relink P under Q, B under P */
845 p->up = q;
846 p->b = q->a;
847 if (p->b != NULL)
848 p->b->up = p;
849 q->a = p;
850
851 /* Fix odict root */
852 if (p->odict->root == p)
853 p->odict->root = q;
854}
855
856/** Ordered dictionary right rotation.
857 *
858 * Q P
859 * P C -> A Q
860 * A B B C
861 *
862 */
863static void odict_rotate_right(odlink_t *q)
864{
865 odlink_t *p;
866
867 p = q->a;
868 assert(p != NULL);
869
870 /* Replace Q with P as the root of the subtree */
871 odict_replace_subtree(p, q);
872
873 /* Relink Q under P, B under Q */
874 q->up = p;
875 q->a = p->b;
876 if (q->a != NULL)
877 q->a->up = q;
878 p->b = q;
879
880 /* Fix odict root */
881 if (q->odict->root == q)
882 q->odict->root = p;
883}
884
885/** Swap two nodes.
886 *
887 * Swap position of two nodes in the tree, keeping their identity.
888 * This means we don't copy the contents, instead we shuffle around pointers
889 * from and to the nodes.
890 *
891 * @param a First node
892 * @param b Second node
893 */
894static void odict_swap_node(odlink_t *a, odlink_t *b)
895{
896 odlink_t *n;
897 odict_color_t c;
898
899 /* Backlink from A's parent */
900 if (a->up != NULL && a->up != b) {
901 if (a->up->a == a) {
902 a->up->a = b;
903 } else {
904 assert(a->up->b == a);
905 a->up->b = b;
906 }
907 }
908
909 /* Backlink from A's left child */
910 if (a->a != NULL && a->a != b)
911 a->a->up = b;
912 /* Backling from A's right child */
913 if (a->b != NULL && a->b != b)
914 a->b->up = b;
915
916 /* Backlink from B's parent */
917 if (b->up != NULL && b->up != a) {
918 if (b->up->a == b) {
919 b->up->a = a;
920 } else {
921 assert(b->up->b == b);
922 b->up->b = a;
923 }
924 }
925
926 /* Backlink from B's left child */
927 if (b->a != NULL && b->a != a)
928 b->a->up = a;
929 /* Backling from B's right child */
930 if (b->b != NULL && b->b != a)
931 b->b->up = a;
932
933 /*
934 * Swap links going out of A and out of B
935 */
936 n = a->up;
937 a->up = b->up;
938 b->up = n;
939
940 n = a->a;
941 a->a = b->a;
942 b->a = n;
943
944 n = a->b;
945 a->b = b->b;
946 b->b = n;
947
948 c = a->color;
949 a->color = b->color;
950 b->color = c;
951
952 /* When A and B are adjacent, fix self-loops that might have arisen */
953 if (a->up == a)
954 a->up = b;
955 if (a->a == a)
956 a->a = b;
957 if (a->b == a)
958 a->b = b;
959 if (b->up == b)
960 b->up = a;
961 if (b->a == b)
962 b->a = a;
963 if (b->b == b)
964 b->b = a;
965
966 /* Fix odict root */
967 if (a == a->odict->root)
968 a->odict->root = b;
969 else if (b == a->odict->root)
970 a->odict->root = a;
971}
972
973/** Replace subtree.
974 *
975 * Replace subtree @a old with another subtree @a n. This makes the parent
976 * point to the new subtree root and the up pointer of @a n to point to
977 * the parent.
978 *
979 * @param old Subtree to be replaced
980 * @param n New subtree
981 */
982static void odict_replace_subtree(odlink_t *n, odlink_t *old)
983{
984 if (old->up != NULL) {
985 if (old->up->a == old) {
986 old->up->a = n;
987 } else {
988 assert(old->up->b == old);
989 old->up->b = n;
990 }
991 } else {
992 assert(old->odict->root == old);
993 old->odict->root = n;
994 }
995
996 n->up = old->up;
997}
998
999/** Unlink node.
1000 *
1001 * @param n Ordered dictionary node
1002 */
1003static void odict_unlink(odlink_t *n)
1004{
1005 if (n->up != NULL) {
1006 if (n->up->a == n) {
1007 n->up->a = NULL;
1008 } else {
1009 assert(n->up->b == n);
1010 n->up->b = NULL;
1011 }
1012
1013 n->up = NULL;
1014 } else {
1015 assert(n->odict->root == n);
1016 n->odict->root = NULL;
1017 }
1018
1019 if (n->a != NULL) {
1020 n->a->up = NULL;
1021 n->a = NULL;
1022 }
1023
1024 if (n->b != NULL) {
1025 n->b->up = NULL;
1026 n->b = NULL;
1027 }
1028
1029 n->odict = NULL;
1030 list_remove(&n->lentries);
1031}
1032
1033/** Link node as left child.
1034 *
1035 * Append new node @a n as left child of existing node @a old.
1036 *
1037 * @param n New node
1038 * @param old Old node
1039 */
1040static void odict_link_child_a(odlink_t *n, odlink_t *old)
1041{
1042 old->a = n;
1043 n->up = old;
1044 n->odict = old->odict;
1045 list_insert_before(&n->lentries, &old->lentries);
1046}
1047
1048/** Link node as right child.
1049 *
1050 * Append new node @a n as right child of existing node @a old.
1051 *
1052 * @param n New node
1053 * @param old Old node
1054 */
1055static void odict_link_child_b(odlink_t *n, odlink_t *old)
1056{
1057 old->b = n;
1058 n->up = old;
1059 n->odict = old->odict;
1060 list_insert_after(&n->lentries, &old->lentries);
1061}
1062
1063/** Get node where search should be started.
1064 *
1065 * @param odict Ordered dictionary
1066 * @param key Key being searched for
1067 * @param hint Node that might be near the search target or @c NULL
1068 *
1069 * @return Node from where search should be started
1070 */
1071static odlink_t *odict_search_start_node(odict_t *odict, void *key,
1072 odlink_t *hint)
1073{
1074 odlink_t *a;
1075 odlink_t *b;
1076 odlink_t *cur;
1077 int d, da, db;
1078
1079 assert(hint == NULL || hint->odict == odict);
1080
1081 /* If the key is greater than the maximum, start search in the maximum */
1082 b = odict_last(odict);
1083 if (b != NULL) {
1084 d = odict->cmp(odict->getkey(b), key);
1085 if (d < 0)
1086 return b;
1087 }
1088
1089 /* If the key is less tna the minimum, start search in the minimum */
1090 a = odict_first(odict);
1091 if (a != NULL) {
1092 d = odict->cmp(key, odict->getkey(a));
1093 if (d < 0)
1094 return a;
1095 }
1096
1097 /*
1098 * Proposition: Let A, B be two BST nodes such that B is a descendant
1099 * of A. Let N be a node such that either key(A) < key(N) < key(B)
1100 * Then N is a descendant of A.
1101 * Corollary: We can start searching for N from A, instead from
1102 * the root.
1103 *
1104 * Proof: When walking the BST in order, visit_tree(A) does a
1105 * visit_tree(A->a), visit(A), visit(A->b). If key(A) < key(B),
1106 * we will first visit A, then while visiting all nodes with values
1107 * between A and B we will not leave subtree A->b.
1108 */
1109
1110 /* If there is no hint, start search from the root */
1111 if (hint == NULL)
1112 return odict->root;
1113
1114 /*
1115 * Start from hint and walk up to the root, keeping track of
1116 * minimum and maximum. Once key is strictly between them,
1117 * we can return the current node, which we've proven to be
1118 * an ancestor of a potential node with the given key
1119 */
1120 a = b = cur = hint;
1121 while (cur->up != NULL) {
1122 cur = cur->up;
1123
1124 d = odict->cmp(odict->getkey(cur), odict->getkey(a));
1125 if (d < 0)
1126 a = cur;
1127
1128 d = odict->cmp(odict->getkey(b), odict->getkey(cur));
1129 if (d < 0)
1130 b = cur;
1131
1132 da = odict->cmp(odict->getkey(a), key);
1133 db = odict->cmp(key, odict->getkey(b));
1134 if (da < 0 && db < 0) {
1135 /* Both a and b are descendants of cur */
1136 return cur;
1137 }
1138 }
1139
1140 return odict->root;
1141}
1142
1143/** @}
1144 */
Note: See TracBrowser for help on using the repository browser.