/*
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));
}
///