github.com/fluhus/gostuff@v0.4.1-0.20240331134726-be71864f2b5d/rhash/rabin32.go (about) 1 package rhash 2 3 import ( 4 "fmt" 5 "hash" 6 ) 7 8 var _ hash.Hash32 = &RabinFingerprint32{} 9 10 // RabinFingerprint32 implements a Rabin fingerprint rolling-hash. 11 // Implements [hash.Hash32]. 12 type RabinFingerprint32 struct { 13 h, pow uint32 14 i int 15 hist []byte 16 } 17 18 // NewRabinFingerprint32 returns a new rolling hash with a window size of n. 19 func NewRabinFingerprint32(n int) *RabinFingerprint32 { 20 if n < 1 { 21 panic(fmt.Sprintf("bad n: %d", n)) 22 } 23 return &RabinFingerprint32{0, 1, 0, make([]byte, n)} 24 } 25 26 // Write updates the hash with the given bytes. Always returns len(data), nil. 27 func (h *RabinFingerprint32) Write(data []byte) (int, error) { 28 for _, b := range data { 29 h.WriteByte(b) 30 } 31 return len(data), nil 32 } 33 34 // WriteByte updates the hash with the given byte. Always returns nil. 35 func (h *RabinFingerprint32) WriteByte(b byte) error { 36 h.h = h.h*rabinPrime + uint32(b) 37 i := h.i % len(h.hist) 38 h.h -= h.pow * uint32(h.hist[i]) 39 h.hist[i] = b 40 if h.i < len(h.hist) { 41 h.pow *= rabinPrime 42 } 43 h.i++ 44 return nil 45 } 46 47 // Sum appends the current hash to b and returns the resulting slice. 48 func (h *RabinFingerprint32) Sum(b []byte) []byte { 49 s := h.Sum32() 50 n := h.Size() 51 for i := 0; i < n; i++ { 52 b = append(b, byte(s)) 53 s >>= 8 54 } 55 return b 56 } 57 58 // Sum32 returns the current hash. 59 func (h *RabinFingerprint32) Sum32() uint32 { 60 return h.h 61 } 62 63 // Size returns the number of bytes Sum will return, which is four. 64 func (h *RabinFingerprint32) Size() int { 65 return 4 66 } 67 68 // BlockSize returns the hash's block size, which is one. 69 func (h *RabinFingerprint32) BlockSize() int { 70 return 1 71 } 72 73 // Reset resets the hash to its initial state. 74 func (h *RabinFingerprint32) Reset() { 75 h.h = 0 76 h.i = 0 77 h.pow = 1 78 for i := range h.hist { 79 h.hist[i] = 0 80 } 81 } 82 83 // RabinFingerprintSum32 returns the Rabin fingerprint of data. 84 func RabinFingerprintSum32(data []byte) uint32 { 85 if len(data) == 0 { 86 return 0 87 } 88 h := NewRabinFingerprint32(len(data)) 89 h.Write(data) 90 return h.Sum32() 91 }