فهرست منبع

If your application wasn't broke before it will be now

Billy Barrow 1 ماه پیش
والد
کامیت
c56f8e9143

+ 41 - 68
src/lib/Associative/Dictionary.vala

@@ -2,92 +2,65 @@ using Invercargill.Convert;
 
 namespace Invercargill {
 
-    public class Dictionary<TKey, TValue> : Associative<TKey, TValue>, KeyValues<TKey, TValue> {
+    public class Dictionary<TKey, TValue> : Enumerable<KeyValuePair<TKey, TValue>>, ReadOnlyCollection<KeyValuePair<TKey, TValue>>, ReadOnlyAssociative<TKey, TValue>, Associative<TKey, TValue> {
 
-        private HashTable<Key<TKey>, TValue> hash_table;
-        private EqualityDelegate<TKey> key_equal_delegate;
-        private HashDelegate<TKey> key_hash_delegate;
+        private HashSet<KeyValuePair<TKey, TValue>> hash_set;
+        private HashDelegate<TKey> hash_func;
+        private EqualityDelegate<TKey> equal_func;
 
         public Dictionary(HashDelegate<TKey>? key_hash_func = null, EqualityDelegate<TKey>? key_equal_func = null) {
-            key_hash_delegate = key_hash_func ?? Operators.hash<TKey>();
-            key_equal_delegate = key_equal_func ?? Operators.equality<TKey>();
-            hash_table = new HashTable<Key<TKey>, TValue>(Key.hash, Key.equal);
+            hash_func = key_hash_func ?? Operators.hash<TKey>();
+            equal_func = key_equal_func ?? Operators.equality<TKey>();
+            clear();
         }
 
-        public override void @set (TKey key, TValue value) {
-            lock(hash_table) {
-                hash_table.set (new Key<TKey>(this, key), value);
-            }
+        public override Tracker<KeyValuePair<TKey, TValue>> get_tracker () {
+            return hash_set.get_tracker();
         }
 
-        public override void set_all (Enumerable<KeyValuePair<TKey, TValue>> key_values) {
-            lock(hash_table) {
-                key_values.iterate(kv => hash_table.set(new Key<TKey>(this, kv.key), kv.value));
-            }
+        public new void @set(TKey key, TValue value) {
+            hash_set.set(new KeyValuePair<TKey, TValue>(key, value));
         }
 
-        public override bool try_get (TKey key, out TValue value) {
-            lock(hash_table) {
-                TKey orig_key;
-                return hash_table.lookup_extended (new Key<TKey>(this, key), out orig_key, out value);
-            }
-        }
-        
-        public override void clear (TKey key) {
-            lock(hash_table) {
-                hash_table.remove(new Key<TKey>(this, key));
+        public bool remove (TKey key, out TValue? value) {
+            var result = hash_set.remove (new KeyValuePair<TKey, TValue>(key, null));
+            if(result != null) {
+                value = result.value;
+                return true;
             }
+            return false;
         }
 
-        public override Tracker<KeyValuePair<TKey, TValue>> get_tracker () {
-            return new DictionaryTracker<TKey, TValue> (this);
-        }
-        public override bool has (TKey key) {
-            lock(hash_table) {
-                return hash_table.contains (new Key<TKey>(this, key));
+        public bool try_get (TKey key, out TValue value) {
+            KeyValuePair<TKey, TValue> result;
+            if(hash_set.try_find (new KeyValuePair<TKey, TValue>(key, null), out result)) {
+                value = result.value;
+                return true;
             }
+            value = null;
+            return false;
         }
 
-        private class DictionaryTracker<TKey, TValue> : Tracker<KeyValuePair<TKey, TValue>> {
-
-            private Dictionary<TKey, TValue> dictionary;
-            private (unowned Key<TKey>)[] keys;
-            private int index;
-
-            public DictionaryTracker(Dictionary<TKey, TValue> dict) {
-                dictionary = dict;
-                keys = dict.hash_table.get_keys_as_array ();
-                index = 0;
-            }
-
-            public override bool has_next() {
-                return index < keys.length;
-            }
-            public override KeyValuePair<TKey, TValue> get_next() {
-                var key = keys[index].key;
-                var item = dictionary.get_or_default(key);
-                index++;
-                return new KeyValuePair<TKey, TValue> (key, item);
-            }
-
+        public bool has(TKey key) {
+            KeyValuePair<TKey, TValue> _;
+            return hash_set.try_find (new KeyValuePair<TKey, TValue>(key, null), out _);
         }
 
-        private class Key<TKey> {
-            public Dictionary owner;
-            public TKey key;
+        public Enumerable<TKey> keys { owned get {
+            return select<TKey>(i => i.key);
+        }}
 
-            public Key(Dictionary owner, TKey key) {
-                this.owner = owner;
-                this.key = key;
-            }
+        public Enumerable<TValue> values { owned get {
+            return select<TValue>(i => i.value);
+        }}
 
-            public bool equal(Key<TKey> other) {
-                return owner.key_equal_delegate(key, other.key);
-            }
-
-            public uint hash() {
-                return owner.key_hash_delegate(key);
-            }
+        public void clear () {
+            hash_set = new HashSet<KeyValuePair<TKey, TValue>>(kv => hash_func(kv.key), (kva, kvb) => equal_func(kva.key, kvb.key));
         }
-    }
+        
+        public bool add (TKey key, TValue value) {
+            return hash_set.add (new KeyValuePair<TKey, TValue>(key, value));
+        }
+
+   }
 }

+ 0 - 14
src/lib/Associative/KeyValues.vala

@@ -1,14 +0,0 @@
-
-namespace Invercargill {
-
-    public interface KeyValues<TKey, TValue> : Enumerable<KeyValuePair<TKey, TValue>> {
-
-        public abstract bool try_get(TKey key, out TValue value);
-        public abstract bool has(TKey key);
-        public abstract new TValue @get(TKey key) throws IndexError;
-        public abstract TValue? get_or_default(TKey key);
-
-
-    }
-
-}

+ 1 - 1
src/lib/Associative/Properties.vala

@@ -1,7 +1,7 @@
 
 namespace Invercargill {
 
-    public interface Properties : Enumerable<KeyValuePair<string, Element>>, KeyValues<string, Element> {
+    public interface Properties : ReadOnlyAssociative<string, Element> {
         public abstract void set_native<T>(string key, T value, bool? defined = null) throws ElementError;
     }
 

+ 0 - 24
src/lib/Collections/Collection.vala

@@ -1,24 +0,0 @@
-namespace Invercargill {
-
-    public abstract class Collection<T> : Enumerable<T> {
-
-        public abstract void add(T item);
-        public abstract void remove_first_where(PredicateDelegate<T> predicate);
-        public abstract void remove_where(PredicateDelegate<T> predicate);
-
-        public virtual void add_all(Enumerable<T> items) {
-            items.iterate(i => add(i));
-        }
-
-    }
-
-    public abstract class IndexedCollection<T> : Collection<T> {
-
-        public new abstract T @get(int index) throws IndexError;
-        public new abstract void @set(int index, T item) throws IndexError;
-        public abstract void remove(int index) throws IndexError;
-        public abstract int index_of(PredicateDelegate<T> predicate);
-
-    }
-    
-}

+ 192 - 0
src/lib/Collections/HashSet.vala

@@ -0,0 +1,192 @@
+using Invercargill.Convert;
+
+namespace Invercargill {
+
+    public class HashSet<T> : Enumerable<T>, ReadOnlyCollection<T>, ReadOnlySet<T>, Set<T> {
+
+        private const uint BUCKET_TOMBSTONE = uint.MAX;
+        private const uint BUCKET_EMPTY = 0;
+        private uint[] buckets;
+        private T[] items;
+        private int n_items = 0;
+        private int n_buckets = 16;
+        private int n_collissions = 0;
+        private SafeReadFunc<T>? safe_read;
+        private SafeWriteFunc<T>? safe_write;
+        private HashDelegate<T> hash_func;
+        private EqualityDelegate<T> equal_func;
+
+        construct {
+            setup();
+        }
+
+        public HashSet(HashDelegate<T>? value_hash_func = null, EqualityDelegate<T>? value_equal_func = null) {
+            setup(value_hash_func, value_equal_func);
+        }
+
+        private void setup(HashDelegate<T>? value_hash_func = null, EqualityDelegate<T>? value_equal_func = null) {
+            hash_func = value_hash_func ?? Operators.hash<T>();
+            equal_func = value_equal_func ?? Operators.equality<T>();
+            safe_read = get_safe_read_function_for<T>();
+            safe_write = get_safe_write_function_for<T>();
+            buckets = new uint[n_buckets];
+            items = new T[n_buckets];
+
+        }
+
+        private T read_item(uint index) {
+            if(safe_read != null){
+                return safe_read(items, index);
+            }
+            return items[index];
+        }
+
+        private void write_item(uint index, T item) {
+            if(safe_write != null) {
+                safe_write(items, index, item);
+                return;
+            }
+            items[index] = item;
+        }
+
+        private void ensure_room_for_items(int count) {
+            if(items.length <= n_items + count) {
+                items.resize(items.length * 2);
+            }
+        }
+
+        private void ensure_room_for_bucket(uint index) {
+            var target = buckets.length;
+            while(target <= index) {
+                target = buckets.length * 2;
+            }
+            if(target != buckets.length) {
+                buckets.resize(target);
+            }
+        }
+
+        private void double_buckets() {
+            n_buckets *= 2;
+            buckets = new uint[n_buckets];
+            n_collissions = 0;
+
+            for(var i = 0; i < n_items; i++) {
+                var item = read_item(i);
+                var bucket_index = bucket_for(item);
+                while(buckets[bucket_index] != BUCKET_EMPTY) {
+                    bucket_index++;
+                    n_collissions++;
+                    ensure_room_for_bucket(bucket_index);
+                }
+                buckets[bucket_index] = i+1;
+            }
+            
+        }
+
+        private T get_item(uint index) {
+            if(index == BUCKET_EMPTY || index == BUCKET_TOMBSTONE) {
+                assert_not_reached();
+            }
+            return read_item(index-1);
+        }
+
+        private uint add_item(T item) {
+            ensure_room_for_items(1);
+            write_item(n_items, item);
+            n_items++;
+            return n_items;
+        }
+
+        private uint bucket_for(T item) {
+            var hash = hash_func(item);
+            return hash % n_buckets;
+        }
+
+        public override Tracker<T> get_tracker () {
+            return range(0, n_items).select<T>(i => read_item(i)).get_tracker();
+        }
+
+        public bool add (T item) {
+            return add_internal(item, false);
+        }
+
+        public new void @set(T item) {
+            add_internal(item, true);
+        }
+
+        private bool add_internal (T item, bool overwrite) {
+            if(n_collissions > n_buckets / 4) {
+                double_buckets();
+            }
+            
+            var bucket_index = bucket_for(item);
+            while(buckets[bucket_index] != BUCKET_EMPTY && buckets[bucket_index] != BUCKET_TOMBSTONE) {
+                if(equal_func(get_item(buckets[bucket_index]), item)) {
+                    if(overwrite)
+                        write_item(buckets[bucket_index] - 1, item);
+                    return overwrite;
+                }
+                bucket_index++;
+                n_collissions++;
+                ensure_room_for_bucket(bucket_index);
+            }
+            
+            buckets[bucket_index] = add_item(item);
+            return true;
+        }
+
+        public bool try_find(T search, out T item) {
+            var bucket_index = bucket_for(search);
+            while(bucket_index < buckets.length && buckets[bucket_index] != BUCKET_EMPTY) {
+                if(buckets[bucket_index] != BUCKET_TOMBSTONE) {
+                    var ours = get_item(buckets[bucket_index]);
+                    if(equal_func(ours, search)) {
+                        item = ours;
+                        return true;
+                    }
+                }
+                bucket_index++;
+            }
+            item = null;
+            return false;
+        }
+
+        public void remove_first_where (Invercargill.PredicateDelegate<T> predicate) {
+            remove(first_or_default(predicate));
+        }
+
+        public void remove_all_where (Invercargill.PredicateDelegate<T> predicate) {
+            except_with(where(predicate));
+        }
+
+        public bool has(T item) {
+            T? _;
+            return try_find(item, out _);
+        }
+
+        public void clear() {
+            n_items = 0;
+            n_buckets = 16;
+            n_collissions = 0;
+            buckets = new uint[n_buckets];
+            items = new T[n_buckets];
+        }
+
+        public T? remove(T item) {
+            var bucket_index = bucket_for(item);
+            while(bucket_index < buckets.length && buckets[bucket_index] != BUCKET_EMPTY) {
+                if(buckets[bucket_index] != BUCKET_TOMBSTONE) {
+                    var ours = get_item(buckets[bucket_index]);
+                    if(equal_func(ours, item)) {
+                        write_item(buckets[bucket_index], null);
+                        buckets[bucket_index] = BUCKET_TOMBSTONE;
+                        return ours;
+                    }
+                }
+                bucket_index++;
+            }
+            return null;
+        }
+
+    }
+}

+ 13 - 5
src/lib/Collections/Series.vala

@@ -1,6 +1,6 @@
 namespace Invercargill {
 
-    public class Series<T> : Collection<T> {
+    public class Series<T> : Enumerable<T>, ReadOnlyCollection<T>, Collection<T> {
      
         internal class SeriesItem<T> {
             public SeriesItem next = null;
@@ -42,7 +42,7 @@ namespace Invercargill {
             return arr;
         }
 
-        public override void add(T item) {
+        public void add(T item) {
             lock(root) {
                 n_items++;
                 var si = new SeriesItem<T>(item);
@@ -56,7 +56,7 @@ namespace Invercargill {
             }
         }
 
-        public override void add_all(Enumerable<T> items) {
+        public void add_all(Enumerable<T> items) {
             items.iterate(i => add(i));
         }
 
@@ -64,10 +64,10 @@ namespace Invercargill {
             return n_items;
         }
 
-        public override void remove_first_where(Invercargill.PredicateDelegate<T> predicate) {
+        public void remove_first_where(Invercargill.PredicateDelegate<T> predicate) {
             remove_items(predicate, true);
         }
-        public override void remove_where(Invercargill.PredicateDelegate<T> predicate) {
+        public void remove_all_where(Invercargill.PredicateDelegate<T> predicate) {
             remove_items(predicate, false);
         }
 
@@ -93,6 +93,14 @@ namespace Invercargill {
             }
         }
 
+        public void clear() {
+            lock(root) {
+                n_items = 0;
+                root = null;
+                end = null;
+            }
+        }
+
         private class SeriesTracker<T> : Tracker<T> {
 
             private SeriesItem<T>? current;

+ 0 - 187
src/lib/Collections/Set.vala

@@ -1,187 +0,0 @@
-using Invercargill.Convert;
-
-namespace Invercargill {
-
-    public class Set<T> : Collection<T> {
-
-        private uint[] buckets;
-        private T[] items;
-        private int n_items = 0;
-        private int n_buckets = 16;
-        private int n_collissions = 0;
-        private SafeReadFunc<T>? safe_read;
-        private SafeWriteFunc<T>? safe_write;
-        private HashDelegate<T> hash_func;
-        private EqualityDelegate<T> equal_func;
-
-        construct {
-            setup();
-        }
-
-        public Set(HashDelegate<T>? value_hash_func = null, EqualityDelegate<T>? value_equal_func = null) {
-            setup(value_hash_func, value_equal_func);
-        }
-
-        private void setup(HashDelegate<T>? value_hash_func = null, EqualityDelegate<T>? value_equal_func = null) {
-            hash_func = value_hash_func ?? Operators.hash<T>();
-            equal_func = value_equal_func ?? Operators.equality<T>();
-            safe_read = get_safe_read_function_for<T>();
-            safe_write = get_safe_write_function_for<T>();
-            buckets = new uint[n_buckets];
-            items = new T[n_buckets];
-
-        }
-
-        private void ensure_room_for_items(int count) {
-            if(items.length <= n_items + count) {
-                items.resize(items.length * 2);
-            }
-        }
-
-        private void ensure_room_for_bucket(uint index) {
-            var target = buckets.length;
-            while(target <= index) {
-                target = buckets.length * 2;
-            }
-            if(target != buckets.length) {
-                buckets.resize(target);
-            }
-        }
-
-        private void double_buckets() {
-            n_buckets *= 2;
-            buckets = new uint[n_buckets];
-            n_collissions = 0;
-
-            for(var i = 0; i < n_items; i++) {
-                var item = safe_read(items, i);
-                var bucket_index = bucket_for(item);
-                while(buckets[bucket_index] != 0) {
-                    bucket_index++;
-                    n_collissions++;
-                    ensure_room_for_bucket(bucket_index);
-                }
-                buckets[bucket_index] = i+1;
-            }
-            
-        }
-
-        private T get_item(uint index) {
-            if(index == 0) {
-                assert_not_reached();
-            }
-            return safe_read(items, (int)index-1);
-        }
-
-        private uint add_item(T item) {
-            n_items++;
-            ensure_room_for_items(1);
-            safe_write(items, (int)n_items-1, item);
-            return n_items;
-        }
-
-        private uint bucket_for(T item) {
-            var hash = hash_func(item);
-            return hash % n_buckets;
-        }
-
-        public override Tracker<T> get_tracker () {
-            return range(0, n_items).select<T>(i => safe_read(items, i)).get_tracker();
-        }
-
-        public override void add (T item) {
-            if(n_collissions > n_buckets / 4) {
-                double_buckets();
-            }
-            
-            var bucket_index = bucket_for(item);
-            while(buckets[bucket_index] != 0) {
-                if(equal_func(get_item(buckets[bucket_index]), item)) {
-                    //set_item(bucket_index, item); MAYBE?
-                    return;
-                }
-                bucket_index++;
-                n_collissions++;
-                ensure_room_for_bucket(bucket_index);
-            }
-            
-            buckets[bucket_index] = add_item(item);
-        }
-
-        public override void add_all (Enumerable<T> items) {
-            items.iterate(add);
-        }
-
-        public Set<T> union(Enumerable<T> items) {
-            var new_set = to_set (hash_func, equal_func);
-            new_set.add_all (items);
-            return new_set;
-        }
-
-        public Set<T> difference(Enumerable<T> items) {
-            var new_set = to_set (hash_func, equal_func);
-            new_set.remove_all(items);
-            return new_set;
-        }
-
-        public Set<T> intersection(Enumerable<T> items) {
-            var new_set = to_set (hash_func, equal_func);
-            new_set.remove_except(items);
-            return new_set;
-        }
-
-        //  public new T? find(T item) {
-        //      var bucket = buckets.get_or_default((int)bucket_for(item));
-        //      if(bucket == null) 
-        //          return null;
-
-        //      foreach (var index in bucket) {
-        //          var result = items[index];
-        //          if(equal_func(result, item)) {
-        //              return result;
-        //          }
-        //      }
-        //      return null;
-        //  }
-
-        public override void remove_first_where (Invercargill.PredicateDelegate<T> predicate) {
-            remove(first_or_default(predicate));
-        }
-
-        public override void remove_where (Invercargill.PredicateDelegate<T> predicate) {
-            //  items.where(predicate).iterate(remove);
-        }
-
-        public void remove(T item) {
-            //  var bucket = buckets.get_or_default((int)bucket_for(item));
-            //  if(bucket == null) 
-            //      return;
-
-            //  foreach (var index in bucket) {
-            //      var result = items[index];
-            //      if(equal_func(result, item)) {
-            //          bucket.remove_first_where(i => i == index);
-            //          items.remove(index);
-            //      }
-            //  }
-        }
-
-        public void remove_all(Enumerable<T> items) {
-            items.iterate(remove);
-        }
-
-        public void remove_except(Enumerable<T> items) {
-            var other = items.to_set(hash_func, equal_func);
-            remove_where(i => !other.has(i));
-        }
-
-        public bool has(T item) {
-            //  var bucket = buckets.get_or_default((int)bucket_for(item));
-            //  return bucket != null && bucket.any(i => equal_func(i, item));
-            return false;
-        }
-
-
-
-    }
-}

+ 24 - 55
src/lib/Collections/Vector.vala

@@ -1,6 +1,6 @@
 namespace Invercargill {
 
-    public class Vector<T> : IndexedCollection<T> {
+    public class Vector<T> : Enumerable<T>, ReadOnlyCollection<T>, ReadOnlyAddressable<T>, Collection<T>, Addressable<T> {
 
         private T[] array;
         private int n_items = 0;
@@ -16,7 +16,7 @@ namespace Invercargill {
         }
 
         public override Tracker<T> get_tracker() {
-            return new VectorTracker<T>(this);
+            return new AddressableTracker<T>(this);
         }
 
         public override T[] to_array () {
@@ -36,7 +36,7 @@ namespace Invercargill {
             }
         }
 
-        public override void add(T item) {
+        public void add(T item) {
             lock(array) {
                 ensure_room(1);
                 array_write(n_items, item);
@@ -54,7 +54,7 @@ namespace Invercargill {
             }
         }
 
-        public override T @get(int index) throws IndexError {
+        public new T @get(uint index) throws IndexError {
             IndexError? e = null;
             lock(array) {
                 if(index < 0) {
@@ -70,16 +70,18 @@ namespace Invercargill {
             throw e;
         }
 
-        public T? get_or_default(int index) {
+        public bool try_get(uint index, out T value) {
             lock(array) {
-                if(index < 0 || index >= n_items) {
-                    return null;
+                if(index >= 0 && index < n_items) {
+                    value = array_read(index);
+                    return true;
                 }
-                return array_read(index);
             }
+            value = null;
+            return false;
         }
 
-        public override void @set(int index, T value) throws IndexError {
+        public new void @set(int index, T value) throws IndexError {
             IndexError? e = null;
             lock(array) {
                 if(index < 0) {
@@ -106,19 +108,14 @@ namespace Invercargill {
             return n_items;
         }
 
-        public override void remove(int index) throws IndexError {
+        public void remove_at(int index) throws IndexError {
             var e = remove_internal(index);
             if(e != null) {
                 throw e;
             }
         }
 
-        public bool try_remove(int index) {
-            var e = remove_internal(index);
-            return e == null;
-        }
-
-        private IndexError? remove_internal(int index) {
+        private IndexError? remove_internal(uint index) {
             IndexError? e = null;
             lock(array) {
                 if(index < 0) {
@@ -128,7 +125,7 @@ namespace Invercargill {
                     e = new IndexError.INDEX_EXCEEDS_UPPER_BOUNDS(@"Tried to set index $(index) on a vector with $(n_items) item(s)");
                 }
                 else {
-                    for(int i = index; i < n_items; i++) {
+                    for(uint i = index; i < n_items; i++) {
                         if(i+1 < n_items) {
                             array_write(i, array_read(i+1));
                             continue;
@@ -173,7 +170,7 @@ namespace Invercargill {
             }
         }
 
-        private void array_write(int index, T item) {
+        private void array_write(uint index, T item) {
             if(safe_write != null) {
                 safe_write(array, index, item);
                 return;
@@ -181,14 +178,14 @@ namespace Invercargill {
             array[index] = item;
         }
 
-        private T array_read(int index) {
+        private T array_read(uint index) {
             if(safe_read != null) {
                 return safe_read(array, index);
             }
             return array[index];
         }
 
-        public override int index_of(PredicateDelegate<T> predicate) {
+        public uint? first_index_of(PredicateDelegate<T> predicate) {
             var i = -1;
             foreach (var item in this) {
                 i++;
@@ -196,52 +193,24 @@ namespace Invercargill {
                     return i;
                 }
             }
-            return -1;
+            return null;
         }
 
-        public override void remove_first_where(Invercargill.PredicateDelegate<T> predicate) {
-            remove_internal(index_of(predicate));
+        public void remove_first_where(Invercargill.PredicateDelegate<T> predicate) {
+            remove_internal(first_index_of(predicate));
         }
 
-        public override void remove_where(Invercargill.PredicateDelegate<T> predicate) {
+        public void remove_all_where(Invercargill.PredicateDelegate<T> predicate) {
             with_positions()
                 .where(i => predicate(i.item))
                 .select<int>(i => i.position)
                 .iterate(i => remove_internal(i));
         }
 
-        private class VectorTracker<T> : Tracker<T> {
-
-            private T? next_item = null;
-            private bool got_next = false;
-            private int index = 0;
-            private Vector<T> vector;
-
-            public VectorTracker(Vector<T> vec) {
-                vector = vec;
-            }
-
-            public override bool has_next() {
-                if(got_next) {
-                    return true;
-                }
-                try {
-                    next_item = vector.get(index);
-                    got_next = true;
-                    return true;
-                }
-                catch(IndexError e) {
-                    return false;
-                }
-            }
-            public override T get_next() {
-                var item = next_item;
-                next_item = null;
-                got_next = false;
-                index++;
-                return item;
-            }
 
+        public void clear() {
+            n_items = 0;
+            array = new T[INITIAL_SIZE];
         }
     }
 

+ 5 - 5
src/lib/Enumerable.vala

@@ -417,19 +417,19 @@ namespace Invercargill {
 
         public virtual Dictionary<TKey, T> to_dictionary<TKey>(TransformDelegate<T, TKey> key_selecter, HashDelegate<TKey>? key_hash_func = null, EqualityDelegate<TKey>? key_equal_func = null) {
             var dict = new Dictionary<TKey, T>(key_hash_func, key_equal_func);       
-            dict.set_all(select<KeyValuePair<TKey, T>>(i => new KeyValuePair<TKey, T>(key_selecter(i), i)));
+            iterate(i => dict.add(key_selecter(i), i));
             return dict;
         }
 
         public virtual Dictionary<TKey, TValue> select_to_dictionary<TKey, TValue>(TransformDelegate<T, TKey> key_selecter, TransformDelegate<T, TValue> value_selecter, HashDelegate<TKey>? key_hash_func = null, EqualityDelegate<TKey>? key_equal_func = null) {
             var dict = new Dictionary<TKey, T>(key_hash_func, key_equal_func);       
-            dict.set_all(select<KeyValuePair<TKey, T>>(i => new KeyValuePair<TKey, T>(key_selecter(i), value_selecter(i))));
+            iterate(i => dict.add(key_selecter(i), value_selecter(i)));
             return dict;
         }
 
-        public virtual Set<T> to_set(HashDelegate<T>? hash_func = null, EqualityDelegate<T>? equal_func = null) {
-            var @set = new Set<T>(hash_func, equal_func);       
-            @set.add_all(this);
+        public virtual HashSet<T> to_hash_set(HashDelegate<T>? hash_func = null, EqualityDelegate<T>? equal_func = null) {
+            var @set = new HashSet<T>(hash_func, equal_func);       
+            @set.union_with(this);
             return @set;
         }
 

+ 2 - 2
src/lib/EnumerableProxy.vala

@@ -202,8 +202,8 @@ namespace Invercargill {
         public override Enumerable<PositionItemPair<T>> with_positions() {
             return inner.with_positions();
         }
-        public override Set<T> to_set(HashDelegate<T>? hash_func = null, EqualityDelegate<T>? equal_func = null) {
-            return inner.to_set(hash_func, equal_func);
+        public override HashSet<T> to_hash_set(HashDelegate<T>? hash_func = null, EqualityDelegate<T>? equal_func = null) {
+            return inner.to_hash_set(hash_func, equal_func);
         }
         public override Elements to_elements() {
             return inner.to_elements();

+ 3 - 1
src/lib/Interfaces/Addressable.vala

@@ -1,8 +1,10 @@
 namespace Invercargill {
 
-    public interface Addressable<T> : ReadOnlyAddressable<T>, Enumerable<T> {
+    [GenericAccessors]
+    public interface Addressable<T> : ReadOnlyAddressable<T> {
 
         public abstract void @set(int index, T item) throws IndexError;
+        public abstract void remove_at(int index) throws IndexError;
 
     }
 

+ 4 - 3
src/lib/Interfaces/Associative.vala

@@ -1,10 +1,11 @@
 namespace Invercargill {
 
-    public interface Associative<TKey, TValue> : ReadOnlyAssociative<TKey, TValue>, Collection<KeyValuePair<TKey, TValue>>, Enumerable<KeyValuePair<TKey, TValue>> {
+    [GenericAccessors]
+    public interface Associative<TKey, TValue> : ReadOnlyAssociative<TKey, TValue> {
 
         public abstract void @set(TKey key, TValue value);
-        public abstract new bool add(TKey key, TValue value);
-        public abstract new bool remove(TKey key);
+        public abstract bool add(TKey key, TValue value);
+        public abstract bool remove(TKey key, out TValue? value);
 
     }
 

+ 7 - 2
src/lib/Interfaces/Collection.vala

@@ -1,11 +1,11 @@
 namespace Invercargill {
 
-    public interface Collection<T> : ReadOnlyCollection<T>, Enumerable<T> {
+    [GenericAccessors]
+    public interface Collection<T> : ReadOnlyCollection<T> {
 
         public abstract void add(T item);
         public abstract void remove_first_where(PredicateDelegate<T> predicate);
         public abstract void remove_all_where(PredicateDelegate<T> predicate);
-        public abstract void remove(T item, EqualityDelegate<T>? equator = null);
         public abstract void clear();
         
         public virtual void add_all(Enumerable<T> items) {
@@ -16,6 +16,11 @@ namespace Invercargill {
             items.iterate(i => remove(i, equator));
         }
 
+        public virtual void remove(T item, Invercargill.EqualityDelegate<T>? equator = null) {
+            var func = equator ?? Operators.equality<T>();
+            remove_first_where(i => func(i, item));
+        }
+
     }
     
 }

+ 16 - 2
src/lib/Interfaces/ReadOnlyAddressable.vala

@@ -1,10 +1,24 @@
 namespace Invercargill {
 
-    public interface ReadOnlyAddressable<T> : ReadOnlyCollection<T>, Enumerable<T> {
+    [GenericAccessors]
+    public interface ReadOnlyAddressable<T> : ReadOnlyCollection<T> {
 
         public abstract T @get(uint index) throws IndexError;
+        public abstract bool try_get(uint index, out T value);
         public abstract uint? first_index_of(PredicateDelegate<T> predicate);
-        public abstract uint? index_of(T item, EqualityDelegate<T>? equator = null);
+        public virtual uint? index_of(T item, EqualityDelegate<T>? equator = null) {
+            var func = equator ?? Operators.equality<T>();
+            return first_index_of(i => func(i, item));
+        }
+
+        
+        public virtual T? get_or_default(uint index) {
+            T value;
+            if(try_get(index, out value)) {
+                return value;
+            }
+            return null;
+        }
 
     }
 

+ 18 - 4
src/lib/Interfaces/ReadOnlyAssociative.vala

@@ -1,14 +1,28 @@
 namespace Invercargill {
 
-    public interface ReadOnlyAssociative<TKey, TValue> : ReadOnlyCollection<KeyValuePair<TKey, TValue>>, KeyValues<TKey, TValue>, Enumerable<KeyValuePair<TKey,TValue>> {
+    [GenericAccessors]
+    public interface ReadOnlyAssociative<TKey, TValue> : ReadOnlyCollection<KeyValuePair<TKey, TValue>> {
 
-        public abstract TValue @get(TKey key) throws IndexError;
         public abstract bool try_get(TKey key, out TValue value);
-        public abstract TValue? get_or_default(TKey key);
         public abstract bool has(TKey key);
         public abstract Enumerable<TKey> keys { owned get; }
-        public abstract Enumerable<TKey> values { owned get; }
+        public abstract Enumerable<TValue> values { owned get; }
+
+        public virtual TValue @get(TKey key) throws IndexError {
+            TValue value;
+            if(try_get(key, out value)) {
+                return value;
+            }
+            throw new IndexError.KEY_NOT_FOUND(@"Key not found in the associative collection");
+        }
         
+        public virtual TValue? get_or_default(TKey key) {
+            TValue value;
+            if(try_get(key, out value)) {
+                return value;
+            }
+            return null;
+        }
 
     }
 }

+ 5 - 2
src/lib/Interfaces/ReadOnlyCollection.vala

@@ -1,9 +1,12 @@
 namespace Invercargill {
 
+    [GenericAccessors]
     public interface ReadOnlyCollection<T> : Enumerable<T> {
         
-        public abstract int size { get; }
-        public abstract bool contains(T item);
+        public virtual bool contains(T item, EqualityDelegate<T>? equator = null) {
+            var func = equator ?? Operators.equality<T>();
+            return any(i => func(i, item));
+        }
 
     }
 

+ 38 - 0
src/lib/Interfaces/ReadOnlySet.vala

@@ -0,0 +1,38 @@
+namespace Invercargill {
+
+    [GenericAccessors]
+    public interface ReadOnlySet<T> : ReadOnlyCollection<T> {
+
+        public abstract bool has(T item);
+        public abstract bool try_find(T search, out T item);
+
+        public virtual bool is_proper_subset_of(Enumerable<T> other) {
+            return false;
+        }
+        public virtual bool is_subset_of(Enumerable<T> other) {
+            return false;
+        }
+        public virtual bool is_proper_superset_of(Enumerable<T> other) {
+            return false;
+        }
+        public virtual bool is_superset_of(Enumerable<T> other) {
+            return false;
+        }
+        public virtual bool overlaps(Enumerable<T> other) {
+            return false;
+        }
+        public virtual bool equals(Enumerable<T> other) {
+            return false;
+        }
+
+        public virtual T? find(T search) {
+            T? item;
+            if(try_find(search, out item)) {
+                return item;
+            }
+            return null;
+        }
+
+    }
+
+}

+ 32 - 0
src/lib/Interfaces/Set.vala

@@ -0,0 +1,32 @@
+namespace Invercargill {
+
+    [GenericAccessors]
+    public interface Set<T> : ReadOnlySet<T> {
+
+        public abstract void @set(T item);
+        public abstract T? remove(T item);
+        public abstract bool add(T item);
+        public abstract void clear();
+
+        public virtual void union_with(Enumerable<T> items) {
+            items.iterate(i => add(i));
+        }
+
+        public virtual void except_with(Enumerable<T> items) {
+            items.iterate(i => remove(i));
+        }
+
+        public virtual void symmetric_except_with(Enumerable<T> items) {
+            var other = items.cache();
+            var to_remove = other.where(i => has(i)).to_series();
+            union_with(other);
+            except_with(to_remove);
+        }
+
+        public virtual void intersect_with(Enumerable<T> items) {
+            except_with(items.where(i => !has(i)));
+        }
+
+    }
+
+}

+ 1 - 1
src/lib/Modifiers/CacheEnumerable.vala

@@ -14,7 +14,7 @@ namespace Invercargill {
 
         public override Tracker<T> get_tracker () {
             var i = 0;
-            return new LambdaTracker<T>(() => has_nth(i), () => vector.get_or_default(i++));
+            return new AssertingLambdaTracker<T>(() => has_nth(i), () => vector[i++]);
         }
 
         private bool has_nth(int n) {

+ 1 - 1
src/lib/Promotions/AttemptEnumerable.vala

@@ -90,7 +90,7 @@ namespace Invercargill {
         }
 
         public new Set<T> to_set(HashDelegate<T>? hash_func = null, EqualityDelegate<T>? equal_func = null) throws Error {
-            var @set = new Set<T>(hash_func, equal_func);       
+            var @set = new HashSet<T>(hash_func, equal_func);       
             iterate(i => @set.add(i));
             return @set;
         }

+ 1 - 1
src/lib/PropertyMapper.vala

@@ -26,7 +26,7 @@ namespace Invercargill {
             this.constructor = constructor;
         }
 
-        public void map_into(T object, KeyValues<string, Element> properties) throws Error {
+        public void map_into(T object, ReadOnlyAssociative<string, Element> properties) throws Error {
             foreach (var mapping in mappings) {
                 var exists = properties.has(mapping.name);
                 if(mapping.undefined_setter != null && !exists) {

+ 26 - 26
src/lib/Safety.vala

@@ -1,10 +1,10 @@
 
 namespace Invercargill {
 
-    internal delegate T SafeReadFunc<T>(T[] array, int index);
-    internal delegate void SafeWriteFunc<T>(T[] array, int index, T value);
+    internal delegate T SafeReadFunc<T>(T[] array, uint index);
+    internal delegate void SafeWriteFunc<T>(T[] array, uint index, T value);
 
-    internal T safely_read_array<T> (T[] array, int index) {
+    internal T safely_read_array<T> (T[] array, uint index) {
         var t = typeof (T);
         if (t == typeof (bool)) {
             return ((bool[])array)[index];
@@ -44,7 +44,7 @@ namespace Invercargill {
         }
     }
 
-    internal void safely_assign_to_array<T> (T[] array, int index, T value) {
+    internal void safely_assign_to_array<T> (T[] array, uint index, T value) {
         var t = typeof (T);
         if (t == typeof (bool)) {
             ((bool[])array)[index] = (bool)value;
@@ -85,71 +85,71 @@ namespace Invercargill {
     }
 
 
-    internal bool safely_read_bool_from_array(bool[] array, int index) {
+    internal bool safely_read_bool_from_array(bool[] array, uint index) {
         return ((bool[])array)[index];
     }
-    internal char safely_read_char_from_array(char[] array, int index) {
+    internal char safely_read_char_from_array(char[] array, uint index) {
         return ((char[])array)[index];
     }
-    internal uchar safely_read_uchar_from_array(uchar[] array, int index) {
+    internal uchar safely_read_uchar_from_array(uchar[] array, uint index) {
         return ((uchar[])array)[index];
     }
-    internal int safely_read_int_from_array(int[] array, int index) {
+    internal int safely_read_int_from_array(int[] array, uint index) {
         return ((int[])array)[index];
     }
-    internal uint safely_read_uint_from_array(uint[] array, int index) {
+    internal uint safely_read_uint_from_array(uint[] array, uint index) {
         return ((uint[])array)[index];
     }
-    internal int64 safely_read_int64_from_array(int64[] array, int index) {
+    internal int64 safely_read_int64_from_array(int64[] array, uint index) {
         return ((int64[])array)[index];
     }
-    internal uint64 safely_read_uint64_from_array(uint64[] array, int index) {
+    internal uint64 safely_read_uint64_from_array(uint64[] array, uint index) {
         return ((uint64[])array)[index];
     }
-    internal long safely_read_long_from_array(long[] array, int index) {
+    internal long safely_read_long_from_array(long[] array, uint index) {
         return ((long[])array)[index];
     }
-    internal ulong safely_read_ulong_from_array(ulong[] array, int index) {
+    internal ulong safely_read_ulong_from_array(ulong[] array, uint index) {
         return ((ulong[])array)[index];
     }
-    internal float safely_read_float_from_array(float?[] array, int index) {
+    internal float safely_read_float_from_array(float?[] array, uint index) {
         return ((float?[])array)[index];
     }
-    internal double? safely_read_double_from_array(double?[] array, int index) {
+    internal double? safely_read_double_from_array(double?[] array, uint index) {
         return ((double?[])array)[index];
     }
 
-    internal void safely_assign_bool_to_array(bool[] array, int index, bool value) {
+    internal void safely_assign_bool_to_array(bool[] array, uint index, bool value) {
         ((bool[])array)[index] = (bool)value;
     }
-    internal void safely_assign_char_to_array(char[] array, int index, char value) {
+    internal void safely_assign_char_to_array(char[] array, uint index, char value) {
         ((char[])array)[index] = (char) value;
     }
-    internal void safely_assign_uchar_to_array(uchar[] array, int index, uchar value) {
+    internal void safely_assign_uchar_to_array(uchar[] array, uint index, uchar value) {
         ((uchar[])array)[index] = (uchar)value;
     }
-    internal void safely_assign_int_to_array(int[] array, int index, int value) {
+    internal void safely_assign_int_to_array(int[] array, uint index, int value) {
         ((int[])array)[index] = (int)value;
     }
-    internal void safely_assign_uint_to_array(uint[] array, int index, uint value) {
+    internal void safely_assign_uint_to_array(uint[] array, uint index, uint value) {
         ((uint[])array)[index] = (uint)value;
     }
-    internal void safely_assign_int64_to_array(int64[] array, int index, int64 value) {
+    internal void safely_assign_int64_to_array(int64[] array, uint index, int64 value) {
         ((int64[])array)[index] = (int64)value;
     }
-    internal void safely_assign_uint64_to_array(uint64[] array, int index, uint64 value) {
+    internal void safely_assign_uint64_to_array(uint64[] array, uint index, uint64 value) {
         ((uint64[])array)[index] = (uint64)value;
     }
-    internal void safely_assign_long_to_array(long[] array, int index, long value) {
+    internal void safely_assign_long_to_array(long[] array, uint index, long value) {
         ((long[])array)[index] = (long)value;
     }
-    internal void safely_assign_ulong_to_array(ulong[] array, int index, ulong value) {
+    internal void safely_assign_ulong_to_array(ulong[] array, uint index, ulong value) {
         ((ulong[])array)[index] = (ulong)value;
     }
-    internal void safely_assign_float_to_array(float?[] array, int index, float? value) {
+    internal void safely_assign_float_to_array(float?[] array, uint index, float? value) {
         ((float?[])array)[index] = (float?)value;
     }
-    internal void safely_assign_double_to_array(double?[] array, int index, double? value) {
+    internal void safely_assign_double_to_array(double?[] array, uint index, double? value) {
         ((double?[])array)[index] = (double?)value;
     }
 

+ 56 - 0
src/lib/Tracker.vala

@@ -61,6 +61,62 @@ namespace Invercargill {
         public override T get_next () {
             return get_next_func();
         }
+    }
+
+    public class AssertingLambdaTracker<T> : Tracker<T> {
+        public delegate bool HasNextDelegate() throws Error;
+        public delegate T GetNextDelegate<T>() throws Error;
+
+        private HasNextDelegate has_next_func;
+        private GetNextDelegate get_next_func;
+
+        public AssertingLambdaTracker(owned HasNextDelegate has_next_delegate, owned GetNextDelegate<T> get_next_delegate) {
+            has_next_func = (owned)has_next_delegate;
+            get_next_func = (owned)get_next_delegate;
+        }
+
+        public override bool has_next () {
+            try {
+                return has_next_func();
+            }
+            catch(Error e) {
+                assert_no_error(e);
+            }
+            assert_not_reached();
+        }
+        public override T get_next () {
+            try {
+                return get_next_func();
+            }
+            catch(Error e) {
+                assert_no_error(e);
+            }
+            assert_not_reached();
+        }
+    }
+
+    public class AddressableTracker<T> : Tracker<T> {
+        private uint index = 0;
+        private ReadOnlyAddressable<T> addressable;
+
+        public AddressableTracker(ReadOnlyAddressable<T> addressable) {
+            this.addressable = addressable;
+        }
+
+        public override bool has_next() {
+            return index < this.addressable.count();
+        }
+        public override T get_next() {
+            try{
+                var item = this.addressable[index];
+                index++;
+                return item;
+            }
+            catch(IndexError e) {
+                assert_no_error(e);
+            }
+            assert_not_reached();
+        }
 
     }
 

+ 3 - 2
src/lib/meson.build

@@ -67,19 +67,20 @@ sources += files('Promotions/PropertyGroupEnumerable.vala')
 sources += files('Interfaces/ReadOnlyCollection.vala')
 sources += files('Interfaces/ReadOnlyAssociative.vala')
 sources += files('Interfaces/ReadOnlyAddressable.vala')
+sources += files('Interfaces/ReadOnlySet.vala')
 sources += files('Interfaces/Collection.vala')
 sources += files('Interfaces/Associative.vala')
 sources += files('Interfaces/Addressable.vala')
+sources += files('Interfaces/Set.vala')
 
 sources += files('Collections/Series.vala')
 sources += files('Collections/Fifo.vala')
 sources += files('Collections/BinaryData.vala')
 sources += files('Collections/Vector.vala')
-sources += files('Collections/Set.vala')
+sources += files('Collections/HashSet.vala')
 
 sources += files('Associative/Dictionary.vala')
 sources += files('Associative/Index.vala')
-sources += files('Associative/KeyValues.vala')
 sources += files('Associative/Properties.vala')
 
 sources += files('Operators/Comparison.vala')

+ 25 - 0
src/tests/Integration/Cache.vala

@@ -5,6 +5,11 @@ void cache_tests() {
 
 
     Test.add_func("/invercargill/operator/cache", () => {
+
+        print("Cl1\n");
+        new Cl1<int>();
+        
+        print("Done\n");
         var runs = 0;
         var enumerable = range(0, 64).act(() => runs++).cache().assert_promotion<SignedNativeIntegers>();
 
@@ -33,4 +38,24 @@ void cache_tests() {
 
     });
 
+}
+
+class Cl1<T> : Enumerable<T>, ReadOnlyCollection<T>, Collection<T> {
+    public void add(T item) {
+        assert_not_reached();
+    }
+    public void clear() {
+        assert_not_reached();
+    }
+    public void remove_all_where(Invercargill.PredicateDelegate<T> predicate) {
+        assert_not_reached();
+    }
+    public void remove_first_where(Invercargill.PredicateDelegate<T> predicate) {
+        assert_not_reached();
+    }
+    public override Invercargill.Tracker<T> get_tracker() {
+        assert_not_reached();
+    }
+
+
 }

+ 8 - 3
src/tests/Integration/Vector.vala

@@ -107,10 +107,15 @@ void vector_tests() {
         var expected = new int[] { 1, 8, 2, 4, 6, 3, 10, 3, 7 };
         var vector = Convert.ate(items).to_vector();
 
-        assert(vector.try_remove(5));
-        assert(vector.count() == 9);
+        try {
+            vector.remove_at(5);
+            assert(vector.count() == 9);
+            assert(vector.matches(Convert.ate(expected), (a, b) => a == b));
+        }
+        catch(Error e) {
+            assert_no_error(e);
+        }
 
-        assert(vector.matches(Convert.ate(expected), (a, b) => a == b));
     });
 
     Test.add_func("/invercargill/structure/vector/last/no-condition", () => {

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

@@ -3,5 +3,5 @@ using Invercargill;
 void dictionary_speed_test() {
     var dict = new Dictionary<int, int>();
     var view = dict.select<int>(i => i.value);
-    speed_test_runner_int("Dictionary", view, i => dict[i] = i, i => dict.set_all(i.select<KeyValuePair<int, int>>(v => new KeyValuePair<int, int>(v, v))));
+    speed_test_runner_int("Dictionary", view, i => dict[i] = i, i => i.iterate(ii => dict.set(ii, ii)));
 }

+ 2 - 2
src/tests/Speed/Set.vala

@@ -1,6 +1,6 @@
 using Invercargill;
 
 void set_speed_test() {
-    var @set = new Set<int>();
-    speed_test_runner_int("Set", @set, i => @set.add(i), i => @set.add_all(i));
+    var @set = new HashSet<int>();
+    speed_test_runner_int("Set", @set, i => @set.add(i), i => @set.union_with(i));
 }