1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2005-2011 Free Software Foundation Europe e.V.
5
6 This program is Free Software; you can redistribute it and/or
7 modify it under the terms of version three of the GNU Affero General Public
8 License as published by the Free Software Foundation and included
9 in the file LICENSE.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Affero General Public License for more details.
15
16 You should have received a copy of the GNU Affero 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
19 02110-1301, USA.
20 */
21 /*
22 * BAREOS red-black binary tree routines.
23 *
24 * rblist is a binary tree with the links being in the data item.
25 *
26 * Developed in part from ideas obtained from several online University courses.
27 *
28 * Kern Sibbald, November MMV
29 */
30
31 #include "include/bareos.h"
32 #include "lib/rblist.h"
33
34 /*
35 * Insert an item in the tree, but only if it is unique
36 * otherwise, the item is returned non inserted
37 * The big trick is keeping the tree balanced after the
38 * insert. We use a parent pointer to make it simpler and
39 * to avoid recursion.
40 *
41 * Returns: item if item inserted
42 * other_item if same value already exists (item not inserted)
43 */
insert(void * item,int compare (void * item1,void * item2))44 void* rblist::insert(void* item, int compare(void* item1, void* item2))
45 {
46 void *x, *y;
47 void* last = NULL; /* last leaf if not found */
48 void* found = NULL;
49 int comp = 0;
50
51 /* Search */
52 x = head;
53 while (x && !found) {
54 last = x;
55 comp = compare(item, x);
56 if (comp < 0) {
57 x = left(x);
58 } else if (comp > 0) {
59 x = right(x);
60 } else {
61 found = x;
62 }
63 }
64
65 if (found) { /* found? */
66 return found; /* yes, return item found */
67 }
68 SetLeft(item, NULL);
69 SetRight(item, NULL);
70 SetParent(item, NULL);
71 SetRed(item, false);
72 /* Handle empty tree */
73 if (num_items == 0) {
74 head = item;
75 num_items++;
76 return item;
77 }
78 x = last;
79 /* Not found, so insert it on appropriate side of tree */
80 if (comp < 0) {
81 SetLeft(last, item);
82 } else {
83 SetRight(last, item);
84 }
85 SetRed(last, true);
86 SetParent(item, last);
87 num_items++;
88
89 /* Now we must walk up the tree balancing it */
90 x = last;
91 while (x != head && red(parent(x))) {
92 if (parent(x) == left(parent(parent(x)))) {
93 /* Look at the right side of our grandparent */
94 y = right(parent(parent(x)));
95 if (y && red(y)) {
96 /* our parent must be black */
97 SetRed(parent(x), false);
98 SetRed(y, false);
99 SetRed(parent(parent(x)), true);
100 x = parent(parent(x)); /* move up to grandpa */
101 } else {
102 if (x == right(parent(x))) { /* right side of parent? */
103 x = parent(x);
104 LeftRotate(x);
105 }
106 /* make parent black too */
107 SetRed(parent(x), false);
108 SetRed(parent(parent(x)), true);
109 RightRotate(parent(parent(x)));
110 }
111 } else {
112 /* Look at left side of our grandparent */
113 y = left(parent(parent(x)));
114 if (y && red(y)) {
115 SetRed(parent(x), false);
116 SetRed(y, false);
117 SetRed(parent(parent(x)), true);
118 x = parent(parent(x)); /* move up to grandpa */
119 } else {
120 if (x == left(parent(x))) {
121 x = parent(x);
122 RightRotate(x);
123 }
124 /* make parent black too */
125 SetRed(parent(x), false);
126 SetRed(parent(parent(x)), true);
127 LeftRotate(parent(parent(x)));
128 }
129 }
130 }
131 /* Make sure the head is always black */
132 SetRed(head, false);
133 return item;
134 }
135
136 /*
137 * Search for item
138 */
search(void * item,int compare (void * item1,void * item2))139 void* rblist::search(void* item, int compare(void* item1, void* item2))
140 {
141 void* found = NULL;
142 void* x;
143 int comp;
144
145 x = head;
146 while (x) {
147 comp = compare(item, x);
148 if (comp < 0) {
149 x = left(x);
150 } else if (comp > 0) {
151 x = right(x);
152 } else {
153 found = x;
154 break;
155 }
156 }
157 return found;
158 }
159
160 /*
161 * Get first item (i.e. lowest value)
162 */
first(void)163 void* rblist::first(void)
164 {
165 void* x;
166
167 x = head;
168 down = true;
169 while (x) {
170 if (left(x)) {
171 x = left(x);
172 continue;
173 }
174 return x;
175 }
176 /* Tree is empty */
177 return NULL;
178 }
179
180 /*
181 * This is a non-recursive btree walk routine that returns
182 * the items one at a time in order. I've never seen a
183 * non-recursive tree walk routine published that returns
184 * one item at a time rather than doing a callback.
185 *
186 * Return the next item in sorted order. We assume first()
187 * was called once before calling this routine.
188 * We always go down as far as we can to the left, then up, and
189 * down one to the right, and again down as far as we can to the
190 * left. etc.
191 *
192 * Returns: pointer to next larger item
193 * NULL when no more items in tree
194 */
next(void * item)195 void* rblist::next(void* item)
196 {
197 void* x;
198
199 if (!item) { return first(); }
200
201 x = item;
202 if ((down && !left(x) && right(x)) || (!down && right(x))) {
203 /* Move down to right one */
204 down = true;
205 x = right(x);
206 /* Then all the way down left */
207 while (left(x)) { x = left(x); }
208 return x;
209 }
210
211 /* We have gone down all we can, so now go up */
212 for (;;) {
213 /* If at head, we are done */
214 if (!parent(x)) { return NULL; }
215 /* Move up in tree */
216 down = false;
217 /* if coming from right, continue up */
218 if (right(parent(x)) == x) {
219 x = parent(x);
220 continue;
221 }
222 /* Coming from left, go up one -- ie. return parent */
223 return parent(x);
224 }
225 }
226
227 /*
228 * Similer to next(), but visits all right nodes when
229 * coming up the tree.
230 */
any(void * item)231 void* rblist::any(void* item)
232 {
233 void* x;
234
235 if (!item) { return NULL; }
236
237 x = item;
238 if ((down && !left(x) && right(x)) || (!down && right(x))) {
239 /* Move down to right one */
240 down = true;
241 x = right(x);
242 /* Then all the way down left */
243 while (left(x)) { x = left(x); }
244 return x;
245 }
246
247 /* We have gone down all we can, so now go up */
248 for (;;) {
249 /* If at head, we are done */
250 if (!parent(x)) { return NULL; }
251 down = false;
252 /* Go up one and return parent */
253 return parent(x);
254 }
255 }
256
257
258 /* x is item, y is below and to right, then rotated to below left */
LeftRotate(void * item)259 void rblist::LeftRotate(void* item)
260 {
261 void* y;
262 void* x;
263
264 x = item;
265 y = right(x);
266 SetRight(x, left(y));
267 if (left(y)) { SetParent(left(y), x); }
268 SetParent(y, parent(x));
269 /* if no parent then we have a new head */
270 if (!parent(x)) {
271 head = y;
272 } else if (x == left(parent(x))) {
273 SetLeft(parent(x), y);
274 } else {
275 SetRight(parent(x), y);
276 }
277 SetLeft(y, x);
278 SetParent(x, y);
279 }
280
RightRotate(void * item)281 void rblist::RightRotate(void* item)
282 {
283 void *x, *y;
284
285 y = item;
286 x = left(y);
287 SetLeft(y, right(x));
288 if (right(x)) { SetParent(right(x), y); }
289 SetParent(x, parent(y));
290 /* if no parent then we have a new head */
291 if (!parent(y)) {
292 head = x;
293 } else if (y == left(parent(y))) {
294 SetLeft(parent(y), x);
295 } else {
296 SetRight(parent(y), x);
297 }
298 SetRight(x, y);
299 SetParent(y, x);
300 }
301
302
remove(void * item)303 void rblist::remove(void* item) {}
304
305 /* Destroy the tree contents. Not totally working */
destroy()306 void rblist::destroy()
307 {
308 void *x, *y = NULL;
309
310 x = first();
311 // printf("head=%p first=%p left=%p right=%p\n", head, x, left(x), right(x));
312 for (; (y = any(x));) {
313 /* Prune the last item */
314 if (parent(x)) {
315 if (x == left(parent(x))) {
316 SetLeft(parent(x), NULL);
317 } else if (x == right(parent(x))) {
318 SetRight(parent(x), NULL);
319 }
320 }
321 if (!left(x) && !right(x)) {
322 if (head == x) { head = NULL; }
323 // if (num_items<30) {
324 // printf("free nitems=%d item=%p left=%p right=%p\n",
325 // num_items, x, left(x), right(x));
326 // }
327 free((void*)x); /* free previous node */
328 num_items--;
329 }
330 x = y; /* save last node */
331 }
332 if (x) {
333 if (x == head) { head = NULL; }
334 // printf("free nitems=%d item=%p left=%p right=%p\n", num_items, x,
335 // left(x), right(x));
336 free((void*)x);
337 num_items--;
338 }
339 if (head) {
340 // printf("Free head\n");
341 free((void*)head);
342 }
343 // printf("free nitems=%d\n", num_items);
344
345 head = NULL;
346 }
347