1 /* src/toolbox/avl.c - AVL tree implementation
3 Copyright (C) 1996-2005, 2006, 2007 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
34 #include "mm/memory.h"
36 #include "threads/lock-common.h"
38 #include "toolbox/avl.h"
39 #include "toolbox/logging.h"
41 #include "vm/global.h"
45 /* avl_create ******************************************************************
47 Creates a AVL tree structure.
49 *******************************************************************************/
51 avl_tree_t *avl_create(avl_comparator *comparator)
58 t->comparator = comparator;
61 #if defined(ENABLE_THREADS)
62 /* create lock object for this tree */
64 t->lock = NEW(java_object_t);
66 LOCK_INIT_OBJECT_LOCK(t->lock);
73 /* avl_newnode *****************************************************************
75 Creates a new AVL node and sets the pointers correctly.
77 *******************************************************************************/
79 static avl_node_t *avl_newnode(void *data)
87 /* ATTENTION: NEW allocates memory zeroed out */
90 /* n->childs[0] = NULL; */
91 /* n->childs[1] = NULL; */
97 /* avl_rotate_left *************************************************************
99 Does a left rotation on an AVL node.
107 *******************************************************************************/
109 static void avl_rotate_left(avl_node_t **node)
114 /* rotate the node */
117 tmpnode = tmp->childs[AVL_RIGHT];
118 tmp->childs[AVL_RIGHT] = tmpnode->childs[AVL_LEFT];
119 tmpnode->childs[AVL_LEFT] = tmp;
121 /* set new parent node */
127 /* avl_rotate_right ************************************************************
129 Does a right rotation on an AVL node.
137 *******************************************************************************/
139 static void avl_rotate_right(avl_node_t **node)
144 /* rotate the node */
147 tmpnode = tmp->childs[AVL_LEFT];
148 tmp->childs[AVL_LEFT] = tmpnode->childs[AVL_RIGHT];
149 tmpnode->childs[AVL_RIGHT] = tmp;
151 /* set new parent node */
157 /* avl_adjust_balance **********************************************************
159 Does a balance adjustment after a double rotation.
161 *******************************************************************************/
163 static void avl_adjust_balance(avl_node_t *node)
168 left = node->childs[AVL_LEFT];
169 right = node->childs[AVL_RIGHT];
171 switch (node->balance) {
192 /* avl_insert_intern ***********************************************************
194 Inserts a AVL node into a AVL tree.
196 *******************************************************************************/
198 static s4 avl_insert_intern(avl_tree_t *tree, avl_node_t **node, void *data)
206 /* set temporary variable */
210 /* per default no node was inserted */
214 /* compare the current node */
216 res = tree->comparator(tmpnode->data, data);
218 /* is this node already in the tree? */
221 vm_abort("avl_insert_intern: node already in the tree");
223 /* goto left or right child */
225 direction = (res < 0) ? AVL_LEFT : AVL_RIGHT;
227 /* there is a child, go recursive */
229 if (tmpnode->childs[direction]) {
230 balance = avl_insert_intern(tree, &tmpnode->childs[direction], data);
235 /* no child, create this node */
237 newnode = avl_newnode(data);
239 /* insert into parent node */
241 tmpnode->childs[direction] = newnode;
243 /* node was inserted, but don't set insert to 1, since this
244 insertion is handled in this recursion depth */
249 /* add insertion value to node balance, value depends on the
252 tmpnode->balance += (direction == AVL_LEFT) ? -balance : balance;
254 if ((balance != 0) && (tmpnode->balance != 0)) {
255 if (tmpnode->balance < -1) {
256 /* left subtree too tall: right rotation needed */
258 if (tmpnode->childs[AVL_LEFT]->balance < 0) {
259 avl_rotate_right(&tmpnode);
261 /* simple balance adjustments */
263 tmpnode->balance = 0;
264 tmpnode->childs[AVL_RIGHT]->balance = 0;
267 avl_rotate_left(&tmpnode->childs[AVL_LEFT]);
268 avl_rotate_right(&tmpnode);
269 avl_adjust_balance(tmpnode);
272 else if (tmpnode->balance > 1) {
273 /* right subtree too tall: left rotation needed */
275 if (tmpnode->childs[AVL_RIGHT]->balance > 0) {
276 avl_rotate_left(&tmpnode);
278 /* simple balance adjustments */
280 tmpnode->balance = 0;
281 tmpnode->childs[AVL_LEFT]->balance = 0;
284 avl_rotate_right(&tmpnode->childs[AVL_RIGHT]);
285 avl_rotate_left(&tmpnode);
286 avl_adjust_balance(tmpnode);
298 /* insertion was ok */
304 /* avl_insert ******************************************************************
306 Inserts a AVL node into a AVL tree.
308 *******************************************************************************/
310 bool avl_insert(avl_tree_t *tree, void *data)
315 LOCK_MONITOR_ENTER(tree->lock);
317 /* if we don't have a root node, create one */
319 if (tree->root == NULL)
320 tree->root = avl_newnode(data);
322 avl_insert_intern(tree, &tree->root, data);
324 /* increase entries count */
328 LOCK_MONITOR_EXIT(tree->lock);
330 /* insertion was ok */
336 /* avl_find ********************************************************************
338 Find a given data structure in the AVL tree, with the comparision
339 function of the tree.
341 *******************************************************************************/
343 void *avl_find(avl_tree_t *tree, void *data)
351 LOCK_MONITOR_ENTER(tree->lock);
353 /* search the tree for the given node */
355 for (node = tree->root; node != NULL; ) {
356 /* compare the current node */
358 res = tree->comparator(node->data, data);
360 /* was the entry found? return it */
363 LOCK_MONITOR_EXIT(tree->lock);
368 /* goto left or right child */
370 node = node->childs[(res < 0) ? AVL_LEFT : AVL_RIGHT];
373 LOCK_MONITOR_EXIT(tree->lock);
375 /* entry was not found, returning NULL */
381 /* avl_dump ********************************************************************
383 Dumps the AVL tree starting with node.
385 *******************************************************************************/
388 void avl_dump(avl_node_t* node, s4 indent)
397 if (node->childs[AVL_RIGHT])
398 avl_dump(node->childs[AVL_RIGHT], tmp + 1);
405 log_print("%p (%d)", node->data, node->balance);
408 if (node->childs[AVL_LEFT])
409 avl_dump(node->childs[AVL_LEFT], tmp + 1);
415 * These are local overrides for various environment variables in Emacs.
416 * Please do not remove this and leave it at the end of the file, where
417 * Emacs will automagically detect them.
418 * ---------------------------------------------------------------------
421 * indent-tabs-mode: t