From d653c5581f6470a9db8e45052f7afebf61dd9373 Mon Sep 17 00:00:00 2001
From: Andrew Riedi <andrewriedi@gmail.com>
Date: Thu, 5 Feb 2009 21:15:42 -0800
Subject: [PATCH] include: Add red-black search tree support.

Based on a patch by Henri Verbeet.
---
 include/wine/rbtree.h |  307 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 307 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..4a88519
--- /dev/null
+++ b/include/wine/rbtree.h
@@ -0,0 +1,307 @@
+/*
+ * Red-black search tree support
+ *
+ * Copyright (C) 2009 Henri Verbeet
+ * Copyright (C) 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
+
+#include <stdarg.h>
+
+#include <windef.h>
+#include <winnt.h>
+#include <winbase.h>
+
+#include "wine/debug.h"
+
+WINE_DECLARE_DEBUG_CHANNEL(rbtree);
+
+#define RB_ENTRY_VALUE(element, type, field) \
+    ((type *)((char *)(element) - FIELD_OFFSET(type, field)))
+
+struct rb_entry
+{
+    BOOL red;
+    struct rb_entry *left;
+    struct rb_entry *right;
+};
+
+struct rb_stack
+{
+    struct rb_entry ***entries;
+    size_t count;
+    size_t size;
+};
+
+typedef int (rb_compare_func_t)(const void *key, const struct rb_entry *entry);
+
+struct rb_tree
+{
+    rb_compare_func_t *compare;
+    struct rb_entry *root;
+    struct rb_stack stack;
+};
+
+static inline BOOL wine_rb_is_red(struct rb_entry *entry)
+{
+    return entry && entry->red;
+}
+
+static inline void wine_rb_stack_clear(struct rb_stack *stack)
+{
+    stack->count = 0;
+}
+
+static inline void wine_rb_rotate_left(struct rb_entry **entry)
+{
+    struct rb_entry *e = *entry;
+    struct rb_entry *right = e->right;
+
+    e->right = right->left;
+    right->left = e;
+    right->red = e->red;
+    e->red = TRUE;
+    *entry = right;
+}
+
+static inline void wine_rb_rotate_right(struct rb_entry **entry)
+{
+    struct rb_entry *e = *entry;
+    struct rb_entry *left = e->left;
+
+    e->left = left->right;
+    left->right = e;
+    left->red = e->red;
+    e->red = TRUE;
+    *entry = left;
+}
+
+static inline void wine_rb_flip_color(struct rb_entry *entry)
+{
+    entry->red = !entry->red;
+    entry->left->red = !entry->left->red;
+    entry->right->red = !entry->right->red;
+}
+
+static inline void wine_rb_fixup(struct rb_stack *stack)
+{
+    while(stack->count)
+    {
+        struct rb_entry **entry = stack->entries[--stack->count];
+
+        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);
+    }
+}
+
+static inline void wine_rb_move_red_left(struct 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 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_stack_push(struct rb_tree *tree,
+    struct rb_entry **entry)
+{
+    struct rb_stack *stack = &tree->stack;
+
+    if (stack->count == stack->size)
+    {
+        size_t new_size = stack->size << 1;
+        struct rb_entry ***new_entries = HeapReAlloc(GetProcessHeap(), 0,
+            stack->entries, new_size * sizeof(*stack->entries));
+
+        if (!new_entries)
+        {
+            ERR_(rbtree)("Failed to allocate memory.\n");
+            return;
+        }
+
+        stack->entries = new_entries;
+        stack->size = new_size;
+    }
+
+    stack->entries[stack->count++] = entry;
+}
+
+static inline void wine_rb_delete_min(struct rb_entry **entry)
+{
+    if (!(*entry)->left)
+    {
+        *entry = NULL;
+        return;
+    }
+
+    if (!wine_rb_is_red((*entry)->left) && !wine_rb_is_red((*entry)->left->left)) wine_rb_move_red_left(entry);
+    wine_rb_delete_min(&(*entry)->left);
+
+    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);
+}
+
+static inline void wine_rb_init(struct rb_tree *tree,
+    rb_compare_func_t *compare)
+{
+    tree->compare = compare;
+    tree->root = NULL;
+    tree->stack.entries = HeapAlloc(GetProcessHeap(), 0,
+        16 * sizeof(*tree->stack.entries));
+    if (!tree->stack.entries)
+    {
+        ERR_(rbtree)("Failed to allocate stack memory.\n");
+    }
+    tree->stack.size = 16;
+    tree->stack.count = 0;
+}
+
+static inline void wine_rb_inorder(struct rb_entry *entry, void (*callback)(struct rb_entry *entry, void *context), void *context)
+{
+    if (entry->left)
+        wine_rb_inorder(entry->left, callback, context);
+    callback(entry, context);
+    if (entry->right)
+        wine_rb_inorder(entry->right, callback, context);
+}
+
+static inline void wine_rb_for_each_entry(struct rb_tree *tree,
+    void (*callback)(struct rb_entry *entry, void *context), void *context)
+{
+    wine_rb_inorder(tree->root, callback, context);
+}
+
+static inline void wine_rb_destroy(struct rb_tree *tree,
+    void (*callback)(struct rb_entry *entry, void *context), void *context)
+{
+    if (callback) wine_rb_for_each_entry(tree, callback, context);
+    tree->root = NULL;
+    HeapFree(GetProcessHeap(), 0, tree->stack.entries);
+}
+
+static inline struct rb_entry *wine_rb_get(const struct rb_tree *tree,
+    const void *key)
+{
+    struct 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 void wine_rb_put(struct rb_tree *tree, const void *key,
+    struct rb_entry *entry)
+{
+    struct rb_entry **parent = &tree->root;
+
+    while(*parent)
+    {
+        int c;
+
+        wine_rb_stack_push(tree, parent);
+        c = tree->compare(key, *parent);
+        if (!c)
+        {
+            wine_rb_stack_clear(&tree->stack);
+            ERR_(rbtree)("Trying to replace an existing entry.\n");
+            return;
+        }
+        else if (c < 0)
+            parent = &(*parent)->left;
+        else
+            parent = &(*parent)->right;
+    }
+
+    entry->red = TRUE;
+    entry->left = NULL;
+    entry->right = NULL;
+    *parent = entry;
+
+    wine_rb_fixup(&tree->stack);
+    tree->root->red = FALSE;
+}
+
+static inline void wine_rb_remove(struct rb_tree *tree, const void *key)
+{
+    struct rb_entry **entry = &tree->root;
+
+    while (*entry)
+    {
+        if (tree->compare(key, *entry) < 0)
+        {
+            if (!wine_rb_is_red((*entry)->left) && !wine_rb_is_red((*entry)->left->left)) wine_rb_move_red_left(entry);
+            wine_rb_stack_push(tree, entry);
+            entry = &(*entry)->left;
+        }
+        else
+        {
+            if (wine_rb_is_red((*entry)->left)) wine_rb_rotate_right(entry);
+            if (!tree->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->compare(key, *entry))
+            {
+                struct rb_entry *m = (*entry)->right;
+                while (m->left) m = m->left;
+
+                wine_rb_stack_push(tree, entry);
+
+                wine_rb_delete_min(&(*entry)->right);
+                *m = **entry;
+                *entry = m;
+
+                break;
+            }
+            else
+            {
+                wine_rb_stack_push(tree, entry);
+                entry = &(*entry)->right;
+            }
+        }
+    }
+
+    wine_rb_fixup(&tree->stack);
+    if (tree->root)
+        tree->root->red = FALSE;
+}
+
+#endif  /* __WINE_WINE_RBTREE_H */
-- 
1.5.6.3

