DeterministicHashCode.cs
1 using System; 2 using System.Numerics; 3 using System.Runtime.CompilerServices; 4 5 namespace Spv.Generator 6 { 7 /// <summary> 8 /// Similar to System.HashCode, but without introducing random values. 9 /// The same primes and shifts are used. 10 /// </summary> 11 internal static class DeterministicHashCode 12 { 13 private const uint Prime1 = 2654435761U; 14 private const uint Prime2 = 2246822519U; 15 private const uint Prime3 = 3266489917U; 16 private const uint Prime4 = 668265263U; 17 18 public static int GetHashCode(string value) 19 { 20 uint hash = (uint)value.Length + Prime1; 21 22 for (int i = 0; i < value.Length; i++) 23 { 24 hash += (hash << 7) ^ value[i]; 25 } 26 27 return (int)MixFinal(hash); 28 } 29 30 public static int Combine<T>(ReadOnlySpan<T> values) 31 { 32 uint hashCode = Prime2; 33 hashCode += 4 * (uint)values.Length; 34 35 foreach (T value in values) 36 { 37 uint hc = (uint)(value?.GetHashCode() ?? 0); 38 hashCode = MixStep(hashCode, hc); 39 } 40 41 return (int)MixFinal(hashCode); 42 } 43 44 public static int Combine<T1, T2>(T1 value1, T2 value2) 45 { 46 uint hc1 = (uint)(value1?.GetHashCode() ?? 0); 47 uint hc2 = (uint)(value2?.GetHashCode() ?? 0); 48 49 uint hash = Prime2; 50 hash += 8; 51 52 hash = MixStep(hash, hc1); 53 hash = MixStep(hash, hc2); 54 55 return (int)MixFinal(hash); 56 } 57 58 public static int Combine<T1, T2, T3>(T1 value1, T2 value2, T3 value3) 59 { 60 uint hc1 = (uint)(value1?.GetHashCode() ?? 0); 61 uint hc2 = (uint)(value2?.GetHashCode() ?? 0); 62 uint hc3 = (uint)(value3?.GetHashCode() ?? 0); 63 64 uint hash = Prime2; 65 hash += 12; 66 67 hash = MixStep(hash, hc1); 68 hash = MixStep(hash, hc2); 69 hash = MixStep(hash, hc3); 70 71 return (int)MixFinal(hash); 72 } 73 74 public static int Combine<T1, T2, T3, T4>(T1 value1, T2 value2, T3 value3, T4 value4) 75 { 76 uint hc1 = (uint)(value1?.GetHashCode() ?? 0); 77 uint hc2 = (uint)(value2?.GetHashCode() ?? 0); 78 uint hc3 = (uint)(value3?.GetHashCode() ?? 0); 79 uint hc4 = (uint)(value4?.GetHashCode() ?? 0); 80 81 uint hash = Prime2; 82 hash += 16; 83 84 hash = MixStep(hash, hc1); 85 hash = MixStep(hash, hc2); 86 hash = MixStep(hash, hc3); 87 hash = MixStep(hash, hc4); 88 89 return (int)MixFinal(hash); 90 } 91 92 [MethodImpl(MethodImplOptions.AggressiveInlining)] 93 private static uint MixStep(uint hashCode, uint mixValue) 94 { 95 return BitOperations.RotateLeft(hashCode + mixValue * Prime3, 17) * Prime4; 96 } 97 98 [MethodImpl(MethodImplOptions.AggressiveInlining)] 99 private static uint MixFinal(uint hash) 100 { 101 hash ^= hash >> 15; 102 hash *= Prime2; 103 hash ^= hash >> 13; 104 hash *= Prime3; 105 hash ^= hash >> 16; 106 return hash; 107 } 108 } 109 }