#region License Information /* HeuristicLab * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Collections { [StorableClass] [Serializable] public class ObservableSet : IObservableSet { [Storable] protected HashSet set; #region Properties public IEqualityComparer Comparer { get { return set.Comparer; } } public int Count { get { return set.Count; } } bool ICollection.IsReadOnly { get { return ((ICollection)set).IsReadOnly; } } #endregion #region Constructors public ObservableSet() { set = new HashSet(); } public ObservableSet(IEnumerable collection) { set = new HashSet(collection); } public ObservableSet(IEqualityComparer comparer) { set = new HashSet(comparer); } public ObservableSet(IEnumerable collection, IEqualityComparer comparer) { set = new HashSet(collection, comparer); } [StorableConstructor] protected ObservableSet(bool deserializing) { } #endregion #region Access public bool Contains(T item) { return set.Contains(item); } public bool IsProperSubsetOf(IEnumerable other) { return set.IsProperSubsetOf(other); } public bool IsProperSupersetOf(IEnumerable other) { return set.IsProperSupersetOf(other); } public bool IsSubsetOf(IEnumerable other) { return set.IsSubsetOf(other); } public bool IsSupersetOf(IEnumerable other) { return set.IsSupersetOf(other); } public bool Overlaps(IEnumerable other) { return set.Overlaps(other); } public bool SetEquals(IEnumerable other) { return set.SetEquals(other); } #endregion #region Manipulation public bool Add(T item) { if (set.Add(item)) { OnPropertyChanged("Count"); OnItemsAdded(new T[] { item }); return true; } return false; } void ICollection.Add(T item) { Add(item); } public void ExceptWith(IEnumerable other) { if (other == null) throw new ArgumentNullException(); List items = new List(); foreach (T item in other) { if (set.Remove(item)) items.Add(item); } if (items.Count > 0) { OnPropertyChanged("Count"); OnItemsRemoved(items); } } public void IntersectWith(IEnumerable other) { if (other == null) throw new ArgumentNullException(); HashSet items = new HashSet(); foreach (T item in set) { if (!other.Contains(item)) items.Add(item); } if (items.Count > 0) { set.ExceptWith(items); OnPropertyChanged("Count"); OnItemsRemoved(items); } } public bool Remove(T item) { if (set.Remove(item)) { OnPropertyChanged("Count"); OnItemsRemoved(new T[] { item }); return true; } return false; } public int RemoveWhere(Predicate match) { if (match == null) throw new ArgumentNullException(); HashSet items = new HashSet(); foreach (T item in set) { if (match(item)) items.Add(item); } if (items.Count > 0) { set.ExceptWith(items); OnPropertyChanged("Count"); OnItemsRemoved(items); } return items.Count; } public void SymmetricExceptWith(IEnumerable other) { if (other == null) throw new ArgumentNullException(); List addedItems = new List(); List removedItems = new List(); foreach (T item in other) { if (set.Contains(item)) { set.Remove(item); removedItems.Add(item); } else { set.Add(item); addedItems.Add(item); } } if ((addedItems.Count > 0) || (removedItems.Count > 0)) { OnPropertyChanged("Count"); if (addedItems.Count > 0) OnItemsAdded(addedItems); if (removedItems.Count > 0) OnItemsRemoved(removedItems); } } public void UnionWith(IEnumerable other) { if (other == null) throw new ArgumentNullException(); List items = new List(); foreach (T item in other) { if (set.Add(item)) { items.Add(item); } } if (items.Count > 0) { OnPropertyChanged("Count"); OnItemsAdded(items); } } public void Clear() { if (set.Count > 0) { T[] items = new T[set.Count]; set.CopyTo(items); set.Clear(); OnPropertyChanged("Count"); OnCollectionReset(new T[0], items); } } #endregion #region Conversion public ReadOnlyObservableSet AsReadOnly() { return new ReadOnlyObservableSet(this); } public void CopyTo(T[] array) { set.CopyTo(array); } public void CopyTo(T[] array, int arrayIndex) { set.CopyTo(array, arrayIndex); } public void CopyTo(T[] array, int arrayIndex, int count) { set.CopyTo(array, arrayIndex, count); } #endregion #region Enumeration public IEnumerator GetEnumerator() { return set.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return set.GetEnumerator(); } #endregion #region Helpers public void TrimExcess() { set.TrimExcess(); } #endregion #region Events [field: NonSerialized] public event CollectionItemsChangedEventHandler ItemsAdded; protected virtual void OnItemsAdded(IEnumerable items) { CollectionItemsChangedEventHandler handler = ItemsAdded; if (handler != null) handler(this, new CollectionItemsChangedEventArgs(items)); } [field: NonSerialized] public event CollectionItemsChangedEventHandler ItemsRemoved; protected virtual void OnItemsRemoved(IEnumerable items) { CollectionItemsChangedEventHandler handler = ItemsRemoved; if (handler != null) handler(this, new CollectionItemsChangedEventArgs(items)); } [field: NonSerialized] public event CollectionItemsChangedEventHandler CollectionReset; protected virtual void OnCollectionReset(IEnumerable items, IEnumerable oldItems) { CollectionItemsChangedEventHandler handler = CollectionReset; if (handler != null) handler(this, new CollectionItemsChangedEventArgs(items, oldItems)); } [field: NonSerialized] public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } #endregion } }