Home | History | Annotate | Line # | Download | only in libiberty
      1 /* A splay-tree datatype.
      2    Copyright (C) 1998-2026 Free Software Foundation, Inc.
      3    Contributed by Mark Mitchell (mark (at) markmitchell.com).
      4 
      5 This file is part of GNU CC.
      6 
      7 GNU CC is free software; you can redistribute it and/or modify it
      8 under the terms of the GNU General Public License as published by
      9 the Free Software Foundation; either version 2, or (at your option)
     10 any later version.
     11 
     12 GNU CC is distributed in the hope that it will be useful, but
     13 WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15 General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with GNU CC; see the file COPYING.  If not, write to
     19 the Free Software Foundation, 51 Franklin Street - Fifth Floor,
     20 Boston, MA 02110-1301, USA.  */
     21 
     22 /* For an easily readable description of splay-trees, see:
     23 
     24      Lewis, Harry R. and Denenberg, Larry.  Data Structures and Their
     25      Algorithms.  Harper-Collins, Inc.  1991.  */
     26 
     27 #ifdef HAVE_CONFIG_H
     28 #include "config.h"
     29 #endif
     30 
     31 #ifdef HAVE_STDLIB_H
     32 #include <stdlib.h>
     33 #endif
     34 #ifdef HAVE_STRING_H
     35 #include <string.h>
     36 #endif
     37 
     38 #include <stdio.h>
     39 
     40 #include "libiberty.h"
     41 #include "splay-tree.h"
     42 
     43 static void splay_tree_delete_helper (splay_tree, splay_tree_node);
     44 static inline void rotate_left (splay_tree_node *,
     45 				splay_tree_node, splay_tree_node);
     46 static inline void rotate_right (splay_tree_node *,
     47 				splay_tree_node, splay_tree_node);
     48 static void splay_tree_splay (splay_tree, splay_tree_key);
     49 static int splay_tree_foreach_helper (splay_tree_node,
     50                                       splay_tree_foreach_fn, void*);
     51 
     52 /* Deallocate NODE (a member of SP), and all its sub-trees.  */
     53 
     54 static void
     55 splay_tree_delete_helper (splay_tree sp, splay_tree_node node)
     56 {
     57   splay_tree_node pending = 0;
     58   splay_tree_node active = 0;
     59 
     60   if (!node)
     61     return;
     62 
     63 #define KDEL(x)  if (sp->delete_key) (*sp->delete_key)(x);
     64 #define VDEL(x)  if (sp->delete_value) (*sp->delete_value)(x);
     65 
     66   KDEL (node->key);
     67   VDEL (node->value);
     68 
     69   /* We use the "key" field to hold the "next" pointer.  */
     70   node->key = (splay_tree_key)pending;
     71   pending = (splay_tree_node)node;
     72 
     73   /* Now, keep processing the pending list until there aren't any
     74      more.  This is a little more complicated than just recursing, but
     75      it doesn't toast the stack for large trees.  */
     76 
     77   while (pending)
     78     {
     79       active = pending;
     80       pending = 0;
     81       while (active)
     82 	{
     83 	  splay_tree_node temp;
     84 
     85 	  /* active points to a node which has its key and value
     86 	     deallocated, we just need to process left and right.  */
     87 
     88 	  if (active->left)
     89 	    {
     90 	      KDEL (active->left->key);
     91 	      VDEL (active->left->value);
     92 	      active->left->key = (splay_tree_key)pending;
     93 	      pending = (splay_tree_node)(active->left);
     94 	    }
     95 	  if (active->right)
     96 	    {
     97 	      KDEL (active->right->key);
     98 	      VDEL (active->right->value);
     99 	      active->right->key = (splay_tree_key)pending;
    100 	      pending = (splay_tree_node)(active->right);
    101 	    }
    102 
    103 	  temp = active;
    104 	  active = (splay_tree_node)(temp->key);
    105 	  (*sp->deallocate) ((char*) temp, sp->allocate_data);
    106 	}
    107     }
    108 #undef KDEL
    109 #undef VDEL
    110 }
    111 
    112 /* Rotate the edge joining the left child N with its parent P.  PP is the
    113    grandparents' pointer to P.  */
    114 
    115 static inline void
    116 rotate_left (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
    117 {
    118   splay_tree_node tmp;
    119   tmp = n->right;
    120   n->right = p;
    121   p->left = tmp;
    122   *pp = n;
    123 }
    124 
    125 /* Rotate the edge joining the right child N with its parent P.  PP is the
    126    grandparents' pointer to P.  */
    127 
    128 static inline void
    129 rotate_right (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
    130 {
    131   splay_tree_node tmp;
    132   tmp = n->left;
    133   n->left = p;
    134   p->right = tmp;
    135   *pp = n;
    136 }
    137 
    138 /* Bottom up splay of key.  */
    139 
    140 static void
    141 splay_tree_splay (splay_tree sp, splay_tree_key key)
    142 {
    143   if (sp->root == 0)
    144     return;
    145 
    146   do {
    147     int cmp1, cmp2;
    148     splay_tree_node n, c;
    149 
    150     n = sp->root;
    151     cmp1 = (*sp->comp) (key, n->key);
    152 
    153     /* Found.  */
    154     if (cmp1 == 0)
    155       return;
    156 
    157     /* Left or right?  If no child, then we're done.  */
    158     if (cmp1 < 0)
    159       c = n->left;
    160     else
    161       c = n->right;
    162     if (!c)
    163       return;
    164 
    165     /* Next one left or right?  If found or no child, we're done
    166        after one rotation.  */
    167     cmp2 = (*sp->comp) (key, c->key);
    168     if (cmp2 == 0
    169         || (cmp2 < 0 && !c->left)
    170         || (cmp2 > 0 && !c->right))
    171       {
    172 	if (cmp1 < 0)
    173 	  rotate_left (&sp->root, n, c);
    174 	else
    175 	  rotate_right (&sp->root, n, c);
    176         return;
    177       }
    178 
    179     /* Now we have the four cases of double-rotation.  */
    180     if (cmp1 < 0 && cmp2 < 0)
    181       {
    182 	rotate_left (&n->left, c, c->left);
    183 	rotate_left (&sp->root, n, n->left);
    184       }
    185     else if (cmp1 > 0 && cmp2 > 0)
    186       {
    187 	rotate_right (&n->right, c, c->right);
    188 	rotate_right (&sp->root, n, n->right);
    189       }
    190     else if (cmp1 < 0 && cmp2 > 0)
    191       {
    192 	rotate_right (&n->left, c, c->right);
    193 	rotate_left (&sp->root, n, n->left);
    194       }
    195     else if (cmp1 > 0 && cmp2 < 0)
    196       {
    197 	rotate_left (&n->right, c, c->left);
    198 	rotate_right (&sp->root, n, n->right);
    199       }
    200   } while (1);
    201 }
    202 
    203 /* Call FN, passing it the DATA, for every node below NODE, all of
    204    which are from SP, following an in-order traversal.  If FN every
    205    returns a non-zero value, the iteration ceases immediately, and the
    206    value is returned.  Otherwise, this function returns 0.  */
    207 
    208 static int
    209 splay_tree_foreach_helper (splay_tree_node node,
    210                            splay_tree_foreach_fn fn, void *data)
    211 {
    212   int val;
    213   splay_tree_node *stack;
    214   int stack_ptr, stack_size;
    215 
    216   /* A non-recursive implementation is used to avoid filling the stack
    217      for large trees.  Splay trees are worst case O(n) in the depth of
    218      the tree.  */
    219 
    220 #define INITIAL_STACK_SIZE 100
    221   stack_size = INITIAL_STACK_SIZE;
    222   stack_ptr = 0;
    223   stack = XNEWVEC (splay_tree_node, stack_size);
    224   val = 0;
    225 
    226   for (;;)
    227     {
    228       while (node != NULL)
    229 	{
    230 	  if (stack_ptr == stack_size)
    231 	    {
    232 	      stack_size *= 2;
    233 	      stack = XRESIZEVEC (splay_tree_node, stack, stack_size);
    234 	    }
    235 	  stack[stack_ptr++] = node;
    236 	  node = node->left;
    237 	}
    238 
    239       if (stack_ptr == 0)
    240 	break;
    241 
    242       node = stack[--stack_ptr];
    243 
    244       val = (*fn) (node, data);
    245       if (val)
    246 	break;
    247 
    248       node = node->right;
    249     }
    250 
    251   XDELETEVEC (stack);
    252   return val;
    253 }
    254 
    255 /* An allocator and deallocator based on xmalloc.  */
    256 static void *
    257 splay_tree_xmalloc_allocate (int size, void *data ATTRIBUTE_UNUSED)
    258 {
    259   return (void *) xmalloc (size);
    260 }
    261 
    262 static void
    263 splay_tree_xmalloc_deallocate (void *object, void *data ATTRIBUTE_UNUSED)
    264 {
    265   free (object);
    266 }
    267 
    268 
    269 /* Allocate a new splay tree, using COMPARE_FN to compare nodes,
    270    DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate
    271    values.  Use xmalloc to allocate the splay tree structure, and any
    272    nodes added.  */
    273 
    274 splay_tree
    275 splay_tree_new (splay_tree_compare_fn compare_fn,
    276                 splay_tree_delete_key_fn delete_key_fn,
    277                 splay_tree_delete_value_fn delete_value_fn)
    278 {
    279   return (splay_tree_new_with_allocator
    280           (compare_fn, delete_key_fn, delete_value_fn,
    281            splay_tree_xmalloc_allocate, splay_tree_xmalloc_deallocate, 0));
    282 }
    283 
    284 
    285 /* Allocate a new splay tree, using COMPARE_FN to compare nodes,
    286    DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate
    287    values.  */
    288 
    289 splay_tree
    290 splay_tree_new_with_allocator (splay_tree_compare_fn compare_fn,
    291                                splay_tree_delete_key_fn delete_key_fn,
    292                                splay_tree_delete_value_fn delete_value_fn,
    293                                splay_tree_allocate_fn allocate_fn,
    294                                splay_tree_deallocate_fn deallocate_fn,
    295                                void *allocate_data)
    296 {
    297   return
    298     splay_tree_new_typed_alloc (compare_fn, delete_key_fn, delete_value_fn,
    299 				allocate_fn, allocate_fn, deallocate_fn,
    300 				allocate_data);
    301 }
    302 
    303 /*
    304 
    305 @deftypefn Supplemental splay_tree splay_tree_new_with_typed_alloc @
    306 (splay_tree_compare_fn @var{compare_fn}, @
    307 splay_tree_delete_key_fn @var{delete_key_fn}, @
    308 splay_tree_delete_value_fn @var{delete_value_fn}, @
    309 splay_tree_allocate_fn @var{tree_allocate_fn}, @
    310 splay_tree_allocate_fn @var{node_allocate_fn}, @
    311 splay_tree_deallocate_fn @var{deallocate_fn}, @
    312 void * @var{allocate_data})
    313 
    314 This function creates a splay tree that uses two different allocators
    315 @var{tree_allocate_fn} and @var{node_allocate_fn} to use for allocating the
    316 tree itself and its nodes respectively.  This is useful when variables of
    317 different types need to be allocated with different allocators.
    318 
    319 The splay tree will use @var{compare_fn} to compare nodes,
    320 @var{delete_key_fn} to deallocate keys, and @var{delete_value_fn} to
    321 deallocate values.  Keys and values will be deallocated when the
    322 tree is deleted using splay_tree_delete or when a node is removed
    323 using splay_tree_remove.  splay_tree_insert will release the previously
    324 inserted key and value using @var{delete_key_fn} and @var{delete_value_fn}
    325 if the inserted key is already found in the tree.
    326 
    327 @end deftypefn
    328 
    329 */
    330 
    331 splay_tree
    332 splay_tree_new_typed_alloc (splay_tree_compare_fn compare_fn,
    333 			    splay_tree_delete_key_fn delete_key_fn,
    334 			    splay_tree_delete_value_fn delete_value_fn,
    335 			    splay_tree_allocate_fn tree_allocate_fn,
    336 			    splay_tree_allocate_fn node_allocate_fn,
    337 			    splay_tree_deallocate_fn deallocate_fn,
    338 			    void * allocate_data)
    339 {
    340   splay_tree sp = (splay_tree) (*tree_allocate_fn)
    341     (sizeof (struct splay_tree_s), allocate_data);
    342 
    343   sp->root = 0;
    344   sp->comp = compare_fn;
    345   sp->delete_key = delete_key_fn;
    346   sp->delete_value = delete_value_fn;
    347   sp->allocate = node_allocate_fn;
    348   sp->deallocate = deallocate_fn;
    349   sp->allocate_data = allocate_data;
    350 
    351   return sp;
    352 }
    353 
    354 /* Deallocate SP.  */
    355 
    356 void
    357 splay_tree_delete (splay_tree sp)
    358 {
    359   splay_tree_delete_helper (sp, sp->root);
    360   (*sp->deallocate) ((char*) sp, sp->allocate_data);
    361 }
    362 
    363 /* Insert a new node (associating KEY with DATA) into SP.  If a
    364    previous node with the indicated KEY exists, its data is replaced
    365    with the new value.  Returns the new node.  */
    366 
    367 splay_tree_node
    368 splay_tree_insert (splay_tree sp, splay_tree_key key, splay_tree_value value)
    369 {
    370   int comparison = 0;
    371 
    372   splay_tree_splay (sp, key);
    373 
    374   if (sp->root)
    375     comparison = (*sp->comp)(sp->root->key, key);
    376 
    377   if (sp->root && comparison == 0)
    378     {
    379       /* If the root of the tree already has the indicated KEY, delete
    380          the old key and old value, and replace them with KEY and  VALUE.  */
    381       if (sp->delete_key)
    382 	(*sp->delete_key) (sp->root->key);
    383       if (sp->delete_value)
    384 	(*sp->delete_value)(sp->root->value);
    385       sp->root->key = key;
    386       sp->root->value = value;
    387     }
    388   else
    389     {
    390       /* Create a new node, and insert it at the root.  */
    391       splay_tree_node node;
    392 
    393       node = ((splay_tree_node)
    394 	      (*sp->allocate) (sizeof (struct splay_tree_node_s),
    395 			       sp->allocate_data));
    396       node->key = key;
    397       node->value = value;
    398 
    399       if (!sp->root)
    400 	node->left = node->right = 0;
    401       else if (comparison < 0)
    402 	{
    403 	  node->left = sp->root;
    404 	  node->right = node->left->right;
    405 	  node->left->right = 0;
    406 	}
    407       else
    408 	{
    409 	  node->right = sp->root;
    410 	  node->left = node->right->left;
    411 	  node->right->left = 0;
    412 	}
    413 
    414       sp->root = node;
    415     }
    416 
    417   return sp->root;
    418 }
    419 
    420 /* Remove KEY from SP.  It is not an error if it did not exist.  */
    421 
    422 void
    423 splay_tree_remove (splay_tree sp, splay_tree_key key)
    424 {
    425   splay_tree_splay (sp, key);
    426 
    427   if (sp->root && (*sp->comp) (sp->root->key, key) == 0)
    428     {
    429       splay_tree_node left, right;
    430 
    431       left = sp->root->left;
    432       right = sp->root->right;
    433 
    434       /* Delete the root node itself.  */
    435       if (sp->delete_key)
    436 	(*sp->delete_key) (sp->root->key);
    437       if (sp->delete_value)
    438 	(*sp->delete_value) (sp->root->value);
    439       (*sp->deallocate) (sp->root, sp->allocate_data);
    440 
    441       /* One of the children is now the root.  Doesn't matter much
    442 	 which, so long as we preserve the properties of the tree.  */
    443       if (left)
    444 	{
    445 	  sp->root = left;
    446 
    447 	  /* If there was a right child as well, hang it off the
    448 	     right-most leaf of the left child.  */
    449 	  if (right)
    450 	    {
    451 	      while (left->right)
    452 		left = left->right;
    453 	      left->right = right;
    454 	    }
    455 	}
    456       else
    457 	sp->root = right;
    458     }
    459 }
    460 
    461 /* Lookup KEY in SP, returning VALUE if present, and NULL
    462    otherwise.  */
    463 
    464 splay_tree_node
    465 splay_tree_lookup (splay_tree sp, splay_tree_key key)
    466 {
    467   splay_tree_splay (sp, key);
    468 
    469   if (sp->root && (*sp->comp)(sp->root->key, key) == 0)
    470     return sp->root;
    471   else
    472     return 0;
    473 }
    474 
    475 /* Return the node in SP with the greatest key.  */
    476 
    477 splay_tree_node
    478 splay_tree_max (splay_tree sp)
    479 {
    480   splay_tree_node n = sp->root;
    481 
    482   if (!n)
    483     return NULL;
    484 
    485   while (n->right)
    486     n = n->right;
    487 
    488   return n;
    489 }
    490 
    491 /* Return the node in SP with the smallest key.  */
    492 
    493 splay_tree_node
    494 splay_tree_min (splay_tree sp)
    495 {
    496   splay_tree_node n = sp->root;
    497 
    498   if (!n)
    499     return NULL;
    500 
    501   while (n->left)
    502     n = n->left;
    503 
    504   return n;
    505 }
    506 
    507 /* Return the immediate predecessor KEY, or NULL if there is no
    508    predecessor.  KEY need not be present in the tree.  */
    509 
    510 splay_tree_node
    511 splay_tree_predecessor (splay_tree sp, splay_tree_key key)
    512 {
    513   int comparison;
    514   splay_tree_node node;
    515 
    516   /* If the tree is empty, there is certainly no predecessor.  */
    517   if (!sp->root)
    518     return NULL;
    519 
    520   /* Splay the tree around KEY.  That will leave either the KEY
    521      itself, its predecessor, or its successor at the root.  */
    522   splay_tree_splay (sp, key);
    523   comparison = (*sp->comp)(sp->root->key, key);
    524 
    525   /* If the predecessor is at the root, just return it.  */
    526   if (comparison < 0)
    527     return sp->root;
    528 
    529   /* Otherwise, find the rightmost element of the left subtree.  */
    530   node = sp->root->left;
    531   if (node)
    532     while (node->right)
    533       node = node->right;
    534 
    535   return node;
    536 }
    537 
    538 /* Return the immediate successor KEY, or NULL if there is no
    539    successor.  KEY need not be present in the tree.  */
    540 
    541 splay_tree_node
    542 splay_tree_successor (splay_tree sp, splay_tree_key key)
    543 {
    544   int comparison;
    545   splay_tree_node node;
    546 
    547   /* If the tree is empty, there is certainly no successor.  */
    548   if (!sp->root)
    549     return NULL;
    550 
    551   /* Splay the tree around KEY.  That will leave either the KEY
    552      itself, its predecessor, or its successor at the root.  */
    553   splay_tree_splay (sp, key);
    554   comparison = (*sp->comp)(sp->root->key, key);
    555 
    556   /* If the successor is at the root, just return it.  */
    557   if (comparison > 0)
    558     return sp->root;
    559 
    560   /* Otherwise, find the leftmost element of the right subtree.  */
    561   node = sp->root->right;
    562   if (node)
    563     while (node->left)
    564       node = node->left;
    565 
    566   return node;
    567 }
    568 
    569 /* Call FN, passing it the DATA, for every node in SP, following an
    570    in-order traversal.  If FN every returns a non-zero value, the
    571    iteration ceases immediately, and the value is returned.
    572    Otherwise, this function returns 0.  */
    573 
    574 int
    575 splay_tree_foreach (splay_tree sp, splay_tree_foreach_fn fn, void *data)
    576 {
    577   return splay_tree_foreach_helper (sp->root, fn, data);
    578 }
    579 
    580 /* Splay-tree comparison function, treating the keys as ints.  */
    581 
    582 int
    583 splay_tree_compare_ints (splay_tree_key k1, splay_tree_key k2)
    584 {
    585   if ((int) k1 < (int) k2)
    586     return -1;
    587   else if ((int) k1 > (int) k2)
    588     return 1;
    589   else
    590     return 0;
    591 }
    592 
    593 /* Splay-tree comparison function, treating the keys as pointers.  */
    594 
    595 int
    596 splay_tree_compare_pointers (splay_tree_key k1, splay_tree_key k2)
    597 {
    598   if ((char*) k1 < (char*) k2)
    599     return -1;
    600   else if ((char*) k1 > (char*) k2)
    601     return 1;
    602   else
    603     return 0;
    604 }
    605 
    606 /* Splay-tree comparison function, treating the keys as strings.  */
    607 
    608 int
    609 splay_tree_compare_strings (splay_tree_key k1, splay_tree_key k2)
    610 {
    611   return strcmp ((char *) k1, (char *) k2);
    612 }
    613 
    614 /* Splay-tree delete function, simply using free.  */
    615 
    616 void
    617 splay_tree_delete_pointers (splay_tree_value value)
    618 {
    619   free ((void *) value);
    620 }
    621