Эх сурвалжийг харах

refactor(grouping): replace ReadOnlyGrouped with CategoryIndex interfaces

BREAKING CHANGE: ReadOnlyGrouped interface has been removed and replaced
with CategoryIndex and ReadOnlyCategoryIndex interfaces along with new
Catalogue and SetCatalogue implementations
Billy Barrow 4 долоо хоног өмнө
parent
commit
168c929abd

+ 183 - 0
src/lib/DataStructures/Catalogue.vala

@@ -0,0 +1,183 @@
+using Invercargill.DataStructures;
+
+namespace Invercargill {
+
+    public class Catalogue<TKey, TValue> : Enumerable<Grouping<TKey, TValue>>, Lot<Grouping<TKey, TValue>>, ReadOnlyCategoryIndex<TKey, TValue>, CategoryIndex<TKey, TValue> {
+
+        public Enumerable<TKey> keys { owned get { return lookup.keys; } }
+        public Enumerable<TValue> values { owned get { return lookup.values.select_many<TValue>(g => g); } }
+        public uint length { get { 
+            rw_lock.reader_lock ();
+            var count = item_count; 
+            rw_lock.reader_unlock ();
+            return count;
+        }}
+        
+        private Dictionary<TKey, Series<TValue>> lookup;
+        private uint item_count;
+        private RWLock rw_lock;
+
+        public Catalogue(HashDelegate<TKey>? key_hash_func = null, EqualityDelegate<TKey>? key_equal_func = null) {
+            lookup = new Dictionary<TKey, Series<TValue>> (key_hash_func, key_equal_func);
+            rw_lock = RWLock();
+        }
+
+        public override Tracker<Grouping<TKey, TValue>> get_tracker () {
+            rw_lock.reader_lock ();
+            var result = lookup
+                .select<Grouping<TKey, TValue>>(kv => new Grouping<TKey, TValue>(kv.key, kv.value))
+                .get_tracker();; 
+            rw_lock.reader_unlock ();
+            return result;
+        }
+
+        public override uint? peek_count () {
+            return item_count;
+        }
+
+        public override EnumerableInfo get_info () {
+            return new EnumerableInfo.infer_ultimate (this, EnumerableCategory.IN_MEMORY);
+        }
+
+        public bool try_get (TKey key, out Grouping<TKey, TValue> value) {
+            rw_lock.reader_lock();
+            Series<TValue> series;
+            if(lookup.try_get (key, out series)) {
+                value = new Grouping<TKey, TValue>(key, series);
+                rw_lock.reader_unlock();
+                return true;
+            }
+            rw_lock.reader_unlock();
+            value = null;
+            return false;
+        }
+
+        public bool has (TKey key) {
+            rw_lock.reader_lock();
+            var result = lookup.has(key);
+            rw_lock.reader_unlock();
+            return result;
+        }
+
+        public bool try_get_any (TKey key, out TValue value) {
+            rw_lock.reader_lock();
+            Series<TValue> series;
+            if(lookup.try_get (key, out series) && series.length > 0) {
+                value = series.first_or_default();
+                rw_lock.reader_unlock();
+                return true;
+            }
+            rw_lock.reader_unlock();
+            value = null;
+            return false;
+        }
+
+
+        public new void @set (TKey key, Enumerable<TValue> values) {
+            rw_lock.writer_lock();
+            Series<TValue> series;
+            if(lookup.try_get (key, out series)) {
+                item_count -= series.length;
+            }
+            series = values.to_series();
+            lookup[key] = series;
+            item_count += series.length;
+            rw_lock.writer_unlock();
+        }
+
+        public void add (TKey key, TValue value) {
+            rw_lock.writer_lock ();
+            Series<TValue> series;
+            if(!lookup.try_get (key, out series)) {
+                series = new Series<TValue>();
+                lookup[key] = series;
+            }
+            series.add(value);
+            item_count ++;
+            rw_lock.writer_unlock ();
+        }
+
+        public void add_all (TKey key, Enumerable<TValue> values) {
+            rw_lock.writer_lock ();
+            Series<TValue> series;
+            if(!lookup.try_get (key, out series)) {
+                series = new Series<TValue>();
+                lookup[key] = series;
+            }
+            series.add_all(values.act(i => item_count++));
+            rw_lock.writer_unlock ();
+        }
+
+        public void remove_from (TKey key, TValue item, Invercargill.EqualityDelegate<TValue>? equator = null) {
+            rw_lock.writer_lock ();
+            Series<TValue> series;
+            if(lookup.try_get (key, out series)) {
+                item_count -= series.length;
+                series.remove(item, equator);
+                item_count += series.length;
+                remove_if_empty(key, series);
+            }
+            rw_lock.writer_unlock ();
+        }
+
+        public void remove_all_from (TKey key, Enumerable<TValue> items, Invercargill.EqualityDelegate<TValue>? equator = null) {
+            rw_lock.writer_lock ();
+            Series<TValue> series;
+            if(lookup.try_get (key, out series)) {
+                item_count -= series.length;
+                series.remove_all(items, equator);
+                item_count += series.length;
+                remove_if_empty(key, series);
+            }
+            rw_lock.writer_unlock ();
+        }
+
+        public void remove (TValue item, Invercargill.EqualityDelegate<TValue>? equator = null) {
+            rw_lock.writer_lock ();
+            foreach (var kv in lookup) {
+                item_count -= kv.value.length;
+                kv.value.remove (item, equator);
+                item_count += kv.value.length;
+                remove_if_empty(kv.key, kv.value);
+            }
+            rw_lock.writer_unlock ();
+        }
+
+        public void remove_all (Enumerable<TValue> items, Invercargill.EqualityDelegate<TValue>? equator = null) {
+            rw_lock.writer_lock ();
+            foreach (var kv in lookup) {
+                item_count -= kv.value.length;
+                kv.value.remove_all (items, equator);
+                item_count += kv.value.length;
+                remove_if_empty(kv.key, kv.value);
+            }
+            rw_lock.writer_unlock ();
+        }
+
+        public bool clear_key (TKey key) {
+            rw_lock.writer_lock ();
+            Series<TValue> series;
+            var result = lookup.remove (key, out series);
+            if(result) {
+                item_count -= series.length;
+            }
+            rw_lock.writer_unlock ();
+            return result;
+        }
+
+        public void clear () {
+            rw_lock.writer_lock ();
+            lookup.clear();
+            item_count = 0;
+            rw_lock.writer_unlock ();
+        }
+
+        private void remove_if_empty(TKey key, Series<TValue> series) {
+            if(series.length == 0) {
+                lookup.remove(key);
+            }
+        }
+
+    }
+
+}

+ 0 - 0
src/lib/DataStructures/SetCatalogue.vala


+ 18 - 0
src/lib/Interfaces/CategoryIndex.vala

@@ -0,0 +1,18 @@
+namespace Invercargill {
+
+    [GenericAccessors]
+    public interface CategoryIndex<TKey, TValue> : ReadOnlyCategoryIndex<TKey, TValue> {
+
+        public abstract void @set(TKey key, Enumerable<TValue> values);
+        public abstract void add(TKey key, TValue value);
+        public abstract void add_all(TKey key, Enumerable<TValue> values);
+        public abstract void remove_from(TKey key, TValue item, Invercargill.EqualityDelegate<TValue>? equator = null);
+        public abstract void remove_all_from(TKey key, Enumerable<TValue> items, Invercargill.EqualityDelegate<TValue>? equator = null);
+        public abstract void remove(TValue item, Invercargill.EqualityDelegate<TValue>? equator = null);
+        public abstract void remove_all(Enumerable<TValue> items, Invercargill.EqualityDelegate<TValue>? equator = null);
+        public abstract bool clear_key(TKey key);
+        public abstract void clear();
+
+    }
+
+}

+ 53 - 0
src/lib/Interfaces/ReadOnlyCategoryIndex.vala

@@ -0,0 +1,53 @@
+namespace Invercargill {
+
+    [GenericAccessors]
+    public interface ReadOnlyCategoryIndex<TKey, TValue> : Lot<Grouping<TKey, TValue>> {
+
+        public abstract bool try_get_any(TKey key, out TValue value);
+        public abstract bool try_get(TKey key, out Grouping<TKey, TValue> value);
+        public abstract bool has(TKey key);
+        public abstract Enumerable<TKey> keys { owned get; }
+        public abstract Enumerable<TValue> values { owned get; }
+
+        public virtual TValue @get_any(TKey key) throws IndexError {
+            TValue value;
+            if(try_get_any(key, out value)) {
+                return value;
+            }
+            throw new IndexError.KEY_NOT_FOUND(@"Key not found in the category index");
+        }
+        
+        public virtual TValue? get_any_or_default(TKey key) {
+            TValue value;
+            if(try_get_any(key, out value)) {
+                return value;
+            }
+            return null;
+        }
+
+        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 category index");
+        }
+        
+        public virtual TValue? get_or_default(TKey key) {
+            TValue value;
+            if(try_get(key, out value)) {
+                return value;
+            }
+            return null;
+        }
+
+        public virtual Enumerable<TValue> get_or_empty(TKey key) {
+            Grouping<TKey, TValue> value;
+            if(try_get(key, out value)) {
+                return value;
+            }
+            return Iterate.nothing();
+        }
+
+    }
+}

+ 0 - 34
src/lib/Interfaces/ReadOnlyGrouped.vala

@@ -1,34 +0,0 @@
-
-namespace Invercargill {
-
-    [GenericAccessors]
-    public interface ReadOnlyGrouped<TKey, TValue> : ReadOnlyAssociative<TKey, Group<TKey, TValue>> {
-        public abstract bool try_get_any(TKey key, out TValue value);
-        public abstract Enumerable<TValue> flat_values { owned get; }
-
-        public virtual TValue get_any(TKey key) throws IndexError {
-            TValue value;
-            if(try_get_any(key, out value)) {
-                return value;
-            }
-            throw new IndexError.KEY_NOT_FOUND(@"Key not found in the associative collection");
-        }
-        
-        public virtual TValue? get_any_or_default(TKey key) {
-            TValue value;
-            if(try_get_any(key, out value)) {
-                return value;
-            }
-            return null;
-        }
-
-        public virtual Enumerable<Group<TKey, TValue>> get_or_empty(TKey key) {
-            Enumerable<Group<TKey, TValue>> value;
-            if(try_get_any(key, out value)) {
-                return value;
-            }
-            return null;
-        }
-    }
-
-}

+ 4 - 0
src/lib/meson.build

@@ -97,6 +97,7 @@ sources += files('Interfaces/ReadOnlyAssociative.vala')
 sources += files('Interfaces/ReadOnlyAddressable.vala')
 sources += files('Interfaces/ReadOnlyAddressableBytes.vala')
 sources += files('Interfaces/ReadOnlySet.vala')
+sources += files('Interfaces/ReadOnlyCategoryIndex.vala')
 sources += files('Interfaces/Collection.vala')
 sources += files('Interfaces/Associative.vala')
 sources += files('Interfaces/Addressable.vala')
@@ -105,6 +106,7 @@ sources += files('Interfaces/AddressableCollection.vala')
 sources += files('Interfaces/AddressableBytes.vala')
 sources += files('Interfaces/Properties.vala')
 sources += files('Interfaces/Queue.vala')
+sources += files('Interfaces/CategoryIndex.vala')
 
 sources += files('DataStructures/Series.vala')
 sources += files('DataStructures/Fifo.vala')
@@ -120,6 +122,8 @@ sources += files('DataStructures/Buffer.vala')
 sources += files('DataStructures/RingBuffer.vala')
 sources += files('DataStructures/ImmutableBuffer.vala')
 sources += files('DataStructures/ByteBuffer.vala')
+sources += files('DataStructures/Catalogue.vala')
+sources += files('DataStructures/SetCatalogue.vala')
 
 sources += files('Mapping/Mapper.vala')
 sources += files('Mapping/PropertyMapper.vala')