/src/e2fsprogs/lib/ext2fs/rbtree.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Red Black Trees |
3 | | (C) 1999 Andrea Arcangeli <andrea@suse.de> |
4 | | (C) 2002 David Woodhouse <dwmw2@infradead.org> |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 2 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program; if not, write to the Free Software |
18 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | |
20 | | linux/lib/rbtree.c |
21 | | */ |
22 | | |
23 | | #include "rbtree.h" |
24 | | |
25 | | static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) |
26 | 0 | { |
27 | 0 | struct rb_node *right = node->rb_right; |
28 | 0 | struct rb_node *parent = ext2fs_rb_parent(node); |
29 | |
|
30 | 0 | if ((node->rb_right = right->rb_left)) |
31 | 0 | ext2fs_rb_set_parent(right->rb_left, node); |
32 | 0 | right->rb_left = node; |
33 | |
|
34 | 0 | ext2fs_rb_set_parent(right, parent); |
35 | |
|
36 | 0 | if (parent) |
37 | 0 | { |
38 | 0 | if (node == parent->rb_left) |
39 | 0 | parent->rb_left = right; |
40 | 0 | else |
41 | 0 | parent->rb_right = right; |
42 | 0 | } |
43 | 0 | else |
44 | 0 | root->rb_node = right; |
45 | 0 | ext2fs_rb_set_parent(node, right); |
46 | 0 | } |
47 | | |
48 | | static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) |
49 | 0 | { |
50 | 0 | struct rb_node *left = node->rb_left; |
51 | 0 | struct rb_node *parent = ext2fs_rb_parent(node); |
52 | |
|
53 | 0 | if ((node->rb_left = left->rb_right)) |
54 | 0 | ext2fs_rb_set_parent(left->rb_right, node); |
55 | 0 | left->rb_right = node; |
56 | |
|
57 | 0 | ext2fs_rb_set_parent(left, parent); |
58 | |
|
59 | 0 | if (parent) |
60 | 0 | { |
61 | 0 | if (node == parent->rb_right) |
62 | 0 | parent->rb_right = left; |
63 | 0 | else |
64 | 0 | parent->rb_left = left; |
65 | 0 | } |
66 | 0 | else |
67 | 0 | root->rb_node = left; |
68 | 0 | ext2fs_rb_set_parent(node, left); |
69 | 0 | } |
70 | | |
71 | | void ext2fs_rb_insert_color(struct rb_node *node, struct rb_root *root) |
72 | 0 | { |
73 | 0 | struct rb_node *parent, *gparent; |
74 | |
|
75 | 0 | while ((parent = ext2fs_rb_parent(node)) && ext2fs_rb_is_red(parent)) |
76 | 0 | { |
77 | 0 | gparent = ext2fs_rb_parent(parent); |
78 | |
|
79 | 0 | if (parent == gparent->rb_left) |
80 | 0 | { |
81 | 0 | { |
82 | 0 | register struct rb_node *uncle = gparent->rb_right; |
83 | 0 | if (uncle && ext2fs_rb_is_red(uncle)) |
84 | 0 | { |
85 | 0 | ext2fs_rb_set_black(uncle); |
86 | 0 | ext2fs_rb_set_black(parent); |
87 | 0 | ext2fs_rb_set_red(gparent); |
88 | 0 | node = gparent; |
89 | 0 | continue; |
90 | 0 | } |
91 | 0 | } |
92 | | |
93 | 0 | if (parent->rb_right == node) |
94 | 0 | { |
95 | 0 | register struct rb_node *tmp; |
96 | 0 | __rb_rotate_left(parent, root); |
97 | 0 | tmp = parent; |
98 | 0 | parent = node; |
99 | 0 | node = tmp; |
100 | 0 | } |
101 | |
|
102 | 0 | ext2fs_rb_set_black(parent); |
103 | 0 | ext2fs_rb_set_red(gparent); |
104 | 0 | __rb_rotate_right(gparent, root); |
105 | 0 | } else { |
106 | 0 | { |
107 | 0 | register struct rb_node *uncle = gparent->rb_left; |
108 | 0 | if (uncle && ext2fs_rb_is_red(uncle)) |
109 | 0 | { |
110 | 0 | ext2fs_rb_set_black(uncle); |
111 | 0 | ext2fs_rb_set_black(parent); |
112 | 0 | ext2fs_rb_set_red(gparent); |
113 | 0 | node = gparent; |
114 | 0 | continue; |
115 | 0 | } |
116 | 0 | } |
117 | | |
118 | 0 | if (parent->rb_left == node) |
119 | 0 | { |
120 | 0 | register struct rb_node *tmp; |
121 | 0 | __rb_rotate_right(parent, root); |
122 | 0 | tmp = parent; |
123 | 0 | parent = node; |
124 | 0 | node = tmp; |
125 | 0 | } |
126 | |
|
127 | 0 | ext2fs_rb_set_black(parent); |
128 | 0 | ext2fs_rb_set_red(gparent); |
129 | 0 | __rb_rotate_left(gparent, root); |
130 | 0 | } |
131 | 0 | } |
132 | |
|
133 | 0 | ext2fs_rb_set_black(root->rb_node); |
134 | 0 | } |
135 | | |
136 | | static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, |
137 | | struct rb_root *root) |
138 | 0 | { |
139 | 0 | struct rb_node *other; |
140 | |
|
141 | 0 | while ((!node || ext2fs_rb_is_black(node)) && node != root->rb_node) |
142 | 0 | { |
143 | 0 | if (parent->rb_left == node) |
144 | 0 | { |
145 | 0 | other = parent->rb_right; |
146 | 0 | if (ext2fs_rb_is_red(other)) |
147 | 0 | { |
148 | 0 | ext2fs_rb_set_black(other); |
149 | 0 | ext2fs_rb_set_red(parent); |
150 | 0 | __rb_rotate_left(parent, root); |
151 | 0 | other = parent->rb_right; |
152 | 0 | } |
153 | 0 | if ((!other->rb_left || ext2fs_rb_is_black(other->rb_left)) && |
154 | 0 | (!other->rb_right || ext2fs_rb_is_black(other->rb_right))) |
155 | 0 | { |
156 | 0 | ext2fs_rb_set_red(other); |
157 | 0 | node = parent; |
158 | 0 | parent = ext2fs_rb_parent(node); |
159 | 0 | } |
160 | 0 | else |
161 | 0 | { |
162 | 0 | if (!other->rb_right || ext2fs_rb_is_black(other->rb_right)) |
163 | 0 | { |
164 | 0 | ext2fs_rb_set_black(other->rb_left); |
165 | 0 | ext2fs_rb_set_red(other); |
166 | 0 | __rb_rotate_right(other, root); |
167 | 0 | other = parent->rb_right; |
168 | 0 | } |
169 | 0 | ext2fs_rb_set_color(other, ext2fs_rb_color(parent)); |
170 | 0 | ext2fs_rb_set_black(parent); |
171 | 0 | ext2fs_rb_set_black(other->rb_right); |
172 | 0 | __rb_rotate_left(parent, root); |
173 | 0 | node = root->rb_node; |
174 | 0 | break; |
175 | 0 | } |
176 | 0 | } |
177 | 0 | else |
178 | 0 | { |
179 | 0 | other = parent->rb_left; |
180 | 0 | if (ext2fs_rb_is_red(other)) |
181 | 0 | { |
182 | 0 | ext2fs_rb_set_black(other); |
183 | 0 | ext2fs_rb_set_red(parent); |
184 | 0 | __rb_rotate_right(parent, root); |
185 | 0 | other = parent->rb_left; |
186 | 0 | } |
187 | 0 | if ((!other->rb_left || ext2fs_rb_is_black(other->rb_left)) && |
188 | 0 | (!other->rb_right || ext2fs_rb_is_black(other->rb_right))) |
189 | 0 | { |
190 | 0 | ext2fs_rb_set_red(other); |
191 | 0 | node = parent; |
192 | 0 | parent = ext2fs_rb_parent(node); |
193 | 0 | } |
194 | 0 | else |
195 | 0 | { |
196 | 0 | if (!other->rb_left || ext2fs_rb_is_black(other->rb_left)) |
197 | 0 | { |
198 | 0 | ext2fs_rb_set_black(other->rb_right); |
199 | 0 | ext2fs_rb_set_red(other); |
200 | 0 | __rb_rotate_left(other, root); |
201 | 0 | other = parent->rb_left; |
202 | 0 | } |
203 | 0 | ext2fs_rb_set_color(other, ext2fs_rb_color(parent)); |
204 | 0 | ext2fs_rb_set_black(parent); |
205 | 0 | ext2fs_rb_set_black(other->rb_left); |
206 | 0 | __rb_rotate_right(parent, root); |
207 | 0 | node = root->rb_node; |
208 | 0 | break; |
209 | 0 | } |
210 | 0 | } |
211 | 0 | } |
212 | 0 | if (node) |
213 | 0 | ext2fs_rb_set_black(node); |
214 | 0 | } |
215 | | |
216 | | void ext2fs_rb_erase(struct rb_node *node, struct rb_root *root) |
217 | 0 | { |
218 | 0 | struct rb_node *child, *parent; |
219 | 0 | int color; |
220 | |
|
221 | 0 | if (!node->rb_left) |
222 | 0 | child = node->rb_right; |
223 | 0 | else if (!node->rb_right) |
224 | 0 | child = node->rb_left; |
225 | 0 | else |
226 | 0 | { |
227 | 0 | struct rb_node *old = node, *left; |
228 | |
|
229 | 0 | node = node->rb_right; |
230 | 0 | while ((left = node->rb_left) != NULL) |
231 | 0 | node = left; |
232 | |
|
233 | 0 | if (ext2fs_rb_parent(old)) { |
234 | 0 | if (ext2fs_rb_parent(old)->rb_left == old) |
235 | 0 | ext2fs_rb_parent(old)->rb_left = node; |
236 | 0 | else |
237 | 0 | ext2fs_rb_parent(old)->rb_right = node; |
238 | 0 | } else |
239 | 0 | root->rb_node = node; |
240 | |
|
241 | 0 | child = node->rb_right; |
242 | 0 | parent = ext2fs_rb_parent(node); |
243 | 0 | color = ext2fs_rb_color(node); |
244 | |
|
245 | 0 | if (parent == old) { |
246 | 0 | parent = node; |
247 | 0 | } else { |
248 | 0 | if (child) |
249 | 0 | ext2fs_rb_set_parent(child, parent); |
250 | 0 | parent->rb_left = child; |
251 | |
|
252 | 0 | node->rb_right = old->rb_right; |
253 | 0 | ext2fs_rb_set_parent(old->rb_right, node); |
254 | 0 | } |
255 | |
|
256 | 0 | node->rb_parent_color = old->rb_parent_color; |
257 | 0 | node->rb_left = old->rb_left; |
258 | 0 | ext2fs_rb_set_parent(old->rb_left, node); |
259 | |
|
260 | 0 | goto color; |
261 | 0 | } |
262 | | |
263 | 0 | parent = ext2fs_rb_parent(node); |
264 | 0 | color = ext2fs_rb_color(node); |
265 | |
|
266 | 0 | if (child) |
267 | 0 | ext2fs_rb_set_parent(child, parent); |
268 | 0 | if (parent) |
269 | 0 | { |
270 | 0 | if (parent->rb_left == node) |
271 | 0 | parent->rb_left = child; |
272 | 0 | else |
273 | 0 | parent->rb_right = child; |
274 | 0 | } |
275 | 0 | else |
276 | 0 | root->rb_node = child; |
277 | |
|
278 | 0 | color: |
279 | 0 | if (color == RB_BLACK) |
280 | 0 | __rb_erase_color(child, parent, root); |
281 | 0 | } |
282 | | |
283 | | /* |
284 | | * This function returns the first node (in sort order) of the tree. |
285 | | */ |
286 | | struct rb_node *ext2fs_rb_first(const struct rb_root *root) |
287 | 0 | { |
288 | 0 | struct rb_node *n; |
289 | |
|
290 | 0 | n = root->rb_node; |
291 | 0 | if (!n) |
292 | 0 | return NULL; |
293 | 0 | while (n->rb_left) |
294 | 0 | n = n->rb_left; |
295 | 0 | return n; |
296 | 0 | } |
297 | | |
298 | | struct rb_node *ext2fs_rb_last(const struct rb_root *root) |
299 | 0 | { |
300 | 0 | struct rb_node *n; |
301 | |
|
302 | 0 | n = root->rb_node; |
303 | 0 | if (!n) |
304 | 0 | return NULL; |
305 | 0 | while (n->rb_right) |
306 | 0 | n = n->rb_right; |
307 | 0 | return n; |
308 | 0 | } |
309 | | |
310 | | struct rb_node *ext2fs_rb_next(struct rb_node *node) |
311 | 0 | { |
312 | 0 | struct rb_node *parent; |
313 | |
|
314 | 0 | if (ext2fs_rb_parent(node) == node) |
315 | 0 | return NULL; |
316 | | |
317 | | /* If we have a right-hand child, go down and then left as far |
318 | | as we can. */ |
319 | 0 | if (node->rb_right) { |
320 | 0 | node = node->rb_right; |
321 | 0 | while (node->rb_left) |
322 | 0 | node=node->rb_left; |
323 | 0 | return (struct rb_node *)node; |
324 | 0 | } |
325 | | |
326 | | /* No right-hand children. Everything down and left is |
327 | | smaller than us, so any 'next' node must be in the general |
328 | | direction of our parent. Go up the tree; any time the |
329 | | ancestor is a right-hand child of its parent, keep going |
330 | | up. First time it's a left-hand child of its parent, said |
331 | | parent is our 'next' node. */ |
332 | 0 | while ((parent = ext2fs_rb_parent(node)) && node == parent->rb_right) |
333 | 0 | node = parent; |
334 | |
|
335 | 0 | return parent; |
336 | 0 | } |
337 | | |
338 | | struct rb_node *ext2fs_rb_prev(struct rb_node *node) |
339 | 0 | { |
340 | 0 | struct rb_node *parent; |
341 | |
|
342 | 0 | if (ext2fs_rb_parent(node) == node) |
343 | 0 | return NULL; |
344 | | |
345 | | /* If we have a left-hand child, go down and then right as far |
346 | | as we can. */ |
347 | 0 | if (node->rb_left) { |
348 | 0 | node = node->rb_left; |
349 | 0 | while (node->rb_right) |
350 | 0 | node=node->rb_right; |
351 | 0 | return (struct rb_node *)node; |
352 | 0 | } |
353 | | |
354 | | /* No left-hand children. Go up till we find an ancestor which |
355 | | is a right-hand child of its parent */ |
356 | 0 | while ((parent = ext2fs_rb_parent(node)) && node == parent->rb_left) |
357 | 0 | node = parent; |
358 | |
|
359 | 0 | return parent; |
360 | 0 | } |
361 | | |
362 | | void ext2fs_rb_replace_node(struct rb_node *victim, struct rb_node *new, |
363 | | struct rb_root *root) |
364 | 0 | { |
365 | 0 | struct rb_node *parent = ext2fs_rb_parent(victim); |
366 | | |
367 | | /* Set the surrounding nodes to point to the replacement */ |
368 | 0 | if (parent) { |
369 | 0 | if (victim == parent->rb_left) |
370 | 0 | parent->rb_left = new; |
371 | 0 | else |
372 | 0 | parent->rb_right = new; |
373 | 0 | } else { |
374 | 0 | root->rb_node = new; |
375 | 0 | } |
376 | 0 | if (victim->rb_left) |
377 | 0 | ext2fs_rb_set_parent(victim->rb_left, new); |
378 | 0 | if (victim->rb_right) |
379 | 0 | ext2fs_rb_set_parent(victim->rb_right, new); |
380 | | |
381 | | /* Copy the pointers/colour from the victim to the replacement */ |
382 | 0 | *new = *victim; |
383 | 0 | } |