#region License Information
/* HeuristicLab
* Copyright (C) 2002-2018 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
}
}