using System; using System.Collections; using System.Collections.Generic; namespace SmartCoalApplication { /// /// Represents an enumerable collection of items. Each item can only be present /// in the collection once. An item's identity is determined by a combination /// of the return values from its GetHashCode and Equals methods. /// This class is analagous to C++'s std::set template class. /// [Serializable] public class Set : ICloneable, ICollection { private Dictionary dictionary; public static Set Intersect(Set set1, Set set2) { Set intersection = new Set(); foreach (T item in set1) { if (set2.Contains(item)) { intersection.Add(item); } } return intersection; } public static Set Union(Set set1, Set set2) { Set union = new Set(set1); foreach (T item in set2) { if (!union.Contains(item)) { union.Add(item); } } return union; } public static Set Without(Set withUs, Set withoutUs) { Set result = new Set(); foreach (T item in withUs) { if (!withoutUs.Contains(item)) { result.Add(item); } } return result; } public static bool AreEqual(Set set1, Set set2) { if (set1.Count != set2.Count) { // Can't be equal if sizes are different return false; } if (set1.Count == 0) { // Empty sets are equal to each other. // We know that set1.Count=set2.Count, so no need to check set2.Count for 0 as well. return true; } // At this point we know that either everything in set1 is in set2, or // that there is something in set1 which is not in set2. foreach (T item in set1) { if (!set2.Contains(item)) { return false; } } return true; } public bool IsEqualTo(Set set2) { return AreEqual(this, set2); } public bool IsSubsetOf(Set set2) { foreach (T item in this) { if (!set2.Contains(item)) { return false; } } return true; } public Set Without(Set withoutUs) { return Set.Without(this, withoutUs); } /// /// Adds an element to the set. /// /// The object reference to be included in the set. /// item is a null reference /// item is already in the Set public void Add(T item) { try { this.dictionary.Add(item, null); } catch (ArgumentNullException e1) { throw e1; } catch (ArgumentException e2) { throw e2; } } public void AddRange(IEnumerable items) { foreach (T item in items) { Add(item); } } public void AddRange(params T[] items) { AddRange((IEnumerable)items); } /// /// Removes an element from the set. /// /// The object reference to be excluded from the set. /// item is a null reference public bool Remove(T item) { try { this.dictionary.Remove(item); return true; } catch (ArgumentNullException) { return false; } } /// /// Determines whether the Set includes a specific element. /// /// The object reference to check for. /// true if the Set includes item, false if it doesn't. /// item is a null reference. public bool Contains(T item) { try { return this.dictionary.ContainsKey(item); } catch (ArgumentNullException e1) { throw e1; } } /// /// Constructs an empty Set. /// public Set() { this.dictionary = new Dictionary(); } /// /// Constructs a Set with data copied from the given list. /// /// public Set(IEnumerable cloneMe) { this.dictionary = new Dictionary(); foreach (T theObject in cloneMe) { Add(theObject); } } public Set(params T[] items) : this((IEnumerable)items) { } /// /// Constructs a copy of a Set. /// /// The Set to copy from. private Set(Set copyMe) { this.dictionary = new Dictionary(copyMe.dictionary); } #region IEnumerable Members /// /// Returns an IEnumerator that can be used to enumerate through the items in the Set. /// /// An IEnumerator for the Set. IEnumerator IEnumerable.GetEnumerator() { return this.dictionary.Keys.GetEnumerator(); } public IEnumerator GetEnumerator() { return this.dictionary.Keys.GetEnumerator(); } #endregion public Set Clone() { return new Set(this); } #region ICloneable Members /// /// Returns a copy of the Set. The elements in the Set are copied by-reference only. /// /// object ICloneable.Clone() { return Clone(); } #endregion #region ICollection Members /// /// Gets a value indicating whether or not the Set is synchronized (thread-safe). /// public bool IsSynchronized { get { return false; } } /// /// Gets a value indicating how many elements are contained within the Set. /// public int Count { get { return this.dictionary.Count; } } /// /// Copies the Set elements to a one-dimensional Array instance at a specified index. /// /// The one-dimensional Array that is the destination of the objects copied from the Set. The Array must have zero-based indexing. /// The zero-based index in array at which copying begins. /// array is a null reference. /// index is less than zero. /// The array is not one-dimensional, or the array could not contain the objects copied to it. /// The Array does not have enough space, starting from the given offset, to contain all the Set's objects. public void CopyTo(T[] array, int index) { int i = index; if (array == null) { throw new ArgumentNullException("array"); } if (index < 0) { throw new ArgumentOutOfRangeException("index"); } foreach (T o in this) { try { array.SetValue(o, i); } catch (ArgumentException e1) { throw e1; } catch (IndexOutOfRangeException e2) { throw e2; } ++i; } } /// /// Gets an object that can be used to synchronize access to the Set. /// public object SyncRoot { get { return this; } } #endregion /// /// Copies the elements of the Set to a new generic array. /// /// An array of object references. public T[] ToArray() { T[] array = new T[Count]; int index = 0; foreach (T o in this) { array[index] = o; ++index; } return array; } #region ICollection Members public void Clear() { this.dictionary = new Dictionary(); } public bool IsReadOnly { get { return false; } } #endregion } }