util.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package hashmap
  2. import (
  3. "fmt"
  4. "reflect"
  5. "strconv"
  6. "unsafe"
  7. "github.com/dchest/siphash"
  8. )
  9. const (
  10. // intSizeBytes is the size in byte of an int or uint value.
  11. intSizeBytes = strconv.IntSize >> 3
  12. // generated by splitting the md5 sum of "hashmap"
  13. sipHashKey1 = 0xdda7806a4847ec61
  14. sipHashKey2 = 0xb5940c2623a5aabd
  15. )
  16. // roundUpPower2 rounds a number to the next power of 2.
  17. func roundUpPower2(i uintptr) uintptr {
  18. i--
  19. i |= i >> 1
  20. i |= i >> 2
  21. i |= i >> 4
  22. i |= i >> 8
  23. i |= i >> 16
  24. i |= i >> 32
  25. i++
  26. return i
  27. }
  28. // log2 computes the binary logarithm of x, rounded up to the next integer.
  29. func log2(i uintptr) uintptr {
  30. var n, p uintptr
  31. for p = 1; p < i; p += p {
  32. n++
  33. }
  34. return n
  35. }
  36. // getKeyHash returns a hash for the key. Only string and number types are supported.
  37. func getKeyHash(key interface{}) uintptr {
  38. switch x := key.(type) {
  39. case string:
  40. return getStringHash(x)
  41. case []byte:
  42. return uintptr(siphash.Hash(sipHashKey1, sipHashKey2, x))
  43. case int:
  44. return getUintptrHash(uintptr(x))
  45. case int8:
  46. return getUintptrHash(uintptr(x))
  47. case int16:
  48. return getUintptrHash(uintptr(x))
  49. case int32:
  50. return getUintptrHash(uintptr(x))
  51. case int64:
  52. return getUintptrHash(uintptr(x))
  53. case uint:
  54. return getUintptrHash(uintptr(x))
  55. case uint8:
  56. return getUintptrHash(uintptr(x))
  57. case uint16:
  58. return getUintptrHash(uintptr(x))
  59. case uint32:
  60. return getUintptrHash(uintptr(x))
  61. case uint64:
  62. return getUintptrHash(uintptr(x))
  63. case uintptr:
  64. return getUintptrHash(x)
  65. }
  66. panic(fmt.Errorf("unsupported key type %T", key))
  67. }
  68. func getStringHash(s string) uintptr {
  69. sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
  70. bh := reflect.SliceHeader{
  71. Data: sh.Data,
  72. Len: sh.Len,
  73. Cap: sh.Len,
  74. }
  75. buf := *(*[]byte)(unsafe.Pointer(&bh))
  76. return uintptr(siphash.Hash(sipHashKey1, sipHashKey2, buf))
  77. }
  78. func getUintptrHash(num uintptr) uintptr {
  79. bh := reflect.SliceHeader{
  80. Data: uintptr(unsafe.Pointer(&num)),
  81. Len: intSizeBytes,
  82. Cap: intSizeBytes,
  83. }
  84. buf := *(*[]byte)(unsafe.Pointer(&bh))
  85. return uintptr(siphash.Hash(sipHashKey1, sipHashKey2, buf))
  86. }