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