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