user32/tests: On Win 8 and later, moving a window off-screen doesn't crop its update...
[wine.git] / include / wine / rbtree.h
blobbdf1a85a7f11fb9fada08e4e8d1a75f80af50c21
1 /*
2 * Red-black search tree support
4 * Copyright 2009 Henri Verbeet
5 * Copyright 2009 Andrew Riedi
6 * Copyright 2016 Jacek Caban for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #ifndef __WINE_WINE_RBTREE_H
24 #define __WINE_WINE_RBTREE_H
26 #define WINE_RB_ENTRY_VALUE(element, type, field) \
27 ((type *)((char *)(element) - offsetof(type, field)))
29 struct wine_rb_entry
31 struct wine_rb_entry *parent;
32 struct wine_rb_entry *left;
33 struct wine_rb_entry *right;
34 unsigned int flags;
37 typedef int (*wine_rb_compare_func_t)(const void *key, const struct wine_rb_entry *entry);
39 struct wine_rb_tree
41 wine_rb_compare_func_t compare;
42 struct wine_rb_entry *root;
45 typedef void (wine_rb_traverse_func_t)(struct wine_rb_entry *entry, void *context);
47 #define WINE_RB_FLAG_RED 0x1
49 static inline int wine_rb_is_red(struct wine_rb_entry *entry)
51 return entry && (entry->flags & WINE_RB_FLAG_RED);
54 static inline void wine_rb_rotate_left(struct wine_rb_tree *tree, struct wine_rb_entry *e)
56 struct wine_rb_entry *right = e->right;
58 if (!e->parent)
59 tree->root = right;
60 else if (e->parent->left == e)
61 e->parent->left = right;
62 else
63 e->parent->right = right;
65 e->right = right->left;
66 if (e->right) e->right->parent = e;
67 right->left = e;
68 right->parent = e->parent;
69 e->parent = right;
72 static inline void wine_rb_rotate_right(struct wine_rb_tree *tree, struct wine_rb_entry *e)
74 struct wine_rb_entry *left = e->left;
76 if (!e->parent)
77 tree->root = left;
78 else if (e->parent->left == e)
79 e->parent->left = left;
80 else
81 e->parent->right = left;
83 e->left = left->right;
84 if (e->left) e->left->parent = e;
85 left->right = e;
86 left->parent = e->parent;
87 e->parent = left;
90 static inline void wine_rb_flip_color(struct wine_rb_entry *entry)
92 entry->flags ^= WINE_RB_FLAG_RED;
93 entry->left->flags ^= WINE_RB_FLAG_RED;
94 entry->right->flags ^= WINE_RB_FLAG_RED;
97 static inline struct wine_rb_entry *wine_rb_postorder_head(struct wine_rb_entry *iter)
99 if (!iter) return NULL;
101 for (;;) {
102 while (iter->left) iter = iter->left;
103 if (!iter->right) return iter;
104 iter = iter->right;
108 static inline struct wine_rb_entry *wine_rb_postorder_next(struct wine_rb_entry *iter)
110 if (!iter->parent) return NULL;
111 if (iter == iter->parent->right || !iter->parent->right) return iter->parent;
112 return wine_rb_postorder_head(iter->parent->right);
115 static inline void wine_rb_postorder(struct wine_rb_tree *tree, wine_rb_traverse_func_t *callback, void *context)
117 struct wine_rb_entry *iter, *next;
119 for (iter = wine_rb_postorder_head(tree->root); iter; iter = next)
121 next = wine_rb_postorder_next(iter);
122 callback(iter, context);
126 static inline void wine_rb_init(struct wine_rb_tree *tree, wine_rb_compare_func_t compare)
128 tree->compare = compare;
129 tree->root = NULL;
132 static inline void wine_rb_for_each_entry(struct wine_rb_tree *tree, wine_rb_traverse_func_t *callback, void *context)
134 wine_rb_postorder(tree, callback, context);
137 static inline void wine_rb_clear(struct wine_rb_tree *tree, wine_rb_traverse_func_t *callback, void *context)
139 /* Note that we use postorder here because the callback will likely free the entry. */
140 if (callback) wine_rb_postorder(tree, callback, context);
141 tree->root = NULL;
144 static inline void wine_rb_destroy(struct wine_rb_tree *tree, wine_rb_traverse_func_t *callback, void *context)
146 wine_rb_clear(tree, callback, context);
149 static inline struct wine_rb_entry *wine_rb_get(const struct wine_rb_tree *tree, const void *key)
151 struct wine_rb_entry *entry = tree->root;
152 while (entry)
154 int c = tree->compare(key, entry);
155 if (!c) return entry;
156 entry = c < 0 ? entry->left : entry->right;
158 return NULL;
161 static inline int wine_rb_put(struct wine_rb_tree *tree, const void *key, struct wine_rb_entry *entry)
163 struct wine_rb_entry **iter = &tree->root, *parent = tree->root;
165 while (*iter)
167 int c;
169 parent = *iter;
170 c = tree->compare(key, parent);
171 if (!c) return -1;
172 else if (c < 0) iter = &parent->left;
173 else iter = &parent->right;
176 entry->flags = WINE_RB_FLAG_RED;
177 entry->parent = parent;
178 entry->left = NULL;
179 entry->right = NULL;
180 *iter = entry;
182 while (wine_rb_is_red(entry->parent))
184 if (entry->parent == entry->parent->parent->left)
186 if (wine_rb_is_red(entry->parent->parent->right))
188 wine_rb_flip_color(entry->parent->parent);
189 entry = entry->parent->parent;
191 else
193 if (entry == entry->parent->right)
195 entry = entry->parent;
196 wine_rb_rotate_left(tree, entry);
198 entry->parent->flags &= ~WINE_RB_FLAG_RED;
199 entry->parent->parent->flags |= WINE_RB_FLAG_RED;
200 wine_rb_rotate_right(tree, entry->parent->parent);
203 else
205 if (wine_rb_is_red(entry->parent->parent->left))
207 wine_rb_flip_color(entry->parent->parent);
208 entry = entry->parent->parent;
210 else
212 if (entry == entry->parent->left)
214 entry = entry->parent;
215 wine_rb_rotate_right(tree, entry);
217 entry->parent->flags &= ~WINE_RB_FLAG_RED;
218 entry->parent->parent->flags |= WINE_RB_FLAG_RED;
219 wine_rb_rotate_left(tree, entry->parent->parent);
224 tree->root->flags &= ~WINE_RB_FLAG_RED;
226 return 0;
229 static inline void wine_rb_remove(struct wine_rb_tree *tree, const void *key)
231 struct wine_rb_entry *entry, *iter, *child, *parent, *w;
232 int need_fixup;
234 if (!(entry = wine_rb_get(tree, key))) return;
236 if (entry->right && entry->left)
237 for(iter = entry->right; iter->left; iter = iter->left);
238 else
239 iter = entry;
241 child = iter->left ? iter->left : iter->right;
243 if (!iter->parent)
244 tree->root = child;
245 else if (iter == iter->parent->left)
246 iter->parent->left = child;
247 else
248 iter->parent->right = child;
250 if (child) child->parent = iter->parent;
251 parent = iter->parent;
253 need_fixup = !wine_rb_is_red(iter);
255 if (entry != iter)
257 *iter = *entry;
258 if (!iter->parent)
259 tree->root = iter;
260 else if (entry == iter->parent->left)
261 iter->parent->left = iter;
262 else
263 iter->parent->right = iter;
265 if (iter->right) iter->right->parent = iter;
266 if (iter->left) iter->left->parent = iter;
267 if (parent == entry) parent = iter;
270 if (need_fixup)
272 while (parent && !wine_rb_is_red(child))
274 if (child == parent->left)
276 w = parent->right;
277 if (wine_rb_is_red(w))
279 w->flags &= ~WINE_RB_FLAG_RED;
280 parent->flags |= WINE_RB_FLAG_RED;
281 wine_rb_rotate_left(tree, parent);
282 w = parent->right;
284 if (wine_rb_is_red(w->left) || wine_rb_is_red(w->right))
286 if (!wine_rb_is_red(w->right))
288 w->left->flags &= ~WINE_RB_FLAG_RED;
289 w->flags |= WINE_RB_FLAG_RED;
290 wine_rb_rotate_right(tree, w);
291 w = parent->right;
293 w->flags = (w->flags & ~WINE_RB_FLAG_RED) | (parent->flags & WINE_RB_FLAG_RED);
294 parent->flags &= ~WINE_RB_FLAG_RED;
295 if (w->right)
296 w->right->flags &= ~WINE_RB_FLAG_RED;
297 wine_rb_rotate_left(tree, parent);
298 child = NULL;
299 break;
302 else
304 w = parent->left;
305 if (wine_rb_is_red(w))
307 w->flags &= ~WINE_RB_FLAG_RED;
308 parent->flags |= WINE_RB_FLAG_RED;
309 wine_rb_rotate_right(tree, parent);
310 w = parent->left;
312 if (wine_rb_is_red(w->left) || wine_rb_is_red(w->right))
314 if (!wine_rb_is_red(w->left))
316 w->right->flags &= ~WINE_RB_FLAG_RED;
317 w->flags |= WINE_RB_FLAG_RED;
318 wine_rb_rotate_left(tree, w);
319 w = parent->left;
321 w->flags = (w->flags & ~WINE_RB_FLAG_RED) | (parent->flags & WINE_RB_FLAG_RED);
322 parent->flags &= ~WINE_RB_FLAG_RED;
323 if (w->left)
324 w->left->flags &= ~WINE_RB_FLAG_RED;
325 wine_rb_rotate_right(tree, parent);
326 child = NULL;
327 break;
330 w->flags |= WINE_RB_FLAG_RED;
331 child = parent;
332 parent = child->parent;
334 if (child) child->flags &= ~WINE_RB_FLAG_RED;
337 if (tree->root) tree->root->flags &= ~WINE_RB_FLAG_RED;
340 #endif /* __WINE_WINE_RBTREE_H */