diff options
Diffstat (limited to 'src/mscorlib/src/System/Collections/Hashtable.cs')
-rw-r--r-- | src/mscorlib/src/System/Collections/Hashtable.cs | 187 |
1 files changed, 44 insertions, 143 deletions
diff --git a/src/mscorlib/src/System/Collections/Hashtable.cs b/src/mscorlib/src/System/Collections/Hashtable.cs index 262ccedea6..d4c7d8d673 100644 --- a/src/mscorlib/src/System/Collections/Hashtable.cs +++ b/src/mscorlib/src/System/Collections/Hashtable.cs @@ -23,10 +23,7 @@ namespace System.Collections { using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Diagnostics.Contracts; -#if !FEATURE_CORECLR - using System.Security.Cryptography; -#endif - + // The Hashtable class represents a dictionary of associated keys and values // with constant lookup time. // @@ -271,9 +268,9 @@ namespace System.Collections { // public Hashtable(int capacity, float loadFactor) { if (capacity < 0) - throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(capacity), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (!(loadFactor >= 0.1f && loadFactor <= 1.0f)) - throw new ArgumentOutOfRangeException("loadFactor", Environment.GetResourceString("ArgumentOutOfRange_HashtableLoadFactor", .1, 1.0)); + throw new ArgumentOutOfRangeException(nameof(loadFactor), Environment.GetResourceString("ArgumentOutOfRange_HashtableLoadFactor", .1, 1.0)); Contract.EndContractBlock(); // Based on perf work, .72 is the optimal load factor for this table. @@ -290,7 +287,7 @@ namespace System.Collections { loadsize = (int)(this.loadFactor * hashsize); isWriterInProgress = false; // Based on the current algorithm, loadsize must be less than hashsize. - Contract.Assert( loadsize < hashsize, "Invalid hashtable loadsize!"); + Debug.Assert( loadsize < hashsize, "Invalid hashtable loadsize!"); } // Constructs a new hashtable with the given initial capacity and load @@ -375,7 +372,7 @@ namespace System.Collections { public Hashtable(IDictionary d, float loadFactor, IHashCodeProvider hcp, IComparer comparer) : this((d != null ? d.Count : 0), loadFactor, hcp, comparer) { if (d==null) - throw new ArgumentNullException("d", Environment.GetResourceString("ArgumentNull_Dictionary")); + throw new ArgumentNullException(nameof(d), Environment.GetResourceString("ArgumentNull_Dictionary")); Contract.EndContractBlock(); IDictionaryEnumerator e = d.GetEnumerator(); @@ -385,7 +382,7 @@ namespace System.Collections { public Hashtable(IDictionary d, float loadFactor, IEqualityComparer equalityComparer) : this((d != null ? d.Count : 0), loadFactor, equalityComparer) { if (d==null) - throw new ArgumentNullException("d", Environment.GetResourceString("ArgumentNull_Dictionary")); + throw new ArgumentNullException(nameof(d), Environment.GetResourceString("ArgumentNull_Dictionary")); Contract.EndContractBlock(); IDictionaryEnumerator e = d.GetEnumerator(); @@ -444,14 +441,11 @@ namespace System.Collections { // Removes all entries from this hashtable. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public virtual void Clear() { - Contract.Assert(!isWriterInProgress, "Race condition detected in usages of Hashtable - multiple threads appear to be writing to a Hashtable instance simultaneously! Don't do that - use Hashtable.Synchronized."); + Debug.Assert(!isWriterInProgress, "Race condition detected in usages of Hashtable - multiple threads appear to be writing to a Hashtable instance simultaneously! Don't do that - use Hashtable.Synchronized."); if (count == 0 && occupancy == 0) return; -#if !FEATURE_CORECLR - Thread.BeginCriticalRegion(); -#endif isWriterInProgress = true; for (int i = 0; i < buckets.Length; i++){ buckets[i].hash_coll = 0; @@ -463,9 +457,6 @@ namespace System.Collections { occupancy = 0; UpdateVersion(); isWriterInProgress = false; -#if !FEATURE_CORECLR - Thread.EndCriticalRegion(); -#endif } // Clone returns a virtually identical copy of this hash table. This does @@ -501,7 +492,7 @@ namespace System.Collections { // public virtual bool ContainsKey(Object key) { if (key == null) { - throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key")); + throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); } Contract.EndContractBlock(); @@ -526,9 +517,7 @@ namespace System.Collections { } while (b.hash_coll < 0 && ++ntry < lbuckets.Length); return false; } - - - + // Checks if this hashtable contains an entry with the given value. The // values of the entries of the hashtable are compared to the given value // using the Object.Equals method. This method performs a linear @@ -590,11 +579,11 @@ namespace System.Collections { public virtual void CopyTo(Array array, int arrayIndex) { if (array == null) - throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Array")); + throw new ArgumentNullException(nameof(array), Environment.GetResourceString("ArgumentNull_Array")); if (array.Rank != 1) throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported")); if (arrayIndex < 0) - throw new ArgumentOutOfRangeException("arrayIndex", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(arrayIndex), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (array.Length - arrayIndex < Count) throw new ArgumentException(Environment.GetResourceString("Arg_ArrayPlusOffTooSmall")); Contract.EndContractBlock(); @@ -643,7 +632,7 @@ namespace System.Collections { public virtual Object this[Object key] { get { if (key == null) { - throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key")); + throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); } Contract.EndContractBlock(); @@ -750,28 +739,23 @@ namespace System.Collections { for (nb = 0; nb < buckets.Length; nb++){ bucket oldb = buckets[nb]; if ((oldb.key != null) && (oldb.key != buckets)) { - int hashcode = ((forceNewHashCode ? GetHash(oldb.key) : oldb.hash_coll) & 0x7FFFFFFF); + int hashcode = ((forceNewHashCode ? GetHash(oldb.key) : oldb.hash_coll) & 0x7FFFFFFF); putEntry(newBuckets, oldb.key, oldb.val, hashcode); } } - + // New bucket[] is good to go - replace buckets and other internal state. -#if !FEATURE_CORECLR - Thread.BeginCriticalRegion(); -#endif isWriterInProgress = true; buckets = newBuckets; loadsize = (int)(loadFactor * newsize); UpdateVersion(); isWriterInProgress = false; -#if !FEATURE_CORECLR - Thread.EndCriticalRegion(); -#endif + // minimun size of hashtable is 3 now and maximum loadFactor is 0.72 now. - Contract.Assert(loadsize < newsize, "Our current implementaion means this is not possible."); + Debug.Assert(loadsize < newsize, "Our current implementaion means this is not possible."); return; } - + // Returns an enumerator for this hashtable. // If modifications made to the hashtable while an enumeration is // in progress, the MoveNext and Current methods of the @@ -820,7 +804,7 @@ namespace System.Collections { // protected virtual bool KeyEquals(Object item, Object key) { - Contract.Assert(key != null, "key can't be null here!"); + Debug.Assert(key != null, "key can't be null here!"); if( Object.ReferenceEquals(buckets, item)) { return false; } @@ -872,7 +856,7 @@ namespace System.Collections { [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] private void Insert (Object key, Object nvalue, bool add) { if (key == null) { - throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key")); + throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); } Contract.EndContractBlock(); if (count >= loadsize) { @@ -913,36 +897,14 @@ namespace System.Collections { // We pretty much have to insert in this order. Don't set hash // code until the value & key are set appropriately. -#if !FEATURE_CORECLR - Thread.BeginCriticalRegion(); -#endif - isWriterInProgress = true; + isWriterInProgress = true; buckets[bucketNumber].val = nvalue; buckets[bucketNumber].key = key; buckets[bucketNumber].hash_coll |= (int) hashcode; count++; UpdateVersion(); isWriterInProgress = false; -#if !FEATURE_CORECLR - Thread.EndCriticalRegion(); -#endif -#if FEATURE_RANDOMIZED_STRING_HASHING -#if !FEATURE_CORECLR - // coreclr has the randomized string hashing on by default so we don't need to resize at this point - - if(ntry > HashHelpers.HashCollisionThreshold && HashHelpers.IsWellKnownEqualityComparer(_keycomparer)) - { - // PERF: We don't want to rehash if _keycomparer is already a RandomizedObjectEqualityComparer since in some - // cases there may not be any strings in the hashtable and we wouldn't get any mixing. - if(_keycomparer == null || !(_keycomparer is System.Collections.Generic.RandomizedObjectEqualityComparer)) - { - _keycomparer = HashHelpers.GetRandomizedEqualityComparer(_keycomparer); - rehash(buckets.Length, true); - } - } -#endif // !FEATURE_CORECLR -#endif // FEATURE_RANDOMIZED_STRING_HASHING return; } @@ -954,31 +916,10 @@ namespace System.Collections { if (add) { throw new ArgumentException(Environment.GetResourceString("Argument_AddingDuplicate__", buckets[bucketNumber].key, key)); } -#if !FEATURE_CORECLR - Thread.BeginCriticalRegion(); -#endif - isWriterInProgress = true; + isWriterInProgress = true; buckets[bucketNumber].val = nvalue; - UpdateVersion(); + UpdateVersion(); isWriterInProgress = false; -#if !FEATURE_CORECLR - Thread.EndCriticalRegion(); -#endif - -#if FEATURE_RANDOMIZED_STRING_HASHING -#if !FEATURE_CORECLR - if(ntry > HashHelpers.HashCollisionThreshold && HashHelpers.IsWellKnownEqualityComparer(_keycomparer)) - { - // PERF: We don't want to rehash if _keycomparer is already a RandomizedObjectEqualityComparer since in some - // cases there may not be any strings in the hashtable and we wouldn't get any mixing. - if(_keycomparer == null || !(_keycomparer is System.Collections.Generic.RandomizedObjectEqualityComparer)) - { - _keycomparer = HashHelpers.GetRandomizedEqualityComparer(_keycomparer); - rehash(buckets.Length, true); - } - } -#endif // !FEATURE_CORECLR -#endif return; } @@ -992,7 +933,7 @@ namespace System.Collections { } } - bucketNumber = (int) (((long)bucketNumber + incr)% (uint)buckets.Length); + bucketNumber = (int) (((long)bucketNumber + incr)% (uint)buckets.Length); } while (++ntry < buckets.Length); // This code is here if and only if there were no buckets without a collision bit set in the entire table @@ -1000,47 +941,27 @@ namespace System.Collections { { // We pretty much have to insert in this order. Don't set hash // code until the value & key are set appropriately. -#if !FEATURE_CORECLR - Thread.BeginCriticalRegion(); -#endif - isWriterInProgress = true; + isWriterInProgress = true; buckets[emptySlotNumber].val = nvalue; buckets[emptySlotNumber].key = key; buckets[emptySlotNumber].hash_coll |= (int) hashcode; count++; UpdateVersion(); isWriterInProgress = false; -#if !FEATURE_CORECLR - Thread.EndCriticalRegion(); -#endif -#if FEATURE_RANDOMIZED_STRING_HASHING -#if !FEATURE_CORECLR - if(buckets.Length > HashHelpers.HashCollisionThreshold && HashHelpers.IsWellKnownEqualityComparer(_keycomparer)) - { - // PERF: We don't want to rehash if _keycomparer is already a RandomizedObjectEqualityComparer since in some - // cases there may not be any strings in the hashtable and we wouldn't get any mixing. - if(_keycomparer == null || !(_keycomparer is System.Collections.Generic.RandomizedObjectEqualityComparer)) - { - _keycomparer = HashHelpers.GetRandomizedEqualityComparer(_keycomparer); - rehash(buckets.Length, true); - } - } -#endif // !FEATURE_CORECLR -#endif return; } - + // If you see this assert, make sure load factor & count are reasonable. // Then verify that our double hash function (h2, described at top of file) // meets the requirements described above. You should never see this assert. - Contract.Assert(false, "hash table insert failed! Load factor too high, or our double hashing function is incorrect."); + Debug.Assert(false, "hash table insert failed! Load factor too high, or our double hashing function is incorrect."); throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HashInsertFailed")); } private void putEntry (bucket[] newBuckets, Object key, Object nvalue, int hashcode) { - Contract.Assert(hashcode >= 0, "hashcode >= 0"); // make sure collision bit (sign bit) wasn't set. + Debug.Assert(hashcode >= 0, "hashcode >= 0"); // make sure collision bit (sign bit) wasn't set. uint seed = (uint) hashcode; uint incr = (uint)(1 + ((seed * HashPrime) % ((uint)newBuckets.Length - 1))); @@ -1058,7 +979,7 @@ namespace System.Collections { newBuckets[bucketNumber].hash_coll |= unchecked((int)0x80000000); occupancy++; } - bucketNumber = (int) (((long)bucketNumber + incr)% (uint)newBuckets.Length); + bucketNumber = (int) (((long)bucketNumber + incr)% (uint)newBuckets.Length); } while (true); } @@ -1069,10 +990,10 @@ namespace System.Collections { [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public virtual void Remove(Object key) { if (key == null) { - throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key")); + throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); } Contract.EndContractBlock(); - Contract.Assert(!isWriterInProgress, "Race condition detected in usages of Hashtable - multiple threads appear to be writing to a Hashtable instance simultaneously! Don't do that - use Hashtable.Synchronized."); + Debug.Assert(!isWriterInProgress, "Race condition detected in usages of Hashtable - multiple threads appear to be writing to a Hashtable instance simultaneously! Don't do that - use Hashtable.Synchronized."); uint seed; uint incr; @@ -1086,9 +1007,6 @@ namespace System.Collections { b = buckets[bn]; if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && KeyEquals (b.key, key)) { -#if !FEATURE_CORECLR - Thread.BeginCriticalRegion(); -#endif isWriterInProgress = true; // Clear hash_coll field, then key, then value buckets[bn].hash_coll &= unchecked((int)0x80000000); @@ -1102,12 +1020,9 @@ namespace System.Collections { count--; UpdateVersion(); isWriterInProgress = false; -#if !FEATURE_CORECLR - Thread.EndCriticalRegion(); -#endif return; } - bn = (int) (((long)bn + incr)% (uint)buckets.Length); + bn = (int) (((long)bn + incr)% (uint)buckets.Length); } while (b.hash_coll < 0 && ++ntry < buckets.Length); //throw new ArgumentException(Environment.GetResourceString("Arg_RemoveArgNotFound")); @@ -1131,10 +1046,9 @@ namespace System.Collections { // Returns a thread-safe wrapper for a Hashtable. // - [HostProtection(Synchronization=true)] public static Hashtable Synchronized(Hashtable table) { if (table==null) - throw new ArgumentNullException("table"); + throw new ArgumentNullException(nameof(table)); Contract.EndContractBlock(); return new SyncHashtable(table); } @@ -1143,10 +1057,9 @@ namespace System.Collections { // The ISerializable Implementation // - [System.Security.SecurityCritical] public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { if (info==null) { - throw new ArgumentNullException("info"); + throw new ArgumentNullException(nameof(info)); } Contract.EndContractBlock(); // This is imperfect - it only works well if all other writes are @@ -1302,11 +1215,11 @@ namespace System.Collections { public virtual void CopyTo(Array array, int arrayIndex) { if (array==null) - throw new ArgumentNullException("array"); + throw new ArgumentNullException(nameof(array)); if (array.Rank != 1) throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported")); if (arrayIndex < 0) - throw new ArgumentOutOfRangeException("arrayIndex", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(arrayIndex), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); Contract.EndContractBlock(); if (array.Length - arrayIndex < _hashtable.count) throw new ArgumentException(Environment.GetResourceString("Arg_ArrayPlusOffTooSmall")); @@ -1343,11 +1256,11 @@ namespace System.Collections { public virtual void CopyTo(Array array, int arrayIndex) { if (array==null) - throw new ArgumentNullException("array"); + throw new ArgumentNullException(nameof(array)); if (array.Rank != 1) throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported")); if (arrayIndex < 0) - throw new ArgumentOutOfRangeException("arrayIndex", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(arrayIndex), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); Contract.EndContractBlock(); if (array.Length - arrayIndex < _hashtable.count) throw new ArgumentException(Environment.GetResourceString("Arg_ArrayPlusOffTooSmall")); @@ -1399,10 +1312,9 @@ namespace System.Collections { ** context -- the StreamingContext for the current serialization (ignored) **Exceptions: ArgumentNullException if info is null. ==============================================================================*/ - [System.Security.SecurityCritical] // auto-generated public override void GetObjectData(SerializationInfo info, StreamingContext context) { if (info==null) { - throw new ArgumentNullException("info"); + throw new ArgumentNullException(nameof(info)); } Contract.EndContractBlock(); // Our serialization code hasn't been fully tweaked to be safe @@ -1461,7 +1373,7 @@ namespace System.Collections { public override bool ContainsKey(Object key) { if (key == null) { - throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key")); + throw new ArgumentNullException(nameof(key), Environment.GetResourceString("ArgumentNull_Key")); } Contract.EndContractBlock(); return _table.ContainsKey(key); @@ -1630,7 +1542,7 @@ namespace System.Collections { public HashtableDebugView( Hashtable hashtable) { if( hashtable == null) { - throw new ArgumentNullException( "hashtable"); + throw new ArgumentNullException(nameof(hashtable)); } Contract.EndContractBlock(); @@ -1746,7 +1658,7 @@ namespace System.Collections { // Note that this check works even when _items.Length overflowed thanks to the (uint) cast if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize) { - Contract.Assert( MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength"); + Debug.Assert( MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength"); return MaxPrimeArrayLength; } @@ -1765,7 +1677,7 @@ namespace System.Collections { public static IEqualityComparer GetRandomizedEqualityComparer(object comparer) { - Contract.Assert(comparer == null || comparer == System.Collections.Generic.EqualityComparer<string>.Default || comparer is IWellKnownStringEqualityComparer); + Debug.Assert(comparer == null || comparer == System.Collections.Generic.EqualityComparer<string>.Default || comparer is IWellKnownStringEqualityComparer); if(comparer == null) { return new System.Collections.Generic.RandomizedObjectEqualityComparer(); @@ -1781,7 +1693,7 @@ namespace System.Collections { return cmp.GetRandomizedEqualityComparer(); } - Contract.Assert(false, "Missing case in GetRandomizedEqualityComparer!"); + Debug.Assert(false, "Missing case in GetRandomizedEqualityComparer!"); return null; } @@ -1804,9 +1716,6 @@ namespace System.Collections { } private const int bufferSize = 1024; -#if !FEATURE_CORECLR - private static RandomNumberGenerator rng; -#endif private static byte[] data; private static int currentIndex = bufferSize; private static readonly object lockObj = new Object(); @@ -1821,18 +1730,10 @@ namespace System.Collections { if(data == null) { data = new byte[bufferSize]; - Contract.Assert(bufferSize % 8 == 0, "We increment our current index by 8, so our buffer size must be a multiple of 8"); -#if !FEATURE_CORECLR - rng = RandomNumberGenerator.Create(); -#endif - + Debug.Assert(bufferSize % 8 == 0, "We increment our current index by 8, so our buffer size must be a multiple of 8"); } -#if FEATURE_CORECLR Microsoft.Win32.Win32Native.Random(true, data, data.Length); -#else - rng.GetBytes(data); -#endif currentIndex = 0; } |