source: mainline/uspace/lib/c/generic/adt/odict.c@ 3061bc1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3061bc1 was 1b20da0, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on non-empty lines, in certain file types.

Command used: tools/srepl '\([^[:space:]]\)\s\+$' '\1' -- *.c *.h *.py *.sh *.s *.S *.ag

  • Property mode set to 100644
File size: 23.8 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 libc
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 <stdio.h>
46#include <stdlib.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 putchar(' ' );
78 odict_print_tree(cur->a);
79 putchar(',');
80 odict_print_tree(cur->b);
81 }
82 putchar(']');
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 Funcition 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/** Initialize ordered dictionary link.
209 *
210 * @param odlink Ordered dictionary link
211 */
212void odlink_initialize(odlink_t *odlink)
213{
214 odlink->odict = NULL;
215 odlink->up = NULL;
216 odlink->a = NULL;
217 odlink->b = NULL;
218 link_initialize(&odlink->lentries);
219}
220
221/** Insert entry in ordered dictionary.
222 *
223 * Insert entry in ordered dictionary, placing it after other entries
224 * with the same key.
225 *
226 * @param odlink New entry
227 * @param odict Ordered dictionary
228 * @param hint An entry that might be near the new entry or @c NULL
229 */
230void odict_insert(odlink_t *odlink, odict_t *odict, odlink_t *hint)
231{
232 int d;
233 odlink_t *cur;
234 odlink_t *p;
235 odlink_t *g;
236 odlink_t *u;
237 odict_child_sel_t pcs, gcs;
238
239 assert(!odlink_used(odlink));
240
241 if (odict->root == NULL) {
242 /* odlink is the root node */
243 odict->root = odlink;
244 odlink->odict = odict;
245 odlink->color = odc_black;
246 list_append(&odlink->lentries, &odict->entries);
247 return;
248 }
249
250 cur = odict_search_start_node(odict, odict->getkey(odlink), hint);
251 while (true) {
252 d = odict->cmp(odict->getkey(odlink), odict->getkey(cur));
253 if (d < 0) {
254 if (cur->a == NULL) {
255 odict_link_child_a(odlink, cur);
256 break;
257 }
258 cur = cur->a;
259 } else {
260 if (cur->b == NULL) {
261 odict_link_child_b(odlink, cur);
262 break;
263 }
264 cur = cur->b;
265 }
266 }
267
268
269 odlink->color = odc_red;
270
271 while (true) {
272 /* Fix up odlink and its parent potentially being red */
273 if (odlink->up == NULL) {
274 odlink->color = odc_black;
275 break;
276 }
277
278 if (odlink->up->color == odc_black)
279 break;
280
281 /* Get parent, grandparent, uncle */
282 odict_pgu(odlink, &p, &pcs, &g, &gcs, &u);
283
284 if (g == NULL) {
285 p->color = odc_black;
286 break;
287 }
288
289 if (p->color == odc_red && u != NULL && u->color == odc_red) {
290 /* Parent and uncle are both red */
291 p->color = odc_black;
292 u->color = odc_black;
293 g->color = odc_red;
294 odlink = g;
295 continue;
296 }
297
298 /* Parent is red but uncle is black, odlink-P-G is trans */
299 if (pcs != gcs) {
300 if (gcs == odcs_a) {
301 /* odlink is right child of P */
302 /* P is left child of G */
303 odict_rotate_left(p);
304 } else {
305 /* odlink is left child of P */
306 /* P is right child of G */
307 odict_rotate_right(p);
308 }
309
310 odlink = p;
311 odict_pgu(odlink, &p, &pcs, &g, &gcs, &u);
312 }
313
314 /* odlink-P-G is now cis */
315 assert(pcs == gcs);
316 if (pcs == odcs_a) {
317 /* odlink is left child of P */
318 /* P is left child of G */
319 odict_rotate_right(g);
320 } else {
321 /* odlink is right child of P */
322 /* P is right child of G */
323 odict_rotate_left(g);
324 }
325
326 p->color = odc_black;
327 g->color = odc_red;
328 break;
329 }
330}
331
332/** Remove entry from ordered dictionary.
333 *
334 * @param odlink Ordered dictionary link
335 */
336void odict_remove(odlink_t *odlink)
337{
338 odlink_t *n;
339 odlink_t *c;
340 odlink_t *p;
341 odlink_t *s;
342 odlink_t *sc, *st;
343 odict_child_sel_t pcs;
344
345 if (odlink->a != NULL && odlink->b != NULL) {
346 n = odict_next(odlink, odlink->odict);
347 assert(n != NULL);
348
349 odict_swap_node(odlink, n);
350 }
351
352 /* odlink has at most one child */
353 if (odlink->a != NULL) {
354 assert(odlink->b == NULL);
355 c = odlink->a;
356 } else {
357 c = odlink->b;
358 }
359
360 if (odlink->color == odc_red) {
361 /* We can remove it harmlessly */
362 assert(c == NULL);
363 odict_unlink(odlink);
364 return;
365 }
366
367 /* odlink->color == odc_black */
368 if (c != NULL && c->color == odc_red) {
369 /* Child is red: swap colors of S and C */
370 c->color = odc_black;
371 odict_replace_subtree(c, odlink);
372 odlink->up = odlink->a = odlink->b = NULL;
373 odlink->odict = NULL;
374 list_remove(&odlink->lentries);
375 return;
376 }
377
378 /* There cannot be one black child */
379 assert(c == NULL);
380
381 n = NULL;
382 p = odlink->up;
383 odict_unlink(odlink);
384 /* We removed one black node, creating imbalance */
385again:
386 /* Case 1: N is the new root */
387 if (p == NULL)
388 return;
389
390 odict_sibling(n, p, &pcs, &s);
391
392 /* Paths through N have one less black node than paths through S */
393
394 /* Case 2: S is red */
395 if (s->color == odc_red) {
396 assert(p->color == odc_black);
397 p->color = odc_red;
398 s->color = odc_black;
399 if (n == p->a)
400 odict_rotate_left(p);
401 else
402 odict_rotate_right(p);
403 odict_sibling(n, p, &pcs, &s);
404 /* Now S is black */
405 assert(s->color == odc_black);
406 }
407
408 /* Case 3: P, S and S's children are black */
409 if (p->color == odc_black &&
410 s->color == odc_black &&
411 (s->a == NULL || s->a->color == odc_black) &&
412 (s->b == NULL || s->b->color == odc_black)) {
413 /*
414 * Changing S to red means all paths through S or N have one
415 * less black node than they should. So redo the same for P.
416 */
417 s->color = odc_red;
418 n = p;
419 p = n->up;
420 goto again;
421 }
422
423 /* Case 4: P is red, S and S's children are black */
424 if (p->color == odc_red &&
425 s->color == odc_black &&
426 (s->a == NULL || s->a->color == odc_black) &&
427 (s->b == NULL || s->b->color == odc_black)) {
428 /* Swap colors of S and P */
429 s->color = odc_red;
430 p->color = odc_black;
431 return;
432 }
433
434 /* N is the left child */
435 if (pcs == odcs_a) {
436 st = s->a;
437 sc = s->b;
438 } else {
439 st = s->b;
440 sc = s->a;
441 }
442
443 /* Case 5: S is black and S's trans child is red, S's cis child is black */
444 if (s->color == odc_black &&
445 (st != NULL && st->color == odc_red) &&
446 (sc == NULL || sc->color == odc_black)) {
447 /* N is the left child */
448 if (pcs == odcs_a)
449 odict_rotate_right(s);
450 else
451 odict_rotate_left(s);
452 s->color = odc_red;
453 s->up->color = odc_black;
454 /* Now N has a black sibling whose cis child is red */
455 odict_sibling(n, p, &pcs, &s);
456 /* N is the left child */
457 if (pcs == odcs_a) {
458 st = s->a;
459 sc = s->b;
460 } else {
461 st = s->b;
462 sc = s->a;
463 }
464 }
465
466 /* Case 6: S is black, S's cis child is red */
467 assert(s->color == odc_black);
468 assert(sc != NULL);
469 assert(sc->color == odc_red);
470
471 if (pcs == odcs_a)
472 odict_rotate_left(p);
473 else
474 odict_rotate_right(p);
475
476 s->color = p->color;
477 p->color = odc_black;
478 sc->color = odc_black;
479}
480
481/** Update dictionary after entry key has been changed.
482 *
483 * After the caller modifies the key of an entry, they need to call
484 * this function so that the dictionary can update itself accordingly.
485 *
486 * @param odlink Ordered dictionary entry
487 * @param odict Ordered dictionary
488 */
489void odict_key_update(odlink_t *odlink, odict_t *odict)
490{
491 odlink_t *n;
492
493 n = odict_next(odlink, odict);
494 odict_remove(odlink);
495 odict_insert(odlink, odict, n);
496}
497
498/** Return true if entry is in a dictionary.
499 *
500 * @param odlink Ordered dictionary entry
501 * @return @c true if entry is in a dictionary, @c false otherwise
502 */
503bool odlink_used(odlink_t *odlink)
504{
505 return odlink->odict != NULL;
506}
507
508/** Return true if ordered dictionary is empty.
509 *
510 * @param odict Ordered dictionary
511 * @return @c true if @a odict is emptry, @c false otherwise
512 */
513bool odict_empty(odict_t *odict)
514{
515 return odict->root == NULL;
516}
517
518/** Return the number of entries in @a odict.
519 *
520 * @param odict Ordered dictionary
521 */
522unsigned long odict_count(odict_t *odict)
523{
524 unsigned long cnt;
525 odlink_t *cur;
526
527 cnt = 0;
528 cur = odict_first(odict);
529 while (cur != NULL) {
530 ++cnt;
531 cur = odict_next(cur, odict);
532 }
533
534 return cnt;
535}
536
537/** Return first entry in a list or @c NULL if list is empty.
538 *
539 * @param odict Ordered dictionary
540 * @return First entry
541 */
542odlink_t *odict_first(odict_t *odict)
543{
544 link_t *link;
545
546 link = list_first(&odict->entries);
547 if (link == NULL)
548 return NULL;
549
550 return list_get_instance(link, odlink_t, lentries);
551}
552
553/** Return last entry in a list or @c NULL if list is empty
554 *
555 * @param odict Ordered dictionary
556 * @return Last entry
557 */
558odlink_t *odict_last(odict_t *odict)
559{
560 link_t *link;
561
562 link = list_last(&odict->entries);
563 if (link == NULL)
564 return NULL;
565
566 return list_get_instance(link, odlink_t, lentries);
567}
568
569/** Return previous entry in list or @c NULL if @a link is the first one.
570 *
571 * @param odlink Entry
572 * @param odict Ordered dictionary
573 * @return Previous entry
574 */
575odlink_t *odict_prev(odlink_t *odlink, odict_t *odict)
576{
577 link_t *link;
578
579 link = list_prev(&odlink->lentries, &odlink->odict->entries);
580 if (link == NULL)
581 return NULL;
582
583 return list_get_instance(link, odlink_t, lentries);
584}
585
586/** Return next entry in dictionary or @c NULL if @a odlink is the last one
587 *
588 * @param odlink Entry
589 * @param odict Ordered dictionary
590 * @return Next entry
591 */
592odlink_t *odict_next(odlink_t *odlink, odict_t *odict)
593{
594 link_t *link;
595
596 link = list_next(&odlink->lentries, &odlink->odict->entries);
597 if (link == NULL)
598 return NULL;
599
600 return list_get_instance(link, odlink_t, lentries);
601}
602
603/** Find first entry whose key is equal to @a key/
604 *
605 * @param odict Ordered dictionary
606 * @param key Key
607 * @param hint Nearby entry
608 * @return Pointer to entry on success, @c NULL on failure
609 */
610odlink_t *odict_find_eq(odict_t *odict, void *key, odlink_t *hint)
611{
612 odlink_t *geq;
613
614 geq = odict_find_geq(odict, key, hint);
615 if (geq == NULL)
616 return NULL;
617
618 if (odict->cmp(odict->getkey(geq), key) == 0)
619 return geq;
620 else
621 return NULL;
622}
623
624/** Find last entry whose key is equal to @a key/
625 *
626 * @param odict Ordered dictionary
627 * @param key Key
628 * @param hint Nearby entry
629 * @return Pointer to entry on success, @c NULL on failure
630 */
631odlink_t *odict_find_eq_last(odict_t *odict, void *key, odlink_t *hint)
632{
633 odlink_t *leq;
634
635 leq = odict_find_leq(odict, key, hint);
636 if (leq == NULL)
637 return NULL;
638
639 if (odict->cmp(odict->getkey(leq), key) == 0)
640 return leq;
641 else
642 return NULL;
643}
644
645/** Find first entry whose key is greater than or equal to @a key
646 *
647 * @param odict Ordered dictionary
648 * @param key Key
649 * @param hint Nearby entry
650 * @return Pointer to entry on success, @c NULL on failure
651 */
652odlink_t *odict_find_geq(odict_t *odict, void *key, odlink_t *hint)
653{
654 odlink_t *cur;
655 odlink_t *next;
656 int d;
657
658 cur = odict_search_start_node(odict, key, hint);
659 if (cur == NULL)
660 return NULL;
661
662 while (true) {
663 d = odict->cmp(odict->getkey(cur), key);
664 if (d >= 0)
665 next = cur->a;
666 else
667 next = cur->b;
668
669 if (next == NULL)
670 break;
671
672 cur = next;
673 }
674
675 if (d >= 0) {
676 return cur;
677 } else {
678 return odict_next(cur, odict);
679 }
680}
681
682/** Find last entry whose key is greater than @a key.
683 *
684 * @param odict Ordered dictionary
685 * @param key Key
686 * @param hint Nearby entry
687 * @return Pointer to entry on success, @c NULL on failure
688 */
689odlink_t *odict_find_gt(odict_t *odict, void *key, odlink_t *hint)
690{
691 odlink_t *leq;
692
693 leq = odict_find_leq(odict, key, hint);
694 if (leq != NULL)
695 return odict_next(leq, odict);
696 else
697 return odict_first(odict);
698}
699
700/** Find last entry whose key is less than or equal to @a key
701 *
702 * @param odict Ordered dictionary
703 * @param key Key
704 * @param hint Nearby entry
705 * @return Pointer to entry on success, @c NULL on failure
706 */
707odlink_t *odict_find_leq(odict_t *odict, void *key, odlink_t *hint)
708{
709 odlink_t *cur;
710 odlink_t *next;
711 int d;
712
713 cur = odict_search_start_node(odict, key, hint);
714 if (cur == NULL)
715 return NULL;
716
717 while (true) {
718 d = odict->cmp(key, odict->getkey(cur));
719 if (d >= 0)
720 next = cur->b;
721 else
722 next = cur->a;
723
724 if (next == NULL)
725 break;
726
727 cur = next;
728 }
729
730 if (d >= 0) {
731 return cur;
732 } else {
733 return odict_prev(cur, odict);
734 }
735}
736
737/** Find last entry whose key is less than @a key.
738 *
739 * @param odict Ordered dictionary
740 * @param key Key
741 * @param hint Nearby entry
742 * @return Pointer to entry on success, @c NULL on failure
743 */
744odlink_t *odict_find_lt(odict_t *odict, void *key, odlink_t *hint)
745{
746 odlink_t *geq;
747
748 geq = odict_find_geq(odict, key, hint);
749 if (geq != NULL)
750 return odict_prev(geq, odict);
751 else
752 return odict_last(odict);
753}
754
755/** Return parent, grandparent and uncle.
756 *
757 * @param n Node
758 * @param p Place to store pointer to parent of @a n
759 * @param pcs Place to store position of @a n w.r.t. @a p
760 * @param g Place to store pointer to grandparent of @a n
761 * @param gcs Place to store position of @a p w.r.t. @a g
762 * @param u Place to store pointer to uncle of @a n
763 */
764static void odict_pgu(odlink_t *n, odlink_t **p, odict_child_sel_t *pcs,
765 odlink_t **g, odict_child_sel_t *gcs, odlink_t **u)
766{
767 *p = n->up;
768
769 if (*p == NULL) {
770 /* No parent */
771 *g = NULL;
772 *u = NULL;
773 return;
774 }
775
776 if ((*p)->a == n) {
777 *pcs = odcs_a;
778 } else {
779 assert((*p)->b == n);
780 *pcs = odcs_b;
781 }
782
783 *g = (*p)->up;
784 if (*g == NULL) {
785 /* No grandparent */
786 *u = NULL;
787 return;
788 }
789
790 if ((*g)->a == *p) {
791 *gcs = odcs_a;
792 *u = (*g)->b;
793 } else {
794 assert((*g)->b == *p);
795 *gcs = odcs_b;
796 *u = (*g)->a;
797 }
798}
799
800/** Return sibling and parent w.r.t. parent.
801 *
802 * @param n Node
803 * @param p Parent of @ an
804 * @param pcs Place to store position of @a n w.r.t. @a p.
805 * @param rs Place to strore pointer to sibling
806 */
807static void odict_sibling(odlink_t *n, odlink_t *p, odict_child_sel_t *pcs,
808 odlink_t **rs)
809{
810 if (p->a == n) {
811 *pcs = odcs_a;
812 *rs = p->b;
813 } else {
814 *pcs = odcs_b;
815 *rs = p->a;
816 }
817}
818
819/** Ordered dictionary left rotation.
820 *
821 * Q P
822 * P C <- A Q
823 * A B B C
824 *
825 */
826static void odict_rotate_left(odlink_t *p)
827{
828 odlink_t *q;
829
830 q = p->b;
831 assert(q != NULL);
832
833 /* Replace P with Q as the root of the subtree */
834 odict_replace_subtree(q, p);
835
836 /* Relink P under Q, B under P */
837 p->up = q;
838 p->b = q->a;
839 if (p->b != NULL)
840 p->b->up = p;
841 q->a = p;
842
843 /* Fix odict root */
844 if (p->odict->root == p)
845 p->odict->root = q;
846}
847
848/** Ordered dictionary right rotation.
849 *
850 * Q P
851 * P C -> A Q
852 * A B B C
853 *
854 */
855static void odict_rotate_right(odlink_t *q)
856{
857 odlink_t *p;
858
859 p = q->a;
860 assert(p != NULL);
861
862 /* Replace Q with P as the root of the subtree */
863 odict_replace_subtree(p, q);
864
865 /* Relink Q under P, B under Q */
866 q->up = p;
867 q->a = p->b;
868 if (q->a != NULL)
869 q->a->up = q;
870 p->b = q;
871
872 /* Fix odict root */
873 if (q->odict->root == q)
874 q->odict->root = p;
875}
876
877/** Swap two nodes.
878 *
879 * Swap position of two nodes in the tree, keeping their identity.
880 * This means we don't copy the contents, instead we shuffle around pointers
881 * from and to the nodes.
882 *
883 * @param a First node
884 * @param b Second node
885 */
886static void odict_swap_node(odlink_t *a, odlink_t *b)
887{
888 odlink_t *n;
889 odict_color_t c;
890
891 /* Backlink from A's parent */
892 if (a->up != NULL && a->up != b) {
893 if (a->up->a == a) {
894 a->up->a = b;
895 } else {
896 assert(a->up->b == a);
897 a->up->b = b;
898 }
899 }
900
901 /* Backlink from A's left child */
902 if (a->a != NULL && a->a != b)
903 a->a->up = b;
904 /* Backling from A's right child */
905 if (a->b != NULL && a->b != b)
906 a->b->up = b;
907
908 /* Backlink from B's parent */
909 if (b->up != NULL && b->up != a) {
910 if (b->up->a == b) {
911 b->up->a = a;
912 } else {
913 assert(b->up->b == b);
914 b->up->b = a;
915 }
916 }
917
918 /* Backlink from B's left child */
919 if (b->a != NULL && b->a != a)
920 b->a->up = a;
921 /* Backling from B's right child */
922 if (b->b != NULL && b->b != a)
923 b->b->up = a;
924
925 /* Swap links going out of A and out of B */
926 n = a->up; a->up = b->up; b->up = n;
927 n = a->a; a->a = b->a; b->a = n;
928 n = a->b; a->b = b->b; b->b = n;
929 c = a->color; a->color = b->color; b->color = c;
930
931 /* When A and B are adjacent, fix self-loops that might have arisen */
932 if (a->up == a)
933 a->up = b;
934 if (a->a == a)
935 a->a = b;
936 if (a->b == a)
937 a->b = b;
938 if (b->up == b)
939 b->up = a;
940 if (b->a == b)
941 b->a = a;
942 if (b->b == b)
943 b->b = a;
944
945 /* Fix odict root */
946 if (a == a->odict->root)
947 a->odict->root = b;
948 else if (b == a->odict->root)
949 a->odict->root = a;
950}
951
952/** Replace subtree.
953 *
954 * Replace subtree @a old with another subtree @a n. This makes the parent
955 * point to the new subtree root and the up pointer of @a n to point to
956 * the parent.
957 *
958 * @param old Subtree to be replaced
959 * @param n New subtree
960 */
961static void odict_replace_subtree(odlink_t *n, odlink_t *old)
962{
963 if (old->up != NULL) {
964 if (old->up->a == old) {
965 old->up->a = n;
966 } else {
967 assert(old->up->b == old);
968 old->up->b = n;
969 }
970 } else {
971 assert(old->odict->root == old);
972 old->odict->root = n;
973 }
974
975 n->up = old->up;
976}
977
978/** Unlink node.
979 *
980 * @param n Ordered dictionary node
981 */
982static void odict_unlink(odlink_t *n)
983{
984 if (n->up != NULL) {
985 if (n->up->a == n) {
986 n->up->a = NULL;
987 } else {
988 assert(n->up->b == n);
989 n->up->b = NULL;
990 }
991
992 n->up = NULL;
993 } else {
994 assert(n->odict->root == n);
995 n->odict->root = NULL;
996 }
997
998 if (n->a != NULL) {
999 n->a->up = NULL;
1000 n->a = NULL;
1001 }
1002
1003 if (n->b != NULL) {
1004 n->b->up = NULL;
1005 n->b = NULL;
1006 }
1007
1008 n->odict = NULL;
1009 list_remove(&n->lentries);
1010}
1011
1012/** Link node as left child.
1013 *
1014 * Append new node @a n as left child of existing node @a old.
1015 *
1016 * @param n New node
1017 * @param old Old node
1018 */
1019static void odict_link_child_a(odlink_t *n, odlink_t *old)
1020{
1021 old->a = n;
1022 n->up = old;
1023 n->odict = old->odict;
1024 list_insert_before(&n->lentries, &old->lentries);
1025}
1026
1027/** Link node as right child.
1028 *
1029 * Append new node @a n as right child of existing node @a old.
1030 *
1031 * @param n New node
1032 * @param old Old node
1033 */
1034static void odict_link_child_b(odlink_t *n, odlink_t *old)
1035{
1036 old->b = n;
1037 n->up = old;
1038 n->odict = old->odict;
1039 list_insert_after(&n->lentries, &old->lentries);
1040}
1041
1042/** Get node where search should be started.
1043 *
1044 * @param odict Ordered dictionary
1045 * @param key Key being searched for
1046 * @param hint Node that might be near the search target or @c NULL
1047 *
1048 * @return Node from where search should be started
1049 */
1050static odlink_t *odict_search_start_node(odict_t *odict, void *key,
1051 odlink_t *hint)
1052{
1053 odlink_t *a;
1054 odlink_t *b;
1055 odlink_t *cur;
1056 int d, da, db;
1057
1058 assert(hint == NULL || hint->odict == odict);
1059
1060 /* If the key is greater than the maximum, start search in the maximum */
1061 b = odict_last(odict);
1062 if (b != NULL) {
1063 d = odict->cmp(odict->getkey(b), key);
1064 if (d < 0)
1065 return b;
1066 }
1067
1068 /* If the key is less tna the minimum, start search in the minimum */
1069 a = odict_first(odict);
1070 if (a != NULL) {
1071 d = odict->cmp(key, odict->getkey(a));
1072 if (d < 0)
1073 return a;
1074 }
1075
1076 /*
1077 * Proposition: Let A, B be two BST nodes such that B is a descendant
1078 * of A. Let N be a node such that either key(A) < key(N) < key(B)
1079 * Then N is a descendant of A.
1080 * Corollary: We can start searching for N from A, instead from
1081 * the root.
1082 *
1083 * Proof: When walking the BST in order, visit_tree(A) does a
1084 * visit_tree(A->a), visit(A), visit(A->b). If key(A) < key(B),
1085 * we will first visit A, then while visiting all nodes with values
1086 * between A and B we will not leave subtree A->b.
1087 */
1088
1089 /* If there is no hint, start search from the root */
1090 if (hint == NULL)
1091 return odict->root;
1092
1093 /*
1094 * Start from hint and walk up to the root, keeping track of
1095 * minimum and maximum. Once key is strictly between them,
1096 * we can return the current node, which we've proven to be
1097 * an ancestor of a potential node with the given key
1098 */
1099 a = b = cur = hint;
1100 while (cur->up != NULL) {
1101 cur = cur->up;
1102
1103 d = odict->cmp(odict->getkey(cur), odict->getkey(a));
1104 if (d < 0)
1105 a = cur;
1106
1107 d = odict->cmp(odict->getkey(b), odict->getkey(cur));
1108 if (d < 0)
1109 b = cur;
1110
1111 da = odict->cmp(odict->getkey(a), key);
1112 db = odict->cmp(key, odict->getkey(b));
1113 if (da < 0 && db < 0) {
1114 /* Both a and b are descendants of cur */
1115 return cur;
1116 }
1117 }
1118
1119 return odict->root;
1120}
1121
1122/** @}
1123 */
Note: See TracBrowser for help on using the repository browser.