Billy Barrow 3 weeks ago
parent
commit
d674d0db9f

+ 108 - 75
src/lib/DataStructures/SortedSeries.vala

@@ -5,18 +5,31 @@ namespace Invercargill.DataStructures {
 
         private class SeriesNode<T> {
             public bool is_red;
-            public Series<T> values;
-            public SeriesNode<T>? left_child;
-            public SeriesNode<T>? right_child;
-            public SeriesNode<T>? parent;
+            public Series<T> values { get; private set; }
+            public SeriesNode<T> left_child { get; set; }
+            public SeriesNode<T> right_child { get; set; }
+            public SeriesNode<T> parent { get; set; }
 
-            public SeriesNode(T item) {
+            public SeriesNode(T item, SeriesNode<T> nil) {
                 is_red = true;
+                left_child = nil;
+                right_child = nil;
                 values = new Series<T>();
                 values.add(item);
             }
 
+            public SeriesNode.nil() {
+                is_red = false;
+                left_child = this;
+                right_child = this;
+                values = new Series<T>();
+            }
+
             public T sample() {
+                assert_nonnull (this);
+                assert_nonnull (left_child);
+                assert_nonnull (right_child);
+                assert_nonnull (values);
                 return values.first_or_default();
             }
 
@@ -24,27 +37,38 @@ namespace Invercargill.DataStructures {
                 values.add(value);
             }
 
+            ~SeriesNode() {
+                if(values.count() > 0)
+                    print(@"Byebye $((int)sample())\n");
+            }
+
             //  public void remove_all_values_where (PredicateDelegate<T> predicate) {
             //      values = values.where(v => !predicate(v)).to_buffer();
             //  }
         }
 
         private SeriesNode<T> root;
+        private SeriesNode<T> nil;
+        private HashSet<SeriesNode<T>> nodes;
         private RWLock rw_lock;
         private CompareDelegate<T> comparitor;
         private int n_items;
 
         public SortedSeries(owned CompareDelegate<T>? comparitor = null) {
+            nil = new SeriesNode<T>.nil();
+            nodes = new HashSet<SeriesNode<T>> ();
+            nodes.add(nil);
+            root = nil;
             rw_lock = RWLock();
             n_items = 0;
             this.comparitor = (owned)comparitor ?? Operators.comparison<T>();
         }
 
         public override Tracker<T> get_tracker () {
-            if(root == null) {
+            if(root == nil) {
                 return empty<T>().get_tracker();
             }
-            return new TreeTracker<T>(root);  
+            return new TreeTracker<T>(this);  
         }
         public override int? peek_count () {
             return n_items;
@@ -56,65 +80,56 @@ namespace Invercargill.DataStructures {
 
         public void add (T item) {
             // Get lock and update count of items
-            print("Get lock and update count of items\n");
             rw_lock.writer_lock();
             n_items++;
 
-            // Set root if it doesn't exist
-            print("Set root if it doesn't exist\n");
-            if(root == null) {
-                root = new SeriesNode<T>(item);
-                root.is_red = false;
-                rw_lock.writer_unlock();
-                return;
-            }
+            SeriesNode<T>? parent = null;
+            SeriesNode<T> current = root;
+            int cmp = 0;
 
-            // Find leaf node
-            print("Find leaf node\n");
-            var node = root;
-            int cmp;
-            while(true) {
-                cmp = comparitor(item, node.sample());
-                print(@"CMP=$cmp; item=$((int)item); sample=$((int)node.sample());\n");
+            while(current != nil) {
+                parent = current;
+                cmp = comparitor(item, current.sample());
                 if(cmp == 0) {
-                    // No change to tree, simply add the value to this node
-                    print("No change to tree, simply add the value to this node\n");
-                    node.add_value (item);
+                    // Add to node, has no effect on tree
+                    current.add_value(item);
                     rw_lock.writer_unlock();
                     return;
                 }
-                if(cmp > 0) {
-                    if(node.right_child == null)
-                        break;
-                    node = node.right_child;
-                }
                 if(cmp < 0) {
-                    if(node.left_child == null) 
-                        break;
-                    node = node.left_child;
+                    current = current.left_child;
+                }
+                else {
+                    current = current.right_child;
                 }
             }
 
-            // Make new node, replacing the leaf
-            print("Make new node, replacing the leaf\n");
-            var new_node = new SeriesNode<T>(item);
-            new_node.parent = node;
-            if(node == null) {
+            var new_node = new SeriesNode<T> (item, nil);
+            nodes.add(new_node);
+            new_node.parent = parent;
+            if(parent == null) {
                 root = new_node;
-                new_node.is_red = true;
-            }
-            else if(cmp > 0) {
-                node.right_child = new_node;
             }
             else {
-                node.left_child = new_node;
+                if(cmp == 0) {
+                    print("Does this actually happen?\n");
+                    assert_not_reached ();
+                }
+                else if(cmp < 0) {
+                    parent.left_child = new_node;
+                }
+                else {
+                    parent.right_child = new_node;
+                }
             }
-            
-            // Balance the tree
-            print("Balance the tree\n");
-            if(new_node.parent?.parent != null) {
-                fix_insert (new_node);
+
+            if(new_node.parent == null) {
+                new_node.is_red = false;
             }
+            else if(new_node.parent.parent != null) {
+                fix_insert(new_node);
+            }
+
             rw_lock.writer_unlock();
         }
 
@@ -123,10 +138,10 @@ namespace Invercargill.DataStructures {
             while(node != root && node.parent.is_red) {
                 if(node.parent == node.parent.parent.left_child) {
                     var uncle = node.parent.parent.right_child;
-                    if(uncle != null && uncle.is_red) {
+                    if(uncle.is_red) {
                         node.parent.is_red = false;
                         uncle.is_red = false;
-                        uncle.parent.is_red = true;
+                        node.parent.parent.is_red = true;
                         node = node.parent.parent;
                         continue;
                     }
@@ -140,10 +155,10 @@ namespace Invercargill.DataStructures {
                 }
                 else {
                     var uncle = node.parent.parent.left_child;
-                    if(uncle != null && uncle.is_red) {
+                    if(uncle.is_red) {
                         node.parent.is_red = false;
                         uncle.is_red = false;
-                        uncle.parent.is_red = true;
+                        node.parent.parent.is_red = true;
                         node = node.parent.parent;
                         continue;
                     }
@@ -157,7 +172,6 @@ namespace Invercargill.DataStructures {
                 }
             }
             root.is_red = false;
-
         }
         public void remove_first_where (PredicateDelegate<T> predicate) {
             assert_not_reached ();
@@ -173,7 +187,7 @@ namespace Invercargill.DataStructures {
         private void rotate_left(SeriesNode<T> x) {
             var y = x.right_child;
             x.right_child = y.left_child;
-            if(y.left_child != null)
+            if(y.left_child != nil)
                 y.left_child.parent = x;
             y.parent = x.parent;
             if(x.parent == null)
@@ -189,7 +203,7 @@ namespace Invercargill.DataStructures {
         private void rotate_right(SeriesNode<T> x) {
             var y = x.left_child;
             x.left_child = y.right_child;
-            if(y.right_child != null)
+            if(y.right_child != nil)
                 y.right_child.parent = x;
             y.parent = x.parent;
             if(x.parent == null)
@@ -206,12 +220,14 @@ namespace Invercargill.DataStructures {
 
             SeriesNode<T> node;
             SeriesNode<T>? next_node;
+            SortedSeries<T> series;
             Tracker<T> values;
 
-            public TreeTracker(SeriesNode<T> root) {
+            public TreeTracker(SortedSeries<T> series) {
                 print("New tracker!\n");
-                node = root;
-                while(node.left_child != null) {
+                this.series = series;
+                node = series.root;
+                while(node.left_child != series.nil) {
                     node = node.left_child;
                 }
                 values = node.values.get_tracker();
@@ -233,25 +249,42 @@ namespace Invercargill.DataStructures {
             }
 
             private void find_next_node() {
+                //  next_node = null;
+                //  if(node.right_child != series.nil) {
+                //      next_node = node.right_child;
+                //      while(next_node.left_child != series.nil) {
+                //          next_node = next_node.left_child;
+                //      }
+                //  }
+                //  else if(node.parent == null) {
+                //      next_node = null;
+                //  }
+                //  else if(node.parent.left_child == node) {
+                //      next_node = node.parent;
+                //  }
+                //  else if(node.parent.parent.right_child == node.parent) {
+                //      next_node = null;
+                //  }
+                //  else {
+                //      next_node = node.parent.parent;
+                //  }
                 next_node = null;
-                if(node.right_child != null) {
-                    next_node = node.right_child;
-                    while(next_node.left_child != null) {
-                        next_node = next_node.left_child;
-                    }
-                }
-                else if(node.parent == null) {
-                    next_node = null;
-                }
-                else if(node.parent.left_child == node) {
-                    next_node = node.parent;
-                }
-                else if(node.parent.parent.right_child == node.parent) {
-                    next_node = null;
+                if (node == null) return;
+                // standard inorder successor:
+                if (node.right_child != series.nil) {
+                    var n = node.right_child;
+                    while (n.left_child != series.nil)
+                        n = n.left_child;
+                    next_node = n;
+                    return;
                 }
-                else {
-                    next_node = node.parent.parent;
+                var n = node;
+                var p = n.parent;
+                while (p != null && n == p.right_child) {
+                    n = p;
+                    p = p.parent;
                 }
+                next_node = p; // could be null (end)
             }
 
         }

+ 7 - 7
src/tests/Integration/SortedSeries.vala

@@ -13,15 +13,15 @@ void sorted_series_tests() {
         assert(series.count() == 1);
     });
 
-    //  Test.add_func("/invercargill/structure/sorted_series/add_many", () => {
+    Test.add_func("/invercargill/structure/sorted_series/add_many", () => {
 
-    //      var series = new SortedSeries<int>();
-    //      var items = range(0, 10000);
-    //      series.add_all(items.debug_trace(i => i.to_string()));
-    //      assert(series.count() == 10000);
+        var series = new SortedSeries<int>();
+        var items = range(0, 100000);
+        series.add_all(items);
+        assert(series.count() == 100000);
 
-    //      series.matches(items, (a, b) => a == b);
-    //  });
+        series.matches(items, (a, b) => a == b);
+    });
 
     Test.add_func("/invercargill/structure/sorted_series/add_twice", () => {
 

+ 1 - 1
src/tests/Speed/Series.vala

@@ -2,6 +2,6 @@ using Invercargill;
 using Invercargill.DataStructures;
 
 void series_speed_test() {
-    var series = new Series<int>();
+    var series = new SortedSeries<int>();
     speed_test_runner_int("Series", series, i => series.add(i), i => series.add_all(i));
 }

+ 1 - 1
src/tests/TestRunner.vala

@@ -25,7 +25,7 @@ public static int main(string[] args) {
     
     Test.run();
     
-    //  series_speed_test();
+    series_speed_test();
     //  vector_speed_test();
     //  set_speed_test();
     //  dictionary_speed_test();