source: mainline/uspace/lib/c/generic/adt/odict.c@ 2c4e1cc

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

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • 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.