| 51 | */ |
| 52 | |
| 53 | public struct HashCode |
| 54 | { |
| 55 | private static readonly uint s_seed = GenerateGlobalSeed(); |
| 56 | |
| 57 | // private const uint Prime1 = 2654435761U; |
| 58 | private const uint Prime2 = 2246822519U; |
| 59 | private const uint Prime3 = 3266489917U; |
| 60 | private const uint Prime4 = 668265263U; |
| 61 | private const uint Prime5 = 374761393U; |
| 62 | |
| 63 | private static uint GenerateGlobalSeed() |
| 64 | { |
| 65 | using RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create(); |
| 66 | byte[] data = new byte[sizeof(uint)]; |
| 67 | randomNumberGenerator.GetBytes(data); |
| 68 | return BitConverter.ToUInt32(data, 0); |
| 69 | } |
| 70 | |
| 71 | public static int Combine<T1, T2>(T1 value1, T2 value2) |
| 72 | { |
| 73 | uint hc1 = (uint) (value1?.GetHashCode() ?? 0); |
| 74 | uint hc2 = (uint) (value2?.GetHashCode() ?? 0); |
| 75 | |
| 76 | uint hash = MixEmptyState(); |
| 77 | hash += 8; |
| 78 | |
| 79 | hash = QueueRound(hash, hc1); |
| 80 | hash = QueueRound(hash, hc2); |
| 81 | |
| 82 | hash = MixFinal(hash); |
| 83 | return (int) hash; |
| 84 | } |
| 85 | |
| 86 | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| 87 | private static uint QueueRound(uint hash, uint queuedValue) |
| 88 | { |
| 89 | return RotateLeft(hash + (queuedValue * Prime3), 17) * Prime4; |
| 90 | } |
| 91 | |
| 92 | private static uint MixEmptyState() |
| 93 | { |
| 94 | return s_seed + Prime5; |
| 95 | } |
| 96 | |
| 97 | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| 98 | private static uint MixFinal(uint hash) |
| 99 | { |
| 100 | hash ^= hash >> 15; |
| 101 | hash *= Prime2; |
| 102 | hash ^= hash >> 13; |
| 103 | hash *= Prime3; |
| 104 | hash ^= hash >> 16; |
| 105 | return hash; |
| 106 | } |
| 107 | |
| 108 | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| 109 | public static uint RotateLeft(uint value, int offset) |
| 110 | { |
nothing calls this directly
no outgoing calls
no test coverage detected