github.com/jxskiss/gopkg@v0.17.3/rthash/hash.go (about) 1 // Package rthash exposes the various hash functions in runtime package. 2 // 3 // The idea mainly comes from https://github.com/golang/go/issues/21195. 4 package rthash 5 6 import ( 7 "github.com/jxskiss/gopkg/internal/linkname" 8 "unsafe" 9 ) 10 11 // Hash exposes the various hash functions in runtime package. 12 // The idea mainly comes from https://github.com/golang/go/issues/21195. 13 // 14 // See also: hash/maphash.Hash. 15 // 16 // Unlike hash.Hash or hash/maphash.Hash, this Hash does not provide 17 // the ability to reset seed, the seed must be provided when creating the 18 // Hash instance and will be used during the lifetime. 19 // 20 // This Hash type is intended to be used to do fast sharding, when 21 // implementing hash tables or other data structures, it's recommended 22 // to consider using hash/maphash.Hash as a proper choice. 23 // 24 // The hash functions are not cryptographically secure. 25 // (See crypto/sha256 and crypto/sha512 for cryptographic use.) 26 // 27 // A Hash must be initialized by calling New(). 28 // After initialized, a Hash is safe for concurrent use by multiple goroutines. 29 // 30 // Each call to a same method with the same value will return the same 31 // result for a Hash instance, but it may and supposed to return different 32 // hash results from each Hash instance. 33 type Hash struct { 34 seed uintptr 35 } 36 37 // New returns a new Hash instance, which exposes the various hash functions 38 // in runtime package. The returned Hash instance is safe for concurrent use 39 // by multiple goroutines. 40 func New() Hash { 41 seed := uintptr(makeseed()) 42 return Hash{seed: seed} 43 } 44 45 // Hash returns a hash code for a comparable argument. 46 // 47 // Note this function calls the hash functions for the concrete type if 48 // x is of type string, int8, uint8, int16, uint16, int32, uint32, 49 // int64, uint64, int, uint, uintptr, float32, float64, complex64, 50 // or complex128, else it calls 51 func (h Hash) Hash(x interface{}) uintptr { 52 switch v := x.(type) { 53 case string: 54 return h.String(v) 55 case int8: 56 return h.Int8(v) 57 case uint8: 58 return h.Uint8(v) 59 case int16: 60 return h.Int16(v) 61 case uint16: 62 return h.Uint16(v) 63 case int32: 64 return h.Int32(v) 65 case uint32: 66 return h.Uint32(v) 67 case int64: 68 return h.Int64(v) 69 case uint64: 70 return h.Uint64(v) 71 case int: 72 return h.Int(v) 73 case uint: 74 return h.Uint(v) 75 case uintptr: 76 return h.Uintptr(v) 77 case float32: 78 return h.Float32(v) 79 case float64: 80 return h.Float64(v) 81 case complex64: 82 return h.Complex64(v) 83 case complex128: 84 return h.Complex128(v) 85 default: 86 return h.Interface(v) 87 } 88 } 89 90 // String exposes the stringHash function from runtime package. 91 func (h Hash) String(x string) uintptr { 92 return linkname.Runtime_stringHash(x, h.seed) 93 } 94 95 // Bytes exposes the bytesHash function from runtime package. 96 func (h Hash) Bytes(x []byte) uintptr { 97 return linkname.Runtime_bytesHash(x, h.seed) 98 } 99 100 // Int8 exposes the memhash8 function from runtime package. 101 func (h Hash) Int8(x int8) uintptr { 102 return linkname.Runtime_memhash8(unsafe.Pointer(&x), h.seed) 103 } 104 105 // Uint8 exposes the memhash8 function from runtime package. 106 func (h Hash) Uint8(x uint8) uintptr { 107 return linkname.Runtime_memhash8(unsafe.Pointer(&x), h.seed) 108 } 109 110 // Int16 exposes the memhash16 function from runtime package. 111 func (h Hash) Int16(x int16) uintptr { 112 return linkname.Runtime_memhash16(unsafe.Pointer(&x), h.seed) 113 } 114 115 // Uint16 exposes the memhash16 function from runtime package. 116 func (h Hash) Uint16(x uint16) uintptr { 117 return linkname.Runtime_memhash16(unsafe.Pointer(&x), h.seed) 118 } 119 120 // Int32 exposes the int32Hash function from runtime package. 121 func (h Hash) Int32(x int32) uintptr { 122 return linkname.Runtime_int32Hash(uint32(x), h.seed) 123 } 124 125 // Uint32 exposes the int32Hash function from runtime package. 126 func (h Hash) Uint32(x uint32) uintptr { 127 return linkname.Runtime_int32Hash(x, h.seed) 128 } 129 130 // Int64 exposes the int64Hash function from runtime package. 131 func (h Hash) Int64(x int64) uintptr { 132 return linkname.Runtime_int64Hash(uint64(x), h.seed) 133 } 134 135 // Uint64 exposes the int64Hash function from runtime package. 136 func (h Hash) Uint64(x uint64) uintptr { 137 return linkname.Runtime_int64Hash(x, h.seed) 138 } 139 140 // Int calculates hash of x using either int32Hash or int64Hash 141 // according to the pointer size of the platform. 142 func (h Hash) Int(x int) uintptr { 143 if ptrSize == 32 { 144 return linkname.Runtime_int32Hash(uint32(x), h.seed) 145 } 146 return linkname.Runtime_int64Hash(uint64(x), h.seed) 147 } 148 149 // Uint calculates hash of x using either int32Hash or int64Hash 150 // according the pointer size of the platform. 151 func (h Hash) Uint(x uint) uintptr { 152 if ptrSize == 32 { 153 return linkname.Runtime_int32Hash(uint32(x), h.seed) 154 } 155 return linkname.Runtime_int64Hash(uint64(x), h.seed) 156 } 157 158 // Uintptr calculates hash of x using either int32Hash or int64Hash 159 // according to the pointer size of the platform. 160 func (h Hash) Uintptr(x uintptr) uintptr { 161 if ptrSize == 32 { 162 return linkname.Runtime_int32Hash(uint32(x), h.seed) 163 } 164 return linkname.Runtime_int64Hash(uint64(x), h.seed) 165 } 166 167 // Float32 exposes the f32hash function from runtime package. 168 func (h Hash) Float32(x float32) uintptr { 169 return linkname.Runtime_f32hash(unsafe.Pointer(&x), h.seed) 170 } 171 172 // Float64 exposes the f64hash function from runtime package. 173 func (h Hash) Float64(x float64) uintptr { 174 return linkname.Runtime_f64hash(unsafe.Pointer(&x), h.seed) 175 } 176 177 // Complex64 exposes the c64hash function from runtime package. 178 func (h Hash) Complex64(x complex64) uintptr { 179 return linkname.Runtime_c64hash(unsafe.Pointer(&x), h.seed) 180 } 181 182 // Complex128 exposes the c128hash function from runtime package. 183 func (h Hash) Complex128(x complex128) uintptr { 184 return linkname.Runtime_c128hash(unsafe.Pointer(&x), h.seed) 185 } 186 187 // Interface exposes the efaceHash function from runtime package. 188 func (h Hash) Interface(x interface{}) uintptr { 189 return linkname.Runtime_efaceHash(x, h.seed) 190 } 191 192 // ptrSize is the size in bits of an int or uint value. 193 const ptrSize = 32 << (^uint(0) >> 63) 194 195 func makeseed() uint64 { 196 var s1, s2 uint64 197 for { 198 s1 = uint64(linkname.Runtime_fastrand()) 199 s2 = uint64(linkname.Runtime_fastrand()) 200 // We use seed 0 to indicate an uninitialized seed/hash, 201 // so keep trying until we get a non-zero seed. 202 if s1|s2 != 0 { 203 break 204 } 205 } 206 return s1<<32 + s2 207 }