Comparer
{
get
{
return this.keyComparer;
}
}
///
/// Returns a View collection that can be used for enumerating the keys and values in the collection in
/// reversed order.
///
///
///Typically, this method is used in conjunction with a foreach statement. For example:
///
/// foreach(KeyValuePair<TKey, TValue> pair in dictionary.Reversed()) {
/// // process pair
/// }
///
/// If an entry is added to or deleted from the dictionary while the View is being enumerated, then
/// the enumeration will end with an InvalidOperationException.
///Calling Reverse does not copy the data in the dictionary, and the operation takes constant time.
///
/// An OrderedDictionary.View of key-value pairs in reverse order.
public View Reversed()
{
return new View(this, tree.EntireRangeTester, true, true);
}
///
/// Returns a collection that can be used for enumerating some of the keys and values in the collection.
/// Only keys that are greater than and
/// less than are included. The keys are enumerated in sorted order.
/// Keys equal to the end points of the range can be included or excluded depending on the
/// and parameters.
///
///
///If is greater than or equal to , the returned collection is empty.
///The sorted order of the keys is determined by the comparison instance or delegate used
/// to create the dictionary.
///Typically, this property is used in conjunction with a foreach statement. For example:
///
/// foreach(KeyValuePair<TKey, TValue> pair in dictionary.Range(from, true, to, false)) {
/// // process pair
/// }
///
///Calling Range does not copy the data in the dictionary, and the operation takes constant time.
/// The lower bound of the range.
/// If true, the lower bound is inclusive--keys equal to the lower bound will
/// be included in the range. If false, the lower bound is exclusive--keys equal to the lower bound will not
/// be included in the range.
/// The upper bound of the range.
/// If true, the upper bound is inclusive--keys equal to the upper bound will
/// be included in the range. If false, the upper bound is exclusive--keys equal to the upper bound will not
/// be included in the range.
/// An OrderedDictionary.View of key-value pairs in the given range.
public View Range(TKey from, bool fromInclusive, TKey to, bool toInclusive)
{
return new View(this, tree.DoubleBoundedRangeTester(NewPair(from), fromInclusive, NewPair(to), toInclusive), false, false);
}
///
/// Returns a collection that can be used for enumerating some of the keys and values in the collection.
/// Only keys that are greater than (and optionally, equal to) are included.
/// The keys are enumerated in sorted order. Keys equal to can be included
/// or excluded depending on the parameter.
///
///
///The sorted order of the keys is determined by the comparison instance or delegate used
/// to create the dictionary.
///Typically, this property is used in conjunction with a foreach statement. For example:
///
/// foreach(KeyValuePair<TKey, TValue> pair in dictionary.RangeFrom(from, true)) {
/// // process pair
/// }
///
///Calling RangeFrom does not copy of the data in the dictionary, and the operation takes constant time.
///
/// The lower bound of the range.
/// If true, the lower bound is inclusive--keys equal to the lower bound will
/// be included in the range. If false, the lower bound is exclusive--keys equal to the lower bound will not
/// be included in the range.
/// An OrderedDictionary.View of key-value pairs in the given range.
public View RangeFrom(TKey from, bool fromInclusive)
{
return new View(this, tree.LowerBoundedRangeTester(NewPair(from), fromInclusive), false, false);
}
///
/// Returns a collection that can be used for enumerating some of the keys and values in the collection.
/// Only items that are less than (and optionally, equal to) are included.
/// The items are enumerated in sorted order. Items equal to can be included
/// or excluded depending on the parameter.
///
///
///The sorted order of the keys is determined by the comparison instance or delegate used
/// to create the dictionary.
///Typically, this property is used in conjunction with a foreach statement. For example:
///
/// foreach(KeyValuePair<TKey, TValue> pair in dictionary.RangeFrom(from, false)) {
/// // process pair
/// }
///
///Calling RangeTo does not copy the data in the dictionary, and the operation takes constant time.
///
/// The upper bound of the range.
/// If true, the upper bound is inclusive--keys equal to the upper bound will
/// be included in the range. If false, the upper bound is exclusive--keys equal to the upper bound will not
/// be included in the range.
/// An OrderedDictionary.View of key-value pairs in the given range.
public View RangeTo(TKey to, bool toInclusive)
{
return new View(this, tree.UpperBoundedRangeTester(NewPair(to), toInclusive), false, false);
}
#region IDictionary Members
///
/// Removes the key (and associated value) from the collection that is equal to the passed in key. If
/// no key in the dictionary is equal to the passed key, false is returned and the
/// dictionary is unchanged.
///
/// Equality between keys is determined by the comparison instance or delegate used
/// to create the dictionary.
/// The key to remove.
/// True if the key was found and removed. False if the key was not found.
public sealed override bool Remove(TKey key)
{
KeyValuePair keyPair = NewPair(key);
KeyValuePair item;
return tree.Delete(keyPair, true, out item);
}
///
/// Removes all keys and values from the dictionary.
///
/// Clearing the dictionary takes a constant amount of time, regardless of the number of keys in it.
public sealed override void Clear()
{
tree.StopEnumerations(); // Invalidate any enumerations.
// The simplest and fastest way is simply to throw away the old tree and create a new one.
tree = new RedBlackTree>(pairComparer);
}
///
/// Finds a key in the dictionary. If the dictionary already contains
/// a key equal to the passed key, then the existing value is returned via value. If the dictionary
/// doesn't contain that key, then value is associated with that key.
///
/// between keys is determined by the comparison instance or delegate used
/// to create the dictionary.
/// This method takes time O(log N), where N is the number of keys in the dictionary. If a value is added, It is more efficient than
/// calling TryGetValue followed by Add, because the dictionary is not searched twice.
/// The new key.
/// The new value to associated with that key, if the key isn't present. If the key was present,
/// returns the exist value associated with that key.
/// True if key was already present, false if key wasn't present (and a new value was added).
public bool GetValueElseAdd(TKey key, ref TValue value)
{
KeyValuePair pair = NewPair(key, value);
KeyValuePair old;
bool added = tree.Insert(pair, DuplicatePolicy.DoNothing, out old);
if (!added)
value = old.Value;
return !added;
}
///
/// Adds a new key and value to the dictionary. If the dictionary already contains
/// a key equal to the passed key, then an ArgumentException is thrown
///
///
/// Equality between keys is determined by the comparison instance or delegate used
/// to create the dictionary.
/// Adding an key and value takes time O(log N), where N is the number of keys in the dictionary.
/// The new key. "null" is a valid key value.
/// The new value to associated with that key.
/// key is already present in the dictionary
public sealed override void Add(TKey key, TValue value)
{
KeyValuePair pair = NewPair(key, value);
KeyValuePair dummy;
bool added = tree.Insert(pair, DuplicatePolicy.DoNothing, out dummy);
if (! added)
throw new ArgumentException(Strings.KeyAlreadyPresent, "key");
}
///
/// Changes the value associated with a given key. If the dictionary does not contain
/// a key equal to the passed key, then an ArgumentException is thrown.
///
///
/// Unlike adding or removing an element, changing the value associated with a key
/// can be performed while an enumeration (foreach) on the the dictionary is in progress.
/// Equality between keys is determined by the comparison instance or delegate used
/// to create the dictionary.
/// Replace takes time O(log N), where N is the number of entries in the dictionary.
/// The new key.
/// The new value to associated with that key.
/// key is not present in the dictionary
public void Replace(TKey key, TValue value)
{
KeyValuePair pair = NewPair(key, value);
KeyValuePair dummy;
bool found = tree.Find(pair, true, true, out dummy);
if (!found)
throw new KeyNotFoundException(Strings.KeyNotFound);
}
///
/// Adds multiple key-value pairs to a dictionary. If a key exists in both the current instance and dictionaryToAdd,
/// then the value is updated with the value from (no exception is thrown).
/// Since IDictionary<TKey,TValue> inherits from IEnumerable<KeyValuePair<TKey,TValue>>, this
/// method can be used to merge one dictionary into another.
///
/// AddMany takes time O(M log (N+M)), where M is the size of , and N is the size of
/// this dictionary.
/// A collection of keys and values whose contents are added to the current dictionary.
public void AddMany(IEnumerable> keysAndValues)
{
if (keysAndValues == null)
throw new ArgumentNullException("keysAndValues");
foreach (KeyValuePair pair in keysAndValues) {
this[pair.Key] = pair.Value;
}
}
///
/// Removes all the keys found in another collection (such as an array or List<TKey>). Each key in keyCollectionToRemove
/// is removed from the dictionary. Keys that are not present are ignored.
///
/// RemoveMany takes time O(M log N), where M is the size of keyCollectionToRemove, and N is this
/// size of this collection.
/// The number of keys removed from the dictionary.
/// A collection of keys to remove from the dictionary.
public int RemoveMany(IEnumerable keyCollectionToRemove)
{
if (keyCollectionToRemove == null)
throw new ArgumentNullException("keyCollectionToRemove");
int count = 0;
foreach (TKey key in keyCollectionToRemove) {
if (this.Remove(key))
++count;
}
return count;
}
///
/// Gets or sets the value associated with a given key. When getting a value, if this
/// key is not found in the collection, then an ArgumentException is thrown. When setting
/// a value, the value replaces any existing value in the dictionary.
///
/// The indexer takes time O(log N), where N is the number of entries in the dictionary.
/// The value associated with the key
/// A value is being retrieved, and the key is not present in the dictionary.
/// is null.
public sealed override TValue this[TKey key]
{
get
{
KeyValuePair pairFound;
bool found;
found = tree.Find(NewPair(key), false, false, out pairFound);
if (found)
return pairFound.Value;
else
throw new KeyNotFoundException(Strings.KeyNotFound);
}
set
{
KeyValuePair dummy;
tree.Insert(NewPair(key, value),
DuplicatePolicy.ReplaceLast, out dummy);
}
}
///
/// Determines if this dictionary contains a key equal to . The dictionary
/// is not changed.
///
/// Searching the dictionary for a key takes time O(log N), where N is the number of keys in the dictionary.
/// The key to search for.
/// True if the dictionary contains key. False if the dictionary does not contain key.
public sealed override bool ContainsKey(TKey key)
{
KeyValuePair pairFound;
return tree.Find(NewPair(key), false, false, out pairFound);
}
///
/// Determines if this dictionary contains a key equal to . If so, the value
/// associated with that key is returned through the value parameter.
///
/// TryGetValue takes time O(log N), where N is the number of entries in the dictionary.
/// The key to search for.
/// Returns the value associated with key, if true was returned.
/// True if the dictionary contains key. False if the dictionary does not contain key.
public sealed override bool TryGetValue(TKey key, out TValue value)
{
KeyValuePair pairFound;
bool found = tree.Find(NewPair(key), false, false, out pairFound);
value = pairFound.Value;
return found;
}
#endregion
#region ICollection> Members
///
/// Returns the number of keys in the dictionary.
///
/// The size of the dictionary is returned in constant time..
/// The number of keys in the dictionary.
public sealed override int Count
{
get
{
return tree.ElementCount;
}
}
#endregion
#region IEnumerable> Members
///
/// Returns an enumerator that enumerates all the entries in the dictionary. Each entry is
/// returned as a KeyValuePair<TKey,TValue>.
/// The entries are enumerated in the sorted order of the keys.
///
///
/// Typically, this method is not called directly. Instead the "foreach" statement is used
/// to enumerate the elements of the dictionary, which uses this method implicitly.
/// If an element is added to or deleted from the dictionary while it is being enumerated, then
/// the enumeration will end with an InvalidOperationException.
/// Enumeration all the entries in the dictionary takes time O(N log N), where N is the number
/// of entries in the dictionary.
///
/// An enumerator for enumerating all the elements in the OrderedDictionary.
public sealed override IEnumerator> GetEnumerator()
{
return tree.GetEnumerator();
}
#endregion
#region ICloneable Members
///
/// Implements ICloneable.Clone. Makes a shallow clone of this dictionary; i.e., if keys or values are reference types, then they are not cloned.
///
/// The cloned dictionary.
object ICloneable.Clone()
{
return Clone();
}
#endregion
///
/// The OrderedDictionary<TKey,TValue>.View class is used to look at a subset of the keys and values
/// inside an ordered dictionary. It is returned from the Range, RangeTo, RangeFrom, and Reversed methods.
///
///
/// Views are dynamic. If the underlying dictionary changes, the view changes in sync. If a change is made
/// to the view, the underlying dictionary changes accordingly.
///Typically, this class is used in conjunction with a foreach statement to enumerate the keys
/// and values in a subset of the OrderedDictionary. For example:
///
/// foreach(KeyValuePair<TKey, TValue> pair in dictionary.Range(from, to)) {
/// // process pair
/// }
///
///
[Serializable]
public class View : DictionaryBase
{
private OrderedDictionary myDictionary;
private RedBlackTree>.RangeTester rangeTester; // range tester for the range being used.
private bool entireTree; // is the view the whole tree?
private bool reversed; // is the view reversed?
///
/// Initialize the View.
///
/// Associated OrderedDictionary to be viewed.
/// Range tester that defines the range being used.
/// If true, then rangeTester defines the entire tree.
/// Is the view enuemerated in reverse order?
internal View(OrderedDictionary myDictionary, RedBlackTree>.RangeTester rangeTester, bool entireTree, bool reversed)
{
this.myDictionary = myDictionary;
this.rangeTester = rangeTester;
this.entireTree = entireTree;
this.reversed = reversed;
}
///
/// Determine if the given key lies within the bounds of this view.
///
/// Key to test.
/// True if the key is within the bounds of this view.
private bool KeyInView(TKey key)
{
return rangeTester(NewPair(key, default(TValue))) == 0;
}
///
/// Enumerate all the keys and values in this view.
///
/// An IEnumerator of KeyValuePairs with the keys and views in this view.
public sealed override IEnumerator> GetEnumerator()
{
if (reversed)
return myDictionary.tree.EnumerateRangeReversed(rangeTester).GetEnumerator();
else
return myDictionary.tree.EnumerateRange(rangeTester).GetEnumerator();
}
///
/// Number of keys in this view.
///
/// Number of keys that lie within the bounds the view.
public sealed override int Count
{
get
{
if (entireTree)
return myDictionary.Count;
else
return myDictionary.tree.CountRange(rangeTester);
}
}
///
/// Tests if the key is present in the part of the dictionary being viewed.
///
/// Key to check for.
/// True if the key is within this view.
public sealed override bool ContainsKey(TKey key)
{
if (!KeyInView(key))
return false;
else
return myDictionary.ContainsKey(key);
}
///
/// Determines if this view contains a key equal to . If so, the value
/// associated with that key is returned through the value parameter.
///
/// The key to search for.
/// Returns the value associated with key, if true was returned.
/// True if the key is within this view.
public sealed override bool TryGetValue(TKey key, out TValue value)
{
if (!KeyInView(key)) {
value = default(TValue);
return false;
}
else {
return myDictionary.TryGetValue(key, out value);
}
}
///
/// Gets or sets the value associated with a given key. When getting a value, if this
/// key is not found in the collection, then an ArgumentException is thrown. When setting
/// a value, the value replaces any existing value in the dictionary. When setting a value, the
/// key must be within the range of keys being viewed.
///
/// The value associated with the key.
/// A value is being retrieved, and the key is not present in the dictionary,
/// or a value is being set, and the key is outside the range of keys being viewed by this View.
public sealed override TValue this[TKey key]
{
get // technically we don't need to override this, but fixes a bug in NDOC.
{
return base[key];
}
set
{
if (!KeyInView(key))
throw new ArgumentException(Strings.OutOfViewRange, "key");
else
myDictionary[key] = value;
}
}
///
/// Removes the key (and associated value) from the underlying dictionary of this view. that is equal to the passed in key. If
/// no key in the view is equal to the passed key, the dictionary and view are unchanged.
///
/// The key to remove.
/// True if the key was found and removed. False if the key was not found.
public sealed override bool Remove(TKey key)
{
if (!KeyInView(key))
return false;
else
return myDictionary.Remove(key);
}
///
/// Removes all the keys and values within this view from the underlying OrderedDictionary.
///
/// The following removes all the keys that start with "A" from an OrderedDictionary.
///
/// dictionary.Range("A", "B").Clear();
///
///
public sealed override void Clear()
{
if (entireTree) {
myDictionary.Clear();
}
else {
myDictionary.tree.DeleteRange(rangeTester);
}
}
///
/// Creates a new View that has the same keys and values as this, in the reversed order.
///
/// A new View that has the reversed order of this view.
public View Reversed()
{
return new View(myDictionary, rangeTester, entireTree, !reversed);
}
}
}
}