/* Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using System; using System.Diagnostics; using SCG = System.Collections.Generic; namespace C5 { /// /// A read-only wrapper class for a generic enumerator /// public class GuardedEnumerator : SCG.IEnumerator { #region Fields SCG.IEnumerator enumerator; #endregion #region Constructor /// /// Create a wrapper around a generic enumerator /// /// The enumerator to wrap public GuardedEnumerator(SCG.IEnumerator enumerator) { this.enumerator = enumerator; } #endregion #region IEnumerator Members /// /// Move wrapped enumerator to next item, or the first item if /// this is the first call to MoveNext. /// /// True if enumerator is valid now public bool MoveNext() { return enumerator.MoveNext(); } /// /// Undefined if enumerator is not valid (MoveNext hash been called returning true) /// /// The current item of the wrapped enumerator. public T Current { get { return enumerator.Current; } } #endregion #region IDisposable Members //TODO: consider possible danger of calling through to Dispose. /// /// Dispose wrapped enumerator. /// public void Dispose() { enumerator.Dispose(); } #endregion #region IEnumerator Members object System.Collections.IEnumerator.Current { get { return enumerator.Current; } } void System.Collections.IEnumerator.Reset() { enumerator.Reset(); } #endregion } /// /// A read-only wrapper class for a generic enumerable /// /// This is mainly interesting as a base of other guard classes /// public class GuardedEnumerable : SCG.IEnumerable { #region Fields SCG.IEnumerable enumerable; #endregion #region Constructor /// /// Wrap an enumerable in a read-only wrapper /// /// The enumerable to wrap public GuardedEnumerable(SCG.IEnumerable enumerable) { this.enumerable = enumerable; } #endregion #region SCG.IEnumerable Members /// /// Get an enumerator from the wrapped enumerable /// /// The enumerator (itself wrapped) public SCG.IEnumerator GetEnumerator() { return new GuardedEnumerator(enumerable.GetEnumerator()); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion } /// /// A read-only wrapper for a generic directed enumerable /// /// This is mainly interesting as a base of other guard classes /// public class GuardedDirectedEnumerable : GuardedEnumerable, IDirectedEnumerable { #region Fields IDirectedEnumerable directedenumerable; #endregion #region Constructor /// /// Wrap a directed enumerable in a read-only wrapper /// /// the collection to wrap public GuardedDirectedEnumerable(IDirectedEnumerable directedenumerable) : base(directedenumerable) { this.directedenumerable = directedenumerable; } #endregion #region IDirectedEnumerable Members /// /// Get a enumerable that enumerates the wrapped collection in the opposite direction /// /// The mirrored enumerable public IDirectedEnumerable Backwards() { return new GuardedDirectedEnumerable(directedenumerable.Backwards()); } /// /// Forwards if same, else Backwards /// /// The enumeration direction relative to the original collection. public EnumerationDirection Direction { get { return directedenumerable.Direction; } } #endregion } /// /// A read-only wrapper for an ICollectionValue<T> /// /// This is mainly interesting as a base of other guard classes /// public class GuardedCollectionValue : GuardedEnumerable, ICollectionValue { #region Events /// /// The ListenableEvents value of the wrapped collection /// /// public virtual EventTypeEnum ListenableEvents { get { return collectionvalue.ListenableEvents; } } /// /// The ActiveEvents value of the wrapped collection /// /// public virtual EventTypeEnum ActiveEvents { get { return collectionvalue.ActiveEvents; } } ProxyEventBlock eventBlock; /// /// The change event. Will be raised for every change operation on the collection. /// public event CollectionChangedHandler CollectionChanged { add { (eventBlock ?? (eventBlock = new ProxyEventBlock(this, collectionvalue))).CollectionChanged += value; } remove { if (eventBlock != null) eventBlock.CollectionChanged -= value; } } /// /// The change event. Will be raised for every change operation on the collection. /// public event CollectionClearedHandler CollectionCleared { add { (eventBlock ?? (eventBlock = new ProxyEventBlock(this, collectionvalue))).CollectionCleared += value; } remove { if (eventBlock != null) eventBlock.CollectionCleared -= value; } } /// /// The item added event. Will be raised for every individual addition to the collection. /// public event ItemsAddedHandler ItemsAdded { add { (eventBlock ?? (eventBlock = new ProxyEventBlock(this, collectionvalue))).ItemsAdded += value; } remove { if (eventBlock != null) eventBlock.ItemsAdded -= value; } } /// /// The item added event. Will be raised for every individual addition to the collection. /// public event ItemInsertedHandler ItemInserted { add { (eventBlock ?? (eventBlock = new ProxyEventBlock(this, collectionvalue))).ItemInserted += value; } remove { if (eventBlock != null) eventBlock.ItemInserted -= value; } } /// /// The item removed event. Will be raised for every individual removal from the collection. /// public event ItemsRemovedHandler ItemsRemoved { add { (eventBlock ?? (eventBlock = new ProxyEventBlock(this, collectionvalue))).ItemsRemoved += value; } remove { if (eventBlock != null) eventBlock.ItemsRemoved -= value; } } /// /// The item removed event. Will be raised for every individual removal from the collection. /// public event ItemRemovedAtHandler ItemRemovedAt { add { (eventBlock ?? (eventBlock = new ProxyEventBlock(this, collectionvalue))).ItemRemovedAt += value; } remove { if (eventBlock != null) eventBlock.ItemRemovedAt -= value; } } #endregion #region Fields ICollectionValue collectionvalue; #endregion #region Constructor /// /// Wrap a ICollectionValue<T> in a read-only wrapper /// /// the collection to wrap public GuardedCollectionValue(ICollectionValue collectionvalue) : base(collectionvalue) { this.collectionvalue = collectionvalue; } #endregion #region ICollection Members /// /// Get the size of the wrapped collection /// /// The size public virtual bool IsEmpty { get { return collectionvalue.IsEmpty; } } /// /// Get the size of the wrapped collection /// /// The size public virtual int Count { get { return collectionvalue.Count; } } /// /// The value is symbolic indicating the type of asymptotic complexity /// in terms of the size of this collection (worst-case or amortized as /// relevant). /// /// A characterization of the speed of the /// Count property in this collection. public virtual Speed CountSpeed { get { return collectionvalue.CountSpeed; } } /// /// Copy the items of the wrapped collection to an array /// /// The array /// Starting offset public virtual void CopyTo(T[] a, int i) { collectionvalue.CopyTo(a, i); } /// /// Create an array from the items of the wrapped collection /// /// The array public virtual T[] ToArray() { return collectionvalue.ToArray(); } /// /// Apply a delegate to all items of the wrapped enumerable. /// /// The delegate to apply //TODO: change this to throw an exception? public virtual void Apply(Act a) { collectionvalue.Apply(a); } /// /// Check if there exists an item that satisfies a /// specific predicate in the wrapped enumerable. /// /// A filter delegate /// () defining the predicate /// True is such an item exists public virtual bool Exists(Fun filter) { return collectionvalue.Exists(filter); } /// /// /// /// /// /// public virtual bool Find(Fun filter, out T item) { return collectionvalue.Find(filter, out item); } /// /// Check if all items in the wrapped enumerable satisfies a specific predicate. /// /// A filter delegate /// () defining the predicate /// True if all items satisfies the predicate public virtual bool All(Fun filter) { return collectionvalue.All(filter); } /// /// Create an enumerable, enumerating the items of this collection that satisfies /// a certain condition. /// /// The T->bool filter delegate defining the condition /// The filtered enumerable public virtual SCG.IEnumerable Filter(Fun filter) { return collectionvalue.Filter(filter); } /// /// Choose some item of this collection. /// /// if collection is empty. /// public virtual T Choose() { return collectionvalue.Choose(); } #endregion #region IShowable Members /// /// /// /// /// /// /// public bool Show(System.Text.StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider) { return collectionvalue.Show(stringbuilder, ref rest, formatProvider); } #endregion #region IFormattable Members /// /// /// /// /// /// public string ToString(string format, IFormatProvider formatProvider) { return collectionvalue.ToString(format, formatProvider); } #endregion } /// /// A read-only wrapper for a directed collection /// /// This is mainly interesting as a base of other guard classes /// public class GuardedDirectedCollectionValue : GuardedCollectionValue, IDirectedCollectionValue { #region Fields IDirectedCollectionValue directedcollection; #endregion #region Constructor /// /// Wrap a directed collection in a read-only wrapper /// /// the collection to wrap public GuardedDirectedCollectionValue(IDirectedCollectionValue directedcollection) : base(directedcollection) { this.directedcollection = directedcollection; } #endregion #region IDirectedCollection Members /// /// Get a collection that enumerates the wrapped collection in the opposite direction /// /// The mirrored collection public virtual IDirectedCollectionValue Backwards() { return new GuardedDirectedCollectionValue(directedcollection.Backwards()); } /// /// /// /// /// /// public virtual bool FindLast(Fun predicate, out T item) { return directedcollection.FindLast(predicate, out item); } #endregion #region IDirectedEnumerable Members IDirectedEnumerable IDirectedEnumerable.Backwards() { return Backwards(); } /// /// Forwards if same, else Backwards /// /// The enumeration direction relative to the original collection. public EnumerationDirection Direction { get { return directedcollection.Direction; } } #endregion } /// /// A read-only wrapper for an , /// /// Suitable for wrapping hash tables, /// and /// public class GuardedCollection : GuardedCollectionValue, ICollection { #region Fields ICollection collection; #endregion #region Constructor /// /// Wrap an ICollection<T> in a read-only wrapper /// /// the collection to wrap public GuardedCollection(ICollection collection) : base(collection) { this.collection = collection; } #endregion #region ICollection Members /// /// (This is a read-only wrapper) /// /// True public virtual bool IsReadOnly { get { return true; } } /// /// Speed of wrapped collection public virtual Speed ContainsSpeed { get { return collection.ContainsSpeed; } } /// /// /// /// public virtual int GetUnsequencedHashCode() { return collection.GetUnsequencedHashCode(); } /// /// /// /// /// public virtual bool UnsequencedEquals(ICollection that) { return collection.UnsequencedEquals(that); } /// /// Check if an item is in the wrapped collection /// /// The item /// True if found public virtual bool Contains(T item) { return collection.Contains(item); } /// /// Count the number of times an item appears in the wrapped collection /// /// The item /// The number of copies public virtual int ContainsCount(T item) { return collection.ContainsCount(item); } /// /// /// /// public virtual ICollectionValue UniqueItems() { return new GuardedCollectionValue(collection.UniqueItems()); } /// /// /// /// public virtual ICollectionValue> ItemMultiplicities() { return new GuardedCollectionValue>(collection.ItemMultiplicities()); } /// /// Check if all items in the argument is in the wrapped collection /// /// The items /// /// True if so public virtual bool ContainsAll(SCG.IEnumerable items) where U : T { return collection.ContainsAll(items); } /// /// Search for an item in the wrapped collection /// /// On entry the item to look for, on exit the equivalent item found (if any) /// public virtual bool Find(ref T item) { return collection.Find(ref item); } /// /// /// since this is a read-only wrappper /// /// public virtual bool FindOrAdd(ref T item) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// /// public virtual bool Update(T item) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// /// /// public virtual bool Update(T item, out T olditem) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// /// public virtual bool UpdateOrAdd(T item) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// /// /// public virtual bool UpdateOrAdd(T item, out T olditem) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// /// public virtual bool Remove(T item) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// The value to remove. /// The removed value. /// public virtual bool Remove(T item, out T removeditem) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// public virtual void RemoveAllCopies(T item) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// /// public virtual void RemoveAll(SCG.IEnumerable items) where U : T { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper public virtual void Clear() { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// /// public virtual void RetainAll(SCG.IEnumerable items) where U : T { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// Check wrapped collection for internal consistency /// /// True if check passed public virtual bool Check() { return collection.Check(); } #endregion #region IExtensible Members /// /// False if wrapped collection has set semantics public virtual bool AllowsDuplicates { get { return collection.AllowsDuplicates; } } //TODO: the equalityComparer should be guarded /// /// /// /// public virtual SCG.IEqualityComparer EqualityComparer { get { return collection.EqualityComparer; } } /// /// By convention this is true for any collection with set semantics. /// /// True if only one representative of a group of equal items /// is kept in the collection together with the total count. public virtual bool DuplicatesByCounting { get { return collection.DuplicatesByCounting; } } /// /// True if wrapped collection is empty public override bool IsEmpty { get { return collection.IsEmpty; } } /// /// /// since this is a read-only wrappper /// /// public virtual bool Add(T item) { throw new ReadOnlyCollectionException(); } /// /// /// since this is a read-only wrappper /// void SCG.ICollection.Add(T item) { throw new ReadOnlyCollectionException(); } /// /// /// since this is a read-only wrappper /// /// public virtual void AddAll(SCG.IEnumerable items) where U : T { throw new ReadOnlyCollectionException(); } #endregion #region ICloneable Members /// /// /// /// public virtual object Clone() { return new GuardedCollection((ICollection)(collection.Clone())); } #endregion } /// /// A read-only wrapper for a sequenced collection /// /// This is mainly interesting as a base of other guard classes /// public class GuardedSequenced : GuardedCollection, ISequenced { #region Fields ISequenced sequenced; #endregion #region Constructor /// /// Wrap a sequenced collection in a read-only wrapper /// /// public GuardedSequenced(ISequenced sorted) : base(sorted) { this.sequenced = sorted; } #endregion /// /// Check if there exists an item that satisfies a /// specific predicate in this collection and return the index of the first one. /// /// A delegate /// ( with R == bool) defining the predicate /// the index, if found, a negative value else public int FindIndex(Fun predicate) { IIndexed indexed = sequenced as IIndexed; if (indexed != null) return indexed.FindIndex(predicate); int index = 0; foreach (T item in this) { if (predicate(item)) return index; index++; } return -1; } /// /// Check if there exists an item that satisfies a /// specific predicate in this collection and return the index of the last one. /// /// A delegate /// ( with R == bool) defining the predicate /// the index, if found, a negative value else public int FindLastIndex(Fun predicate) { IIndexed indexed = sequenced as IIndexed; if (indexed != null) return indexed.FindLastIndex(predicate); int index = Count - 1; foreach (T item in Backwards()) { if (predicate(item)) return index; index--; } return -1; } #region ISequenced Members /// /// /// /// public int GetSequencedHashCode() { return sequenced.GetSequencedHashCode(); } /// /// /// /// /// public bool SequencedEquals(ISequenced that) { return sequenced.SequencedEquals(that); } #endregion #region IDirectedCollection Members /// /// Get a collection that enumerates the wrapped collection in the opposite direction /// /// The mirrored collection public virtual IDirectedCollectionValue Backwards() { return new GuardedDirectedCollectionValue(sequenced.Backwards()); } /// /// /// /// /// /// public virtual bool FindLast(Fun predicate, out T item) { return sequenced.FindLast(predicate, out item); } #endregion #region IDirectedEnumerable Members IDirectedEnumerable IDirectedEnumerable.Backwards() { return Backwards(); } /// /// Forwards if same, else Backwards /// /// The enumeration direction relative to the original collection. public EnumerationDirection Direction { get { return EnumerationDirection.Forwards; } } #endregion #region ICloneable Members /// /// /// /// public override object Clone() { return new GuardedCollection((ISequenced)(sequenced.Clone())); } #endregion } /// /// A read-only wrapper for a sorted collection /// /// This is mainly interesting as a base of other guard classes /// public class GuardedSorted : GuardedSequenced, ISorted { #region Fields ISorted sorted; #endregion #region Constructor /// /// Wrap a sorted collection in a read-only wrapper /// /// public GuardedSorted(ISorted sorted) : base(sorted) { this.sorted = sorted; } #endregion #region ISorted Members /// /// Find the strict predecessor of item in the guarded sorted collection, /// that is, the greatest item in the collection smaller than the item. /// /// The item to find the predecessor for. /// The predecessor, if any; otherwise the default value for T. /// True if item has a predecessor; otherwise false. public bool TryPredecessor(T item, out T res) { return sorted.TryPredecessor(item, out res); } /// /// Find the strict successor of item in the guarded sorted collection, /// that is, the least item in the collection greater than the supplied value. /// /// The item to find the successor for. /// The successor, if any; otherwise the default value for T. /// True if item has a successor; otherwise false. public bool TrySuccessor(T item, out T res) { return sorted.TrySuccessor(item, out res); } /// /// Find the weak predecessor of item in the guarded sorted collection, /// that is, the greatest item in the collection smaller than or equal to the item. /// /// The item to find the weak predecessor for. /// The weak predecessor, if any; otherwise the default value for T. /// True if item has a weak predecessor; otherwise false. public bool TryWeakPredecessor(T item, out T res) { return sorted.TryWeakPredecessor(item, out res); } /// /// Find the weak successor of item in the sorted collection, /// that is, the least item in the collection greater than or equal to the supplied value. /// /// The item to find the weak successor for. /// The weak successor, if any; otherwise the default value for T. /// True if item has a weak successor; otherwise false. public bool TryWeakSuccessor(T item, out T res) { return sorted.TryWeakSuccessor(item, out res); } /// /// Find the predecessor of the item in the wrapped sorted collection /// /// if no such element exists /// The item /// The predecessor public T Predecessor(T item) { return sorted.Predecessor(item); } /// /// Find the Successor of the item in the wrapped sorted collection /// /// if no such element exists /// The item /// The Successor public T Successor(T item) { return sorted.Successor(item); } /// /// Find the weak predecessor of the item in the wrapped sorted collection /// /// if no such element exists /// The item /// The weak predecessor public T WeakPredecessor(T item) { return sorted.WeakPredecessor(item); } /// /// Find the weak Successor of the item in the wrapped sorted collection /// /// if no such element exists /// The item /// The weak Successor public T WeakSuccessor(T item) { return sorted.WeakSuccessor(item); } /// /// Run Cut on the wrapped sorted collection /// /// /// /// /// /// /// public bool Cut(IComparable c, out T low, out bool lval, out T high, out bool hval) { return sorted.Cut(c, out low, out lval, out high, out hval); } /// /// Get the specified range from the wrapped collection. /// (The current implementation erroneously does not wrap the result.) /// /// /// public IDirectedEnumerable RangeFrom(T bot) { return sorted.RangeFrom(bot); } /// /// Get the specified range from the wrapped collection. /// (The current implementation erroneously does not wrap the result.) /// /// /// /// public IDirectedEnumerable RangeFromTo(T bot, T top) { return sorted.RangeFromTo(bot, top); } /// /// Get the specified range from the wrapped collection. /// (The current implementation erroneously does not wrap the result.) /// /// /// public IDirectedEnumerable RangeTo(T top) { return sorted.RangeTo(top); } /// /// Get the specified range from the wrapped collection. /// (The current implementation erroneously does not wrap the result.) /// /// public IDirectedCollectionValue RangeAll() { return sorted.RangeAll(); } /// /// /// since this is a read-only wrappper /// /// public void AddSorted(SCG.IEnumerable items) where U : T { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// public void RemoveRangeFrom(T low) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// /// public void RemoveRangeFromTo(T low, T hi) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// public void RemoveRangeTo(T hi) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } #endregion #region IPriorityQueue Members /// /// Find the minimum of the wrapped collection /// /// The minimum public T FindMin() { return sorted.FindMin(); } /// /// /// since this is a read-only wrappper /// public T DeleteMin() { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// Find the maximum of the wrapped collection /// /// The maximum public T FindMax() { return sorted.FindMax(); } /// /// /// since this is a read-only wrappper /// public T DeleteMax() { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } //TODO: we should guard the comparer! /// /// The comparer object supplied at creation time for the underlying collection /// /// The comparer public SCG.IComparer Comparer { get { return sorted.Comparer; } } #endregion #region IDirectedEnumerable Members IDirectedEnumerable IDirectedEnumerable.Backwards() { return Backwards(); } #endregion /// /// /// /// public override object Clone() { return new GuardedSorted((ISorted)(sorted.Clone())); } } /// /// Read-only wrapper for indexed sorted collections /// /// Suitable for wrapping TreeSet, TreeBag and SortedArray /// public class GuardedIndexedSorted : GuardedSorted, IIndexedSorted { #region Fields IIndexedSorted indexedsorted; #endregion #region Constructor /// /// Wrap an indexed sorted collection in a read-only wrapper /// /// the indexed sorted collection public GuardedIndexedSorted(IIndexedSorted list) : base(list) { this.indexedsorted = list; } #endregion #region IIndexedSorted Members /// /// Get the specified range from the wrapped collection. /// (The current implementation erroneously does not wrap the result.) /// /// /// public new IDirectedCollectionValue RangeFrom(T bot) { return indexedsorted.RangeFrom(bot); } /// /// Get the specified range from the wrapped collection. /// (The current implementation erroneously does not wrap the result.) /// /// /// /// public new IDirectedCollectionValue RangeFromTo(T bot, T top) { return indexedsorted.RangeFromTo(bot, top); } /// /// Get the specified range from the wrapped collection. /// (The current implementation erroneously does not wrap the result.) /// /// /// public new IDirectedCollectionValue RangeTo(T top) { return indexedsorted.RangeTo(top); } /// /// Report the number of items in the specified range of the wrapped collection /// /// /// public int CountFrom(T bot) { return indexedsorted.CountFrom(bot); } /// /// Report the number of items in the specified range of the wrapped collection /// /// /// /// public int CountFromTo(T bot, T top) { return indexedsorted.CountFromTo(bot, top); } /// /// Report the number of items in the specified range of the wrapped collection /// /// /// public int CountTo(T top) { return indexedsorted.CountTo(top); } /// /// Run FindAll on the wrapped collection with the indicated filter. /// The result will not be read-only. /// /// /// public IIndexedSorted FindAll(Fun f) { return indexedsorted.FindAll(f); } /// /// Run Map on the wrapped collection with the indicated mapper. /// The result will not be read-only. /// /// /// The comparer to use in the result /// public IIndexedSorted Map(Fun m, SCG.IComparer c) { return indexedsorted.Map(m, c); } #endregion #region IIndexed Members /// /// /// /// The i'th item of the wrapped sorted collection public T this[int i] { get { return indexedsorted[i]; } } /// /// /// /// public virtual Speed IndexingSpeed { get { return indexedsorted.IndexingSpeed; } } /// /// A directed collection of the items in the indicated interval of the wrapped collection public IDirectedCollectionValue this[int start, int end] { get { return new GuardedDirectedCollectionValue(indexedsorted[start, end]); } } /// /// Find the (first) index of an item in the wrapped collection /// /// /// public int IndexOf(T item) { return indexedsorted.IndexOf(item); } /// /// Find the last index of an item in the wrapped collection /// /// /// public int LastIndexOf(T item) { return indexedsorted.LastIndexOf(item); } /// /// /// since this is a read-only wrappper /// /// public T RemoveAt(int i) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// since this is a read-only wrappper /// /// public void RemoveInterval(int start, int count) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } #endregion #region IDirectedEnumerable Members IDirectedEnumerable IDirectedEnumerable.Backwards() { return Backwards(); } #endregion /// /// /// /// public override object Clone() { return new GuardedIndexedSorted((IIndexedSorted)(indexedsorted.Clone())); } } /// /// A read-only wrapper for a generic list collection /// Suitable as a wrapper for LinkedList, HashedLinkedList, ArrayList and HashedArray. /// , /// , /// or /// . /// /// public class GuardedList : GuardedSequenced, IList, SCG.IList { #region Fields IList innerlist; GuardedList underlying; bool slidableView = false; #endregion #region Constructor /// /// Wrap a list in a read-only wrapper. A list gets wrapped as read-only, /// a list view gets wrapped as read-only and non-slidable. /// /// The list public GuardedList(IList list) : base(list) { this.innerlist = list; // If wrapping a list view, make innerlist = the view, and make // underlying = a guarded version of the view's underlying list if (list.Underlying != null) underlying = new GuardedList(list.Underlying, null, false); } GuardedList(IList list, GuardedList underlying, bool slidableView) : base(list) { this.innerlist = list; this.underlying = underlying; this.slidableView = slidableView; } #endregion #region IList Members /// /// /// /// The first item of the wrapped list public T First { get { return innerlist.First; } } /// /// /// /// The last item of the wrapped list public T Last { get { return innerlist.Last; } } /// /// /// if used as setter /// True if wrapped list has FIFO semantics for the Add(T item) and Remove() methods public bool FIFO { get { return innerlist.FIFO; } set { throw new ReadOnlyCollectionException("List is read only"); } } /// /// /// public virtual bool IsFixedSize { get { return true; } } /// /// /// if used as setter /// The i'th item of the wrapped list public T this[int i] { get { return innerlist[i]; } set { throw new ReadOnlyCollectionException("List is read only"); } } /// /// /// /// public virtual Speed IndexingSpeed { get { return innerlist.IndexingSpeed; } } /// /// /// since this is a read-only wrappper /// /// public void Insert(int index, T item) { throw new ReadOnlyCollectionException(); } /// /// /// since this is a read-only wrappper /// /// public void Insert(IList pointer, T item) { throw new ReadOnlyCollectionException(); } /// /// /// since this is a read-only wrappper /// public void InsertFirst(T item) { throw new ReadOnlyCollectionException("List is read only"); } /// /// /// since this is a read-only wrappper /// public void InsertLast(T item) { throw new ReadOnlyCollectionException("List is read only"); } /// /// /// since this is a read-only wrappper /// /// public void InsertBefore(T item, T target) { throw new ReadOnlyCollectionException("List is read only"); } /// /// /// since this is a read-only wrappper /// /// public void InsertAfter(T item, T target) { throw new ReadOnlyCollectionException("List is read only"); } /// /// /// since this is a read-only wrappper /// /// public void InsertAll(int i, SCG.IEnumerable items) where U : T { throw new ReadOnlyCollectionException("List is read only"); } /// /// Perform FindAll on the wrapped list. The result is not necessarily read-only. /// /// The filter to use /// public IList FindAll(Fun filter) { return innerlist.FindAll(filter); } /// /// Perform Map on the wrapped list. The result is not necessarily read-only. /// /// The type of items of the new list /// The mapper to use. /// The mapped list public IList Map(Fun mapper) { return innerlist.Map(mapper); } /// /// Perform Map on the wrapped list. The result is not necessarily read-only. /// /// The type of items of the new list /// The delegate defining the map. /// The itemequalityComparer to use for the new list /// The new list. public IList Map(Fun mapper, SCG.IEqualityComparer itemequalityComparer) { return innerlist.Map(mapper, itemequalityComparer); } /// /// /// since this is a read-only wrappper /// public T Remove() { throw new ReadOnlyCollectionException("List is read only"); } /// /// /// since this is a read-only wrappper /// public T RemoveFirst() { throw new ReadOnlyCollectionException("List is read only"); } /// /// /// since this is a read-only wrappper /// public T RemoveLast() { throw new ReadOnlyCollectionException("List is read only"); } /// /// Create the indicated view on the wrapped list and wrap it read-only. /// /// /// /// public IList View(int start, int count) { IList view = innerlist.View(start, count); return view == null ? null : new GuardedList(view, underlying ?? this, true); } /// /// Create the indicated view on the wrapped list and wrap it read-only. /// /// /// public IList ViewOf(T item) { IList view = innerlist.ViewOf(item); return view == null ? null : new GuardedList(view, underlying ?? this, true); } /// /// Create the indicated view on the wrapped list and wrap it read-only. /// /// /// public IList LastViewOf(T item) { IList view = innerlist.LastViewOf(item); return view == null ? null : new GuardedList(view, underlying ?? this, true); } /// /// /// The wrapped underlying list of the wrapped view public IList Underlying { get { return underlying; } } /// /// /// /// The offset of the wrapped list as a view. public int Offset { get { return innerlist.Offset; } } /// /// /// /// public virtual bool IsValid { get { return innerlist.IsValid; } } /// /// /// if this is a wrapped view and not a view that was made on a wrapper /// public IList Slide(int offset) { if (slidableView) { innerlist.Slide(offset); return this; } else throw new ReadOnlyCollectionException("List is read only"); } /// /// /// since this is a read-only wrappper /// /// public IList Slide(int offset, int size) { if (slidableView) { innerlist.Slide(offset, size); return this; } else throw new ReadOnlyCollectionException("List is read only"); } /// /// /// /// since this is a read-only wrappper /// /// public bool TrySlide(int offset) { if (slidableView) return innerlist.TrySlide(offset); else throw new ReadOnlyCollectionException("List is read only"); } /// /// /// /// since this is a read-only wrappper /// /// /// public bool TrySlide(int offset, int size) { if (slidableView) return innerlist.TrySlide(offset, size); else throw new ReadOnlyCollectionException("List is read only"); } /// /// /// /// /// public IList Span(IList otherView) { GuardedList otherGuardedList = otherView as GuardedList; if (otherGuardedList == null) throw new IncompatibleViewException(); IList span = innerlist.Span(otherGuardedList.innerlist); if (span == null) return null; return new GuardedList(span, underlying ?? otherGuardedList.underlying ?? this, true); } /// /// since this is a read-only wrappper /// public void Reverse() { throw new ReadOnlyCollectionException("List is read only"); } /// /// /// since this is a read-only wrappper /// /// public void Reverse(int start, int count) { throw new ReadOnlyCollectionException("List is read only"); } /// /// Check if wrapped list is sorted according to the default sorting order /// for the item type T, as defined by the class /// /// if T is not comparable /// True if the list is sorted, else false. public bool IsSorted() { return innerlist.IsSorted(Comparer.Default); } /// /// Check if wrapped list is sorted /// /// The sorting order to use /// True if sorted public bool IsSorted(SCG.IComparer c) { return innerlist.IsSorted(c); } /// /// /// since this is a read-only wrappper public void Sort() { throw new ReadOnlyCollectionException("List is read only"); } /// /// /// since this is a read-only wrappper /// public void Sort(SCG.IComparer c) { throw new ReadOnlyCollectionException("List is read only"); } /// /// /// since this is a read-only wrappper public void Shuffle() { throw new ReadOnlyCollectionException("List is read only"); } /// /// /// since this is a read-only wrappper /// public void Shuffle(Random rnd) { throw new ReadOnlyCollectionException("List is read only"); } #endregion #region IIndexed Members /// /// A directed collection of the items in the indicated interval of the wrapped collection public IDirectedCollectionValue this[int start, int end] { get { return new GuardedDirectedCollectionValue(innerlist[start, end]); } } /// /// Find the (first) index of an item in the wrapped collection /// /// /// public int IndexOf(T item) { return innerlist.IndexOf(item); } /// /// Find the last index of an item in the wrapped collection /// /// /// public int LastIndexOf(T item) { return innerlist.LastIndexOf(item); } /// /// /// since this is a read-only wrappper /// /// public T RemoveAt(int i) { throw new ReadOnlyCollectionException("List is read only"); } /// /// /// since this is a read-only wrappper /// /// public void RemoveInterval(int start, int count) { throw new ReadOnlyCollectionException("List is read only"); } #endregion #region IDirectedEnumerable Members IDirectedEnumerable IDirectedEnumerable.Backwards() { return Backwards(); } #endregion #region IStack Members /// /// /// /// since this is a read-only wrappper /// - public void Push(T item) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// /// since this is a read-only wrappper /// - public T Pop() { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } #endregion #region IQueue Members /// /// /// /// since this is a read-only wrappper /// - public void Enqueue(T item) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } /// /// /// /// since this is a read-only wrappper /// - public T Dequeue() { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } #endregion #region IDisposable Members /// /// Ignore: this may be called by a foreach or using statement. /// public void Dispose() { } #endregion /// /// /// /// public override object Clone() { return new GuardedList((IList)(innerlist.Clone())); } #region System.Collections.Generic.IList Members void System.Collections.Generic.IList.RemoveAt(int index) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } void System.Collections.Generic.ICollection.Add(T item) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } #endregion #region System.Collections.ICollection Members bool System.Collections.ICollection.IsSynchronized { get { return false; } } [Obsolete] Object System.Collections.ICollection.SyncRoot { get { return innerlist.SyncRoot; } } void System.Collections.ICollection.CopyTo(Array arr, int index) { if (index < 0 || index + Count > arr.Length) throw new ArgumentOutOfRangeException(); foreach (T item in this) arr.SetValue(item, index++); } #endregion #region System.Collections.IList Members Object System.Collections.IList.this[int index] { get { return this[index]; } set { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } } int System.Collections.IList.Add(Object o) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } bool System.Collections.IList.Contains(Object o) { return Contains((T)o); } int System.Collections.IList.IndexOf(Object o) { return Math.Max(-1, IndexOf((T)o)); } void System.Collections.IList.Insert(int index, Object o) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } void System.Collections.IList.Remove(Object o) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } void System.Collections.IList.RemoveAt(int index) { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); } #endregion } /// /// A read-only wrapper for a generic indexable queue (allows indexing). /// /// Suitable for wrapping a /// /// The item type. public class GuardedQueue : GuardedDirectedCollectionValue, IQueue { #region Fields IQueue queue; #endregion #region Constructor /// /// Wrap a queue in a read-only wrapper /// /// The queue public GuardedQueue(IQueue queue) : base(queue) { this.queue = queue; } #endregion #region IQueue Members /// /// /// /// public bool AllowsDuplicates { get { return queue.AllowsDuplicates; } } /// /// Index into the wrapped queue /// /// /// public T this[int i] { get { return queue[i]; } } /// /// /// /// since this is a read-only wrappper /// - public void Enqueue(T item) { throw new ReadOnlyCollectionException("Queue cannot be modified through this guard object"); } /// /// /// /// since this is a read-only wrappper /// - public T Dequeue() { throw new ReadOnlyCollectionException("Queue cannot be modified through this guard object"); } #endregion } /// /// A read-only wrapper for a dictionary. /// /// Suitable for wrapping a HashDictionary. /// public class GuardedDictionary : GuardedCollectionValue>, IDictionary { #region Fields IDictionary dict; #endregion #region Constructor /// /// Wrap a dictionary in a read-only wrapper /// /// the dictionary public GuardedDictionary(IDictionary dict) : base(dict) { this.dict = dict; } #endregion #region IDictionary Members /// /// /// /// public SCG.IEqualityComparer EqualityComparer { get { return dict.EqualityComparer; } } /// /// /// since this is a /// read-only wrappper if used as a setter /// Get the value corresponding to a key in the wrapped dictionary public V this[K key] { get { return dict[key]; } set { throw new ReadOnlyCollectionException(); } } /// /// (This is a read-only wrapper) /// /// True public bool IsReadOnly { get { return true; } } //TODO: guard with a read-only wrapper? Probably so! /// /// The collection of keys of the wrapped dictionary public ICollectionValue Keys { get { return dict.Keys; } } /// /// The collection of values of the wrapped dictionary public ICollectionValue Values { get { return dict.Values; } } /// /// /// public virtual Fun Fun { get { return delegate(K k) { return this[k]; }; } } /// /// /// since this is a read-only wrappper /// /// public void Add(K key, V val) { throw new ReadOnlyCollectionException(); } /// /// /// /// since this is a read-only wrappper /// public void AddAll(SCG.IEnumerable> items) where L : K where W : V { throw new ReadOnlyCollectionException(); } /// /// /// since this is a read-only wrappper /// /// public bool Remove(K key) { throw new ReadOnlyCollectionException(); } /// /// /// since this is a read-only wrappper /// /// /// public bool Remove(K key, out V val) { throw new ReadOnlyCollectionException(); } /// /// /// since this is a read-only wrappper public void Clear() { throw new ReadOnlyCollectionException(); } /// /// /// /// public Speed ContainsSpeed { get { return dict.ContainsSpeed; } } /// /// Check if the wrapped dictionary contains a specific key /// /// The key /// True if it does public bool Contains(K key) { return dict.Contains(key); } /// /// /// /// /// public bool ContainsAll(SCG.IEnumerable keys) where H : K { return dict.ContainsAll(keys); } /// /// Search for a key in the wrapped dictionary, reporting the value if found /// /// The key /// On exit: the value if found /// True if found public bool Find(K key, out V val) { return dict.Find(key, out val); } /// /// Search for a key in the wrapped dictionary, reporting the value if found /// /// The key /// On exit: the value if found /// True if found public bool Find(ref K key, out V val) { return dict.Find(ref key, out val); } /// /// /// since this is a read-only wrappper /// /// /// public bool Update(K key, V val) { throw new ReadOnlyCollectionException(); } /// /// /// since this is a read-only wrappper /// /// /// /// public bool Update(K key, V val, out V oldval) { throw new ReadOnlyCollectionException(); } /// /// /// since this is a read-only wrappper /// /// /// public bool FindOrAdd(K key, ref V val) { throw new ReadOnlyCollectionException(); } /// /// /// since this is a read-only wrappper /// /// /// public bool UpdateOrAdd(K key, V val) { throw new ReadOnlyCollectionException(); } /// /// /// since this is a read-only wrappper /// /// /// /// public bool UpdateOrAdd(K key, V val, out V oldval) { throw new ReadOnlyCollectionException(); } /// /// Check the internal consistency of the wrapped dictionary /// /// True if check passed public bool Check() { return dict.Check(); } #endregion /// /// /// /// public virtual object Clone() { return new GuardedDictionary((IDictionary)(dict.Clone())); } } /// /// A read-only wrapper for a sorted dictionary. /// /// Suitable for wrapping a Dictionary. /// public class GuardedSortedDictionary : GuardedDictionary, ISortedDictionary { #region Fields ISortedDictionary sorteddict; #endregion #region Constructor /// /// Wrap a sorted dictionary in a read-only wrapper /// /// the dictionary public GuardedSortedDictionary(ISortedDictionary sorteddict) : base(sorteddict) { this.sorteddict = sorteddict; } #endregion #region ISortedDictionary Members /// /// The key comparer used by this dictionary. /// /// public SCG.IComparer Comparer { get { return sorteddict.Comparer; } } /// /// /// /// public new ISorted Keys { get { return null; } } /// /// Find the entry in the dictionary whose key is the /// predecessor of the specified key. /// /// The key /// The predecessor, if any /// True if key has a predecessor public bool TryPredecessor(K key, out KeyValuePair res) { return sorteddict.TryPredecessor(key, out res); } /// /// Find the entry in the dictionary whose key is the /// successor of the specified key. /// /// The key /// The successor, if any /// True if the key has a successor public bool TrySuccessor(K key, out KeyValuePair res) { return sorteddict.TrySuccessor(key, out res); } /// /// Find the entry in the dictionary whose key is the /// weak predecessor of the specified key. /// /// The key /// The predecessor, if any /// True if key has a weak predecessor public bool TryWeakPredecessor(K key, out KeyValuePair res) { return sorteddict.TryWeakPredecessor(key, out res); } /// /// Find the entry in the dictionary whose key is the /// weak successor of the specified key. /// /// The key /// The weak successor, if any /// True if the key has a weak successor public bool TryWeakSuccessor(K key, out KeyValuePair res) { return sorteddict.TryWeakSuccessor(key, out res); } /// /// Get the entry in the wrapped dictionary whose key is the /// predecessor of a specified key. /// /// if no such entry exists /// The key /// The entry public KeyValuePair Predecessor(K key) { return sorteddict.Predecessor(key); } /// /// Get the entry in the wrapped dictionary whose key is the /// successor of a specified key. /// /// if no such entry exists /// The key /// The entry public KeyValuePair Successor(K key) { return sorteddict.Successor(key); } /// /// Get the entry in the wrapped dictionary whose key is the /// weak predecessor of a specified key. /// /// if no such entry exists /// The key /// The entry public KeyValuePair WeakPredecessor(K key) { return sorteddict.WeakPredecessor(key); } /// /// Get the entry in the wrapped dictionary whose key is the /// weak successor of a specified key. /// /// if no such entry exists /// The key /// The entry public KeyValuePair WeakSuccessor(K key) { return sorteddict.WeakSuccessor(key); } /// /// /// /// public KeyValuePair FindMin() { return sorteddict.FindMin(); } /// /// /// /// since this is a read-only wrappper /// public KeyValuePair DeleteMin() { throw new ReadOnlyCollectionException(); } /// /// /// /// public KeyValuePair FindMax() { return sorteddict.FindMax(); } /// /// /// /// since this is a read-only wrappper /// public KeyValuePair DeleteMax() { throw new ReadOnlyCollectionException(); } /// /// /// /// /// /// /// /// /// public bool Cut(IComparable c, out KeyValuePair lowEntry, out bool lowIsValid, out KeyValuePair highEntry, out bool highIsValid) { return sorteddict.Cut(c, out lowEntry, out lowIsValid, out highEntry, out highIsValid); ; } /// /// /// /// /// public IDirectedEnumerable> RangeFrom(K bot) { return new GuardedDirectedEnumerable>(sorteddict.RangeFrom(bot)); } /// /// /// /// /// /// public IDirectedEnumerable> RangeFromTo(K bot, K top) { return new GuardedDirectedEnumerable>(sorteddict.RangeFromTo(bot, top)); } /// /// /// /// /// public IDirectedEnumerable> RangeTo(K top) { return new GuardedDirectedEnumerable>(sorteddict.RangeTo(top)); } /// /// /// /// public IDirectedCollectionValue> RangeAll() { return new GuardedDirectedCollectionValue>(sorteddict.RangeAll()); } /// /// /// /// since this is a read-only wrappper /// public void AddSorted(System.Collections.Generic.IEnumerable> items) { throw new ReadOnlyCollectionException(); } /// /// /// /// since this is a read-only wrappper /// public void RemoveRangeFrom(K low) { throw new ReadOnlyCollectionException(); } /// /// /// /// since this is a read-only wrappper /// /// public void RemoveRangeFromTo(K low, K hi) { throw new ReadOnlyCollectionException(); } /// /// /// /// since this is a read-only wrappper /// public void RemoveRangeTo(K hi) { throw new ReadOnlyCollectionException(); } #endregion } }