blob: 784ec8427cc3ea2db20c7da09f684bf77de14416 [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 *
ajscee3df12004-11-24 17:14:49 +000017 * $Id: dict.c,v 1.3 2004/11/24 17:14:49 ajs Exp $
jardineb5d44e2003-12-23 08:09:43 +000018 * $Name: $
19 */
20
21#include <stdlib.h>
22#include <stddef.h>
ajscee3df12004-11-24 17:14:49 +000023#include "zassert.h"
jardineb5d44e2003-12-23 08:09:43 +000024#define DICT_IMPLEMENTATION
25#include "dict.h"
26
27#ifdef KAZLIB_RCSID
hassof390d2c2004-09-10 20:48:21 +000028static const char rcsid[] =
ajscee3df12004-11-24 17:14:49 +000029 "$Id: dict.c,v 1.3 2004/11/24 17:14:49 ajs Exp $";
jardineb5d44e2003-12-23 08:09:43 +000030#endif
31
32/*
33 * These macros provide short convenient names for structure members,
34 * which are embellished with dict_ prefixes so that they are
35 * properly confined to the documented namespace. It's legal for a
36 * program which uses dict to define, for instance, a macro called ``parent''.
37 * Such a macro would interfere with the dnode_t struct definition.
38 * In general, highly portable and reusable C modules which expose their
39 * structures need to confine structure member names to well-defined spaces.
40 * The resulting identifiers aren't necessarily convenient to use, nor
41 * readable, in the implementation, however!
42 */
43
44#define left dict_left
45#define right dict_right
46#define parent dict_parent
47#define color dict_color
48#define key dict_key
49#define data dict_data
50
51#define nilnode dict_nilnode
52#define nodecount dict_nodecount
53#define maxcount dict_maxcount
54#define compare dict_compare
55#define allocnode dict_allocnode
56#define freenode dict_freenode
57#define context dict_context
58#define dupes dict_dupes
59
60#define dictptr dict_dictptr
61
62#define dict_root(D) ((D)->nilnode.left)
63#define dict_nil(D) (&(D)->nilnode)
64#define DICT_DEPTH_MAX 64
65
hassof390d2c2004-09-10 20:48:21 +000066static dnode_t *dnode_alloc (void *context);
67static void dnode_free (dnode_t * node, void *context);
jardineb5d44e2003-12-23 08:09:43 +000068
69/*
70 * Perform a ``left rotation'' adjustment on the tree. The given node P and
71 * its right child C are rearranged so that the P instead becomes the left
72 * child of C. The left subtree of C is inherited as the new right subtree
73 * for P. The ordering of the keys within the tree is thus preserved.
74 */
75
hassof390d2c2004-09-10 20:48:21 +000076static void
77rotate_left (dnode_t * upper)
jardineb5d44e2003-12-23 08:09:43 +000078{
hassof390d2c2004-09-10 20:48:21 +000079 dnode_t *lower, *lowleft, *upparent;
jardineb5d44e2003-12-23 08:09:43 +000080
hassof390d2c2004-09-10 20:48:21 +000081 lower = upper->right;
82 upper->right = lowleft = lower->left;
83 lowleft->parent = upper;
jardineb5d44e2003-12-23 08:09:43 +000084
hassof390d2c2004-09-10 20:48:21 +000085 lower->parent = upparent = upper->parent;
jardineb5d44e2003-12-23 08:09:43 +000086
hassof390d2c2004-09-10 20:48:21 +000087 /* don't need to check for root node here because root->parent is
88 the sentinel nil node, and root->parent->left points back to root */
jardineb5d44e2003-12-23 08:09:43 +000089
hassof390d2c2004-09-10 20:48:21 +000090 if (upper == upparent->left)
91 {
92 upparent->left = lower;
93 }
94 else
95 {
96 assert (upper == upparent->right);
97 upparent->right = lower;
jardineb5d44e2003-12-23 08:09:43 +000098 }
99
hassof390d2c2004-09-10 20:48:21 +0000100 lower->left = upper;
101 upper->parent = lower;
jardineb5d44e2003-12-23 08:09:43 +0000102}
103
104/*
105 * This operation is the ``mirror'' image of rotate_left. It is
106 * the same procedure, but with left and right interchanged.
107 */
108
hassof390d2c2004-09-10 20:48:21 +0000109static void
110rotate_right (dnode_t * upper)
jardineb5d44e2003-12-23 08:09:43 +0000111{
hassof390d2c2004-09-10 20:48:21 +0000112 dnode_t *lower, *lowright, *upparent;
jardineb5d44e2003-12-23 08:09:43 +0000113
hassof390d2c2004-09-10 20:48:21 +0000114 lower = upper->left;
115 upper->left = lowright = lower->right;
116 lowright->parent = upper;
jardineb5d44e2003-12-23 08:09:43 +0000117
hassof390d2c2004-09-10 20:48:21 +0000118 lower->parent = upparent = upper->parent;
jardineb5d44e2003-12-23 08:09:43 +0000119
hassof390d2c2004-09-10 20:48:21 +0000120 if (upper == upparent->right)
121 {
122 upparent->right = lower;
123 }
124 else
125 {
126 assert (upper == upparent->left);
127 upparent->left = lower;
jardineb5d44e2003-12-23 08:09:43 +0000128 }
129
hassof390d2c2004-09-10 20:48:21 +0000130 lower->right = upper;
131 upper->parent = lower;
jardineb5d44e2003-12-23 08:09:43 +0000132}
133
134/*
135 * Do a postorder traversal of the tree rooted at the specified
136 * node and free everything under it. Used by dict_free().
137 */
138
hassof390d2c2004-09-10 20:48:21 +0000139static void
140free_nodes (dict_t * dict, dnode_t * node, dnode_t * nil)
jardineb5d44e2003-12-23 08:09:43 +0000141{
hassof390d2c2004-09-10 20:48:21 +0000142 if (node == nil)
143 return;
144 free_nodes (dict, node->left, nil);
145 free_nodes (dict, node->right, nil);
146 dict->freenode (node, dict->context);
jardineb5d44e2003-12-23 08:09:43 +0000147}
148
149/*
150 * This procedure performs a verification that the given subtree is a binary
151 * search tree. It performs an inorder traversal of the tree using the
152 * dict_next() successor function, verifying that the key of each node is
153 * strictly lower than that of its successor, if duplicates are not allowed,
154 * or lower or equal if duplicates are allowed. This function is used for
155 * debugging purposes.
156 */
157
hassof390d2c2004-09-10 20:48:21 +0000158static int
159verify_bintree (dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +0000160{
hassof390d2c2004-09-10 20:48:21 +0000161 dnode_t *first, *next;
jardineb5d44e2003-12-23 08:09:43 +0000162
hassof390d2c2004-09-10 20:48:21 +0000163 first = dict_first (dict);
jardineb5d44e2003-12-23 08:09:43 +0000164
hassof390d2c2004-09-10 20:48:21 +0000165 if (dict->dupes)
166 {
167 while (first && (next = dict_next (dict, first)))
168 {
169 if (dict->compare (first->key, next->key) > 0)
170 return 0;
171 first = next;
jardineb5d44e2003-12-23 08:09:43 +0000172 }
173 }
hassof390d2c2004-09-10 20:48:21 +0000174 else
175 {
176 while (first && (next = dict_next (dict, first)))
177 {
178 if (dict->compare (first->key, next->key) >= 0)
179 return 0;
180 first = next;
181 }
182 }
183 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000184}
185
186
187/*
188 * This function recursively verifies that the given binary subtree satisfies
189 * three of the red black properties. It checks that every red node has only
190 * black children. It makes sure that each node is either red or black. And it
191 * checks that every path has the same count of black nodes from root to leaf.
192 * It returns the blackheight of the given subtree; this allows blackheights to
193 * be computed recursively and compared for left and right siblings for
194 * mismatches. It does not check for every nil node being black, because there
195 * is only one sentinel nil node. The return value of this function is the
196 * black height of the subtree rooted at the node ``root'', or zero if the
197 * subtree is not red-black.
198 */
199
hassof390d2c2004-09-10 20:48:21 +0000200static unsigned int
201verify_redblack (dnode_t * nil, dnode_t * root)
jardineb5d44e2003-12-23 08:09:43 +0000202{
hassof390d2c2004-09-10 20:48:21 +0000203 unsigned height_left, height_right;
jardineb5d44e2003-12-23 08:09:43 +0000204
hassof390d2c2004-09-10 20:48:21 +0000205 if (root != nil)
206 {
207 height_left = verify_redblack (nil, root->left);
208 height_right = verify_redblack (nil, root->right);
209 if (height_left == 0 || height_right == 0)
210 return 0;
211 if (height_left != height_right)
212 return 0;
213 if (root->color == dnode_red)
214 {
215 if (root->left->color != dnode_black)
jardineb5d44e2003-12-23 08:09:43 +0000216 return 0;
hassof390d2c2004-09-10 20:48:21 +0000217 if (root->right->color != dnode_black)
jardineb5d44e2003-12-23 08:09:43 +0000218 return 0;
hassof390d2c2004-09-10 20:48:21 +0000219 return height_left;
jardineb5d44e2003-12-23 08:09:43 +0000220 }
hassof390d2c2004-09-10 20:48:21 +0000221 if (root->color != dnode_black)
222 return 0;
223 return height_left + 1;
224 }
225 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000226}
227
228/*
229 * Compute the actual count of nodes by traversing the tree and
230 * return it. This could be compared against the stored count to
231 * detect a mismatch.
232 */
233
hassof390d2c2004-09-10 20:48:21 +0000234static dictcount_t
235verify_node_count (dnode_t * nil, dnode_t * root)
jardineb5d44e2003-12-23 08:09:43 +0000236{
hassof390d2c2004-09-10 20:48:21 +0000237 if (root == nil)
238 return 0;
239 else
240 return 1 + verify_node_count (nil, root->left)
241 + verify_node_count (nil, root->right);
jardineb5d44e2003-12-23 08:09:43 +0000242}
243
244/*
245 * Verify that the tree contains the given node. This is done by
246 * traversing all of the nodes and comparing their pointers to the
247 * given pointer. Returns 1 if the node is found, otherwise
248 * returns zero. It is intended for debugging purposes.
249 */
250
hassof390d2c2004-09-10 20:48:21 +0000251static int
252verify_dict_has_node (dnode_t * nil, dnode_t * root, dnode_t * node)
jardineb5d44e2003-12-23 08:09:43 +0000253{
hassof390d2c2004-09-10 20:48:21 +0000254 if (root != nil)
255 {
256 return root == node
257 || verify_dict_has_node (nil, root->left, node)
258 || verify_dict_has_node (nil, root->right, node);
jardineb5d44e2003-12-23 08:09:43 +0000259 }
hassof390d2c2004-09-10 20:48:21 +0000260 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000261}
262
jardineb5d44e2003-12-23 08:09:43 +0000263/*
264 * Dynamically allocate and initialize a dictionary object.
265 */
266
hassof390d2c2004-09-10 20:48:21 +0000267dict_t *
268dict_create (dictcount_t maxcount, dict_comp_t comp)
jardineb5d44e2003-12-23 08:09:43 +0000269{
hassof390d2c2004-09-10 20:48:21 +0000270 dict_t *new = malloc (sizeof *new);
jardineb5d44e2003-12-23 08:09:43 +0000271
hassof390d2c2004-09-10 20:48:21 +0000272 if (new)
273 {
274 new->compare = comp;
275 new->allocnode = dnode_alloc;
276 new->freenode = dnode_free;
277 new->context = NULL;
278 new->nodecount = 0;
279 new->maxcount = maxcount;
280 new->nilnode.left = &new->nilnode;
281 new->nilnode.right = &new->nilnode;
282 new->nilnode.parent = &new->nilnode;
283 new->nilnode.color = dnode_black;
284 new->dupes = 0;
jardineb5d44e2003-12-23 08:09:43 +0000285 }
hassof390d2c2004-09-10 20:48:21 +0000286 return new;
jardineb5d44e2003-12-23 08:09:43 +0000287}
288
289/*
290 * Select a different set of node allocator routines.
291 */
292
hassof390d2c2004-09-10 20:48:21 +0000293void
294dict_set_allocator (dict_t * dict, dnode_alloc_t al,
295 dnode_free_t fr, void *context)
jardineb5d44e2003-12-23 08:09:43 +0000296{
hassof390d2c2004-09-10 20:48:21 +0000297 assert (dict_count (dict) == 0);
298 assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL));
jardineb5d44e2003-12-23 08:09:43 +0000299
hassof390d2c2004-09-10 20:48:21 +0000300 dict->allocnode = al ? al : dnode_alloc;
301 dict->freenode = fr ? fr : dnode_free;
302 dict->context = context;
jardineb5d44e2003-12-23 08:09:43 +0000303}
304
305/*
306 * Free a dynamically allocated dictionary object. Removing the nodes
307 * from the tree before deleting it is required.
308 */
309
hassof390d2c2004-09-10 20:48:21 +0000310void
311dict_destroy (dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +0000312{
hassof390d2c2004-09-10 20:48:21 +0000313 assert (dict_isempty (dict));
314 free (dict);
jardineb5d44e2003-12-23 08:09:43 +0000315}
316
317/*
318 * Free all the nodes in the dictionary by using the dictionary's
319 * installed free routine. The dictionary is emptied.
320 */
321
hassof390d2c2004-09-10 20:48:21 +0000322void
323dict_free_nodes (dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +0000324{
hassof390d2c2004-09-10 20:48:21 +0000325 dnode_t *nil = dict_nil (dict), *root = dict_root (dict);
326 free_nodes (dict, root, nil);
327 dict->nodecount = 0;
328 dict->nilnode.left = &dict->nilnode;
329 dict->nilnode.right = &dict->nilnode;
jardineb5d44e2003-12-23 08:09:43 +0000330}
331
332/*
333 * Obsolescent function, equivalent to dict_free_nodes
334 */
335
hassof390d2c2004-09-10 20:48:21 +0000336void
337dict_free (dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +0000338{
339#ifdef KAZLIB_OBSOLESCENT_DEBUG
hassof390d2c2004-09-10 20:48:21 +0000340 assert ("call to obsolescent function dict_free()" && 0);
jardineb5d44e2003-12-23 08:09:43 +0000341#endif
hassof390d2c2004-09-10 20:48:21 +0000342 dict_free_nodes (dict);
jardineb5d44e2003-12-23 08:09:43 +0000343}
344
345/*
346 * Initialize a user-supplied dictionary object.
347 */
348
hassof390d2c2004-09-10 20:48:21 +0000349dict_t *
350dict_init (dict_t * dict, dictcount_t maxcount, dict_comp_t comp)
jardineb5d44e2003-12-23 08:09:43 +0000351{
hassof390d2c2004-09-10 20:48:21 +0000352 dict->compare = comp;
353 dict->allocnode = dnode_alloc;
354 dict->freenode = dnode_free;
355 dict->context = NULL;
356 dict->nodecount = 0;
357 dict->maxcount = maxcount;
358 dict->nilnode.left = &dict->nilnode;
359 dict->nilnode.right = &dict->nilnode;
360 dict->nilnode.parent = &dict->nilnode;
361 dict->nilnode.color = dnode_black;
362 dict->dupes = 0;
363 return dict;
jardineb5d44e2003-12-23 08:09:43 +0000364}
365
366/*
367 * Initialize a dictionary in the likeness of another dictionary
368 */
369
hassof390d2c2004-09-10 20:48:21 +0000370void
371dict_init_like (dict_t * dict, const dict_t * template)
jardineb5d44e2003-12-23 08:09:43 +0000372{
hassof390d2c2004-09-10 20:48:21 +0000373 dict->compare = template->compare;
374 dict->allocnode = template->allocnode;
375 dict->freenode = template->freenode;
376 dict->context = template->context;
377 dict->nodecount = 0;
378 dict->maxcount = template->maxcount;
379 dict->nilnode.left = &dict->nilnode;
380 dict->nilnode.right = &dict->nilnode;
381 dict->nilnode.parent = &dict->nilnode;
382 dict->nilnode.color = dnode_black;
383 dict->dupes = template->dupes;
jardineb5d44e2003-12-23 08:09:43 +0000384
hassof390d2c2004-09-10 20:48:21 +0000385 assert (dict_similar (dict, template));
jardineb5d44e2003-12-23 08:09:43 +0000386}
387
388/*
389 * Remove all nodes from the dictionary (without freeing them in any way).
390 */
391
hassof390d2c2004-09-10 20:48:21 +0000392static void
393dict_clear (dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +0000394{
hassof390d2c2004-09-10 20:48:21 +0000395 dict->nodecount = 0;
396 dict->nilnode.left = &dict->nilnode;
397 dict->nilnode.right = &dict->nilnode;
398 dict->nilnode.parent = &dict->nilnode;
399 assert (dict->nilnode.color == dnode_black);
jardineb5d44e2003-12-23 08:09:43 +0000400}
401
jardineb5d44e2003-12-23 08:09:43 +0000402/*
403 * Verify the integrity of the dictionary structure. This is provided for
404 * debugging purposes, and should be placed in assert statements. Just because
405 * this function succeeds doesn't mean that the tree is not corrupt. Certain
406 * corruptions in the tree may simply cause undefined behavior.
hassof390d2c2004-09-10 20:48:21 +0000407 */
jardineb5d44e2003-12-23 08:09:43 +0000408
hassof390d2c2004-09-10 20:48:21 +0000409int
410dict_verify (dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +0000411{
hassof390d2c2004-09-10 20:48:21 +0000412 dnode_t *nil = dict_nil (dict), *root = dict_root (dict);
jardineb5d44e2003-12-23 08:09:43 +0000413
hassof390d2c2004-09-10 20:48:21 +0000414 /* check that the sentinel node and root node are black */
415 if (root->color != dnode_black)
416 return 0;
417 if (nil->color != dnode_black)
418 return 0;
419 if (nil->right != nil)
420 return 0;
421 /* nil->left is the root node; check that its parent pointer is nil */
422 if (nil->left->parent != nil)
423 return 0;
424 /* perform a weak test that the tree is a binary search tree */
425 if (!verify_bintree (dict))
426 return 0;
427 /* verify that the tree is a red-black tree */
428 if (!verify_redblack (nil, root))
429 return 0;
430 if (verify_node_count (nil, root) != dict_count (dict))
431 return 0;
432 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000433}
434
435/*
436 * Determine whether two dictionaries are similar: have the same comparison and
437 * allocator functions, and same status as to whether duplicates are allowed.
438 */
439
hassof390d2c2004-09-10 20:48:21 +0000440int
441dict_similar (const dict_t * left, const dict_t * right)
jardineb5d44e2003-12-23 08:09:43 +0000442{
hassof390d2c2004-09-10 20:48:21 +0000443 if (left->compare != right->compare)
444 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000445
hassof390d2c2004-09-10 20:48:21 +0000446 if (left->allocnode != right->allocnode)
447 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000448
hassof390d2c2004-09-10 20:48:21 +0000449 if (left->freenode != right->freenode)
450 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000451
hassof390d2c2004-09-10 20:48:21 +0000452 if (left->context != right->context)
453 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000454
hassof390d2c2004-09-10 20:48:21 +0000455 if (left->dupes != right->dupes)
456 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000457
hassof390d2c2004-09-10 20:48:21 +0000458 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000459}
460
461/*
462 * Locate a node in the dictionary having the given key.
463 * If the node is not found, a null a pointer is returned (rather than
464 * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
465 * located node is returned.
466 */
467
hassof390d2c2004-09-10 20:48:21 +0000468dnode_t *
469dict_lookup (dict_t * dict, const void *key)
jardineb5d44e2003-12-23 08:09:43 +0000470{
hassof390d2c2004-09-10 20:48:21 +0000471 dnode_t *root = dict_root (dict);
472 dnode_t *nil = dict_nil (dict);
473 dnode_t *saved;
474 int result;
jardineb5d44e2003-12-23 08:09:43 +0000475
hassof390d2c2004-09-10 20:48:21 +0000476 /* simple binary search adapted for trees that contain duplicate keys */
jardineb5d44e2003-12-23 08:09:43 +0000477
hassof390d2c2004-09-10 20:48:21 +0000478 while (root != nil)
479 {
480 result = dict->compare (key, root->key);
481 if (result < 0)
482 root = root->left;
483 else if (result > 0)
484 root = root->right;
485 else
486 {
487 if (!dict->dupes)
488 { /* no duplicates, return match */
489 return root;
490 }
491 else
492 { /* could be dupes, find leftmost one */
493 do
494 {
495 saved = root;
496 root = root->left;
497 while (root != nil && dict->compare (key, root->key))
498 root = root->right;
499 }
500 while (root != nil);
501 return saved;
jardineb5d44e2003-12-23 08:09:43 +0000502 }
503 }
504 }
505
hassof390d2c2004-09-10 20:48:21 +0000506 return NULL;
jardineb5d44e2003-12-23 08:09:43 +0000507}
508
509/*
510 * Look for the node corresponding to the lowest key that is equal to or
511 * greater than the given key. If there is no such node, return null.
512 */
513
hassof390d2c2004-09-10 20:48:21 +0000514dnode_t *
515dict_lower_bound (dict_t * dict, const void *key)
jardineb5d44e2003-12-23 08:09:43 +0000516{
hassof390d2c2004-09-10 20:48:21 +0000517 dnode_t *root = dict_root (dict);
518 dnode_t *nil = dict_nil (dict);
519 dnode_t *tentative = 0;
jardineb5d44e2003-12-23 08:09:43 +0000520
hassof390d2c2004-09-10 20:48:21 +0000521 while (root != nil)
522 {
523 int result = dict->compare (key, root->key);
jardineb5d44e2003-12-23 08:09:43 +0000524
hassof390d2c2004-09-10 20:48:21 +0000525 if (result > 0)
526 {
527 root = root->right;
528 }
529 else if (result < 0)
530 {
531 tentative = root;
532 root = root->left;
533 }
534 else
535 {
536 if (!dict->dupes)
537 {
538 return root;
jardineb5d44e2003-12-23 08:09:43 +0000539 }
hassof390d2c2004-09-10 20:48:21 +0000540 else
541 {
542 tentative = root;
543 root = root->left;
544 }
545 }
jardineb5d44e2003-12-23 08:09:43 +0000546 }
hassof390d2c2004-09-10 20:48:21 +0000547
548 return tentative;
jardineb5d44e2003-12-23 08:09:43 +0000549}
550
551/*
552 * Look for the node corresponding to the greatest key that is equal to or
553 * lower than the given key. If there is no such node, return null.
554 */
555
hassof390d2c2004-09-10 20:48:21 +0000556dnode_t *
557dict_upper_bound (dict_t * dict, const void *key)
jardineb5d44e2003-12-23 08:09:43 +0000558{
hassof390d2c2004-09-10 20:48:21 +0000559 dnode_t *root = dict_root (dict);
560 dnode_t *nil = dict_nil (dict);
561 dnode_t *tentative = 0;
jardineb5d44e2003-12-23 08:09:43 +0000562
hassof390d2c2004-09-10 20:48:21 +0000563 while (root != nil)
564 {
565 int result = dict->compare (key, root->key);
jardineb5d44e2003-12-23 08:09:43 +0000566
hassof390d2c2004-09-10 20:48:21 +0000567 if (result < 0)
568 {
569 root = root->left;
570 }
571 else if (result > 0)
572 {
573 tentative = root;
574 root = root->right;
575 }
576 else
577 {
578 if (!dict->dupes)
579 {
580 return root;
jardineb5d44e2003-12-23 08:09:43 +0000581 }
hassof390d2c2004-09-10 20:48:21 +0000582 else
583 {
584 tentative = root;
585 root = root->right;
586 }
587 }
jardineb5d44e2003-12-23 08:09:43 +0000588 }
hassof390d2c2004-09-10 20:48:21 +0000589
590 return tentative;
jardineb5d44e2003-12-23 08:09:43 +0000591}
592
593/*
594 * Insert a node into the dictionary. The node should have been
595 * initialized with a data field. All other fields are ignored.
596 * The behavior is undefined if the user attempts to insert into
597 * a dictionary that is already full (for which the dict_isfull()
598 * function returns true).
599 */
600
hassof390d2c2004-09-10 20:48:21 +0000601void
602dict_insert (dict_t * dict, dnode_t * node, const void *key)
jardineb5d44e2003-12-23 08:09:43 +0000603{
hassof390d2c2004-09-10 20:48:21 +0000604 dnode_t *where = dict_root (dict), *nil = dict_nil (dict);
605 dnode_t *parent = nil, *uncle, *grandpa;
606 int result = -1;
jardineb5d44e2003-12-23 08:09:43 +0000607
hassof390d2c2004-09-10 20:48:21 +0000608 node->key = key;
jardineb5d44e2003-12-23 08:09:43 +0000609
hassof390d2c2004-09-10 20:48:21 +0000610 assert (!dict_isfull (dict));
611 assert (!dict_contains (dict, node));
612 assert (!dnode_is_in_a_dict (node));
jardineb5d44e2003-12-23 08:09:43 +0000613
hassof390d2c2004-09-10 20:48:21 +0000614 /* basic binary tree insert */
jardineb5d44e2003-12-23 08:09:43 +0000615
hassof390d2c2004-09-10 20:48:21 +0000616 while (where != nil)
617 {
618 parent = where;
619 result = dict->compare (key, where->key);
620 /* trap attempts at duplicate key insertion unless it's explicitly allowed */
621 assert (dict->dupes || result != 0);
622 if (result < 0)
623 where = where->left;
624 else
625 where = where->right;
jardineb5d44e2003-12-23 08:09:43 +0000626 }
627
hassof390d2c2004-09-10 20:48:21 +0000628 assert (where == nil);
jardineb5d44e2003-12-23 08:09:43 +0000629
hassof390d2c2004-09-10 20:48:21 +0000630 if (result < 0)
631 parent->left = node;
632 else
633 parent->right = node;
jardineb5d44e2003-12-23 08:09:43 +0000634
hassof390d2c2004-09-10 20:48:21 +0000635 node->parent = parent;
636 node->left = nil;
637 node->right = nil;
jardineb5d44e2003-12-23 08:09:43 +0000638
hassof390d2c2004-09-10 20:48:21 +0000639 dict->nodecount++;
jardineb5d44e2003-12-23 08:09:43 +0000640
hassof390d2c2004-09-10 20:48:21 +0000641 /* red black adjustments */
jardineb5d44e2003-12-23 08:09:43 +0000642
hassof390d2c2004-09-10 20:48:21 +0000643 node->color = dnode_red;
jardineb5d44e2003-12-23 08:09:43 +0000644
hassof390d2c2004-09-10 20:48:21 +0000645 while (parent->color == dnode_red)
646 {
647 grandpa = parent->parent;
648 if (parent == grandpa->left)
649 {
650 uncle = grandpa->right;
651 if (uncle->color == dnode_red)
652 { /* red parent, red uncle */
653 parent->color = dnode_black;
654 uncle->color = dnode_black;
655 grandpa->color = dnode_red;
656 node = grandpa;
657 parent = grandpa->parent;
jardineb5d44e2003-12-23 08:09:43 +0000658 }
hassof390d2c2004-09-10 20:48:21 +0000659 else
660 { /* red parent, black uncle */
661 if (node == parent->right)
662 {
663 rotate_left (parent);
664 parent = node;
665 assert (grandpa == parent->parent);
666 /* rotation between parent and child preserves grandpa */
jardineb5d44e2003-12-23 08:09:43 +0000667 }
hassof390d2c2004-09-10 20:48:21 +0000668 parent->color = dnode_black;
669 grandpa->color = dnode_red;
670 rotate_right (grandpa);
671 break;
672 }
673 }
674 else
675 { /* symmetric cases: parent == parent->parent->right */
676 uncle = grandpa->left;
677 if (uncle->color == dnode_red)
678 {
679 parent->color = dnode_black;
680 uncle->color = dnode_black;
681 grandpa->color = dnode_red;
682 node = grandpa;
683 parent = grandpa->parent;
684 }
685 else
686 {
687 if (node == parent->left)
688 {
689 rotate_right (parent);
690 parent = node;
691 assert (grandpa == parent->parent);
692 }
693 parent->color = dnode_black;
694 grandpa->color = dnode_red;
695 rotate_left (grandpa);
696 break;
jardineb5d44e2003-12-23 08:09:43 +0000697 }
698 }
699 }
700
hassof390d2c2004-09-10 20:48:21 +0000701 dict_root (dict)->color = dnode_black;
jardineb5d44e2003-12-23 08:09:43 +0000702
hassof390d2c2004-09-10 20:48:21 +0000703 assert (dict_verify (dict));
jardineb5d44e2003-12-23 08:09:43 +0000704}
705
706/*
707 * Delete the given node from the dictionary. If the given node does not belong
708 * to the given dictionary, undefined behavior results. A pointer to the
709 * deleted node is returned.
710 */
711
hassof390d2c2004-09-10 20:48:21 +0000712dnode_t *
713dict_delete (dict_t * dict, dnode_t * delete)
jardineb5d44e2003-12-23 08:09:43 +0000714{
hassof390d2c2004-09-10 20:48:21 +0000715 dnode_t *nil = dict_nil (dict), *child, *delparent = delete->parent;
jardineb5d44e2003-12-23 08:09:43 +0000716
hassof390d2c2004-09-10 20:48:21 +0000717 /* basic deletion */
jardineb5d44e2003-12-23 08:09:43 +0000718
hassof390d2c2004-09-10 20:48:21 +0000719 assert (!dict_isempty (dict));
720 assert (dict_contains (dict, delete));
jardineb5d44e2003-12-23 08:09:43 +0000721
hassof390d2c2004-09-10 20:48:21 +0000722 /*
723 * If the node being deleted has two children, then we replace it with its
724 * successor (i.e. the leftmost node in the right subtree.) By doing this,
725 * we avoid the traditional algorithm under which the successor's key and
726 * value *only* move to the deleted node and the successor is spliced out
727 * from the tree. We cannot use this approach because the user may hold
728 * pointers to the successor, or nodes may be inextricably tied to some
729 * other structures by way of embedding, etc. So we must splice out the
730 * node we are given, not some other node, and must not move contents from
731 * one node to another behind the user's back.
732 */
jardineb5d44e2003-12-23 08:09:43 +0000733
hassof390d2c2004-09-10 20:48:21 +0000734 if (delete->left != nil && delete->right != nil)
735 {
736 dnode_t *next = dict_next (dict, delete);
737 dnode_t *nextparent = next->parent;
738 dnode_color_t nextcolor = next->color;
jardineb5d44e2003-12-23 08:09:43 +0000739
hassof390d2c2004-09-10 20:48:21 +0000740 assert (next != nil);
741 assert (next->parent != nil);
742 assert (next->left == nil);
jardineb5d44e2003-12-23 08:09:43 +0000743
hassof390d2c2004-09-10 20:48:21 +0000744 /*
745 * First, splice out the successor from the tree completely, by
746 * moving up its right child into its place.
747 */
jardineb5d44e2003-12-23 08:09:43 +0000748
hassof390d2c2004-09-10 20:48:21 +0000749 child = next->right;
750 child->parent = nextparent;
jardineb5d44e2003-12-23 08:09:43 +0000751
hassof390d2c2004-09-10 20:48:21 +0000752 if (nextparent->left == next)
753 {
754 nextparent->left = child;
755 }
756 else
757 {
758 assert (nextparent->right == next);
759 nextparent->right = child;
jardineb5d44e2003-12-23 08:09:43 +0000760 }
761
hassof390d2c2004-09-10 20:48:21 +0000762 /*
763 * Now that the successor has been extricated from the tree, install it
764 * in place of the node that we want deleted.
765 */
jardineb5d44e2003-12-23 08:09:43 +0000766
hassof390d2c2004-09-10 20:48:21 +0000767 next->parent = delparent;
768 next->left = delete->left;
769 next->right = delete->right;
770 next->left->parent = next;
771 next->right->parent = next;
772 next->color = delete->color;
773 delete->color = nextcolor;
jardineb5d44e2003-12-23 08:09:43 +0000774
hassof390d2c2004-09-10 20:48:21 +0000775 if (delparent->left == delete)
776 {
777 delparent->left = next;
778 }
779 else
780 {
781 assert (delparent->right == delete);
782 delparent->right = next;
jardineb5d44e2003-12-23 08:09:43 +0000783 }
784
hassof390d2c2004-09-10 20:48:21 +0000785 }
786 else
787 {
788 assert (delete != nil);
789 assert (delete->left == nil || delete->right == nil);
jardineb5d44e2003-12-23 08:09:43 +0000790
hassof390d2c2004-09-10 20:48:21 +0000791 child = (delete->left != nil) ? delete->left : delete->right;
jardineb5d44e2003-12-23 08:09:43 +0000792
hassof390d2c2004-09-10 20:48:21 +0000793 child->parent = delparent = delete->parent;
jardineb5d44e2003-12-23 08:09:43 +0000794
hassof390d2c2004-09-10 20:48:21 +0000795 if (delete == delparent->left)
796 {
797 delparent->left = child;
798 }
799 else
800 {
801 assert (delete == delparent->right);
802 delparent->right = child;
jardineb5d44e2003-12-23 08:09:43 +0000803 }
804 }
805
hassof390d2c2004-09-10 20:48:21 +0000806 delete->parent = NULL;
807 delete->right = NULL;
808 delete->left = NULL;
jardineb5d44e2003-12-23 08:09:43 +0000809
hassof390d2c2004-09-10 20:48:21 +0000810 dict->nodecount--;
jardineb5d44e2003-12-23 08:09:43 +0000811
hassof390d2c2004-09-10 20:48:21 +0000812 assert (verify_bintree (dict));
jardineb5d44e2003-12-23 08:09:43 +0000813
hassof390d2c2004-09-10 20:48:21 +0000814 /* red-black adjustments */
jardineb5d44e2003-12-23 08:09:43 +0000815
hassof390d2c2004-09-10 20:48:21 +0000816 if (delete->color == dnode_black)
817 {
818 dnode_t *parent, *sister;
jardineb5d44e2003-12-23 08:09:43 +0000819
hassof390d2c2004-09-10 20:48:21 +0000820 dict_root (dict)->color = dnode_red;
jardineb5d44e2003-12-23 08:09:43 +0000821
hassof390d2c2004-09-10 20:48:21 +0000822 while (child->color == dnode_black)
823 {
824 parent = child->parent;
825 if (child == parent->left)
826 {
827 sister = parent->right;
828 assert (sister != nil);
829 if (sister->color == dnode_red)
830 {
831 sister->color = dnode_black;
832 parent->color = dnode_red;
833 rotate_left (parent);
834 sister = parent->right;
835 assert (sister != nil);
jardineb5d44e2003-12-23 08:09:43 +0000836 }
hassof390d2c2004-09-10 20:48:21 +0000837 if (sister->left->color == dnode_black
838 && sister->right->color == dnode_black)
839 {
840 sister->color = dnode_red;
841 child = parent;
842 }
843 else
844 {
845 if (sister->right->color == dnode_black)
846 {
847 assert (sister->left->color == dnode_red);
848 sister->left->color = dnode_black;
849 sister->color = dnode_red;
850 rotate_right (sister);
851 sister = parent->right;
852 assert (sister != nil);
jardineb5d44e2003-12-23 08:09:43 +0000853 }
hassof390d2c2004-09-10 20:48:21 +0000854 sister->color = parent->color;
855 sister->right->color = dnode_black;
856 parent->color = dnode_black;
857 rotate_left (parent);
858 break;
jardineb5d44e2003-12-23 08:09:43 +0000859 }
hassof390d2c2004-09-10 20:48:21 +0000860 }
861 else
862 { /* symmetric case: child == child->parent->right */
863 assert (child == parent->right);
864 sister = parent->left;
865 assert (sister != nil);
866 if (sister->color == dnode_red)
867 {
868 sister->color = dnode_black;
869 parent->color = dnode_red;
870 rotate_right (parent);
871 sister = parent->left;
872 assert (sister != nil);
jardineb5d44e2003-12-23 08:09:43 +0000873 }
hassof390d2c2004-09-10 20:48:21 +0000874 if (sister->right->color == dnode_black
875 && sister->left->color == dnode_black)
876 {
877 sister->color = dnode_red;
878 child = parent;
879 }
880 else
881 {
882 if (sister->left->color == dnode_black)
883 {
884 assert (sister->right->color == dnode_red);
885 sister->right->color = dnode_black;
886 sister->color = dnode_red;
887 rotate_left (sister);
888 sister = parent->left;
889 assert (sister != nil);
jardineb5d44e2003-12-23 08:09:43 +0000890 }
hassof390d2c2004-09-10 20:48:21 +0000891 sister->color = parent->color;
892 sister->left->color = dnode_black;
893 parent->color = dnode_black;
894 rotate_right (parent);
895 break;
jardineb5d44e2003-12-23 08:09:43 +0000896 }
897 }
898 }
899
hassof390d2c2004-09-10 20:48:21 +0000900 child->color = dnode_black;
901 dict_root (dict)->color = dnode_black;
jardineb5d44e2003-12-23 08:09:43 +0000902 }
903
hassof390d2c2004-09-10 20:48:21 +0000904 assert (dict_verify (dict));
jardineb5d44e2003-12-23 08:09:43 +0000905
hassof390d2c2004-09-10 20:48:21 +0000906 return delete;
jardineb5d44e2003-12-23 08:09:43 +0000907}
908
909/*
910 * Allocate a node using the dictionary's allocator routine, give it
911 * the data item.
912 */
913
hassof390d2c2004-09-10 20:48:21 +0000914int
915dict_alloc_insert (dict_t * dict, const void *key, void *data)
jardineb5d44e2003-12-23 08:09:43 +0000916{
hassof390d2c2004-09-10 20:48:21 +0000917 dnode_t *node = dict->allocnode (dict->context);
jardineb5d44e2003-12-23 08:09:43 +0000918
hassof390d2c2004-09-10 20:48:21 +0000919 if (node)
920 {
921 dnode_init (node, data);
922 dict_insert (dict, node, key);
923 return 1;
jardineb5d44e2003-12-23 08:09:43 +0000924 }
hassof390d2c2004-09-10 20:48:21 +0000925 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000926}
927
hassof390d2c2004-09-10 20:48:21 +0000928void
929dict_delete_free (dict_t * dict, dnode_t * node)
jardineb5d44e2003-12-23 08:09:43 +0000930{
hassof390d2c2004-09-10 20:48:21 +0000931 dict_delete (dict, node);
932 dict->freenode (node, dict->context);
jardineb5d44e2003-12-23 08:09:43 +0000933}
934
935/*
936 * Return the node with the lowest (leftmost) key. If the dictionary is empty
937 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
938 */
939
hassof390d2c2004-09-10 20:48:21 +0000940dnode_t *
941dict_first (dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +0000942{
hassof390d2c2004-09-10 20:48:21 +0000943 dnode_t *nil = dict_nil (dict), *root = dict_root (dict), *left;
jardineb5d44e2003-12-23 08:09:43 +0000944
hassof390d2c2004-09-10 20:48:21 +0000945 if (root != nil)
946 while ((left = root->left) != nil)
947 root = left;
jardineb5d44e2003-12-23 08:09:43 +0000948
hassof390d2c2004-09-10 20:48:21 +0000949 return (root == nil) ? NULL : root;
jardineb5d44e2003-12-23 08:09:43 +0000950}
951
952/*
953 * Return the node with the highest (rightmost) key. If the dictionary is empty
954 * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
955 */
956
hassof390d2c2004-09-10 20:48:21 +0000957dnode_t *
958dict_last (dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +0000959{
hassof390d2c2004-09-10 20:48:21 +0000960 dnode_t *nil = dict_nil (dict), *root = dict_root (dict), *right;
jardineb5d44e2003-12-23 08:09:43 +0000961
hassof390d2c2004-09-10 20:48:21 +0000962 if (root != nil)
963 while ((right = root->right) != nil)
964 root = right;
jardineb5d44e2003-12-23 08:09:43 +0000965
hassof390d2c2004-09-10 20:48:21 +0000966 return (root == nil) ? NULL : root;
jardineb5d44e2003-12-23 08:09:43 +0000967}
968
969/*
970 * Return the given node's successor node---the node which has the
971 * next key in the the left to right ordering. If the node has
972 * no successor, a null pointer is returned rather than a pointer to
973 * the nil node.
974 */
975
hassof390d2c2004-09-10 20:48:21 +0000976dnode_t *
977dict_next (dict_t * dict, dnode_t * curr)
jardineb5d44e2003-12-23 08:09:43 +0000978{
hassof390d2c2004-09-10 20:48:21 +0000979 dnode_t *nil = dict_nil (dict), *parent, *left;
jardineb5d44e2003-12-23 08:09:43 +0000980
hassof390d2c2004-09-10 20:48:21 +0000981 if (curr->right != nil)
982 {
983 curr = curr->right;
984 while ((left = curr->left) != nil)
985 curr = left;
986 return curr;
jardineb5d44e2003-12-23 08:09:43 +0000987 }
988
hassof390d2c2004-09-10 20:48:21 +0000989 parent = curr->parent;
jardineb5d44e2003-12-23 08:09:43 +0000990
hassof390d2c2004-09-10 20:48:21 +0000991 while (parent != nil && curr == parent->right)
992 {
993 curr = parent;
994 parent = curr->parent;
jardineb5d44e2003-12-23 08:09:43 +0000995 }
996
hassof390d2c2004-09-10 20:48:21 +0000997 return (parent == nil) ? NULL : parent;
jardineb5d44e2003-12-23 08:09:43 +0000998}
999
1000/*
1001 * Return the given node's predecessor, in the key order.
1002 * The nil sentinel node is returned if there is no predecessor.
1003 */
1004
hassof390d2c2004-09-10 20:48:21 +00001005dnode_t *
1006dict_prev (dict_t * dict, dnode_t * curr)
jardineb5d44e2003-12-23 08:09:43 +00001007{
hassof390d2c2004-09-10 20:48:21 +00001008 dnode_t *nil = dict_nil (dict), *parent, *right;
jardineb5d44e2003-12-23 08:09:43 +00001009
hassof390d2c2004-09-10 20:48:21 +00001010 if (curr->left != nil)
1011 {
1012 curr = curr->left;
1013 while ((right = curr->right) != nil)
1014 curr = right;
1015 return curr;
jardineb5d44e2003-12-23 08:09:43 +00001016 }
1017
hassof390d2c2004-09-10 20:48:21 +00001018 parent = curr->parent;
jardineb5d44e2003-12-23 08:09:43 +00001019
hassof390d2c2004-09-10 20:48:21 +00001020 while (parent != nil && curr == parent->left)
1021 {
1022 curr = parent;
1023 parent = curr->parent;
jardineb5d44e2003-12-23 08:09:43 +00001024 }
1025
hassof390d2c2004-09-10 20:48:21 +00001026 return (parent == nil) ? NULL : parent;
jardineb5d44e2003-12-23 08:09:43 +00001027}
1028
hassof390d2c2004-09-10 20:48:21 +00001029void
1030dict_allow_dupes (dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +00001031{
hassof390d2c2004-09-10 20:48:21 +00001032 dict->dupes = 1;
jardineb5d44e2003-12-23 08:09:43 +00001033}
1034
1035#undef dict_count
1036#undef dict_isempty
1037#undef dict_isfull
1038#undef dnode_get
1039#undef dnode_put
1040#undef dnode_getkey
1041
hassof390d2c2004-09-10 20:48:21 +00001042dictcount_t
1043dict_count (dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +00001044{
hassof390d2c2004-09-10 20:48:21 +00001045 return dict->nodecount;
jardineb5d44e2003-12-23 08:09:43 +00001046}
1047
hassof390d2c2004-09-10 20:48:21 +00001048int
1049dict_isempty (dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +00001050{
hassof390d2c2004-09-10 20:48:21 +00001051 return dict->nodecount == 0;
jardineb5d44e2003-12-23 08:09:43 +00001052}
1053
hassof390d2c2004-09-10 20:48:21 +00001054int
1055dict_isfull (dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +00001056{
hassof390d2c2004-09-10 20:48:21 +00001057 return dict->nodecount == dict->maxcount;
jardineb5d44e2003-12-23 08:09:43 +00001058}
1059
hassof390d2c2004-09-10 20:48:21 +00001060int
1061dict_contains (dict_t * dict, dnode_t * node)
jardineb5d44e2003-12-23 08:09:43 +00001062{
hassof390d2c2004-09-10 20:48:21 +00001063 return verify_dict_has_node (dict_nil (dict), dict_root (dict), node);
jardineb5d44e2003-12-23 08:09:43 +00001064}
1065
hassof390d2c2004-09-10 20:48:21 +00001066static dnode_t *
1067dnode_alloc (void *context)
jardineb5d44e2003-12-23 08:09:43 +00001068{
hassof390d2c2004-09-10 20:48:21 +00001069 return malloc (sizeof *dnode_alloc (NULL));
jardineb5d44e2003-12-23 08:09:43 +00001070}
1071
hassof390d2c2004-09-10 20:48:21 +00001072static void
1073dnode_free (dnode_t * node, void *context)
jardineb5d44e2003-12-23 08:09:43 +00001074{
hassof390d2c2004-09-10 20:48:21 +00001075 free (node);
jardineb5d44e2003-12-23 08:09:43 +00001076}
1077
hassof390d2c2004-09-10 20:48:21 +00001078dnode_t *
1079dnode_create (void *data)
jardineb5d44e2003-12-23 08:09:43 +00001080{
hassof390d2c2004-09-10 20:48:21 +00001081 dnode_t *new = malloc (sizeof *new);
1082 if (new)
1083 {
1084 new->data = data;
1085 new->parent = NULL;
1086 new->left = NULL;
1087 new->right = NULL;
jardineb5d44e2003-12-23 08:09:43 +00001088 }
hassof390d2c2004-09-10 20:48:21 +00001089 return new;
jardineb5d44e2003-12-23 08:09:43 +00001090}
1091
hassof390d2c2004-09-10 20:48:21 +00001092dnode_t *
1093dnode_init (dnode_t * dnode, void *data)
jardineb5d44e2003-12-23 08:09:43 +00001094{
hassof390d2c2004-09-10 20:48:21 +00001095 dnode->data = data;
1096 dnode->parent = NULL;
1097 dnode->left = NULL;
1098 dnode->right = NULL;
1099 return dnode;
jardineb5d44e2003-12-23 08:09:43 +00001100}
1101
hassof390d2c2004-09-10 20:48:21 +00001102void
1103dnode_destroy (dnode_t * dnode)
jardineb5d44e2003-12-23 08:09:43 +00001104{
hassof390d2c2004-09-10 20:48:21 +00001105 assert (!dnode_is_in_a_dict (dnode));
1106 free (dnode);
jardineb5d44e2003-12-23 08:09:43 +00001107}
1108
hassof390d2c2004-09-10 20:48:21 +00001109void *
1110dnode_get (dnode_t * dnode)
jardineb5d44e2003-12-23 08:09:43 +00001111{
hassof390d2c2004-09-10 20:48:21 +00001112 return dnode->data;
jardineb5d44e2003-12-23 08:09:43 +00001113}
1114
hassof390d2c2004-09-10 20:48:21 +00001115const void *
1116dnode_getkey (dnode_t * dnode)
jardineb5d44e2003-12-23 08:09:43 +00001117{
hassof390d2c2004-09-10 20:48:21 +00001118 return dnode->key;
jardineb5d44e2003-12-23 08:09:43 +00001119}
1120
hassof390d2c2004-09-10 20:48:21 +00001121void
1122dnode_put (dnode_t * dnode, void *data)
jardineb5d44e2003-12-23 08:09:43 +00001123{
hassof390d2c2004-09-10 20:48:21 +00001124 dnode->data = data;
jardineb5d44e2003-12-23 08:09:43 +00001125}
1126
hassof390d2c2004-09-10 20:48:21 +00001127int
1128dnode_is_in_a_dict (dnode_t * dnode)
jardineb5d44e2003-12-23 08:09:43 +00001129{
hassof390d2c2004-09-10 20:48:21 +00001130 return (dnode->parent && dnode->left && dnode->right);
jardineb5d44e2003-12-23 08:09:43 +00001131}
1132
hassof390d2c2004-09-10 20:48:21 +00001133void
1134dict_process (dict_t * dict, void *context, dnode_process_t function)
jardineb5d44e2003-12-23 08:09:43 +00001135{
hassof390d2c2004-09-10 20:48:21 +00001136 dnode_t *node = dict_first (dict), *next;
jardineb5d44e2003-12-23 08:09:43 +00001137
hassof390d2c2004-09-10 20:48:21 +00001138 while (node != NULL)
1139 {
1140 /* check for callback function deleting */
1141 /* the next node from under us */
1142 assert (dict_contains (dict, node));
1143 next = dict_next (dict, node);
1144 function (dict, node, context);
1145 node = next;
jardineb5d44e2003-12-23 08:09:43 +00001146 }
1147}
1148
hassof390d2c2004-09-10 20:48:21 +00001149static void
1150load_begin_internal (dict_load_t * load, dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +00001151{
hassof390d2c2004-09-10 20:48:21 +00001152 load->dictptr = dict;
1153 load->nilnode.left = &load->nilnode;
1154 load->nilnode.right = &load->nilnode;
jardineb5d44e2003-12-23 08:09:43 +00001155}
1156
hassof390d2c2004-09-10 20:48:21 +00001157void
1158dict_load_begin (dict_load_t * load, dict_t * dict)
jardineb5d44e2003-12-23 08:09:43 +00001159{
hassof390d2c2004-09-10 20:48:21 +00001160 assert (dict_isempty (dict));
1161 load_begin_internal (load, dict);
jardineb5d44e2003-12-23 08:09:43 +00001162}
1163
hassof390d2c2004-09-10 20:48:21 +00001164void
1165dict_load_next (dict_load_t * load, dnode_t * newnode, const void *key)
jardineb5d44e2003-12-23 08:09:43 +00001166{
hassof390d2c2004-09-10 20:48:21 +00001167 dict_t *dict = load->dictptr;
1168 dnode_t *nil = &load->nilnode;
jardineb5d44e2003-12-23 08:09:43 +00001169
hassof390d2c2004-09-10 20:48:21 +00001170 assert (!dnode_is_in_a_dict (newnode));
1171 assert (dict->nodecount < dict->maxcount);
1172
1173#ifndef NDEBUG
1174 if (dict->nodecount > 0)
1175 {
1176 if (dict->dupes)
1177 assert (dict->compare (nil->left->key, key) <= 0);
1178 else
1179 assert (dict->compare (nil->left->key, key) < 0);
jardineb5d44e2003-12-23 08:09:43 +00001180 }
hassof390d2c2004-09-10 20:48:21 +00001181#endif
jardineb5d44e2003-12-23 08:09:43 +00001182
hassof390d2c2004-09-10 20:48:21 +00001183 newnode->key = key;
1184 nil->right->left = newnode;
1185 nil->right = newnode;
1186 newnode->left = nil;
1187 dict->nodecount++;
jardineb5d44e2003-12-23 08:09:43 +00001188}
1189
hassof390d2c2004-09-10 20:48:21 +00001190void
1191dict_load_end (dict_load_t * load)
jardineb5d44e2003-12-23 08:09:43 +00001192{
hassof390d2c2004-09-10 20:48:21 +00001193 dict_t *dict = load->dictptr;
1194 dnode_t *tree[DICT_DEPTH_MAX] = { 0 };
1195 dnode_t *curr, *dictnil = dict_nil (dict), *loadnil = &load->nilnode, *next;
1196 dnode_t *complete = 0;
1197 dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount;
1198 dictcount_t botrowcount;
1199 unsigned baselevel = 0, level = 0, i;
jardineb5d44e2003-12-23 08:09:43 +00001200
hassof390d2c2004-09-10 20:48:21 +00001201 assert (dnode_red == 0 && dnode_black == 1);
jardineb5d44e2003-12-23 08:09:43 +00001202
hassof390d2c2004-09-10 20:48:21 +00001203 while (fullcount >= nodecount && fullcount)
1204 fullcount >>= 1;
jardineb5d44e2003-12-23 08:09:43 +00001205
hassof390d2c2004-09-10 20:48:21 +00001206 botrowcount = nodecount - fullcount;
jardineb5d44e2003-12-23 08:09:43 +00001207
hassof390d2c2004-09-10 20:48:21 +00001208 for (curr = loadnil->left; curr != loadnil; curr = next)
1209 {
1210 next = curr->left;
jardineb5d44e2003-12-23 08:09:43 +00001211
hassof390d2c2004-09-10 20:48:21 +00001212 if (complete == NULL && botrowcount-- == 0)
1213 {
1214 assert (baselevel == 0);
1215 assert (level == 0);
1216 baselevel = level = 1;
1217 complete = tree[0];
jardineb5d44e2003-12-23 08:09:43 +00001218
hassof390d2c2004-09-10 20:48:21 +00001219 if (complete != 0)
1220 {
1221 tree[0] = 0;
1222 complete->right = dictnil;
1223 while (tree[level] != 0)
1224 {
1225 tree[level]->right = complete;
1226 complete->parent = tree[level];
1227 complete = tree[level];
1228 tree[level++] = 0;
jardineb5d44e2003-12-23 08:09:43 +00001229 }
1230 }
1231 }
1232
hassof390d2c2004-09-10 20:48:21 +00001233 if (complete == NULL)
1234 {
1235 curr->left = dictnil;
1236 curr->right = dictnil;
1237 curr->color = level % 2;
1238 complete = curr;
jardineb5d44e2003-12-23 08:09:43 +00001239
hassof390d2c2004-09-10 20:48:21 +00001240 assert (level == baselevel);
1241 while (tree[level] != 0)
1242 {
1243 tree[level]->right = complete;
1244 complete->parent = tree[level];
1245 complete = tree[level];
1246 tree[level++] = 0;
jardineb5d44e2003-12-23 08:09:43 +00001247 }
hassof390d2c2004-09-10 20:48:21 +00001248 }
1249 else
1250 {
1251 curr->left = complete;
1252 curr->color = (level + 1) % 2;
1253 complete->parent = curr;
1254 tree[level] = curr;
1255 complete = 0;
1256 level = baselevel;
jardineb5d44e2003-12-23 08:09:43 +00001257 }
1258 }
1259
hassof390d2c2004-09-10 20:48:21 +00001260 if (complete == NULL)
1261 complete = dictnil;
jardineb5d44e2003-12-23 08:09:43 +00001262
hassof390d2c2004-09-10 20:48:21 +00001263 for (i = 0; i < DICT_DEPTH_MAX; i++)
1264 {
1265 if (tree[i] != 0)
1266 {
1267 tree[i]->right = complete;
1268 complete->parent = tree[i];
1269 complete = tree[i];
jardineb5d44e2003-12-23 08:09:43 +00001270 }
1271 }
1272
hassof390d2c2004-09-10 20:48:21 +00001273 dictnil->color = dnode_black;
1274 dictnil->right = dictnil;
1275 complete->parent = dictnil;
1276 complete->color = dnode_black;
1277 dict_root (dict) = complete;
jardineb5d44e2003-12-23 08:09:43 +00001278
hassof390d2c2004-09-10 20:48:21 +00001279 assert (dict_verify (dict));
jardineb5d44e2003-12-23 08:09:43 +00001280}
1281
hassof390d2c2004-09-10 20:48:21 +00001282void
1283dict_merge (dict_t * dest, dict_t * source)
jardineb5d44e2003-12-23 08:09:43 +00001284{
hassof390d2c2004-09-10 20:48:21 +00001285 dict_load_t load;
1286 dnode_t *leftnode = dict_first (dest), *rightnode = dict_first (source);
jardineb5d44e2003-12-23 08:09:43 +00001287
hassof390d2c2004-09-10 20:48:21 +00001288 assert (dict_similar (dest, source));
jardineb5d44e2003-12-23 08:09:43 +00001289
hassof390d2c2004-09-10 20:48:21 +00001290 if (source == dest)
1291 return;
jardineb5d44e2003-12-23 08:09:43 +00001292
hassof390d2c2004-09-10 20:48:21 +00001293 dest->nodecount = 0;
1294 load_begin_internal (&load, dest);
jardineb5d44e2003-12-23 08:09:43 +00001295
hassof390d2c2004-09-10 20:48:21 +00001296 for (;;)
1297 {
1298 if (leftnode != NULL && rightnode != NULL)
1299 {
1300 if (dest->compare (leftnode->key, rightnode->key) < 0)
jardineb5d44e2003-12-23 08:09:43 +00001301 goto copyleft;
hassof390d2c2004-09-10 20:48:21 +00001302 else
jardineb5d44e2003-12-23 08:09:43 +00001303 goto copyright;
hassof390d2c2004-09-10 20:48:21 +00001304 }
1305 else if (leftnode != NULL)
1306 {
1307 goto copyleft;
1308 }
1309 else if (rightnode != NULL)
1310 {
1311 goto copyright;
1312 }
1313 else
1314 {
1315 assert (leftnode == NULL && rightnode == NULL);
1316 break;
jardineb5d44e2003-12-23 08:09:43 +00001317 }
1318
1319 copyleft:
hassof390d2c2004-09-10 20:48:21 +00001320 {
1321 dnode_t *next = dict_next (dest, leftnode);
1322#ifndef NDEBUG
1323 leftnode->left = NULL; /* suppress assertion in dict_load_next */
1324#endif
1325 dict_load_next (&load, leftnode, leftnode->key);
1326 leftnode = next;
1327 continue;
1328 }
1329
jardineb5d44e2003-12-23 08:09:43 +00001330 copyright:
hassof390d2c2004-09-10 20:48:21 +00001331 {
1332 dnode_t *next = dict_next (source, rightnode);
1333#ifndef NDEBUG
1334 rightnode->left = NULL;
1335#endif
1336 dict_load_next (&load, rightnode, rightnode->key);
1337 rightnode = next;
1338 continue;
1339 }
jardineb5d44e2003-12-23 08:09:43 +00001340 }
1341
hassof390d2c2004-09-10 20:48:21 +00001342 dict_clear (source);
1343 dict_load_end (&load);
jardineb5d44e2003-12-23 08:09:43 +00001344}
1345
1346#ifdef KAZLIB_TEST_MAIN
1347
1348#include <stdio.h>
1349#include <string.h>
1350#include <ctype.h>
1351#include <stdarg.h>
1352
1353typedef char input_t[256];
1354
hassof390d2c2004-09-10 20:48:21 +00001355static int
1356tokenize (char *string, ...)
jardineb5d44e2003-12-23 08:09:43 +00001357{
hassof390d2c2004-09-10 20:48:21 +00001358 char **tokptr;
1359 va_list arglist;
1360 int tokcount = 0;
jardineb5d44e2003-12-23 08:09:43 +00001361
hassof390d2c2004-09-10 20:48:21 +00001362 va_start (arglist, string);
1363 tokptr = va_arg (arglist, char **);
1364 while (tokptr)
1365 {
1366 while (*string && isspace ((unsigned char) *string))
1367 string++;
1368 if (!*string)
1369 break;
1370 *tokptr = string;
1371 while (*string && !isspace ((unsigned char) *string))
1372 string++;
1373 tokptr = va_arg (arglist, char **);
1374 tokcount++;
1375 if (!*string)
1376 break;
1377 *string++ = 0;
jardineb5d44e2003-12-23 08:09:43 +00001378 }
hassof390d2c2004-09-10 20:48:21 +00001379 va_end (arglist);
jardineb5d44e2003-12-23 08:09:43 +00001380
hassof390d2c2004-09-10 20:48:21 +00001381 return tokcount;
jardineb5d44e2003-12-23 08:09:43 +00001382}
1383
hassof390d2c2004-09-10 20:48:21 +00001384static int
1385comparef (const void *key1, const void *key2)
jardineb5d44e2003-12-23 08:09:43 +00001386{
hassof390d2c2004-09-10 20:48:21 +00001387 return strcmp (key1, key2);
jardineb5d44e2003-12-23 08:09:43 +00001388}
1389
hassof390d2c2004-09-10 20:48:21 +00001390static char *
1391dupstring (char *str)
jardineb5d44e2003-12-23 08:09:43 +00001392{
hassof390d2c2004-09-10 20:48:21 +00001393 int sz = strlen (str) + 1;
1394 char *new = malloc (sz);
1395 if (new)
1396 memcpy (new, str, sz);
1397 return new;
jardineb5d44e2003-12-23 08:09:43 +00001398}
1399
hassof390d2c2004-09-10 20:48:21 +00001400static dnode_t *
1401new_node (void *c)
jardineb5d44e2003-12-23 08:09:43 +00001402{
hassof390d2c2004-09-10 20:48:21 +00001403 static dnode_t few[5];
1404 static int count;
jardineb5d44e2003-12-23 08:09:43 +00001405
hassof390d2c2004-09-10 20:48:21 +00001406 if (count < 5)
1407 return few + count++;
jardineb5d44e2003-12-23 08:09:43 +00001408
hassof390d2c2004-09-10 20:48:21 +00001409 return NULL;
jardineb5d44e2003-12-23 08:09:43 +00001410}
1411
hassof390d2c2004-09-10 20:48:21 +00001412static void
1413del_node (dnode_t * n, void *c)
jardineb5d44e2003-12-23 08:09:43 +00001414{
1415}
1416
1417static int prompt = 0;
1418
hassof390d2c2004-09-10 20:48:21 +00001419static void
1420construct (dict_t * d)
jardineb5d44e2003-12-23 08:09:43 +00001421{
hassof390d2c2004-09-10 20:48:21 +00001422 input_t in;
1423 int done = 0;
1424 dict_load_t dl;
1425 dnode_t *dn;
1426 char *tok1, *tok2, *val;
1427 const char *key;
1428 char *help =
1429 "p turn prompt on\n"
1430 "q finish construction\n"
1431 "a <key> <val> add new entry\n";
jardineb5d44e2003-12-23 08:09:43 +00001432
hassof390d2c2004-09-10 20:48:21 +00001433 if (!dict_isempty (d))
1434 puts ("warning: dictionary not empty!");
jardineb5d44e2003-12-23 08:09:43 +00001435
hassof390d2c2004-09-10 20:48:21 +00001436 dict_load_begin (&dl, d);
jardineb5d44e2003-12-23 08:09:43 +00001437
hassof390d2c2004-09-10 20:48:21 +00001438 while (!done)
1439 {
1440 if (prompt)
1441 putchar ('>');
1442 fflush (stdout);
jardineb5d44e2003-12-23 08:09:43 +00001443
hassof390d2c2004-09-10 20:48:21 +00001444 if (!fgets (in, sizeof (input_t), stdin))
1445 break;
jardineb5d44e2003-12-23 08:09:43 +00001446
hassof390d2c2004-09-10 20:48:21 +00001447 switch (in[0])
1448 {
1449 case '?':
1450 puts (help);
1451 break;
1452 case 'p':
1453 prompt = 1;
1454 break;
1455 case 'q':
1456 done = 1;
1457 break;
1458 case 'a':
1459 if (tokenize (in + 1, &tok1, &tok2, (char **) 0) != 2)
1460 {
1461 puts ("what?");
1462 break;
1463 }
1464 key = dupstring (tok1);
1465 val = dupstring (tok2);
1466 dn = dnode_create (val);
jardineb5d44e2003-12-23 08:09:43 +00001467
hassof390d2c2004-09-10 20:48:21 +00001468 if (!key || !val || !dn)
1469 {
1470 puts ("out of memory");
1471 free ((void *) key);
1472 free (val);
1473 if (dn)
1474 dnode_destroy (dn);
1475 }
jardineb5d44e2003-12-23 08:09:43 +00001476
hassof390d2c2004-09-10 20:48:21 +00001477 dict_load_next (&dl, dn, key);
1478 break;
1479 default:
1480 putchar ('?');
1481 putchar ('\n');
1482 break;
jardineb5d44e2003-12-23 08:09:43 +00001483 }
1484 }
1485
hassof390d2c2004-09-10 20:48:21 +00001486 dict_load_end (&dl);
jardineb5d44e2003-12-23 08:09:43 +00001487}
1488
hassof390d2c2004-09-10 20:48:21 +00001489int
1490main (void)
jardineb5d44e2003-12-23 08:09:43 +00001491{
hassof390d2c2004-09-10 20:48:21 +00001492 input_t in;
1493 dict_t darray[10];
1494 dict_t *d = &darray[0];
1495 dnode_t *dn;
1496 int i;
1497 char *tok1, *tok2, *val;
1498 const char *key;
jardineb5d44e2003-12-23 08:09:43 +00001499
hassof390d2c2004-09-10 20:48:21 +00001500 char *help =
1501 "a <key> <val> add value to dictionary\n"
1502 "d <key> delete value from dictionary\n"
1503 "l <key> lookup value in dictionary\n"
1504 "( <key> lookup lower bound\n"
1505 ") <key> lookup upper bound\n"
1506 "# <num> switch to alternate dictionary (0-9)\n"
1507 "j <num> <num> merge two dictionaries\n"
1508 "f free the whole dictionary\n"
1509 "k allow duplicate keys\n"
1510 "c show number of entries\n"
1511 "t dump whole dictionary in sort order\n"
1512 "m make dictionary out of sorted items\n"
1513 "p turn prompt on\n"
1514 "s switch to non-functioning allocator\n"
1515 "q quit";
jardineb5d44e2003-12-23 08:09:43 +00001516
hassof390d2c2004-09-10 20:48:21 +00001517 for (i = 0; i < sizeof darray / sizeof *darray; i++)
1518 dict_init (&darray[i], DICTCOUNT_T_MAX, comparef);
jardineb5d44e2003-12-23 08:09:43 +00001519
hassof390d2c2004-09-10 20:48:21 +00001520 for (;;)
1521 {
1522 if (prompt)
1523 putchar ('>');
1524 fflush (stdout);
jardineb5d44e2003-12-23 08:09:43 +00001525
hassof390d2c2004-09-10 20:48:21 +00001526 if (!fgets (in, sizeof (input_t), stdin))
1527 break;
jardineb5d44e2003-12-23 08:09:43 +00001528
hassof390d2c2004-09-10 20:48:21 +00001529 switch (in[0])
1530 {
1531 case '?':
1532 puts (help);
1533 break;
1534 case 'a':
1535 if (tokenize (in + 1, &tok1, &tok2, (char **) 0) != 2)
1536 {
1537 puts ("what?");
1538 break;
1539 }
1540 key = dupstring (tok1);
1541 val = dupstring (tok2);
jardineb5d44e2003-12-23 08:09:43 +00001542
hassof390d2c2004-09-10 20:48:21 +00001543 if (!key || !val)
1544 {
1545 puts ("out of memory");
1546 free ((void *) key);
1547 free (val);
1548 }
jardineb5d44e2003-12-23 08:09:43 +00001549
hassof390d2c2004-09-10 20:48:21 +00001550 if (!dict_alloc_insert (d, key, val))
1551 {
1552 puts ("dict_alloc_insert failed");
1553 free ((void *) key);
1554 free (val);
1555 break;
1556 }
1557 break;
1558 case 'd':
1559 if (tokenize (in + 1, &tok1, (char **) 0) != 1)
1560 {
1561 puts ("what?");
1562 break;
1563 }
1564 dn = dict_lookup (d, tok1);
1565 if (!dn)
1566 {
1567 puts ("dict_lookup failed");
1568 break;
1569 }
1570 val = dnode_get (dn);
1571 key = dnode_getkey (dn);
1572 dict_delete_free (d, dn);
jardineb5d44e2003-12-23 08:09:43 +00001573
hassof390d2c2004-09-10 20:48:21 +00001574 free (val);
1575 free ((void *) key);
1576 break;
1577 case 'f':
1578 dict_free (d);
1579 break;
1580 case 'l':
1581 case '(':
1582 case ')':
1583 if (tokenize (in + 1, &tok1, (char **) 0) != 1)
1584 {
1585 puts ("what?");
1586 break;
1587 }
1588 dn = 0;
1589 switch (in[0])
1590 {
jardineb5d44e2003-12-23 08:09:43 +00001591 case 'l':
hassof390d2c2004-09-10 20:48:21 +00001592 dn = dict_lookup (d, tok1);
1593 break;
jardineb5d44e2003-12-23 08:09:43 +00001594 case '(':
hassof390d2c2004-09-10 20:48:21 +00001595 dn = dict_lower_bound (d, tok1);
1596 break;
jardineb5d44e2003-12-23 08:09:43 +00001597 case ')':
hassof390d2c2004-09-10 20:48:21 +00001598 dn = dict_upper_bound (d, tok1);
1599 break;
1600 }
1601 if (!dn)
1602 {
1603 puts ("lookup failed");
1604 break;
1605 }
1606 val = dnode_get (dn);
1607 puts (val);
1608 break;
1609 case 'm':
1610 construct (d);
1611 break;
1612 case 'k':
1613 dict_allow_dupes (d);
1614 break;
1615 case 'c':
1616 printf ("%lu\n", (unsigned long) dict_count (d));
1617 break;
1618 case 't':
1619 for (dn = dict_first (d); dn; dn = dict_next (d, dn))
1620 {
1621 printf ("%s\t%s\n", (char *) dnode_getkey (dn),
1622 (char *) dnode_get (dn));
1623 }
1624 break;
1625 case 'q':
1626 exit (0);
1627 break;
1628 case '\0':
1629 break;
1630 case 'p':
1631 prompt = 1;
1632 break;
1633 case 's':
1634 dict_set_allocator (d, new_node, del_node, NULL);
1635 break;
1636 case '#':
1637 if (tokenize (in + 1, &tok1, (char **) 0) != 1)
1638 {
1639 puts ("what?");
1640 break;
1641 }
1642 else
1643 {
1644 int dictnum = atoi (tok1);
1645 if (dictnum < 0 || dictnum > 9)
1646 {
1647 puts ("invalid number");
1648 break;
jardineb5d44e2003-12-23 08:09:43 +00001649 }
hassof390d2c2004-09-10 20:48:21 +00001650 d = &darray[dictnum];
1651 }
1652 break;
1653 case 'j':
1654 if (tokenize (in + 1, &tok1, &tok2, (char **) 0) != 2)
1655 {
1656 puts ("what?");
1657 break;
1658 }
1659 else
1660 {
1661 int dict1 = atoi (tok1), dict2 = atoi (tok2);
1662 if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9)
1663 {
1664 puts ("invalid number");
1665 break;
jardineb5d44e2003-12-23 08:09:43 +00001666 }
hassof390d2c2004-09-10 20:48:21 +00001667 dict_merge (&darray[dict1], &darray[dict2]);
1668 }
1669 break;
1670 default:
1671 putchar ('?');
1672 putchar ('\n');
1673 break;
jardineb5d44e2003-12-23 08:09:43 +00001674 }
1675 }
1676
hassof390d2c2004-09-10 20:48:21 +00001677 return 0;
jardineb5d44e2003-12-23 08:09:43 +00001678}
1679
1680#endif