]> git.proxmox.com Git - mirror_frr.git/blob - isisd/dict.c
isisd: address coverity findings
[mirror_frr.git] / isisd / dict.c
1 /*
2 * Dictionary Abstract Data Type
3 * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
4 *
5 * Free Software License:
6 *
7 * All rights are reserved by the author, with the following exceptions:
8 * Permission is granted to freely reproduce and distribute this software,
9 * possibly in exchange for a fee, provided that this copyright notice appears
10 * intact. Permission is also granted to adapt this software to produce
11 * derivative works, as long as the modified versions carry this copyright
12 * notice and additional notices stating that the work has been modified.
13 * This source code may be translated into executable form and incorporated
14 * into proprietary software; there is no requirement for such software to
15 * contain a copyright notice related to this source.
16 */
17
18 #include "zebra.h"
19 #include "zassert.h"
20 #include "memory.h"
21 #include "isis_memory.h"
22 #include "dict.h"
23
24 /*
25 * These macros provide short convenient names for structure members,
26 * which are embellished with dict_ prefixes so that they are
27 * properly confined to the documented namespace. It's legal for a
28 * program which uses dict to define, for instance, a macro called ``parent''.
29 * Such a macro would interfere with the dnode_t struct definition.
30 * In general, highly portable and reusable C modules which expose their
31 * structures need to confine structure member names to well-defined spaces.
32 * The resulting identifiers aren't necessarily convenient to use, nor
33 * readable, in the implementation, however!
34 */
35
36 #define left dict_left
37 #define right dict_right
38 #define parent dict_parent
39 #define color dict_color
40 #define key dict_key
41 #define data dict_data
42
43 #define nilnode dict_nilnode
44 #define nodecount dict_nodecount
45 #define maxcount dict_maxcount
46 #define compare dict_compare
47 #define allocnode dict_allocnode
48 #define freenode dict_freenode
49 #define context dict_context
50 #define dupes dict_dupes
51
52 #define dictptr dict_dictptr
53
54 #define dict_root(D) ((D)->nilnode.left)
55 #define dict_nil(D) (&(D)->nilnode)
56 #define DICT_DEPTH_MAX 64
57
58 static dnode_t *dnode_alloc(void *context);
59 static void dnode_free(dnode_t *node, void *context);
60
61 /*
62 * Perform a ``left rotation'' adjustment on the tree. The given node P and
63 * its right child C are rearranged so that the P instead becomes the left
64 * child of C. The left subtree of C is inherited as the new right subtree
65 * for P. The ordering of the keys within the tree is thus preserved.
66 */
67
68 static void rotate_left(dnode_t *upper)
69 {
70 dnode_t *lower, *lowleft, *upparent;
71
72 lower = upper->right;
73 upper->right = lowleft = lower->left;
74 lowleft->parent = upper;
75
76 lower->parent = upparent = upper->parent;
77
78 /* don't need to check for root node here because root->parent is
79 the sentinel nil node, and root->parent->left points back to root */
80
81 if (upper == upparent->left) {
82 upparent->left = lower;
83 } else {
84 assert (upper == upparent->right);
85 upparent->right = lower;
86 }
87
88 lower->left = upper;
89 upper->parent = lower;
90 }
91
92 /*
93 * This operation is the ``mirror'' image of rotate_left. It is
94 * the same procedure, but with left and right interchanged.
95 */
96
97 static void rotate_right(dnode_t *upper)
98 {
99 dnode_t *lower, *lowright, *upparent;
100
101 lower = upper->left;
102 upper->left = lowright = lower->right;
103 lowright->parent = upper;
104
105 lower->parent = upparent = upper->parent;
106
107 if (upper == upparent->right) {
108 upparent->right = lower;
109 } else {
110 assert (upper == upparent->left);
111 upparent->left = lower;
112 }
113
114 lower->right = upper;
115 upper->parent = lower;
116 }
117
118 /*
119 * Do a postorder traversal of the tree rooted at the specified
120 * node and free everything under it. Used by dict_free().
121 */
122
123 static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
124 {
125 if (node == nil)
126 return;
127 free_nodes(dict, node->left, nil);
128 free_nodes(dict, node->right, nil);
129 dict->freenode(node, dict->context);
130 }
131
132 /*
133 * This procedure performs a verification that the given subtree is a binary
134 * search tree. It performs an inorder traversal of the tree using the
135 * dict_next() successor function, verifying that the key of each node is
136 * strictly lower than that of its successor, if duplicates are not allowed,
137 * or lower or equal if duplicates are allowed. This function is used for
138 * debugging purposes.
139 */
140
141 static int verify_bintree(dict_t *dict)
142 {
143 dnode_t *first, *next;
144
145 first = dict_first(dict);
146
147 if (dict->dupes) {
148 while (first && (next = dict_next(dict, first))) {
149 if (dict->compare(first->key, next->key) > 0)
150 return 0;
151 first = next;
152 }
153 } else {
154 while (first && (next = dict_next(dict, first))) {
155 if (dict->compare(first->key, next->key) >= 0)
156 return 0;
157 first = next;
158 }
159 }
160 return 1;
161 }
162
163
164 /*
165 * This function recursively verifies that the given binary subtree satisfies
166 * three of the red black properties. It checks that every red node has only
167 * black children. It makes sure that each node is either red or black. And it
168 * checks that every path has the same count of black nodes from root to leaf.
169 * It returns the blackheight of the given subtree; this allows blackheights to
170 * be computed recursively and compared for left and right siblings for
171 * mismatches. It does not check for every nil node being black, because there
172 * is only one sentinel nil node. The return value of this function is the
173 * black height of the subtree rooted at the node ``root'', or zero if the
174 * subtree is not red-black.
175 */
176
177 static unsigned int verify_redblack(dnode_t *nil, dnode_t *root)
178 {
179 unsigned height_left, height_right;
180
181 if (root != nil) {
182 height_left = verify_redblack(nil, root->left);
183 height_right = verify_redblack(nil, root->right);
184 if (height_left == 0 || height_right == 0)
185 return 0;
186 if (height_left != height_right)
187 return 0;
188 if (root->color == dnode_red) {
189 if (root->left->color != dnode_black)
190 return 0;
191 if (root->right->color != dnode_black)
192 return 0;
193 return height_left;
194 }
195 if (root->color != dnode_black)
196 return 0;
197 return height_left + 1;
198 }
199 return 1;
200 }
201
202 /*
203 * Compute the actual count of nodes by traversing the tree and
204 * return it. This could be compared against the stored count to
205 * detect a mismatch.
206 */
207
208 static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root)
209 {
210 if (root == nil)
211 return 0;
212 else
213 return 1 + verify_node_count(nil, root->left)
214 + verify_node_count(nil, root->right);
215 }
216
217 /*
218 * Verify that the tree contains the given node. This is done by
219 * traversing all of the nodes and comparing their pointers to the
220 * given pointer. Returns 1 if the node is found, otherwise
221 * returns zero. It is intended for debugging purposes.
222 */
223
224 static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
225 {
226 if (root != nil) {
227 return root == node
228 || verify_dict_has_node(nil, root->left, node)
229 || verify_dict_has_node(nil, root->right, node);
230 }
231 return 0;
232 }
233
234
235 /*
236 * Dynamically allocate and initialize a dictionary object.
237 */
238
239 dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp)
240 {
241 dict_t *new = XCALLOC(MTYPE_ISIS_DICT, sizeof(dict_t));
242
243 if (new) {
244 new->compare = comp;
245 new->allocnode = dnode_alloc;
246 new->freenode = dnode_free;
247 new->context = NULL;
248 new->nodecount = 0;
249 new->maxcount = maxcount;
250 new->nilnode.left = &new->nilnode;
251 new->nilnode.right = &new->nilnode;
252 new->nilnode.parent = &new->nilnode;
253 new->nilnode.color = dnode_black;
254 new->dupes = 0;
255 }
256 return new;
257 }
258
259 /*
260 * Select a different set of node allocator routines.
261 */
262
263 void dict_set_allocator(dict_t *dict, dnode_alloc_t al,
264 dnode_free_t fr, void *context)
265 {
266 assert (dict_count(dict) == 0);
267 assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL));
268
269 dict->allocnode = al ? al : dnode_alloc;
270 dict->freenode = fr ? fr : dnode_free;
271 dict->context = context;
272 }
273
274 /*
275 * Free a dynamically allocated dictionary object. Removing the nodes
276 * from the tree before deleting it is required.
277 */
278
279 void dict_destroy(dict_t *dict)
280 {
281 assert (dict_isempty(dict));
282 XFREE(MTYPE_ISIS_DICT, dict);
283 }
284
285 /*
286 * Free all the nodes in the dictionary by using the dictionary's
287 * installed free routine. The dictionary is emptied.
288 */
289
290 void dict_free_nodes(dict_t *dict)
291 {
292 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
293 free_nodes(dict, root, nil);
294 dict->nodecount = 0;
295 dict->nilnode.left = &dict->nilnode;
296 dict->nilnode.right = &dict->nilnode;
297 }
298
299 /*
300 * Obsolescent function, equivalent to dict_free_nodes
301 */
302
303 void dict_free(dict_t *dict)
304 {
305 dict_free_nodes(dict);
306 }
307
308 /*
309 * Initialize a user-supplied dictionary object.
310 */
311
312 dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
313 {
314 dict->compare = comp;
315 dict->allocnode = dnode_alloc;
316 dict->freenode = dnode_free;
317 dict->context = NULL;
318 dict->nodecount = 0;
319 dict->maxcount = maxcount;
320 dict->nilnode.left = &dict->nilnode;
321 dict->nilnode.right = &dict->nilnode;
322 dict->nilnode.parent = &dict->nilnode;
323 dict->nilnode.color = dnode_black;
324 dict->dupes = 0;
325 return dict;
326 }
327
328 /*
329 * Initialize a dictionary in the likeness of another dictionary
330 */
331
332 void dict_init_like(dict_t *dict, const dict_t *template)
333 {
334 dict->compare = template->compare;
335 dict->allocnode = template->allocnode;
336 dict->freenode = template->freenode;
337 dict->context = template->context;
338 dict->nodecount = 0;
339 dict->maxcount = template->maxcount;
340 dict->nilnode.left = &dict->nilnode;
341 dict->nilnode.right = &dict->nilnode;
342 dict->nilnode.parent = &dict->nilnode;
343 dict->nilnode.color = dnode_black;
344 dict->dupes = template->dupes;
345
346 assert (dict_similar(dict, template));
347 }
348
349 /*
350 * Remove all nodes from the dictionary (without freeing them in any way).
351 */
352
353 static void dict_clear(dict_t *dict)
354 {
355 dict->nodecount = 0;
356 dict->nilnode.left = &dict->nilnode;
357 dict->nilnode.right = &dict->nilnode;
358 dict->nilnode.parent = &dict->nilnode;
359 assert (dict->nilnode.color == dnode_black);
360 }
361
362
363 /*
364 * Verify the integrity of the dictionary structure. This is provided for
365 * debugging purposes, and should be placed in assert statements. Just because
366 * this function succeeds doesn't mean that the tree is not corrupt. Certain
367 * corruptions in the tree may simply cause undefined behavior.
368 */
369
370 int dict_verify(dict_t *dict)
371 {
372 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
373
374 /* check that the sentinel node and root node are black */
375 if (root->color != dnode_black)
376 return 0;
377 if (nil->color != dnode_black)
378 return 0;
379 if (nil->right != nil)
380 return 0;
381 /* nil->left is the root node; check that its parent pointer is nil */
382 if (nil->left->parent != nil)
383 return 0;
384 /* perform a weak test that the tree is a binary search tree */
385 if (!verify_bintree(dict))
386 return 0;
387 /* verify that the tree is a red-black tree */
388 if (!verify_redblack(nil, root))
389 return 0;
390 if (verify_node_count(nil, root) != dict_count(dict))
391 return 0;
392 return 1;
393 }
394
395 /*
396 * Determine whether two dictionaries are similar: have the same comparison and
397 * allocator functions, and same status as to whether duplicates are allowed.
398 */
399
400 int dict_similar(const dict_t *left, const dict_t *right)
401 {
402 if (left->compare != right->compare)
403 return 0;
404
405 if (left->allocnode != right->allocnode)
406 return 0;
407
408 if (left->freenode != right->freenode)
409 return 0;
410
411 if (left->context != right->context)
412 return 0;
413
414 if (left->dupes != right->dupes)
415 return 0;
416
417 return 1;
418 }
419
420 /*
421 * Locate a node in the dictionary having the given key.
422 * If the node is not found, a null a pointer is returned (rather than
423 * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
424 * located node is returned.
425 */
426
427 dnode_t *dict_lookup(dict_t *dict, const void *key)
428 {
429 dnode_t *root = dict_root(dict);
430 dnode_t *nil = dict_nil(dict);
431 dnode_t *saved;
432 int result;
433
434 /* simple binary search adapted for trees that contain duplicate keys */
435
436 while (root != nil) {
437 result = dict->compare(key, root->key);
438 if (result < 0)
439 root = root->left;
440 else if (result > 0)
441 root = root->right;
442 else {
443 if (!dict->dupes) { /* no duplicates, return match */
444 return root;
445 } else { /* could be dupes, find leftmost one */
446 do {
447 saved = root;
448 root = root->left;
449 while (root != nil && dict->compare(key, root->key))
450 root = root->right;
451 } while (root != nil);
452 return saved;
453 }
454 }
455 }
456
457 return NULL;
458 }
459
460 /*
461 * Look for the node corresponding to the lowest key that is equal to or
462 * greater than the given key. If there is no such node, return null.
463 */
464
465 dnode_t *dict_lower_bound(dict_t *dict, const void *key)
466 {
467 dnode_t *root = dict_root(dict);
468 dnode_t *nil = dict_nil(dict);
469 dnode_t *tentative = 0;
470
471 while (root != nil) {
472 int result = dict->compare(key, root->key);
473
474 if (result > 0) {
475 root = root->right;
476 } else if (result < 0) {
477 tentative = root;
478 root = root->left;
479 } else {
480 if (!dict->dupes) {
481 return root;
482 } else {
483 tentative = root;
484 root = root->left;
485 }
486 }
487 }
488
489 return tentative;
490 }
491
492 /*
493 * Look for the node corresponding to the greatest key that is equal to or
494 * lower than the given key. If there is no such node, return null.
495 */
496
497 dnode_t *dict_upper_bound(dict_t *dict, const void *key)
498 {
499 dnode_t *root = dict_root(dict);
500 dnode_t *nil = dict_nil(dict);
501 dnode_t *tentative = 0;
502
503 while (root != nil) {
504 int result = dict->compare(key, root->key);
505
506 if (result < 0) {
507 root = root->left;
508 } else if (result > 0) {
509 tentative = root;
510 root = root->right;
511 } else {
512 if (!dict->dupes) {
513 return root;
514 } else {
515 tentative = root;
516 root = root->right;
517 }
518 }
519 }
520
521 return tentative;
522 }
523
524 /*
525 * Insert a node into the dictionary. The node should have been
526 * initialized with a data field. All other fields are ignored.
527 * The behavior is undefined if the user attempts to insert into
528 * a dictionary that is already full (for which the dict_isfull()
529 * function returns true).
530 */
531
532 void dict_insert(dict_t *dict, dnode_t *node, const void *key)
533 {
534 dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
535 dnode_t *parent = nil, *uncle, *grandpa;
536 int result = -1;
537
538 node->key = key;
539
540 assert (!dict_isfull(dict));
541 assert (!dict_contains(dict, node));
542 assert (!dnode_is_in_a_dict(node));
543
544 /* basic binary tree insert */
545
546 while (where != nil) {
547 parent = where;
548 result = dict->compare(key, where->key);
549 /* trap attempts at duplicate key insertion unless it's explicitly allowed */
550 assert (dict->dupes || result != 0);
551 if (result < 0)
552 where = where->left;
553 else
554 where = where->right;
555 }
556
557 assert (where == nil);
558
559 if (result < 0)
560 parent->left = node;
561 else
562 parent->right = node;
563
564 node->parent = parent;
565 node->left = nil;
566 node->right = nil;
567
568 dict->nodecount++;
569
570 /* red black adjustments */
571
572 node->color = dnode_red;
573
574 while (parent->color == dnode_red) {
575 grandpa = parent->parent;
576 if (parent == grandpa->left) {
577 uncle = grandpa->right;
578 if (uncle->color == dnode_red) { /* red parent, red uncle */
579 parent->color = dnode_black;
580 uncle->color = dnode_black;
581 grandpa->color = dnode_red;
582 node = grandpa;
583 parent = grandpa->parent;
584 } else { /* red parent, black uncle */
585 if (node == parent->right) {
586 rotate_left(parent);
587 parent = node;
588 assert (grandpa == parent->parent);
589 /* rotation between parent and child preserves grandpa */
590 }
591 parent->color = dnode_black;
592 grandpa->color = dnode_red;
593 rotate_right(grandpa);
594 break;
595 }
596 } else { /* symmetric cases: parent == parent->parent->right */
597 uncle = grandpa->left;
598 if (uncle->color == dnode_red) {
599 parent->color = dnode_black;
600 uncle->color = dnode_black;
601 grandpa->color = dnode_red;
602 node = grandpa;
603 parent = grandpa->parent;
604 } else {
605 if (node == parent->left) {
606 rotate_right(parent);
607 parent = node;
608 assert (grandpa == parent->parent);
609 }
610 parent->color = dnode_black;
611 grandpa->color = dnode_red;
612 rotate_left(grandpa);
613 break;
614 }
615 }
616 }
617
618 dict_root(dict)->color = dnode_black;
619
620 assert (dict_verify(dict));
621 }
622
623 /*
624 * Delete the given node from the dictionary. If the given node does not belong
625 * to the given dictionary, undefined behavior results. A pointer to the
626 * deleted node is returned.
627 */
628
629 dnode_t *dict_delete(dict_t *dict, dnode_t *delete)
630 {
631 dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent;
632
633 /* basic deletion */
634
635 assert (!dict_isempty(dict));
636 assert (dict_contains(dict, delete));
637
638 /*
639 * If the node being deleted has two children, then we replace it with its
640 * successor (i.e. the leftmost node in the right subtree.) By doing this,
641 * we avoid the traditional algorithm under which the successor's key and
642 * value *only* move to the deleted node and the successor is spliced out
643 * from the tree. We cannot use this approach because the user may hold
644 * pointers to the successor, or nodes may be inextricably tied to some
645 * other structures by way of embedding, etc. So we must splice out the
646 * node we are given, not some other node, and must not move contents from
647 * one node to another behind the user's back.
648 */
649
650 if (delete->left != nil && delete->right != nil) {
651 dnode_t *next = dict_next(dict, delete);
652 assert (next);
653 dnode_t *nextparent = next->parent;
654 dnode_color_t nextcolor = next->color;
655
656 assert (next != nil);
657 assert (next->parent != nil);
658 assert (next->left == nil);
659
660 /*
661 * First, splice out the successor from the tree completely, by
662 * moving up its right child into its place.
663 */
664
665 child = next->right;
666 child->parent = nextparent;
667
668 if (nextparent->left == next) {
669 nextparent->left = child;
670 } else {
671 assert (nextparent->right == next);
672 nextparent->right = child;
673 }
674
675 /*
676 * Now that the successor has been extricated from the tree, install it
677 * in place of the node that we want deleted.
678 */
679
680 next->parent = delparent;
681 next->left = delete->left;
682 next->right = delete->right;
683 next->left->parent = next;
684 next->right->parent = next;
685 next->color = delete->color;
686 delete->color = nextcolor;
687
688 if (delparent->left == delete) {
689 delparent->left = next;
690 } else {
691 assert (delparent->right == delete);
692 delparent->right = next;
693 }
694
695 } else {
696 assert (delete != nil);
697 assert (delete->left == nil || delete->right == nil);
698
699 child = (delete->left != nil) ? delete->left : delete->right;
700
701 child->parent = delparent = delete->parent;
702
703 if (delete == delparent->left) {
704 delparent->left = child;
705 } else {
706 assert (delete == delparent->right);
707 delparent->right = child;
708 }
709 }
710
711 delete->parent = NULL;
712 delete->right = NULL;
713 delete->left = NULL;
714
715 dict->nodecount--;
716
717 assert (verify_bintree(dict));
718
719 /* red-black adjustments */
720
721 if (delete->color == dnode_black) {
722 dnode_t *parent, *sister;
723
724 dict_root(dict)->color = dnode_red;
725
726 while (child->color == dnode_black) {
727 parent = child->parent;
728 if (child == parent->left) {
729 sister = parent->right;
730 assert (sister != nil);
731 if (sister->color == dnode_red) {
732 sister->color = dnode_black;
733 parent->color = dnode_red;
734 rotate_left(parent);
735 sister = parent->right;
736 assert (sister != nil);
737 }
738 if (sister->left->color == dnode_black
739 && sister->right->color == dnode_black) {
740 sister->color = dnode_red;
741 child = parent;
742 } else {
743 if (sister->right->color == dnode_black) {
744 assert (sister->left->color == dnode_red);
745 sister->left->color = dnode_black;
746 sister->color = dnode_red;
747 rotate_right(sister);
748 sister = parent->right;
749 assert (sister != nil);
750 }
751 sister->color = parent->color;
752 sister->right->color = dnode_black;
753 parent->color = dnode_black;
754 rotate_left(parent);
755 break;
756 }
757 } else { /* symmetric case: child == child->parent->right */
758 assert (child == parent->right);
759 sister = parent->left;
760 assert (sister != nil);
761 if (sister->color == dnode_red) {
762 sister->color = dnode_black;
763 parent->color = dnode_red;
764 rotate_right(parent);
765 sister = parent->left;
766 assert (sister != nil);
767 }
768 if (sister->right->color == dnode_black
769 && sister->left->color == dnode_black) {
770 sister->color = dnode_red;
771 child = parent;
772 } else {
773 if (sister->left->color == dnode_black) {
774 assert (sister->right->color == dnode_red);
775 sister->right->color = dnode_black;
776 sister->color = dnode_red;
777 rotate_left(sister);
778 sister = parent->left;
779 assert (sister != nil);
780 }
781 sister->color = parent->color;
782 sister->left->color = dnode_black;
783 parent->color = dnode_black;
784 rotate_right(parent);
785 break;
786 }
787 }
788 }
789
790 child->color = dnode_black;
791 dict_root(dict)->color = dnode_black;
792 }
793
794 assert (dict_verify(dict));
795
796 return delete;
797 }
798
799 /*
800 * Allocate a node using the dictionary's allocator routine, give it
801 * the data item.
802 */
803
804 int dict_alloc_insert(dict_t *dict, const void *key, void *data)
805 {
806 dnode_t *node = dict->allocnode (dict->context);
807
808 if (node) {
809 dnode_init(node, data);
810 dict_insert(dict, node, key);
811 return 1;
812 }
813 return 0;
814 }
815
816 void dict_delete_free(dict_t *dict, dnode_t *node)
817 {
818 dict_delete(dict, node);
819 dict->freenode(node, dict->context);
820 }
821
822 /*
823 * Return the node with the lowest (leftmost) key. If the dictionary is empty
824 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
825 */
826
827 dnode_t *dict_first(dict_t *dict)
828 {
829 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
830
831 if (root != nil)
832 while ((left = root->left) != nil)
833 root = left;
834
835 return (root == nil) ? NULL : root;
836 }
837
838 /*
839 * Return the node with the highest (rightmost) key. If the dictionary is empty
840 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
841 */
842
843 dnode_t *dict_last(dict_t *dict)
844 {
845 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right;
846
847 if (root != nil)
848 while ((right = root->right) != nil)
849 root = right;
850
851 return (root == nil) ? NULL : root;
852 }
853
854 /*
855 * Return the given node's successor node---the node which has the
856 * next key in the the left to right ordering. If the node has
857 * no successor, a null pointer is returned rather than a pointer to
858 * the nil node.
859 */
860
861 dnode_t *dict_next(dict_t *dict, dnode_t *curr)
862 {
863 dnode_t *nil = dict_nil(dict), *parent, *left;
864
865 if (curr->right != nil) {
866 curr = curr->right;
867 while ((left = curr->left) != nil)
868 curr = left;
869 return curr;
870 }
871
872 parent = curr->parent;
873
874 while (parent != nil && curr == parent->right) {
875 curr = parent;
876 parent = curr->parent;
877 }
878
879 return (parent == nil) ? NULL : parent;
880 }
881
882 /*
883 * Return the given node's predecessor, in the key order.
884 * The nil sentinel node is returned if there is no predecessor.
885 */
886
887 dnode_t *dict_prev(dict_t *dict, dnode_t *curr)
888 {
889 dnode_t *nil = dict_nil(dict), *parent, *right;
890
891 if (curr->left != nil) {
892 curr = curr->left;
893 while ((right = curr->right) != nil)
894 curr = right;
895 return curr;
896 }
897
898 parent = curr->parent;
899
900 while (parent != nil && curr == parent->left) {
901 curr = parent;
902 parent = curr->parent;
903 }
904
905 return (parent == nil) ? NULL : parent;
906 }
907
908 void dict_allow_dupes(dict_t *dict)
909 {
910 dict->dupes = 1;
911 }
912
913 #undef dict_count
914 #undef dict_isempty
915 #undef dict_isfull
916 #undef dnode_get
917 #undef dnode_put
918 #undef dnode_getkey
919
920 dictcount_t dict_count(dict_t *dict)
921 {
922 return dict->nodecount;
923 }
924
925 int dict_isempty(dict_t *dict)
926 {
927 return dict->nodecount == 0;
928 }
929
930 int dict_isfull(dict_t *dict)
931 {
932 return dict->nodecount == dict->maxcount;
933 }
934
935 int dict_contains(dict_t *dict, dnode_t *node)
936 {
937 return verify_dict_has_node(dict_nil(dict), dict_root(dict), node);
938 }
939
940 static dnode_t *dnode_alloc(void *context)
941 {
942 return XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
943 }
944
945 static void dnode_free(dnode_t *node, void *context)
946 {
947 XFREE(MTYPE_ISIS_DICT_NODE, node);
948 }
949
950 dnode_t *dnode_create(void *data)
951 {
952 dnode_t *new = XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
953 if (new) {
954 new->data = data;
955 new->parent = NULL;
956 new->left = NULL;
957 new->right = NULL;
958 }
959 return new;
960 }
961
962 dnode_t *dnode_init(dnode_t *dnode, void *data)
963 {
964 dnode->data = data;
965 dnode->parent = NULL;
966 dnode->left = NULL;
967 dnode->right = NULL;
968 return dnode;
969 }
970
971 void dnode_destroy(dnode_t *dnode)
972 {
973 assert (!dnode_is_in_a_dict(dnode));
974 XFREE(MTYPE_ISIS_DICT_NODE, dnode);
975 }
976
977 void *dnode_get(dnode_t *dnode)
978 {
979 return dnode->data;
980 }
981
982 const void *dnode_getkey(dnode_t *dnode)
983 {
984 return dnode->key;
985 }
986
987 void dnode_put(dnode_t *dnode, void *data)
988 {
989 dnode->data = data;
990 }
991
992 int dnode_is_in_a_dict(dnode_t *dnode)
993 {
994 return (dnode->parent && dnode->left && dnode->right);
995 }
996
997 void dict_process(dict_t *dict, void *context, dnode_process_t function)
998 {
999 dnode_t *node = dict_first(dict), *next;
1000
1001 while (node != NULL) {
1002 /* check for callback function deleting */
1003 /* the next node from under us */
1004 assert (dict_contains(dict, node));
1005 next = dict_next(dict, node);
1006 function(dict, node, context);
1007 node = next;
1008 }
1009 }
1010
1011 static void load_begin_internal(dict_load_t *load, dict_t *dict)
1012 {
1013 load->dictptr = dict;
1014 load->nilnode.left = &load->nilnode;
1015 load->nilnode.right = &load->nilnode;
1016 }
1017
1018 void dict_load_begin(dict_load_t *load, dict_t *dict)
1019 {
1020 assert (dict_isempty(dict));
1021 load_begin_internal(load, dict);
1022 }
1023
1024 void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key)
1025 {
1026 dict_t *dict = load->dictptr;
1027 dnode_t *nil = &load->nilnode;
1028
1029 assert (!dnode_is_in_a_dict(newnode));
1030 assert (dict->nodecount < dict->maxcount);
1031
1032 #ifndef NDEBUG
1033 if (dict->nodecount > 0) {
1034 if (dict->dupes)
1035 assert (dict->compare(nil->left->key, key) <= 0);
1036 else
1037 assert (dict->compare(nil->left->key, key) < 0);
1038 }
1039 #endif
1040
1041 newnode->key = key;
1042 nil->right->left = newnode;
1043 nil->right = newnode;
1044 newnode->left = nil;
1045 dict->nodecount++;
1046 }
1047
1048 void dict_load_end(dict_load_t *load)
1049 {
1050 dict_t *dict = load->dictptr;
1051 dnode_t *tree[DICT_DEPTH_MAX] = { 0 };
1052 dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next;
1053 dnode_t *complete = 0;
1054 dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount;
1055 dictcount_t botrowcount;
1056 unsigned baselevel = 0, level = 0, i;
1057
1058 assert (dnode_red == 0 && dnode_black == 1);
1059
1060 while (fullcount >= nodecount && fullcount)
1061 fullcount >>= 1;
1062
1063 botrowcount = nodecount - fullcount;
1064
1065 for (curr = loadnil->left; curr != loadnil; curr = next) {
1066 next = curr->left;
1067
1068 if (complete == NULL && botrowcount-- == 0) {
1069 assert (baselevel == 0);
1070 assert (level == 0);
1071 baselevel = level = 1;
1072 complete = tree[0];
1073
1074 if (complete != 0) {
1075 tree[0] = 0;
1076 complete->right = dictnil;
1077 while (tree[level] != 0) {
1078 tree[level]->right = complete;
1079 complete->parent = tree[level];
1080 complete = tree[level];
1081 tree[level++] = 0;
1082 }
1083 }
1084 }
1085
1086 if (complete == NULL) {
1087 curr->left = dictnil;
1088 curr->right = dictnil;
1089 curr->color = level % 2;
1090 complete = curr;
1091
1092 assert (level == baselevel);
1093 while (tree[level] != 0) {
1094 tree[level]->right = complete;
1095 complete->parent = tree[level];
1096 complete = tree[level];
1097 tree[level++] = 0;
1098 }
1099 } else {
1100 curr->left = complete;
1101 curr->color = (level + 1) % 2;
1102 complete->parent = curr;
1103 tree[level] = curr;
1104 complete = 0;
1105 level = baselevel;
1106 }
1107 }
1108
1109 if (complete == NULL)
1110 complete = dictnil;
1111
1112 for (i = 0; i < DICT_DEPTH_MAX; i++) {
1113 if (tree[i] != 0) {
1114 tree[i]->right = complete;
1115 complete->parent = tree[i];
1116 complete = tree[i];
1117 }
1118 }
1119
1120 dictnil->color = dnode_black;
1121 dictnil->right = dictnil;
1122 complete->parent = dictnil;
1123 complete->color = dnode_black;
1124 dict_root(dict) = complete;
1125
1126 assert (dict_verify(dict));
1127 }
1128
1129 void dict_merge(dict_t *dest, dict_t *source)
1130 {
1131 dict_load_t load;
1132 dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source);
1133
1134 assert (dict_similar(dest, source));
1135
1136 if (source == dest)
1137 return;
1138
1139 dest->nodecount = 0;
1140 load_begin_internal(&load, dest);
1141
1142 for (;;) {
1143 if (leftnode != NULL && rightnode != NULL) {
1144 if (dest->compare(leftnode->key, rightnode->key) < 0)
1145 goto copyleft;
1146 else
1147 goto copyright;
1148 } else if (leftnode != NULL) {
1149 goto copyleft;
1150 } else if (rightnode != NULL) {
1151 goto copyright;
1152 } else {
1153 assert (leftnode == NULL && rightnode == NULL);
1154 break;
1155 }
1156
1157 copyleft:
1158 {
1159 dnode_t *next = dict_next(dest, leftnode);
1160 #ifndef NDEBUG
1161 leftnode->left = NULL; /* suppress assertion in dict_load_next */
1162 #endif
1163 dict_load_next(&load, leftnode, leftnode->key);
1164 leftnode = next;
1165 continue;
1166 }
1167
1168 copyright:
1169 {
1170 dnode_t *next = dict_next(source, rightnode);
1171 #ifndef NDEBUG
1172 rightnode->left = NULL;
1173 #endif
1174 dict_load_next(&load, rightnode, rightnode->key);
1175 rightnode = next;
1176 continue;
1177 }
1178 }
1179
1180 dict_clear(source);
1181 dict_load_end(&load);
1182 }
1183
1184 #ifdef KAZLIB_TEST_MAIN
1185
1186 #include <stdio.h>
1187 #include <string.h>
1188 #include <ctype.h>
1189 #include <stdarg.h>
1190
1191 typedef char input_t[256];
1192
1193 static int tokenize(char *string, ...)
1194 {
1195 char **tokptr;
1196 va_list arglist;
1197 int tokcount = 0;
1198
1199 va_start(arglist, string);
1200 tokptr = va_arg(arglist, char **);
1201 while (tokptr) {
1202 while (*string && isspace((unsigned char) *string))
1203 string++;
1204 if (!*string)
1205 break;
1206 *tokptr = string;
1207 while (*string && !isspace((unsigned char) *string))
1208 string++;
1209 tokptr = va_arg(arglist, char **);
1210 tokcount++;
1211 if (!*string)
1212 break;
1213 *string++ = 0;
1214 }
1215 va_end(arglist);
1216
1217 return tokcount;
1218 }
1219
1220 static int comparef(const void *key1, const void *key2)
1221 {
1222 return strcmp(key1, key2);
1223 }
1224
1225 static char *dupstring(char *str)
1226 {
1227 int sz = strlen(str) + 1;
1228 char *new = XCALLOC(MTYPE_ISIS_TMP, sz);
1229 if (new)
1230 memcpy(new, str, sz);
1231 return new;
1232 }
1233
1234 static dnode_t *new_node(void *c)
1235 {
1236 static dnode_t few[5];
1237 static int count;
1238
1239 if (count < 5)
1240 return few + count++;
1241
1242 return NULL;
1243 }
1244
1245 static void del_node(dnode_t *n, void *c)
1246 {
1247 }
1248
1249 static int prompt = 0;
1250
1251 static void construct(dict_t *d)
1252 {
1253 input_t in;
1254 int done = 0;
1255 dict_load_t dl;
1256 dnode_t *dn;
1257 char *tok1, *tok2, *val;
1258 const char *key;
1259 char *help =
1260 "p turn prompt on\n"
1261 "q finish construction\n"
1262 "a <key> <val> add new entry\n";
1263
1264 if (!dict_isempty(d))
1265 puts("warning: dictionary not empty!");
1266
1267 dict_load_begin(&dl, d);
1268
1269 while (!done) {
1270 if (prompt)
1271 putchar('>');
1272 fflush(stdout);
1273
1274 if (!fgets(in, sizeof(input_t), stdin))
1275 break;
1276
1277 switch (in[0]) {
1278 case '?':
1279 puts(help);
1280 break;
1281 case 'p':
1282 prompt = 1;
1283 break;
1284 case 'q':
1285 done = 1;
1286 break;
1287 case 'a':
1288 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1289 puts("what?");
1290 break;
1291 }
1292 key = dupstring(tok1);
1293 val = dupstring(tok2);
1294 dn = dnode_create(val);
1295
1296 if (!key || !val || !dn) {
1297 puts("out of memory");
1298 free((void *) key);
1299 free(val);
1300 if (dn)
1301 dnode_destroy(dn);
1302 }
1303
1304 dict_load_next(&dl, dn, key);
1305 break;
1306 default:
1307 putchar('?');
1308 putchar('\n');
1309 break;
1310 }
1311 }
1312
1313 dict_load_end(&dl);
1314 }
1315
1316 int main(void)
1317 {
1318 input_t in;
1319 dict_t darray[10];
1320 dict_t *d = &darray[0];
1321 dnode_t *dn;
1322 int i;
1323 char *tok1, *tok2, *val;
1324 const char *key;
1325
1326 char *help =
1327 "a <key> <val> add value to dictionary\n"
1328 "d <key> delete value from dictionary\n"
1329 "l <key> lookup value in dictionary\n"
1330 "( <key> lookup lower bound\n"
1331 ") <key> lookup upper bound\n"
1332 "# <num> switch to alternate dictionary (0-9)\n"
1333 "j <num> <num> merge two dictionaries\n"
1334 "f free the whole dictionary\n"
1335 "k allow duplicate keys\n"
1336 "c show number of entries\n"
1337 "t dump whole dictionary in sort order\n"
1338 "m make dictionary out of sorted items\n"
1339 "p turn prompt on\n"
1340 "s switch to non-functioning allocator\n"
1341 "q quit";
1342
1343 for (i = 0; i < 10; i++)
1344 dict_init(&darray[i], DICTCOUNT_T_MAX, comparef);
1345
1346 for (;;) {
1347 if (prompt)
1348 putchar('>');
1349 fflush(stdout);
1350
1351 if (!fgets(in, sizeof(input_t), stdin))
1352 break;
1353
1354 switch(in[0]) {
1355 case '?':
1356 puts(help);
1357 break;
1358 case 'a':
1359 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1360 puts("what?");
1361 break;
1362 }
1363 key = dupstring(tok1);
1364 val = dupstring(tok2);
1365
1366 if (!key || !val) {
1367 puts("out of memory");
1368 free((void *) key);
1369 free(val);
1370 }
1371
1372 if (!dict_alloc_insert(d, key, val)) {
1373 puts("dict_alloc_insert failed");
1374 free((void *) key);
1375 free(val);
1376 break;
1377 }
1378 break;
1379 case 'd':
1380 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1381 puts("what?");
1382 break;
1383 }
1384 dn = dict_lookup(d, tok1);
1385 if (!dn) {
1386 puts("dict_lookup failed");
1387 break;
1388 }
1389 val = dnode_get(dn);
1390 key = dnode_getkey(dn);
1391 dict_delete_free(d, dn);
1392
1393 free(val);
1394 free((void *) key);
1395 break;
1396 case 'f':
1397 dict_free(d);
1398 break;
1399 case 'l':
1400 case '(':
1401 case ')':
1402 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1403 puts("what?");
1404 break;
1405 }
1406 dn = 0;
1407 switch (in[0]) {
1408 case 'l':
1409 dn = dict_lookup(d, tok1);
1410 break;
1411 case '(':
1412 dn = dict_lower_bound(d, tok1);
1413 break;
1414 case ')':
1415 dn = dict_upper_bound(d, tok1);
1416 break;
1417 }
1418 if (!dn) {
1419 puts("lookup failed");
1420 break;
1421 }
1422 val = dnode_get(dn);
1423 puts(val);
1424 break;
1425 case 'm':
1426 construct(d);
1427 break;
1428 case 'k':
1429 dict_allow_dupes(d);
1430 break;
1431 case 'c':
1432 printf("%lu\n", (unsigned long) dict_count(d));
1433 break;
1434 case 't':
1435 for (dn = dict_first(d); dn; dn = dict_next(d, dn)) {
1436 printf("%s\t%s\n", (char *) dnode_getkey(dn),
1437 (char *) dnode_get(dn));
1438 }
1439 break;
1440 case 'q':
1441 exit(0);
1442 break;
1443 case '\0':
1444 break;
1445 case 'p':
1446 prompt = 1;
1447 break;
1448 case 's':
1449 dict_set_allocator(d, new_node, del_node, NULL);
1450 break;
1451 case '#':
1452 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1453 puts("what?");
1454 break;
1455 } else {
1456 int dictnum = atoi(tok1);
1457 if (dictnum < 0 || dictnum > 9) {
1458 puts("invalid number");
1459 break;
1460 }
1461 d = &darray[dictnum];
1462 }
1463 break;
1464 case 'j':
1465 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1466 puts("what?");
1467 break;
1468 } else {
1469 int dict1 = atoi(tok1), dict2 = atoi(tok2);
1470 if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) {
1471 puts("invalid number");
1472 break;
1473 }
1474 dict_merge(&darray[dict1], &darray[dict2]);
1475 }
1476 break;
1477 default:
1478 putchar('?');
1479 putchar('\n');
1480 break;
1481 }
1482 }
1483
1484 return 0;
1485 }
1486
1487 #endif