DeterministicHashCode.cs 3.1 KB

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