5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2008 Pekka Riikonen
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are
13 1. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15 2. Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18 3. The name of the author may not be used to endorse or promote
19 products derived from this software without specific prior written
22 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
25 NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 /* AVL Tree. This code is based on code in libdict package. I am putting
36 all changes under the same license, that is the revised BSD license. The
37 original code is copyright by Farooq Mela.
39 Main differences are that this implementation does not use a separate
40 node context but the user provided entry itself is the node in the tree,
41 thus avoiding issues like memory allocation, cleanup, etc., and making
42 the interface more generic. This interface does not allocate any
43 memory. This implementation also supports duplicates by adding them to
46 #include <silcruntime.h>
48 /************************ Static utility functions **************************/
60 static int silc_avl_tree_rot_left(SilcTree *tree, SilcTreeHeader *h)
62 SilcTreeHeader *right, *parent;
66 SILC_ASSERT(h->right);
69 h->right = right->left;
71 right->left->parent = h;
74 right->parent = parent;
77 if (parent->left == h)
80 parent->right = right;
89 h->t -= 1 + SILC_MAX(right->t, 0);
90 right->t -= 1 - SILC_MIN(h->t, 0);
105 static int silc_avl_tree_rot_right(SilcTree *tree, SilcTreeHeader *h)
107 SilcTreeHeader *left, *parent;
111 SILC_ASSERT(h->left);
114 h->left = left->right;
116 left->right->parent = h;
119 left->parent = parent;
122 if (parent->left == h)
125 parent->right = left;
134 h->t += 1 - SILC_MIN(left->t, 0);
135 left->t += 1 + SILC_MAX(h->t, 0);
140 /****************************** Public API **********************************/
144 void *silc_avl_tree_find(SilcTree *tree, void *entry,
145 SilcTreeCompare compare, void *context)
148 SilcTreeCompare cmp = compare ? compare : tree->compare;
149 void *cmp_context = compare ? context : tree->context;
152 SILC_LOG_DEBUG(("AVL tree %p, find %p", tree, entry));
156 ret = cmp(entry, SILC_TREE_GET_ENTRY(tree, h), cmp_context);
158 SILC_LOG_DEBUG(("Found %p", SILC_TREE_GET_ENTRY(tree, h)));
159 return SILC_TREE_GET_ENTRY(tree, h);
161 h = ret > 0 ? h->right : h->left;
164 SILC_LOG_DEBUG(("Not found"));
165 silc_set_errno(SILC_ERR_NOT_FOUND);
169 /* Insert entry to tree */
171 SilcBool silc_avl_tree_add(SilcTree *tree, void *entry)
173 SilcTreeHeader *h, *parent = NULL, *q = NULL;
176 SILC_LOG_DEBUG(("AVL tree %p, adding %p", tree, entry));
178 /* If tree is empty, add to root */
180 h = SILC_TREE_GET_HEADER(tree, entry);
181 h->parent = h->left = h->right = h->dup = NULL;
185 SILC_LOG_DEBUG(("Entry %p added as root", entry));
187 SILC_ASSERT(!tree->count);
192 /* Find the spot to add the new entry */
195 /* Same entry context must not be in tree */
196 if (entry == SILC_TREE_GET_ENTRY(tree, h)) {
197 silc_set_errno(SILC_ERR_ALREADY_EXISTS);
201 ret = tree->compare(entry, SILC_TREE_GET_ENTRY(tree, h), tree->context);
202 if (!tree->duplicates && ret == 0) {
203 silc_set_errno(SILC_ERR_ALREADY_EXISTS);
207 /* Duplicate entry, add to list */
209 q = SILC_TREE_GET_HEADER(tree, entry);
216 SILC_LOG_DEBUG(("Entry %p is duplicate to %p", entry,
217 SILC_TREE_GET_ENTRY(tree, h)));
225 h = ret > 0 ? h->right : h->left;
229 h = SILC_TREE_GET_HEADER(tree, entry);
235 SILC_LOG_DEBUG(("Entry %p added, parent %p", entry,
236 SILC_TREE_GET_ENTRY(tree, parent)));
238 /* Update the new entry */
240 h->left = h->right = h->dup = NULL;
244 while (parent != q) {
245 parent->t = (parent->right == h) * 2 - 1;
252 if (--q->t == (-2)) {
254 silc_avl_tree_rot_left(tree, q->left);
255 silc_avl_tree_rot_right(tree, q);
260 silc_avl_tree_rot_right(tree, q->right);
261 silc_avl_tree_rot_left(tree, q);
270 /* Delete entry from tree */
272 SilcBool silc_avl_tree_del(SilcTree *tree, void *entry)
274 SilcTreeHeader *h, *q, *out, *parent = NULL, tmp;
277 SILC_LOG_DEBUG(("AVL tree %p, delete %p", tree, entry));
279 if (!tree->root || !entry) {
280 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
284 /* Unless the incoming entry is already the one to be deleted find it
285 from the tree first. */
286 q = h = SILC_TREE_GET_HEADER(tree, entry);
287 if (!h->parent && !h->left && !h->right && !h->t) {
288 entry = silc_avl_tree_find(tree, entry, NULL, NULL);
291 q = h = SILC_TREE_GET_HEADER(tree, entry);
294 /* If entry has duplicates, replace this with one of them */
296 h->dup->duplicate = FALSE;
297 h->dup->parent = h->parent;
298 h->dup->left = h->left;
299 h->dup->right = h->right;
304 if (h->parent->left == h)
305 h->parent->left = h->dup;
307 h->parent->right = h->dup;
314 h->left->parent = h->dup;
316 h->right->parent = h->dup;
318 /* Cleanup the deleted entry */
319 SILC_LOG_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h)));
320 h->parent = h->left = h->right = h->dup = NULL;
327 /* If the entry is not a leaf, swap with the smallest from right side */
328 if (h->left && h->right) {
329 for (q = out = h->right; out->left; q = out = out->left) ;
334 /* Update node's parent with the replaced node */
336 if (out->parent->left == h)
337 out->parent->left = out;
339 out->parent->right = out;
344 /* Update parents and leafs */
347 if (out->left == out)
349 else if (out->right == out)
351 out->left->parent = out;
352 out->right->parent = out;
356 out = h->left ? h->left : h->right;
358 out->parent = parent;
360 /* Cleanup the deleted entry */
361 SILC_LOG_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h)));
362 h->parent = h->left = h->right = h->dup = NULL;
372 left = parent->left == q;
381 if (++parent->t == 0) {
385 if (parent->t == 2) {
386 SILC_ASSERT(parent->right);
387 if (parent->right->t < 0) {
388 silc_avl_tree_rot_right(tree, parent->right);
389 silc_avl_tree_rot_left(tree, parent);
391 SILC_ASSERT(parent->right->right);
392 if (silc_avl_tree_rot_left(tree, parent) == 0)
399 if (--parent->t == 0) {
403 if (parent->t == (-2)) {
404 SILC_ASSERT(parent->left);
405 if (parent->left->t > 0) {
406 silc_avl_tree_rot_left(tree, parent->left);
407 silc_avl_tree_rot_right(tree, parent);
409 SILC_ASSERT(parent->left->left);
410 if (silc_avl_tree_rot_right(tree, parent) == 0)
418 /* Only get here on double rotations or single rotations that changed
419 subtree height - in either event, `parent->parent' is positioned
420 where `parent' was positioned before any rotations. */
423 if ((parent = h->parent) == NULL)
425 left = parent->left == h;
432 /* AVL tree operations */
433 const struct SilcTreeOpsStruct silc_tree_avl_ops =