From 93d884bed637e95643e20be67df230daa4f1ed5a Mon Sep 17 00:00:00 2001
From: Henri Verbeet <hverbeet@codeweavers.com>
Date: Mon, 22 Aug 2016 18:26:15 +0200
Subject: [PATCH] rbtree: Get rid of the explicit stack.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
---
 include/wine/rbtree.h | 123 ++++++++++++++++----------------------------------
 1 file changed, 38 insertions(+), 85 deletions(-)

diff --git a/include/wine/rbtree.h b/include/wine/rbtree.h
index 13452d9..ac49773 100644
--- a/include/wine/rbtree.h
+++ b/include/wine/rbtree.h
@@ -3,6 +3,7 @@
  *
  * Copyright 2009 Henri Verbeet
  * Copyright 2009 Andrew Riedi
+ * Copyright 2016 Henri Verbeet for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -29,16 +30,10 @@ struct wine_rb_entry
 {
     struct wine_rb_entry *left;
     struct wine_rb_entry *right;
+    struct wine_rb_entry **next;
     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);
@@ -51,7 +46,6 @@ 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);
@@ -61,35 +55,6 @@ typedef void (wine_rb_traverse_func_t)(struct wine_rb_entry *entry, void *contex
 #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);
@@ -128,22 +93,26 @@ static inline void wine_rb_flip_color(struct wine_rb_entry *entry)
     entry->right->flags ^= WINE_RB_FLAG_RED;
 }
 
-static inline void wine_rb_fixup(struct wine_rb_stack *stack)
+static inline void wine_rb_fixup(struct wine_rb_entry **root, struct wine_rb_entry **entry)
 {
-    while (stack->count)
-    {
-        struct wine_rb_entry **entry = stack->entries[stack->count - 1];
+    struct wine_rb_entry **next;
 
+    while (entry)
+    {
         if ((*entry)->flags & WINE_RB_FLAG_STOP)
         {
             (*entry)->flags &= ~WINE_RB_FLAG_STOP;
             return;
         }
 
+        next = (*entry)->next;
+
         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;
+
+        if (entry == root) return;
+        entry = next;
     }
 }
 
@@ -180,25 +149,25 @@ static inline void wine_rb_postorder(struct wine_rb_tree *tree, wine_rb_traverse
 
         if (e->left && !(e->flags & WINE_RB_FLAG_TRAVERSED_LEFT))
         {
-            wine_rb_stack_push(&tree->stack, entry);
             e->flags |= WINE_RB_FLAG_TRAVERSED_LEFT;
+            e->left->next = entry;
             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;
+            e->right->next = entry;
             entry = &e->right;
             continue;
         }
 
         e->flags &= ~(WINE_RB_FLAG_TRAVERSED_LEFT | WINE_RB_FLAG_TRAVERSED_RIGHT);
+        entry = e->next;
         callback(e, context);
 
-        if (!tree->stack.count) break;
-        entry = tree->stack.entries[--tree->stack.count];
+        if (e == tree->root) break;
     }
 }
 
@@ -207,11 +176,6 @@ static inline int wine_rb_init(struct wine_rb_tree *tree, const struct wine_rb_f
     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;
 }
 
@@ -230,7 +194,6 @@ static inline void wine_rb_clear(struct wine_rb_tree *tree, wine_rb_traverse_fun
 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);
-    tree->functions->free(tree->stack.entries);
 }
 
 static inline struct wine_rb_entry *wine_rb_get(const struct wine_rb_tree *tree, const void *key)
@@ -247,40 +210,24 @@ static inline struct wine_rb_entry *wine_rb_get(const struct wine_rb_tree *tree,
 
 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;
-    }
+    struct wine_rb_entry **node = &tree->root, **parent = node;
+    int c;
 
-    /* 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)
+    while (*node)
     {
-        wine_rb_stack_clear(&tree->stack);
-        return -1;
+        if (!(c = tree->functions->compare(key, *node))) return -1;
+        (*node)->next = parent;
+        parent = node;
+        if (c < 0) node = &(*node)->left;
+        else node = &(*node)->right;
     }
 
     entry->flags = WINE_RB_FLAG_RED;
     entry->left = NULL;
     entry->right = NULL;
-    *parent = entry;
+    *node = entry;
 
-    wine_rb_fixup(&tree->stack);
+    wine_rb_fixup(&tree->root, parent);
     tree->root->flags &= ~WINE_RB_FLAG_RED;
 
     return 0;
@@ -288,14 +235,15 @@ static inline int wine_rb_put(struct wine_rb_tree *tree, const void *key, struct
 
 static inline void wine_rb_remove(struct wine_rb_tree *tree, const void *key)
 {
-    struct wine_rb_entry **entry = &tree->root;
+    struct wine_rb_entry **root = &tree->root, **entry = root, **parent = NULL;
 
     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)->next = parent;
+            parent = entry;
             entry = &(*entry)->left;
         }
         else
@@ -314,17 +262,21 @@ static inline void wine_rb_remove(struct wine_rb_tree *tree, const void *key)
                 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;
+                (*entry)->next = parent;
+                parent = entry;
+                root = entry;
 
                 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)->next = parent;
+                    parent = e;
                     e = &(*e)->left;
                 }
                 *e = NULL;
-                wine_rb_fixup(&tree->stack);
+                wine_rb_fixup(root, parent);
+                parent = root;
 
                 *m = **entry;
                 *entry = m;
@@ -333,13 +285,14 @@ static inline void wine_rb_remove(struct wine_rb_tree *tree, const void *key)
             }
             else
             {
-                wine_rb_stack_push(&tree->stack, entry);
+                (*entry)->next = parent;
+                parent = entry;
                 entry = &(*entry)->right;
             }
         }
     }
 
-    wine_rb_fixup(&tree->stack);
+    wine_rb_fixup(&tree->root, parent);
     if (tree->root) tree->root->flags &= ~WINE_RB_FLAG_RED;
 }
 
-- 
2.1.4

