github.com/moontrade/nogc@v0.1.7/hash/metro.go (about)

     1  package hash
     2  
     3  import "math/bits"
     4  
     5  func Metro32(v uint32) uint32 {
     6  	const (
     7  		k0   uint64 = 0xD6D018F5
     8  		k1   uint64 = 0xA2AA033B
     9  		k2   uint64 = 0x62992FC1
    10  		k3   uint64 = 0x30BC5B29
    11  		seed uint64 = 979532
    12  	)
    13  	hash := (seed + k2) * k0
    14  	hash += uint64(v) * k3
    15  	hash ^= bits.RotateLeft64(hash, -26) * k1
    16  	hash ^= bits.RotateLeft64(hash, -28)
    17  	hash *= k0
    18  	hash ^= bits.RotateLeft64(hash, -29)
    19  	return uint32(hash)
    20  }
    21  
    22  func Metro64(v uint64) uint64 {
    23  	const (
    24  		k0   uint64 = 0xD6D018F5
    25  		k1   uint64 = 0xA2AA033B
    26  		k2   uint64 = 0x62992FC1
    27  		k3   uint64 = 0x30BC5B29
    28  		seed uint64 = 979532
    29  	)
    30  	hash := (seed + k2) * k0
    31  	hash += v * k3
    32  	hash ^= bits.RotateLeft64(hash, -26) * k1
    33  	hash ^= bits.RotateLeft64(hash, -28)
    34  	hash *= k0
    35  	hash ^= bits.RotateLeft64(hash, -29)
    36  	return hash
    37  }
    38  
    39  func Metro(buffer []byte, seed uint64) uint64 {
    40  	const (
    41  		k0 = 0xD6D018F5
    42  		k1 = 0xA2AA033B
    43  		k2 = 0x62992FC1
    44  		k3 = 0x30BC5B29
    45  	)
    46  
    47  	var (
    48  		ptr  = buffer
    49  		hash = (seed + k2) * k0
    50  	)
    51  	if len(ptr) >= 32 {
    52  		v0, v1, v2, v3 := hash, hash, hash, hash
    53  
    54  		for len(ptr) >= 32 {
    55  			v0 += toUint64LE(ptr[:8]) * k0
    56  			v0 = bits.RotateLeft64(v0, -29) + v2
    57  			v1 += toUint64LE(ptr[8:16]) * k1
    58  			v1 = bits.RotateLeft64(v1, -29) + v3
    59  			v2 += toUint64LE(ptr[16:24]) * k2
    60  			v2 = bits.RotateLeft64(v2, -29) + v0
    61  			v3 += toUint64LE(ptr[24:32]) * k3
    62  			v3 = bits.RotateLeft64(v3, -29) + v1
    63  			ptr = ptr[32:]
    64  		}
    65  
    66  		v2 ^= bits.RotateLeft64(((v0+v3)*k0)+v1, -37) * k1
    67  		v3 ^= bits.RotateLeft64(((v1+v2)*k1)+v0, -37) * k0
    68  		v0 ^= bits.RotateLeft64(((v0+v2)*k0)+v3, -37) * k1
    69  		v1 ^= bits.RotateLeft64(((v1+v3)*k1)+v2, -37) * k0
    70  		hash += v0 ^ v1
    71  	}
    72  	if len(ptr) >= 16 {
    73  		v0 := hash + (toUint64LE(ptr[:8]) * k2)
    74  		v0 = bits.RotateLeft64(v0, -29) * k3
    75  		v1 := hash + (toUint64LE(ptr[8:16]) * k2)
    76  		v1 = bits.RotateLeft64(v1, -29) * k3
    77  		v0 ^= bits.RotateLeft64(v0*k0, -21) + v1
    78  		v1 ^= bits.RotateLeft64(v1*k3, -21) + v0
    79  		hash += v1
    80  		ptr = ptr[16:]
    81  	}
    82  	if len(ptr) >= 8 {
    83  		hash += toUint64LE(ptr[:8]) * k3
    84  		ptr = ptr[8:]
    85  		hash ^= bits.RotateLeft64(hash, -55) * k1
    86  	}
    87  	if len(ptr) >= 4 {
    88  		hash += uint64(toUint32LE(ptr[:4])) * k3
    89  		hash ^= bits.RotateLeft64(hash, -26) * k1
    90  		ptr = ptr[4:]
    91  	}
    92  	if len(ptr) >= 2 {
    93  		hash += uint64(toUint16LE(ptr[:2])) * k3
    94  		ptr = ptr[2:]
    95  		hash ^= bits.RotateLeft64(hash, -48) * k1
    96  	}
    97  	if len(ptr) >= 1 {
    98  		hash += uint64(ptr[0]) * k3
    99  		hash ^= bits.RotateLeft64(hash, -37) * k1
   100  	}
   101  
   102  	hash ^= bits.RotateLeft64(hash, -28)
   103  	hash *= k0
   104  	hash ^= bits.RotateLeft64(hash, -29)
   105  
   106  	return hash
   107  }