]> git.proxmox.com Git - mirror_frr.git/blob - isisd/dict.c
Merge remote-tracking branch 'origin/cmaster' into cmaster-next
[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 dnode_t *nextparent = next->parent;
653 dnode_color_t nextcolor = next->color;
654
655 assert (next != nil);
656 assert (next->parent != nil);
657 assert (next->left == nil);
658
659 /*
660 * First, splice out the successor from the tree completely, by
661 * moving up its right child into its place.
662 */
663
664 child = next->right;
665 child->parent = nextparent;
666
667 if (nextparent->left == next) {
668 nextparent->left = child;
669 } else {
670 assert (nextparent->right == next);
671 nextparent->right = child;
672 }
673
674 /*
675 * Now that the successor has been extricated from the tree, install it
676 * in place of the node that we want deleted.
677 */
678
679 next->parent = delparent;
680 next->left = delete->left;
681 next->right = delete->right;
682 next->left->parent = next;
683 next->right->parent = next;
684 next->color = delete->color;
685 delete->color = nextcolor;
686
687 if (delparent->left == delete) {
688 delparent->left = next;
689 } else {
690 assert (delparent->right == delete);
691 delparent->right = next;
692 }
693
694 } else {
695 assert (delete != nil);
696 assert (delete->left == nil || delete->right == nil);
697
698 child = (delete->left != nil) ? delete->left : delete->right;
699
700 child->parent = delparent = delete->parent;
701
702 if (delete == delparent->left) {
703 delparent->left = child;
704 } else {
705 assert (delete == delparent->right);
706 delparent->right = child;
707 }
708 }
709
710 delete->parent = NULL;
711 delete->right = NULL;
712 delete->left = NULL;
713
714 dict->nodecount--;
715
716 assert (verify_bintree(dict));
717
718 /* red-black adjustments */
719
720 if (delete->color == dnode_black) {
721 dnode_t *parent, *sister;
722
723 dict_root(dict)->color = dnode_red;
724
725 while (child->color == dnode_black) {
726 parent = child->parent;
727 if (child == parent->left) {
728 sister = parent->right;
729 assert (sister != nil);
730 if (sister->color == dnode_red) {
731 sister->color = dnode_black;
732 parent->color = dnode_red;
733 rotate_left(parent);
734 sister = parent->right;
735 assert (sister != nil);
736 }
737 if (sister->left->color == dnode_black
738 && sister->right->color == dnode_black) {
739 sister->color = dnode_red;
740 child = parent;
741 } else {
742 if (sister->right->color == dnode_black) {
743 assert (sister->left->color == dnode_red);
744 sister->left->color = dnode_black;
745 sister->color = dnode_red;
746 rotate_right(sister);
747 sister = parent->right;
748 assert (sister != nil);
749 }
750 sister->color = parent->color;
751 sister->right->color = dnode_black;
752 parent->color = dnode_black;
753 rotate_left(parent);
754 break;
755 }
756 } else { /* symmetric case: child == child->parent->right */
757 assert (child == parent->right);
758 sister = parent->left;
759 assert (sister != nil);
760 if (sister->color == dnode_red) {
761 sister->color = dnode_black;
762 parent->color = dnode_red;
763 rotate_right(parent);
764 sister = parent->left;
765 assert (sister != nil);
766 }
767 if (sister->right->color == dnode_black
768 && sister->left->color == dnode_black) {
769 sister->color = dnode_red;
770 child = parent;
771 } else {
772 if (sister->left->color == dnode_black) {
773 assert (sister->right->color == dnode_red);
774 sister->right->color = dnode_black;
775 sister->color = dnode_red;
776 rotate_left(sister);
777 sister = parent->left;
778 assert (sister != nil);
779 }
780 sister->color = parent->color;
781 sister->left->color = dnode_black;
782 parent->color = dnode_black;
783 rotate_right(parent);
784 break;
785 }
786 }
787 }
788
789 child->color = dnode_black;
790 dict_root(dict)->color = dnode_black;
791 }
792
793 assert (dict_verify(dict));
794
795 return delete;
796 }
797
798 /*
799 * Allocate a node using the dictionary's allocator routine, give it
800 * the data item.
801 */
802
803 int dict_alloc_insert(dict_t *dict, const void *key, void *data)
804 {
805 dnode_t *node = dict->allocnode (dict->context);
806
807 if (node) {
808 dnode_init(node, data);
809 dict_insert(dict, node, key);
810 return 1;
811 }
812 return 0;
813 }
814
815 void dict_delete_free(dict_t *dict, dnode_t *node)
816 {
817 dict_delete(dict, node);
818 dict->freenode(node, dict->context);
819 }
820
821 /*
822 * Return the node with the lowest (leftmost) key. If the dictionary is empty
823 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
824 */
825
826 dnode_t *dict_first(dict_t *dict)
827 {
828 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
829
830 if (root != nil)
831 while ((left = root->left) != nil)
832 root = left;
833
834 return (root == nil) ? NULL : root;
835 }
836
837 /*
838 * Return the node with the highest (rightmost) key. If the dictionary is empty
839 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
840 */
841
842 dnode_t *dict_last(dict_t *dict)
843 {
844 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right;
845
846 if (root != nil)
847 while ((right = root->right) != nil)
848 root = right;
849
850 return (root == nil) ? NULL : root;
851 }
852
853 /*
854 * Return the given node's successor node---the node which has the
855 * next key in the the left to right ordering. If the node has
856 * no successor, a null pointer is returned rather than a pointer to
857 * the nil node.
858 */
859
860 dnode_t *dict_next(dict_t *dict, dnode_t *curr)
861 {
862 dnode_t *nil = dict_nil(dict), *parent, *left;
863
864 if (curr->right != nil) {
865 curr = curr->right;
866 while ((left = curr->left) != nil)
867 curr = left;
868 return curr;
869 }
870
871 parent = curr->parent;
872
873 while (parent != nil && curr == parent->right) {
874 curr = parent;
875 parent = curr->parent;
876 }
877
878 return (parent == nil) ? NULL : parent;
879 }
880
881 /*
882 * Return the given node's predecessor, in the key order.
883 * The nil sentinel node is returned if there is no predecessor.
884 */
885
886 dnode_t *dict_prev(dict_t *dict, dnode_t *curr)
887 {
888 dnode_t *nil = dict_nil(dict), *parent, *right;
889
890 if (curr->left != nil) {
891 curr = curr->left;
892 while ((right = curr->right) != nil)
893 curr = right;
894 return curr;
895 }
896
897 parent = curr->parent;
898
899 while (parent != nil && curr == parent->left) {
900 curr = parent;
901 parent = curr->parent;
902 }
903
904 return (parent == nil) ? NULL : parent;
905 }
906
907 void dict_allow_dupes(dict_t *dict)
908 {
909 dict->dupes = 1;
910 }
911
912 #undef dict_count
913 #undef dict_isempty
914 #undef dict_isfull
915 #undef dnode_get
916 #undef dnode_put
917 #undef dnode_getkey
918
919 dictcount_t dict_count(dict_t *dict)
920 {
921 return dict->nodecount;
922 }
923
924 int dict_isempty(dict_t *dict)
925 {
926 return dict->nodecount == 0;
927 }
928
929 int dict_isfull(dict_t *dict)
930 {
931 return dict->nodecount == dict->maxcount;
932 }
933
934 int dict_contains(dict_t *dict, dnode_t *node)
935 {
936 return verify_dict_has_node(dict_nil(dict), dict_root(dict), node);
937 }
938
939 static dnode_t *dnode_alloc(void *context)
940 {
941 return XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
942 }
943
944 static void dnode_free(dnode_t *node, void *context)
945 {
946 XFREE(MTYPE_ISIS_DICT_NODE, node);
947 }
948
949 dnode_t *dnode_create(void *data)
950 {
951 dnode_t *new = XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
952 if (new) {
953 new->data = data;
954 new->parent = NULL;
955 new->left = NULL;
956 new->right = NULL;
957 }
958 return new;
959 }
960
961 dnode_t *dnode_init(dnode_t *dnode, void *data)
962 {
963 dnode->data = data;
964 dnode->parent = NULL;
965 dnode->left = NULL;
966 dnode->right = NULL;
967 return dnode;
968 }
969
970 void dnode_destroy(dnode_t *dnode)
971 {
972 assert (!dnode_is_in_a_dict(dnode));
973 XFREE(MTYPE_ISIS_DICT_NODE, dnode);
974 }
975
976 void *dnode_get(dnode_t *dnode)
977 {
978 return dnode->data;
979 }
980
981 const void *dnode_getkey(dnode_t *dnode)
982 {
983 return dnode->key;
984 }
985
986 void dnode_put(dnode_t *dnode, void *data)
987 {
988 dnode->data = data;
989 }
990
991 int dnode_is_in_a_dict(dnode_t *dnode)
992 {
993 return (dnode->parent && dnode->left && dnode->right);
994 }
995
996 void dict_process(dict_t *dict, void *context, dnode_process_t function)
997 {
998 dnode_t *node = dict_first(dict), *next;
999
1000 while (node != NULL) {
1001 /* check for callback function deleting */
1002 /* the next node from under us */
1003 assert (dict_contains(dict, node));
1004 next = dict_next(dict, node);
1005 function(dict, node, context);
1006 node = next;
1007 }
1008 }
1009
1010 static void load_begin_internal(dict_load_t *load, dict_t *dict)
1011 {
1012 load->dictptr = dict;
1013 load->nilnode.left = &load->nilnode;
1014 load->nilnode.right = &load->nilnode;
1015 }
1016
1017 void dict_load_begin(dict_load_t *load, dict_t *dict)
1018 {
1019 assert (dict_isempty(dict));
1020 load_begin_internal(load, dict);
1021 }
1022
1023 void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key)
1024 {
1025 dict_t *dict = load->dictptr;
1026 dnode_t *nil = &load->nilnode;
1027
1028 assert (!dnode_is_in_a_dict(newnode));
1029 assert (dict->nodecount < dict->maxcount);
1030
1031 #ifndef NDEBUG
1032 if (dict->nodecount > 0) {
1033 if (dict->dupes)
1034 assert (dict->compare(nil->left->key, key) <= 0);
1035 else
1036 assert (dict->compare(nil->left->key, key) < 0);
1037 }
1038 #endif
1039
1040 newnode->key = key;
1041 nil->right->left = newnode;
1042 nil->right = newnode;
1043 newnode->left = nil;
1044 dict->nodecount++;
1045 }
1046
1047 void dict_load_end(dict_load_t *load)
1048 {
1049 dict_t *dict = load->dictptr;
1050 dnode_t *tree[DICT_DEPTH_MAX] = { 0 };
1051 dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next;
1052 dnode_t *complete = 0;
1053 dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount;
1054 dictcount_t botrowcount;
1055 unsigned baselevel = 0, level = 0, i;
1056
1057 assert (dnode_red == 0 && dnode_black == 1);
1058
1059 while (fullcount >= nodecount && fullcount)
1060 fullcount >>= 1;
1061
1062 botrowcount = nodecount - fullcount;
1063
1064 for (curr = loadnil->left; curr != loadnil; curr = next) {
1065 next = curr->left;
1066
1067 if (complete == NULL && botrowcount-- == 0) {
1068 assert (baselevel == 0);
1069 assert (level == 0);
1070 baselevel = level = 1;
1071 complete = tree[0];
1072
1073 if (complete != 0) {
1074 tree[0] = 0;
1075 complete->right = dictnil;
1076 while (tree[level] != 0) {
1077 tree[level]->right = complete;
1078 complete->parent = tree[level];
1079 complete = tree[level];
1080 tree[level++] = 0;
1081 }
1082 }
1083 }
1084
1085 if (complete == NULL) {
1086 curr->left = dictnil;
1087 curr->right = dictnil;
1088 curr->color = level % 2;
1089 complete = curr;
1090
1091 assert (level == baselevel);
1092 while (tree[level] != 0) {
1093 tree[level]->right = complete;
1094 complete->parent = tree[level];
1095 complete = tree[level];
1096 tree[level++] = 0;
1097 }
1098 } else {
1099 curr->left = complete;
1100 curr->color = (level + 1) % 2;
1101 complete->parent = curr;
1102 tree[level] = curr;
1103 complete = 0;
1104 level = baselevel;
1105 }
1106 }
1107
1108 if (complete == NULL)
1109 complete = dictnil;
1110
1111 for (i = 0; i < DICT_DEPTH_MAX; i++) {
1112 if (tree[i] != 0) {
1113 tree[i]->right = complete;
1114 complete->parent = tree[i];
1115 complete = tree[i];
1116 }
1117 }
1118
1119 dictnil->color = dnode_black;
1120 dictnil->right = dictnil;
1121 complete->parent = dictnil;
1122 complete->color = dnode_black;
1123 dict_root(dict) = complete;
1124
1125 assert (dict_verify(dict));
1126 }
1127
1128 void dict_merge(dict_t *dest, dict_t *source)
1129 {
1130 dict_load_t load;
1131 dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source);
1132
1133 assert (dict_similar(dest, source));
1134
1135 if (source == dest)
1136 return;
1137
1138 dest->nodecount = 0;
1139 load_begin_internal(&load, dest);
1140
1141 for (;;) {
1142 if (leftnode != NULL && rightnode != NULL) {
1143 if (dest->compare(leftnode->key, rightnode->key) < 0)
1144 goto copyleft;
1145 else
1146 goto copyright;
1147 } else if (leftnode != NULL) {
1148 goto copyleft;
1149 } else if (rightnode != NULL) {
1150 goto copyright;
1151 } else {
1152 assert (leftnode == NULL && rightnode == NULL);
1153 break;
1154 }
1155
1156 copyleft:
1157 {
1158 dnode_t *next = dict_next(dest, leftnode);
1159 #ifndef NDEBUG
1160 leftnode->left = NULL; /* suppress assertion in dict_load_next */
1161 #endif
1162 dict_load_next(&load, leftnode, leftnode->key);
1163 leftnode = next;
1164 continue;
1165 }
1166
1167 copyright:
1168 {
1169 dnode_t *next = dict_next(source, rightnode);
1170 #ifndef NDEBUG
1171 rightnode->left = NULL;
1172 #endif
1173 dict_load_next(&load, rightnode, rightnode->key);
1174 rightnode = next;
1175 continue;
1176 }
1177 }
1178
1179 dict_clear(source);
1180 dict_load_end(&load);
1181 }
1182
1183 #ifdef KAZLIB_TEST_MAIN
1184
1185 #include <stdio.h>
1186 #include <string.h>
1187 #include <ctype.h>
1188 #include <stdarg.h>
1189
1190 typedef char input_t[256];
1191
1192 static int tokenize(char *string, ...)
1193 {
1194 char **tokptr;
1195 va_list arglist;
1196 int tokcount = 0;
1197
1198 va_start(arglist, string);
1199 tokptr = va_arg(arglist, char **);
1200 while (tokptr) {
1201 while (*string && isspace((unsigned char) *string))
1202 string++;
1203 if (!*string)
1204 break;
1205 *tokptr = string;
1206 while (*string && !isspace((unsigned char) *string))
1207 string++;
1208 tokptr = va_arg(arglist, char **);
1209 tokcount++;
1210 if (!*string)
1211 break;
1212 *string++ = 0;
1213 }
1214 va_end(arglist);
1215
1216 return tokcount;
1217 }
1218
1219 static int comparef(const void *key1, const void *key2)
1220 {
1221 return strcmp(key1, key2);
1222 }
1223
1224 static char *dupstring(char *str)
1225 {
1226 int sz = strlen(str) + 1;
1227 char *new = XCALLOC(MTYPE_ISIS_TMP, sz);
1228 if (new)
1229 memcpy(new, str, sz);
1230 return new;
1231 }
1232
1233 static dnode_t *new_node(void *c)
1234 {
1235 static dnode_t few[5];
1236 static int count;
1237
1238 if (count < 5)
1239 return few + count++;
1240
1241 return NULL;
1242 }
1243
1244 static void del_node(dnode_t *n, void *c)
1245 {
1246 }
1247
1248 static int prompt = 0;
1249
1250 static void construct(dict_t *d)
1251 {
1252 input_t in;
1253 int done = 0;
1254 dict_load_t dl;
1255 dnode_t *dn;
1256 char *tok1, *tok2, *val;
1257 const char *key;
1258 char *help =
1259 "p turn prompt on\n"
1260 "q finish construction\n"
1261 "a <key> <val> add new entry\n";
1262
1263 if (!dict_isempty(d))
1264 puts("warning: dictionary not empty!");
1265
1266 dict_load_begin(&dl, d);
1267
1268 while (!done) {
1269 if (prompt)
1270 putchar('>');
1271 fflush(stdout);
1272
1273 if (!fgets(in, sizeof(input_t), stdin))
1274 break;
1275
1276 switch (in[0]) {
1277 case '?':
1278 puts(help);
1279 break;
1280 case 'p':
1281 prompt = 1;
1282 break;
1283 case 'q':
1284 done = 1;
1285 break;
1286 case 'a':
1287 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1288 puts("what?");
1289 break;
1290 }
1291 key = dupstring(tok1);
1292 val = dupstring(tok2);
1293 dn = dnode_create(val);
1294
1295 if (!key || !val || !dn) {
1296 puts("out of memory");
1297 free((void *) key);
1298 free(val);
1299 if (dn)
1300 dnode_destroy(dn);
1301 }
1302
1303 dict_load_next(&dl, dn, key);
1304 break;
1305 default:
1306 putchar('?');
1307 putchar('\n');
1308 break;
1309 }
1310 }
1311
1312 dict_load_end(&dl);
1313 }
1314
1315 int main(void)
1316 {
1317 input_t in;
1318 dict_t darray[10];
1319 dict_t *d = &darray[0];
1320 dnode_t *dn;
1321 int i;
1322 char *tok1, *tok2, *val;
1323 const char *key;
1324
1325 char *help =
1326 "a <key> <val> add value to dictionary\n"
1327 "d <key> delete value from dictionary\n"
1328 "l <key> lookup value in dictionary\n"
1329 "( <key> lookup lower bound\n"
1330 ") <key> lookup upper bound\n"
1331 "# <num> switch to alternate dictionary (0-9)\n"
1332 "j <num> <num> merge two dictionaries\n"
1333 "f free the whole dictionary\n"
1334 "k allow duplicate keys\n"
1335 "c show number of entries\n"
1336 "t dump whole dictionary in sort order\n"
1337 "m make dictionary out of sorted items\n"
1338 "p turn prompt on\n"
1339 "s switch to non-functioning allocator\n"
1340 "q quit";
1341
1342 for (i = 0; i < 10; i++)
1343 dict_init(&darray[i], DICTCOUNT_T_MAX, comparef);
1344
1345 for (;;) {
1346 if (prompt)
1347 putchar('>');
1348 fflush(stdout);
1349
1350 if (!fgets(in, sizeof(input_t), stdin))
1351 break;
1352
1353 switch(in[0]) {
1354 case '?':
1355 puts(help);
1356 break;
1357 case 'a':
1358 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1359 puts("what?");
1360 break;
1361 }
1362 key = dupstring(tok1);
1363 val = dupstring(tok2);
1364
1365 if (!key || !val) {
1366 puts("out of memory");
1367 free((void *) key);
1368 free(val);
1369 }
1370
1371 if (!dict_alloc_insert(d, key, val)) {
1372 puts("dict_alloc_insert failed");
1373 free((void *) key);
1374 free(val);
1375 break;
1376 }
1377 break;
1378 case 'd':
1379 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1380 puts("what?");
1381 break;
1382 }
1383 dn = dict_lookup(d, tok1);
1384 if (!dn) {
1385 puts("dict_lookup failed");
1386 break;
1387 }
1388 val = dnode_get(dn);
1389 key = dnode_getkey(dn);
1390 dict_delete_free(d, dn);
1391
1392 free(val);
1393 free((void *) key);
1394 break;
1395 case 'f':
1396 dict_free(d);
1397 break;
1398 case 'l':
1399 case '(':
1400 case ')':
1401 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1402 puts("what?");
1403 break;
1404 }
1405 dn = 0;
1406 switch (in[0]) {
1407 case 'l':
1408 dn = dict_lookup(d, tok1);
1409 break;
1410 case '(':
1411 dn = dict_lower_bound(d, tok1);
1412 break;
1413 case ')':
1414 dn = dict_upper_bound(d, tok1);
1415 break;
1416 }
1417 if (!dn) {
1418 puts("lookup failed");
1419 break;
1420 }
1421 val = dnode_get(dn);
1422 puts(val);
1423 break;
1424 case 'm':
1425 construct(d);
1426 break;
1427 case 'k':
1428 dict_allow_dupes(d);
1429 break;
1430 case 'c':
1431 printf("%lu\n", (unsigned long) dict_count(d));
1432 break;
1433 case 't':
1434 for (dn = dict_first(d); dn; dn = dict_next(d, dn)) {
1435 printf("%s\t%s\n", (char *) dnode_getkey(dn),
1436 (char *) dnode_get(dn));
1437 }
1438 break;
1439 case 'q':
1440 exit(0);
1441 break;
1442 case '\0':
1443 break;
1444 case 'p':
1445 prompt = 1;
1446 break;
1447 case 's':
1448 dict_set_allocator(d, new_node, del_node, NULL);
1449 break;
1450 case '#':
1451 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1452 puts("what?");
1453 break;
1454 } else {
1455 int dictnum = atoi(tok1);
1456 if (dictnum < 0 || dictnum > 9) {
1457 puts("invalid number");
1458 break;
1459 }
1460 d = &darray[dictnum];
1461 }
1462 break;
1463 case 'j':
1464 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1465 puts("what?");
1466 break;
1467 } else {
1468 int dict1 = atoi(tok1), dict2 = atoi(tok2);
1469 if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) {
1470 puts("invalid number");
1471 break;
1472 }
1473 dict_merge(&darray[dict1], &darray[dict2]);
1474 }
1475 break;
1476 default:
1477 putchar('?');
1478 putchar('\n');
1479 break;
1480 }
1481 }
1482
1483 return 0;
1484 }
1485
1486 #endif