Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 20 additions & 32 deletions src/libraries/System.Private.CoreLib/src/System/HashCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals

Expand Down Expand Up @@ -317,9 +316,6 @@ public void Add<T>(T value, IEqualityComparer<T>? comparer)
/// </remarks>
public void AddBytes(ReadOnlySpan<byte> value)
{
ref byte pos = ref MemoryMarshal.GetReference(value);
ref byte end = ref Unsafe.Add(ref pos, value.Length);

if (value.Length < (sizeof(int) * 4))
{
goto Small;
Expand All @@ -337,55 +333,47 @@ public void AddBytes(ReadOnlySpan<byte> value)
switch (_length % 4)
{
case 1:
Debug.Assert(Unsafe.ByteOffset(ref pos, ref end) >= sizeof(int));
Add(Unsafe.ReadUnaligned<int>(ref pos));
pos = ref Unsafe.Add(ref pos, sizeof(int));
Debug.Assert(value.Length >= sizeof(int));
Add(BitConverter.ToInt32(value));
value = value.Slice(sizeof(int));
goto case 2;
case 2:
Debug.Assert(Unsafe.ByteOffset(ref pos, ref end) >= sizeof(int));
Add(Unsafe.ReadUnaligned<int>(ref pos));
pos = ref Unsafe.Add(ref pos, sizeof(int));
Debug.Assert(value.Length >= sizeof(int));
Add(BitConverter.ToInt32(value));
value = value.Slice(sizeof(int));
goto case 3;
case 3:
Debug.Assert(Unsafe.ByteOffset(ref pos, ref end) >= sizeof(int));
Add(Unsafe.ReadUnaligned<int>(ref pos));
pos = ref Unsafe.Add(ref pos, sizeof(int));
Debug.Assert(value.Length >= sizeof(int));
Add(BitConverter.ToInt32(value));
value = value.Slice(sizeof(int));
Comment thread
EgorBo marked this conversation as resolved.
break;
}
}

// With the queue clear, we add sixteen bytes at a time until the input has fewer than sixteen bytes remaining.
// We first have to round the end pointer to the nearest 16-byte block from the offset. This makes the loop's condition simpler.
ref byte blockEnd = ref Unsafe.Subtract(ref end, Unsafe.ByteOffset(ref pos, ref end) % (sizeof(int) * 4));
while (Unsafe.IsAddressLessThan(ref pos, ref blockEnd))
while (value.Length >= sizeof(int) * 4)
{
Debug.Assert(Unsafe.ByteOffset(ref pos, ref blockEnd) >= (sizeof(int) * 4));
uint v1 = Unsafe.ReadUnaligned<uint>(ref pos);
_v1 = Round(_v1, v1);
uint v2 = Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref pos, sizeof(int) * 1));
_v2 = Round(_v2, v2);
uint v3 = Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref pos, sizeof(int) * 2));
_v3 = Round(_v3, v3);
uint v4 = Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref pos, sizeof(int) * 3));
_v4 = Round(_v4, v4);
_v1 = Round(_v1, BitConverter.ToUInt32(value));
_v2 = Round(_v2, BitConverter.ToUInt32(value.Slice(sizeof(int) * 1)));
_v3 = Round(_v3, BitConverter.ToUInt32(value.Slice(sizeof(int) * 2)));
_v4 = Round(_v4, BitConverter.ToUInt32(value.Slice(sizeof(int) * 3)));

_length += 4;
pos = ref Unsafe.Add(ref pos, sizeof(int) * 4);
value = value.Slice(sizeof(int) * 4);
}

Small:
// Add four bytes at a time until the input has fewer than four bytes remaining.
while (Unsafe.ByteOffset(ref pos, ref end) >= sizeof(int))
while (value.Length >= sizeof(int))
{
Add(Unsafe.ReadUnaligned<int>(ref pos));
pos = ref Unsafe.Add(ref pos, sizeof(int));
Add(BitConverter.ToInt32(value));
value = value.Slice(sizeof(int));
}

// Add the remaining bytes a single byte at a time.
while (Unsafe.IsAddressLessThan(ref pos, ref end))
foreach (byte b in value)
{
Add((int)pos);
pos = ref Unsafe.Add(ref pos, 1);
Add((int)b);
Comment thread
EgorBo marked this conversation as resolved.
}
}

Expand Down
Loading