1 /* src/toolbox/avl.c - AVL tree implementation
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Christian Thalinger
31 $Id: avl.c 4357 2006-01-22 23:33:38Z twisti $
42 #include "mm/memory.h"
43 #include "toolbox/avl.h"
45 #if defined(USE_THREADS)
46 # if defined(NATIVE_THREADS)
47 # include "threads/native/threads.h"
49 # include "threads/green/threads.h"
53 #include "vm/builtin.h"
56 /* avl_create ******************************************************************
58 Creates a AVL tree structure.
60 *******************************************************************************/
62 avl_tree *avl_create(avl_comparator *compar)
69 t->comparator = compar;
72 #if defined(USE_THREADS)
73 /* create lock object for this tree */
75 t->lock = NEW(java_objectheader);
77 # if defined(NATIVE_THREADS)
78 initObjectLock(t->lock);
86 /* avl_newnode *****************************************************************
88 Creates a new AVL node and sets the pointers correctly.
90 *******************************************************************************/
92 static avl_node *avl_newnode(void *data)
100 /* ATTENTION: NEW allocates memory zeroed out */
102 /* n->balance = 0; */
103 /* n->childs[0] = NULL; */
104 /* n->childs[1] = NULL; */
110 /* avl_rotate_left *************************************************************
112 Does a left rotation on an AVL node.
120 *******************************************************************************/
122 static void avl_rotate_left(avl_node **node)
127 /* rotate the node */
130 tmpnode = tmp->childs[AVL_RIGHT];
131 tmp->childs[AVL_RIGHT] = tmpnode->childs[AVL_LEFT];
132 tmpnode->childs[AVL_LEFT] = tmp;
134 /* set new parent node */
140 /* avl_rotate_right ************************************************************
142 Does a right rotation on an AVL node.
150 *******************************************************************************/
152 static void avl_rotate_right(avl_node **node)
157 /* rotate the node */
160 tmpnode = tmp->childs[AVL_LEFT];
161 tmp->childs[AVL_LEFT] = tmpnode->childs[AVL_RIGHT];
162 tmpnode->childs[AVL_RIGHT] = tmp;
164 /* set new parent node */
170 /* avl_adjust_balance **********************************************************
172 Does a balance adjustment after a double rotation.
174 *******************************************************************************/
176 static void avl_adjust_balance(avl_node *node)
181 left = node->childs[AVL_LEFT];
182 right = node->childs[AVL_RIGHT];
184 switch (node->balance) {
205 /* avl_insert_intern ***********************************************************
207 Inserts a AVL node into a AVL tree.
209 *******************************************************************************/
211 static s4 avl_insert_intern(avl_tree *tree, avl_node **node, void *data)
219 /* set temporary variable */
223 /* per default no node was inserted */
227 /* compare the current node */
229 res = tree->comparator(data, tmpnode->data);
231 /* is this node already in the tree? */
236 /* goto left or right child */
238 direction = (res < 0) ? AVL_LEFT : AVL_RIGHT;
240 /* there is a child, go recursive */
242 if (tmpnode->childs[direction]) {
243 balance = avl_insert_intern(tree, &tmpnode->childs[direction], data);
248 /* no child, create this node */
250 newnode = avl_newnode(data);
252 /* insert into parent node */
254 tmpnode->childs[direction] = newnode;
256 /* node was inserted, but don't set insert to 1, since this
257 insertion is handled in this recursion depth */
262 /* add insertion value to node balance, value depends on the
265 tmpnode->balance += (direction == AVL_LEFT) ? -balance : balance;
267 if ((balance != 0) && (tmpnode->balance != 0)) {
268 if (tmpnode->balance < -1) {
269 /* left subtree too tall: right rotation needed */
271 if (tmpnode->childs[AVL_LEFT]->balance < 0) {
272 avl_rotate_right(&tmpnode);
274 /* simple balance adjustments */
276 tmpnode->balance = 0;
277 tmpnode->childs[AVL_RIGHT]->balance = 0;
280 avl_rotate_left(&tmpnode->childs[AVL_LEFT]);
281 avl_rotate_right(&tmpnode);
282 avl_adjust_balance(tmpnode);
285 } else if (tmpnode->balance > 1) {
286 /* right subtree too tall: left rotation needed */
288 if (tmpnode->childs[AVL_RIGHT]->balance > 0) {
289 avl_rotate_left(&tmpnode);
291 /* simple balance adjustments */
293 tmpnode->balance = 0;
294 tmpnode->childs[AVL_LEFT]->balance = 0;
297 avl_rotate_right(&tmpnode->childs[AVL_RIGHT]);
298 avl_rotate_left(&tmpnode);
299 avl_adjust_balance(tmpnode);
311 /* insertion was ok */
317 /* avl_insert ******************************************************************
319 Inserts a AVL node into a AVL tree.
321 *******************************************************************************/
323 bool avl_insert(avl_tree *tree, void *data)
328 #if defined(USE_THREADS)
329 builtin_monitorenter(tree->lock);
332 /* if we don't have a root node, create one */
334 if (tree->root == NULL) {
335 tree->root = avl_newnode(data);
338 avl_insert_intern(tree, &tree->root, data);
341 /* increase entries count */
346 printf("tree=%p entries=%d\n", tree, tree->entries);
348 printf("-------------------\n");
349 avl_dump(tree->root, 0);
350 printf("-------------------\n");
353 #if defined(USE_THREADS)
354 builtin_monitorexit(tree->lock);
357 /* insertion was ok */
363 /* avl_find ********************************************************************
365 Find a given data structure in the AVL tree, with the comparision
366 function of the tree.
368 *******************************************************************************/
370 void *avl_find(avl_tree *tree, void *data)
378 #if defined(USE_THREADS)
379 builtin_monitorenter(tree->lock);
382 /* search the tree for the given node */
384 for (node = tree->root; node != NULL; ) {
385 /* compare the current node */
387 res = tree->comparator(data, node->data);
389 /* was the entry found? return it */
392 #if defined(USE_THREADS)
393 builtin_monitorexit(tree->lock);
399 /* goto left or right child */
401 node = node->childs[(res < 0) ? AVL_LEFT : AVL_RIGHT];
404 #if defined(USE_THREADS)
405 builtin_monitorexit(tree->lock);
408 /* entry was not found, returning NULL */
414 /* avl_dump ********************************************************************
416 Dumps the AVL tree starting with node.
418 *******************************************************************************/
421 void avl_dump(avl_node* node, s4 indent)
430 if (node->childs[AVL_RIGHT])
431 avl_dump(node->childs[AVL_RIGHT], tmp + 1);
436 printf("%p (%d)\n", node->data, node->balance);
438 if (node->childs[AVL_LEFT])
439 avl_dump(node->childs[AVL_LEFT], tmp + 1);
445 * These are local overrides for various environment variables in Emacs.
446 * Please do not remove this and leave it at the end of the file, where
447 * Emacs will automagically detect them.
448 * ---------------------------------------------------------------------
451 * indent-tabs-mode: t