github.com/scottcagno/storage@v1.8.0/pkg/hash/xxhash/xxhash32.go (about) 1 /* 2 * // Copyright (c) 2021. Scott Cagno. All rights reserved. 3 * // The license can be found in the root of this project; see LICENSE. 4 */ 5 6 package xxhash 7 8 import "hash" 9 10 const ( 11 prime32_1 = 2654435761 12 prime32_2 = 2246822519 13 prime32_3 = 3266489917 14 prime32_4 = 668265263 15 prime32_5 = 374761393 16 ) 17 18 type xxHash32 struct { 19 seed uint32 20 v1 uint32 21 v2 uint32 22 v3 uint32 23 v4 uint32 24 totalLen uint64 25 buf [16]byte 26 bufused int 27 } 28 29 // New returns a new Hash32 instance. 30 func NewHash32(seed uint32) hash.Hash32 { 31 xxh := &xxHash32{seed: seed} 32 xxh.Reset() 33 return xxh 34 } 35 36 func Sum32(b []byte) uint32 { 37 h := NewHash32(0xCAFE) 38 h.Write(b) 39 return h.Sum32() 40 } 41 42 // Sum appends the current hash to b and returns the resulting slice. 43 // It does not change the underlying hash state. 44 func (xxh xxHash32) Sum(b []byte) []byte { 45 h32 := xxh.Sum32() 46 return append(b, byte(h32), byte(h32>>8), byte(h32>>16), byte(h32>>24)) 47 } 48 49 // Reset resets the Hash to its initial state. 50 func (xxh *xxHash32) Reset() { 51 xxh.v1 = xxh.seed + prime32_1 + prime32_2 52 xxh.v2 = xxh.seed + prime32_2 53 xxh.v3 = xxh.seed 54 xxh.v4 = xxh.seed - prime32_1 55 xxh.totalLen = 0 56 xxh.bufused = 0 57 } 58 59 // Size returns the number of bytes returned by Sum(). 60 func (xxh *xxHash32) Size() int { 61 return 4 62 } 63 64 // BlockSize gives the minimum number of bytes accepted by Write(). 65 func (xxh *xxHash32) BlockSize() int { 66 return 1 67 } 68 69 // Write adds input bytes to the Hash. 70 // It never returns an error. 71 func (xxh *xxHash32) Write(input []byte) (int, error) { 72 n := len(input) 73 m := xxh.bufused 74 75 xxh.totalLen += uint64(n) 76 77 r := len(xxh.buf) - m 78 if n < r { 79 copy(xxh.buf[m:], input) 80 xxh.bufused += len(input) 81 return n, nil 82 } 83 84 p := 0 85 if m > 0 { 86 // some data left from previous update 87 copy(xxh.buf[xxh.bufused:], input[:r]) 88 xxh.bufused += len(input) - r 89 90 // fast rotl(13) 91 xxh.v1 = u32_rol13(xxh.v1+u32_u32(xxh.buf[:])*prime32_2) * prime32_1 92 xxh.v2 = u32_rol13(xxh.v2+u32_u32(xxh.buf[4:])*prime32_2) * prime32_1 93 xxh.v3 = u32_rol13(xxh.v3+u32_u32(xxh.buf[8:])*prime32_2) * prime32_1 94 xxh.v4 = u32_rol13(xxh.v4+u32_u32(xxh.buf[12:])*prime32_2) * prime32_1 95 p = r 96 xxh.bufused = 0 97 } 98 99 // Causes compiler to work directly from registers instead of stack: 100 v1, v2, v3, v4 := xxh.v1, xxh.v2, xxh.v3, xxh.v4 101 for n := n - 16; p <= n; p += 16 { 102 sub := input[p:][:16] //BCE hint for compiler 103 v1 = u32_rol13(v1+u32_u32(sub[:])*prime32_2) * prime32_1 104 v2 = u32_rol13(v2+u32_u32(sub[4:])*prime32_2) * prime32_1 105 v3 = u32_rol13(v3+u32_u32(sub[8:])*prime32_2) * prime32_1 106 v4 = u32_rol13(v4+u32_u32(sub[12:])*prime32_2) * prime32_1 107 } 108 xxh.v1, xxh.v2, xxh.v3, xxh.v4 = v1, v2, v3, v4 109 110 copy(xxh.buf[xxh.bufused:], input[p:]) 111 xxh.bufused += len(input) - p 112 113 return n, nil 114 } 115 116 // Sum32 returns the 32 bits Hash value. 117 func (xxh *xxHash32) Sum32() uint32 { 118 h32 := uint32(xxh.totalLen) 119 if xxh.totalLen >= 16 { 120 h32 += u32_rol1(xxh.v1) + u32_rol7(xxh.v2) + u32_rol12(xxh.v3) + u32_rol18(xxh.v4) 121 } else { 122 h32 += xxh.seed + prime32_5 123 } 124 125 p := 0 126 n := xxh.bufused 127 for n := n - 4; p <= n; p += 4 { 128 h32 += u32_u32(xxh.buf[p:p+4]) * prime32_3 129 h32 = u32_rol17(h32) * prime32_4 130 } 131 for ; p < n; p++ { 132 h32 += uint32(xxh.buf[p]) * prime32_5 133 h32 = u32_rol11(h32) * prime32_1 134 } 135 136 h32 ^= h32 >> 15 137 h32 *= prime32_2 138 h32 ^= h32 >> 13 139 h32 *= prime32_3 140 h32 ^= h32 >> 16 141 142 return h32 143 } 144 145 // Checksum returns the 32bits Hash value. 146 func Checksum32(input []byte, seed uint32) uint32 { 147 n := len(input) 148 h32 := uint32(n) 149 150 if n < 16 { 151 h32 += seed + prime32_5 152 } else { 153 v1 := seed + prime32_1 + prime32_2 154 v2 := seed + prime32_2 155 v3 := seed 156 v4 := seed - prime32_1 157 p := 0 158 for n := n - 16; p <= n; p += 16 { 159 sub := input[p:][:16] //BCE hint for compiler 160 v1 = u32_rol13(v1+u32_u32(sub[:])*prime32_2) * prime32_1 161 v2 = u32_rol13(v2+u32_u32(sub[4:])*prime32_2) * prime32_1 162 v3 = u32_rol13(v3+u32_u32(sub[8:])*prime32_2) * prime32_1 163 v4 = u32_rol13(v4+u32_u32(sub[12:])*prime32_2) * prime32_1 164 } 165 input = input[p:] 166 n -= p 167 h32 += u32_rol1(v1) + u32_rol7(v2) + u32_rol12(v3) + u32_rol18(v4) 168 } 169 170 p := 0 171 for n := n - 4; p <= n; p += 4 { 172 h32 += u32_u32(input[p:p+4]) * prime32_3 173 h32 = u32_rol17(h32) * prime32_4 174 } 175 for p < n { 176 h32 += uint32(input[p]) * prime32_5 177 h32 = u32_rol11(h32) * prime32_1 178 p++ 179 } 180 181 h32 ^= h32 >> 15 182 h32 *= prime32_2 183 h32 ^= h32 >> 13 184 h32 *= prime32_3 185 h32 ^= h32 >> 16 186 187 return h32 188 } 189 190 func u32_u32(buf []byte) uint32 { 191 // go compiler recognizes this pattern and optimizes it on little endian platforms 192 return uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24 193 } 194 195 func u32_rol1(u uint32) uint32 { 196 return u<<1 | u>>31 197 } 198 199 func u32_rol7(u uint32) uint32 { 200 return u<<7 | u>>25 201 } 202 203 func u32_rol11(u uint32) uint32 { 204 return u<<11 | u>>21 205 } 206 207 func u32_rol12(u uint32) uint32 { 208 return u<<12 | u>>20 209 } 210 211 func u32_rol13(u uint32) uint32 { 212 return u<<13 | u>>19 213 } 214 215 func u32_rol17(u uint32) uint32 { 216 return u<<17 | u>>15 217 } 218 219 func u32_rol18(u uint32) uint32 { 220 return u<<18 | u>>14 221 }