|
@@ -0,0 +1,157 @@
|
|
|
+using Invercargill.Convert;
|
|
|
+
|
|
|
+namespace Invercargill {
|
|
|
+
|
|
|
+ public class Set<T> : Collection<T> {
|
|
|
+
|
|
|
+ private HashTable<T, T> hash_table;
|
|
|
+ private HashFunc<T> hash_func;
|
|
|
+ private EqualFunc<T> equal_func;
|
|
|
+
|
|
|
+ public Set(HashFunc<T>? value_hash_func = null, EqualFunc<T>? value_equal_func = null) {
|
|
|
+ hash_func = value_hash_func;
|
|
|
+ equal_func = value_equal_func;
|
|
|
+
|
|
|
+ var key_type = typeof(T);
|
|
|
+ if(hash_func == null) {
|
|
|
+ if(key_type == typeof(string)) {
|
|
|
+ hash_func = GLib.str_hash;
|
|
|
+ }
|
|
|
+ else if(key_type == typeof(int64) || key_type == typeof(uint64)) {
|
|
|
+ hash_func = GLib.int64_hash;
|
|
|
+ }
|
|
|
+ else if(key_type == typeof(int)) {
|
|
|
+ hash_func = GLib.direct_hash;
|
|
|
+ }
|
|
|
+ else if(key_type == typeof(double)) {
|
|
|
+ hash_func = GLib.double_hash;
|
|
|
+ }
|
|
|
+ else if(key_type.is_a(typeof(Hashable))) {
|
|
|
+ hash_func = (k) => ((Hashable)k).hash_code();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(equal_func == null) {
|
|
|
+ if(key_type == typeof(string)) {
|
|
|
+ equal_func = GLib.str_equal;
|
|
|
+ }
|
|
|
+ else if(key_type == typeof(int64) || key_type == typeof(uint64)) {
|
|
|
+ equal_func = GLib.int64_equal;
|
|
|
+ }
|
|
|
+ else if(key_type == typeof(int)) {
|
|
|
+ equal_func = GLib.direct_equal;
|
|
|
+ }
|
|
|
+ else if(key_type == typeof(double)) {
|
|
|
+ equal_func = GLib.double_equal;
|
|
|
+ }
|
|
|
+ else if(key_type.is_a(typeof(Equatable))) {
|
|
|
+ equal_func = (a, b) => ((Equatable<T>)a).equals(b);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ hash_table = new HashTable<T, T>(hash_func, equal_func);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public override Tracker<T> get_tracker () {
|
|
|
+ return Convert.ate(hash_table.get_keys_as_array()).get_tracker();
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void add (T item) {
|
|
|
+ lock(hash_table) {
|
|
|
+ hash_table.set(item, item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void with_lock(Func<Set<T>> action) {
|
|
|
+ lock(hash_table) {
|
|
|
+ action(this);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void add_all (Enumerable<T> items) {
|
|
|
+ lock(hash_table) {
|
|
|
+ if(items.get_type().is_a (typeof(Set))) {
|
|
|
+ if(items == this) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ((Set<T>)items).with_lock((s) => s.hash_table.foreach (i => hash_table.set(i, i)));
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ items.iterate(i => hash_table.set(i, i));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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) {
|
|
|
+ lock(hash_table) {
|
|
|
+ return hash_table.get(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void remove_first_where (Invercargill.PredicateDelegate<T> predicate) {
|
|
|
+ remove(first_or_default(predicate));
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void remove_where (Invercargill.PredicateDelegate<T> predicate) {
|
|
|
+ lock(hash_table) {
|
|
|
+ hash_table.foreach_remove(k => predicate(k));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void remove(T item) {
|
|
|
+ lock(hash_table) {
|
|
|
+ hash_table.remove (item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void remove_all(Enumerable<T> items) {
|
|
|
+ lock(hash_table) {
|
|
|
+ if(items.get_type().is_a (typeof(Set))) {
|
|
|
+ if(items == this) {
|
|
|
+ hash_table.remove_all();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ ((Set<T>)items).with_lock((s) => s.hash_table.foreach (i => hash_table.remove(i)));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ items.iterate(i => hash_table.remove(i));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void remove_except(Enumerable<T> items) {
|
|
|
+ lock(hash_table) {
|
|
|
+ Set<T> other = items.to_set(hash_func, equal_func);
|
|
|
+ hash_table.foreach_remove(i => !other.has(i));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool has(T item) {
|
|
|
+ lock(hash_table) {
|
|
|
+ return hash_table.contains(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+}
|