/* Copyright (c) 2003-2004 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 MSG = System.Collections.Generic; namespace C5 { /// /// An entry in a dictionary from K to V. /// public struct KeyValuePair { /// /// The key field of the entry /// public K key; /// /// The value field of the entry /// public V value; /// /// Create an entry with specified key and value /// /// The key /// The value public KeyValuePair(K k, V v) { key = k; value = v; } /// /// Create an entry with a specified key. The value is undefined. /// /// The key public KeyValuePair(K k) { key = k; value = default(V); } /// /// Pretty print an entry /// /// (key, value) [Tested] public override string ToString() { return "(" + key + ", " + value + ")"; } /// /// Check equality of entries /// /// The other object /// True if obj is an entry of the same type and has the same key [Tested] public override bool Equals(object obj) { return obj is KeyValuePair && key.Equals(((KeyValuePair)obj).key); } /// /// Get the hash code of the key. /// /// The hash code [Tested] public override int GetHashCode() { return key.GetHashCode(); } } /// /// Default comparer for dictionary entries in a sorted dictionary. /// Entry comparisons only look at keys. /// public class KeyValuePairComparer: IComparer> { IComparer myc; /// /// Create an entry comparer for a item comparer of the keys /// /// Comparer of keys public KeyValuePairComparer(IComparer c) { myc = c; } /// /// Compare two entries /// /// First entry /// Second entry /// The result of comparing the keys [Tested] public int Compare(KeyValuePair a, KeyValuePair b) { return myc.Compare(a.key, b.key); } } /// /// Default hasher for dictionary entries. /// Operations only look at keys. /// public sealed class KeyValuePairHasher: IHasher> { IHasher myh; /// /// Create an entry hasher using the default hasher for keys /// public KeyValuePairHasher() { myh = HasherBuilder.ByPrototype.Examine(); } /// /// Create an entry hasher from a specified item hasher for the keys /// /// The key hasher public KeyValuePairHasher(IHasher c) { myh = c; } /// /// Get the hash code of the entry /// /// The entry /// The hash code of the key [Tested] public int GetHashCode(KeyValuePair item) { return myh.GetHashCode(item.key); } /// /// Test two entries for equality /// /// First entry /// Second entry /// True if keys are equal [Tested] public bool Equals(KeyValuePair i1, KeyValuePair i2) { return myh.Equals(i1.key, i2.key); } } /// /// A base class for implementing a dictionary based on a set collection implementation. ///

See the source code for for an example

/// ///
public abstract class DictionaryBase: EnumerableBase>, IDictionary { /// /// The set collection of entries underlying this dictionary implementation /// protected ICollection> pairs; #region IDictionary Members /// /// /// /// The number of entrues in the dictionary [Tested] public int Count { [Tested]get { return pairs.Count; } } /// /// /// /// A distinguished object to use for locking to synchronize multithreaded access [Tested] public object SyncRoot { [Tested]get { return pairs.SyncRoot; } } /// /// Add a new (key, value) pair (a mapping) to the dictionary. /// if there already is an entry with the same key. /// /// Key to add /// Value to add [Tested] public void Add(K key, V val) { KeyValuePair p = new KeyValuePair(key, val); if (!pairs.Add(p)) throw new System.ArgumentException("Item has already been added. Key in dictionary: '" + key + "' Key being added: '" + key + "'"); } /// /// Remove an entry with a given key from the dictionary /// /// The key of the entry to remove /// True if an entry was found (and removed) [Tested] public bool Remove(K key) { KeyValuePair p = new KeyValuePair(key); return pairs.Remove(p); } /// /// Remove an entry with a given key from the dictionary and report its value. /// /// The key of the entry to remove /// On exit, the value of the removed entry /// True if an entry was found (and removed) [Tested] public bool Remove(K key, out V val) { KeyValuePair p = new KeyValuePair(key); if (pairs.RemoveWithReturn(ref p)) { val = p.value; return true; } else { val = default(V); return false; } } /// /// Remove all entries from the dictionary /// [Tested] public void Clear() { pairs.Clear(); } /// /// Check if there is an entry with a specified key /// /// The key to look for /// True if key was found [Tested] public bool Contains(K key) { KeyValuePair p = new KeyValuePair(key); return pairs.Contains(p); } /// /// Check if there is an entry with a specified key and report the corresponding /// value if found. This can be seen as a safe form of "val = this[key]". /// /// The key to look for /// On exit, the value of the entry /// True if key was found [Tested] public bool Find(K key, out V val) { KeyValuePair p = new KeyValuePair(key); if (pairs.Find(ref p)) { val = p.value; return true; } else { val = default(V); return false; } } /// /// Look for a specific key in the dictionary and if found replace the value with a new one. /// This can be seen as a non-adding version of "this[key] = val". /// /// The key to look for /// The new value /// True if key was found [Tested] public bool Update(K key, V val) { KeyValuePair p = new KeyValuePair(key, val); return pairs.Update(p); } /// /// Look for a specific key in the dictionary. If found, report the corresponding value, /// else add an entry with the key and the supplied value. /// /// The key to look for /// On entry the value to add if the key is not found. /// On exit the value found if any. /// True if key was found [Tested] public bool FindOrAdd(K key, ref V val) { KeyValuePair p = new KeyValuePair(key, val); if (!pairs.FindOrAdd(ref p)) return false; else { val = p.value; return true; } } /// /// Update value in dictionary corresponding to key if found, else add new entry. /// More general than "this[key] = val;" by reporting if key was found. /// /// The key to look for /// The value to add or replace with. /// True if entry was updated. [Tested] public bool UpdateOrAdd(K key, V val) { return pairs.UpdateOrAdd(new KeyValuePair(key, val)); } #region Keys,Values support classes internal class ValuesCollection: CollectionValueBase, ICollectionValue { ICollection> pairs; internal ValuesCollection(ICollection> pairs) { this.pairs = pairs; } [Tested] public override MSG.IEnumerator GetEnumerator() { //Updatecheck is performed by the pairs enumerator foreach (KeyValuePair p in pairs) yield return p.value; } [Tested] public override int Count { [Tested]get { return pairs.Count; } } public override Speed CountSpeed { get { return Speed.Constant; } } } internal class KeysCollection: CollectionValueBase, ICollectionValue { ICollection> pairs; internal KeysCollection(ICollection> pairs) { this.pairs = pairs; } [Tested] public override MSG.IEnumerator GetEnumerator() { foreach (KeyValuePair p in pairs) yield return p.key; } [Tested] public override int Count { [Tested]get { return pairs.Count; } } public override Speed CountSpeed { get { return pairs.CountSpeed; } } } #endregion /// /// /// /// A collection containg the all the keys of the dictionary [Tested] public ICollectionValue Keys { [Tested]get { return new KeysCollection(pairs); } } /// /// /// /// A collection containing all the values of the dictionary [Tested] public ICollectionValue Values { [Tested]get { return new ValuesCollection(pairs); } } /// /// Indexer for dictionary. /// if no entry is found. /// /// The value corresponding to the key [Tested] public V this[K key] { [Tested] get { KeyValuePair p = new KeyValuePair(key); if (pairs.Find(ref p)) return p.value; else throw new System.ArgumentException("Key not present in Dictionary"); } [Tested] set { pairs.UpdateOrAdd(new KeyValuePair(key, value)); } } /// /// /// /// True if dictionary is read only [Tested] public bool IsReadOnly { [Tested]get { return pairs.IsReadOnly; } } /// /// Check the integrity of the internal data structures of this dictionary. /// Only avaliable in DEBUG builds??? /// /// True if check does not fail. [Tested] public bool Check() { return pairs.Check(); } #endregion #region IEnumerable> Members /// /// Create an enumerator for the collection of entries of the dictionary /// /// The enumerator [Tested] public override MSG.IEnumerator> GetEnumerator() { return pairs.GetEnumerator();; } #endregion } }