Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 5c0429a

Browse files
committed
Externalize Dictionary Rehash
1 parent 79e69a9 commit 5c0429a

File tree

1 file changed

+43
-37
lines changed

1 file changed

+43
-37
lines changed

src/mscorlib/shared/System/Collections/Generic/Dictionary.cs

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,21 @@ internal enum InsertionBehavior : byte
3737
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
3838
public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>, ISerializable, IDeserializationCallback
3939
{
40-
private struct Entry
40+
internal struct Entry
4141
{
4242
public int hashCode; // Lower 31 bits of hash code, -1 if unused
4343
public int next; // Index of next entry, -1 if last
4444
public TKey key; // Key of entry
4545
public TValue value; // Value of entry
4646
}
4747

48-
private int[] _buckets;
49-
private Entry[] _entries;
50-
private int _count;
48+
internal int[] _buckets;
49+
internal Entry[] _entries;
50+
internal int _count;
5151
private int _version;
5252
private int _freeList;
5353
private int _freeCount;
54-
private IEqualityComparer<TKey> _comparer;
54+
internal IEqualityComparer<TKey> _comparer;
5555
private KeyCollection _keys;
5656
private ValueCollection _values;
5757
private object _syncRoot;
@@ -440,13 +440,13 @@ private bool TryInsert(TKey key, TValue value, InsertionBehavior behavior)
440440
_buckets[targetBucket] = index;
441441
_version++;
442442

443-
// If we hit the collision threshold we'll need to switch to the comparer which is using randomized string hashing
444-
// i.e. EqualityComparer<string>.Default.
445443

446444
if (default(TKey) == null && collisionCount > HashHelpers.HashCollisionThreshold && _comparer is NonRandomizedStringEqualityComparer)
447445
{
446+
// If we hit the collision threshold we'll need to switch to the comparer which is using randomized string hashing
447+
// i.e. EqualityComparer<string>.Default.
448448
_comparer = (IEqualityComparer<TKey>)EqualityComparer<string>.Default;
449-
Rehash();
449+
DictionaryHelper.Rehash((Dictionary<string, TValue>)(object)this);
450450
}
451451

452452
return true;
@@ -498,35 +498,6 @@ public virtual void OnDeserialization(object sender)
498498
HashHelpers.SerializationInfoTable.Remove(this);
499499
}
500500

501-
private void Rehash()
502-
{
503-
int[] buckets = _buckets;
504-
for (int i = 0; i < buckets.Length; i++)
505-
{
506-
buckets[i] = -1;
507-
}
508-
509-
int count = _count;
510-
int length = buckets.Length;
511-
Entry[] entries = _entries;
512-
513-
IEqualityComparer<TKey> comparer = _comparer;
514-
515-
for (int i = 0; i < count; i++)
516-
{
517-
ref Entry entry = ref entries[i];
518-
int hashCode = entry.hashCode;
519-
if (hashCode >= 0)
520-
{
521-
hashCode = (comparer.GetHashCode(entry.key) & 0x7FFFFFFF);
522-
int bucket = hashCode % length;
523-
entry.hashCode = hashCode;
524-
entry.next = buckets[bucket];
525-
buckets[bucket] = i;
526-
}
527-
}
528-
}
529-
530501
private void Expand(int prime)
531502
{
532503
Debug.Assert(HashHelpers.IsPrime(prime));
@@ -1485,4 +1456,39 @@ void System.Collections.IEnumerator.Reset()
14851456
}
14861457
}
14871458
}
1459+
1460+
internal class DictionaryHelper
1461+
{
1462+
internal static void Rehash<TValue>(Dictionary<string, TValue> dict)
1463+
{
1464+
// Rehash is externalised for string keys only; rather than an instance method
1465+
// so it isn't compiled into every generic instance type for AOT compiles
1466+
1467+
int[] buckets = dict._buckets;
1468+
for (int i = 0; i < buckets.Length; i++)
1469+
{
1470+
buckets[i] = -1;
1471+
}
1472+
1473+
int count = dict._count;
1474+
int length = buckets.Length;
1475+
Dictionary<string, TValue>.Entry[] entries = dict._entries;
1476+
1477+
IEqualityComparer<string> comparer = dict._comparer;
1478+
1479+
for (int i = 0; i < count; i++)
1480+
{
1481+
ref Dictionary<string, TValue>.Entry entry = ref entries[i];
1482+
int hashCode = entry.hashCode;
1483+
if (hashCode >= 0)
1484+
{
1485+
hashCode = (comparer.GetHashCode(entry.key) & 0x7FFFFFFF);
1486+
int bucket = hashCode % length;
1487+
entry.hashCode = hashCode;
1488+
entry.next = buckets[bucket];
1489+
buckets[bucket] = i;
1490+
}
1491+
}
1492+
}
1493+
}
14881494
}

0 commit comments

Comments
 (0)