go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/sdk/murmur3/murmur.go (about)

     1  /*
     2  
     3  Copyright (c) 2023 - Present. Will Charczuk. All rights reserved.
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository.
     5  
     6  */
     7  
     8  // Copyright 2013, Sébastien Paolacci. All rights reserved.
     9  // Use of this source code is governed by a BSD-style
    10  // license that can be found in the LICENSE file.
    11  
    12  /*
    13  Package murmur3 implements Austin Appleby's non-cryptographic MurmurHash3.
    14  
    15  	Reference implementation:
    16  	   http://code.google.com/p/smhasher/wiki/MurmurHash3
    17  
    18  	History, characteristics and (legacy) perfs:
    19  	   https://sites.google.com/site/murmurhash/
    20  	   https://sites.google.com/site/murmurhash/statistics
    21  */
    22  package murmur3
    23  
    24  type bmixer interface {
    25  	bmix(p []byte) (tail []byte)
    26  	Size() (n int)
    27  	reset()
    28  }
    29  
    30  type digest struct {
    31  	clen int      // Digested input cumulative length.
    32  	tail []byte   // 0 to Size()-1 bytes view of `buf'.
    33  	buf  [16]byte // Expected (but not required) to be Size() large.
    34  	seed uint32   // Seed for initializing the hash.
    35  	bmixer
    36  }
    37  
    38  func (d *digest) BlockSize() int { return 1 }
    39  
    40  func (d *digest) Write(p []byte) (n int, err error) {
    41  	n = len(p)
    42  	d.clen += n
    43  
    44  	if len(d.tail) > 0 {
    45  		// Stick back pending bytes.
    46  		nfree := d.Size() - len(d.tail) // nfree ∈ [1, d.Size()-1].
    47  		if nfree < len(p) {
    48  			// One full block can be formed.
    49  			block := append(d.tail, p[:nfree]...)
    50  			p = p[nfree:]
    51  			_ = d.bmix(block) // No tail.
    52  		} else {
    53  			// Tail's buf is large enough to prevent reallocs.
    54  			p = append(d.tail, p...)
    55  		}
    56  	}
    57  
    58  	d.tail = d.bmix(p)
    59  
    60  	// Keep own copy of the 0 to Size()-1 pending bytes.
    61  	nn := copy(d.buf[:], d.tail)
    62  	d.tail = d.buf[:nn]
    63  
    64  	return n, nil
    65  }
    66  
    67  func (d *digest) Reset() {
    68  	d.clen = 0
    69  	d.tail = nil
    70  	d.bmixer.reset()
    71  }