diff --git a/src/StringTools/InternableString.Simple.cs b/src/StringTools/InternableString.Simple.cs index 7dd2b72b9ac..44955d274aa 100644 --- a/src/StringTools/InternableString.Simple.cs +++ b/src/StringTools/InternableString.Simple.cs @@ -200,29 +200,45 @@ public override unsafe string ToString() /// A stable hashcode of the string represented by this instance. public override int GetHashCode() { - int hashCode = 5381; + uint hash = (5381 << 16) + 5381; + bool isOddIndex = false; if (_firstString != null) { foreach (char ch in _firstString) { - unchecked - { - hashCode = hashCode * 33 ^ ch; - } + hash = HashOneCharacter(hash, ch, isOddIndex); + isOddIndex = !isOddIndex; } } else if (_builder != null) { for (int i = 0; i < _builder.Length; i++) { - unchecked - { - hashCode = hashCode * 33 ^ _builder[i]; - } + hash = HashOneCharacter(hash, _builder[i], isOddIndex); + isOddIndex = !isOddIndex; } } - return hashCode; + return (int)hash; + } + + /// + /// A helper to hash one character. + /// + /// The running hash code. + /// The character to hash. + /// True if the index of the character in the string is odd. + /// + private static uint HashOneCharacter(uint hash, char ch, bool isOddIndex) + { + if (isOddIndex) + { + // The hash code was rotated for the previous character, just xor. + return hash ^ ((uint)ch << 16); + } + + uint rotatedHash = (hash << 5) | (hash >> (32 - 5)); + return (rotatedHash + hash) ^ ch; } } }