#region CPL License /* Nuclex Framework Copyright (C) 2002-2014 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library 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 IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #endregion using System; using System.Collections.Generic; using System.Collections; namespace Nuclex.Support.Collections { partial class MultiDictionary { /// /// Provides access to the values stored in a multi dictionary as a collection /// private class ValueCollection : ICollection, ICollection { #region class Enumerator /// Enumerates the values stored in a multi dictionary private class Enumerator : IEnumerator { /// Initializes a new enumerator /// Value collections being enumerated public Enumerator(ICollection> valueCollections) { this.valueCollections = valueCollections; Reset(); } /// Immediately releases all resources owned by the instance public void Dispose() { if(this.currentValue != null) { this.currentValue.Dispose(); this.currentValue = null; } if(this.currentCollection != null) { this.currentCollection.Dispose(); this.currentCollection = null; } } /// The current value the enumerator is pointing at public TValue Current { get { if(this.currentValue == null) { throw new InvalidOperationException("Enumerator is not on a valid position"); } return this.currentValue.Current; } } /// Advances the enumerator to the next item /// /// True if there was a next item, false if the enumerator reached the end /// public bool MoveNext() { if(this.currentCollection == null) { return false; } for(; ; ) { // Try to move the enumerator in the current key's list to the next item if(this.currentValue != null) { if(this.currentValue.MoveNext()) { return true; // We found the next item } else { this.currentValue.Dispose(); } } // Enumerator for the current key's list reached the end, go to the next key if(this.currentCollection.MoveNext()) { this.currentValue = this.currentCollection.Current.GetEnumerator(); } else { this.currentValue = null; // Guaranteed to be disposed already this.currentCollection.Dispose(); this.currentCollection = null; return false; } } } /// Resets the enumerator to its initial position public void Reset() { if(this.currentValue != null) { this.currentValue.Dispose(); this.currentValue = null; } if(this.currentCollection != null) { this.currentCollection.Dispose(); } this.currentCollection = valueCollections.GetEnumerator(); } #region IEnumerator implementation /// The current entry the enumerator is pointing at object IEnumerator.Current { get { return Current; } } #endregion // IEnumerator implementation /// Value collections being enumerated private ICollection> valueCollections; /// The current value collection the enumerator is in private IEnumerator> currentCollection; /// Current value in the collection the enumerator is in private IEnumerator currentValue; } #endregion // class Enumerator /// Initializes a new multi dictionary value collection /// Dictionary whose values the collection represents public ValueCollection(MultiDictionary dictionary) { this.dictionary = dictionary; this.dictionaryAsICollection = (ICollection)dictionary; } /// Determines whether the collection contains a specific value /// Value for which the collection will be checked /// True if the collection contains the specified value public bool Contains(TValue item) { foreach(ICollection values in this.dictionary.Values) { if(values.Contains(item)) { return true; } } return false; } /// Copies the contents of the collection into an array /// Array the collection contents will be copied into /// /// Starting index in the array where writing will begin /// public void CopyTo(TValue[] array, int arrayIndex) { foreach(ICollection values in this.dictionary.Values) { foreach(TValue value in values) { array[arrayIndex] = value; ++arrayIndex; } } } /// The number of values in the collection public int Count { get { return this.dictionary.count; } } /// Always true since the value collection is read-only public bool IsReadOnly { get { return true; } } /// Returns a new enumerator for the value collection /// A new enumerator for the value collection public IEnumerator GetEnumerator() { return new Enumerator(this.dictionary.typedDictionary.Values); } #region IEnumerator implementation /// Returns a non-typesafe enumerator for the collection /// The non-typesafe collection enumerator IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion // IEnumerator implementation #region ICollection<> implementation /// Throws a NotSupportedException /// Not used void ICollection.Add(TValue item) { throw new NotSupportedException( "Items cannot be added to a dictionary through its values collection" ); } /// Throws a NotSupportedException void ICollection.Clear() { throw new NotSupportedException( "The values collection of a dictionary cannot be cleared" ); } /// Throws a NotSupportedException /// Not used /// Nothing, since the method always throws an exception bool ICollection.Contains(TValue item) { throw new NotImplementedException(); } /// Not supported /// Item that will not be removed /// Nothing because the method throws an exception bool ICollection.Remove(TValue item) { throw new NotSupportedException( "Items cannot be removed from a dictionary through its values collection" ); } #endregion ICollection<> implementation #region ICollection implementation /// Copies the contents of the collection into an array /// Array the collection's contents are copied into /// /// Starting index in the array where writing will begin /// void ICollection.CopyTo(Array array, int arrayIndex) { foreach(ICollection values in this.dictionary.Values) { foreach(TValue value in values) { array.SetValue(value, arrayIndex); ++arrayIndex; } } } /// Whether the dictionary is thread-safe bool ICollection.IsSynchronized { get { return this.dictionaryAsICollection.IsSynchronized; } } /// /// The synchronization root used by the dictionary for thread synchronization /// object ICollection.SyncRoot { get { return this.dictionaryAsICollection.IsSynchronized; } } #endregion // ICollection implementation /// Dictionary whose values the collection represents private MultiDictionary dictionary; /// The dictionary under its ICollection interface private ICollection dictionaryAsICollection; } } } // namespace Nuclex.Support.Collections