VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/shaderlib/libWineStub/include/wine/rbtree.h@ 93468

Last change on this file since 93468 was 53201, checked in by vboxsync, 10 years ago

Devices/Main: vmsvga updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.2 KB
Line 
1/*
2 * Red-black search tree support
3 *
4 * Copyright 2009 Henri Verbeet
5 * Copyright 2009 Andrew Riedi
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22/*
23 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
24 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
25 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
26 * a choice of LGPL license versions is made available with the language indicating
27 * that LGPLv2 or any later version may be used, or where a choice of which version
28 * of the LGPL is applied is otherwise unspecified.
29 */
30
31#ifndef __WINE_WINE_RBTREE_H
32#define __WINE_WINE_RBTREE_H
33
34#ifdef inline
35#undef inline
36#endif
37#define inline __inline
38
39
40#define WINE_RB_ENTRY_VALUE(element, type, field) \
41 ((type *)((char *)(element) - FIELD_OFFSET(type, field)))
42
43struct wine_rb_entry
44{
45 struct wine_rb_entry *left;
46 struct wine_rb_entry *right;
47 unsigned int flags;
48};
49
50struct wine_rb_stack
51{
52 struct wine_rb_entry ***entries;
53 size_t count;
54 size_t size;
55};
56
57struct wine_rb_functions
58{
59 void *(*alloc)(size_t size);
60 void *(*realloc)(void *ptr, size_t size);
61 void (*free)(void *ptr);
62 int (*compare)(const void *key, const struct wine_rb_entry *entry);
63};
64
65struct wine_rb_tree
66{
67 const struct wine_rb_functions *functions;
68 struct wine_rb_entry *root;
69 struct wine_rb_stack stack;
70};
71
72typedef void (wine_rb_traverse_func_t)(struct wine_rb_entry *entry, void *context);
73
74#define WINE_RB_FLAG_RED 0x1
75#define WINE_RB_FLAG_STOP 0x2
76#define WINE_RB_FLAG_TRAVERSED_LEFT 0x4
77#define WINE_RB_FLAG_TRAVERSED_RIGHT 0x8
78
79static inline void wine_rb_stack_clear(struct wine_rb_stack *stack)
80{
81 stack->count = 0;
82}
83
84static inline void wine_rb_stack_push(struct wine_rb_stack *stack, struct wine_rb_entry **entry)
85{
86 stack->entries[stack->count++] = entry;
87}
88
89static inline int wine_rb_ensure_stack_size(struct wine_rb_tree *tree, size_t size)
90{
91 struct wine_rb_stack *stack = &tree->stack;
92
93 if (size > stack->size)
94 {
95 size_t new_size = stack->size << 1;
96 struct wine_rb_entry ***new_entries = tree->functions->realloc(stack->entries,
97 new_size * sizeof(*stack->entries));
98
99 if (!new_entries) return -1;
100
101 stack->entries = new_entries;
102 stack->size = new_size;
103 }
104
105 return 0;
106}
107
108static inline int wine_rb_is_red(struct wine_rb_entry *entry)
109{
110 return entry && (entry->flags & WINE_RB_FLAG_RED);
111}
112
113static inline void wine_rb_rotate_left(struct wine_rb_entry **entry)
114{
115 struct wine_rb_entry *e = *entry;
116 struct wine_rb_entry *right = e->right;
117
118 e->right = right->left;
119 right->left = e;
120 right->flags &= ~WINE_RB_FLAG_RED;
121 right->flags |= e->flags & WINE_RB_FLAG_RED;
122 e->flags |= WINE_RB_FLAG_RED;
123 *entry = right;
124}
125
126static inline void wine_rb_rotate_right(struct wine_rb_entry **entry)
127{
128 struct wine_rb_entry *e = *entry;
129 struct wine_rb_entry *left = e->left;
130
131 e->left = left->right;
132 left->right = e;
133 left->flags &= ~WINE_RB_FLAG_RED;
134 left->flags |= e->flags & WINE_RB_FLAG_RED;
135 e->flags |= WINE_RB_FLAG_RED;
136 *entry = left;
137}
138
139static inline void wine_rb_flip_color(struct wine_rb_entry *entry)
140{
141 entry->flags ^= WINE_RB_FLAG_RED;
142 entry->left->flags ^= WINE_RB_FLAG_RED;
143 entry->right->flags ^= WINE_RB_FLAG_RED;
144}
145
146static inline void wine_rb_fixup(struct wine_rb_stack *stack)
147{
148 while (stack->count)
149 {
150 struct wine_rb_entry **entry = stack->entries[stack->count - 1];
151
152 if ((*entry)->flags & WINE_RB_FLAG_STOP)
153 {
154 (*entry)->flags &= ~WINE_RB_FLAG_STOP;
155 return;
156 }
157
158 if (wine_rb_is_red((*entry)->right) && !wine_rb_is_red((*entry)->left)) wine_rb_rotate_left(entry);
159 if (wine_rb_is_red((*entry)->left) && wine_rb_is_red((*entry)->left->left)) wine_rb_rotate_right(entry);
160 if (wine_rb_is_red((*entry)->left) && wine_rb_is_red((*entry)->right)) wine_rb_flip_color(*entry);
161 --stack->count;
162 }
163}
164
165static inline void wine_rb_move_red_left(struct wine_rb_entry **entry)
166{
167 wine_rb_flip_color(*entry);
168 if (wine_rb_is_red((*entry)->right->left))
169 {
170 wine_rb_rotate_right(&(*entry)->right);
171 wine_rb_rotate_left(entry);
172 wine_rb_flip_color(*entry);
173 }
174}
175
176static inline void wine_rb_move_red_right(struct wine_rb_entry **entry)
177{
178 wine_rb_flip_color(*entry);
179 if (wine_rb_is_red((*entry)->left->left))
180 {
181 wine_rb_rotate_right(entry);
182 wine_rb_flip_color(*entry);
183 }
184}
185
186static inline void wine_rb_postorder(struct wine_rb_tree *tree, wine_rb_traverse_func_t *callback, void *context)
187{
188 struct wine_rb_entry **entry;
189
190 if (!tree->root) return;
191
192 for (entry = &tree->root;;)
193 {
194 struct wine_rb_entry *e = *entry;
195
196 if (e->left && !(e->flags & WINE_RB_FLAG_TRAVERSED_LEFT))
197 {
198 wine_rb_stack_push(&tree->stack, entry);
199 e->flags |= WINE_RB_FLAG_TRAVERSED_LEFT;
200 entry = &e->left;
201 continue;
202 }
203
204 if (e->right && !(e->flags & WINE_RB_FLAG_TRAVERSED_RIGHT))
205 {
206 wine_rb_stack_push(&tree->stack, entry);
207 e->flags |= WINE_RB_FLAG_TRAVERSED_RIGHT;
208 entry = &e->right;
209 continue;
210 }
211
212 e->flags &= ~(WINE_RB_FLAG_TRAVERSED_LEFT | WINE_RB_FLAG_TRAVERSED_RIGHT);
213 callback(e, context);
214
215 if (!tree->stack.count) break;
216 entry = tree->stack.entries[--tree->stack.count];
217 }
218}
219
220static inline int wine_rb_init(struct wine_rb_tree *tree, const struct wine_rb_functions *functions)
221{
222 tree->functions = functions;
223 tree->root = NULL;
224
225 tree->stack.entries = functions->alloc(16 * sizeof(*tree->stack.entries));
226 if (!tree->stack.entries) return -1;
227 tree->stack.size = 16;
228 tree->stack.count = 0;
229
230 return 0;
231}
232
233static inline void wine_rb_for_each_entry(struct wine_rb_tree *tree, wine_rb_traverse_func_t *callback, void *context)
234{
235 wine_rb_postorder(tree, callback, context);
236}
237
238static inline void wine_rb_destroy(struct wine_rb_tree *tree, wine_rb_traverse_func_t *callback, void *context)
239{
240 /* Note that we use postorder here because the callback will likely free the entry. */
241 if (callback) wine_rb_postorder(tree, callback, context);
242
243 tree->root = NULL;
244 tree->functions->free(tree->stack.entries);
245}
246
247static inline struct wine_rb_entry *wine_rb_get(const struct wine_rb_tree *tree, const void *key)
248{
249 struct wine_rb_entry *entry = tree->root;
250 while (entry)
251 {
252 int c = tree->functions->compare(key, entry);
253 if (!c) return entry;
254 entry = c < 0 ? entry->left : entry->right;
255 }
256 return NULL;
257}
258
259static inline int wine_rb_put(struct wine_rb_tree *tree, const void *key, struct wine_rb_entry *entry)
260{
261 struct wine_rb_entry **parent = &tree->root;
262 size_t black_height = 1;
263
264 while (*parent)
265 {
266 int c;
267
268 if (!wine_rb_is_red(*parent)) ++black_height;
269
270 wine_rb_stack_push(&tree->stack, parent);
271
272 c = tree->functions->compare(key, *parent);
273 if (!c)
274 {
275 wine_rb_stack_clear(&tree->stack);
276 return -1;
277 }
278 else if (c < 0) parent = &(*parent)->left;
279 else parent = &(*parent)->right;
280 }
281
282 /* After insertion, the path length to any node should be <= (black_height + 1) * 2. */
283 if (wine_rb_ensure_stack_size(tree, black_height << 1) == -1)
284 {
285 wine_rb_stack_clear(&tree->stack);
286 return -1;
287 }
288
289 entry->flags = WINE_RB_FLAG_RED;
290 entry->left = NULL;
291 entry->right = NULL;
292 *parent = entry;
293
294 wine_rb_fixup(&tree->stack);
295 tree->root->flags &= ~WINE_RB_FLAG_RED;
296
297 return 0;
298}
299
300static inline void wine_rb_remove(struct wine_rb_tree *tree, const void *key)
301{
302 struct wine_rb_entry **entry = &tree->root;
303
304 while (*entry)
305 {
306 if (tree->functions->compare(key, *entry) < 0)
307 {
308 wine_rb_stack_push(&tree->stack, entry);
309 if (!wine_rb_is_red((*entry)->left) && !wine_rb_is_red((*entry)->left->left)) wine_rb_move_red_left(entry);
310 entry = &(*entry)->left;
311 }
312 else
313 {
314 if (wine_rb_is_red((*entry)->left)) wine_rb_rotate_right(entry);
315 if (!tree->functions->compare(key, *entry) && !(*entry)->right)
316 {
317 *entry = NULL;
318 break;
319 }
320 if (!wine_rb_is_red((*entry)->right) && !wine_rb_is_red((*entry)->right->left))
321 wine_rb_move_red_right(entry);
322 if (!tree->functions->compare(key, *entry))
323 {
324 struct wine_rb_entry **e = &(*entry)->right;
325 struct wine_rb_entry *m = *e;
326 while (m->left) m = m->left;
327
328 wine_rb_stack_push(&tree->stack, entry);
329 (*entry)->flags |= WINE_RB_FLAG_STOP;
330
331 while ((*e)->left)
332 {
333 wine_rb_stack_push(&tree->stack, e);
334 if (!wine_rb_is_red((*e)->left) && !wine_rb_is_red((*e)->left->left)) wine_rb_move_red_left(e);
335 e = &(*e)->left;
336 }
337 *e = NULL;
338 wine_rb_fixup(&tree->stack);
339
340 *m = **entry;
341 *entry = m;
342
343 break;
344 }
345 else
346 {
347 wine_rb_stack_push(&tree->stack, entry);
348 entry = &(*entry)->right;
349 }
350 }
351 }
352
353 wine_rb_fixup(&tree->stack);
354 if (tree->root) tree->root->flags &= ~WINE_RB_FLAG_RED;
355}
356
357#endif /* __WINE_WINE_RBTREE_H */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette