hash.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package cache
  2. import (
  3. "math"
  4. "reflect"
  5. )
  6. // Hash is an interface implemented by cache keys to
  7. // override default hash function.
  8. type Hash interface {
  9. Sum64() uint64
  10. }
  11. // sum calculates hash value of the given key.
  12. func sum(k interface{}) uint64 {
  13. switch h := k.(type) {
  14. case Hash:
  15. return h.Sum64()
  16. case int:
  17. return hashU64(uint64(h))
  18. case int8:
  19. return hashU32(uint32(h))
  20. case int16:
  21. return hashU32(uint32(h))
  22. case int32:
  23. return hashU32(uint32(h))
  24. case int64:
  25. return hashU64(uint64(h))
  26. case uint:
  27. return hashU64(uint64(h))
  28. case uint8:
  29. return hashU32(uint32(h))
  30. case uint16:
  31. return hashU32(uint32(h))
  32. case uint32:
  33. return hashU32(h)
  34. case uint64:
  35. return hashU64(h)
  36. case uintptr:
  37. return hashU64(uint64(h))
  38. case float32:
  39. return hashU32(math.Float32bits(h))
  40. case float64:
  41. return hashU64(math.Float64bits(h))
  42. case bool:
  43. if h {
  44. return 1
  45. }
  46. return 0
  47. case string:
  48. return hashString(h)
  49. }
  50. // TODO: complex64 and complex128
  51. if h, ok := hashPointer(k); ok {
  52. return h
  53. }
  54. // TODO: use gob to encode k to bytes then hash.
  55. return 0
  56. }
  57. const (
  58. fnvOffset uint64 = 14695981039346656037
  59. fnvPrime uint64 = 1099511628211
  60. )
  61. func hashU64(v uint64) uint64 {
  62. // Inline code from hash/fnv to reduce memory allocations
  63. h := fnvOffset
  64. // for i := uint(0); i < 64; i += 8 {
  65. // h ^= (v >> i) & 0xFF
  66. // h *= fnvPrime
  67. // }
  68. h ^= (v >> 0) & 0xFF
  69. h *= fnvPrime
  70. h ^= (v >> 8) & 0xFF
  71. h *= fnvPrime
  72. h ^= (v >> 16) & 0xFF
  73. h *= fnvPrime
  74. h ^= (v >> 24) & 0xFF
  75. h *= fnvPrime
  76. h ^= (v >> 32) & 0xFF
  77. h *= fnvPrime
  78. h ^= (v >> 40) & 0xFF
  79. h *= fnvPrime
  80. h ^= (v >> 48) & 0xFF
  81. h *= fnvPrime
  82. h ^= (v >> 56) & 0xFF
  83. h *= fnvPrime
  84. return h
  85. }
  86. func hashU32(v uint32) uint64 {
  87. h := fnvOffset
  88. h ^= uint64(v>>0) & 0xFF
  89. h *= fnvPrime
  90. h ^= uint64(v>>8) & 0xFF
  91. h *= fnvPrime
  92. h ^= uint64(v>>16) & 0xFF
  93. h *= fnvPrime
  94. h ^= uint64(v>>24) & 0xFF
  95. h *= fnvPrime
  96. return h
  97. }
  98. // hashString calculates hash value using FNV-1a algorithm.
  99. func hashString(data string) uint64 {
  100. // Inline code from hash/fnv to reduce memory allocations
  101. h := fnvOffset
  102. for _, b := range data {
  103. h ^= uint64(b)
  104. h *= fnvPrime
  105. }
  106. return h
  107. }
  108. func hashPointer(k interface{}) (uint64, bool) {
  109. v := reflect.ValueOf(k)
  110. switch v.Kind() {
  111. case reflect.Ptr, reflect.UnsafePointer, reflect.Func, reflect.Slice, reflect.Map, reflect.Chan:
  112. return hashU64(uint64(v.Pointer())), true
  113. default:
  114. return 0, false
  115. }
  116. }