Skip to content

Commit

Permalink
Calculate hashcode pre-lock
Browse files Browse the repository at this point in the history
  • Loading branch information
benaadams committed Jan 16, 2021
1 parent 65ad845 commit 1fecf39
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 7 deletions.
60 changes: 60 additions & 0 deletions src/InternPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,66 @@ public unsafe string InternUtf8(ReadOnlySpan<byte> utf8Value)
}
}
#endif
internal int GetHashCode(ReadOnlySpan<char> value, out bool randomisedHash)
{
randomisedHash = _randomisedHash;
return randomisedHash ? value.GetRandomizedHashCode() : value.GetNonRandomizedHashCode();
}

/// <summary>Adds the specified element to the intern pool if it's not already contained.</summary>
/// <param name="value">The char sequence to add to the intern pool.</param>
/// <returns>The interned string.</returns>
internal string Intern(int hashCode, bool randomisedHash, ReadOnlySpan<char> value)
{
_lastUse += 2;
if (value.Length == 0) return string.Empty;
if (value.Length > _maxLength) return value.ToString();

if (_buckets == null)
{
Initialize(0);
}
Debug.Assert(_buckets != null);

Entry[]? entries = _entries;
Debug.Assert(entries != null, "expected entries to be non-null");

uint collisionCount = 0;
ref int bucket = ref Unsafe.NullRef<int>();

if (randomisedHash != _randomisedHash)
{
// Precalcuated hash mode changed before the lock was taken
hashCode = _randomisedHash ? value.GetRandomizedHashCode() : value.GetNonRandomizedHashCode();
}

bucket = ref GetBucketRef(hashCode);
int i = bucket - 1; // Value in _buckets is 1-based

while (i >= 0)
{
ref Entry entry = ref entries[i];
if (entry.HashCode == hashCode && value.SequenceEqual(entry.Value.AsSpan()))
{
if (entry.LastUse < 0)
{
RemoveFromChurnPool(entry.Value, entry.LastUse);
}
entry.LastUse = GetMultipleUse();
return entry.Value;
}
i = entry.Next;

collisionCount++;
if (collisionCount > (uint)entries.Length)
{
// The chain of entries forms a loop, which means a concurrent update has happened.
ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported();
}
}

return AddNewEntry(value.ToString(), ref entries, hashCode, collisionCount, ref bucket);
}

/// <summary>Adds the specified element to the intern pool if it's not already contained.</summary>
/// <param name="value">The char sequence to add to the intern pool.</param>
Expand Down
31 changes: 25 additions & 6 deletions src/SharedInternPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,12 @@ public string Intern(ReadOnlySpan<char> value)
var firstChar = value[0];
var pool = GetPool(firstChar);

// Calcuate hash outside lock
var hashCode = pool.GetHashCode(value, out bool randomisedHash);

lock (pool)
{
return pool.Intern(value);
return pool.Intern(hashCode, randomisedHash, value);
}
}

Expand All @@ -60,9 +63,13 @@ public string Intern(ReadOnlySpan<char> value)
var firstChar = value[0];
var pool = GetPool(firstChar);

// Calcuate hash outside lock
var span = value.AsSpan();
var hashCode = pool.GetHashCode(span, out bool randomisedHash);

lock (pool)
{
return pool.Intern(value);
return pool.Intern(hashCode, randomisedHash, span);
}
}

Expand Down Expand Up @@ -121,9 +128,12 @@ public string Intern(ReadOnlySpan<byte> value, Encoding encoding)

var pool = GetPool(span[0]);

// Calcuate hash outside lock
var hashCode = pool.GetHashCode(span, out bool randomisedHash);

lock (pool)
{
return pool.Intern(span);
return pool.Intern(hashCode, randomisedHash, span);
}
}
#else
Expand Down Expand Up @@ -159,9 +169,12 @@ public unsafe string Intern(ReadOnlySpan<byte> value, Encoding encoding)

var pool = GetPool(span[0]);

// Calcuate hash outside lock
var hashCode = pool.GetHashCode(span, out bool randomisedHash);

lock (pool)
{
return pool.Intern(span);
return pool.Intern(hashCode, randomisedHash, span);
}
}
}
Expand Down Expand Up @@ -198,9 +211,12 @@ public string InternUtf8(ReadOnlySpan<byte> utf8Value)

var pool = GetPool(span[0]);

// Calcuate hash outside lock
var hashCode = pool.GetHashCode(span, out bool randomisedHash);

lock (pool)
{
return pool.Intern(span);
return pool.Intern(hashCode, randomisedHash, span);
}
}
#else
Expand Down Expand Up @@ -236,9 +252,12 @@ public unsafe string InternUtf8(ReadOnlySpan<byte> utf8Value)

var pool = GetPool(span[0]);

// Calcuate hash outside lock
var hashCode = pool.GetHashCode(span, out bool randomisedHash);

lock (pool)
{
return pool.Intern(span);
return pool.Intern(hashCode, randomisedHash, span);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion version.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.1.3",
"version": "0.1.4",
"publicReleaseRefSpec": [
"^refs/heads/main$", // we release out of master
"^refs/heads/dev$", // we release out of develop
Expand Down

0 comments on commit 1fecf39

Please sign in to comment.