Author: raja
Date: 2007-04-30 10:40:27 -0400 (Mon, 30 Apr 2007)
New Revision: 76498

Modified:
   trunk/mcs/class/System/System.Collections.Generic/ChangeLog
   trunk/mcs/class/System/System.Collections.Generic/RBTree.cs
Log:
* RBTree.cs: Refactor to reduce generics code.


Modified: trunk/mcs/class/System/System.Collections.Generic/ChangeLog
===================================================================
--- trunk/mcs/class/System/System.Collections.Generic/ChangeLog 2007-04-30 
14:37:36 UTC (rev 76497)
+++ trunk/mcs/class/System/System.Collections.Generic/ChangeLog 2007-04-30 
14:40:27 UTC (rev 76498)
@@ -1,3 +1,7 @@
+2007-04-30  Raja R Harinath  <[EMAIL PROTECTED]>
+
+       * RBTree.cs: Refactor to reduce generics code.
+
 2007-04-30  Raja R Harinath  <[EMAIL PROTECTED]>
 
        * RBTree.cs: New red-black tree implementation for use with

Modified: trunk/mcs/class/System/System.Collections.Generic/RBTree.cs
===================================================================
--- trunk/mcs/class/System/System.Collections.Generic/RBTree.cs 2007-04-30 
14:37:36 UTC (rev 76497)
+++ trunk/mcs/class/System/System.Collections.Generic/RBTree.cs 2007-04-30 
14:40:27 UTC (rev 76498)
@@ -36,10 +36,13 @@
 
 namespace System.Collections.Generic
 {
-       internal class RBTree<T> {
-               public class Node {
+       internal class RBTreeCore {
+               public interface INodeComparer<T> {
+                       int Compare (T value, Node node);
+               }
+
+               public abstract class Node {
                        public Node left, right;
-                       public T value;
                        uint size_black;
 
                        const uint black_mask = 1;
@@ -64,12 +67,13 @@
                                return Size;
                        }
 
-                       public Node (T v)
+                       public Node ()
                        {
-                               value = v;
                                size_black = 2; // Size == 1, IsBlack = false
                        }
 
+                       public abstract void SwapValue (Node other);
+
 #if TEST
                        public int VerifyInvariants ()
                        {
@@ -100,19 +104,12 @@
                                return black_depth_l + (IsBlack ? 1 : 0);
                        }
 
-                       public void Dump (string indent)
-                       {
-                               Console.WriteLine ("{0}{1} {2}({3})", indent, 
value, IsBlack ? "*" : "", Size);
-                               if (left != null)
-                                       left.Dump (indent + "  /");
-                               if (right != null)
-                                       right.Dump (indent + "  \\");
-                       }
+                       public abstract void Dump (string indent);
 #endif
                }
 
                Node root;
-               IComparer<T> cmp;
+               object cmp;
                uint version;
 
 #if ONE_MEMBER_CACHE
@@ -124,15 +121,17 @@
                        if (cached_path == null)
                                return new List<Node> ();
 
-                       List<Node> retval = cached_path;
+                       List<Node> path = cached_path;
                        cached_path = null;
-                       retval.Clear ();
-                       return retval;
+                       return path;
                }
 
                static void release_path (List<Node> path)
                {
-                       cached_path = path;
+                       if (cached_path == null || cached_path.Capacity < 
path.Capacity) {
+                               path.Clear ();
+                               cached_path = path;
+                       }
                }
 #else
                static List<Node> alloc_path ()
@@ -145,20 +144,103 @@
                }
 #endif
 
-               public RBTree () : this (Comparer<T>.Default)
+               public RBTreeCore (object cmp)
                {
+                       // cmp is INodeComparer<T> for some T
+                       this.cmp = cmp;
                }
 
-               public RBTree (IComparer<T> cmp)
+               // returns the newly inserted node (or null if the value is 
already in the tree)
+               public Node Insert<T> (T key, Node new_node)
                {
-                       this.cmp = cmp;
+                       if (root == null) {
+                               root = new_node;
+                               root.IsBlack = true;
+                               ++version;
+                               return root;
+                       }
+
+                       List<Node> path = alloc_path ();
+                       int in_tree_cmp = find_key (key, path);
+                       Node retval = in_tree_cmp == 0 ? null : do_insert 
(in_tree_cmp, new_node, path);
+                       // no need for a try .. finally, this is only used to 
mitigate allocations
+                       release_path (path);
+                       return retval;
                }
 
-               int Find (T value, List<Node> path)
+               // returns the just-removed node (or null if the value wasn't 
in the tree)
+               public Node Remove<T> (T key)
                {
                        if (root == null)
-                               throw new SystemException ("Internal Error: no 
tree");
+                               return null;
 
+                       List<Node> path = alloc_path ();
+                       int in_tree_cmp = find_key (key, path);
+                       Node retval = in_tree_cmp == 0 ? do_remove (path) : 
null;
+                       // no need for a try .. finally, this is only used to 
mitigate allocations
+                       release_path (path);
+                       return retval;
+               }
+
+               public bool Contains<T> (T key)
+               {
+                       return root != null && find_key (key, null) == 0;
+               }
+
+               public int Count {
+                       get { return root == null ? 0 : (int) root.Size; }
+               }
+
+               public Node this [int index] {
+                       get {
+                               if (index < 0 || index >= Count)
+                                       throw new IndexOutOfRangeException 
("index");
+
+                               Node current = root;
+                               while (current.Size > 1) {
+                                       int left_size = current.left == null ? 
0 : (int) current.left.Size;
+                                       if (index == left_size)
+                                               return current;
+                                       if (index < left_size) {
+                                               current = current.left;
+                                       } else {
+                                               index -= left_size + 1;
+                                               current = current.right;
+                                       }
+                               }
+
+                               if (index != 0)
+                                       throw new SystemException ("Internal 
Error: index calculation");
+                               return current;
+                       }
+               }
+
+               public NodeEnumerator GetNodeEnumerator ()
+               {
+                       return new NodeEnumerator (this);
+               }
+
+#if TEST
+               public void VerifyInvariants ()
+               {
+                       if (root != null) {
+                               if (!root.IsBlack)
+                                       throw new SystemException ("Internal 
Error: root is not black");
+                               root.VerifyInvariants ();
+                       }
+               }
+
+               public void Dump ()
+               {
+                       if (root != null)
+                               root.Dump ("");
+               }
+#endif
+
+               // Pre-condition: root != null
+               int find_key<T> (T key, List<Node> path)
+               {
+                       INodeComparer<T> cmp = (INodeComparer<T>) this.cmp;
                        int c = 0;
                        Node sibling = null;
                        Node current = root;
@@ -167,7 +249,7 @@
                                path.Add (root);
 
                        while (current != null) {
-                               c = cmp.Compare (value, current.value);
+                               c = cmp.Compare (key, current);
                                if (c == 0)
                                        return c;
 
@@ -188,22 +270,10 @@
                        return c;
                }
 
-               public void Insert (T value)
+               Node do_insert (int in_tree_cmp, Node current, List<Node> path)
                {
-                       if (root == null) {
-                               root = new Node (value);
-                               root.IsBlack = true;
-                               ++version;
-                               return;
-                       }
-
-                       List<Node> path = alloc_path ();
-                       int in_tree_cmp = Find (value, path);
-                       if (in_tree_cmp == 0)
-                               throw new ArgumentException ("value already in 
the tree");
-
+                       path [path.Count - 1] = current;
                        Node parent = path [path.Count - 3];
-                       Node current = path [path.Count - 1] = new Node (value);
 
                        if (in_tree_cmp < 0)
                                parent.left = current;
@@ -213,45 +283,42 @@
                                ++ path [i].Size;
 
                        if (!parent.IsBlack)
-                               rebalance_insert (current, path);
+                               rebalance_insert (path);
 
-                       // no need for a try .. finally, this is only used to 
mitigate allocations/gc
-                       release_path (path);
-
                        if (!root.IsBlack)
                                throw new SystemException ("Internal error: 
root is not black");
+
                        ++version;
+                       return current;
                }
 
-               public Node Remove (T value)
+               Node do_remove (List<Node> path)
                {
-                       if (root == null)
-                               return null;
+                       int curpos = path.Count - 1;
 
-                       List<Node> path = alloc_path ();
-                       int in_tree_cmp = Find (value, path);
-                       if (in_tree_cmp != 0) {
-                               release_path (path);
-                               return null;
+                       Node n1 = path [curpos];
+                       Node n2 = null;
+                       Node n3 = null;
+
+                       if (n1.left != null) {
+                               n2 = right_most (n1.left, n1.right, path);
+                               n3 = n2.left == null ? null : right_most 
(n2.left, null, path);
+                       } else if (n1.right != null) {
+                               n2 = left_most (n1.right, n1.left, path);
+                               n3 = n2.right == null ? null : left_most 
(n2.right, null, path);
                        }
 
-                       int curpos = path.Count - 1;
+                       if (n2 != null) {
+                               n1.SwapValue (n2);
+                               if (n3 != null)
+                                       n2.SwapValue (n3);
+                       }
+
+                       curpos = path.Count - 1;
                        Node current = path [curpos];
-                       T old_value = current.value;
-                       bool changed = false;
-                       for (; current.Size != 1; current = path [curpos]) {
-                               Node next = current.left == null
-                                       ? left_most (current.right, null, path)
-                                       : right_most (current.left, 
current.right, path);
-                               current.value = next.value;
-                               changed = true;
-                               curpos = path.Count - 1;
-                               if (next != path [curpos])
-                                       throw new SystemException ("Internal 
error: path wrong");
 
-                       }
-                       if (changed)
-                               current.value = old_value;
+                       if (current.Size != 1)
+                               throw new SystemException ("Internal Error: 
red-black violation somewhere");
 
                        // remove it from our data structures
                        path [curpos] = null;
@@ -260,7 +327,7 @@
                        for (int i = 0; i < path.Count - 2; i += 2)
                                -- path [i].Size;
 
-                       if (current.IsBlack)
+                       if (curpos != 0 && current.IsBlack)
                                rebalance_delete (path);
 
                        // no need for a try .. finally, this is only used to 
mitigate allocations/gc
@@ -273,106 +340,39 @@
                        return current;
                }
 
-               public bool Contains (T value)
+               // Pre-condition: current is red
+               void rebalance_insert (List<Node> path)
                {
-                       return root != null && Find (value, null) == 0;
-               }
-
-               public int Count {
-                       get { return root == null ? 0 : (int) root.Size; }
-               }
-
-               public Node this [int index] {
-                       get {
-                               if (index < 0 || index >= Count)
-                                       throw new IndexOutOfRangeException 
("index");
-
-                               Node current = root;
-                               while (current.Size > 1) {
-                                       int left_size = current.left == null ? 
0 : (int) current.left.Size;
-                                       if (index == left_size)
-                                               return current;
-                                       if (index < left_size) {
-                                               current = current.left;
-                                       } else {
-                                               index -= left_size + 1;
-                                               current = current.right;
-                                       }
+                       int curpos = path.Count - 1;
+                       do {
+                               // parent == curpos-2, uncle == curpos-3, 
grandpa == curpos-4
+                               if (path [curpos-3] == null || path 
[curpos-3].IsBlack) {
+                                       rebalance_insert__rotate_final (curpos, 
path);
+                                       return;
                                }
 
-                               if (index != 0)
-                                       throw new SystemException ("Internal 
Error: index calculation");
-                               return current;
-                       }
-               }
+                               path [curpos-2].IsBlack = path 
[curpos-3].IsBlack = true;
 
-               public Enumerator GetEnumerator ()
-               {
-                       return new Enumerator (this);
-               }
+                               curpos -= 4; // move to the grandpa
 
-               public NodeEnumerator GetNodeEnumerator ()
-               {
-                       return new NodeEnumerator (this);
-               }
-
-#if TEST
-               public void VerifyInvariants ()
-               {
-                       if (root != null) {
-                               if (!root.IsBlack)
-                                       throw new SystemException ("Internal 
Error: root is not black");
-                               root.VerifyInvariants ();
-                       }
-               }
-
-               public void Dump ()
-               {
-                       if (root != null)
-                               root.Dump ("");
-               }
-#endif
-
-               void rebalance_insert (Node current, List<Node> path)
-               {
-                       for (int parpos = path.Count - 3; !path 
[parpos].IsBlack; parpos -= 4) {
-                               // uncle == parpos - 1, grandpa == parpos - 2, 
great-grandpa = parpos - 4
-                               if (path [parpos-1] == null || path 
[parpos-1].IsBlack) {
-                                       rebalance_insert__rotate_final 
(current, parpos, path);
+                               if (curpos == 0) // => current == root
                                        return;
-                               }
-
-                               path [parpos].IsBlack = path [parpos-1].IsBlack 
= true;
-
-                               // move to the grandpa
-                               current = path [parpos-2];
-                               if (current == root) // => parpos == 2
-                                       return;
-
-                               current.IsBlack = false;
-                       }
-
+                               path [curpos].IsBlack = false;
+                       } while (!path [curpos-2].IsBlack);
                }
 
+               // Pre-condition: current is black
                void rebalance_delete (List<Node> path)
                {
-                       path.Add (null); path.Add (null); // accomodate a 
rotation
-
-                       for (int curpos = path.Count - 3; curpos > 0; curpos -= 
2) {
-                               Node current = path [curpos];
-                               if (current != null && !current.IsBlack) {
-                                       current.IsBlack = true;
-                                       return;
-                               }
-
-
+                       int curpos = path.Count - 1;
+                       do {
                                Node sibling = path [curpos-1];
-
                                // current is black => sibling != null
-                               if (!path [curpos-1].IsBlack) {
+                               if (!sibling.IsBlack) {
                                        // current is black && sibling is red 
-                                       // => both sibling.left and 
sibling.right are not null and are black
+                                       // => both sibling.left and 
sibling.right are black, and are not null
                                        curpos = ensure_sibling_black (curpos, 
path);
+                                       // one of the nephews became the new 
sibling -- in either case, sibling != null
                                        sibling = path [curpos-1];
                                }
 
@@ -383,13 +383,20 @@
                                }
 
                                sibling.IsBlack = false;
-                       }
+
+                               curpos -= 2; // move to the parent
+
+                               if (curpos == 0)
+                                       return;
+                       } while (path [curpos].IsBlack);
+                       path [curpos].IsBlack = true;
                }
 
-               void rebalance_insert__rotate_final (Node current, int parpos, 
List<Node> path)
+               void rebalance_insert__rotate_final (int curpos, List<Node> 
path)
                {
-                       Node parent = path [parpos];
-                       Node grandpa = path [parpos-2];
+                       Node current = path [curpos];
+                       Node parent = path [curpos-2];
+                       Node grandpa = path [curpos-4];
 
                        uint grandpa_size = grandpa.Size;
 
@@ -418,7 +425,7 @@
                                parent.FixSize (); /* parent is red already, so 
no need to set it */
 
                        new_root.IsBlack = true;
-                       node_reparent (parpos == 2 ? null : path [parpos-4], 
grandpa, grandpa_size, new_root);
+                       node_reparent (curpos == 4 ? null : path [curpos-6], 
grandpa, grandpa_size, new_root);
                }
 
                // Pre-condition: sibling is black, and one of sibling.left and 
sibling.right is red
@@ -491,6 +498,12 @@
                        sibling.IsBlack = true;
                        node_reparent (curpos == 2 ? null : path [curpos-4], 
parent, parent_size, sibling);
 
+                       // accomodate the rotation
+                       if (curpos+1 == path.Count) {
+                               path.Add (null);
+                               path.Add (null);
+                       }
+
                        path [curpos-2] = sibling;
                        path [curpos-1] = current_on_left ? sibling.right : 
sibling.left;
                        path [curpos] = parent;
@@ -541,46 +554,14 @@
                        }
                }
 
-               public struct Enumerator : IDisposable, IEnumerator, 
IEnumerator<T> {
-                       NodeEnumerator host;
-
-                       internal Enumerator (RBTree<T> tree)
-                       {
-                               host = new NodeEnumerator (tree);
-                       }
-
-                       void IEnumerator.Reset ()
-                       {
-                               ((IEnumerator) host).Reset ();
-                       }
-
-                       public T Current {
-                               get { return host.Current.value; }
-                       }
-
-                       object IEnumerator.Current {
-                               get { return Current; }
-                       }
-
-                       public bool MoveNext ()
-                       {
-                               return host.MoveNext ();
-                       }
-
-                       public void Dispose ()
-                       {
-                               host.Dispose ();
-                       }
-               }
-
                public struct NodeEnumerator : IEnumerator, IEnumerator<Node> {
-                       RBTree<T> tree;
+                       RBTreeCore tree;
                        uint version;
 
                        List<Node> path;
                        Node current;
 
-                       internal NodeEnumerator (RBTree<T> tree)
+                       internal NodeEnumerator (RBTreeCore tree)
                        {
                                this.tree = tree;
                                version = tree.version;
@@ -617,6 +598,9 @@
                                                return false;
 
                                        path = new List<Node> ();
+
+                                       // sentinel: "parent" of root is null
+                                       path.Add (null);
                                        current = left_most (tree.root, null, 
path);
                                        return true;
                                }
@@ -629,10 +613,7 @@
 
                                int parpos = path.Count - 3;
                                Node parent;
-                               for (;;) {
-                                       parent = parpos < 0 ? null : path 
[parpos];
-                                       if (parent == null)
-                                               break;
+                               while ((parent = path [parpos]) != null) {
                                        if (current == parent.left)
                                                break;
                                        current = parent;
@@ -666,13 +647,154 @@
 #if TEST
 namespace Mono.ValidationTest {
        using System.Collections.Generic;
+
+       internal class TreeSet<T> : IEnumerable<T>, IEnumerable
+       {
+               public class Node : RBTreeCore.Node {
+                       public T value;
+
+                       public Node (T v)
+                       {
+                               value = v;
+                       }
+
+                       public override void SwapValue (RBTreeCore.Node other)
+                       {
+                               Node o = (Node) other;
+                               T v = value;
+                               value = o.value;
+                               o.value = v;
+                       }
+
+                       public override void Dump (string indent)
+                       {
+                               Console.WriteLine ("{0}{1} {2}({3})", indent, 
value, IsBlack ? "*" : "", Size);
+                               if (left != null)
+                                       left.Dump (indent + "  /");
+                               if (right != null)
+                                       right.Dump (indent + "  \\");
+                       }
+               }
+
+               public class NodeComparer : RBTreeCore.INodeComparer<T> {
+                       IComparer<T> cmp;
+
+                       public int Compare (T value, RBTreeCore.Node node)
+                       {
+                               return cmp.Compare (value, ((Node) node).value);
+                       }
+
+                       private NodeComparer (IComparer<T> cmp)
+                       {
+                               this.cmp = cmp;
+                       }
+                       static NodeComparer Default = new NodeComparer 
(Comparer<T>.Default);
+                       public static NodeComparer GetComparer (IComparer<T> 
cmp)
+                       {
+                               if (cmp == null || cmp == Comparer<T>.Default)
+                                       return Default;
+                               return new NodeComparer (cmp);
+                       }
+               }
+
+               public struct Enumerator : IDisposable, IEnumerator, 
IEnumerator<T> {
+                       RBTreeCore.NodeEnumerator host;
+
+                       internal Enumerator (TreeSet<T> tree)
+                       {
+                               host = new RBTreeCore.NodeEnumerator 
(tree.tree);
+                       }
+
+                       void IEnumerator.Reset ()
+                       {
+                               ((IEnumerator) host).Reset ();
+                       }
+
+                       public T Current {
+                               get { return ((Node) host.Current).value; }
+                       }
+
+                       object IEnumerator.Current {
+                               get { return Current; }
+                       }
+
+                       public bool MoveNext ()
+                       {
+                               return host.MoveNext ();
+                       }
+
+                       public void Dispose ()
+                       {
+                               host.Dispose ();
+                       }
+               }
+
+               RBTreeCore tree;
+
+               public TreeSet () : this (null)
+               {
+               }
+
+               public TreeSet (IComparer<T> cmp)
+               {
+                       tree = new RBTreeCore (NodeComparer.GetComparer (cmp));
+               }
+
+               IEnumerator IEnumerable.GetEnumerator ()
+               {
+                       return GetEnumerator ();
+               }
+
+               IEnumerator<T> IEnumerable<T>.GetEnumerator ()
+               {
+                       return GetEnumerator ();
+               }
+
+               public Enumerator GetEnumerator ()
+               {
+                       return new Enumerator (this);
+               }
+
+               public Node Insert (T value)
+               {
+                       return (Node) tree.Insert (value, new Node (value));
+               }
+
+               public Node Remove (T value)
+               {
+                       return (Node) tree.Remove (value);
+               }
+
+               public bool Contains (T value)
+               {
+                       return tree.Contains (value);
+               }
+
+               public T this [int index] {
+                       get { return ((Node) tree [index]).value; }
+               }
+
+               public int Count {
+                       get { return (int) tree.Count; }
+               }
+
+               public void VerifyInvariants ()
+               {
+                       tree.VerifyInvariants ();
+               }
+
+               public void Dump ()
+               {
+                       tree.Dump ();
+               }
+       }
        
        class Test {
                static void Main (string [] args)
                {
                        Random r = new Random ();
                        Dictionary<int, int> d = new Dictionary<int, int> ();
-                       RBTree<int> t = new RBTree<int> ();
+                       TreeSet<int> t = new TreeSet<int> ();
                        int iters = args.Length == 0 ? 100000 : Int32.Parse 
(args [0]);
 
                        for (int i = 0; i < iters; ++i) {
@@ -704,10 +826,15 @@
                                if (!t.Contains (n))
                                        throw new Exception ("tree says it 
doesn't have a number it should");
 
+                       Dictionary<int, int> d1 = new Dictionary<int, int> (d);
+
                        foreach (int n in t)
-                               if (!d.ContainsKey (n))
+                               if (!d1.Remove (n))
                                        throw new Exception ("tree has a number 
it shouldn't");
 
+                       if (d1.Count != 0)
+                               throw new Exception ("tree has numbers it 
shouldn't");
+
                        for (int i = 0; i < iters; ++i) {
                                int n = r.Next ();
                                if (!d.ContainsKey (n)) {

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to