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