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 SilcCompare compare, void *context)
148 SilcCompare 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);
157 if (ret == SILC_COMPARE_EQUAL_TO) {
158 SILC_LOG_DEBUG(("Found %p", SILC_TREE_GET_ENTRY(tree, h)));
159 return SILC_TREE_GET_ENTRY(tree, h);
161 if (ret == SILC_COMPARE_STOP)
163 h = ret > 0 ? h->right : h->left;
166 SILC_LOG_DEBUG(("Not found"));
167 silc_set_errno(SILC_ERR_NOT_FOUND);
171 /* Insert entry to tree */
173 SilcBool silc_avl_tree_add(SilcTree *tree, void *entry)
175 SilcTreeHeader *h, *parent = NULL, *q = NULL;
178 SILC_LOG_DEBUG(("AVL tree %p, adding %p", tree, entry));
180 /* If tree is empty, add to root */
182 h = SILC_TREE_GET_HEADER(tree, entry);
183 h->parent = h->left = h->right = h->dup = NULL;
187 SILC_LOG_DEBUG(("Entry %p added as root", entry));
189 SILC_ASSERT(!tree->count);
194 /* Find the spot to add the new entry */
197 /* Same entry context must not be in tree */
198 if (entry == SILC_TREE_GET_ENTRY(tree, h)) {
199 silc_set_errno(SILC_ERR_ALREADY_EXISTS);
203 ret = tree->compare(entry, SILC_TREE_GET_ENTRY(tree, h), tree->context);
204 if (!tree->duplicates && ret == SILC_COMPARE_EQUAL_TO) {
205 silc_set_errno(SILC_ERR_ALREADY_EXISTS);
209 /* Duplicate entry, add to list */
210 if (ret == SILC_COMPARE_EQUAL_TO) {
211 q = SILC_TREE_GET_HEADER(tree, entry);
218 SILC_LOG_DEBUG(("Entry %p is duplicate to %p", entry,
219 SILC_TREE_GET_ENTRY(tree, h)));
227 h = ret > 0 ? h->right : h->left;
231 h = SILC_TREE_GET_HEADER(tree, entry);
237 SILC_LOG_DEBUG(("Entry %p added, parent %p", entry,
238 SILC_TREE_GET_ENTRY(tree, parent)));
240 /* Update the new entry */
242 h->left = h->right = h->dup = NULL;
246 while (parent != q) {
247 parent->t = (parent->right == h) * 2 - 1;
254 if (--q->t == (-2)) {
256 silc_avl_tree_rot_left(tree, q->left);
257 silc_avl_tree_rot_right(tree, q);
262 silc_avl_tree_rot_right(tree, q->right);
263 silc_avl_tree_rot_left(tree, q);
272 /* Delete entry from tree */
274 SilcBool silc_avl_tree_del(SilcTree *tree, void *entry)
276 SilcTreeHeader *h, *q, *out, *parent = NULL, tmp;
279 SILC_LOG_DEBUG(("AVL tree %p, delete %p", tree, entry));
281 if (!tree->root || !entry) {
282 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
286 /* Unless the incoming entry is already the one to be deleted find it
287 from the tree first. */
288 q = h = SILC_TREE_GET_HEADER(tree, entry);
289 if (!h->parent && !h->left && !h->right && !h->t) {
290 entry = silc_avl_tree_find(tree, entry, NULL, NULL);
293 q = h = SILC_TREE_GET_HEADER(tree, entry);
296 /* If entry has duplicates, replace this with one of them */
298 h->dup->duplicate = FALSE;
299 h->dup->parent = h->parent;
300 h->dup->left = h->left;
301 h->dup->right = h->right;
306 if (h->parent->left == h)
307 h->parent->left = h->dup;
309 h->parent->right = h->dup;
316 h->left->parent = h->dup;
318 h->right->parent = h->dup;
320 /* Cleanup the deleted entry */
321 SILC_LOG_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h)));
322 h->parent = h->left = h->right = h->dup = NULL;
329 /* If the entry is not a leaf, swap with the smallest from right side */
330 if (h->left && h->right) {
331 for (q = out = h->right; out->left; q = out = out->left) ;
336 /* Update node's parent with the replaced node */
338 if (out->parent->left == h)
339 out->parent->left = out;
341 out->parent->right = out;
346 /* Update parents and leafs */
349 if (out->left == out)
351 else if (out->right == out)
353 out->left->parent = out;
354 out->right->parent = out;
358 out = h->left ? h->left : h->right;
360 out->parent = parent;
362 /* Cleanup the deleted entry */
363 SILC_LOG_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h)));
364 h->parent = h->left = h->right = h->dup = NULL;
374 left = parent->left == q;
383 if (++parent->t == 0) {
387 if (parent->t == 2) {
388 SILC_ASSERT(parent->right);
389 if (parent->right->t < 0) {
390 silc_avl_tree_rot_right(tree, parent->right);
391 silc_avl_tree_rot_left(tree, parent);
393 SILC_ASSERT(parent->right->right);
394 if (silc_avl_tree_rot_left(tree, parent) == 0)
401 if (--parent->t == 0) {
405 if (parent->t == (-2)) {
406 SILC_ASSERT(parent->left);
407 if (parent->left->t > 0) {
408 silc_avl_tree_rot_left(tree, parent->left);
409 silc_avl_tree_rot_right(tree, parent);
411 SILC_ASSERT(parent->left->left);
412 if (silc_avl_tree_rot_right(tree, parent) == 0)
420 /* Only get here on double rotations or single rotations that changed
421 subtree height - in either event, `parent->parent' is positioned
422 where `parent' was positioned before any rotations. */
425 if ((parent = h->parent) == NULL)
427 left = parent->left == h;
434 /* AVL tree operations */
435 const struct SilcTreeOpsStruct silc_tree_avl_ops =