/// <summary> /// Removes a given value from the values associated with a key. If the /// last value is removed from a key, the key is removed also. /// </summary> /// <param name="key">A key to remove a value from.</param> /// <param name="value">The value to remove.</param> /// <returns>True if <paramref name="value"/> was associated with <paramref name="key"/> (and was /// therefore removed). False if <paramref name="value"/> was not associated with <paramref name="key"/>.</returns> public sealed override bool Remove(TKey key, TValue value) { KeyAndValues keyValues = new KeyAndValues(key); KeyAndValues existing; if (hash.Find(keyValues, false, out existing)) { // There is an item in the hash table equal to this key. Find the value. int existingCount = existing.Count; int valueHash = CollectionUtil.GetHashCode(value, valueEqualityComparer); int indexFound = -1; for (int i = 0; i < existingCount; ++i) { if (CollectionUtil.GetHashCode(existing.Values[i], valueEqualityComparer) == valueHash && valueEqualityComparer.Equals(existing.Values[i], value)) { // Found an equal existing value indexFound = i; } } if (existingCount == 1) { // Removing the last value. Remove the key. hash.Delete(existing, out keyValues); return(true); } else if (indexFound >= 0) { // Found a value. Remove it. if (indexFound < existingCount - 1) { Array.Copy(existing.Values, indexFound + 1, existing.Values, indexFound, existingCount - indexFound - 1); } existing.Count = existingCount - 1; // Update the hash. hash.Find(existing, true, out keyValues); return(true); } else { // Value was not found. return(false); } } else { return(false); // key not found. } }
/// <summary> /// <para>Adds a new value to be associated with a key. If duplicate values are permitted, this /// method always adds a new key-value pair to the dictionary.</para> /// <para>If duplicate values are not permitted, and <paramref name="key"/> already has a value /// equal to <paramref name="value"/> associated with it, then that value is replaced with <paramref name="value"/>, /// and the number of values associate with <paramref name="key"/> is unchanged.</para> /// </summary> /// <param name="key">The key to associate with.</param> /// <param name="value">The value to associated with <paramref name="key"/>.</param> public sealed override void Add(TKey key, TValue value) { KeyAndValues keyValues = new KeyAndValues(key); KeyAndValues existing; if (hash.Find(keyValues, false, out existing)) { // There already is an item in the hash table equal to this key. Add the new value, // taking into account duplicates if needed. int existingCount = existing.Count; if (!allowDuplicateValues) { int valueHash = CollectionUtil.GetHashCode(value, valueEqualityComparer); for (int i = 0; i < existingCount; ++i) { if (CollectionUtil.GetHashCode(existing.Values[i], valueEqualityComparer) == valueHash && valueEqualityComparer.Equals(existing.Values[i], value)) { // Found an equal existing value. Replace it and we're done. existing.Values[i] = value; return; } } } // Add a new value to an existing key. if (existingCount == existing.Values.Length) { // Grow the array to make room. TValue[] newValues = new TValue[existingCount * 2]; Array.Copy(existing.Values, newValues, existingCount); existing.Values = newValues; } existing.Values[existingCount] = value; existing.Count = existingCount + 1; // Update the hash table. hash.Find(existing, true, out keyValues); return; } else { // No item with this key. Add it. keyValues.Count = 1; keyValues.Values = new TValue[1] { value }; hash.Insert(keyValues, true, out existing); return; } }
/// <summary> /// Gets the full hash code for an item. /// </summary> /// <param name="item">Item to get hash code for.</param> /// <returns>The full hash code. It is never zero.</returns> private int GetFullHash(T item) { uint hash; hash = (uint)CollectionUtil.GetHashCode(item, equalityComparer); // The .NET framework tends to produce pretty bad hash codes. // Scramble them up to be much more random! hash += ~(hash << 15); hash ^= (hash >> 10); hash += (hash << 3); hash ^= (hash >> 6); hash += ~(hash << 11); hash ^= (hash >> 16); hash &= 0x7FFFFFFF; if (hash == 0) { hash = 0x7FFFFFFF; // Make sure it isn't zero. } return((int)hash); }
/// <summary> /// Checks to see if <paramref name="value"/> is associated with <paramref name="key"/> /// in the dictionary. /// </summary> /// <param name="key">The key to check.</param> /// <param name="value">The value to check.</param> /// <returns>True if <paramref name="value"/> is associated with <paramref name="key"/>.</returns> public sealed override bool Contains(TKey key, TValue value) { KeyAndValues find = new KeyAndValues(key); KeyAndValues item; if (hash.Find(find, false, out item)) { int existingCount = item.Count; int valueHash = CollectionUtil.GetHashCode(value, valueEqualityComparer); for (int i = 0; i < existingCount; ++i) { if (CollectionUtil.GetHashCode(item.Values[i], valueEqualityComparer) == valueHash && valueEqualityComparer.Equals(item.Values[i], value)) { // Found an equal existing value. return(true); } } } return(false); }
public int GetHashCode(KeyAndValues obj) { return(CollectionUtil.GetHashCode(obj.Key, keyEqualityComparer)); }
public int GetHashCode(KeyValuePair <TKey, TValue> obj) { return(CollectionUtil.GetHashCode(obj.Key, keyEqualityComparer)); }