blob: 35cb924ca6dd766d7e0fef31452b62a437264962 [file] [log] [blame]
jardineb5d44e2003-12-23 08:09:43 +00001/*
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 *
Paul Jakma238497f2007-08-07 18:49:18 +000017 * $Id$
18 * $Name$
jardineb5d44e2003-12-23 08:09:43 +000019 */
20
Paul Jakma238497f2007-08-07 18:49:18 +000021#include "zebra.h"
ajscee3df12004-11-24 17:14:49 +000022#include "zassert.h"
Josh Bailey3f045a02012-03-24 08:35:20 -070023#include "memory.h"
jardineb5d44e2003-12-23 08:09:43 +000024#include "dict.h"
25
jardineb5d44e2003-12-23 08:09:43 +000026/*
27 * These macros provide short convenient names for structure members,
28 * which are embellished with dict_ prefixes so that they are
29 * properly confined to the documented namespace. It's legal for a
30 * program which uses dict to define, for instance, a macro called ``parent''.
31 * Such a macro would interfere with the dnode_t struct definition.
32 * In general, highly portable and reusable C modules which expose their
33 * structures need to confine structure member names to well-defined spaces.
34 * The resulting identifiers aren't necessarily convenient to use, nor
35 * readable, in the implementation, however!
36 */
37
38#define left dict_left
39#define right dict_right
40#define parent dict_parent
41#define color dict_color
42#define key dict_key
43#define data dict_data
44
45#define nilnode dict_nilnode
46#define nodecount dict_nodecount
47#define maxcount dict_maxcount
48#define compare dict_compare
49#define allocnode dict_allocnode
50#define freenode dict_freenode
51#define context dict_context
52#define dupes dict_dupes
53
54#define dictptr dict_dictptr
55
56#define dict_root(D) ((D)->nilnode.left)
57#define dict_nil(D) (&(D)->nilnode)
58#define DICT_DEPTH_MAX 64
59
hassoffe543a2005-09-25 12:04:25 +000060static dnode_t *dnode_alloc(void *context);
61static void dnode_free(dnode_t *node, void *context);
jardineb5d44e2003-12-23 08:09:43 +000062
63/*
64 * Perform a ``left rotation'' adjustment on the tree. The given node P and
65 * its right child C are rearranged so that the P instead becomes the left
66 * child of C. The left subtree of C is inherited as the new right subtree
67 * for P. The ordering of the keys within the tree is thus preserved.
68 */
69
hassoffe543a2005-09-25 12:04:25 +000070static void rotate_left(dnode_t *upper)
jardineb5d44e2003-12-23 08:09:43 +000071{
hassoffe543a2005-09-25 12:04:25 +000072 dnode_t *lower, *lowleft, *upparent;
jardineb5d44e2003-12-23 08:09:43 +000073
hassoffe543a2005-09-25 12:04:25 +000074 lower = upper->right;
75 upper->right = lowleft = lower->left;
76 lowleft->parent = upper;
jardineb5d44e2003-12-23 08:09:43 +000077
hassoffe543a2005-09-25 12:04:25 +000078 lower->parent = upparent = upper->parent;
jardineb5d44e2003-12-23 08:09:43 +000079
hassoffe543a2005-09-25 12:04:25 +000080 /* don't need to check for root node here because root->parent is
81 the sentinel nil node, and root->parent->left points back to root */
jardineb5d44e2003-12-23 08:09:43 +000082
hassoffe543a2005-09-25 12:04:25 +000083 if (upper == upparent->left) {
84 upparent->left = lower;
85 } else {
86 assert (upper == upparent->right);
87 upparent->right = lower;
jardineb5d44e2003-12-23 08:09:43 +000088 }
89
hassoffe543a2005-09-25 12:04:25 +000090 lower->left = upper;
91 upper->parent = lower;
jardineb5d44e2003-12-23 08:09:43 +000092}
93
94/*
95 * This operation is the ``mirror'' image of rotate_left. It is
96 * the same procedure, but with left and right interchanged.
97 */
98
hassoffe543a2005-09-25 12:04:25 +000099static void rotate_right(dnode_t *upper)
jardineb5d44e2003-12-23 08:09:43 +0000100{
hassoffe543a2005-09-25 12:04:25 +0000101 dnode_t *lower, *lowright, *upparent;
jardineb5d44e2003-12-23 08:09:43 +0000102
hassoffe543a2005-09-25 12:04:25 +0000103 lower = upper->left;
104 upper->left = lowright = lower->right;
105 lowright->parent = upper;
jardineb5d44e2003-12-23 08:09:43 +0000106
hassoffe543a2005-09-25 12:04:25 +0000107 lower->parent = upparent = upper->parent;
jardineb5d44e2003-12-23 08:09:43 +0000108
hassoffe543a2005-09-25 12:04:25 +0000109 if (upper == upparent->right) {
110 upparent->right = lower;
111 } else {
112 assert (upper == upparent->left);
113 upparent->left = lower;
jardineb5d44e2003-12-23 08:09:43 +0000114 }
115
hassoffe543a2005-09-25 12:04:25 +0000116 lower->right = upper;
117 upper->parent = lower;
jardineb5d44e2003-12-23 08:09:43 +0000118}
119
120/*
121 * Do a postorder traversal of the tree rooted at the specified
122 * node and free everything under it. Used by dict_free().
123 */
124
hassoffe543a2005-09-25 12:04:25 +0000125static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
jardineb5d44e2003-12-23 08:09:43 +0000126{
hassoffe543a2005-09-25 12:04:25 +0000127 if (node == nil)
128 return;
129 free_nodes(dict, node->left, nil);
130 free_nodes(dict, node->right, nil);
131 dict->freenode(node, dict->context);
jardineb5d44e2003-12-23 08:09:43 +0000132}
133
134/*
135 * This procedure performs a verification that the given subtree is a binary
136 * search tree. It performs an inorder traversal of the tree using the
137 * dict_next() successor function, verifying that the key of each node is
138 * strictly lower than that of its successor, if duplicates are not allowed,
139 * or lower or equal if duplicates are allowed. This function is used for
140 * debugging purposes.
141 */
142
hassoffe543a2005-09-25 12:04:25 +0000143static int verify_bintree(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000144{
hassoffe543a2005-09-25 12:04:25 +0000145 dnode_t *first, *next;
jardineb5d44e2003-12-23 08:09:43 +0000146
hassoffe543a2005-09-25 12:04:25 +0000147 first = dict_first(dict);
jardineb5d44e2003-12-23 08:09:43 +0000148
hassoffe543a2005-09-25 12:04:25 +0000149 if (dict->dupes) {
150 while (first && (next = dict_next(dict, first))) {
151 if (dict->compare(first->key, next->key) > 0)
152 return 0;
153 first = next;
154 }
155 } else {
156 while (first && (next = dict_next(dict, first))) {
157 if (dict->compare(first->key, next->key) >= 0)
158 return 0;
159 first = next;
jardineb5d44e2003-12-23 08:09:43 +0000160 }
161 }
hassoffe543a2005-09-25 12:04:25 +0000162 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000163}
164
165
166/*
167 * This function recursively verifies that the given binary subtree satisfies
168 * three of the red black properties. It checks that every red node has only
169 * black children. It makes sure that each node is either red or black. And it
170 * checks that every path has the same count of black nodes from root to leaf.
171 * It returns the blackheight of the given subtree; this allows blackheights to
172 * be computed recursively and compared for left and right siblings for
173 * mismatches. It does not check for every nil node being black, because there
174 * is only one sentinel nil node. The return value of this function is the
175 * black height of the subtree rooted at the node ``root'', or zero if the
176 * subtree is not red-black.
177 */
178
hassoffe543a2005-09-25 12:04:25 +0000179static unsigned int verify_redblack(dnode_t *nil, dnode_t *root)
jardineb5d44e2003-12-23 08:09:43 +0000180{
hassoffe543a2005-09-25 12:04:25 +0000181 unsigned height_left, height_right;
jardineb5d44e2003-12-23 08:09:43 +0000182
hassoffe543a2005-09-25 12:04:25 +0000183 if (root != nil) {
184 height_left = verify_redblack(nil, root->left);
185 height_right = verify_redblack(nil, root->right);
186 if (height_left == 0 || height_right == 0)
jardineb5d44e2003-12-23 08:09:43 +0000187 return 0;
hassoffe543a2005-09-25 12:04:25 +0000188 if (height_left != height_right)
jardineb5d44e2003-12-23 08:09:43 +0000189 return 0;
hassoffe543a2005-09-25 12:04:25 +0000190 if (root->color == dnode_red) {
191 if (root->left->color != dnode_black)
192 return 0;
193 if (root->right->color != dnode_black)
194 return 0;
195 return height_left;
jardineb5d44e2003-12-23 08:09:43 +0000196 }
hassoffe543a2005-09-25 12:04:25 +0000197 if (root->color != dnode_black)
198 return 0;
199 return height_left + 1;
200 }
201 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000202}
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
hassoffe543a2005-09-25 12:04:25 +0000210static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root)
jardineb5d44e2003-12-23 08:09:43 +0000211{
hassoffe543a2005-09-25 12:04:25 +0000212 if (root == nil)
213 return 0;
214 else
215 return 1 + verify_node_count(nil, root->left)
216 + verify_node_count(nil, root->right);
jardineb5d44e2003-12-23 08:09:43 +0000217}
218
219/*
220 * Verify that the tree contains the given node. This is done by
221 * traversing all of the nodes and comparing their pointers to the
222 * given pointer. Returns 1 if the node is found, otherwise
223 * returns zero. It is intended for debugging purposes.
224 */
225
hassoffe543a2005-09-25 12:04:25 +0000226static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
jardineb5d44e2003-12-23 08:09:43 +0000227{
hassoffe543a2005-09-25 12:04:25 +0000228 if (root != nil) {
229 return root == node
230 || verify_dict_has_node(nil, root->left, node)
231 || verify_dict_has_node(nil, root->right, node);
jardineb5d44e2003-12-23 08:09:43 +0000232 }
hassoffe543a2005-09-25 12:04:25 +0000233 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000234}
235
hassoffe543a2005-09-25 12:04:25 +0000236
jardineb5d44e2003-12-23 08:09:43 +0000237/*
238 * Dynamically allocate and initialize a dictionary object.
239 */
240
hassoffe543a2005-09-25 12:04:25 +0000241dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp)
jardineb5d44e2003-12-23 08:09:43 +0000242{
Josh Bailey3f045a02012-03-24 08:35:20 -0700243 dict_t *new = XCALLOC(MTYPE_ISIS_DICT, sizeof(dict_t));
jardineb5d44e2003-12-23 08:09:43 +0000244
hassoffe543a2005-09-25 12:04:25 +0000245 if (new) {
246 new->compare = comp;
247 new->allocnode = dnode_alloc;
248 new->freenode = dnode_free;
249 new->context = NULL;
250 new->nodecount = 0;
251 new->maxcount = maxcount;
252 new->nilnode.left = &new->nilnode;
253 new->nilnode.right = &new->nilnode;
254 new->nilnode.parent = &new->nilnode;
255 new->nilnode.color = dnode_black;
256 new->dupes = 0;
jardineb5d44e2003-12-23 08:09:43 +0000257 }
hassoffe543a2005-09-25 12:04:25 +0000258 return new;
jardineb5d44e2003-12-23 08:09:43 +0000259}
260
261/*
262 * Select a different set of node allocator routines.
263 */
264
hassoffe543a2005-09-25 12:04:25 +0000265void dict_set_allocator(dict_t *dict, dnode_alloc_t al,
266 dnode_free_t fr, void *context)
jardineb5d44e2003-12-23 08:09:43 +0000267{
hassoffe543a2005-09-25 12:04:25 +0000268 assert (dict_count(dict) == 0);
269 assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL));
jardineb5d44e2003-12-23 08:09:43 +0000270
hassoffe543a2005-09-25 12:04:25 +0000271 dict->allocnode = al ? al : dnode_alloc;
272 dict->freenode = fr ? fr : dnode_free;
273 dict->context = context;
jardineb5d44e2003-12-23 08:09:43 +0000274}
275
276/*
277 * Free a dynamically allocated dictionary object. Removing the nodes
278 * from the tree before deleting it is required.
279 */
280
hassoffe543a2005-09-25 12:04:25 +0000281void dict_destroy(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000282{
hassoffe543a2005-09-25 12:04:25 +0000283 assert (dict_isempty(dict));
Josh Bailey3f045a02012-03-24 08:35:20 -0700284 XFREE(MTYPE_ISIS_DICT, dict);
jardineb5d44e2003-12-23 08:09:43 +0000285}
286
287/*
288 * Free all the nodes in the dictionary by using the dictionary's
289 * installed free routine. The dictionary is emptied.
290 */
291
hassoffe543a2005-09-25 12:04:25 +0000292void dict_free_nodes(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000293{
hassoffe543a2005-09-25 12:04:25 +0000294 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
295 free_nodes(dict, root, nil);
296 dict->nodecount = 0;
297 dict->nilnode.left = &dict->nilnode;
298 dict->nilnode.right = &dict->nilnode;
jardineb5d44e2003-12-23 08:09:43 +0000299}
300
301/*
302 * Obsolescent function, equivalent to dict_free_nodes
303 */
304
hassoffe543a2005-09-25 12:04:25 +0000305void dict_free(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000306{
hassoffe543a2005-09-25 12:04:25 +0000307 dict_free_nodes(dict);
jardineb5d44e2003-12-23 08:09:43 +0000308}
309
310/*
311 * Initialize a user-supplied dictionary object.
312 */
313
hassoffe543a2005-09-25 12:04:25 +0000314dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
jardineb5d44e2003-12-23 08:09:43 +0000315{
hassoffe543a2005-09-25 12:04:25 +0000316 dict->compare = comp;
317 dict->allocnode = dnode_alloc;
318 dict->freenode = dnode_free;
319 dict->context = NULL;
320 dict->nodecount = 0;
321 dict->maxcount = maxcount;
322 dict->nilnode.left = &dict->nilnode;
323 dict->nilnode.right = &dict->nilnode;
324 dict->nilnode.parent = &dict->nilnode;
325 dict->nilnode.color = dnode_black;
326 dict->dupes = 0;
327 return dict;
jardineb5d44e2003-12-23 08:09:43 +0000328}
329
330/*
331 * Initialize a dictionary in the likeness of another dictionary
332 */
333
hassoffe543a2005-09-25 12:04:25 +0000334void dict_init_like(dict_t *dict, const dict_t *template)
jardineb5d44e2003-12-23 08:09:43 +0000335{
hassoffe543a2005-09-25 12:04:25 +0000336 dict->compare = template->compare;
337 dict->allocnode = template->allocnode;
338 dict->freenode = template->freenode;
339 dict->context = template->context;
340 dict->nodecount = 0;
341 dict->maxcount = template->maxcount;
342 dict->nilnode.left = &dict->nilnode;
343 dict->nilnode.right = &dict->nilnode;
344 dict->nilnode.parent = &dict->nilnode;
345 dict->nilnode.color = dnode_black;
346 dict->dupes = template->dupes;
jardineb5d44e2003-12-23 08:09:43 +0000347
hassoffe543a2005-09-25 12:04:25 +0000348 assert (dict_similar(dict, template));
jardineb5d44e2003-12-23 08:09:43 +0000349}
350
351/*
352 * Remove all nodes from the dictionary (without freeing them in any way).
353 */
354
hassoffe543a2005-09-25 12:04:25 +0000355static void dict_clear(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000356{
hassoffe543a2005-09-25 12:04:25 +0000357 dict->nodecount = 0;
358 dict->nilnode.left = &dict->nilnode;
359 dict->nilnode.right = &dict->nilnode;
360 dict->nilnode.parent = &dict->nilnode;
361 assert (dict->nilnode.color == dnode_black);
jardineb5d44e2003-12-23 08:09:43 +0000362}
363
hassoffe543a2005-09-25 12:04:25 +0000364
jardineb5d44e2003-12-23 08:09:43 +0000365/*
366 * Verify the integrity of the dictionary structure. This is provided for
367 * debugging purposes, and should be placed in assert statements. Just because
368 * this function succeeds doesn't mean that the tree is not corrupt. Certain
369 * corruptions in the tree may simply cause undefined behavior.
hassoffe543a2005-09-25 12:04:25 +0000370 */
jardineb5d44e2003-12-23 08:09:43 +0000371
hassoffe543a2005-09-25 12:04:25 +0000372int dict_verify(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000373{
hassoffe543a2005-09-25 12:04:25 +0000374 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
jardineb5d44e2003-12-23 08:09:43 +0000375
hassoffe543a2005-09-25 12:04:25 +0000376 /* check that the sentinel node and root node are black */
377 if (root->color != dnode_black)
378 return 0;
379 if (nil->color != dnode_black)
380 return 0;
381 if (nil->right != nil)
382 return 0;
383 /* nil->left is the root node; check that its parent pointer is nil */
384 if (nil->left->parent != nil)
385 return 0;
386 /* perform a weak test that the tree is a binary search tree */
387 if (!verify_bintree(dict))
388 return 0;
389 /* verify that the tree is a red-black tree */
390 if (!verify_redblack(nil, root))
391 return 0;
392 if (verify_node_count(nil, root) != dict_count(dict))
393 return 0;
394 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000395}
396
397/*
398 * Determine whether two dictionaries are similar: have the same comparison and
399 * allocator functions, and same status as to whether duplicates are allowed.
400 */
401
hassoffe543a2005-09-25 12:04:25 +0000402int dict_similar(const dict_t *left, const dict_t *right)
jardineb5d44e2003-12-23 08:09:43 +0000403{
hassoffe543a2005-09-25 12:04:25 +0000404 if (left->compare != right->compare)
405 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000406
hassoffe543a2005-09-25 12:04:25 +0000407 if (left->allocnode != right->allocnode)
408 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000409
hassoffe543a2005-09-25 12:04:25 +0000410 if (left->freenode != right->freenode)
411 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000412
hassoffe543a2005-09-25 12:04:25 +0000413 if (left->context != right->context)
414 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000415
hassoffe543a2005-09-25 12:04:25 +0000416 if (left->dupes != right->dupes)
417 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000418
hassoffe543a2005-09-25 12:04:25 +0000419 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000420}
421
422/*
423 * Locate a node in the dictionary having the given key.
424 * If the node is not found, a null a pointer is returned (rather than
425 * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
426 * located node is returned.
427 */
428
hassoffe543a2005-09-25 12:04:25 +0000429dnode_t *dict_lookup(dict_t *dict, const void *key)
jardineb5d44e2003-12-23 08:09:43 +0000430{
hassoffe543a2005-09-25 12:04:25 +0000431 dnode_t *root = dict_root(dict);
432 dnode_t *nil = dict_nil(dict);
433 dnode_t *saved;
434 int result;
jardineb5d44e2003-12-23 08:09:43 +0000435
hassoffe543a2005-09-25 12:04:25 +0000436 /* simple binary search adapted for trees that contain duplicate keys */
jardineb5d44e2003-12-23 08:09:43 +0000437
hassoffe543a2005-09-25 12:04:25 +0000438 while (root != nil) {
439 result = dict->compare(key, root->key);
440 if (result < 0)
441 root = root->left;
442 else if (result > 0)
443 root = root->right;
444 else {
445 if (!dict->dupes) { /* no duplicates, return match */
446 return root;
447 } else { /* could be dupes, find leftmost one */
448 do {
449 saved = root;
450 root = root->left;
451 while (root != nil && dict->compare(key, root->key))
452 root = root->right;
453 } while (root != nil);
454 return saved;
jardineb5d44e2003-12-23 08:09:43 +0000455 }
456 }
457 }
458
hassoffe543a2005-09-25 12:04:25 +0000459 return NULL;
jardineb5d44e2003-12-23 08:09:43 +0000460}
461
462/*
463 * Look for the node corresponding to the lowest key that is equal to or
464 * greater than the given key. If there is no such node, return null.
465 */
466
hassoffe543a2005-09-25 12:04:25 +0000467dnode_t *dict_lower_bound(dict_t *dict, const void *key)
jardineb5d44e2003-12-23 08:09:43 +0000468{
hassoffe543a2005-09-25 12:04:25 +0000469 dnode_t *root = dict_root(dict);
470 dnode_t *nil = dict_nil(dict);
471 dnode_t *tentative = 0;
jardineb5d44e2003-12-23 08:09:43 +0000472
hassoffe543a2005-09-25 12:04:25 +0000473 while (root != nil) {
474 int result = dict->compare(key, root->key);
jardineb5d44e2003-12-23 08:09:43 +0000475
hassoffe543a2005-09-25 12:04:25 +0000476 if (result > 0) {
477 root = root->right;
478 } else if (result < 0) {
479 tentative = root;
480 root = root->left;
481 } else {
482 if (!dict->dupes) {
483 return root;
484 } else {
485 tentative = root;
486 root = root->left;
jardineb5d44e2003-12-23 08:09:43 +0000487 }
hassoffe543a2005-09-25 12:04:25 +0000488 }
jardineb5d44e2003-12-23 08:09:43 +0000489 }
hassoffe543a2005-09-25 12:04:25 +0000490
491 return tentative;
jardineb5d44e2003-12-23 08:09:43 +0000492}
493
494/*
495 * Look for the node corresponding to the greatest key that is equal to or
496 * lower than the given key. If there is no such node, return null.
497 */
498
hassoffe543a2005-09-25 12:04:25 +0000499dnode_t *dict_upper_bound(dict_t *dict, const void *key)
jardineb5d44e2003-12-23 08:09:43 +0000500{
hassoffe543a2005-09-25 12:04:25 +0000501 dnode_t *root = dict_root(dict);
502 dnode_t *nil = dict_nil(dict);
503 dnode_t *tentative = 0;
jardineb5d44e2003-12-23 08:09:43 +0000504
hassoffe543a2005-09-25 12:04:25 +0000505 while (root != nil) {
506 int result = dict->compare(key, root->key);
jardineb5d44e2003-12-23 08:09:43 +0000507
hassoffe543a2005-09-25 12:04:25 +0000508 if (result < 0) {
509 root = root->left;
510 } else if (result > 0) {
511 tentative = root;
512 root = root->right;
513 } else {
514 if (!dict->dupes) {
515 return root;
516 } else {
517 tentative = root;
518 root = root->right;
jardineb5d44e2003-12-23 08:09:43 +0000519 }
hassoffe543a2005-09-25 12:04:25 +0000520 }
jardineb5d44e2003-12-23 08:09:43 +0000521 }
hassoffe543a2005-09-25 12:04:25 +0000522
523 return tentative;
jardineb5d44e2003-12-23 08:09:43 +0000524}
525
526/*
527 * Insert a node into the dictionary. The node should have been
528 * initialized with a data field. All other fields are ignored.
529 * The behavior is undefined if the user attempts to insert into
530 * a dictionary that is already full (for which the dict_isfull()
531 * function returns true).
532 */
533
hassoffe543a2005-09-25 12:04:25 +0000534void dict_insert(dict_t *dict, dnode_t *node, const void *key)
jardineb5d44e2003-12-23 08:09:43 +0000535{
hassoffe543a2005-09-25 12:04:25 +0000536 dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
537 dnode_t *parent = nil, *uncle, *grandpa;
538 int result = -1;
jardineb5d44e2003-12-23 08:09:43 +0000539
hassoffe543a2005-09-25 12:04:25 +0000540 node->key = key;
jardineb5d44e2003-12-23 08:09:43 +0000541
hassoffe543a2005-09-25 12:04:25 +0000542 assert (!dict_isfull(dict));
543 assert (!dict_contains(dict, node));
544 assert (!dnode_is_in_a_dict(node));
jardineb5d44e2003-12-23 08:09:43 +0000545
hassoffe543a2005-09-25 12:04:25 +0000546 /* basic binary tree insert */
jardineb5d44e2003-12-23 08:09:43 +0000547
hassoffe543a2005-09-25 12:04:25 +0000548 while (where != nil) {
549 parent = where;
550 result = dict->compare(key, where->key);
551 /* trap attempts at duplicate key insertion unless it's explicitly allowed */
552 assert (dict->dupes || result != 0);
553 if (result < 0)
554 where = where->left;
555 else
556 where = where->right;
jardineb5d44e2003-12-23 08:09:43 +0000557 }
558
hassoffe543a2005-09-25 12:04:25 +0000559 assert (where == nil);
jardineb5d44e2003-12-23 08:09:43 +0000560
hassoffe543a2005-09-25 12:04:25 +0000561 if (result < 0)
562 parent->left = node;
563 else
564 parent->right = node;
jardineb5d44e2003-12-23 08:09:43 +0000565
hassoffe543a2005-09-25 12:04:25 +0000566 node->parent = parent;
567 node->left = nil;
568 node->right = nil;
jardineb5d44e2003-12-23 08:09:43 +0000569
hassoffe543a2005-09-25 12:04:25 +0000570 dict->nodecount++;
jardineb5d44e2003-12-23 08:09:43 +0000571
hassoffe543a2005-09-25 12:04:25 +0000572 /* red black adjustments */
jardineb5d44e2003-12-23 08:09:43 +0000573
hassoffe543a2005-09-25 12:04:25 +0000574 node->color = dnode_red;
jardineb5d44e2003-12-23 08:09:43 +0000575
hassoffe543a2005-09-25 12:04:25 +0000576 while (parent->color == dnode_red) {
577 grandpa = parent->parent;
578 if (parent == grandpa->left) {
579 uncle = grandpa->right;
580 if (uncle->color == dnode_red) { /* red parent, red uncle */
581 parent->color = dnode_black;
582 uncle->color = dnode_black;
583 grandpa->color = dnode_red;
584 node = grandpa;
585 parent = grandpa->parent;
586 } else { /* red parent, black uncle */
587 if (node == parent->right) {
588 rotate_left(parent);
589 parent = node;
590 assert (grandpa == parent->parent);
591 /* rotation between parent and child preserves grandpa */
jardineb5d44e2003-12-23 08:09:43 +0000592 }
hassoffe543a2005-09-25 12:04:25 +0000593 parent->color = dnode_black;
594 grandpa->color = dnode_red;
595 rotate_right(grandpa);
596 break;
hassof390d2c2004-09-10 20:48:21 +0000597 }
hassoffe543a2005-09-25 12:04:25 +0000598 } else { /* symmetric cases: parent == parent->parent->right */
599 uncle = grandpa->left;
600 if (uncle->color == dnode_red) {
601 parent->color = dnode_black;
602 uncle->color = dnode_black;
603 grandpa->color = dnode_red;
604 node = grandpa;
605 parent = grandpa->parent;
606 } else {
607 if (node == parent->left) {
608 rotate_right(parent);
609 parent = node;
610 assert (grandpa == parent->parent);
hassof390d2c2004-09-10 20:48:21 +0000611 }
hassoffe543a2005-09-25 12:04:25 +0000612 parent->color = dnode_black;
613 grandpa->color = dnode_red;
614 rotate_left(grandpa);
615 break;
jardineb5d44e2003-12-23 08:09:43 +0000616 }
617 }
618 }
619
hassoffe543a2005-09-25 12:04:25 +0000620 dict_root(dict)->color = dnode_black;
jardineb5d44e2003-12-23 08:09:43 +0000621
hassoffe543a2005-09-25 12:04:25 +0000622 assert (dict_verify(dict));
jardineb5d44e2003-12-23 08:09:43 +0000623}
624
625/*
626 * Delete the given node from the dictionary. If the given node does not belong
627 * to the given dictionary, undefined behavior results. A pointer to the
628 * deleted node is returned.
629 */
630
hassoffe543a2005-09-25 12:04:25 +0000631dnode_t *dict_delete(dict_t *dict, dnode_t *delete)
jardineb5d44e2003-12-23 08:09:43 +0000632{
hassoffe543a2005-09-25 12:04:25 +0000633 dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent;
jardineb5d44e2003-12-23 08:09:43 +0000634
hassoffe543a2005-09-25 12:04:25 +0000635 /* basic deletion */
jardineb5d44e2003-12-23 08:09:43 +0000636
hassoffe543a2005-09-25 12:04:25 +0000637 assert (!dict_isempty(dict));
638 assert (dict_contains(dict, delete));
jardineb5d44e2003-12-23 08:09:43 +0000639
hassoffe543a2005-09-25 12:04:25 +0000640 /*
641 * If the node being deleted has two children, then we replace it with its
642 * successor (i.e. the leftmost node in the right subtree.) By doing this,
643 * we avoid the traditional algorithm under which the successor's key and
644 * value *only* move to the deleted node and the successor is spliced out
645 * from the tree. We cannot use this approach because the user may hold
646 * pointers to the successor, or nodes may be inextricably tied to some
647 * other structures by way of embedding, etc. So we must splice out the
648 * node we are given, not some other node, and must not move contents from
649 * one node to another behind the user's back.
650 */
jardineb5d44e2003-12-23 08:09:43 +0000651
hassoffe543a2005-09-25 12:04:25 +0000652 if (delete->left != nil && delete->right != nil) {
653 dnode_t *next = dict_next(dict, delete);
654 dnode_t *nextparent = next->parent;
655 dnode_color_t nextcolor = next->color;
jardineb5d44e2003-12-23 08:09:43 +0000656
hassoffe543a2005-09-25 12:04:25 +0000657 assert (next != nil);
658 assert (next->parent != nil);
659 assert (next->left == nil);
jardineb5d44e2003-12-23 08:09:43 +0000660
hassoffe543a2005-09-25 12:04:25 +0000661 /*
662 * First, splice out the successor from the tree completely, by
663 * moving up its right child into its place.
664 */
jardineb5d44e2003-12-23 08:09:43 +0000665
hassoffe543a2005-09-25 12:04:25 +0000666 child = next->right;
667 child->parent = nextparent;
jardineb5d44e2003-12-23 08:09:43 +0000668
hassoffe543a2005-09-25 12:04:25 +0000669 if (nextparent->left == next) {
670 nextparent->left = child;
671 } else {
672 assert (nextparent->right == next);
673 nextparent->right = child;
jardineb5d44e2003-12-23 08:09:43 +0000674 }
675
hassoffe543a2005-09-25 12:04:25 +0000676 /*
677 * Now that the successor has been extricated from the tree, install it
678 * in place of the node that we want deleted.
679 */
jardineb5d44e2003-12-23 08:09:43 +0000680
hassoffe543a2005-09-25 12:04:25 +0000681 next->parent = delparent;
682 next->left = delete->left;
683 next->right = delete->right;
684 next->left->parent = next;
685 next->right->parent = next;
686 next->color = delete->color;
687 delete->color = nextcolor;
jardineb5d44e2003-12-23 08:09:43 +0000688
hassoffe543a2005-09-25 12:04:25 +0000689 if (delparent->left == delete) {
690 delparent->left = next;
691 } else {
692 assert (delparent->right == delete);
693 delparent->right = next;
jardineb5d44e2003-12-23 08:09:43 +0000694 }
695
hassoffe543a2005-09-25 12:04:25 +0000696 } else {
697 assert (delete != nil);
698 assert (delete->left == nil || delete->right == nil);
jardineb5d44e2003-12-23 08:09:43 +0000699
hassoffe543a2005-09-25 12:04:25 +0000700 child = (delete->left != nil) ? delete->left : delete->right;
jardineb5d44e2003-12-23 08:09:43 +0000701
hassoffe543a2005-09-25 12:04:25 +0000702 child->parent = delparent = delete->parent;
jardineb5d44e2003-12-23 08:09:43 +0000703
hassoffe543a2005-09-25 12:04:25 +0000704 if (delete == delparent->left) {
705 delparent->left = child;
706 } else {
707 assert (delete == delparent->right);
708 delparent->right = child;
jardineb5d44e2003-12-23 08:09:43 +0000709 }
710 }
711
hassoffe543a2005-09-25 12:04:25 +0000712 delete->parent = NULL;
713 delete->right = NULL;
714 delete->left = NULL;
jardineb5d44e2003-12-23 08:09:43 +0000715
hassoffe543a2005-09-25 12:04:25 +0000716 dict->nodecount--;
jardineb5d44e2003-12-23 08:09:43 +0000717
hassoffe543a2005-09-25 12:04:25 +0000718 assert (verify_bintree(dict));
jardineb5d44e2003-12-23 08:09:43 +0000719
hassoffe543a2005-09-25 12:04:25 +0000720 /* red-black adjustments */
jardineb5d44e2003-12-23 08:09:43 +0000721
hassoffe543a2005-09-25 12:04:25 +0000722 if (delete->color == dnode_black) {
723 dnode_t *parent, *sister;
jardineb5d44e2003-12-23 08:09:43 +0000724
hassoffe543a2005-09-25 12:04:25 +0000725 dict_root(dict)->color = dnode_red;
jardineb5d44e2003-12-23 08:09:43 +0000726
hassoffe543a2005-09-25 12:04:25 +0000727 while (child->color == dnode_black) {
728 parent = child->parent;
729 if (child == parent->left) {
730 sister = parent->right;
731 assert (sister != nil);
732 if (sister->color == dnode_red) {
733 sister->color = dnode_black;
734 parent->color = dnode_red;
735 rotate_left(parent);
736 sister = parent->right;
737 assert (sister != nil);
jardineb5d44e2003-12-23 08:09:43 +0000738 }
hassoffe543a2005-09-25 12:04:25 +0000739 if (sister->left->color == dnode_black
740 && sister->right->color == dnode_black) {
741 sister->color = dnode_red;
742 child = parent;
743 } else {
744 if (sister->right->color == dnode_black) {
745 assert (sister->left->color == dnode_red);
746 sister->left->color = dnode_black;
747 sister->color = dnode_red;
748 rotate_right(sister);
749 sister = parent->right;
750 assert (sister != nil);
jardineb5d44e2003-12-23 08:09:43 +0000751 }
hassoffe543a2005-09-25 12:04:25 +0000752 sister->color = parent->color;
753 sister->right->color = dnode_black;
754 parent->color = dnode_black;
755 rotate_left(parent);
756 break;
jardineb5d44e2003-12-23 08:09:43 +0000757 }
hassoffe543a2005-09-25 12:04:25 +0000758 } else { /* symmetric case: child == child->parent->right */
759 assert (child == parent->right);
760 sister = parent->left;
761 assert (sister != nil);
762 if (sister->color == dnode_red) {
763 sister->color = dnode_black;
764 parent->color = dnode_red;
765 rotate_right(parent);
766 sister = parent->left;
767 assert (sister != nil);
jardineb5d44e2003-12-23 08:09:43 +0000768 }
hassoffe543a2005-09-25 12:04:25 +0000769 if (sister->right->color == dnode_black
770 && sister->left->color == dnode_black) {
771 sister->color = dnode_red;
772 child = parent;
773 } else {
774 if (sister->left->color == dnode_black) {
775 assert (sister->right->color == dnode_red);
776 sister->right->color = dnode_black;
777 sister->color = dnode_red;
778 rotate_left(sister);
779 sister = parent->left;
780 assert (sister != nil);
jardineb5d44e2003-12-23 08:09:43 +0000781 }
hassoffe543a2005-09-25 12:04:25 +0000782 sister->color = parent->color;
783 sister->left->color = dnode_black;
784 parent->color = dnode_black;
785 rotate_right(parent);
786 break;
jardineb5d44e2003-12-23 08:09:43 +0000787 }
788 }
789 }
790
hassoffe543a2005-09-25 12:04:25 +0000791 child->color = dnode_black;
792 dict_root(dict)->color = dnode_black;
jardineb5d44e2003-12-23 08:09:43 +0000793 }
794
hassoffe543a2005-09-25 12:04:25 +0000795 assert (dict_verify(dict));
jardineb5d44e2003-12-23 08:09:43 +0000796
hassoffe543a2005-09-25 12:04:25 +0000797 return delete;
jardineb5d44e2003-12-23 08:09:43 +0000798}
799
800/*
801 * Allocate a node using the dictionary's allocator routine, give it
802 * the data item.
803 */
804
hassoffe543a2005-09-25 12:04:25 +0000805int dict_alloc_insert(dict_t *dict, const void *key, void *data)
jardineb5d44e2003-12-23 08:09:43 +0000806{
Josh Bailey3f045a02012-03-24 08:35:20 -0700807 dnode_t *node = dict->allocnode (dict->context);
jardineb5d44e2003-12-23 08:09:43 +0000808
hassoffe543a2005-09-25 12:04:25 +0000809 if (node) {
810 dnode_init(node, data);
811 dict_insert(dict, node, key);
812 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000813 }
hassoffe543a2005-09-25 12:04:25 +0000814 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000815}
816
hassoffe543a2005-09-25 12:04:25 +0000817void dict_delete_free(dict_t *dict, dnode_t *node)
jardineb5d44e2003-12-23 08:09:43 +0000818{
hassoffe543a2005-09-25 12:04:25 +0000819 dict_delete(dict, node);
820 dict->freenode(node, dict->context);
jardineb5d44e2003-12-23 08:09:43 +0000821}
822
823/*
824 * Return the node with the lowest (leftmost) key. If the dictionary is empty
825 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
826 */
827
hassoffe543a2005-09-25 12:04:25 +0000828dnode_t *dict_first(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000829{
hassoffe543a2005-09-25 12:04:25 +0000830 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
jardineb5d44e2003-12-23 08:09:43 +0000831
hassoffe543a2005-09-25 12:04:25 +0000832 if (root != nil)
833 while ((left = root->left) != nil)
834 root = left;
jardineb5d44e2003-12-23 08:09:43 +0000835
hassoffe543a2005-09-25 12:04:25 +0000836 return (root == nil) ? NULL : root;
jardineb5d44e2003-12-23 08:09:43 +0000837}
838
839/*
840 * Return the node with the highest (rightmost) key. If the dictionary is empty
841 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
842 */
843
hassoffe543a2005-09-25 12:04:25 +0000844dnode_t *dict_last(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000845{
hassoffe543a2005-09-25 12:04:25 +0000846 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right;
jardineb5d44e2003-12-23 08:09:43 +0000847
hassoffe543a2005-09-25 12:04:25 +0000848 if (root != nil)
849 while ((right = root->right) != nil)
850 root = right;
jardineb5d44e2003-12-23 08:09:43 +0000851
hassoffe543a2005-09-25 12:04:25 +0000852 return (root == nil) ? NULL : root;
jardineb5d44e2003-12-23 08:09:43 +0000853}
854
855/*
856 * Return the given node's successor node---the node which has the
857 * next key in the the left to right ordering. If the node has
858 * no successor, a null pointer is returned rather than a pointer to
859 * the nil node.
860 */
861
hassoffe543a2005-09-25 12:04:25 +0000862dnode_t *dict_next(dict_t *dict, dnode_t *curr)
jardineb5d44e2003-12-23 08:09:43 +0000863{
hassoffe543a2005-09-25 12:04:25 +0000864 dnode_t *nil = dict_nil(dict), *parent, *left;
jardineb5d44e2003-12-23 08:09:43 +0000865
hassoffe543a2005-09-25 12:04:25 +0000866 if (curr->right != nil) {
867 curr = curr->right;
868 while ((left = curr->left) != nil)
869 curr = left;
870 return curr;
jardineb5d44e2003-12-23 08:09:43 +0000871 }
872
hassoffe543a2005-09-25 12:04:25 +0000873 parent = curr->parent;
jardineb5d44e2003-12-23 08:09:43 +0000874
hassoffe543a2005-09-25 12:04:25 +0000875 while (parent != nil && curr == parent->right) {
876 curr = parent;
877 parent = curr->parent;
jardineb5d44e2003-12-23 08:09:43 +0000878 }
879
hassoffe543a2005-09-25 12:04:25 +0000880 return (parent == nil) ? NULL : parent;
jardineb5d44e2003-12-23 08:09:43 +0000881}
882
883/*
884 * Return the given node's predecessor, in the key order.
885 * The nil sentinel node is returned if there is no predecessor.
886 */
887
hassoffe543a2005-09-25 12:04:25 +0000888dnode_t *dict_prev(dict_t *dict, dnode_t *curr)
jardineb5d44e2003-12-23 08:09:43 +0000889{
hassoffe543a2005-09-25 12:04:25 +0000890 dnode_t *nil = dict_nil(dict), *parent, *right;
jardineb5d44e2003-12-23 08:09:43 +0000891
hassoffe543a2005-09-25 12:04:25 +0000892 if (curr->left != nil) {
893 curr = curr->left;
894 while ((right = curr->right) != nil)
895 curr = right;
896 return curr;
jardineb5d44e2003-12-23 08:09:43 +0000897 }
898
hassoffe543a2005-09-25 12:04:25 +0000899 parent = curr->parent;
jardineb5d44e2003-12-23 08:09:43 +0000900
hassoffe543a2005-09-25 12:04:25 +0000901 while (parent != nil && curr == parent->left) {
902 curr = parent;
903 parent = curr->parent;
jardineb5d44e2003-12-23 08:09:43 +0000904 }
905
hassoffe543a2005-09-25 12:04:25 +0000906 return (parent == nil) ? NULL : parent;
jardineb5d44e2003-12-23 08:09:43 +0000907}
908
hassoffe543a2005-09-25 12:04:25 +0000909void dict_allow_dupes(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000910{
hassoffe543a2005-09-25 12:04:25 +0000911 dict->dupes = 1;
jardineb5d44e2003-12-23 08:09:43 +0000912}
913
914#undef dict_count
915#undef dict_isempty
916#undef dict_isfull
917#undef dnode_get
918#undef dnode_put
919#undef dnode_getkey
920
hassoffe543a2005-09-25 12:04:25 +0000921dictcount_t dict_count(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000922{
hassoffe543a2005-09-25 12:04:25 +0000923 return dict->nodecount;
jardineb5d44e2003-12-23 08:09:43 +0000924}
925
hassoffe543a2005-09-25 12:04:25 +0000926int dict_isempty(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000927{
hassoffe543a2005-09-25 12:04:25 +0000928 return dict->nodecount == 0;
jardineb5d44e2003-12-23 08:09:43 +0000929}
930
hassoffe543a2005-09-25 12:04:25 +0000931int dict_isfull(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000932{
hassoffe543a2005-09-25 12:04:25 +0000933 return dict->nodecount == dict->maxcount;
jardineb5d44e2003-12-23 08:09:43 +0000934}
935
hassoffe543a2005-09-25 12:04:25 +0000936int dict_contains(dict_t *dict, dnode_t *node)
jardineb5d44e2003-12-23 08:09:43 +0000937{
hassoffe543a2005-09-25 12:04:25 +0000938 return verify_dict_has_node(dict_nil(dict), dict_root(dict), node);
jardineb5d44e2003-12-23 08:09:43 +0000939}
940
hassoffe543a2005-09-25 12:04:25 +0000941static dnode_t *dnode_alloc(void *context)
jardineb5d44e2003-12-23 08:09:43 +0000942{
Josh Bailey3f045a02012-03-24 08:35:20 -0700943 return XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
jardineb5d44e2003-12-23 08:09:43 +0000944}
945
hassoffe543a2005-09-25 12:04:25 +0000946static void dnode_free(dnode_t *node, void *context)
jardineb5d44e2003-12-23 08:09:43 +0000947{
Josh Bailey3f045a02012-03-24 08:35:20 -0700948 XFREE(MTYPE_ISIS_DICT_NODE, node);
jardineb5d44e2003-12-23 08:09:43 +0000949}
950
hassoffe543a2005-09-25 12:04:25 +0000951dnode_t *dnode_create(void *data)
jardineb5d44e2003-12-23 08:09:43 +0000952{
Josh Bailey3f045a02012-03-24 08:35:20 -0700953 dnode_t *new = XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
hassoffe543a2005-09-25 12:04:25 +0000954 if (new) {
955 new->data = data;
956 new->parent = NULL;
957 new->left = NULL;
958 new->right = NULL;
jardineb5d44e2003-12-23 08:09:43 +0000959 }
hassoffe543a2005-09-25 12:04:25 +0000960 return new;
jardineb5d44e2003-12-23 08:09:43 +0000961}
962
hassoffe543a2005-09-25 12:04:25 +0000963dnode_t *dnode_init(dnode_t *dnode, void *data)
jardineb5d44e2003-12-23 08:09:43 +0000964{
hassoffe543a2005-09-25 12:04:25 +0000965 dnode->data = data;
966 dnode->parent = NULL;
967 dnode->left = NULL;
968 dnode->right = NULL;
969 return dnode;
jardineb5d44e2003-12-23 08:09:43 +0000970}
971
hassoffe543a2005-09-25 12:04:25 +0000972void dnode_destroy(dnode_t *dnode)
jardineb5d44e2003-12-23 08:09:43 +0000973{
hassoffe543a2005-09-25 12:04:25 +0000974 assert (!dnode_is_in_a_dict(dnode));
Josh Bailey3f045a02012-03-24 08:35:20 -0700975 XFREE(MTYPE_ISIS_DICT_NODE, dnode);
jardineb5d44e2003-12-23 08:09:43 +0000976}
977
hassoffe543a2005-09-25 12:04:25 +0000978void *dnode_get(dnode_t *dnode)
jardineb5d44e2003-12-23 08:09:43 +0000979{
hassoffe543a2005-09-25 12:04:25 +0000980 return dnode->data;
jardineb5d44e2003-12-23 08:09:43 +0000981}
982
hassoffe543a2005-09-25 12:04:25 +0000983const void *dnode_getkey(dnode_t *dnode)
jardineb5d44e2003-12-23 08:09:43 +0000984{
hassoffe543a2005-09-25 12:04:25 +0000985 return dnode->key;
jardineb5d44e2003-12-23 08:09:43 +0000986}
987
hassoffe543a2005-09-25 12:04:25 +0000988void dnode_put(dnode_t *dnode, void *data)
jardineb5d44e2003-12-23 08:09:43 +0000989{
hassoffe543a2005-09-25 12:04:25 +0000990 dnode->data = data;
jardineb5d44e2003-12-23 08:09:43 +0000991}
992
hassoffe543a2005-09-25 12:04:25 +0000993int dnode_is_in_a_dict(dnode_t *dnode)
jardineb5d44e2003-12-23 08:09:43 +0000994{
hassoffe543a2005-09-25 12:04:25 +0000995 return (dnode->parent && dnode->left && dnode->right);
jardineb5d44e2003-12-23 08:09:43 +0000996}
997
hassoffe543a2005-09-25 12:04:25 +0000998void dict_process(dict_t *dict, void *context, dnode_process_t function)
jardineb5d44e2003-12-23 08:09:43 +0000999{
hassoffe543a2005-09-25 12:04:25 +00001000 dnode_t *node = dict_first(dict), *next;
jardineb5d44e2003-12-23 08:09:43 +00001001
hassoffe543a2005-09-25 12:04:25 +00001002 while (node != NULL) {
1003 /* check for callback function deleting */
1004 /* the next node from under us */
1005 assert (dict_contains(dict, node));
1006 next = dict_next(dict, node);
1007 function(dict, node, context);
1008 node = next;
jardineb5d44e2003-12-23 08:09:43 +00001009 }
1010}
1011
hassoffe543a2005-09-25 12:04:25 +00001012static void load_begin_internal(dict_load_t *load, dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +00001013{
hassoffe543a2005-09-25 12:04:25 +00001014 load->dictptr = dict;
1015 load->nilnode.left = &load->nilnode;
1016 load->nilnode.right = &load->nilnode;
jardineb5d44e2003-12-23 08:09:43 +00001017}
1018
hassoffe543a2005-09-25 12:04:25 +00001019void dict_load_begin(dict_load_t *load, dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +00001020{
hassoffe543a2005-09-25 12:04:25 +00001021 assert (dict_isempty(dict));
1022 load_begin_internal(load, dict);
jardineb5d44e2003-12-23 08:09:43 +00001023}
1024
hassoffe543a2005-09-25 12:04:25 +00001025void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key)
jardineb5d44e2003-12-23 08:09:43 +00001026{
hassoffe543a2005-09-25 12:04:25 +00001027 dict_t *dict = load->dictptr;
1028 dnode_t *nil = &load->nilnode;
1029
1030 assert (!dnode_is_in_a_dict(newnode));
1031 assert (dict->nodecount < dict->maxcount);
jardineb5d44e2003-12-23 08:09:43 +00001032
hassoffe543a2005-09-25 12:04:25 +00001033 #ifndef NDEBUG
1034 if (dict->nodecount > 0) {
1035 if (dict->dupes)
1036 assert (dict->compare(nil->left->key, key) <= 0);
1037 else
1038 assert (dict->compare(nil->left->key, key) < 0);
jardineb5d44e2003-12-23 08:09:43 +00001039 }
hassoffe543a2005-09-25 12:04:25 +00001040 #endif
jardineb5d44e2003-12-23 08:09:43 +00001041
hassoffe543a2005-09-25 12:04:25 +00001042 newnode->key = key;
1043 nil->right->left = newnode;
1044 nil->right = newnode;
1045 newnode->left = nil;
1046 dict->nodecount++;
jardineb5d44e2003-12-23 08:09:43 +00001047}
1048
hassoffe543a2005-09-25 12:04:25 +00001049void dict_load_end(dict_load_t *load)
jardineb5d44e2003-12-23 08:09:43 +00001050{
hassoffe543a2005-09-25 12:04:25 +00001051 dict_t *dict = load->dictptr;
1052 dnode_t *tree[DICT_DEPTH_MAX] = { 0 };
1053 dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next;
1054 dnode_t *complete = 0;
1055 dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount;
1056 dictcount_t botrowcount;
1057 unsigned baselevel = 0, level = 0, i;
jardineb5d44e2003-12-23 08:09:43 +00001058
hassoffe543a2005-09-25 12:04:25 +00001059 assert (dnode_red == 0 && dnode_black == 1);
jardineb5d44e2003-12-23 08:09:43 +00001060
hassoffe543a2005-09-25 12:04:25 +00001061 while (fullcount >= nodecount && fullcount)
1062 fullcount >>= 1;
jardineb5d44e2003-12-23 08:09:43 +00001063
hassoffe543a2005-09-25 12:04:25 +00001064 botrowcount = nodecount - fullcount;
jardineb5d44e2003-12-23 08:09:43 +00001065
hassoffe543a2005-09-25 12:04:25 +00001066 for (curr = loadnil->left; curr != loadnil; curr = next) {
1067 next = curr->left;
jardineb5d44e2003-12-23 08:09:43 +00001068
hassoffe543a2005-09-25 12:04:25 +00001069 if (complete == NULL && botrowcount-- == 0) {
1070 assert (baselevel == 0);
1071 assert (level == 0);
1072 baselevel = level = 1;
1073 complete = tree[0];
jardineb5d44e2003-12-23 08:09:43 +00001074
hassoffe543a2005-09-25 12:04:25 +00001075 if (complete != 0) {
1076 tree[0] = 0;
1077 complete->right = dictnil;
1078 while (tree[level] != 0) {
1079 tree[level]->right = complete;
1080 complete->parent = tree[level];
1081 complete = tree[level];
1082 tree[level++] = 0;
jardineb5d44e2003-12-23 08:09:43 +00001083 }
1084 }
1085 }
1086
hassoffe543a2005-09-25 12:04:25 +00001087 if (complete == NULL) {
1088 curr->left = dictnil;
1089 curr->right = dictnil;
1090 curr->color = level % 2;
1091 complete = curr;
jardineb5d44e2003-12-23 08:09:43 +00001092
hassoffe543a2005-09-25 12:04:25 +00001093 assert (level == baselevel);
1094 while (tree[level] != 0) {
1095 tree[level]->right = complete;
1096 complete->parent = tree[level];
1097 complete = tree[level];
1098 tree[level++] = 0;
jardineb5d44e2003-12-23 08:09:43 +00001099 }
hassoffe543a2005-09-25 12:04:25 +00001100 } else {
1101 curr->left = complete;
1102 curr->color = (level + 1) % 2;
1103 complete->parent = curr;
1104 tree[level] = curr;
1105 complete = 0;
1106 level = baselevel;
jardineb5d44e2003-12-23 08:09:43 +00001107 }
1108 }
1109
hassoffe543a2005-09-25 12:04:25 +00001110 if (complete == NULL)
1111 complete = dictnil;
jardineb5d44e2003-12-23 08:09:43 +00001112
hassoffe543a2005-09-25 12:04:25 +00001113 for (i = 0; i < DICT_DEPTH_MAX; i++) {
1114 if (tree[i] != 0) {
1115 tree[i]->right = complete;
1116 complete->parent = tree[i];
1117 complete = tree[i];
jardineb5d44e2003-12-23 08:09:43 +00001118 }
1119 }
1120
hassoffe543a2005-09-25 12:04:25 +00001121 dictnil->color = dnode_black;
1122 dictnil->right = dictnil;
1123 complete->parent = dictnil;
1124 complete->color = dnode_black;
1125 dict_root(dict) = complete;
jardineb5d44e2003-12-23 08:09:43 +00001126
hassoffe543a2005-09-25 12:04:25 +00001127 assert (dict_verify(dict));
jardineb5d44e2003-12-23 08:09:43 +00001128}
1129
hassoffe543a2005-09-25 12:04:25 +00001130void dict_merge(dict_t *dest, dict_t *source)
jardineb5d44e2003-12-23 08:09:43 +00001131{
hassoffe543a2005-09-25 12:04:25 +00001132 dict_load_t load;
1133 dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source);
jardineb5d44e2003-12-23 08:09:43 +00001134
hassoffe543a2005-09-25 12:04:25 +00001135 assert (dict_similar(dest, source));
jardineb5d44e2003-12-23 08:09:43 +00001136
hassoffe543a2005-09-25 12:04:25 +00001137 if (source == dest)
1138 return;
jardineb5d44e2003-12-23 08:09:43 +00001139
hassoffe543a2005-09-25 12:04:25 +00001140 dest->nodecount = 0;
1141 load_begin_internal(&load, dest);
jardineb5d44e2003-12-23 08:09:43 +00001142
hassoffe543a2005-09-25 12:04:25 +00001143 for (;;) {
1144 if (leftnode != NULL && rightnode != NULL) {
1145 if (dest->compare(leftnode->key, rightnode->key) < 0)
1146 goto copyleft;
1147 else
1148 goto copyright;
1149 } else if (leftnode != NULL) {
jardineb5d44e2003-12-23 08:09:43 +00001150 goto copyleft;
hassoffe543a2005-09-25 12:04:25 +00001151 } else if (rightnode != NULL) {
jardineb5d44e2003-12-23 08:09:43 +00001152 goto copyright;
hassoffe543a2005-09-25 12:04:25 +00001153 } else {
1154 assert (leftnode == NULL && rightnode == NULL);
1155 break;
jardineb5d44e2003-12-23 08:09:43 +00001156 }
1157
1158 copyleft:
hassoffe543a2005-09-25 12:04:25 +00001159 {
1160 dnode_t *next = dict_next(dest, leftnode);
1161 #ifndef NDEBUG
1162 leftnode->left = NULL; /* suppress assertion in dict_load_next */
1163 #endif
1164 dict_load_next(&load, leftnode, leftnode->key);
1165 leftnode = next;
1166 continue;
1167 }
1168
jardineb5d44e2003-12-23 08:09:43 +00001169 copyright:
hassoffe543a2005-09-25 12:04:25 +00001170 {
1171 dnode_t *next = dict_next(source, rightnode);
1172 #ifndef NDEBUG
1173 rightnode->left = NULL;
1174 #endif
1175 dict_load_next(&load, rightnode, rightnode->key);
1176 rightnode = next;
1177 continue;
1178 }
jardineb5d44e2003-12-23 08:09:43 +00001179 }
1180
hassoffe543a2005-09-25 12:04:25 +00001181 dict_clear(source);
1182 dict_load_end(&load);
jardineb5d44e2003-12-23 08:09:43 +00001183}
1184
1185#ifdef KAZLIB_TEST_MAIN
1186
1187#include <stdio.h>
1188#include <string.h>
1189#include <ctype.h>
1190#include <stdarg.h>
1191
1192typedef char input_t[256];
1193
hassoffe543a2005-09-25 12:04:25 +00001194static int tokenize(char *string, ...)
jardineb5d44e2003-12-23 08:09:43 +00001195{
hassoffe543a2005-09-25 12:04:25 +00001196 char **tokptr;
1197 va_list arglist;
1198 int tokcount = 0;
jardineb5d44e2003-12-23 08:09:43 +00001199
hassoffe543a2005-09-25 12:04:25 +00001200 va_start(arglist, string);
1201 tokptr = va_arg(arglist, char **);
1202 while (tokptr) {
1203 while (*string && isspace((unsigned char) *string))
1204 string++;
1205 if (!*string)
1206 break;
1207 *tokptr = string;
1208 while (*string && !isspace((unsigned char) *string))
1209 string++;
1210 tokptr = va_arg(arglist, char **);
1211 tokcount++;
1212 if (!*string)
1213 break;
1214 *string++ = 0;
jardineb5d44e2003-12-23 08:09:43 +00001215 }
hassoffe543a2005-09-25 12:04:25 +00001216 va_end(arglist);
jardineb5d44e2003-12-23 08:09:43 +00001217
hassoffe543a2005-09-25 12:04:25 +00001218 return tokcount;
jardineb5d44e2003-12-23 08:09:43 +00001219}
1220
hassoffe543a2005-09-25 12:04:25 +00001221static int comparef(const void *key1, const void *key2)
jardineb5d44e2003-12-23 08:09:43 +00001222{
hassoffe543a2005-09-25 12:04:25 +00001223 return strcmp(key1, key2);
jardineb5d44e2003-12-23 08:09:43 +00001224}
1225
hassoffe543a2005-09-25 12:04:25 +00001226static char *dupstring(char *str)
jardineb5d44e2003-12-23 08:09:43 +00001227{
hassoffe543a2005-09-25 12:04:25 +00001228 int sz = strlen(str) + 1;
Josh Bailey3f045a02012-03-24 08:35:20 -07001229 char *new = XCALLOC(MTYPE_ISIS_TMP, sz);
hassoffe543a2005-09-25 12:04:25 +00001230 if (new)
1231 memcpy(new, str, sz);
1232 return new;
jardineb5d44e2003-12-23 08:09:43 +00001233}
1234
hassoffe543a2005-09-25 12:04:25 +00001235static dnode_t *new_node(void *c)
jardineb5d44e2003-12-23 08:09:43 +00001236{
hassoffe543a2005-09-25 12:04:25 +00001237 static dnode_t few[5];
1238 static int count;
jardineb5d44e2003-12-23 08:09:43 +00001239
hassoffe543a2005-09-25 12:04:25 +00001240 if (count < 5)
1241 return few + count++;
jardineb5d44e2003-12-23 08:09:43 +00001242
hassoffe543a2005-09-25 12:04:25 +00001243 return NULL;
jardineb5d44e2003-12-23 08:09:43 +00001244}
1245
hassoffe543a2005-09-25 12:04:25 +00001246static void del_node(dnode_t *n, void *c)
jardineb5d44e2003-12-23 08:09:43 +00001247{
1248}
1249
1250static int prompt = 0;
1251
hassoffe543a2005-09-25 12:04:25 +00001252static void construct(dict_t *d)
jardineb5d44e2003-12-23 08:09:43 +00001253{
hassoffe543a2005-09-25 12:04:25 +00001254 input_t in;
1255 int done = 0;
1256 dict_load_t dl;
1257 dnode_t *dn;
1258 char *tok1, *tok2, *val;
1259 const char *key;
1260 char *help =
1261 "p turn prompt on\n"
1262 "q finish construction\n"
1263 "a <key> <val> add new entry\n";
jardineb5d44e2003-12-23 08:09:43 +00001264
hassoffe543a2005-09-25 12:04:25 +00001265 if (!dict_isempty(d))
1266 puts("warning: dictionary not empty!");
jardineb5d44e2003-12-23 08:09:43 +00001267
hassoffe543a2005-09-25 12:04:25 +00001268 dict_load_begin(&dl, d);
jardineb5d44e2003-12-23 08:09:43 +00001269
hassoffe543a2005-09-25 12:04:25 +00001270 while (!done) {
1271 if (prompt)
1272 putchar('>');
1273 fflush(stdout);
jardineb5d44e2003-12-23 08:09:43 +00001274
hassoffe543a2005-09-25 12:04:25 +00001275 if (!fgets(in, sizeof(input_t), stdin))
1276 break;
jardineb5d44e2003-12-23 08:09:43 +00001277
hassoffe543a2005-09-25 12:04:25 +00001278 switch (in[0]) {
1279 case '?':
1280 puts(help);
1281 break;
1282 case 'p':
1283 prompt = 1;
1284 break;
1285 case 'q':
1286 done = 1;
1287 break;
1288 case 'a':
1289 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1290 puts("what?");
1291 break;
1292 }
1293 key = dupstring(tok1);
1294 val = dupstring(tok2);
1295 dn = dnode_create(val);
jardineb5d44e2003-12-23 08:09:43 +00001296
hassoffe543a2005-09-25 12:04:25 +00001297 if (!key || !val || !dn) {
1298 puts("out of memory");
1299 free((void *) key);
1300 free(val);
1301 if (dn)
1302 dnode_destroy(dn);
1303 }
jardineb5d44e2003-12-23 08:09:43 +00001304
hassoffe543a2005-09-25 12:04:25 +00001305 dict_load_next(&dl, dn, key);
1306 break;
1307 default:
1308 putchar('?');
1309 putchar('\n');
1310 break;
jardineb5d44e2003-12-23 08:09:43 +00001311 }
1312 }
1313
hassoffe543a2005-09-25 12:04:25 +00001314 dict_load_end(&dl);
jardineb5d44e2003-12-23 08:09:43 +00001315}
1316
hassoffe543a2005-09-25 12:04:25 +00001317int main(void)
jardineb5d44e2003-12-23 08:09:43 +00001318{
hassoffe543a2005-09-25 12:04:25 +00001319 input_t in;
1320 dict_t darray[10];
1321 dict_t *d = &darray[0];
1322 dnode_t *dn;
1323 int i;
1324 char *tok1, *tok2, *val;
1325 const char *key;
jardineb5d44e2003-12-23 08:09:43 +00001326
hassoffe543a2005-09-25 12:04:25 +00001327 char *help =
1328 "a <key> <val> add value to dictionary\n"
1329 "d <key> delete value from dictionary\n"
1330 "l <key> lookup value in dictionary\n"
1331 "( <key> lookup lower bound\n"
1332 ") <key> lookup upper bound\n"
1333 "# <num> switch to alternate dictionary (0-9)\n"
1334 "j <num> <num> merge two dictionaries\n"
1335 "f free the whole dictionary\n"
1336 "k allow duplicate keys\n"
1337 "c show number of entries\n"
1338 "t dump whole dictionary in sort order\n"
1339 "m make dictionary out of sorted items\n"
1340 "p turn prompt on\n"
1341 "s switch to non-functioning allocator\n"
1342 "q quit";
jardineb5d44e2003-12-23 08:09:43 +00001343
Josh Bailey3f045a02012-03-24 08:35:20 -07001344 for (i = 0; i < 10; i++)
hassoffe543a2005-09-25 12:04:25 +00001345 dict_init(&darray[i], DICTCOUNT_T_MAX, comparef);
jardineb5d44e2003-12-23 08:09:43 +00001346
hassoffe543a2005-09-25 12:04:25 +00001347 for (;;) {
1348 if (prompt)
1349 putchar('>');
1350 fflush(stdout);
jardineb5d44e2003-12-23 08:09:43 +00001351
hassoffe543a2005-09-25 12:04:25 +00001352 if (!fgets(in, sizeof(input_t), stdin))
1353 break;
jardineb5d44e2003-12-23 08:09:43 +00001354
hassoffe543a2005-09-25 12:04:25 +00001355 switch(in[0]) {
1356 case '?':
1357 puts(help);
1358 break;
1359 case 'a':
1360 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1361 puts("what?");
1362 break;
1363 }
1364 key = dupstring(tok1);
1365 val = dupstring(tok2);
jardineb5d44e2003-12-23 08:09:43 +00001366
hassoffe543a2005-09-25 12:04:25 +00001367 if (!key || !val) {
1368 puts("out of memory");
1369 free((void *) key);
1370 free(val);
1371 }
jardineb5d44e2003-12-23 08:09:43 +00001372
hassoffe543a2005-09-25 12:04:25 +00001373 if (!dict_alloc_insert(d, key, val)) {
1374 puts("dict_alloc_insert failed");
1375 free((void *) key);
1376 free(val);
1377 break;
1378 }
1379 break;
1380 case 'd':
1381 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1382 puts("what?");
1383 break;
1384 }
1385 dn = dict_lookup(d, tok1);
1386 if (!dn) {
1387 puts("dict_lookup failed");
1388 break;
1389 }
1390 val = dnode_get(dn);
1391 key = dnode_getkey(dn);
1392 dict_delete_free(d, dn);
jardineb5d44e2003-12-23 08:09:43 +00001393
hassoffe543a2005-09-25 12:04:25 +00001394 free(val);
1395 free((void *) key);
1396 break;
1397 case 'f':
1398 dict_free(d);
1399 break;
jardineb5d44e2003-12-23 08:09:43 +00001400 case 'l':
1401 case '(':
1402 case ')':
hassoffe543a2005-09-25 12:04:25 +00001403 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1404 puts("what?");
1405 break;
jardineb5d44e2003-12-23 08:09:43 +00001406 }
hassoffe543a2005-09-25 12:04:25 +00001407 dn = 0;
1408 switch (in[0]) {
1409 case 'l':
1410 dn = dict_lookup(d, tok1);
1411 break;
1412 case '(':
1413 dn = dict_lower_bound(d, tok1);
1414 break;
1415 case ')':
1416 dn = dict_upper_bound(d, tok1);
1417 break;
jardineb5d44e2003-12-23 08:09:43 +00001418 }
hassoffe543a2005-09-25 12:04:25 +00001419 if (!dn) {
1420 puts("lookup failed");
1421 break;
1422 }
1423 val = dnode_get(dn);
1424 puts(val);
1425 break;
1426 case 'm':
1427 construct(d);
1428 break;
1429 case 'k':
1430 dict_allow_dupes(d);
1431 break;
1432 case 'c':
1433 printf("%lu\n", (unsigned long) dict_count(d));
1434 break;
1435 case 't':
1436 for (dn = dict_first(d); dn; dn = dict_next(d, dn)) {
1437 printf("%s\t%s\n", (char *) dnode_getkey(dn),
1438 (char *) dnode_get(dn));
1439 }
1440 break;
1441 case 'q':
1442 exit(0);
1443 break;
1444 case '\0':
1445 break;
1446 case 'p':
1447 prompt = 1;
1448 break;
1449 case 's':
1450 dict_set_allocator(d, new_node, del_node, NULL);
1451 break;
1452 case '#':
1453 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1454 puts("what?");
1455 break;
1456 } else {
1457 int dictnum = atoi(tok1);
1458 if (dictnum < 0 || dictnum > 9) {
1459 puts("invalid number");
1460 break;
1461 }
1462 d = &darray[dictnum];
1463 }
1464 break;
1465 case 'j':
1466 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1467 puts("what?");
1468 break;
1469 } else {
1470 int dict1 = atoi(tok1), dict2 = atoi(tok2);
1471 if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) {
1472 puts("invalid number");
1473 break;
1474 }
1475 dict_merge(&darray[dict1], &darray[dict2]);
1476 }
1477 break;
1478 default:
1479 putchar('?');
1480 putchar('\n');
1481 break;
jardineb5d44e2003-12-23 08:09:43 +00001482 }
1483 }
1484
hassoffe543a2005-09-25 12:04:25 +00001485 return 0;
jardineb5d44e2003-12-23 08:09:43 +00001486}
1487
1488#endif