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  }