LCOV - code coverage report
Current view: top level - toolbox - avl.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 91 107 85.0 %
Date: 2017-07-14 10:03:36 Functions: 8 9 88.9 %

          Line data    Source code
       1             : /* src/toolbox/avl.c - AVL tree implementation
       2             : 
       3             :    Copyright (C) 1996-2013
       4             :    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
       5             : 
       6             :    This file is part of CACAO.
       7             : 
       8             :    This program is free software; you can redistribute it and/or
       9             :    modify it under the terms of the GNU General Public License as
      10             :    published by the Free Software Foundation; either version 2, or (at
      11             :    your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful, but
      14             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :    General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program; if not, write to the Free Software
      20             :    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
      21             :    02110-1301, USA.
      22             : 
      23             : */
      24             : 
      25             : #include "toolbox/avl.hpp"
      26             : #include <assert.h>                     // for assert
      27             : #include <stddef.h>                     // for NULL
      28             : #include "mm/memory.hpp"                // for NEW
      29             : #include "threads/mutex.hpp"            // for Mutex
      30             : #include "toolbox/logging.hpp"          // for log_print, log_finish, etc
      31             : #include "vm/types.hpp"                 // for s4
      32             : #include "vm/vm.hpp"                    // for vm_abort
      33             : 
      34             : /* define direction in an AVL node ********************************************/
      35             : 
      36             : #define AVL_LEFT     0
      37             : #define AVL_RIGHT    1
      38             : 
      39             : 
      40             : /* avl_tree_t *****************************************************************/
      41             : 
      42             : struct avl_tree_t {
      43             :    Mutex*          mutex;              ///< Mutex to lock the tree.
      44             :    avl_node_t     *root;               /* pointer to root node               */
      45             :    avl_comparator *comparator;         /* pointer to comparison function     */
      46             :    s4              entries;            /* contains number of entries         */
      47             : };
      48             : 
      49             : 
      50             : /* avl_node_t *****************************************************************/
      51             : 
      52             : struct avl_node_t {
      53             :    void       *data;                   /* pointer to data structure          */
      54             :    s4          balance;                /* the range of the field is -2...2   */
      55             :    avl_node_t *childs[2];              /* pointers to the child nodes        */
      56             : };
      57             : 
      58             : 
      59             : /* avl_create ******************************************************************
      60             : 
      61             :    Creates a AVL tree structure.
      62             : 
      63             : *******************************************************************************/
      64             : 
      65         163 : avl_tree_t *avl_create(avl_comparator *comparator)
      66             : {
      67             :         avl_tree_t *t;
      68             : 
      69         163 :         t = NEW(avl_tree_t);
      70             : 
      71         163 :         t->mutex      = new Mutex();
      72         163 :         t->root       = NULL;
      73         163 :         t->comparator = comparator;
      74         163 :         t->entries    = 0;
      75             : 
      76         163 :         return t;
      77             : }
      78             : 
      79             : 
      80             : /* avl_newnode *****************************************************************
      81             : 
      82             :    Creates a new AVL node and sets the pointers correctly.
      83             : 
      84             : *******************************************************************************/
      85             : 
      86       99619 : static avl_node_t *avl_newnode(void *data)
      87             : {
      88             :         avl_node_t *n;
      89             : 
      90       99619 :         n = NEW(avl_node_t);
      91             : 
      92       99619 :         n->data      = data;
      93             : 
      94             :         /* ATTENTION: NEW allocates memory zeroed out */
      95             : 
      96             : /*      n->balance   = 0; */
      97             : /*      n->childs[0] = NULL; */
      98             : /*      n->childs[1] = NULL; */
      99             : 
     100       99619 :         return n;
     101             : }
     102             : 
     103             : 
     104             : /* avl_rotate_left *************************************************************
     105             : 
     106             :    Does a left rotation on an AVL node.
     107             : 
     108             :    A (node)         B
     109             :     \              / \
     110             :      B       -->  A   C
     111             :       \
     112             :        C
     113             : 
     114             : *******************************************************************************/
     115             : 
     116       98067 : static void avl_rotate_left(avl_node_t **node)
     117             : {
     118             :         avl_node_t *tmp;
     119             :         avl_node_t *tmpnode;
     120             : 
     121             :         /* rotate the node */
     122             : 
     123       98067 :         tmp                       = *node;
     124       98067 :         tmpnode                   = tmp->childs[AVL_RIGHT];
     125       98067 :         tmp->childs[AVL_RIGHT]    = tmpnode->childs[AVL_LEFT];
     126       98067 :         tmpnode->childs[AVL_LEFT] = tmp;
     127             : 
     128             :         /* set new parent node */
     129             : 
     130       98067 :         *node                     = tmpnode;
     131       98067 : }
     132             : 
     133             : 
     134             : /* avl_rotate_right ************************************************************
     135             : 
     136             :    Does a right rotation on an AVL node.
     137             : 
     138             :        C (node)         B
     139             :       /                / \
     140             :      B           -->  A   C
     141             :     /
     142             :    A
     143             : 
     144             : *******************************************************************************/
     145             : 
     146          99 : static void avl_rotate_right(avl_node_t **node)
     147             : {
     148             :         avl_node_t *tmp;
     149             :         avl_node_t *tmpnode;
     150             : 
     151             :         /* rotate the node */
     152             : 
     153          99 :         tmp                        = *node;
     154          99 :         tmpnode                    = tmp->childs[AVL_LEFT];
     155          99 :         tmp->childs[AVL_LEFT]      = tmpnode->childs[AVL_RIGHT];
     156          99 :         tmpnode->childs[AVL_RIGHT] = tmp;
     157             : 
     158             :         /* set new parent node */
     159             : 
     160          99 :         *node                      = tmpnode;
     161          99 : }
     162             : 
     163             : 
     164             : /* avl_adjust_balance **********************************************************
     165             : 
     166             :    Does a balance adjustment after a double rotation.
     167             : 
     168             : *******************************************************************************/
     169             : 
     170          97 : static void avl_adjust_balance(avl_node_t *node)
     171             : {
     172             :         avl_node_t *left;
     173             :         avl_node_t *right;
     174             : 
     175          97 :         left  = node->childs[AVL_LEFT];
     176          97 :         right = node->childs[AVL_RIGHT];
     177             : 
     178          97 :         switch (node->balance) {
     179             :         case -1:
     180           4 :                 left->balance  = 0;
     181           4 :                 right->balance = 1;
     182           4 :                 break;
     183             : 
     184             :         case 0:
     185          61 :                 left->balance  = 0;
     186          61 :                 right->balance = 0;
     187          61 :                 break;
     188             : 
     189             :         case 1:
     190          32 :                 left->balance  = -1;
     191          32 :                 right->balance = 0;
     192             :                 break;
     193             :         }
     194             : 
     195          97 :         node->balance = 0;
     196          97 : }
     197             : 
     198             : 
     199             : /* avl_insert_intern ***********************************************************
     200             : 
     201             :    Inserts a AVL node into a AVL tree.
     202             : 
     203             : *******************************************************************************/
     204             : 
     205      850429 : static s4 avl_insert_intern(avl_tree_t *tree, avl_node_t **node, void *data)
     206             : {
     207             :         avl_node_t *tmpnode;
     208             :         s4          res;
     209             :         s4          direction;
     210             :         s4          insert;
     211             :         s4          balance;
     212             : 
     213             :         /* set temporary variable */
     214             : 
     215      850429 :         tmpnode = *node;
     216             : 
     217             :         /* per default no node was inserted */
     218             : 
     219      850429 :         insert = 0;
     220             : 
     221             :         /* compare the current node */
     222             : 
     223      850429 :         res = tree->comparator(tmpnode->data, data);
     224             : 
     225             :         /* is this node already in the tree? */
     226             : 
     227      850429 :         if (res == 0)
     228           0 :                 vm_abort("avl_insert_intern: node already in the tree");
     229             : 
     230             :         /* goto left or right child */
     231             : 
     232      850429 :         direction = (res < 0) ? AVL_LEFT : AVL_RIGHT;
     233             : 
     234             :         /* there is a child, go recursive */
     235             : 
     236      850429 :         if (tmpnode->childs[direction]) {
     237      750973 :                 balance = avl_insert_intern(tree, &tmpnode->childs[direction], data);
     238             :         }
     239             :         else {
     240             :                 avl_node_t *newnode;
     241             : 
     242             :                 /* no child, create this node */
     243             : 
     244       99456 :                 newnode = avl_newnode(data);
     245             : 
     246             :                 /* insert into parent node */
     247             : 
     248       99456 :                 tmpnode->childs[direction] = newnode;
     249             : 
     250             :                 /* node was inserted, but don't set insert to 1, since this
     251             :                    insertion is handled in this recursion depth */
     252             : 
     253       99456 :                 balance = 1;
     254             :         }
     255             : 
     256             :         /* add insertion value to node balance, value depends on the
     257             :            direction */
     258             : 
     259      850429 :         tmpnode->balance += (direction == AVL_LEFT) ? -balance : balance;
     260             : 
     261      850429 :         if ((balance != 0) && (tmpnode->balance != 0)) {
     262      294990 :                 if (tmpnode->balance < -1) {
     263             :                         /* left subtree too tall: right rotation needed */
     264             : 
     265          96 :                         if (tmpnode->childs[AVL_LEFT]->balance < 0) {
     266           2 :                                 avl_rotate_right(&tmpnode);
     267             : 
     268             :                                 /* simple balance adjustments */
     269             : 
     270           2 :                                 tmpnode->balance = 0;
     271           2 :                                 tmpnode->childs[AVL_RIGHT]->balance = 0;
     272             :                         }
     273             :                         else {
     274          94 :                                 avl_rotate_left(&tmpnode->childs[AVL_LEFT]);
     275          94 :                                 avl_rotate_right(&tmpnode);
     276          94 :                                 avl_adjust_balance(tmpnode);
     277             :                         }
     278             :                 }
     279      294894 :                 else if (tmpnode->balance > 1) {
     280             :                         /* right subtree too tall: left rotation needed */
     281             : 
     282       97973 :                         if (tmpnode->childs[AVL_RIGHT]->balance > 0) {
     283       97970 :                                 avl_rotate_left(&tmpnode);
     284             : 
     285             :                                 /* simple balance adjustments */
     286             : 
     287       97970 :                                 tmpnode->balance = 0;
     288       97970 :                                 tmpnode->childs[AVL_LEFT]->balance = 0;
     289             :                         }
     290             :                         else {
     291           3 :                                 avl_rotate_right(&tmpnode->childs[AVL_RIGHT]);
     292           3 :                                 avl_rotate_left(&tmpnode);
     293           3 :                                 avl_adjust_balance(tmpnode);
     294             :                         }
     295             :                 }
     296             :                 else {
     297      196921 :                         insert = 1;
     298             :                 }
     299             :         }
     300             : 
     301             :         /* set back node */
     302             : 
     303      850429 :         *node = tmpnode;
     304             : 
     305             :         /* insertion was ok */
     306             : 
     307      850429 :         return insert;
     308             : }
     309             : 
     310             : 
     311             : /* avl_insert ******************************************************************
     312             : 
     313             :    Inserts a AVL node into a AVL tree.
     314             : 
     315             : *******************************************************************************/
     316             : 
     317       99619 : bool avl_insert(avl_tree_t *tree, void *data)
     318             : {
     319       99619 :         assert(tree);
     320       99619 :         assert(data);
     321             : 
     322       99619 :         tree->mutex->lock();
     323             : 
     324             :         /* if we don't have a root node, create one */
     325             : 
     326       99619 :         if (tree->root == NULL)
     327         163 :                 tree->root = avl_newnode(data);
     328             :         else
     329       99456 :                 avl_insert_intern(tree, &tree->root, data);
     330             : 
     331             :         /* increase entries count */
     332             : 
     333       99619 :         tree->entries++;
     334             : 
     335       99619 :         tree->mutex->unlock();
     336             : 
     337             :         /* insertion was ok */
     338             : 
     339       99619 :         return true;
     340             : }
     341             : 
     342             : 
     343             : /* avl_find ********************************************************************
     344             : 
     345             :    Find a given data structure in the AVL tree, with the comparision
     346             :    function of the tree.
     347             : 
     348             : *******************************************************************************/
     349             : 
     350     2235495 : void *avl_find(avl_tree_t *tree, void *data)
     351             : {
     352             :         avl_node_t *node;
     353             :         s4          res;
     354             : 
     355     2235495 :         assert(tree);
     356     2235495 :         assert(data);
     357             : 
     358     2235495 :         tree->mutex->lock();
     359             : 
     360             :         /* search the tree for the given node */
     361             : 
     362    24927708 :         for (node = tree->root; node != NULL; ) {
     363             :                 /* compare the current node */
     364             : 
     365    22692213 :                 res = tree->comparator(node->data, data);
     366             : 
     367             :                 /* was the entry found? return it */
     368             : 
     369    22692213 :                 if (res == 0) {
     370     2235495 :                         tree->mutex->unlock();
     371             : 
     372     2235495 :                         return node->data;
     373             :                 }
     374             : 
     375             :                 /* goto left or right child */
     376             : 
     377    20456718 :                 node = node->childs[(res < 0) ? AVL_LEFT : AVL_RIGHT];
     378             :         }
     379             : 
     380           0 :         tree->mutex->unlock();
     381             : 
     382             :         /* entry was not found, returning NULL */
     383             : 
     384           0 :         return NULL;
     385             : }
     386             : 
     387             : 
     388             : /* avl_dump ********************************************************************
     389             : 
     390             :    Dumps the AVL tree starting with node.
     391             : 
     392             : *******************************************************************************/
     393             : 
     394             : #if !defined(NDEBUG)
     395           0 : void avl_dump(avl_node_t* node, s4 indent)
     396             : {
     397             :         s4 tmp;
     398             : 
     399           0 :         tmp = indent;
     400             : 
     401           0 :         if (node == NULL)
     402           0 :                         return;
     403             : 
     404           0 :         if (node->childs[AVL_RIGHT])
     405           0 :                 avl_dump(node->childs[AVL_RIGHT], tmp + 1);
     406             : 
     407           0 :         log_start();
     408             : 
     409           0 :         while(indent--)
     410           0 :                 log_print("   ");
     411             : 
     412           0 :         log_print("%p (%d)", node->data, node->balance);
     413           0 :         log_finish();
     414             : 
     415           0 :         if (node->childs[AVL_LEFT])
     416           0 :                 avl_dump(node->childs[AVL_LEFT], tmp + 1);
     417             : }
     418             : #endif
     419             : 
     420             : 
     421             : /*
     422             :  * These are local overrides for various environment variables in Emacs.
     423             :  * Please do not remove this and leave it at the end of the file, where
     424             :  * Emacs will automagically detect them.
     425             :  * ---------------------------------------------------------------------
     426             :  * Local variables:
     427             :  * mode: c++
     428             :  * indent-tabs-mode: t
     429             :  * c-basic-offset: 4
     430             :  * tab-width: 4
     431             :  * End:
     432             :  */

Generated by: LCOV version 1.11