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

Commit

Permalink
x64 only
Browse files Browse the repository at this point in the history
  • Loading branch information
benaadams committed Oct 24, 2019
1 parent abbe77d commit ee71bd6
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ private struct Entry
public TValue value; // Value of entry
}

private ulong _fastModMultiplier;
private int[]? _buckets;
private Entry[]? _entries;
#if BIT64
private ulong _fastModMultiplier;
#endif
private int _count;
private int _freeList;
private int _freeCount;
Expand Down Expand Up @@ -340,7 +342,7 @@ private ref TValue FindValue(TKey key)
if (comparer == null)
{
uint hashCode = (uint)key.GetHashCode();
int i = buckets[HashHelpers.FastMod(hashCode, (uint)buckets.Length, _fastModMultiplier)];
int i = buckets[FastMod(hashCode, (uint)buckets.Length)];
Entry[]? entries = _entries;
uint collisionCount = 0;
if (default(TKey)! != null) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
Expand Down Expand Up @@ -408,7 +410,7 @@ private ref TValue FindValue(TKey key)
else
{
uint hashCode = (uint)comparer.GetHashCode(key);
int i = buckets[HashHelpers.FastMod(hashCode, (uint)buckets.Length, _fastModMultiplier)];
int i = buckets[FastMod(hashCode, (uint)buckets.Length)];
Entry[]? entries = _entries;
uint collisionCount = 0;
// Value in _buckets is 1-based; subtract 1 from i. We do it here so it fuses with the following conditional.
Expand Down Expand Up @@ -454,7 +456,9 @@ private ref TValue FindValue(TKey key)
private int Initialize(int capacity)
{
int size = HashHelpers.GetPrime(capacity);
#if BIT64
_fastModMultiplier = HashHelpers.GetFastModMultiplier((uint)size);
#endif

_freeList = -1;
_buckets = new int[size];
Expand Down Expand Up @@ -483,7 +487,7 @@ private bool TryInsert(TKey key, TValue value, InsertionBehavior behavior)
uint hashCode = (uint)((comparer == null) ? key.GetHashCode() : comparer.GetHashCode(key));

uint collisionCount = 0;
ref int bucket = ref _buckets[HashHelpers.FastMod(hashCode, (uint)_buckets.Length, _fastModMultiplier)];
ref int bucket = ref _buckets[FastMod(hashCode, (uint)_buckets.Length)];
// Value in _buckets is 1-based
int i = bucket - 1;

Expand Down Expand Up @@ -627,7 +631,7 @@ private bool TryInsert(TKey key, TValue value, InsertionBehavior behavior)
if (count == entries.Length)
{
Resize();
bucket = ref _buckets[HashHelpers.FastMod(hashCode, (uint)_buckets.Length, _fastModMultiplier)];
bucket = ref _buckets[FastMod(hashCode, (uint)_buckets.Length)];
}
index = count;
_count = count + 1;
Expand Down Expand Up @@ -711,7 +715,9 @@ public virtual void OnDeserialization(object? sender)
private void Resize()
{
int size = HashHelpers.ExpandPrime(_count);
#if BIT64
_fastModMultiplier = HashHelpers.GetFastModMultiplier((uint)size);
#endif
Resize(size, false);
}

Expand Down Expand Up @@ -744,7 +750,7 @@ private void Resize(int newSize, bool forceNewHashCodes)
{
if (entries[i].next >= -1)
{
uint bucket = HashHelpers.FastMod(entries[i].hashCode, (uint)newSize, _fastModMultiplier);
uint bucket = FastMod(entries[i].hashCode, (uint)newSize);
// Value in _buckets is 1-based
entries[i].next = buckets[bucket] - 1;
// Value in _buckets is 1-based
Expand Down Expand Up @@ -773,7 +779,7 @@ public bool Remove(TKey key)
Debug.Assert(entries != null, "entries should be non-null");
uint collisionCount = 0;
uint hashCode = (uint)(_comparer?.GetHashCode(key) ?? key.GetHashCode());
uint bucket = HashHelpers.FastMod(hashCode, (uint)buckets.Length, _fastModMultiplier);
uint bucket = FastMod(hashCode, (uint)buckets.Length);
int last = -1;
// Value in buckets is 1-based
int i = buckets[bucket] - 1;
Expand Down Expand Up @@ -842,7 +848,7 @@ public bool Remove(TKey key, [MaybeNullWhen(false)] out TValue value)
Debug.Assert(entries != null, "entries should be non-null");
uint collisionCount = 0;
uint hashCode = (uint)(_comparer?.GetHashCode(key) ?? key.GetHashCode());
uint bucket = HashHelpers.FastMod(hashCode, (uint)buckets.Length, _fastModMultiplier);
uint bucket = FastMod(hashCode, (uint)buckets.Length);
int last = -1;
// Value in buckets is 1-based
int i = buckets[bucket] - 1;
Expand Down Expand Up @@ -989,7 +995,9 @@ public int EnsureCapacity(int capacity)
if (_buckets == null)
return Initialize(capacity);
int newSize = HashHelpers.GetPrime(capacity);
#if BIT64
_fastModMultiplier = HashHelpers.GetFastModMultiplier((uint)newSize);
#endif
Resize(newSize, forceNewHashCodes: false);
return newSize;
}
Expand Down Expand Up @@ -1019,7 +1027,9 @@ public void TrimExcess(int capacity)
if (capacity < Count)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity);
int newSize = HashHelpers.GetPrime(capacity);
#if BIT64
_fastModMultiplier = HashHelpers.GetFastModMultiplier((uint)newSize);
#endif

Entry[]? oldEntries = _entries;
int currentCapacity = oldEntries == null ? 0 : oldEntries.Length;
Expand All @@ -1039,7 +1049,7 @@ public void TrimExcess(int capacity)
{
ref Entry entry = ref entries![count];
entry = oldEntries[i];
uint bucket = HashHelpers.FastMod(hashCode, (uint)newSize, _fastModMultiplier);
uint bucket = FastMod(hashCode, (uint)newSize);
// Value in _buckets is 1-based
entry.next = buckets![bucket] - 1; // If we get here, we have entries, therefore buckets is not null.
// Value in _buckets is 1-based
Expand Down Expand Up @@ -1161,6 +1171,14 @@ void IDictionary.Remove(object key)
}
}

#if BIT64
private uint FastMod(uint value, uint divisor)
=> HashHelpers.FastMod(value, divisor, _fastModMultiplier);
#else
private static uint FastMod(uint value, uint divisor)
=> value % divisor;
#endif

public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>,
IDictionaryEnumerator
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public static int ExpandPrime(int oldSize)
return GetPrime(newSize);
}

#if BIT64
public static ulong GetFastModMultiplier(uint divisor)
=> ulong.MaxValue / divisor + 1;

Expand All @@ -111,5 +112,6 @@ public static unsafe uint FastMod(uint value, uint divisor, ulong multiplier)
return value % divisor;
}
}
#endif
}
}

0 comments on commit ee71bd6

Please sign in to comment.