xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/splay-tree.c (revision 7e120ff03ede3fe64e2c8620c01465d528502ddb)
198b9484cSchristos /* A splay-tree datatype.
2*7e120ff0Schristos    Copyright (C) 1998-2024 Free Software Foundation, Inc.
398b9484cSchristos    Contributed by Mark Mitchell (mark@markmitchell.com).
498b9484cSchristos 
598b9484cSchristos This file is part of GNU CC.
698b9484cSchristos 
798b9484cSchristos GNU CC is free software; you can redistribute it and/or modify it
898b9484cSchristos under the terms of the GNU General Public License as published by
998b9484cSchristos the Free Software Foundation; either version 2, or (at your option)
1098b9484cSchristos any later version.
1198b9484cSchristos 
1298b9484cSchristos GNU CC is distributed in the hope that it will be useful, but
1398b9484cSchristos WITHOUT ANY WARRANTY; without even the implied warranty of
1498b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1598b9484cSchristos General Public License for more details.
1698b9484cSchristos 
1798b9484cSchristos You should have received a copy of the GNU General Public License
1898b9484cSchristos along with GNU CC; see the file COPYING.  If not, write to
1998b9484cSchristos the Free Software Foundation, 51 Franklin Street - Fifth Floor,
2098b9484cSchristos Boston, MA 02110-1301, USA.  */
2198b9484cSchristos 
2298b9484cSchristos /* For an easily readable description of splay-trees, see:
2398b9484cSchristos 
2498b9484cSchristos      Lewis, Harry R. and Denenberg, Larry.  Data Structures and Their
2598b9484cSchristos      Algorithms.  Harper-Collins, Inc.  1991.  */
2698b9484cSchristos 
2798b9484cSchristos #ifdef HAVE_CONFIG_H
2898b9484cSchristos #include "config.h"
2998b9484cSchristos #endif
3098b9484cSchristos 
3198b9484cSchristos #ifdef HAVE_STDLIB_H
3298b9484cSchristos #include <stdlib.h>
3398b9484cSchristos #endif
344559860eSchristos #ifdef HAVE_STRING_H
354559860eSchristos #include <string.h>
364559860eSchristos #endif
3798b9484cSchristos 
3898b9484cSchristos #include <stdio.h>
3998b9484cSchristos 
4098b9484cSchristos #include "libiberty.h"
4198b9484cSchristos #include "splay-tree.h"
4298b9484cSchristos 
4398b9484cSchristos static void splay_tree_delete_helper (splay_tree, splay_tree_node);
4498b9484cSchristos static inline void rotate_left (splay_tree_node *,
4598b9484cSchristos 				splay_tree_node, splay_tree_node);
4698b9484cSchristos static inline void rotate_right (splay_tree_node *,
4798b9484cSchristos 				splay_tree_node, splay_tree_node);
4898b9484cSchristos static void splay_tree_splay (splay_tree, splay_tree_key);
4998b9484cSchristos static int splay_tree_foreach_helper (splay_tree_node,
5098b9484cSchristos                                       splay_tree_foreach_fn, void*);
5198b9484cSchristos 
5298b9484cSchristos /* Deallocate NODE (a member of SP), and all its sub-trees.  */
5398b9484cSchristos 
5498b9484cSchristos static void
5598b9484cSchristos splay_tree_delete_helper (splay_tree sp, splay_tree_node node)
5698b9484cSchristos {
5798b9484cSchristos   splay_tree_node pending = 0;
5898b9484cSchristos   splay_tree_node active = 0;
5998b9484cSchristos 
6098b9484cSchristos   if (!node)
6198b9484cSchristos     return;
6298b9484cSchristos 
6398b9484cSchristos #define KDEL(x)  if (sp->delete_key) (*sp->delete_key)(x);
6498b9484cSchristos #define VDEL(x)  if (sp->delete_value) (*sp->delete_value)(x);
6598b9484cSchristos 
6698b9484cSchristos   KDEL (node->key);
6798b9484cSchristos   VDEL (node->value);
6898b9484cSchristos 
6998b9484cSchristos   /* We use the "key" field to hold the "next" pointer.  */
7098b9484cSchristos   node->key = (splay_tree_key)pending;
7198b9484cSchristos   pending = (splay_tree_node)node;
7298b9484cSchristos 
7398b9484cSchristos   /* Now, keep processing the pending list until there aren't any
7498b9484cSchristos      more.  This is a little more complicated than just recursing, but
7598b9484cSchristos      it doesn't toast the stack for large trees.  */
7698b9484cSchristos 
7798b9484cSchristos   while (pending)
7898b9484cSchristos     {
7998b9484cSchristos       active = pending;
8098b9484cSchristos       pending = 0;
8198b9484cSchristos       while (active)
8298b9484cSchristos 	{
8398b9484cSchristos 	  splay_tree_node temp;
8498b9484cSchristos 
8598b9484cSchristos 	  /* active points to a node which has its key and value
8698b9484cSchristos 	     deallocated, we just need to process left and right.  */
8798b9484cSchristos 
8898b9484cSchristos 	  if (active->left)
8998b9484cSchristos 	    {
9098b9484cSchristos 	      KDEL (active->left->key);
9198b9484cSchristos 	      VDEL (active->left->value);
9298b9484cSchristos 	      active->left->key = (splay_tree_key)pending;
9398b9484cSchristos 	      pending = (splay_tree_node)(active->left);
9498b9484cSchristos 	    }
9598b9484cSchristos 	  if (active->right)
9698b9484cSchristos 	    {
9798b9484cSchristos 	      KDEL (active->right->key);
9898b9484cSchristos 	      VDEL (active->right->value);
9998b9484cSchristos 	      active->right->key = (splay_tree_key)pending;
10098b9484cSchristos 	      pending = (splay_tree_node)(active->right);
10198b9484cSchristos 	    }
10298b9484cSchristos 
10398b9484cSchristos 	  temp = active;
10498b9484cSchristos 	  active = (splay_tree_node)(temp->key);
10598b9484cSchristos 	  (*sp->deallocate) ((char*) temp, sp->allocate_data);
10698b9484cSchristos 	}
10798b9484cSchristos     }
10898b9484cSchristos #undef KDEL
10998b9484cSchristos #undef VDEL
11098b9484cSchristos }
11198b9484cSchristos 
11298b9484cSchristos /* Rotate the edge joining the left child N with its parent P.  PP is the
11398b9484cSchristos    grandparents' pointer to P.  */
11498b9484cSchristos 
11598b9484cSchristos static inline void
11698b9484cSchristos rotate_left (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
11798b9484cSchristos {
11898b9484cSchristos   splay_tree_node tmp;
11998b9484cSchristos   tmp = n->right;
12098b9484cSchristos   n->right = p;
12198b9484cSchristos   p->left = tmp;
12298b9484cSchristos   *pp = n;
12398b9484cSchristos }
12498b9484cSchristos 
12598b9484cSchristos /* Rotate the edge joining the right child N with its parent P.  PP is the
12698b9484cSchristos    grandparents' pointer to P.  */
12798b9484cSchristos 
12898b9484cSchristos static inline void
12998b9484cSchristos rotate_right (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
13098b9484cSchristos {
13198b9484cSchristos   splay_tree_node tmp;
13298b9484cSchristos   tmp = n->left;
13398b9484cSchristos   n->left = p;
13498b9484cSchristos   p->right = tmp;
13598b9484cSchristos   *pp = n;
13698b9484cSchristos }
13798b9484cSchristos 
13898b9484cSchristos /* Bottom up splay of key.  */
13998b9484cSchristos 
14098b9484cSchristos static void
14198b9484cSchristos splay_tree_splay (splay_tree sp, splay_tree_key key)
14298b9484cSchristos {
14398b9484cSchristos   if (sp->root == 0)
14498b9484cSchristos     return;
14598b9484cSchristos 
14698b9484cSchristos   do {
14798b9484cSchristos     int cmp1, cmp2;
14898b9484cSchristos     splay_tree_node n, c;
14998b9484cSchristos 
15098b9484cSchristos     n = sp->root;
15198b9484cSchristos     cmp1 = (*sp->comp) (key, n->key);
15298b9484cSchristos 
15398b9484cSchristos     /* Found.  */
15498b9484cSchristos     if (cmp1 == 0)
15598b9484cSchristos       return;
15698b9484cSchristos 
15798b9484cSchristos     /* Left or right?  If no child, then we're done.  */
15898b9484cSchristos     if (cmp1 < 0)
15998b9484cSchristos       c = n->left;
16098b9484cSchristos     else
16198b9484cSchristos       c = n->right;
16298b9484cSchristos     if (!c)
16398b9484cSchristos       return;
16498b9484cSchristos 
16598b9484cSchristos     /* Next one left or right?  If found or no child, we're done
16698b9484cSchristos        after one rotation.  */
16798b9484cSchristos     cmp2 = (*sp->comp) (key, c->key);
16898b9484cSchristos     if (cmp2 == 0
16998b9484cSchristos         || (cmp2 < 0 && !c->left)
17098b9484cSchristos         || (cmp2 > 0 && !c->right))
17198b9484cSchristos       {
17298b9484cSchristos 	if (cmp1 < 0)
17398b9484cSchristos 	  rotate_left (&sp->root, n, c);
17498b9484cSchristos 	else
17598b9484cSchristos 	  rotate_right (&sp->root, n, c);
17698b9484cSchristos         return;
17798b9484cSchristos       }
17898b9484cSchristos 
17998b9484cSchristos     /* Now we have the four cases of double-rotation.  */
18098b9484cSchristos     if (cmp1 < 0 && cmp2 < 0)
18198b9484cSchristos       {
18298b9484cSchristos 	rotate_left (&n->left, c, c->left);
18398b9484cSchristos 	rotate_left (&sp->root, n, n->left);
18498b9484cSchristos       }
18598b9484cSchristos     else if (cmp1 > 0 && cmp2 > 0)
18698b9484cSchristos       {
18798b9484cSchristos 	rotate_right (&n->right, c, c->right);
18898b9484cSchristos 	rotate_right (&sp->root, n, n->right);
18998b9484cSchristos       }
19098b9484cSchristos     else if (cmp1 < 0 && cmp2 > 0)
19198b9484cSchristos       {
19298b9484cSchristos 	rotate_right (&n->left, c, c->right);
19398b9484cSchristos 	rotate_left (&sp->root, n, n->left);
19498b9484cSchristos       }
19598b9484cSchristos     else if (cmp1 > 0 && cmp2 < 0)
19698b9484cSchristos       {
19798b9484cSchristos 	rotate_left (&n->right, c, c->left);
19898b9484cSchristos 	rotate_right (&sp->root, n, n->right);
19998b9484cSchristos       }
20098b9484cSchristos   } while (1);
20198b9484cSchristos }
20298b9484cSchristos 
20398b9484cSchristos /* Call FN, passing it the DATA, for every node below NODE, all of
20498b9484cSchristos    which are from SP, following an in-order traversal.  If FN every
20598b9484cSchristos    returns a non-zero value, the iteration ceases immediately, and the
20698b9484cSchristos    value is returned.  Otherwise, this function returns 0.  */
20798b9484cSchristos 
20898b9484cSchristos static int
20998b9484cSchristos splay_tree_foreach_helper (splay_tree_node node,
21098b9484cSchristos                            splay_tree_foreach_fn fn, void *data)
21198b9484cSchristos {
21298b9484cSchristos   int val;
21398b9484cSchristos   splay_tree_node *stack;
21498b9484cSchristos   int stack_ptr, stack_size;
21598b9484cSchristos 
21698b9484cSchristos   /* A non-recursive implementation is used to avoid filling the stack
21798b9484cSchristos      for large trees.  Splay trees are worst case O(n) in the depth of
21898b9484cSchristos      the tree.  */
21998b9484cSchristos 
22098b9484cSchristos #define INITIAL_STACK_SIZE 100
22198b9484cSchristos   stack_size = INITIAL_STACK_SIZE;
22298b9484cSchristos   stack_ptr = 0;
22398b9484cSchristos   stack = XNEWVEC (splay_tree_node, stack_size);
22498b9484cSchristos   val = 0;
22598b9484cSchristos 
22698b9484cSchristos   for (;;)
22798b9484cSchristos     {
22898b9484cSchristos       while (node != NULL)
22998b9484cSchristos 	{
23098b9484cSchristos 	  if (stack_ptr == stack_size)
23198b9484cSchristos 	    {
23298b9484cSchristos 	      stack_size *= 2;
23398b9484cSchristos 	      stack = XRESIZEVEC (splay_tree_node, stack, stack_size);
23498b9484cSchristos 	    }
23598b9484cSchristos 	  stack[stack_ptr++] = node;
23698b9484cSchristos 	  node = node->left;
23798b9484cSchristos 	}
23898b9484cSchristos 
23998b9484cSchristos       if (stack_ptr == 0)
24098b9484cSchristos 	break;
24198b9484cSchristos 
24298b9484cSchristos       node = stack[--stack_ptr];
24398b9484cSchristos 
24498b9484cSchristos       val = (*fn) (node, data);
24598b9484cSchristos       if (val)
24698b9484cSchristos 	break;
24798b9484cSchristos 
24898b9484cSchristos       node = node->right;
24998b9484cSchristos     }
25098b9484cSchristos 
25198b9484cSchristos   XDELETEVEC (stack);
25298b9484cSchristos   return val;
25398b9484cSchristos }
25498b9484cSchristos 
25598b9484cSchristos /* An allocator and deallocator based on xmalloc.  */
25698b9484cSchristos static void *
25798b9484cSchristos splay_tree_xmalloc_allocate (int size, void *data ATTRIBUTE_UNUSED)
25898b9484cSchristos {
25998b9484cSchristos   return (void *) xmalloc (size);
26098b9484cSchristos }
26198b9484cSchristos 
26298b9484cSchristos static void
26398b9484cSchristos splay_tree_xmalloc_deallocate (void *object, void *data ATTRIBUTE_UNUSED)
26498b9484cSchristos {
26598b9484cSchristos   free (object);
26698b9484cSchristos }
26798b9484cSchristos 
26898b9484cSchristos 
26998b9484cSchristos /* Allocate a new splay tree, using COMPARE_FN to compare nodes,
27098b9484cSchristos    DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate
27198b9484cSchristos    values.  Use xmalloc to allocate the splay tree structure, and any
27298b9484cSchristos    nodes added.  */
27398b9484cSchristos 
27498b9484cSchristos splay_tree
27598b9484cSchristos splay_tree_new (splay_tree_compare_fn compare_fn,
27698b9484cSchristos                 splay_tree_delete_key_fn delete_key_fn,
27798b9484cSchristos                 splay_tree_delete_value_fn delete_value_fn)
27898b9484cSchristos {
27998b9484cSchristos   return (splay_tree_new_with_allocator
28098b9484cSchristos           (compare_fn, delete_key_fn, delete_value_fn,
28198b9484cSchristos            splay_tree_xmalloc_allocate, splay_tree_xmalloc_deallocate, 0));
28298b9484cSchristos }
28398b9484cSchristos 
28498b9484cSchristos 
28598b9484cSchristos /* Allocate a new splay tree, using COMPARE_FN to compare nodes,
28698b9484cSchristos    DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate
28798b9484cSchristos    values.  */
28898b9484cSchristos 
28998b9484cSchristos splay_tree
29098b9484cSchristos splay_tree_new_with_allocator (splay_tree_compare_fn compare_fn,
29198b9484cSchristos                                splay_tree_delete_key_fn delete_key_fn,
29298b9484cSchristos                                splay_tree_delete_value_fn delete_value_fn,
29398b9484cSchristos                                splay_tree_allocate_fn allocate_fn,
29498b9484cSchristos                                splay_tree_deallocate_fn deallocate_fn,
29598b9484cSchristos                                void *allocate_data)
29698b9484cSchristos {
29798b9484cSchristos   return
29898b9484cSchristos     splay_tree_new_typed_alloc (compare_fn, delete_key_fn, delete_value_fn,
29998b9484cSchristos 				allocate_fn, allocate_fn, deallocate_fn,
30098b9484cSchristos 				allocate_data);
30198b9484cSchristos }
30298b9484cSchristos 
30398b9484cSchristos /*
30498b9484cSchristos 
30598b9484cSchristos @deftypefn Supplemental splay_tree splay_tree_new_with_typed_alloc @
30698b9484cSchristos (splay_tree_compare_fn @var{compare_fn}, @
30798b9484cSchristos splay_tree_delete_key_fn @var{delete_key_fn}, @
30898b9484cSchristos splay_tree_delete_value_fn @var{delete_value_fn}, @
30998b9484cSchristos splay_tree_allocate_fn @var{tree_allocate_fn}, @
31098b9484cSchristos splay_tree_allocate_fn @var{node_allocate_fn}, @
31198b9484cSchristos splay_tree_deallocate_fn @var{deallocate_fn}, @
31298b9484cSchristos void * @var{allocate_data})
31398b9484cSchristos 
31498b9484cSchristos This function creates a splay tree that uses two different allocators
31598b9484cSchristos @var{tree_allocate_fn} and @var{node_allocate_fn} to use for allocating the
31698b9484cSchristos tree itself and its nodes respectively.  This is useful when variables of
31798b9484cSchristos different types need to be allocated with different allocators.
31898b9484cSchristos 
31998b9484cSchristos The splay tree will use @var{compare_fn} to compare nodes,
32098b9484cSchristos @var{delete_key_fn} to deallocate keys, and @var{delete_value_fn} to
3214559860eSchristos deallocate values.  Keys and values will be deallocated when the
3224559860eSchristos tree is deleted using splay_tree_delete or when a node is removed
3234559860eSchristos using splay_tree_remove.  splay_tree_insert will release the previously
3244559860eSchristos inserted key and value using @var{delete_key_fn} and @var{delete_value_fn}
3254559860eSchristos if the inserted key is already found in the tree.
32698b9484cSchristos 
32798b9484cSchristos @end deftypefn
32898b9484cSchristos 
32998b9484cSchristos */
33098b9484cSchristos 
33198b9484cSchristos splay_tree
33298b9484cSchristos splay_tree_new_typed_alloc (splay_tree_compare_fn compare_fn,
33398b9484cSchristos 			    splay_tree_delete_key_fn delete_key_fn,
33498b9484cSchristos 			    splay_tree_delete_value_fn delete_value_fn,
33598b9484cSchristos 			    splay_tree_allocate_fn tree_allocate_fn,
33698b9484cSchristos 			    splay_tree_allocate_fn node_allocate_fn,
33798b9484cSchristos 			    splay_tree_deallocate_fn deallocate_fn,
33898b9484cSchristos 			    void * allocate_data)
33998b9484cSchristos {
34098b9484cSchristos   splay_tree sp = (splay_tree) (*tree_allocate_fn)
34198b9484cSchristos     (sizeof (struct splay_tree_s), allocate_data);
34298b9484cSchristos 
34398b9484cSchristos   sp->root = 0;
34498b9484cSchristos   sp->comp = compare_fn;
34598b9484cSchristos   sp->delete_key = delete_key_fn;
34698b9484cSchristos   sp->delete_value = delete_value_fn;
34798b9484cSchristos   sp->allocate = node_allocate_fn;
34898b9484cSchristos   sp->deallocate = deallocate_fn;
34998b9484cSchristos   sp->allocate_data = allocate_data;
35098b9484cSchristos 
35198b9484cSchristos   return sp;
35298b9484cSchristos }
35398b9484cSchristos 
35498b9484cSchristos /* Deallocate SP.  */
35598b9484cSchristos 
35698b9484cSchristos void
35798b9484cSchristos splay_tree_delete (splay_tree sp)
35898b9484cSchristos {
35998b9484cSchristos   splay_tree_delete_helper (sp, sp->root);
36098b9484cSchristos   (*sp->deallocate) ((char*) sp, sp->allocate_data);
36198b9484cSchristos }
36298b9484cSchristos 
36398b9484cSchristos /* Insert a new node (associating KEY with DATA) into SP.  If a
36498b9484cSchristos    previous node with the indicated KEY exists, its data is replaced
36598b9484cSchristos    with the new value.  Returns the new node.  */
36698b9484cSchristos 
36798b9484cSchristos splay_tree_node
36898b9484cSchristos splay_tree_insert (splay_tree sp, splay_tree_key key, splay_tree_value value)
36998b9484cSchristos {
37098b9484cSchristos   int comparison = 0;
37198b9484cSchristos 
37298b9484cSchristos   splay_tree_splay (sp, key);
37398b9484cSchristos 
37498b9484cSchristos   if (sp->root)
37598b9484cSchristos     comparison = (*sp->comp)(sp->root->key, key);
37698b9484cSchristos 
37798b9484cSchristos   if (sp->root && comparison == 0)
37898b9484cSchristos     {
3794559860eSchristos       /* If the root of the tree already has the indicated KEY, delete
3804559860eSchristos          the old key and old value, and replace them with KEY and  VALUE.  */
3814559860eSchristos       if (sp->delete_key)
3824559860eSchristos 	(*sp->delete_key) (sp->root->key);
38398b9484cSchristos       if (sp->delete_value)
38498b9484cSchristos 	(*sp->delete_value)(sp->root->value);
3854559860eSchristos       sp->root->key = key;
38698b9484cSchristos       sp->root->value = value;
38798b9484cSchristos     }
38898b9484cSchristos   else
38998b9484cSchristos     {
39098b9484cSchristos       /* Create a new node, and insert it at the root.  */
39198b9484cSchristos       splay_tree_node node;
39298b9484cSchristos 
39398b9484cSchristos       node = ((splay_tree_node)
39498b9484cSchristos 	      (*sp->allocate) (sizeof (struct splay_tree_node_s),
39598b9484cSchristos 			       sp->allocate_data));
39698b9484cSchristos       node->key = key;
39798b9484cSchristos       node->value = value;
39898b9484cSchristos 
39998b9484cSchristos       if (!sp->root)
40098b9484cSchristos 	node->left = node->right = 0;
40198b9484cSchristos       else if (comparison < 0)
40298b9484cSchristos 	{
40398b9484cSchristos 	  node->left = sp->root;
40498b9484cSchristos 	  node->right = node->left->right;
40598b9484cSchristos 	  node->left->right = 0;
40698b9484cSchristos 	}
40798b9484cSchristos       else
40898b9484cSchristos 	{
40998b9484cSchristos 	  node->right = sp->root;
41098b9484cSchristos 	  node->left = node->right->left;
41198b9484cSchristos 	  node->right->left = 0;
41298b9484cSchristos 	}
41398b9484cSchristos 
41498b9484cSchristos       sp->root = node;
41598b9484cSchristos     }
41698b9484cSchristos 
41798b9484cSchristos   return sp->root;
41898b9484cSchristos }
41998b9484cSchristos 
42098b9484cSchristos /* Remove KEY from SP.  It is not an error if it did not exist.  */
42198b9484cSchristos 
42298b9484cSchristos void
42398b9484cSchristos splay_tree_remove (splay_tree sp, splay_tree_key key)
42498b9484cSchristos {
42598b9484cSchristos   splay_tree_splay (sp, key);
42698b9484cSchristos 
42798b9484cSchristos   if (sp->root && (*sp->comp) (sp->root->key, key) == 0)
42898b9484cSchristos     {
42998b9484cSchristos       splay_tree_node left, right;
43098b9484cSchristos 
43198b9484cSchristos       left = sp->root->left;
43298b9484cSchristos       right = sp->root->right;
43398b9484cSchristos 
43498b9484cSchristos       /* Delete the root node itself.  */
4354559860eSchristos       if (sp->delete_key)
4364559860eSchristos 	(*sp->delete_key) (sp->root->key);
43798b9484cSchristos       if (sp->delete_value)
43898b9484cSchristos 	(*sp->delete_value) (sp->root->value);
43998b9484cSchristos       (*sp->deallocate) (sp->root, sp->allocate_data);
44098b9484cSchristos 
44198b9484cSchristos       /* One of the children is now the root.  Doesn't matter much
44298b9484cSchristos 	 which, so long as we preserve the properties of the tree.  */
44398b9484cSchristos       if (left)
44498b9484cSchristos 	{
44598b9484cSchristos 	  sp->root = left;
44698b9484cSchristos 
44798b9484cSchristos 	  /* If there was a right child as well, hang it off the
44898b9484cSchristos 	     right-most leaf of the left child.  */
44998b9484cSchristos 	  if (right)
45098b9484cSchristos 	    {
45198b9484cSchristos 	      while (left->right)
45298b9484cSchristos 		left = left->right;
45398b9484cSchristos 	      left->right = right;
45498b9484cSchristos 	    }
45598b9484cSchristos 	}
45698b9484cSchristos       else
45798b9484cSchristos 	sp->root = right;
45898b9484cSchristos     }
45998b9484cSchristos }
46098b9484cSchristos 
46198b9484cSchristos /* Lookup KEY in SP, returning VALUE if present, and NULL
46298b9484cSchristos    otherwise.  */
46398b9484cSchristos 
46498b9484cSchristos splay_tree_node
46598b9484cSchristos splay_tree_lookup (splay_tree sp, splay_tree_key key)
46698b9484cSchristos {
46798b9484cSchristos   splay_tree_splay (sp, key);
46898b9484cSchristos 
46998b9484cSchristos   if (sp->root && (*sp->comp)(sp->root->key, key) == 0)
47098b9484cSchristos     return sp->root;
47198b9484cSchristos   else
47298b9484cSchristos     return 0;
47398b9484cSchristos }
47498b9484cSchristos 
47598b9484cSchristos /* Return the node in SP with the greatest key.  */
47698b9484cSchristos 
47798b9484cSchristos splay_tree_node
47898b9484cSchristos splay_tree_max (splay_tree sp)
47998b9484cSchristos {
48098b9484cSchristos   splay_tree_node n = sp->root;
48198b9484cSchristos 
48298b9484cSchristos   if (!n)
48398b9484cSchristos     return NULL;
48498b9484cSchristos 
48598b9484cSchristos   while (n->right)
48698b9484cSchristos     n = n->right;
48798b9484cSchristos 
48898b9484cSchristos   return n;
48998b9484cSchristos }
49098b9484cSchristos 
49198b9484cSchristos /* Return the node in SP with the smallest key.  */
49298b9484cSchristos 
49398b9484cSchristos splay_tree_node
49498b9484cSchristos splay_tree_min (splay_tree sp)
49598b9484cSchristos {
49698b9484cSchristos   splay_tree_node n = sp->root;
49798b9484cSchristos 
49898b9484cSchristos   if (!n)
49998b9484cSchristos     return NULL;
50098b9484cSchristos 
50198b9484cSchristos   while (n->left)
50298b9484cSchristos     n = n->left;
50398b9484cSchristos 
50498b9484cSchristos   return n;
50598b9484cSchristos }
50698b9484cSchristos 
50798b9484cSchristos /* Return the immediate predecessor KEY, or NULL if there is no
50898b9484cSchristos    predecessor.  KEY need not be present in the tree.  */
50998b9484cSchristos 
51098b9484cSchristos splay_tree_node
51198b9484cSchristos splay_tree_predecessor (splay_tree sp, splay_tree_key key)
51298b9484cSchristos {
51398b9484cSchristos   int comparison;
51498b9484cSchristos   splay_tree_node node;
51598b9484cSchristos 
51698b9484cSchristos   /* If the tree is empty, there is certainly no predecessor.  */
51798b9484cSchristos   if (!sp->root)
51898b9484cSchristos     return NULL;
51998b9484cSchristos 
52098b9484cSchristos   /* Splay the tree around KEY.  That will leave either the KEY
52198b9484cSchristos      itself, its predecessor, or its successor at the root.  */
52298b9484cSchristos   splay_tree_splay (sp, key);
52398b9484cSchristos   comparison = (*sp->comp)(sp->root->key, key);
52498b9484cSchristos 
52598b9484cSchristos   /* If the predecessor is at the root, just return it.  */
52698b9484cSchristos   if (comparison < 0)
52798b9484cSchristos     return sp->root;
52898b9484cSchristos 
52998b9484cSchristos   /* Otherwise, find the rightmost element of the left subtree.  */
53098b9484cSchristos   node = sp->root->left;
53198b9484cSchristos   if (node)
53298b9484cSchristos     while (node->right)
53398b9484cSchristos       node = node->right;
53498b9484cSchristos 
53598b9484cSchristos   return node;
53698b9484cSchristos }
53798b9484cSchristos 
53898b9484cSchristos /* Return the immediate successor KEY, or NULL if there is no
53998b9484cSchristos    successor.  KEY need not be present in the tree.  */
54098b9484cSchristos 
54198b9484cSchristos splay_tree_node
54298b9484cSchristos splay_tree_successor (splay_tree sp, splay_tree_key key)
54398b9484cSchristos {
54498b9484cSchristos   int comparison;
54598b9484cSchristos   splay_tree_node node;
54698b9484cSchristos 
54798b9484cSchristos   /* If the tree is empty, there is certainly no successor.  */
54898b9484cSchristos   if (!sp->root)
54998b9484cSchristos     return NULL;
55098b9484cSchristos 
55198b9484cSchristos   /* Splay the tree around KEY.  That will leave either the KEY
55298b9484cSchristos      itself, its predecessor, or its successor at the root.  */
55398b9484cSchristos   splay_tree_splay (sp, key);
55498b9484cSchristos   comparison = (*sp->comp)(sp->root->key, key);
55598b9484cSchristos 
55698b9484cSchristos   /* If the successor is at the root, just return it.  */
55798b9484cSchristos   if (comparison > 0)
55898b9484cSchristos     return sp->root;
55998b9484cSchristos 
56098b9484cSchristos   /* Otherwise, find the leftmost element of the right subtree.  */
56198b9484cSchristos   node = sp->root->right;
56298b9484cSchristos   if (node)
56398b9484cSchristos     while (node->left)
56498b9484cSchristos       node = node->left;
56598b9484cSchristos 
56698b9484cSchristos   return node;
56798b9484cSchristos }
56898b9484cSchristos 
56998b9484cSchristos /* Call FN, passing it the DATA, for every node in SP, following an
57098b9484cSchristos    in-order traversal.  If FN every returns a non-zero value, the
57198b9484cSchristos    iteration ceases immediately, and the value is returned.
57298b9484cSchristos    Otherwise, this function returns 0.  */
57398b9484cSchristos 
57498b9484cSchristos int
57598b9484cSchristos splay_tree_foreach (splay_tree sp, splay_tree_foreach_fn fn, void *data)
57698b9484cSchristos {
57798b9484cSchristos   return splay_tree_foreach_helper (sp->root, fn, data);
57898b9484cSchristos }
57998b9484cSchristos 
58098b9484cSchristos /* Splay-tree comparison function, treating the keys as ints.  */
58198b9484cSchristos 
58298b9484cSchristos int
58398b9484cSchristos splay_tree_compare_ints (splay_tree_key k1, splay_tree_key k2)
58498b9484cSchristos {
58598b9484cSchristos   if ((int) k1 < (int) k2)
58698b9484cSchristos     return -1;
58798b9484cSchristos   else if ((int) k1 > (int) k2)
58898b9484cSchristos     return 1;
58998b9484cSchristos   else
59098b9484cSchristos     return 0;
59198b9484cSchristos }
59298b9484cSchristos 
59398b9484cSchristos /* Splay-tree comparison function, treating the keys as pointers.  */
59498b9484cSchristos 
59598b9484cSchristos int
59698b9484cSchristos splay_tree_compare_pointers (splay_tree_key k1, splay_tree_key k2)
59798b9484cSchristos {
59898b9484cSchristos   if ((char*) k1 < (char*) k2)
59998b9484cSchristos     return -1;
60098b9484cSchristos   else if ((char*) k1 > (char*) k2)
60198b9484cSchristos     return 1;
60298b9484cSchristos   else
60398b9484cSchristos     return 0;
60498b9484cSchristos }
6054559860eSchristos 
6064559860eSchristos /* Splay-tree comparison function, treating the keys as strings.  */
6074559860eSchristos 
6084559860eSchristos int
6094559860eSchristos splay_tree_compare_strings (splay_tree_key k1, splay_tree_key k2)
6104559860eSchristos {
6114559860eSchristos   return strcmp ((char *) k1, (char *) k2);
6124559860eSchristos }
6134559860eSchristos 
6144559860eSchristos /* Splay-tree delete function, simply using free.  */
6154559860eSchristos 
6164559860eSchristos void
6174559860eSchristos splay_tree_delete_pointers (splay_tree_value value)
6184559860eSchristos {
6194559860eSchristos   free ((void *) value);
6204559860eSchristos }
621