include: Add a generic red-black tree.

Henri Verbeet hverbeet at codeweavers.com
Wed Jun 3 03:47:26 CDT 2009


---
 include/wine/rbtree.h |  342 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 342 insertions(+), 0 deletions(-)
 create mode 100644 include/wine/rbtree.h

diff --git a/include/wine/rbtree.h b/include/wine/rbtree.h
new file mode 100644
index 0000000..de29d10
--- /dev/null
+++ b/include/wine/rbtree.h
@@ -0,0 +1,342 @@
+/*
+ * Red-black search tree support
+ *
+ * Copyright 2009 Henri Verbeet
+ * Copyright 2009 Andrew Riedi
+ *
+ * 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) - FIELD_OFFSET(type, field)))
+
+struct wine_rb_entry
+{
+    struct wine_rb_entry *left;
+    struct wine_rb_entry *right;
+    unsigned int flags;
+};
+
+struct wine_rb_stack
+{
+    struct wine_rb_entry ***entries;
+    size_t count;
+    size_t size;
+};
+
+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
+{
+    const struct wine_rb_functions *functions;
+    struct wine_rb_entry *root;
+    struct wine_rb_stack stack;
+};
+
+typedef void (wine_rb_traverse_func_t)(struct wine_rb_entry *entry, void *context);
+
+#define WINE_RB_FLAG_RED                0x1
+#define WINE_RB_FLAG_STOP               0x2
+#define WINE_RB_FLAG_TRAVERSED_LEFT     0x4
+#define WINE_RB_FLAG_TRAVERSED_RIGHT    0x8
+
+static inline void wine_rb_stack_clear(struct wine_rb_stack *stack)
+{
+    stack->count = 0;
+}
+
+static inline void wine_rb_stack_push(struct wine_rb_stack *stack, struct wine_rb_entry **entry)
+{
+    stack->entries[stack->count++] = entry;
+}
+
+static inline int wine_rb_ensure_stack_size(struct wine_rb_tree *tree, size_t size)
+{
+    struct wine_rb_stack *stack = &tree->stack;
+
+    if (size > stack->size)
+    {
+        size_t new_size = stack->size << 1;
+        struct wine_rb_entry ***new_entries = tree->functions->realloc(stack->entries,
+                new_size * sizeof(*stack->entries));
+
+        if (!new_entries) return -1;
+
+        stack->entries = new_entries;
+        stack->size = new_size;
+    }
+
+    return 0;
+}
+
+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_entry **entry)
+{
+    struct wine_rb_entry *e = *entry;
+    struct wine_rb_entry *right = e->right;
+
+    e->right = right->left;
+    right->left = e;
+    right->flags &= ~WINE_RB_FLAG_RED;
+    right->flags |= e->flags & WINE_RB_FLAG_RED;
+    e->flags |= WINE_RB_FLAG_RED;
+    *entry = right;
+}
+
+static inline void wine_rb_rotate_right(struct wine_rb_entry **entry)
+{
+    struct wine_rb_entry *e = *entry;
+    struct wine_rb_entry *left = e->left;
+
+    e->left = left->right;
+    left->right = e;
+    left->flags &= ~WINE_RB_FLAG_RED;
+    left->flags |= e->flags & WINE_RB_FLAG_RED;
+    e->flags |= WINE_RB_FLAG_RED;
+    *entry = 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 void wine_rb_fixup(struct wine_rb_stack *stack)
+{
+    while (stack->count)
+    {
+        struct wine_rb_entry **entry = stack->entries[stack->count - 1];
+
+        if ((*entry)->flags & WINE_RB_FLAG_STOP)
+        {
+            (*entry)->flags &= ~WINE_RB_FLAG_STOP;
+            return;
+        }
+
+        if (wine_rb_is_red((*entry)->right) && !wine_rb_is_red((*entry)->left)) wine_rb_rotate_left(entry);
+        if (wine_rb_is_red((*entry)->left) && wine_rb_is_red((*entry)->left->left)) wine_rb_rotate_right(entry);
+        if (wine_rb_is_red((*entry)->left) && wine_rb_is_red((*entry)->right)) wine_rb_flip_color(*entry);
+        --stack->count;
+    }
+}
+
+static inline void wine_rb_move_red_left(struct wine_rb_entry **entry)
+{
+    wine_rb_flip_color(*entry);
+    if (wine_rb_is_red((*entry)->right->left))
+    {
+        wine_rb_rotate_right(&(*entry)->right);
+        wine_rb_rotate_left(entry);
+        wine_rb_flip_color(*entry);
+    }
+}
+
+static inline void wine_rb_move_red_right(struct wine_rb_entry **entry)
+{
+    wine_rb_flip_color(*entry);
+    if (wine_rb_is_red((*entry)->left->left))
+    {
+        wine_rb_rotate_right(entry);
+        wine_rb_flip_color(*entry);
+    }
+}
+
+static inline void wine_rb_postorder(struct wine_rb_tree *tree, wine_rb_traverse_func_t *callback, void *context)
+{
+    struct wine_rb_entry **entry;
+
+    if (!tree->root) return;
+
+    for (entry = &tree->root;;)
+    {
+        struct wine_rb_entry *e = *entry;
+
+        if (e->left && !(e->flags & WINE_RB_FLAG_TRAVERSED_LEFT))
+        {
+            wine_rb_stack_push(&tree->stack, entry);
+            e->flags |= WINE_RB_FLAG_TRAVERSED_LEFT;
+            entry = &e->left;
+            continue;
+        }
+
+        if (e->right && !(e->flags & WINE_RB_FLAG_TRAVERSED_RIGHT))
+        {
+            wine_rb_stack_push(&tree->stack, entry);
+            e->flags |= WINE_RB_FLAG_TRAVERSED_RIGHT;
+            entry = &e->right;
+            continue;
+        }
+
+        e->flags &= ~(WINE_RB_FLAG_TRAVERSED_LEFT | WINE_RB_FLAG_TRAVERSED_RIGHT);
+        callback(e, context);
+
+        if (!tree->stack.count) break;
+        entry = tree->stack.entries[--tree->stack.count];
+    }
+}
+
+static inline int wine_rb_init(struct wine_rb_tree *tree, const struct wine_rb_functions *functions)
+{
+    tree->functions = functions;
+    tree->root = NULL;
+
+    tree->stack.entries = functions->alloc(16 * sizeof(*tree->stack.entries));
+    if (!tree->stack.entries) return -1;
+    tree->stack.size = 16;
+    tree->stack.count = 0;
+
+    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_destroy(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;
+    tree->functions->free(tree->stack.entries);
+}
+
+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->functions->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 **parent = &tree->root;
+    size_t black_height = 1;
+
+    while (*parent)
+    {
+        int c;
+
+        if (!wine_rb_is_red(*parent)) ++black_height;
+
+        wine_rb_stack_push(&tree->stack, parent);
+
+        c = tree->functions->compare(key, *parent);
+        if (!c)
+        {
+            wine_rb_stack_clear(&tree->stack);
+            return -1;
+        }
+        else if (c < 0) parent = &(*parent)->left;
+        else parent = &(*parent)->right;
+    }
+
+    /* After insertion, the path length to any node should be <= (black_height + 1) * 2. */
+    if (wine_rb_ensure_stack_size(tree, black_height << 1) == -1)
+    {
+        wine_rb_stack_clear(&tree->stack);
+        return -1;
+    }
+
+    entry->flags = WINE_RB_FLAG_RED;
+    entry->left = NULL;
+    entry->right = NULL;
+    *parent = entry;
+
+    wine_rb_fixup(&tree->stack);
+    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 = &tree->root;
+
+    while (*entry)
+    {
+        if (tree->functions->compare(key, *entry) < 0)
+        {
+            wine_rb_stack_push(&tree->stack, entry);
+            if (!wine_rb_is_red((*entry)->left) && !wine_rb_is_red((*entry)->left->left)) wine_rb_move_red_left(entry);
+            entry = &(*entry)->left;
+        }
+        else
+        {
+            if (wine_rb_is_red((*entry)->left)) wine_rb_rotate_right(entry);
+            if (!tree->functions->compare(key, *entry) && !(*entry)->right)
+            {
+                *entry = NULL;
+                break;
+            }
+            if (!wine_rb_is_red((*entry)->right) && !wine_rb_is_red((*entry)->right->left))
+                wine_rb_move_red_right(entry);
+            if (!tree->functions->compare(key, *entry))
+            {
+                struct wine_rb_entry **e = &(*entry)->right;
+                struct wine_rb_entry *m = *e;
+                while (m->left) m = m->left;
+
+                wine_rb_stack_push(&tree->stack, entry);
+                (*entry)->flags |= WINE_RB_FLAG_STOP;
+
+                while ((*e)->left)
+                {
+                    wine_rb_stack_push(&tree->stack, e);
+                    if (!wine_rb_is_red((*e)->left) && !wine_rb_is_red((*e)->left->left)) wine_rb_move_red_left(e);
+                    e = &(*e)->left;
+                }
+                *e = NULL;
+                wine_rb_fixup(&tree->stack);
+
+                *m = **entry;
+                *entry = m;
+
+                break;
+            }
+            else
+            {
+                wine_rb_stack_push(&tree->stack, entry);
+                entry = &(*entry)->right;
+            }
+        }
+    }
+
+    wine_rb_fixup(&tree->stack);
+    if (tree->root) tree->root->flags &= ~WINE_RB_FLAG_RED;
+}
+
+#endif  /* __WINE_WINE_RBTREE_H */
-- 
1.6.0.6



--------------000702030508090807020006--



More information about the wine-patches mailing list