Blame view

lib/rbtree.c 8.62 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  /*
    Red Black Trees
    (C) 1999  Andrea Arcangeli <andrea@suse.de>
    (C) 2002  David Woodhouse <dwmw2@infradead.org>
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
  
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
  
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  
    linux/lib/rbtree.c
  */
  
  #include <linux/rbtree.h>
  #include <linux/module.h>
  
  static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
  {
  	struct rb_node *right = node->rb_right;
55a981027   David Woodhouse   [RBTREE] Merge co...
29
  	struct rb_node *parent = rb_parent(node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
  
  	if ((node->rb_right = right->rb_left))
55a981027   David Woodhouse   [RBTREE] Merge co...
32
  		rb_set_parent(right->rb_left, node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  	right->rb_left = node;
55a981027   David Woodhouse   [RBTREE] Merge co...
34
35
36
  	rb_set_parent(right, parent);
  
  	if (parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  	{
55a981027   David Woodhouse   [RBTREE] Merge co...
38
39
  		if (node == parent->rb_left)
  			parent->rb_left = right;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  		else
55a981027   David Woodhouse   [RBTREE] Merge co...
41
  			parent->rb_right = right;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  	}
  	else
  		root->rb_node = right;
55a981027   David Woodhouse   [RBTREE] Merge co...
45
  	rb_set_parent(node, right);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
  }
  
  static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
  {
  	struct rb_node *left = node->rb_left;
55a981027   David Woodhouse   [RBTREE] Merge co...
51
  	struct rb_node *parent = rb_parent(node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
  
  	if ((node->rb_left = left->rb_right))
55a981027   David Woodhouse   [RBTREE] Merge co...
54
  		rb_set_parent(left->rb_right, node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  	left->rb_right = node;
55a981027   David Woodhouse   [RBTREE] Merge co...
56
57
58
  	rb_set_parent(left, parent);
  
  	if (parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  	{
55a981027   David Woodhouse   [RBTREE] Merge co...
60
61
  		if (node == parent->rb_right)
  			parent->rb_right = left;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  		else
55a981027   David Woodhouse   [RBTREE] Merge co...
63
  			parent->rb_left = left;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
  	}
  	else
  		root->rb_node = left;
55a981027   David Woodhouse   [RBTREE] Merge co...
67
  	rb_set_parent(node, left);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
  }
  
  void rb_insert_color(struct rb_node *node, struct rb_root *root)
  {
  	struct rb_node *parent, *gparent;
55a981027   David Woodhouse   [RBTREE] Merge co...
73
  	while ((parent = rb_parent(node)) && rb_is_red(parent))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  	{
55a981027   David Woodhouse   [RBTREE] Merge co...
75
  		gparent = rb_parent(parent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
  
  		if (parent == gparent->rb_left)
  		{
  			{
  				register struct rb_node *uncle = gparent->rb_right;
55a981027   David Woodhouse   [RBTREE] Merge co...
81
  				if (uncle && rb_is_red(uncle))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  				{
55a981027   David Woodhouse   [RBTREE] Merge co...
83
84
85
  					rb_set_black(uncle);
  					rb_set_black(parent);
  					rb_set_red(gparent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
94
95
96
97
98
  					node = gparent;
  					continue;
  				}
  			}
  
  			if (parent->rb_right == node)
  			{
  				register struct rb_node *tmp;
  				__rb_rotate_left(parent, root);
  				tmp = parent;
  				parent = node;
  				node = tmp;
  			}
55a981027   David Woodhouse   [RBTREE] Merge co...
99
100
  			rb_set_black(parent);
  			rb_set_red(gparent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
  			__rb_rotate_right(gparent, root);
  		} else {
  			{
  				register struct rb_node *uncle = gparent->rb_left;
55a981027   David Woodhouse   [RBTREE] Merge co...
105
  				if (uncle && rb_is_red(uncle))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  				{
55a981027   David Woodhouse   [RBTREE] Merge co...
107
108
109
  					rb_set_black(uncle);
  					rb_set_black(parent);
  					rb_set_red(gparent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
115
116
117
118
119
120
121
122
  					node = gparent;
  					continue;
  				}
  			}
  
  			if (parent->rb_left == node)
  			{
  				register struct rb_node *tmp;
  				__rb_rotate_right(parent, root);
  				tmp = parent;
  				parent = node;
  				node = tmp;
  			}
55a981027   David Woodhouse   [RBTREE] Merge co...
123
124
  			rb_set_black(parent);
  			rb_set_red(gparent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
  			__rb_rotate_left(gparent, root);
  		}
  	}
55a981027   David Woodhouse   [RBTREE] Merge co...
128
  	rb_set_black(root->rb_node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
132
133
134
135
  }
  EXPORT_SYMBOL(rb_insert_color);
  
  static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
  			     struct rb_root *root)
  {
  	struct rb_node *other;
55a981027   David Woodhouse   [RBTREE] Merge co...
136
  	while ((!node || rb_is_black(node)) && node != root->rb_node)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
  	{
  		if (parent->rb_left == node)
  		{
  			other = parent->rb_right;
55a981027   David Woodhouse   [RBTREE] Merge co...
141
  			if (rb_is_red(other))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  			{
55a981027   David Woodhouse   [RBTREE] Merge co...
143
144
  				rb_set_black(other);
  				rb_set_red(parent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
  				__rb_rotate_left(parent, root);
  				other = parent->rb_right;
  			}
55a981027   David Woodhouse   [RBTREE] Merge co...
148
149
  			if ((!other->rb_left || rb_is_black(other->rb_left)) &&
  			    (!other->rb_right || rb_is_black(other->rb_right)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  			{
55a981027   David Woodhouse   [RBTREE] Merge co...
151
  				rb_set_red(other);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  				node = parent;
55a981027   David Woodhouse   [RBTREE] Merge co...
153
  				parent = rb_parent(node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
  			}
  			else
  			{
55a981027   David Woodhouse   [RBTREE] Merge co...
157
  				if (!other->rb_right || rb_is_black(other->rb_right))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  				{
55a981027   David Woodhouse   [RBTREE] Merge co...
159
  					struct rb_node *o_left;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  					if ((o_left = other->rb_left))
55a981027   David Woodhouse   [RBTREE] Merge co...
161
162
  						rb_set_black(o_left);
  					rb_set_red(other);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
  					__rb_rotate_right(other, root);
  					other = parent->rb_right;
  				}
2f3243aeb   David Woodhouse   [RBTREE] Switch r...
166
  				rb_set_color(other, rb_color(parent));
55a981027   David Woodhouse   [RBTREE] Merge co...
167
  				rb_set_black(parent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  				if (other->rb_right)
55a981027   David Woodhouse   [RBTREE] Merge co...
169
  					rb_set_black(other->rb_right);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
174
175
176
177
  				__rb_rotate_left(parent, root);
  				node = root->rb_node;
  				break;
  			}
  		}
  		else
  		{
  			other = parent->rb_left;
55a981027   David Woodhouse   [RBTREE] Merge co...
178
  			if (rb_is_red(other))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  			{
55a981027   David Woodhouse   [RBTREE] Merge co...
180
181
  				rb_set_black(other);
  				rb_set_red(parent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
  				__rb_rotate_right(parent, root);
  				other = parent->rb_left;
  			}
55a981027   David Woodhouse   [RBTREE] Merge co...
185
186
  			if ((!other->rb_left || rb_is_black(other->rb_left)) &&
  			    (!other->rb_right || rb_is_black(other->rb_right)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  			{
55a981027   David Woodhouse   [RBTREE] Merge co...
188
  				rb_set_red(other);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  				node = parent;
55a981027   David Woodhouse   [RBTREE] Merge co...
190
  				parent = rb_parent(node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
  			}
  			else
  			{
55a981027   David Woodhouse   [RBTREE] Merge co...
194
  				if (!other->rb_left || rb_is_black(other->rb_left))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
  				{
  					register struct rb_node *o_right;
  					if ((o_right = other->rb_right))
55a981027   David Woodhouse   [RBTREE] Merge co...
198
199
  						rb_set_black(o_right);
  					rb_set_red(other);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
  					__rb_rotate_left(other, root);
  					other = parent->rb_left;
  				}
2f3243aeb   David Woodhouse   [RBTREE] Switch r...
203
  				rb_set_color(other, rb_color(parent));
55a981027   David Woodhouse   [RBTREE] Merge co...
204
  				rb_set_black(parent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
  				if (other->rb_left)
55a981027   David Woodhouse   [RBTREE] Merge co...
206
  					rb_set_black(other->rb_left);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
211
212
213
  				__rb_rotate_right(parent, root);
  				node = root->rb_node;
  				break;
  			}
  		}
  	}
  	if (node)
55a981027   David Woodhouse   [RBTREE] Merge co...
214
  		rb_set_black(node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  }
  
  void rb_erase(struct rb_node *node, struct rb_root *root)
  {
  	struct rb_node *child, *parent;
  	int color;
  
  	if (!node->rb_left)
  		child = node->rb_right;
  	else if (!node->rb_right)
  		child = node->rb_left;
  	else
  	{
  		struct rb_node *old = node, *left;
  
  		node = node->rb_right;
  		while ((left = node->rb_left) != NULL)
  			node = left;
  		child = node->rb_right;
55a981027   David Woodhouse   [RBTREE] Merge co...
234
  		parent = rb_parent(node);
2f3243aeb   David Woodhouse   [RBTREE] Switch r...
235
  		color = rb_color(node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
  
  		if (child)
55a981027   David Woodhouse   [RBTREE] Merge co...
238
239
  			rb_set_parent(child, parent);
  		if (parent == old) {
1975e5937   David Woodhouse   [RBTREE] Remove d...
240
  			parent->rb_right = child;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
  			parent = node;
55a981027   David Woodhouse   [RBTREE] Merge co...
242
  		} else
1975e5937   David Woodhouse   [RBTREE] Remove d...
243
  			parent->rb_left = child;
2f3243aeb   David Woodhouse   [RBTREE] Switch r...
244
  		node->rb_parent_color = old->rb_parent_color;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
  		node->rb_right = old->rb_right;
  		node->rb_left = old->rb_left;
55a981027   David Woodhouse   [RBTREE] Merge co...
247
  		if (rb_parent(old))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  		{
55a981027   David Woodhouse   [RBTREE] Merge co...
249
250
  			if (rb_parent(old)->rb_left == old)
  				rb_parent(old)->rb_left = node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  			else
55a981027   David Woodhouse   [RBTREE] Merge co...
252
  				rb_parent(old)->rb_right = node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
  		} else
  			root->rb_node = node;
55a981027   David Woodhouse   [RBTREE] Merge co...
255
  		rb_set_parent(old->rb_left, node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
  		if (old->rb_right)
55a981027   David Woodhouse   [RBTREE] Merge co...
257
  			rb_set_parent(old->rb_right, node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
  		goto color;
  	}
55a981027   David Woodhouse   [RBTREE] Merge co...
260
  	parent = rb_parent(node);
2f3243aeb   David Woodhouse   [RBTREE] Switch r...
261
  	color = rb_color(node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
  
  	if (child)
55a981027   David Woodhouse   [RBTREE] Merge co...
264
  		rb_set_parent(child, parent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  	if (parent)
  	{
  		if (parent->rb_left == node)
  			parent->rb_left = child;
  		else
  			parent->rb_right = child;
  	}
  	else
  		root->rb_node = child;
  
   color:
  	if (color == RB_BLACK)
  		__rb_erase_color(child, parent, root);
  }
  EXPORT_SYMBOL(rb_erase);
  
  /*
   * This function returns the first node (in sort order) of the tree.
   */
  struct rb_node *rb_first(struct rb_root *root)
  {
  	struct rb_node	*n;
  
  	n = root->rb_node;
  	if (!n)
  		return NULL;
  	while (n->rb_left)
  		n = n->rb_left;
  	return n;
  }
  EXPORT_SYMBOL(rb_first);
  
  struct rb_node *rb_last(struct rb_root *root)
  {
  	struct rb_node	*n;
  
  	n = root->rb_node;
  	if (!n)
  		return NULL;
  	while (n->rb_right)
  		n = n->rb_right;
  	return n;
  }
  EXPORT_SYMBOL(rb_last);
  
  struct rb_node *rb_next(struct rb_node *node)
  {
55a981027   David Woodhouse   [RBTREE] Merge co...
312
  	struct rb_node *parent;
10fd48f23   Jens Axboe   [PATCH] rbtree: f...
313
314
  	if (rb_parent(node) == node)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
  	/* If we have a right-hand child, go down and then left as far
  	   as we can. */
  	if (node->rb_right) {
  		node = node->rb_right; 
  		while (node->rb_left)
  			node=node->rb_left;
  		return node;
  	}
  
  	/* No right-hand children.  Everything down and left is
  	   smaller than us, so any 'next' node must be in the general
  	   direction of our parent. Go up the tree; any time the
  	   ancestor is a right-hand child of its parent, keep going
  	   up. First time it's a left-hand child of its parent, said
  	   parent is our 'next' node. */
55a981027   David Woodhouse   [RBTREE] Merge co...
330
331
  	while ((parent = rb_parent(node)) && node == parent->rb_right)
  		node = parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332

55a981027   David Woodhouse   [RBTREE] Merge co...
333
  	return parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
338
  }
  EXPORT_SYMBOL(rb_next);
  
  struct rb_node *rb_prev(struct rb_node *node)
  {
55a981027   David Woodhouse   [RBTREE] Merge co...
339
  	struct rb_node *parent;
10fd48f23   Jens Axboe   [PATCH] rbtree: f...
340
341
  	if (rb_parent(node) == node)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
344
345
346
347
348
349
350
351
352
  	/* If we have a left-hand child, go down and then right as far
  	   as we can. */
  	if (node->rb_left) {
  		node = node->rb_left; 
  		while (node->rb_right)
  			node=node->rb_right;
  		return node;
  	}
  
  	/* No left-hand children. Go up till we find an ancestor which
  	   is a right-hand child of its parent */
55a981027   David Woodhouse   [RBTREE] Merge co...
353
354
  	while ((parent = rb_parent(node)) && node == parent->rb_left)
  		node = parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355

55a981027   David Woodhouse   [RBTREE] Merge co...
356
  	return parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
361
362
  }
  EXPORT_SYMBOL(rb_prev);
  
  void rb_replace_node(struct rb_node *victim, struct rb_node *new,
  		     struct rb_root *root)
  {
55a981027   David Woodhouse   [RBTREE] Merge co...
363
  	struct rb_node *parent = rb_parent(victim);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
367
368
369
370
371
372
373
374
  
  	/* Set the surrounding nodes to point to the replacement */
  	if (parent) {
  		if (victim == parent->rb_left)
  			parent->rb_left = new;
  		else
  			parent->rb_right = new;
  	} else {
  		root->rb_node = new;
  	}
  	if (victim->rb_left)
55a981027   David Woodhouse   [RBTREE] Merge co...
375
  		rb_set_parent(victim->rb_left, new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  	if (victim->rb_right)
55a981027   David Woodhouse   [RBTREE] Merge co...
377
  		rb_set_parent(victim->rb_right, new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
382
  
  	/* Copy the pointers/colour from the victim to the replacement */
  	*new = *victim;
  }
  EXPORT_SYMBOL(rb_replace_node);