1*38fd1498Szrj /* A splay-tree datatype.
2*38fd1498Szrj Copyright (C) 1998-2018 Free Software Foundation, Inc.
3*38fd1498Szrj Contributed by Mark Mitchell (mark@markmitchell.com).
4*38fd1498Szrj
5*38fd1498Szrj This file is part of the GNU Offloading and Multi Processing Library
6*38fd1498Szrj (libgomp).
7*38fd1498Szrj
8*38fd1498Szrj Libgomp is free software; you can redistribute it and/or modify it
9*38fd1498Szrj under the terms of the GNU General Public License as published by
10*38fd1498Szrj the Free Software Foundation; either version 3, or (at your option)
11*38fd1498Szrj any later version.
12*38fd1498Szrj
13*38fd1498Szrj Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
14*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15*38fd1498Szrj FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16*38fd1498Szrj more details.
17*38fd1498Szrj
18*38fd1498Szrj Under Section 7 of GPL version 3, you are granted additional
19*38fd1498Szrj permissions described in the GCC Runtime Library Exception, version
20*38fd1498Szrj 3.1, as published by the Free Software Foundation.
21*38fd1498Szrj
22*38fd1498Szrj You should have received a copy of the GNU General Public License and
23*38fd1498Szrj a copy of the GCC Runtime Library Exception along with this program;
24*38fd1498Szrj see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25*38fd1498Szrj <http://www.gnu.org/licenses/>. */
26*38fd1498Szrj
27*38fd1498Szrj /* The splay tree code copied from include/splay-tree.h and adjusted,
28*38fd1498Szrj so that all the data lives directly in splay_tree_node_s structure
29*38fd1498Szrj and no extra allocations are needed. */
30*38fd1498Szrj
31*38fd1498Szrj /* For an easily readable description of splay-trees, see:
32*38fd1498Szrj
33*38fd1498Szrj Lewis, Harry R. and Denenberg, Larry. Data Structures and Their
34*38fd1498Szrj Algorithms. Harper-Collins, Inc. 1991.
35*38fd1498Szrj
36*38fd1498Szrj The major feature of splay trees is that all basic tree operations
37*38fd1498Szrj are amortized O(log n) time for a tree with n nodes. */
38*38fd1498Szrj
39*38fd1498Szrj #include "libgomp.h"
40*38fd1498Szrj
41*38fd1498Szrj /* Rotate the edge joining the left child N with its parent P. PP is the
42*38fd1498Szrj grandparents' pointer to P. */
43*38fd1498Szrj
44*38fd1498Szrj static inline void
rotate_left(splay_tree_node * pp,splay_tree_node p,splay_tree_node n)45*38fd1498Szrj rotate_left (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
46*38fd1498Szrj {
47*38fd1498Szrj splay_tree_node tmp;
48*38fd1498Szrj tmp = n->right;
49*38fd1498Szrj n->right = p;
50*38fd1498Szrj p->left = tmp;
51*38fd1498Szrj *pp = n;
52*38fd1498Szrj }
53*38fd1498Szrj
54*38fd1498Szrj /* Rotate the edge joining the right child N with its parent P. PP is the
55*38fd1498Szrj grandparents' pointer to P. */
56*38fd1498Szrj
57*38fd1498Szrj static inline void
rotate_right(splay_tree_node * pp,splay_tree_node p,splay_tree_node n)58*38fd1498Szrj rotate_right (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
59*38fd1498Szrj {
60*38fd1498Szrj splay_tree_node tmp;
61*38fd1498Szrj tmp = n->left;
62*38fd1498Szrj n->left = p;
63*38fd1498Szrj p->right = tmp;
64*38fd1498Szrj *pp = n;
65*38fd1498Szrj }
66*38fd1498Szrj
67*38fd1498Szrj /* Bottom up splay of KEY. */
68*38fd1498Szrj
69*38fd1498Szrj static void
splay_tree_splay(splay_tree sp,splay_tree_key key)70*38fd1498Szrj splay_tree_splay (splay_tree sp, splay_tree_key key)
71*38fd1498Szrj {
72*38fd1498Szrj if (sp->root == NULL)
73*38fd1498Szrj return;
74*38fd1498Szrj
75*38fd1498Szrj do {
76*38fd1498Szrj int cmp1, cmp2;
77*38fd1498Szrj splay_tree_node n, c;
78*38fd1498Szrj
79*38fd1498Szrj n = sp->root;
80*38fd1498Szrj cmp1 = splay_compare (key, &n->key);
81*38fd1498Szrj
82*38fd1498Szrj /* Found. */
83*38fd1498Szrj if (cmp1 == 0)
84*38fd1498Szrj return;
85*38fd1498Szrj
86*38fd1498Szrj /* Left or right? If no child, then we're done. */
87*38fd1498Szrj if (cmp1 < 0)
88*38fd1498Szrj c = n->left;
89*38fd1498Szrj else
90*38fd1498Szrj c = n->right;
91*38fd1498Szrj if (!c)
92*38fd1498Szrj return;
93*38fd1498Szrj
94*38fd1498Szrj /* Next one left or right? If found or no child, we're done
95*38fd1498Szrj after one rotation. */
96*38fd1498Szrj cmp2 = splay_compare (key, &c->key);
97*38fd1498Szrj if (cmp2 == 0
98*38fd1498Szrj || (cmp2 < 0 && !c->left)
99*38fd1498Szrj || (cmp2 > 0 && !c->right))
100*38fd1498Szrj {
101*38fd1498Szrj if (cmp1 < 0)
102*38fd1498Szrj rotate_left (&sp->root, n, c);
103*38fd1498Szrj else
104*38fd1498Szrj rotate_right (&sp->root, n, c);
105*38fd1498Szrj return;
106*38fd1498Szrj }
107*38fd1498Szrj
108*38fd1498Szrj /* Now we have the four cases of double-rotation. */
109*38fd1498Szrj if (cmp1 < 0 && cmp2 < 0)
110*38fd1498Szrj {
111*38fd1498Szrj rotate_left (&n->left, c, c->left);
112*38fd1498Szrj rotate_left (&sp->root, n, n->left);
113*38fd1498Szrj }
114*38fd1498Szrj else if (cmp1 > 0 && cmp2 > 0)
115*38fd1498Szrj {
116*38fd1498Szrj rotate_right (&n->right, c, c->right);
117*38fd1498Szrj rotate_right (&sp->root, n, n->right);
118*38fd1498Szrj }
119*38fd1498Szrj else if (cmp1 < 0 && cmp2 > 0)
120*38fd1498Szrj {
121*38fd1498Szrj rotate_right (&n->left, c, c->right);
122*38fd1498Szrj rotate_left (&sp->root, n, n->left);
123*38fd1498Szrj }
124*38fd1498Szrj else if (cmp1 > 0 && cmp2 < 0)
125*38fd1498Szrj {
126*38fd1498Szrj rotate_left (&n->right, c, c->left);
127*38fd1498Szrj rotate_right (&sp->root, n, n->right);
128*38fd1498Szrj }
129*38fd1498Szrj } while (1);
130*38fd1498Szrj }
131*38fd1498Szrj
132*38fd1498Szrj /* Insert a new NODE into SP. The NODE shouldn't exist in the tree. */
133*38fd1498Szrj
134*38fd1498Szrj attribute_hidden void
splay_tree_insert(splay_tree sp,splay_tree_node node)135*38fd1498Szrj splay_tree_insert (splay_tree sp, splay_tree_node node)
136*38fd1498Szrj {
137*38fd1498Szrj int comparison = 0;
138*38fd1498Szrj
139*38fd1498Szrj splay_tree_splay (sp, &node->key);
140*38fd1498Szrj
141*38fd1498Szrj if (sp->root)
142*38fd1498Szrj comparison = splay_compare (&sp->root->key, &node->key);
143*38fd1498Szrj
144*38fd1498Szrj if (sp->root && comparison == 0)
145*38fd1498Szrj gomp_fatal ("Duplicate node");
146*38fd1498Szrj else
147*38fd1498Szrj {
148*38fd1498Szrj /* Insert it at the root. */
149*38fd1498Szrj if (sp->root == NULL)
150*38fd1498Szrj node->left = node->right = NULL;
151*38fd1498Szrj else if (comparison < 0)
152*38fd1498Szrj {
153*38fd1498Szrj node->left = sp->root;
154*38fd1498Szrj node->right = node->left->right;
155*38fd1498Szrj node->left->right = NULL;
156*38fd1498Szrj }
157*38fd1498Szrj else
158*38fd1498Szrj {
159*38fd1498Szrj node->right = sp->root;
160*38fd1498Szrj node->left = node->right->left;
161*38fd1498Szrj node->right->left = NULL;
162*38fd1498Szrj }
163*38fd1498Szrj
164*38fd1498Szrj sp->root = node;
165*38fd1498Szrj }
166*38fd1498Szrj }
167*38fd1498Szrj
168*38fd1498Szrj /* Remove node with KEY from SP. It is not an error if it did not exist. */
169*38fd1498Szrj
170*38fd1498Szrj attribute_hidden void
splay_tree_remove(splay_tree sp,splay_tree_key key)171*38fd1498Szrj splay_tree_remove (splay_tree sp, splay_tree_key key)
172*38fd1498Szrj {
173*38fd1498Szrj splay_tree_splay (sp, key);
174*38fd1498Szrj
175*38fd1498Szrj if (sp->root && splay_compare (&sp->root->key, key) == 0)
176*38fd1498Szrj {
177*38fd1498Szrj splay_tree_node left, right;
178*38fd1498Szrj
179*38fd1498Szrj left = sp->root->left;
180*38fd1498Szrj right = sp->root->right;
181*38fd1498Szrj
182*38fd1498Szrj /* One of the children is now the root. Doesn't matter much
183*38fd1498Szrj which, so long as we preserve the properties of the tree. */
184*38fd1498Szrj if (left)
185*38fd1498Szrj {
186*38fd1498Szrj sp->root = left;
187*38fd1498Szrj
188*38fd1498Szrj /* If there was a right child as well, hang it off the
189*38fd1498Szrj right-most leaf of the left child. */
190*38fd1498Szrj if (right)
191*38fd1498Szrj {
192*38fd1498Szrj while (left->right)
193*38fd1498Szrj left = left->right;
194*38fd1498Szrj left->right = right;
195*38fd1498Szrj }
196*38fd1498Szrj }
197*38fd1498Szrj else
198*38fd1498Szrj sp->root = right;
199*38fd1498Szrj }
200*38fd1498Szrj }
201*38fd1498Szrj
202*38fd1498Szrj /* Lookup KEY in SP, returning NODE if present, and NULL
203*38fd1498Szrj otherwise. */
204*38fd1498Szrj
205*38fd1498Szrj attribute_hidden splay_tree_key
splay_tree_lookup(splay_tree sp,splay_tree_key key)206*38fd1498Szrj splay_tree_lookup (splay_tree sp, splay_tree_key key)
207*38fd1498Szrj {
208*38fd1498Szrj splay_tree_splay (sp, key);
209*38fd1498Szrj
210*38fd1498Szrj if (sp->root && splay_compare (&sp->root->key, key) == 0)
211*38fd1498Szrj return &sp->root->key;
212*38fd1498Szrj else
213*38fd1498Szrj return NULL;
214*38fd1498Szrj }
215*38fd1498Szrj
216*38fd1498Szrj /* Helper function for splay_tree_foreach.
217*38fd1498Szrj
218*38fd1498Szrj Run FUNC on every node in KEY. */
219*38fd1498Szrj
220*38fd1498Szrj static void
splay_tree_foreach_internal(splay_tree_node node,splay_tree_callback func,void * data)221*38fd1498Szrj splay_tree_foreach_internal (splay_tree_node node, splay_tree_callback func,
222*38fd1498Szrj void *data)
223*38fd1498Szrj {
224*38fd1498Szrj if (!node)
225*38fd1498Szrj return;
226*38fd1498Szrj func (&node->key, data);
227*38fd1498Szrj splay_tree_foreach_internal (node->left, func, data);
228*38fd1498Szrj /* Yeah, whatever. GCC can fix my tail recursion. */
229*38fd1498Szrj splay_tree_foreach_internal (node->right, func, data);
230*38fd1498Szrj }
231*38fd1498Szrj
232*38fd1498Szrj /* Run FUNC on each of the nodes in SP. */
233*38fd1498Szrj
234*38fd1498Szrj attribute_hidden void
splay_tree_foreach(splay_tree sp,splay_tree_callback func,void * data)235*38fd1498Szrj splay_tree_foreach (splay_tree sp, splay_tree_callback func, void *data)
236*38fd1498Szrj {
237*38fd1498Szrj splay_tree_foreach_internal (sp->root, func, data);
238*38fd1498Szrj }
239