349 lines
10 KiB
C
349 lines
10 KiB
C
/*
|
|
* Red-black search tree support
|
|
*
|
|
* Copyright 2009 Henri Verbeet
|
|
* Copyright 2009 Andrew Riedi
|
|
* Copyright 2016 Jacek Caban for CodeWeavers
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#ifndef __WINE_WINE_RBTREE_H
|
|
#define __WINE_WINE_RBTREE_H
|
|
|
|
#define WINE_RB_ENTRY_VALUE(element, type, field) \
|
|
((type *)((char *)(element) - offsetof(type, field)))
|
|
|
|
struct wine_rb_entry
|
|
{
|
|
struct wine_rb_entry *parent;
|
|
struct wine_rb_entry *left;
|
|
struct wine_rb_entry *right;
|
|
unsigned int flags;
|
|
};
|
|
|
|
struct wine_rb_functions
|
|
{
|
|
void *(*alloc)(size_t size);
|
|
void *(*realloc)(void *ptr, size_t size);
|
|
void (*free)(void *ptr);
|
|
int (*compare)(const void *key, const struct wine_rb_entry *entry);
|
|
};
|
|
|
|
struct wine_rb_tree
|
|
{
|
|
int (*compare)(const void *key, const struct wine_rb_entry *entry);
|
|
struct wine_rb_entry *root;
|
|
};
|
|
|
|
typedef void (wine_rb_traverse_func_t)(struct wine_rb_entry *entry, void *context);
|
|
|
|
#define WINE_RB_FLAG_RED 0x1
|
|
|
|
static inline int wine_rb_is_red(struct wine_rb_entry *entry)
|
|
{
|
|
return entry && (entry->flags & WINE_RB_FLAG_RED);
|
|
}
|
|
|
|
static inline void wine_rb_rotate_left(struct wine_rb_tree *tree, struct wine_rb_entry *e)
|
|
{
|
|
struct wine_rb_entry *right = e->right;
|
|
|
|
if (!e->parent)
|
|
tree->root = right;
|
|
else if (e->parent->left == e)
|
|
e->parent->left = right;
|
|
else
|
|
e->parent->right = right;
|
|
|
|
e->right = right->left;
|
|
if (e->right) e->right->parent = e;
|
|
right->left = e;
|
|
right->parent = e->parent;
|
|
e->parent = right;
|
|
}
|
|
|
|
static inline void wine_rb_rotate_right(struct wine_rb_tree *tree, struct wine_rb_entry *e)
|
|
{
|
|
struct wine_rb_entry *left = e->left;
|
|
|
|
if (!e->parent)
|
|
tree->root = left;
|
|
else if (e->parent->left == e)
|
|
e->parent->left = left;
|
|
else
|
|
e->parent->right = left;
|
|
|
|
e->left = left->right;
|
|
if (e->left) e->left->parent = e;
|
|
left->right = e;
|
|
left->parent = e->parent;
|
|
e->parent = left;
|
|
}
|
|
|
|
static inline void wine_rb_flip_color(struct wine_rb_entry *entry)
|
|
{
|
|
entry->flags ^= WINE_RB_FLAG_RED;
|
|
entry->left->flags ^= WINE_RB_FLAG_RED;
|
|
entry->right->flags ^= WINE_RB_FLAG_RED;
|
|
}
|
|
|
|
static inline struct wine_rb_entry *wine_rb_postorder_head(struct wine_rb_entry *iter)
|
|
{
|
|
if (!iter) return NULL;
|
|
|
|
for (;;) {
|
|
while (iter->left) iter = iter->left;
|
|
if (!iter->right) return iter;
|
|
iter = iter->right;
|
|
}
|
|
}
|
|
|
|
static inline struct wine_rb_entry *wine_rb_postorder_next(struct wine_rb_entry *iter)
|
|
{
|
|
if (!iter->parent) return NULL;
|
|
if (iter == iter->parent->right || !iter->parent->right) return iter->parent;
|
|
return wine_rb_postorder_head(iter->parent->right);
|
|
}
|
|
|
|
static inline void wine_rb_postorder(struct wine_rb_tree *tree, wine_rb_traverse_func_t *callback, void *context)
|
|
{
|
|
struct wine_rb_entry *iter, *next;
|
|
|
|
for (iter = wine_rb_postorder_head(tree->root); iter; iter = next)
|
|
{
|
|
next = wine_rb_postorder_next(iter);
|
|
callback(iter, context);
|
|
}
|
|
}
|
|
|
|
static inline int wine_rb_init(struct wine_rb_tree *tree, const struct wine_rb_functions *functions)
|
|
{
|
|
tree->compare = functions->compare;
|
|
tree->root = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline void wine_rb_for_each_entry(struct wine_rb_tree *tree, wine_rb_traverse_func_t *callback, void *context)
|
|
{
|
|
wine_rb_postorder(tree, callback, context);
|
|
}
|
|
|
|
static inline void wine_rb_clear(struct wine_rb_tree *tree, wine_rb_traverse_func_t *callback, void *context)
|
|
{
|
|
/* Note that we use postorder here because the callback will likely free the entry. */
|
|
if (callback) wine_rb_postorder(tree, callback, context);
|
|
tree->root = NULL;
|
|
}
|
|
|
|
static inline void wine_rb_destroy(struct wine_rb_tree *tree, wine_rb_traverse_func_t *callback, void *context)
|
|
{
|
|
wine_rb_clear(tree, callback, context);
|
|
}
|
|
|
|
static inline struct wine_rb_entry *wine_rb_get(const struct wine_rb_tree *tree, const void *key)
|
|
{
|
|
struct wine_rb_entry *entry = tree->root;
|
|
while (entry)
|
|
{
|
|
int c = tree->compare(key, entry);
|
|
if (!c) return entry;
|
|
entry = c < 0 ? entry->left : entry->right;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static inline int wine_rb_put(struct wine_rb_tree *tree, const void *key, struct wine_rb_entry *entry)
|
|
{
|
|
struct wine_rb_entry **iter = &tree->root, *parent = tree->root;
|
|
|
|
while (*iter)
|
|
{
|
|
int c;
|
|
|
|
parent = *iter;
|
|
c = tree->compare(key, parent);
|
|
if (!c) return -1;
|
|
else if (c < 0) iter = &parent->left;
|
|
else iter = &parent->right;
|
|
}
|
|
|
|
entry->flags = WINE_RB_FLAG_RED;
|
|
entry->parent = parent;
|
|
entry->left = NULL;
|
|
entry->right = NULL;
|
|
*iter = entry;
|
|
|
|
while (wine_rb_is_red(entry->parent))
|
|
{
|
|
if (entry->parent == entry->parent->parent->left)
|
|
{
|
|
if (wine_rb_is_red(entry->parent->parent->right))
|
|
{
|
|
wine_rb_flip_color(entry->parent->parent);
|
|
entry = entry->parent->parent;
|
|
}
|
|
else
|
|
{
|
|
if (entry == entry->parent->right)
|
|
{
|
|
entry = entry->parent;
|
|
wine_rb_rotate_left(tree, entry);
|
|
}
|
|
entry->parent->flags &= ~WINE_RB_FLAG_RED;
|
|
entry->parent->parent->flags |= WINE_RB_FLAG_RED;
|
|
wine_rb_rotate_right(tree, entry->parent->parent);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (wine_rb_is_red(entry->parent->parent->left))
|
|
{
|
|
wine_rb_flip_color(entry->parent->parent);
|
|
entry = entry->parent->parent;
|
|
}
|
|
else
|
|
{
|
|
if (entry == entry->parent->left)
|
|
{
|
|
entry = entry->parent;
|
|
wine_rb_rotate_right(tree, entry);
|
|
}
|
|
entry->parent->flags &= ~WINE_RB_FLAG_RED;
|
|
entry->parent->parent->flags |= WINE_RB_FLAG_RED;
|
|
wine_rb_rotate_left(tree, entry->parent->parent);
|
|
}
|
|
}
|
|
}
|
|
|
|
tree->root->flags &= ~WINE_RB_FLAG_RED;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline void wine_rb_remove(struct wine_rb_tree *tree, const void *key)
|
|
{
|
|
struct wine_rb_entry *entry, *iter, *child, *parent, *w;
|
|
int need_fixup;
|
|
|
|
if (!(entry = wine_rb_get(tree, key))) return;
|
|
|
|
if (entry->right && entry->left)
|
|
for(iter = entry->right; iter->left; iter = iter->left);
|
|
else
|
|
iter = entry;
|
|
|
|
child = iter->left ? iter->left : iter->right;
|
|
|
|
if (!iter->parent)
|
|
tree->root = child;
|
|
else if (iter == iter->parent->left)
|
|
iter->parent->left = child;
|
|
else
|
|
iter->parent->right = child;
|
|
|
|
if (child) child->parent = iter->parent;
|
|
parent = iter->parent;
|
|
|
|
need_fixup = !wine_rb_is_red(iter);
|
|
|
|
if (entry != iter)
|
|
{
|
|
*iter = *entry;
|
|
if (!iter->parent)
|
|
tree->root = iter;
|
|
else if (entry == iter->parent->left)
|
|
iter->parent->left = iter;
|
|
else
|
|
iter->parent->right = iter;
|
|
|
|
if (iter->right) iter->right->parent = iter;
|
|
if (iter->left) iter->left->parent = iter;
|
|
if (parent == entry) parent = iter;
|
|
}
|
|
|
|
if (need_fixup)
|
|
{
|
|
while (parent && !wine_rb_is_red(child))
|
|
{
|
|
if (child == parent->left)
|
|
{
|
|
w = parent->right;
|
|
if (wine_rb_is_red(w))
|
|
{
|
|
w->flags &= ~WINE_RB_FLAG_RED;
|
|
parent->flags |= WINE_RB_FLAG_RED;
|
|
wine_rb_rotate_left(tree, parent);
|
|
w = parent->right;
|
|
}
|
|
if (wine_rb_is_red(w->left) || wine_rb_is_red(w->right))
|
|
{
|
|
if (!wine_rb_is_red(w->right))
|
|
{
|
|
w->left->flags &= ~WINE_RB_FLAG_RED;
|
|
w->flags |= WINE_RB_FLAG_RED;
|
|
wine_rb_rotate_right(tree, w);
|
|
w = parent->right;
|
|
}
|
|
w->flags = (w->flags & ~WINE_RB_FLAG_RED) | (parent->flags & WINE_RB_FLAG_RED);
|
|
parent->flags &= ~WINE_RB_FLAG_RED;
|
|
if (w->right)
|
|
w->right->flags &= ~WINE_RB_FLAG_RED;
|
|
wine_rb_rotate_left(tree, parent);
|
|
child = NULL;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
w = parent->left;
|
|
if (wine_rb_is_red(w))
|
|
{
|
|
w->flags &= ~WINE_RB_FLAG_RED;
|
|
parent->flags |= WINE_RB_FLAG_RED;
|
|
wine_rb_rotate_right(tree, parent);
|
|
w = parent->left;
|
|
}
|
|
if (wine_rb_is_red(w->left) || wine_rb_is_red(w->right))
|
|
{
|
|
if (!wine_rb_is_red(w->left))
|
|
{
|
|
w->right->flags &= ~WINE_RB_FLAG_RED;
|
|
w->flags |= WINE_RB_FLAG_RED;
|
|
wine_rb_rotate_left(tree, w);
|
|
w = parent->left;
|
|
}
|
|
w->flags = (w->flags & ~WINE_RB_FLAG_RED) | (parent->flags & WINE_RB_FLAG_RED);
|
|
parent->flags &= ~WINE_RB_FLAG_RED;
|
|
if (w->left)
|
|
w->left->flags &= ~WINE_RB_FLAG_RED;
|
|
wine_rb_rotate_right(tree, parent);
|
|
child = NULL;
|
|
break;
|
|
}
|
|
}
|
|
w->flags |= WINE_RB_FLAG_RED;
|
|
child = parent;
|
|
parent = child->parent;
|
|
}
|
|
if (child) child->flags &= ~WINE_RB_FLAG_RED;
|
|
}
|
|
|
|
if (tree->root) tree->root->flags &= ~WINE_RB_FLAG_RED;
|
|
}
|
|
|
|
#endif /* __WINE_WINE_RBTREE_H */
|