/// <summary> /// Adds the specified key. /// </summary> /// <param name="key">The key to add.</param> /// <param name="value">The value to add.</param> /// <param name="keyOnlyComparer">The key comparer.</param> /// <param name="valueComparer">The value comparer.</param> /// <param name="behavior">The intended behavior for certain cases that may come up during the operation.</param> /// <param name="result">A description of the effect was on adding an element to this <see cref="HashBucket"/>.</param> /// <returns>A new <see cref="HashBucket"/> that contains the added value and any values already held by this <see cref="HashBucket"/>.</returns> internal HashBucket Add(TKey key, TValue value, IEqualityComparer <KeyValuePair <TKey, TValue> > keyOnlyComparer, IEqualityComparer <TValue> valueComparer, KeyCollisionBehavior behavior, out OperationResult result) { var kv = new KeyValuePair <TKey, TValue>(key, value); if (this.IsEmpty) { result = OperationResult.SizeChanged; return(new HashBucket(kv)); } if (keyOnlyComparer.Equals(kv, _firstValue)) { switch (behavior) { case KeyCollisionBehavior.SetValue: result = OperationResult.AppliedWithoutSizeChange; return(new HashBucket(kv, _additionalElements)); case KeyCollisionBehavior.Skip: result = OperationResult.NoChangeRequired; return(this); case KeyCollisionBehavior.ThrowIfValueDifferent: if (!valueComparer.Equals(_firstValue.Value, value)) { throw new ArgumentException(SR.Format(SR.DuplicateKey, key)); } result = OperationResult.NoChangeRequired; return(this); case KeyCollisionBehavior.ThrowAlways: throw new ArgumentException(SR.Format(SR.DuplicateKey, key)); default: throw new InvalidOperationException(); // unreachable } } int keyCollisionIndex = _additionalElements.IndexOf(kv, keyOnlyComparer); if (keyCollisionIndex < 0) { result = OperationResult.SizeChanged; return(new HashBucket(_firstValue, _additionalElements.Add(kv))); } else { switch (behavior) { case KeyCollisionBehavior.SetValue: result = OperationResult.AppliedWithoutSizeChange; return(new HashBucket(_firstValue, _additionalElements.ReplaceAt(keyCollisionIndex, kv))); case KeyCollisionBehavior.Skip: result = OperationResult.NoChangeRequired; return(this); case KeyCollisionBehavior.ThrowIfValueDifferent: ref readonly var existingEntry = ref _additionalElements.ItemRef(keyCollisionIndex);
/// <summary> /// Adds the specified value. /// </summary> /// <param name="value">The value.</param> /// <param name="valueComparer">The value comparer.</param> /// <param name="result">A description of the effect was on adding an element to this <see cref="HashBucket"/>.</param> /// <returns>A new <see cref="HashBucket"/> that contains the added value and any values already held by this <see cref="HashBucket"/>.</returns> internal HashBucket Add(T value, IEqualityComparer <T> valueComparer, out OperationResult result) { if (this.IsEmpty) { result = OperationResult.SizeChanged; return(new HashBucket(value)); } if (valueComparer.Equals(value, _firstValue) || _additionalElements.IndexOf(value, valueComparer) >= 0) { result = OperationResult.NoChangeRequired; return(this); } result = OperationResult.SizeChanged; return(new HashBucket(_firstValue, _additionalElements.Add(value))); }