github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/memhash_leveldb.go (about) 1 //go:build runtime_memhash_leveldb || (wasip1 && !runtime_memhash_fnv && !runtime_memhash_tsip) 2 3 // This is the default for WASI, but can also be used on other targets with the 4 // right build tag. 5 6 // This is the hash function from Google's leveldb key-value storage system. It 7 // processes 4 bytes at a time making it faster than the FNV hash for buffer 8 // lengths > 16 bytes. 9 10 // https://github.com/google/leveldb 11 // https://en.wikipedia.org/wiki/LevelDB 12 13 package runtime 14 15 import ( 16 "unsafe" 17 ) 18 19 func ptrToSlice(ptr unsafe.Pointer, n uintptr) []byte { 20 var p []byte 21 22 type _bslice struct { 23 ptr *byte 24 len uintptr 25 cap uintptr 26 } 27 28 pslice := (*_bslice)(unsafe.Pointer(&p)) 29 pslice.ptr = (*byte)(ptr) 30 pslice.cap = n 31 pslice.len = n 32 33 return p 34 } 35 36 // leveldb hash 37 func hash32(ptr unsafe.Pointer, n, seed uintptr) uint32 { 38 39 const ( 40 lseed = 0xbc9f1d34 41 m = 0xc6a4a793 42 ) 43 44 b := ptrToSlice(ptr, n) 45 46 h := uint32(lseed^seed) ^ uint32(uint(len(b))*uint(m)) 47 48 for ; len(b) >= 4; b = b[4:] { 49 h += uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 50 h *= m 51 h ^= h >> 16 52 } 53 switch len(b) { 54 case 3: 55 h += uint32(b[2]) << 16 56 fallthrough 57 case 2: 58 h += uint32(b[1]) << 8 59 fallthrough 60 case 1: 61 h += uint32(b[0]) 62 h *= m 63 h ^= h >> 24 64 } 65 66 return h 67 } 68 69 // hash64finalizer is a 64-bit integer mixing function from 70 // https://web.archive.org/web/20120720045250/http://www.cris.com/~Ttwang/tech/inthash.htm 71 func hash64finalizer(key uint64) uint64 { 72 key = ^key + (key << 21) // key = (key << 21) - key - 1; 73 key = key ^ (key >> 24) 74 key = (key + (key << 3)) + (key << 8) // key * 265 75 key = key ^ (key >> 14) 76 key = (key + (key << 2)) + (key << 4) // key * 21 77 key = key ^ (key >> 28) 78 key = key + (key << 31) 79 return key 80 } 81 82 // hash64 turns hash32 into a 64-bit hash, by use hash64finalizer to 83 // mix the result of hash32 function combined with an xorshifted version of 84 // the seed. 85 func hash64(ptr unsafe.Pointer, n, seed uintptr) uint64 { 86 h32 := hash32(ptr, n, seed) 87 return hash64finalizer((uint64(h32^xorshift32(uint32(seed))) << 32) | uint64(h32)) 88 }