blob: bbcb42134d1e34018b818a09630d2f6cfafef4ad [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.
jardineb5d44e2003-12-23 08:09:43 +000016 */
17
Paul Jakma238497f2007-08-07 18:49:18 +000018#include "zebra.h"
ajscee3df12004-11-24 17:14:49 +000019#include "zassert.h"
Josh Bailey3f045a02012-03-24 08:35:20 -070020#include "memory.h"
jardineb5d44e2003-12-23 08:09:43 +000021#include "dict.h"
22
jardineb5d44e2003-12-23 08:09:43 +000023/*
24 * These macros provide short convenient names for structure members,
25 * which are embellished with dict_ prefixes so that they are
26 * properly confined to the documented namespace. It's legal for a
27 * program which uses dict to define, for instance, a macro called ``parent''.
28 * Such a macro would interfere with the dnode_t struct definition.
29 * In general, highly portable and reusable C modules which expose their
30 * structures need to confine structure member names to well-defined spaces.
31 * The resulting identifiers aren't necessarily convenient to use, nor
32 * readable, in the implementation, however!
33 */
34
35#define left dict_left
36#define right dict_right
37#define parent dict_parent
38#define color dict_color
39#define key dict_key
40#define data dict_data
41
42#define nilnode dict_nilnode
43#define nodecount dict_nodecount
44#define maxcount dict_maxcount
45#define compare dict_compare
46#define allocnode dict_allocnode
47#define freenode dict_freenode
48#define context dict_context
49#define dupes dict_dupes
50
51#define dictptr dict_dictptr
52
53#define dict_root(D) ((D)->nilnode.left)
54#define dict_nil(D) (&(D)->nilnode)
55#define DICT_DEPTH_MAX 64
56
hassoffe543a2005-09-25 12:04:25 +000057static dnode_t *dnode_alloc(void *context);
58static void dnode_free(dnode_t *node, void *context);
jardineb5d44e2003-12-23 08:09:43 +000059
60/*
61 * Perform a ``left rotation'' adjustment on the tree. The given node P and
62 * its right child C are rearranged so that the P instead becomes the left
63 * child of C. The left subtree of C is inherited as the new right subtree
64 * for P. The ordering of the keys within the tree is thus preserved.
65 */
66
hassoffe543a2005-09-25 12:04:25 +000067static void rotate_left(dnode_t *upper)
jardineb5d44e2003-12-23 08:09:43 +000068{
hassoffe543a2005-09-25 12:04:25 +000069 dnode_t *lower, *lowleft, *upparent;
jardineb5d44e2003-12-23 08:09:43 +000070
hassoffe543a2005-09-25 12:04:25 +000071 lower = upper->right;
72 upper->right = lowleft = lower->left;
73 lowleft->parent = upper;
jardineb5d44e2003-12-23 08:09:43 +000074
hassoffe543a2005-09-25 12:04:25 +000075 lower->parent = upparent = upper->parent;
jardineb5d44e2003-12-23 08:09:43 +000076
hassoffe543a2005-09-25 12:04:25 +000077 /* don't need to check for root node here because root->parent is
78 the sentinel nil node, and root->parent->left points back to root */
jardineb5d44e2003-12-23 08:09:43 +000079
hassoffe543a2005-09-25 12:04:25 +000080 if (upper == upparent->left) {
81 upparent->left = lower;
82 } else {
83 assert (upper == upparent->right);
84 upparent->right = lower;
jardineb5d44e2003-12-23 08:09:43 +000085 }
86
hassoffe543a2005-09-25 12:04:25 +000087 lower->left = upper;
88 upper->parent = lower;
jardineb5d44e2003-12-23 08:09:43 +000089}
90
91/*
92 * This operation is the ``mirror'' image of rotate_left. It is
93 * the same procedure, but with left and right interchanged.
94 */
95
hassoffe543a2005-09-25 12:04:25 +000096static void rotate_right(dnode_t *upper)
jardineb5d44e2003-12-23 08:09:43 +000097{
hassoffe543a2005-09-25 12:04:25 +000098 dnode_t *lower, *lowright, *upparent;
jardineb5d44e2003-12-23 08:09:43 +000099
hassoffe543a2005-09-25 12:04:25 +0000100 lower = upper->left;
101 upper->left = lowright = lower->right;
102 lowright->parent = upper;
jardineb5d44e2003-12-23 08:09:43 +0000103
hassoffe543a2005-09-25 12:04:25 +0000104 lower->parent = upparent = upper->parent;
jardineb5d44e2003-12-23 08:09:43 +0000105
hassoffe543a2005-09-25 12:04:25 +0000106 if (upper == upparent->right) {
107 upparent->right = lower;
108 } else {
109 assert (upper == upparent->left);
110 upparent->left = lower;
jardineb5d44e2003-12-23 08:09:43 +0000111 }
112
hassoffe543a2005-09-25 12:04:25 +0000113 lower->right = upper;
114 upper->parent = lower;
jardineb5d44e2003-12-23 08:09:43 +0000115}
116
117/*
118 * Do a postorder traversal of the tree rooted at the specified
119 * node and free everything under it. Used by dict_free().
120 */
121
hassoffe543a2005-09-25 12:04:25 +0000122static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
jardineb5d44e2003-12-23 08:09:43 +0000123{
hassoffe543a2005-09-25 12:04:25 +0000124 if (node == nil)
125 return;
126 free_nodes(dict, node->left, nil);
127 free_nodes(dict, node->right, nil);
128 dict->freenode(node, dict->context);
jardineb5d44e2003-12-23 08:09:43 +0000129}
130
131/*
132 * This procedure performs a verification that the given subtree is a binary
133 * search tree. It performs an inorder traversal of the tree using the
134 * dict_next() successor function, verifying that the key of each node is
135 * strictly lower than that of its successor, if duplicates are not allowed,
136 * or lower or equal if duplicates are allowed. This function is used for
137 * debugging purposes.
138 */
139
hassoffe543a2005-09-25 12:04:25 +0000140static int verify_bintree(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000141{
hassoffe543a2005-09-25 12:04:25 +0000142 dnode_t *first, *next;
jardineb5d44e2003-12-23 08:09:43 +0000143
hassoffe543a2005-09-25 12:04:25 +0000144 first = dict_first(dict);
jardineb5d44e2003-12-23 08:09:43 +0000145
hassoffe543a2005-09-25 12:04:25 +0000146 if (dict->dupes) {
147 while (first && (next = dict_next(dict, first))) {
148 if (dict->compare(first->key, next->key) > 0)
149 return 0;
150 first = next;
151 }
152 } else {
153 while (first && (next = dict_next(dict, first))) {
154 if (dict->compare(first->key, next->key) >= 0)
155 return 0;
156 first = next;
jardineb5d44e2003-12-23 08:09:43 +0000157 }
158 }
hassoffe543a2005-09-25 12:04:25 +0000159 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000160}
161
162
163/*
164 * This function recursively verifies that the given binary subtree satisfies
165 * three of the red black properties. It checks that every red node has only
166 * black children. It makes sure that each node is either red or black. And it
167 * checks that every path has the same count of black nodes from root to leaf.
168 * It returns the blackheight of the given subtree; this allows blackheights to
169 * be computed recursively and compared for left and right siblings for
170 * mismatches. It does not check for every nil node being black, because there
171 * is only one sentinel nil node. The return value of this function is the
172 * black height of the subtree rooted at the node ``root'', or zero if the
173 * subtree is not red-black.
174 */
175
hassoffe543a2005-09-25 12:04:25 +0000176static unsigned int verify_redblack(dnode_t *nil, dnode_t *root)
jardineb5d44e2003-12-23 08:09:43 +0000177{
hassoffe543a2005-09-25 12:04:25 +0000178 unsigned height_left, height_right;
jardineb5d44e2003-12-23 08:09:43 +0000179
hassoffe543a2005-09-25 12:04:25 +0000180 if (root != nil) {
181 height_left = verify_redblack(nil, root->left);
182 height_right = verify_redblack(nil, root->right);
183 if (height_left == 0 || height_right == 0)
jardineb5d44e2003-12-23 08:09:43 +0000184 return 0;
hassoffe543a2005-09-25 12:04:25 +0000185 if (height_left != height_right)
jardineb5d44e2003-12-23 08:09:43 +0000186 return 0;
hassoffe543a2005-09-25 12:04:25 +0000187 if (root->color == dnode_red) {
188 if (root->left->color != dnode_black)
189 return 0;
190 if (root->right->color != dnode_black)
191 return 0;
192 return height_left;
jardineb5d44e2003-12-23 08:09:43 +0000193 }
hassoffe543a2005-09-25 12:04:25 +0000194 if (root->color != dnode_black)
195 return 0;
196 return height_left + 1;
197 }
198 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000199}
200
201/*
202 * Compute the actual count of nodes by traversing the tree and
203 * return it. This could be compared against the stored count to
204 * detect a mismatch.
205 */
206
hassoffe543a2005-09-25 12:04:25 +0000207static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root)
jardineb5d44e2003-12-23 08:09:43 +0000208{
hassoffe543a2005-09-25 12:04:25 +0000209 if (root == nil)
210 return 0;
211 else
212 return 1 + verify_node_count(nil, root->left)
213 + verify_node_count(nil, root->right);
jardineb5d44e2003-12-23 08:09:43 +0000214}
215
216/*
217 * Verify that the tree contains the given node. This is done by
218 * traversing all of the nodes and comparing their pointers to the
219 * given pointer. Returns 1 if the node is found, otherwise
220 * returns zero. It is intended for debugging purposes.
221 */
222
hassoffe543a2005-09-25 12:04:25 +0000223static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
jardineb5d44e2003-12-23 08:09:43 +0000224{
hassoffe543a2005-09-25 12:04:25 +0000225 if (root != nil) {
226 return root == node
227 || verify_dict_has_node(nil, root->left, node)
228 || verify_dict_has_node(nil, root->right, node);
jardineb5d44e2003-12-23 08:09:43 +0000229 }
hassoffe543a2005-09-25 12:04:25 +0000230 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000231}
232
hassoffe543a2005-09-25 12:04:25 +0000233
jardineb5d44e2003-12-23 08:09:43 +0000234/*
235 * Dynamically allocate and initialize a dictionary object.
236 */
237
hassoffe543a2005-09-25 12:04:25 +0000238dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp)
jardineb5d44e2003-12-23 08:09:43 +0000239{
Josh Bailey3f045a02012-03-24 08:35:20 -0700240 dict_t *new = XCALLOC(MTYPE_ISIS_DICT, sizeof(dict_t));
jardineb5d44e2003-12-23 08:09:43 +0000241
hassoffe543a2005-09-25 12:04:25 +0000242 if (new) {
243 new->compare = comp;
244 new->allocnode = dnode_alloc;
245 new->freenode = dnode_free;
246 new->context = NULL;
247 new->nodecount = 0;
248 new->maxcount = maxcount;
249 new->nilnode.left = &new->nilnode;
250 new->nilnode.right = &new->nilnode;
251 new->nilnode.parent = &new->nilnode;
252 new->nilnode.color = dnode_black;
253 new->dupes = 0;
jardineb5d44e2003-12-23 08:09:43 +0000254 }
hassoffe543a2005-09-25 12:04:25 +0000255 return new;
jardineb5d44e2003-12-23 08:09:43 +0000256}
257
258/*
259 * Select a different set of node allocator routines.
260 */
261
hassoffe543a2005-09-25 12:04:25 +0000262void dict_set_allocator(dict_t *dict, dnode_alloc_t al,
263 dnode_free_t fr, void *context)
jardineb5d44e2003-12-23 08:09:43 +0000264{
hassoffe543a2005-09-25 12:04:25 +0000265 assert (dict_count(dict) == 0);
266 assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL));
jardineb5d44e2003-12-23 08:09:43 +0000267
hassoffe543a2005-09-25 12:04:25 +0000268 dict->allocnode = al ? al : dnode_alloc;
269 dict->freenode = fr ? fr : dnode_free;
270 dict->context = context;
jardineb5d44e2003-12-23 08:09:43 +0000271}
272
273/*
274 * Free a dynamically allocated dictionary object. Removing the nodes
275 * from the tree before deleting it is required.
276 */
277
hassoffe543a2005-09-25 12:04:25 +0000278void dict_destroy(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000279{
hassoffe543a2005-09-25 12:04:25 +0000280 assert (dict_isempty(dict));
Josh Bailey3f045a02012-03-24 08:35:20 -0700281 XFREE(MTYPE_ISIS_DICT, dict);
jardineb5d44e2003-12-23 08:09:43 +0000282}
283
284/*
285 * Free all the nodes in the dictionary by using the dictionary's
286 * installed free routine. The dictionary is emptied.
287 */
288
hassoffe543a2005-09-25 12:04:25 +0000289void dict_free_nodes(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000290{
hassoffe543a2005-09-25 12:04:25 +0000291 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
292 free_nodes(dict, root, nil);
293 dict->nodecount = 0;
294 dict->nilnode.left = &dict->nilnode;
295 dict->nilnode.right = &dict->nilnode;
jardineb5d44e2003-12-23 08:09:43 +0000296}
297
298/*
299 * Obsolescent function, equivalent to dict_free_nodes
300 */
301
hassoffe543a2005-09-25 12:04:25 +0000302void dict_free(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000303{
hassoffe543a2005-09-25 12:04:25 +0000304 dict_free_nodes(dict);
jardineb5d44e2003-12-23 08:09:43 +0000305}
306
307/*
308 * Initialize a user-supplied dictionary object.
309 */
310
hassoffe543a2005-09-25 12:04:25 +0000311dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
jardineb5d44e2003-12-23 08:09:43 +0000312{
hassoffe543a2005-09-25 12:04:25 +0000313 dict->compare = comp;
314 dict->allocnode = dnode_alloc;
315 dict->freenode = dnode_free;
316 dict->context = NULL;
317 dict->nodecount = 0;
318 dict->maxcount = maxcount;
319 dict->nilnode.left = &dict->nilnode;
320 dict->nilnode.right = &dict->nilnode;
321 dict->nilnode.parent = &dict->nilnode;
322 dict->nilnode.color = dnode_black;
323 dict->dupes = 0;
324 return dict;
jardineb5d44e2003-12-23 08:09:43 +0000325}
326
327/*
328 * Initialize a dictionary in the likeness of another dictionary
329 */
330
hassoffe543a2005-09-25 12:04:25 +0000331void dict_init_like(dict_t *dict, const dict_t *template)
jardineb5d44e2003-12-23 08:09:43 +0000332{
hassoffe543a2005-09-25 12:04:25 +0000333 dict->compare = template->compare;
334 dict->allocnode = template->allocnode;
335 dict->freenode = template->freenode;
336 dict->context = template->context;
337 dict->nodecount = 0;
338 dict->maxcount = template->maxcount;
339 dict->nilnode.left = &dict->nilnode;
340 dict->nilnode.right = &dict->nilnode;
341 dict->nilnode.parent = &dict->nilnode;
342 dict->nilnode.color = dnode_black;
343 dict->dupes = template->dupes;
jardineb5d44e2003-12-23 08:09:43 +0000344
hassoffe543a2005-09-25 12:04:25 +0000345 assert (dict_similar(dict, template));
jardineb5d44e2003-12-23 08:09:43 +0000346}
347
348/*
349 * Remove all nodes from the dictionary (without freeing them in any way).
350 */
351
hassoffe543a2005-09-25 12:04:25 +0000352static void dict_clear(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000353{
hassoffe543a2005-09-25 12:04:25 +0000354 dict->nodecount = 0;
355 dict->nilnode.left = &dict->nilnode;
356 dict->nilnode.right = &dict->nilnode;
357 dict->nilnode.parent = &dict->nilnode;
358 assert (dict->nilnode.color == dnode_black);
jardineb5d44e2003-12-23 08:09:43 +0000359}
360
hassoffe543a2005-09-25 12:04:25 +0000361
jardineb5d44e2003-12-23 08:09:43 +0000362/*
363 * Verify the integrity of the dictionary structure. This is provided for
364 * debugging purposes, and should be placed in assert statements. Just because
365 * this function succeeds doesn't mean that the tree is not corrupt. Certain
366 * corruptions in the tree may simply cause undefined behavior.
hassoffe543a2005-09-25 12:04:25 +0000367 */
jardineb5d44e2003-12-23 08:09:43 +0000368
hassoffe543a2005-09-25 12:04:25 +0000369int dict_verify(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000370{
hassoffe543a2005-09-25 12:04:25 +0000371 dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
jardineb5d44e2003-12-23 08:09:43 +0000372
hassoffe543a2005-09-25 12:04:25 +0000373 /* check that the sentinel node and root node are black */
374 if (root->color != dnode_black)
375 return 0;
376 if (nil->color != dnode_black)
377 return 0;
378 if (nil->right != nil)
379 return 0;
380 /* nil->left is the root node; check that its parent pointer is nil */
381 if (nil->left->parent != nil)
382 return 0;
383 /* perform a weak test that the tree is a binary search tree */
384 if (!verify_bintree(dict))
385 return 0;
386 /* verify that the tree is a red-black tree */
387 if (!verify_redblack(nil, root))
388 return 0;
389 if (verify_node_count(nil, root) != dict_count(dict))
390 return 0;
391 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000392}
393
394/*
395 * Determine whether two dictionaries are similar: have the same comparison and
396 * allocator functions, and same status as to whether duplicates are allowed.
397 */
398
hassoffe543a2005-09-25 12:04:25 +0000399int dict_similar(const dict_t *left, const dict_t *right)
jardineb5d44e2003-12-23 08:09:43 +0000400{
hassoffe543a2005-09-25 12:04:25 +0000401 if (left->compare != right->compare)
402 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000403
hassoffe543a2005-09-25 12:04:25 +0000404 if (left->allocnode != right->allocnode)
405 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000406
hassoffe543a2005-09-25 12:04:25 +0000407 if (left->freenode != right->freenode)
408 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000409
hassoffe543a2005-09-25 12:04:25 +0000410 if (left->context != right->context)
411 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000412
hassoffe543a2005-09-25 12:04:25 +0000413 if (left->dupes != right->dupes)
414 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000415
hassoffe543a2005-09-25 12:04:25 +0000416 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000417}
418
419/*
420 * Locate a node in the dictionary having the given key.
421 * If the node is not found, a null a pointer is returned (rather than
422 * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
423 * located node is returned.
424 */
425
hassoffe543a2005-09-25 12:04:25 +0000426dnode_t *dict_lookup(dict_t *dict, const void *key)
jardineb5d44e2003-12-23 08:09:43 +0000427{
hassoffe543a2005-09-25 12:04:25 +0000428 dnode_t *root = dict_root(dict);
429 dnode_t *nil = dict_nil(dict);
430 dnode_t *saved;
431 int result;
jardineb5d44e2003-12-23 08:09:43 +0000432
hassoffe543a2005-09-25 12:04:25 +0000433 /* simple binary search adapted for trees that contain duplicate keys */
jardineb5d44e2003-12-23 08:09:43 +0000434
hassoffe543a2005-09-25 12:04:25 +0000435 while (root != nil) {
436 result = dict->compare(key, root->key);
437 if (result < 0)
438 root = root->left;
439 else if (result > 0)
440 root = root->right;
441 else {
442 if (!dict->dupes) { /* no duplicates, return match */
443 return root;
444 } else { /* could be dupes, find leftmost one */
445 do {
446 saved = root;
447 root = root->left;
448 while (root != nil && dict->compare(key, root->key))
449 root = root->right;
450 } while (root != nil);
451 return saved;
jardineb5d44e2003-12-23 08:09:43 +0000452 }
453 }
454 }
455
hassoffe543a2005-09-25 12:04:25 +0000456 return NULL;
jardineb5d44e2003-12-23 08:09:43 +0000457}
458
459/*
460 * Look for the node corresponding to the lowest key that is equal to or
461 * greater than the given key. If there is no such node, return null.
462 */
463
hassoffe543a2005-09-25 12:04:25 +0000464dnode_t *dict_lower_bound(dict_t *dict, const void *key)
jardineb5d44e2003-12-23 08:09:43 +0000465{
hassoffe543a2005-09-25 12:04:25 +0000466 dnode_t *root = dict_root(dict);
467 dnode_t *nil = dict_nil(dict);
468 dnode_t *tentative = 0;
jardineb5d44e2003-12-23 08:09:43 +0000469
hassoffe543a2005-09-25 12:04:25 +0000470 while (root != nil) {
471 int result = dict->compare(key, root->key);
jardineb5d44e2003-12-23 08:09:43 +0000472
hassoffe543a2005-09-25 12:04:25 +0000473 if (result > 0) {
474 root = root->right;
475 } else if (result < 0) {
476 tentative = root;
477 root = root->left;
478 } else {
479 if (!dict->dupes) {
480 return root;
481 } else {
482 tentative = root;
483 root = root->left;
jardineb5d44e2003-12-23 08:09:43 +0000484 }
hassoffe543a2005-09-25 12:04:25 +0000485 }
jardineb5d44e2003-12-23 08:09:43 +0000486 }
hassoffe543a2005-09-25 12:04:25 +0000487
488 return tentative;
jardineb5d44e2003-12-23 08:09:43 +0000489}
490
491/*
492 * Look for the node corresponding to the greatest key that is equal to or
493 * lower than the given key. If there is no such node, return null.
494 */
495
hassoffe543a2005-09-25 12:04:25 +0000496dnode_t *dict_upper_bound(dict_t *dict, const void *key)
jardineb5d44e2003-12-23 08:09:43 +0000497{
hassoffe543a2005-09-25 12:04:25 +0000498 dnode_t *root = dict_root(dict);
499 dnode_t *nil = dict_nil(dict);
500 dnode_t *tentative = 0;
jardineb5d44e2003-12-23 08:09:43 +0000501
hassoffe543a2005-09-25 12:04:25 +0000502 while (root != nil) {
503 int result = dict->compare(key, root->key);
jardineb5d44e2003-12-23 08:09:43 +0000504
hassoffe543a2005-09-25 12:04:25 +0000505 if (result < 0) {
506 root = root->left;
507 } else if (result > 0) {
508 tentative = root;
509 root = root->right;
510 } else {
511 if (!dict->dupes) {
512 return root;
513 } else {
514 tentative = root;
515 root = root->right;
jardineb5d44e2003-12-23 08:09:43 +0000516 }
hassoffe543a2005-09-25 12:04:25 +0000517 }
jardineb5d44e2003-12-23 08:09:43 +0000518 }
hassoffe543a2005-09-25 12:04:25 +0000519
520 return tentative;
jardineb5d44e2003-12-23 08:09:43 +0000521}
522
523/*
524 * Insert a node into the dictionary. The node should have been
525 * initialized with a data field. All other fields are ignored.
526 * The behavior is undefined if the user attempts to insert into
527 * a dictionary that is already full (for which the dict_isfull()
528 * function returns true).
529 */
530
hassoffe543a2005-09-25 12:04:25 +0000531void dict_insert(dict_t *dict, dnode_t *node, const void *key)
jardineb5d44e2003-12-23 08:09:43 +0000532{
hassoffe543a2005-09-25 12:04:25 +0000533 dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
534 dnode_t *parent = nil, *uncle, *grandpa;
535 int result = -1;
jardineb5d44e2003-12-23 08:09:43 +0000536
hassoffe543a2005-09-25 12:04:25 +0000537 node->key = key;
jardineb5d44e2003-12-23 08:09:43 +0000538
hassoffe543a2005-09-25 12:04:25 +0000539 assert (!dict_isfull(dict));
540 assert (!dict_contains(dict, node));
541 assert (!dnode_is_in_a_dict(node));
jardineb5d44e2003-12-23 08:09:43 +0000542
hassoffe543a2005-09-25 12:04:25 +0000543 /* basic binary tree insert */
jardineb5d44e2003-12-23 08:09:43 +0000544
hassoffe543a2005-09-25 12:04:25 +0000545 while (where != nil) {
546 parent = where;
547 result = dict->compare(key, where->key);
548 /* trap attempts at duplicate key insertion unless it's explicitly allowed */
549 assert (dict->dupes || result != 0);
550 if (result < 0)
551 where = where->left;
552 else
553 where = where->right;
jardineb5d44e2003-12-23 08:09:43 +0000554 }
555
hassoffe543a2005-09-25 12:04:25 +0000556 assert (where == nil);
jardineb5d44e2003-12-23 08:09:43 +0000557
hassoffe543a2005-09-25 12:04:25 +0000558 if (result < 0)
559 parent->left = node;
560 else
561 parent->right = node;
jardineb5d44e2003-12-23 08:09:43 +0000562
hassoffe543a2005-09-25 12:04:25 +0000563 node->parent = parent;
564 node->left = nil;
565 node->right = nil;
jardineb5d44e2003-12-23 08:09:43 +0000566
hassoffe543a2005-09-25 12:04:25 +0000567 dict->nodecount++;
jardineb5d44e2003-12-23 08:09:43 +0000568
hassoffe543a2005-09-25 12:04:25 +0000569 /* red black adjustments */
jardineb5d44e2003-12-23 08:09:43 +0000570
hassoffe543a2005-09-25 12:04:25 +0000571 node->color = dnode_red;
jardineb5d44e2003-12-23 08:09:43 +0000572
hassoffe543a2005-09-25 12:04:25 +0000573 while (parent->color == dnode_red) {
574 grandpa = parent->parent;
575 if (parent == grandpa->left) {
576 uncle = grandpa->right;
577 if (uncle->color == dnode_red) { /* red parent, red uncle */
578 parent->color = dnode_black;
579 uncle->color = dnode_black;
580 grandpa->color = dnode_red;
581 node = grandpa;
582 parent = grandpa->parent;
583 } else { /* red parent, black uncle */
584 if (node == parent->right) {
585 rotate_left(parent);
586 parent = node;
587 assert (grandpa == parent->parent);
588 /* rotation between parent and child preserves grandpa */
jardineb5d44e2003-12-23 08:09:43 +0000589 }
hassoffe543a2005-09-25 12:04:25 +0000590 parent->color = dnode_black;
591 grandpa->color = dnode_red;
592 rotate_right(grandpa);
593 break;
hassof390d2c2004-09-10 20:48:21 +0000594 }
hassoffe543a2005-09-25 12:04:25 +0000595 } else { /* symmetric cases: parent == parent->parent->right */
596 uncle = grandpa->left;
597 if (uncle->color == dnode_red) {
598 parent->color = dnode_black;
599 uncle->color = dnode_black;
600 grandpa->color = dnode_red;
601 node = grandpa;
602 parent = grandpa->parent;
603 } else {
604 if (node == parent->left) {
605 rotate_right(parent);
606 parent = node;
607 assert (grandpa == parent->parent);
hassof390d2c2004-09-10 20:48:21 +0000608 }
hassoffe543a2005-09-25 12:04:25 +0000609 parent->color = dnode_black;
610 grandpa->color = dnode_red;
611 rotate_left(grandpa);
612 break;
jardineb5d44e2003-12-23 08:09:43 +0000613 }
614 }
615 }
616
hassoffe543a2005-09-25 12:04:25 +0000617 dict_root(dict)->color = dnode_black;
jardineb5d44e2003-12-23 08:09:43 +0000618
hassoffe543a2005-09-25 12:04:25 +0000619 assert (dict_verify(dict));
jardineb5d44e2003-12-23 08:09:43 +0000620}
621
622/*
623 * Delete the given node from the dictionary. If the given node does not belong
624 * to the given dictionary, undefined behavior results. A pointer to the
625 * deleted node is returned.
626 */
627
hassoffe543a2005-09-25 12:04:25 +0000628dnode_t *dict_delete(dict_t *dict, dnode_t *delete)
jardineb5d44e2003-12-23 08:09:43 +0000629{
hassoffe543a2005-09-25 12:04:25 +0000630 dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent;
jardineb5d44e2003-12-23 08:09:43 +0000631
hassoffe543a2005-09-25 12:04:25 +0000632 /* basic deletion */
jardineb5d44e2003-12-23 08:09:43 +0000633
hassoffe543a2005-09-25 12:04:25 +0000634 assert (!dict_isempty(dict));
635 assert (dict_contains(dict, delete));
jardineb5d44e2003-12-23 08:09:43 +0000636
hassoffe543a2005-09-25 12:04:25 +0000637 /*
638 * If the node being deleted has two children, then we replace it with its
639 * successor (i.e. the leftmost node in the right subtree.) By doing this,
640 * we avoid the traditional algorithm under which the successor's key and
641 * value *only* move to the deleted node and the successor is spliced out
642 * from the tree. We cannot use this approach because the user may hold
643 * pointers to the successor, or nodes may be inextricably tied to some
644 * other structures by way of embedding, etc. So we must splice out the
645 * node we are given, not some other node, and must not move contents from
646 * one node to another behind the user's back.
647 */
jardineb5d44e2003-12-23 08:09:43 +0000648
hassoffe543a2005-09-25 12:04:25 +0000649 if (delete->left != nil && delete->right != nil) {
650 dnode_t *next = dict_next(dict, delete);
651 dnode_t *nextparent = next->parent;
652 dnode_color_t nextcolor = next->color;
jardineb5d44e2003-12-23 08:09:43 +0000653
hassoffe543a2005-09-25 12:04:25 +0000654 assert (next != nil);
655 assert (next->parent != nil);
656 assert (next->left == nil);
jardineb5d44e2003-12-23 08:09:43 +0000657
hassoffe543a2005-09-25 12:04:25 +0000658 /*
659 * First, splice out the successor from the tree completely, by
660 * moving up its right child into its place.
661 */
jardineb5d44e2003-12-23 08:09:43 +0000662
hassoffe543a2005-09-25 12:04:25 +0000663 child = next->right;
664 child->parent = nextparent;
jardineb5d44e2003-12-23 08:09:43 +0000665
hassoffe543a2005-09-25 12:04:25 +0000666 if (nextparent->left == next) {
667 nextparent->left = child;
668 } else {
669 assert (nextparent->right == next);
670 nextparent->right = child;
jardineb5d44e2003-12-23 08:09:43 +0000671 }
672
hassoffe543a2005-09-25 12:04:25 +0000673 /*
674 * Now that the successor has been extricated from the tree, install it
675 * in place of the node that we want deleted.
676 */
jardineb5d44e2003-12-23 08:09:43 +0000677
hassoffe543a2005-09-25 12:04:25 +0000678 next->parent = delparent;
679 next->left = delete->left;
680 next->right = delete->right;
681 next->left->parent = next;
682 next->right->parent = next;
683 next->color = delete->color;
684 delete->color = nextcolor;
jardineb5d44e2003-12-23 08:09:43 +0000685
hassoffe543a2005-09-25 12:04:25 +0000686 if (delparent->left == delete) {
687 delparent->left = next;
688 } else {
689 assert (delparent->right == delete);
690 delparent->right = next;
jardineb5d44e2003-12-23 08:09:43 +0000691 }
692
hassoffe543a2005-09-25 12:04:25 +0000693 } else {
694 assert (delete != nil);
695 assert (delete->left == nil || delete->right == nil);
jardineb5d44e2003-12-23 08:09:43 +0000696
hassoffe543a2005-09-25 12:04:25 +0000697 child = (delete->left != nil) ? delete->left : delete->right;
jardineb5d44e2003-12-23 08:09:43 +0000698
hassoffe543a2005-09-25 12:04:25 +0000699 child->parent = delparent = delete->parent;
jardineb5d44e2003-12-23 08:09:43 +0000700
hassoffe543a2005-09-25 12:04:25 +0000701 if (delete == delparent->left) {
702 delparent->left = child;
703 } else {
704 assert (delete == delparent->right);
705 delparent->right = child;
jardineb5d44e2003-12-23 08:09:43 +0000706 }
707 }
708
hassoffe543a2005-09-25 12:04:25 +0000709 delete->parent = NULL;
710 delete->right = NULL;
711 delete->left = NULL;
jardineb5d44e2003-12-23 08:09:43 +0000712
hassoffe543a2005-09-25 12:04:25 +0000713 dict->nodecount--;
jardineb5d44e2003-12-23 08:09:43 +0000714
hassoffe543a2005-09-25 12:04:25 +0000715 assert (verify_bintree(dict));
jardineb5d44e2003-12-23 08:09:43 +0000716
hassoffe543a2005-09-25 12:04:25 +0000717 /* red-black adjustments */
jardineb5d44e2003-12-23 08:09:43 +0000718
hassoffe543a2005-09-25 12:04:25 +0000719 if (delete->color == dnode_black) {
720 dnode_t *parent, *sister;
jardineb5d44e2003-12-23 08:09:43 +0000721
hassoffe543a2005-09-25 12:04:25 +0000722 dict_root(dict)->color = dnode_red;
jardineb5d44e2003-12-23 08:09:43 +0000723
hassoffe543a2005-09-25 12:04:25 +0000724 while (child->color == dnode_black) {
725 parent = child->parent;
726 if (child == parent->left) {
727 sister = parent->right;
728 assert (sister != nil);
729 if (sister->color == dnode_red) {
730 sister->color = dnode_black;
731 parent->color = dnode_red;
732 rotate_left(parent);
733 sister = parent->right;
734 assert (sister != nil);
jardineb5d44e2003-12-23 08:09:43 +0000735 }
hassoffe543a2005-09-25 12:04:25 +0000736 if (sister->left->color == dnode_black
737 && sister->right->color == dnode_black) {
738 sister->color = dnode_red;
739 child = parent;
740 } else {
741 if (sister->right->color == dnode_black) {
742 assert (sister->left->color == dnode_red);
743 sister->left->color = dnode_black;
744 sister->color = dnode_red;
745 rotate_right(sister);
746 sister = parent->right;
747 assert (sister != nil);
jardineb5d44e2003-12-23 08:09:43 +0000748 }
hassoffe543a2005-09-25 12:04:25 +0000749 sister->color = parent->color;
750 sister->right->color = dnode_black;
751 parent->color = dnode_black;
752 rotate_left(parent);
753 break;
jardineb5d44e2003-12-23 08:09:43 +0000754 }
hassoffe543a2005-09-25 12:04:25 +0000755 } else { /* symmetric case: child == child->parent->right */
756 assert (child == parent->right);
757 sister = parent->left;
758 assert (sister != nil);
759 if (sister->color == dnode_red) {
760 sister->color = dnode_black;
761 parent->color = dnode_red;
762 rotate_right(parent);
763 sister = parent->left;
764 assert (sister != nil);
jardineb5d44e2003-12-23 08:09:43 +0000765 }
hassoffe543a2005-09-25 12:04:25 +0000766 if (sister->right->color == dnode_black
767 && sister->left->color == dnode_black) {
768 sister->color = dnode_red;
769 child = parent;
770 } else {
771 if (sister->left->color == dnode_black) {
772 assert (sister->right->color == dnode_red);
773 sister->right->color = dnode_black;
774 sister->color = dnode_red;
775 rotate_left(sister);
776 sister = parent->left;
777 assert (sister != nil);
jardineb5d44e2003-12-23 08:09:43 +0000778 }
hassoffe543a2005-09-25 12:04:25 +0000779 sister->color = parent->color;
780 sister->left->color = dnode_black;
781 parent->color = dnode_black;
782 rotate_right(parent);
783 break;
jardineb5d44e2003-12-23 08:09:43 +0000784 }
785 }
786 }
787
hassoffe543a2005-09-25 12:04:25 +0000788 child->color = dnode_black;
789 dict_root(dict)->color = dnode_black;
jardineb5d44e2003-12-23 08:09:43 +0000790 }
791
hassoffe543a2005-09-25 12:04:25 +0000792 assert (dict_verify(dict));
jardineb5d44e2003-12-23 08:09:43 +0000793
hassoffe543a2005-09-25 12:04:25 +0000794 return delete;
jardineb5d44e2003-12-23 08:09:43 +0000795}
796
797/*
798 * Allocate a node using the dictionary's allocator routine, give it
799 * the data item.
800 */
801
hassoffe543a2005-09-25 12:04:25 +0000802int dict_alloc_insert(dict_t *dict, const void *key, void *data)
jardineb5d44e2003-12-23 08:09:43 +0000803{
Josh Bailey3f045a02012-03-24 08:35:20 -0700804 dnode_t *node = dict->allocnode (dict->context);
jardineb5d44e2003-12-23 08:09:43 +0000805
hassoffe543a2005-09-25 12:04:25 +0000806 if (node) {
807 dnode_init(node, data);
808 dict_insert(dict, node, key);
809 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000810 }
hassoffe543a2005-09-25 12:04:25 +0000811 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000812}
813
hassoffe543a2005-09-25 12:04:25 +0000814void dict_delete_free(dict_t *dict, dnode_t *node)
jardineb5d44e2003-12-23 08:09:43 +0000815{
hassoffe543a2005-09-25 12:04:25 +0000816 dict_delete(dict, node);
817 dict->freenode(node, dict->context);
jardineb5d44e2003-12-23 08:09:43 +0000818}
819
820/*
821 * Return the node with the lowest (leftmost) key. If the dictionary is empty
822 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
823 */
824
hassoffe543a2005-09-25 12:04:25 +0000825dnode_t *dict_first(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000826{
hassoffe543a2005-09-25 12:04:25 +0000827 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
jardineb5d44e2003-12-23 08:09:43 +0000828
hassoffe543a2005-09-25 12:04:25 +0000829 if (root != nil)
830 while ((left = root->left) != nil)
831 root = left;
jardineb5d44e2003-12-23 08:09:43 +0000832
hassoffe543a2005-09-25 12:04:25 +0000833 return (root == nil) ? NULL : root;
jardineb5d44e2003-12-23 08:09:43 +0000834}
835
836/*
837 * Return the node with the highest (rightmost) key. If the dictionary is empty
838 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
839 */
840
hassoffe543a2005-09-25 12:04:25 +0000841dnode_t *dict_last(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000842{
hassoffe543a2005-09-25 12:04:25 +0000843 dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right;
jardineb5d44e2003-12-23 08:09:43 +0000844
hassoffe543a2005-09-25 12:04:25 +0000845 if (root != nil)
846 while ((right = root->right) != nil)
847 root = right;
jardineb5d44e2003-12-23 08:09:43 +0000848
hassoffe543a2005-09-25 12:04:25 +0000849 return (root == nil) ? NULL : root;
jardineb5d44e2003-12-23 08:09:43 +0000850}
851
852/*
853 * Return the given node's successor node---the node which has the
854 * next key in the the left to right ordering. If the node has
855 * no successor, a null pointer is returned rather than a pointer to
856 * the nil node.
857 */
858
hassoffe543a2005-09-25 12:04:25 +0000859dnode_t *dict_next(dict_t *dict, dnode_t *curr)
jardineb5d44e2003-12-23 08:09:43 +0000860{
hassoffe543a2005-09-25 12:04:25 +0000861 dnode_t *nil = dict_nil(dict), *parent, *left;
jardineb5d44e2003-12-23 08:09:43 +0000862
hassoffe543a2005-09-25 12:04:25 +0000863 if (curr->right != nil) {
864 curr = curr->right;
865 while ((left = curr->left) != nil)
866 curr = left;
867 return curr;
jardineb5d44e2003-12-23 08:09:43 +0000868 }
869
hassoffe543a2005-09-25 12:04:25 +0000870 parent = curr->parent;
jardineb5d44e2003-12-23 08:09:43 +0000871
hassoffe543a2005-09-25 12:04:25 +0000872 while (parent != nil && curr == parent->right) {
873 curr = parent;
874 parent = curr->parent;
jardineb5d44e2003-12-23 08:09:43 +0000875 }
876
hassoffe543a2005-09-25 12:04:25 +0000877 return (parent == nil) ? NULL : parent;
jardineb5d44e2003-12-23 08:09:43 +0000878}
879
880/*
881 * Return the given node's predecessor, in the key order.
882 * The nil sentinel node is returned if there is no predecessor.
883 */
884
hassoffe543a2005-09-25 12:04:25 +0000885dnode_t *dict_prev(dict_t *dict, dnode_t *curr)
jardineb5d44e2003-12-23 08:09:43 +0000886{
hassoffe543a2005-09-25 12:04:25 +0000887 dnode_t *nil = dict_nil(dict), *parent, *right;
jardineb5d44e2003-12-23 08:09:43 +0000888
hassoffe543a2005-09-25 12:04:25 +0000889 if (curr->left != nil) {
890 curr = curr->left;
891 while ((right = curr->right) != nil)
892 curr = right;
893 return curr;
jardineb5d44e2003-12-23 08:09:43 +0000894 }
895
hassoffe543a2005-09-25 12:04:25 +0000896 parent = curr->parent;
jardineb5d44e2003-12-23 08:09:43 +0000897
hassoffe543a2005-09-25 12:04:25 +0000898 while (parent != nil && curr == parent->left) {
899 curr = parent;
900 parent = curr->parent;
jardineb5d44e2003-12-23 08:09:43 +0000901 }
902
hassoffe543a2005-09-25 12:04:25 +0000903 return (parent == nil) ? NULL : parent;
jardineb5d44e2003-12-23 08:09:43 +0000904}
905
hassoffe543a2005-09-25 12:04:25 +0000906void dict_allow_dupes(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000907{
hassoffe543a2005-09-25 12:04:25 +0000908 dict->dupes = 1;
jardineb5d44e2003-12-23 08:09:43 +0000909}
910
911#undef dict_count
912#undef dict_isempty
913#undef dict_isfull
914#undef dnode_get
915#undef dnode_put
916#undef dnode_getkey
917
hassoffe543a2005-09-25 12:04:25 +0000918dictcount_t dict_count(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000919{
hassoffe543a2005-09-25 12:04:25 +0000920 return dict->nodecount;
jardineb5d44e2003-12-23 08:09:43 +0000921}
922
hassoffe543a2005-09-25 12:04:25 +0000923int dict_isempty(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000924{
hassoffe543a2005-09-25 12:04:25 +0000925 return dict->nodecount == 0;
jardineb5d44e2003-12-23 08:09:43 +0000926}
927
hassoffe543a2005-09-25 12:04:25 +0000928int dict_isfull(dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +0000929{
hassoffe543a2005-09-25 12:04:25 +0000930 return dict->nodecount == dict->maxcount;
jardineb5d44e2003-12-23 08:09:43 +0000931}
932
hassoffe543a2005-09-25 12:04:25 +0000933int dict_contains(dict_t *dict, dnode_t *node)
jardineb5d44e2003-12-23 08:09:43 +0000934{
hassoffe543a2005-09-25 12:04:25 +0000935 return verify_dict_has_node(dict_nil(dict), dict_root(dict), node);
jardineb5d44e2003-12-23 08:09:43 +0000936}
937
hassoffe543a2005-09-25 12:04:25 +0000938static dnode_t *dnode_alloc(void *context)
jardineb5d44e2003-12-23 08:09:43 +0000939{
Josh Bailey3f045a02012-03-24 08:35:20 -0700940 return XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
jardineb5d44e2003-12-23 08:09:43 +0000941}
942
hassoffe543a2005-09-25 12:04:25 +0000943static void dnode_free(dnode_t *node, void *context)
jardineb5d44e2003-12-23 08:09:43 +0000944{
Josh Bailey3f045a02012-03-24 08:35:20 -0700945 XFREE(MTYPE_ISIS_DICT_NODE, node);
jardineb5d44e2003-12-23 08:09:43 +0000946}
947
hassoffe543a2005-09-25 12:04:25 +0000948dnode_t *dnode_create(void *data)
jardineb5d44e2003-12-23 08:09:43 +0000949{
Josh Bailey3f045a02012-03-24 08:35:20 -0700950 dnode_t *new = XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
hassoffe543a2005-09-25 12:04:25 +0000951 if (new) {
952 new->data = data;
953 new->parent = NULL;
954 new->left = NULL;
955 new->right = NULL;
jardineb5d44e2003-12-23 08:09:43 +0000956 }
hassoffe543a2005-09-25 12:04:25 +0000957 return new;
jardineb5d44e2003-12-23 08:09:43 +0000958}
959
hassoffe543a2005-09-25 12:04:25 +0000960dnode_t *dnode_init(dnode_t *dnode, void *data)
jardineb5d44e2003-12-23 08:09:43 +0000961{
hassoffe543a2005-09-25 12:04:25 +0000962 dnode->data = data;
963 dnode->parent = NULL;
964 dnode->left = NULL;
965 dnode->right = NULL;
966 return dnode;
jardineb5d44e2003-12-23 08:09:43 +0000967}
968
hassoffe543a2005-09-25 12:04:25 +0000969void dnode_destroy(dnode_t *dnode)
jardineb5d44e2003-12-23 08:09:43 +0000970{
hassoffe543a2005-09-25 12:04:25 +0000971 assert (!dnode_is_in_a_dict(dnode));
Josh Bailey3f045a02012-03-24 08:35:20 -0700972 XFREE(MTYPE_ISIS_DICT_NODE, dnode);
jardineb5d44e2003-12-23 08:09:43 +0000973}
974
hassoffe543a2005-09-25 12:04:25 +0000975void *dnode_get(dnode_t *dnode)
jardineb5d44e2003-12-23 08:09:43 +0000976{
hassoffe543a2005-09-25 12:04:25 +0000977 return dnode->data;
jardineb5d44e2003-12-23 08:09:43 +0000978}
979
hassoffe543a2005-09-25 12:04:25 +0000980const void *dnode_getkey(dnode_t *dnode)
jardineb5d44e2003-12-23 08:09:43 +0000981{
hassoffe543a2005-09-25 12:04:25 +0000982 return dnode->key;
jardineb5d44e2003-12-23 08:09:43 +0000983}
984
hassoffe543a2005-09-25 12:04:25 +0000985void dnode_put(dnode_t *dnode, void *data)
jardineb5d44e2003-12-23 08:09:43 +0000986{
hassoffe543a2005-09-25 12:04:25 +0000987 dnode->data = data;
jardineb5d44e2003-12-23 08:09:43 +0000988}
989
hassoffe543a2005-09-25 12:04:25 +0000990int dnode_is_in_a_dict(dnode_t *dnode)
jardineb5d44e2003-12-23 08:09:43 +0000991{
hassoffe543a2005-09-25 12:04:25 +0000992 return (dnode->parent && dnode->left && dnode->right);
jardineb5d44e2003-12-23 08:09:43 +0000993}
994
hassoffe543a2005-09-25 12:04:25 +0000995void dict_process(dict_t *dict, void *context, dnode_process_t function)
jardineb5d44e2003-12-23 08:09:43 +0000996{
hassoffe543a2005-09-25 12:04:25 +0000997 dnode_t *node = dict_first(dict), *next;
jardineb5d44e2003-12-23 08:09:43 +0000998
hassoffe543a2005-09-25 12:04:25 +0000999 while (node != NULL) {
1000 /* check for callback function deleting */
1001 /* the next node from under us */
1002 assert (dict_contains(dict, node));
1003 next = dict_next(dict, node);
1004 function(dict, node, context);
1005 node = next;
jardineb5d44e2003-12-23 08:09:43 +00001006 }
1007}
1008
hassoffe543a2005-09-25 12:04:25 +00001009static void load_begin_internal(dict_load_t *load, dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +00001010{
hassoffe543a2005-09-25 12:04:25 +00001011 load->dictptr = dict;
1012 load->nilnode.left = &load->nilnode;
1013 load->nilnode.right = &load->nilnode;
jardineb5d44e2003-12-23 08:09:43 +00001014}
1015
hassoffe543a2005-09-25 12:04:25 +00001016void dict_load_begin(dict_load_t *load, dict_t *dict)
jardineb5d44e2003-12-23 08:09:43 +00001017{
hassoffe543a2005-09-25 12:04:25 +00001018 assert (dict_isempty(dict));
1019 load_begin_internal(load, dict);
jardineb5d44e2003-12-23 08:09:43 +00001020}
1021
hassoffe543a2005-09-25 12:04:25 +00001022void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key)
jardineb5d44e2003-12-23 08:09:43 +00001023{
hassoffe543a2005-09-25 12:04:25 +00001024 dict_t *dict = load->dictptr;
1025 dnode_t *nil = &load->nilnode;
1026
1027 assert (!dnode_is_in_a_dict(newnode));
1028 assert (dict->nodecount < dict->maxcount);
jardineb5d44e2003-12-23 08:09:43 +00001029
hassoffe543a2005-09-25 12:04:25 +00001030 #ifndef NDEBUG
1031 if (dict->nodecount > 0) {
1032 if (dict->dupes)
1033 assert (dict->compare(nil->left->key, key) <= 0);
1034 else
1035 assert (dict->compare(nil->left->key, key) < 0);
jardineb5d44e2003-12-23 08:09:43 +00001036 }
hassoffe543a2005-09-25 12:04:25 +00001037 #endif
jardineb5d44e2003-12-23 08:09:43 +00001038
hassoffe543a2005-09-25 12:04:25 +00001039 newnode->key = key;
1040 nil->right->left = newnode;
1041 nil->right = newnode;
1042 newnode->left = nil;
1043 dict->nodecount++;
jardineb5d44e2003-12-23 08:09:43 +00001044}
1045
hassoffe543a2005-09-25 12:04:25 +00001046void dict_load_end(dict_load_t *load)
jardineb5d44e2003-12-23 08:09:43 +00001047{
hassoffe543a2005-09-25 12:04:25 +00001048 dict_t *dict = load->dictptr;
1049 dnode_t *tree[DICT_DEPTH_MAX] = { 0 };
1050 dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next;
1051 dnode_t *complete = 0;
1052 dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount;
1053 dictcount_t botrowcount;
1054 unsigned baselevel = 0, level = 0, i;
jardineb5d44e2003-12-23 08:09:43 +00001055
hassoffe543a2005-09-25 12:04:25 +00001056 assert (dnode_red == 0 && dnode_black == 1);
jardineb5d44e2003-12-23 08:09:43 +00001057
hassoffe543a2005-09-25 12:04:25 +00001058 while (fullcount >= nodecount && fullcount)
1059 fullcount >>= 1;
jardineb5d44e2003-12-23 08:09:43 +00001060
hassoffe543a2005-09-25 12:04:25 +00001061 botrowcount = nodecount - fullcount;
jardineb5d44e2003-12-23 08:09:43 +00001062
hassoffe543a2005-09-25 12:04:25 +00001063 for (curr = loadnil->left; curr != loadnil; curr = next) {
1064 next = curr->left;
jardineb5d44e2003-12-23 08:09:43 +00001065
hassoffe543a2005-09-25 12:04:25 +00001066 if (complete == NULL && botrowcount-- == 0) {
1067 assert (baselevel == 0);
1068 assert (level == 0);
1069 baselevel = level = 1;
1070 complete = tree[0];
jardineb5d44e2003-12-23 08:09:43 +00001071
hassoffe543a2005-09-25 12:04:25 +00001072 if (complete != 0) {
1073 tree[0] = 0;
1074 complete->right = dictnil;
1075 while (tree[level] != 0) {
1076 tree[level]->right = complete;
1077 complete->parent = tree[level];
1078 complete = tree[level];
1079 tree[level++] = 0;
jardineb5d44e2003-12-23 08:09:43 +00001080 }
1081 }
1082 }
1083
hassoffe543a2005-09-25 12:04:25 +00001084 if (complete == NULL) {
1085 curr->left = dictnil;
1086 curr->right = dictnil;
1087 curr->color = level % 2;
1088 complete = curr;
jardineb5d44e2003-12-23 08:09:43 +00001089
hassoffe543a2005-09-25 12:04:25 +00001090 assert (level == baselevel);
1091 while (tree[level] != 0) {
1092 tree[level]->right = complete;
1093 complete->parent = tree[level];
1094 complete = tree[level];
1095 tree[level++] = 0;
jardineb5d44e2003-12-23 08:09:43 +00001096 }
hassoffe543a2005-09-25 12:04:25 +00001097 } else {
1098 curr->left = complete;
1099 curr->color = (level + 1) % 2;
1100 complete->parent = curr;
1101 tree[level] = curr;
1102 complete = 0;
1103 level = baselevel;
jardineb5d44e2003-12-23 08:09:43 +00001104 }
1105 }
1106
hassoffe543a2005-09-25 12:04:25 +00001107 if (complete == NULL)
1108 complete = dictnil;
jardineb5d44e2003-12-23 08:09:43 +00001109
hassoffe543a2005-09-25 12:04:25 +00001110 for (i = 0; i < DICT_DEPTH_MAX; i++) {
1111 if (tree[i] != 0) {
1112 tree[i]->right = complete;
1113 complete->parent = tree[i];
1114 complete = tree[i];
jardineb5d44e2003-12-23 08:09:43 +00001115 }
1116 }
1117
hassoffe543a2005-09-25 12:04:25 +00001118 dictnil->color = dnode_black;
1119 dictnil->right = dictnil;
1120 complete->parent = dictnil;
1121 complete->color = dnode_black;
1122 dict_root(dict) = complete;
jardineb5d44e2003-12-23 08:09:43 +00001123
hassoffe543a2005-09-25 12:04:25 +00001124 assert (dict_verify(dict));
jardineb5d44e2003-12-23 08:09:43 +00001125}
1126
hassoffe543a2005-09-25 12:04:25 +00001127void dict_merge(dict_t *dest, dict_t *source)
jardineb5d44e2003-12-23 08:09:43 +00001128{
hassoffe543a2005-09-25 12:04:25 +00001129 dict_load_t load;
1130 dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source);
jardineb5d44e2003-12-23 08:09:43 +00001131
hassoffe543a2005-09-25 12:04:25 +00001132 assert (dict_similar(dest, source));
jardineb5d44e2003-12-23 08:09:43 +00001133
hassoffe543a2005-09-25 12:04:25 +00001134 if (source == dest)
1135 return;
jardineb5d44e2003-12-23 08:09:43 +00001136
hassoffe543a2005-09-25 12:04:25 +00001137 dest->nodecount = 0;
1138 load_begin_internal(&load, dest);
jardineb5d44e2003-12-23 08:09:43 +00001139
hassoffe543a2005-09-25 12:04:25 +00001140 for (;;) {
1141 if (leftnode != NULL && rightnode != NULL) {
1142 if (dest->compare(leftnode->key, rightnode->key) < 0)
1143 goto copyleft;
1144 else
1145 goto copyright;
1146 } else if (leftnode != NULL) {
jardineb5d44e2003-12-23 08:09:43 +00001147 goto copyleft;
hassoffe543a2005-09-25 12:04:25 +00001148 } else if (rightnode != NULL) {
jardineb5d44e2003-12-23 08:09:43 +00001149 goto copyright;
hassoffe543a2005-09-25 12:04:25 +00001150 } else {
1151 assert (leftnode == NULL && rightnode == NULL);
1152 break;
jardineb5d44e2003-12-23 08:09:43 +00001153 }
1154
1155 copyleft:
hassoffe543a2005-09-25 12:04:25 +00001156 {
1157 dnode_t *next = dict_next(dest, leftnode);
1158 #ifndef NDEBUG
1159 leftnode->left = NULL; /* suppress assertion in dict_load_next */
1160 #endif
1161 dict_load_next(&load, leftnode, leftnode->key);
1162 leftnode = next;
1163 continue;
1164 }
1165
jardineb5d44e2003-12-23 08:09:43 +00001166 copyright:
hassoffe543a2005-09-25 12:04:25 +00001167 {
1168 dnode_t *next = dict_next(source, rightnode);
1169 #ifndef NDEBUG
1170 rightnode->left = NULL;
1171 #endif
1172 dict_load_next(&load, rightnode, rightnode->key);
1173 rightnode = next;
1174 continue;
1175 }
jardineb5d44e2003-12-23 08:09:43 +00001176 }
1177
hassoffe543a2005-09-25 12:04:25 +00001178 dict_clear(source);
1179 dict_load_end(&load);
jardineb5d44e2003-12-23 08:09:43 +00001180}
1181
1182#ifdef KAZLIB_TEST_MAIN
1183
1184#include <stdio.h>
1185#include <string.h>
1186#include <ctype.h>
1187#include <stdarg.h>
1188
1189typedef char input_t[256];
1190
hassoffe543a2005-09-25 12:04:25 +00001191static int tokenize(char *string, ...)
jardineb5d44e2003-12-23 08:09:43 +00001192{
hassoffe543a2005-09-25 12:04:25 +00001193 char **tokptr;
1194 va_list arglist;
1195 int tokcount = 0;
jardineb5d44e2003-12-23 08:09:43 +00001196
hassoffe543a2005-09-25 12:04:25 +00001197 va_start(arglist, string);
1198 tokptr = va_arg(arglist, char **);
1199 while (tokptr) {
1200 while (*string && isspace((unsigned char) *string))
1201 string++;
1202 if (!*string)
1203 break;
1204 *tokptr = string;
1205 while (*string && !isspace((unsigned char) *string))
1206 string++;
1207 tokptr = va_arg(arglist, char **);
1208 tokcount++;
1209 if (!*string)
1210 break;
1211 *string++ = 0;
jardineb5d44e2003-12-23 08:09:43 +00001212 }
hassoffe543a2005-09-25 12:04:25 +00001213 va_end(arglist);
jardineb5d44e2003-12-23 08:09:43 +00001214
hassoffe543a2005-09-25 12:04:25 +00001215 return tokcount;
jardineb5d44e2003-12-23 08:09:43 +00001216}
1217
hassoffe543a2005-09-25 12:04:25 +00001218static int comparef(const void *key1, const void *key2)
jardineb5d44e2003-12-23 08:09:43 +00001219{
hassoffe543a2005-09-25 12:04:25 +00001220 return strcmp(key1, key2);
jardineb5d44e2003-12-23 08:09:43 +00001221}
1222
hassoffe543a2005-09-25 12:04:25 +00001223static char *dupstring(char *str)
jardineb5d44e2003-12-23 08:09:43 +00001224{
hassoffe543a2005-09-25 12:04:25 +00001225 int sz = strlen(str) + 1;
Josh Bailey3f045a02012-03-24 08:35:20 -07001226 char *new = XCALLOC(MTYPE_ISIS_TMP, sz);
hassoffe543a2005-09-25 12:04:25 +00001227 if (new)
1228 memcpy(new, str, sz);
1229 return new;
jardineb5d44e2003-12-23 08:09:43 +00001230}
1231
hassoffe543a2005-09-25 12:04:25 +00001232static dnode_t *new_node(void *c)
jardineb5d44e2003-12-23 08:09:43 +00001233{
hassoffe543a2005-09-25 12:04:25 +00001234 static dnode_t few[5];
1235 static int count;
jardineb5d44e2003-12-23 08:09:43 +00001236
hassoffe543a2005-09-25 12:04:25 +00001237 if (count < 5)
1238 return few + count++;
jardineb5d44e2003-12-23 08:09:43 +00001239
hassoffe543a2005-09-25 12:04:25 +00001240 return NULL;
jardineb5d44e2003-12-23 08:09:43 +00001241}
1242
hassoffe543a2005-09-25 12:04:25 +00001243static void del_node(dnode_t *n, void *c)
jardineb5d44e2003-12-23 08:09:43 +00001244{
1245}
1246
1247static int prompt = 0;
1248
hassoffe543a2005-09-25 12:04:25 +00001249static void construct(dict_t *d)
jardineb5d44e2003-12-23 08:09:43 +00001250{
hassoffe543a2005-09-25 12:04:25 +00001251 input_t in;
1252 int done = 0;
1253 dict_load_t dl;
1254 dnode_t *dn;
1255 char *tok1, *tok2, *val;
1256 const char *key;
1257 char *help =
1258 "p turn prompt on\n"
1259 "q finish construction\n"
1260 "a <key> <val> add new entry\n";
jardineb5d44e2003-12-23 08:09:43 +00001261
hassoffe543a2005-09-25 12:04:25 +00001262 if (!dict_isempty(d))
1263 puts("warning: dictionary not empty!");
jardineb5d44e2003-12-23 08:09:43 +00001264
hassoffe543a2005-09-25 12:04:25 +00001265 dict_load_begin(&dl, d);
jardineb5d44e2003-12-23 08:09:43 +00001266
hassoffe543a2005-09-25 12:04:25 +00001267 while (!done) {
1268 if (prompt)
1269 putchar('>');
1270 fflush(stdout);
jardineb5d44e2003-12-23 08:09:43 +00001271
hassoffe543a2005-09-25 12:04:25 +00001272 if (!fgets(in, sizeof(input_t), stdin))
1273 break;
jardineb5d44e2003-12-23 08:09:43 +00001274
hassoffe543a2005-09-25 12:04:25 +00001275 switch (in[0]) {
1276 case '?':
1277 puts(help);
1278 break;
1279 case 'p':
1280 prompt = 1;
1281 break;
1282 case 'q':
1283 done = 1;
1284 break;
1285 case 'a':
1286 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1287 puts("what?");
1288 break;
1289 }
1290 key = dupstring(tok1);
1291 val = dupstring(tok2);
1292 dn = dnode_create(val);
jardineb5d44e2003-12-23 08:09:43 +00001293
hassoffe543a2005-09-25 12:04:25 +00001294 if (!key || !val || !dn) {
1295 puts("out of memory");
1296 free((void *) key);
1297 free(val);
1298 if (dn)
1299 dnode_destroy(dn);
1300 }
jardineb5d44e2003-12-23 08:09:43 +00001301
hassoffe543a2005-09-25 12:04:25 +00001302 dict_load_next(&dl, dn, key);
1303 break;
1304 default:
1305 putchar('?');
1306 putchar('\n');
1307 break;
jardineb5d44e2003-12-23 08:09:43 +00001308 }
1309 }
1310
hassoffe543a2005-09-25 12:04:25 +00001311 dict_load_end(&dl);
jardineb5d44e2003-12-23 08:09:43 +00001312}
1313
hassoffe543a2005-09-25 12:04:25 +00001314int main(void)
jardineb5d44e2003-12-23 08:09:43 +00001315{
hassoffe543a2005-09-25 12:04:25 +00001316 input_t in;
1317 dict_t darray[10];
1318 dict_t *d = &darray[0];
1319 dnode_t *dn;
1320 int i;
1321 char *tok1, *tok2, *val;
1322 const char *key;
jardineb5d44e2003-12-23 08:09:43 +00001323
hassoffe543a2005-09-25 12:04:25 +00001324 char *help =
1325 "a <key> <val> add value to dictionary\n"
1326 "d <key> delete value from dictionary\n"
1327 "l <key> lookup value in dictionary\n"
1328 "( <key> lookup lower bound\n"
1329 ") <key> lookup upper bound\n"
1330 "# <num> switch to alternate dictionary (0-9)\n"
1331 "j <num> <num> merge two dictionaries\n"
1332 "f free the whole dictionary\n"
1333 "k allow duplicate keys\n"
1334 "c show number of entries\n"
1335 "t dump whole dictionary in sort order\n"
1336 "m make dictionary out of sorted items\n"
1337 "p turn prompt on\n"
1338 "s switch to non-functioning allocator\n"
1339 "q quit";
jardineb5d44e2003-12-23 08:09:43 +00001340
Josh Bailey3f045a02012-03-24 08:35:20 -07001341 for (i = 0; i < 10; i++)
hassoffe543a2005-09-25 12:04:25 +00001342 dict_init(&darray[i], DICTCOUNT_T_MAX, comparef);
jardineb5d44e2003-12-23 08:09:43 +00001343
hassoffe543a2005-09-25 12:04:25 +00001344 for (;;) {
1345 if (prompt)
1346 putchar('>');
1347 fflush(stdout);
jardineb5d44e2003-12-23 08:09:43 +00001348
hassoffe543a2005-09-25 12:04:25 +00001349 if (!fgets(in, sizeof(input_t), stdin))
1350 break;
jardineb5d44e2003-12-23 08:09:43 +00001351
hassoffe543a2005-09-25 12:04:25 +00001352 switch(in[0]) {
1353 case '?':
1354 puts(help);
1355 break;
1356 case 'a':
1357 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1358 puts("what?");
1359 break;
1360 }
1361 key = dupstring(tok1);
1362 val = dupstring(tok2);
jardineb5d44e2003-12-23 08:09:43 +00001363
hassoffe543a2005-09-25 12:04:25 +00001364 if (!key || !val) {
1365 puts("out of memory");
1366 free((void *) key);
1367 free(val);
1368 }
jardineb5d44e2003-12-23 08:09:43 +00001369
hassoffe543a2005-09-25 12:04:25 +00001370 if (!dict_alloc_insert(d, key, val)) {
1371 puts("dict_alloc_insert failed");
1372 free((void *) key);
1373 free(val);
1374 break;
1375 }
1376 break;
1377 case 'd':
1378 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1379 puts("what?");
1380 break;
1381 }
1382 dn = dict_lookup(d, tok1);
1383 if (!dn) {
1384 puts("dict_lookup failed");
1385 break;
1386 }
1387 val = dnode_get(dn);
1388 key = dnode_getkey(dn);
1389 dict_delete_free(d, dn);
jardineb5d44e2003-12-23 08:09:43 +00001390
hassoffe543a2005-09-25 12:04:25 +00001391 free(val);
1392 free((void *) key);
1393 break;
1394 case 'f':
1395 dict_free(d);
1396 break;
jardineb5d44e2003-12-23 08:09:43 +00001397 case 'l':
1398 case '(':
1399 case ')':
hassoffe543a2005-09-25 12:04:25 +00001400 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1401 puts("what?");
1402 break;
jardineb5d44e2003-12-23 08:09:43 +00001403 }
hassoffe543a2005-09-25 12:04:25 +00001404 dn = 0;
1405 switch (in[0]) {
1406 case 'l':
1407 dn = dict_lookup(d, tok1);
1408 break;
1409 case '(':
1410 dn = dict_lower_bound(d, tok1);
1411 break;
1412 case ')':
1413 dn = dict_upper_bound(d, tok1);
1414 break;
jardineb5d44e2003-12-23 08:09:43 +00001415 }
hassoffe543a2005-09-25 12:04:25 +00001416 if (!dn) {
1417 puts("lookup failed");
1418 break;
1419 }
1420 val = dnode_get(dn);
1421 puts(val);
1422 break;
1423 case 'm':
1424 construct(d);
1425 break;
1426 case 'k':
1427 dict_allow_dupes(d);
1428 break;
1429 case 'c':
1430 printf("%lu\n", (unsigned long) dict_count(d));
1431 break;
1432 case 't':
1433 for (dn = dict_first(d); dn; dn = dict_next(d, dn)) {
1434 printf("%s\t%s\n", (char *) dnode_getkey(dn),
1435 (char *) dnode_get(dn));
1436 }
1437 break;
1438 case 'q':
1439 exit(0);
1440 break;
1441 case '\0':
1442 break;
1443 case 'p':
1444 prompt = 1;
1445 break;
1446 case 's':
1447 dict_set_allocator(d, new_node, del_node, NULL);
1448 break;
1449 case '#':
1450 if (tokenize(in+1, &tok1, (char **) 0) != 1) {
1451 puts("what?");
1452 break;
1453 } else {
1454 int dictnum = atoi(tok1);
1455 if (dictnum < 0 || dictnum > 9) {
1456 puts("invalid number");
1457 break;
1458 }
1459 d = &darray[dictnum];
1460 }
1461 break;
1462 case 'j':
1463 if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
1464 puts("what?");
1465 break;
1466 } else {
1467 int dict1 = atoi(tok1), dict2 = atoi(tok2);
1468 if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) {
1469 puts("invalid number");
1470 break;
1471 }
1472 dict_merge(&darray[dict1], &darray[dict2]);
1473 }
1474 break;
1475 default:
1476 putchar('?');
1477 putchar('\n');
1478 break;
jardineb5d44e2003-12-23 08:09:43 +00001479 }
1480 }
1481
hassoffe543a2005-09-25 12:04:25 +00001482 return 0;
jardineb5d44e2003-12-23 08:09:43 +00001483}
1484
1485#endif