فهرست منبع

Non-functional Red-Black tree

Billy Barrow 3 هفته پیش
والد
کامیت
55150c291a

+ 77 - 0
src/lib/DataStructures/Buffer.vala

@@ -0,0 +1,77 @@
+
+namespace Invercargill.DataStructures {
+
+    public class Buffer<T> : Enumerable<T>, Lot<T>, ReadOnlyAddressable<T>, Addressable<T> {
+
+        private T[] array;
+        private SafeReadFunc<T>? safe_read;
+        private SafeWriteFunc<T>? safe_write;
+
+        public override Tracker<T> get_tracker () {
+            return new AddressableTracker<T> (this);
+        }
+        public override int? peek_count () {
+            return array.length;
+        }
+        public override EnumerableInfo get_info () {
+            return new EnumerableInfo.infer_ultimate(this, EnumerableCategory.IN_MEMORY);
+        }
+
+        public Buffer(uint size) {
+            array = new T[size];
+            safe_read = get_safe_read_function_for<T>();
+            safe_write = get_safe_write_function_for<T>();
+        }
+
+        internal Buffer.take_array(owned T[] array) {
+            this.array = (owned)array;
+            safe_read = get_safe_read_function_for<T>();
+            safe_write = get_safe_write_function_for<T>();
+        }
+
+        public new void set (uint index, T item) throws IndexError {
+            if(index >= array.length) {
+                throw new IndexError.INDEX_EXCEEDS_UPPER_BOUNDS(@"Tried to set index $(index) on a buffer of length $(array.length)");
+            }
+            if(safe_write != null) {
+                safe_write(array, index, item);
+                return;
+            }
+            array[index] = item;
+        }
+
+        public new T get (uint index) throws IndexError {
+            if(index >= array.length) {
+                throw new IndexError.INDEX_EXCEEDS_UPPER_BOUNDS(@"Tried to access index $(index) on a buffer of length $(array.length)");
+            }
+            if(safe_read != null) {
+                return safe_read(array, index);
+            }
+            return array[index];
+        }
+
+        public bool try_get (uint index, out T value) {
+            try {
+                value = get(index);
+                return true;
+            }
+            catch {
+                value = null;
+                return false;
+            }
+        }
+
+        public uint? first_index_of (Invercargill.PredicateDelegate<T> predicate) {
+            var i = 0;
+            foreach (var item in this) {
+                if(predicate(item)) {
+                    return i;
+                }
+                i++;
+            }
+            return null;
+        }
+
+    }
+
+}

+ 261 - 0
src/lib/DataStructures/SortedSeries.vala

@@ -0,0 +1,261 @@
+
+namespace Invercargill.DataStructures {
+
+    public class SortedSeries<T> : Enumerable<T>, Lot<T>, ReadOnlyCollection<T>, Collection<T> {
+
+        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 SeriesNode(T item) {
+                is_red = true;
+                values = new Series<T>();
+                values.add(item);
+            }
+
+            public T sample() {
+                return values.first_or_default();
+            }
+
+            public void add_value(T value) {
+                values.add(value);
+            }
+
+            //  public void remove_all_values_where (PredicateDelegate<T> predicate) {
+            //      values = values.where(v => !predicate(v)).to_buffer();
+            //  }
+        }
+
+        private SeriesNode<T> root;
+        private RWLock rw_lock;
+        private CompareDelegate<T> comparitor;
+        private int n_items;
+
+        public SortedSeries(owned CompareDelegate<T>? comparitor = null) {
+            rw_lock = RWLock();
+            n_items = 0;
+            this.comparitor = (owned)comparitor ?? Operators.comparison<T>();
+        }
+
+        public override Tracker<T> get_tracker () {
+            if(root == null) {
+                return empty<T>().get_tracker();
+            }
+            return new TreeTracker<T>(root);  
+        }
+        public override int? peek_count () {
+            return n_items;
+        }
+        public override EnumerableInfo get_info () {
+            return new EnumerableInfo.infer_ultimate (this, EnumerableCategory.IN_MEMORY);
+        }
+
+
+        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;
+            }
+
+            // 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");
+                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);
+                    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;
+                }
+            }
+
+            // 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) {
+                root = new_node;
+                new_node.is_red = true;
+            }
+            else if(cmp > 0) {
+                node.right_child = new_node;
+            }
+            else {
+                node.left_child = new_node;
+            }
+            
+            // Balance the tree
+            print("Balance the tree\n");
+            if(new_node.parent?.parent != null) {
+                fix_insert (new_node);
+            }
+            rw_lock.writer_unlock();
+        }
+
+        private void fix_insert(SeriesNode<T> new_node) {
+            var node = new_node;
+            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) {
+                        node.parent.is_red = false;
+                        uncle.is_red = false;
+                        uncle.parent.is_red = true;
+                        node = node.parent.parent;
+                        continue;
+                    }
+                    if(node == node.parent.right_child) {
+                        node = node.parent;
+                        rotate_left(node);
+                    }
+                    node.parent.is_red = false;
+                    node.parent.parent.is_red = true;
+                    rotate_right (node.parent.parent);
+                }
+                else {
+                    var uncle = node.parent.parent.left_child;
+                    if(uncle != null && uncle.is_red) {
+                        node.parent.is_red = false;
+                        uncle.is_red = false;
+                        uncle.parent.is_red = true;
+                        node = node.parent.parent;
+                        continue;
+                    }
+                    if(node == node.parent.left_child) {
+                        node = node.parent;
+                        rotate_right(node);
+                    }
+                    node.parent.is_red = false;
+                    node.parent.parent.is_red = true;
+                    rotate_left(node.parent.parent);
+                }
+            }
+            root.is_red = false;
+
+        }
+        public void remove_first_where (PredicateDelegate<T> predicate) {
+            assert_not_reached ();
+        }
+        public void remove_all_where (PredicateDelegate<T> predicate) {
+            assert_not_reached ();
+        }
+        public void clear () {
+            assert_not_reached ();
+        }
+
+
+        private void rotate_left(SeriesNode<T> x) {
+            var y = x.right_child;
+            x.right_child = y.left_child;
+            if(y.left_child != null)
+                y.left_child.parent = x;
+            y.parent = x.parent;
+            if(x.parent == null)
+                root = y;
+            else if(x.parent.left_child == x)
+                x.parent.left_child = y;
+            else
+                x.parent.right_child = y;
+            y.left_child = x;
+            x.parent = y;
+        }
+
+        private void rotate_right(SeriesNode<T> x) {
+            var y = x.left_child;
+            x.left_child = y.right_child;
+            if(y.right_child != null)
+                y.right_child.parent = x;
+            y.parent = x.parent;
+            if(x.parent == null)
+                root = y;
+            else if(x.parent.right_child == x)
+                x.parent.right_child = y;
+            else
+                x.parent.left_child = y;
+            y.right_child = x;
+            x.parent = y;
+        }
+        
+        private class TreeTracker<T> : Tracker<T> {
+
+            SeriesNode<T> node;
+            SeriesNode<T>? next_node;
+            Tracker<T> values;
+
+            public TreeTracker(SeriesNode<T> root) {
+                print("New tracker!\n");
+                node = root;
+                while(node.left_child != null) {
+                    node = node.left_child;
+                }
+                values = node.values.get_tracker();
+                find_next_node();
+            }
+
+            public override bool has_next () {
+                return values.has_next() || next_node != null;
+            }
+            public override T get_next () {
+                if(values.has_next()) {
+                    return values.get_next();
+                }
+                node = next_node;
+                values = node.values.get_tracker();
+                var result = values.get_next();
+                find_next_node();
+                return result;
+            }
+
+            private void find_next_node() {
+                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;
+                }
+                else {
+                    next_node = node.parent.parent;
+                }
+            }
+
+        }
+
+    }
+
+}

+ 10 - 2
src/lib/Enumerable.vala

@@ -51,7 +51,9 @@ namespace Invercargill {
         }
 
         public virtual T[] to_array() {
-            var array = new T[1024];
+            T[] array;
+            array = new T[1024];
+
             var index = 0;
             foreach (var item in this) {
                 if(index >= array.length) {
@@ -60,10 +62,16 @@ namespace Invercargill {
                 safely_assign_to_array<T>(array, index, item);
                 index++;
             }
-            array.resize(index);
+            if(array.length != index) {
+                array.resize(index);
+            }
             return array;
         }
 
+        public virtual Buffer<T> to_buffer() {
+            return new Buffer<T>.take_array(to_array());
+        }
+
         public virtual int count(PredicateDelegate<T>? predicate = null) {
             var enumerable = this;
             // When no predicate is passed, see if we can peek at the count of

+ 11 - 0
src/lib/Errors.vala

@@ -1,4 +1,15 @@
 namespace Invercargill {
+
+    internal delegate void NonErrorDelegate() throws Error;
+    internal void non_error(NonErrorDelegate func) {
+        try {
+            func();
+        }
+        catch(Error e) {
+            assert_no_error(e);
+        }
+    }
+
     public errordomain SequenceError {
         NO_ELEMENTS,
         MULTUPLE_ELEMENTS,

+ 8 - 0
src/lib/Interfaces/Addressable.vala

@@ -4,6 +4,14 @@ namespace Invercargill {
     public interface Addressable<T> : ReadOnlyAddressable<T> {
 
         public abstract void @set(uint index, T item) throws IndexError;
+        
+        public virtual void set_all(uint first_index, Enumerable<T> items) throws IndexError {
+            uint pos = 0;
+            foreach (var item in items) {
+                set(pos, item);
+                pos++;
+            }
+        }
 
     }
 

+ 2 - 0
src/lib/meson.build

@@ -82,6 +82,8 @@ sources += files('DataStructures/HashSet.vala')
 sources += files('DataStructures/Dictionary.vala')
 sources += files('DataStructures/PropertyDictionary.vala')
 sources += files('DataStructures/SortedVector.vala')
+sources += files('DataStructures/SortedSeries.vala')
+sources += files('DataStructures/Buffer.vala')
 
 sources += files('Mapping/Mapper.vala')
 sources += files('Mapping/PropertyMapper.vala')

+ 51 - 0
src/tests/Integration/SortedSeries.vala

@@ -0,0 +1,51 @@
+using Invercargill;
+using Invercargill.Convert;
+using Invercargill.DataStructures;
+
+
+void sorted_series_tests() {
+
+    Test.add_func("/invercargill/structure/sorted_series/add_item", () => {
+        var series = new SortedSeries<int>();
+        series.add(8);
+
+        assert(series.first_or_default() == 8);
+        assert(series.count() == 1);
+    });
+
+    //  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);
+
+    //      series.matches(items, (a, b) => a == b);
+    //  });
+
+    Test.add_func("/invercargill/structure/sorted_series/add_twice", () => {
+
+        var series = new SortedSeries<int>();
+        var items = range(0, 100);
+        series.add_all(items);
+        series.add_all(items.debug_trace(i => i.to_string()));
+        assert(series.count() == 200);
+
+        series.matches(items.interleave(items), (a, b) => a == b);
+    });
+
+    Test.add_func("/invercargill/structure/sorted_series/to_array", () => {
+
+        var items = new int[] { 1, 8, 2, 4, 6, 5, 3, 10, 3, 7 };
+        var expected = new int[] { 1, 2, 3, 3, 4, 5, 6, 7, 8, 10 };
+        var series = new SortedSeries<int>();
+        series.add_all(Convert.ate(items).debug_trace(i => i.to_string()));
+        var array = series.to_array();
+        assert_cmpint(array.length, CompareOperator.EQ, 10);
+        series.debug_dump(n => n.to_string());
+
+        for(int i = 0; i < expected.length; i++) {
+            assert_cmpint(array[i], CompareOperator.EQ, expected[i]);
+        }
+    });
+}

+ 4 - 4
src/tests/Integration/SortedVector.vala

@@ -5,7 +5,7 @@ using Invercargill.DataStructures;
 
 void sorted_vector_tests() {
 
-    Test.add_func("/invercargill/structure/sorted_series/add_item", () => {
+    Test.add_func("/invercargill/structure/sorted_vector/add_item", () => {
         var series = new SortedVector<int>();
         series.add(8);
 
@@ -13,7 +13,7 @@ void sorted_vector_tests() {
         assert(series.count() == 1);
     });
 
-    Test.add_func("/invercargill/structure/sorted_series/add_many", () => {
+    Test.add_func("/invercargill/structure/sorted_vector/add_many", () => {
 
         var series = new SortedVector<int>();
         var items = range(0, 10000000);
@@ -23,7 +23,7 @@ void sorted_vector_tests() {
         series.matches(items, (a, b) => a == b);
     });
 
-    Test.add_func("/invercargill/structure/sorted_series/add_twice", () => {
+    Test.add_func("/invercargill/structure/sorted_vector/add_twice", () => {
 
         var series = new SortedVector<int>();
         var items = range(0, 100);
@@ -34,7 +34,7 @@ void sorted_vector_tests() {
         series.matches(items.interleave(items), (a, b) => a == b);
     });
 
-    Test.add_func("/invercargill/structure/sorted_series/to_array", () => {
+    Test.add_func("/invercargill/structure/sorted_vector/to_array", () => {
 
         var items = new int[] { 1, 8, 2, 4, 6, 5, 3, 10, 3, 7 };
         var expected = new int[] { 1, 2, 3, 3, 4, 5, 6, 7, 8, 10 };

+ 24 - 24
src/tests/TestRunner.vala

@@ -3,33 +3,33 @@ public static int main(string[] args) {
 
     Test.init(ref args);
 
-    where_tests();
-    select_tests();
-    select_many_tests();
-    gee_tests();
-    tracker_tests();
-    parallel_tests();
-    first_tests();
-    binary_data_tests();
-    sort_tests();
-    vector_tests();
-    series_tests();
-    array_tests();
-    promotion_tests();
-    numbers_test();
-    dictionary_tests();
-    property_mapper_tests();
-    cache_tests();
-    sorted_vector_tests();
+    //  where_tests();
+    //  select_tests();
+    //  select_many_tests();
+    //  gee_tests();
+    //  tracker_tests();
+    //  parallel_tests();
+    //  first_tests();
+    //  binary_data_tests();
+    //  sort_tests();
+    //  vector_tests();
+    //  series_tests();
+    //  array_tests();
+    //  promotion_tests();
+    //  numbers_test();
+    //  dictionary_tests();
+    //  property_mapper_tests();
+    //  cache_tests();
+    //  sorted_vector_tests();
+    sorted_series_tests();
     
     Test.run();
     
-    series_speed_test();
-    vector_speed_test();
-    //  sorted_vector_speed_test();
-    set_speed_test();
-    dictionary_speed_test();
-    fifo_speed_test();
+    //  series_speed_test();
+    //  vector_speed_test();
+    //  set_speed_test();
+    //  dictionary_speed_test();
+    //  fifo_speed_test();
 
 
     return 0;

+ 1 - 0
src/tests/meson.build

@@ -20,6 +20,7 @@ sources += files('Integration/Dictionary.vala')
 sources += files('Integration/PropertyMapper.vala')
 sources += files('Integration/Cache.vala')
 sources += files('Integration/SortedVector.vala')
+sources += files('Integration/SortedSeries.vala')
 
 sources += files('Speed/SpeedTest.vala')
 sources += files('Speed/Series.vala')