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  }