LCOV - code coverage report
Current view: top level - tommyds/tommyds - tommytree.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 127 127 100.0 %
Date: 2018-04-02 17:50:51 Functions: 19 19 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015, Andrea Mazzoleni. All rights reserved.
       3             :  *
       4             :  * Redistribution and use in source and binary forms, with or without
       5             :  * modification, are permitted provided that the following conditions
       6             :  * are met:
       7             :  *
       8             :  * 1. Redistributions of source code must retain the above copyright
       9             :  *    notice, this list of conditions and the following disclaimer.
      10             :  *
      11             :  * 2. Redistributions in binary form must reproduce the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer in the
      13             :  *    documentation and/or other materials provided with the distribution.
      14             :  *
      15             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
      16             :  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      17             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      18             :  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
      19             :  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      20             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      21             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      22             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      23             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      24             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      25             :  * POSSIBILITY OF SUCH DAMAGE.
      26             :  */
      27             : 
      28             : #include "tommytree.h"
      29             : 
      30             : #include <assert.h> /* for assert */
      31             : 
      32             : /******************************************************************************/
      33             : /* tree */
      34             : 
      35           1 : void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp)
      36             : {
      37           1 :         tree->root = 0;
      38           1 :         tree->count = 0;
      39           1 :         tree->cmp = cmp;
      40           1 : }
      41             : 
      42    34670891 : static tommy_ssize_t tommy_tree_delta(tommy_tree_node* root)
      43             : {
      44    34670891 :         tommy_ssize_t left_height = root->prev ? root->prev->index : 0;
      45    34670891 :         tommy_ssize_t right_height = root->next ? root->next->index : 0;
      46             : 
      47    34670891 :         return left_height - right_height;
      48             : }
      49             : 
      50             : /* AVL tree operations */
      51             : static tommy_tree_node* tommy_tree_balance(tommy_tree_node*);
      52             : 
      53     1323565 : static tommy_tree_node* tommy_tree_rotate_left(tommy_tree_node* root)
      54             : {
      55     1323565 :         tommy_tree_node* next = root->next;
      56             : 
      57     1323565 :         root->next = next->prev;
      58             : 
      59     1323565 :         next->prev = tommy_tree_balance(root);
      60             : 
      61     1323565 :         return tommy_tree_balance(next);
      62             : }
      63             : 
      64      663118 : static tommy_tree_node* tommy_tree_rotate_right(tommy_tree_node* root)
      65             : {
      66      663118 :         tommy_tree_node* prev = root->prev;
      67             : 
      68      663118 :         root->prev = prev->next;
      69             : 
      70      663118 :         prev->next = tommy_tree_balance(root);
      71             : 
      72      663118 :         return tommy_tree_balance(prev);
      73             : }
      74             : 
      75     1317359 : static tommy_tree_node* tommy_tree_move_right(tommy_tree_node* root, tommy_tree_node* node)
      76             : {
      77     1317359 :         if (!root)
      78      750000 :                 return node;
      79             : 
      80      567359 :         root->next = tommy_tree_move_right(root->next, node);
      81             : 
      82      567359 :         return tommy_tree_balance(root);
      83             : }
      84             : 
      85    32941689 : static tommy_tree_node* tommy_tree_balance(tommy_tree_node* root)
      86             : {
      87    32941689 :         tommy_ssize_t delta = tommy_tree_delta(root);
      88             : 
      89    32941689 :         if (delta < -1) {
      90     1262823 :                 if (tommy_tree_delta(root->next) > 0)
      91      196739 :                         root->next = tommy_tree_rotate_right(root->next);
      92     1262823 :                 return tommy_tree_rotate_left(root);
      93             :         }
      94             : 
      95    31678866 :         if (delta > 1) {
      96      466379 :                 if (tommy_tree_delta(root->prev) < 0)
      97       60742 :                         root->prev = tommy_tree_rotate_left(root->prev);
      98      466379 :                 return tommy_tree_rotate_right(root);
      99             :         }
     100             : 
     101             :         /* recompute key */
     102    31212487 :         root->index = 0;
     103             : 
     104    31212487 :         if (root->prev && root->prev->index > root->index)
     105    29060015 :                 root->index = root->prev->index;
     106             : 
     107    31212487 :         if (root->next && root->next->index > root->index)
     108     7300994 :                 root->index = root->next->index;
     109             : 
     110             :         /* count itself */
     111    31212487 :         root->index += 1;
     112             : 
     113    31212487 :         return root;
     114             : }
     115             : 
     116    18185468 : static tommy_tree_node* tommy_tree_insert_node(tommy_compare_func* cmp, tommy_tree_node* root, tommy_tree_node** let)
     117             : {
     118             :         int c;
     119             : 
     120    18185468 :         if (!root)
     121      750000 :                 return *let;
     122             : 
     123    17435468 :         c = cmp((*let)->data, root->data);
     124             : 
     125    17435468 :         if (c < 0) {
     126     8635115 :                 root->prev = tommy_tree_insert_node(cmp, root->prev, let);
     127     8635115 :                 return tommy_tree_balance(root);
     128             :         }
     129             : 
     130     8800353 :         if (c > 0) {
     131     8550353 :                 root->next = tommy_tree_insert_node(cmp, root->next, let);
     132     8550353 :                 return tommy_tree_balance(root);
     133             :         }
     134             : 
     135             :         /* already present, set the return pointer */
     136      250000 :         *let = root;
     137             : 
     138      250000 :         return root;
     139             : }
     140             : 
     141     1000000 : void* tommy_tree_insert(tommy_tree* tree, tommy_tree_node* node, void* data)
     142             : {
     143     1000000 :         tommy_tree_node* insert = node;
     144             : 
     145     1000000 :         insert->data = data;
     146     1000000 :         insert->prev = 0;
     147     1000000 :         insert->next = 0;
     148     1000000 :         insert->index = 0;
     149             : 
     150     1000000 :         tree->root = tommy_tree_insert_node(tree->cmp, tree->root, &insert);
     151             : 
     152     1000000 :         if (insert == node)
     153      750000 :                 ++tree->count;
     154             : 
     155     1000000 :         return insert->data;
     156             : }
     157             : 
     158    12090496 : static tommy_tree_node* tommy_tree_remove_node(tommy_compare_func* cmp, tommy_tree_node* root, void* data, tommy_tree_node** let)
     159             : {
     160             :         int c;
     161             : 
     162    12090496 :         if (!root)
     163      125000 :                 return 0;
     164             : 
     165    11965496 :         c = cmp(data, root->data);
     166             : 
     167    11965496 :         if (c < 0) {
     168     6435032 :                 root->prev = tommy_tree_remove_node(cmp, root->prev, data, let);
     169     6435032 :                 return tommy_tree_balance(root);
     170             :         }
     171             : 
     172     5530464 :         if (c > 0) {
     173     4780464 :                 root->next = tommy_tree_remove_node(cmp, root->next, data, let);
     174     4780464 :                 return tommy_tree_balance(root);
     175             :         }
     176             : 
     177             :         /* found */
     178      750000 :         *let = root;
     179             : 
     180      750000 :         return tommy_tree_move_right(root->prev, root->next);
     181             : }
     182             : 
     183      875000 : void* tommy_tree_remove(tommy_tree* tree, void* data)
     184             : {
     185      875000 :         tommy_tree_node* node = 0;
     186             : 
     187      875000 :         tree->root = tommy_tree_remove_node(tree->cmp, tree->root, data, &node);
     188             : 
     189      875000 :         if (!node)
     190      125000 :                 return 0;
     191             : 
     192      750000 :         --tree->count;
     193             : 
     194      750000 :         return node->data;
     195             : }
     196             : 
     197     8000014 : static tommy_tree_node* tommy_tree_search_node(tommy_compare_func* cmp, tommy_tree_node* root, void* data)
     198             : {
     199             :         int c;
     200             : 
     201     8000014 :         if (!root)
     202      250000 :                 return 0;
     203             : 
     204     7750014 :         c = cmp(data, root->data);
     205             : 
     206     7750014 :         if (c < 0)
     207     5653752 :                 return tommy_tree_search_node(cmp, root->prev, data);
     208             : 
     209     2096262 :         if (c > 0)
     210     1846262 :                 return tommy_tree_search_node(cmp, root->next, data);
     211             : 
     212      250000 :         return root;
     213             : }
     214             : 
     215      250000 : void* tommy_tree_search(tommy_tree* tree, void* data)
     216             : {
     217      250000 :         tommy_tree_node* node = tommy_tree_search_node(tree->cmp, tree->root, data);
     218             : 
     219      250000 :         if (!node)
     220      125000 :                 return 0;
     221             : 
     222      125000 :         return node->data;
     223             : }
     224             : 
     225      250000 : void* tommy_tree_search_compare(tommy_tree* tree, tommy_compare_func* cmp, void* cmp_arg)
     226             : {
     227      250000 :         tommy_tree_node* node = tommy_tree_search_node(cmp, tree->root, cmp_arg);
     228             : 
     229      250000 :         if (!node)
     230      125000 :                 return 0;
     231             : 
     232      125000 :         return node->data;
     233             : }
     234             : 
     235      625000 : void* tommy_tree_remove_existing(tommy_tree* tree, tommy_tree_node* node)
     236             : {
     237      625000 :         void* data = tommy_tree_remove(tree, node->data);
     238             : 
     239      625000 :         assert(data != 0);
     240             : 
     241      625000 :         return data;
     242             : }
     243             : 
     244      500001 : static void tommy_tree_foreach_node(tommy_tree_node* root, tommy_foreach_func* func)
     245             : {
     246             :         tommy_tree_node* next;
     247             : 
     248      500001 :         if (!root)
     249      250001 :                 return;
     250             : 
     251      250000 :         tommy_tree_foreach_node(root->prev, func);
     252             : 
     253             :         /* make a copy in case func is free() */
     254      250000 :         next = root->next;
     255             : 
     256      250000 :         func(root->data);
     257             : 
     258      250000 :         tommy_tree_foreach_node(next, func);
     259             : }
     260             : 
     261           1 : void tommy_tree_foreach(tommy_tree* tree, tommy_foreach_func* func)
     262             : {
     263           1 :         tommy_tree_foreach_node(tree->root, func);
     264           1 : }
     265             : 
     266      500001 : static void tommy_tree_foreach_arg_node(tommy_tree_node* root, tommy_foreach_arg_func* func, void* arg)
     267             : {
     268             :         tommy_tree_node* next;
     269             : 
     270      500001 :         if (!root)
     271      250001 :                 return;
     272             : 
     273      250000 :         tommy_tree_foreach_arg_node(root->prev, func, arg);
     274             : 
     275             :         /* make a copy in case func is free() */
     276      250000 :         next = root->next;
     277             : 
     278      250000 :         func(arg, root->data);
     279             : 
     280      250000 :         tommy_tree_foreach_arg_node(next, func, arg);
     281             : }
     282             : 
     283           1 : void tommy_tree_foreach_arg(tommy_tree* tree, tommy_foreach_arg_func* func, void* arg)
     284             : {
     285           1 :         tommy_tree_foreach_arg_node(tree->root, func, arg);
     286           1 : }
     287             : 
     288           1 : tommy_size_t tommy_tree_memory_usage(tommy_tree* tree)
     289             : {
     290           1 :         return tommy_tree_count(tree) * sizeof(tommy_tree_node);
     291             : }
     292             : 

Generated by: LCOV version 1.13