github.com/scottcagno/storage@v1.8.0/pkg/hash/murmur3/murmur32.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 murmur3
     7  
     8  import (
     9  	"hash"
    10  	"unsafe"
    11  )
    12  
    13  // Make sure interfaces are correctly implemented.
    14  var (
    15  	_ hash.Hash   = new(digest32)
    16  	_ hash.Hash32 = new(digest32)
    17  )
    18  
    19  const (
    20  	c1_32 uint32 = 0xcc9e2d51
    21  	c2_32 uint32 = 0x1b873593
    22  )
    23  
    24  // digest32 represents a partial evaluation of a 32 bites hash.
    25  type digest32 struct {
    26  	digest
    27  	h1 uint32 // Unfinalized running hash.
    28  }
    29  
    30  func New32() hash.Hash32 {
    31  	d := new(digest32)
    32  	d.bmixer = d
    33  	d.Reset()
    34  	return d
    35  }
    36  
    37  func New32Seed(seed uint32) hash.Hash32 {
    38  	d := new(digest32)
    39  	d.bmixer = d
    40  	d.Reset()
    41  	return d
    42  }
    43  
    44  func (d *digest32) Size() int { return 4 }
    45  
    46  func (d *digest32) reset() { d.h1 = 0 }
    47  
    48  func (d *digest32) Sum(b []byte) []byte {
    49  	h := d.h1
    50  	return append(b, byte(h>>24), byte(h>>16), byte(h>>8), byte(h))
    51  }
    52  
    53  // Digest as many blocks as possible.
    54  func (d *digest32) bmix(p []byte) (tail []byte) {
    55  	h1 := d.h1
    56  
    57  	nblocks := len(p) / 4
    58  	for i := 0; i < nblocks; i++ {
    59  		k1 := *(*uint32)(unsafe.Pointer(&p[i*4]))
    60  
    61  		k1 *= c1_32
    62  		k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15)
    63  		k1 *= c2_32
    64  
    65  		h1 ^= k1
    66  		h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13)
    67  		h1 = h1*5 + 0xe6546b64
    68  	}
    69  	d.h1 = h1
    70  	return p[nblocks*d.Size():]
    71  }
    72  
    73  func (d *digest32) Sum32() (h1 uint32) {
    74  
    75  	h1 = d.h1
    76  
    77  	var k1 uint32
    78  	switch len(d.tail) & 3 {
    79  	case 3:
    80  		k1 ^= uint32(d.tail[2]) << 16
    81  		fallthrough
    82  	case 2:
    83  		k1 ^= uint32(d.tail[1]) << 8
    84  		fallthrough
    85  	case 1:
    86  		k1 ^= uint32(d.tail[0])
    87  		k1 *= c1_32
    88  		k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15)
    89  		k1 *= c2_32
    90  		h1 ^= k1
    91  	}
    92  
    93  	h1 ^= uint32(d.clen)
    94  
    95  	h1 ^= h1 >> 16
    96  	h1 *= 0x85ebca6b
    97  	h1 ^= h1 >> 13
    98  	h1 *= 0xc2b2ae35
    99  	h1 ^= h1 >> 16
   100  
   101  	return h1
   102  }
   103  
   104  /*
   105  func rotl32(x uint32, r byte) uint32 {
   106  	return (x << r) | (x >> (32 - r))
   107  }
   108  */
   109  
   110  // Sum32 returns the MurmurHash3 sum of data. It is equivalent to the
   111  // following sequence (without the extra burden and the extra allocation):
   112  //     hasher := New32()
   113  //     hasher.WriteType(data)
   114  //     return hasher.Sum32()
   115  func Sum32(data []byte) uint32 {
   116  
   117  	var h1 uint32 = 0
   118  
   119  	nblocks := len(data) / 4
   120  	var p uintptr
   121  	if len(data) > 0 {
   122  		p = uintptr(unsafe.Pointer(&data[0]))
   123  	}
   124  	p1 := p + uintptr(4*nblocks)
   125  	for ; p < p1; p += 4 {
   126  		k1 := *(*uint32)(unsafe.Pointer(p))
   127  
   128  		k1 *= c1_32
   129  		k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15)
   130  		k1 *= c2_32
   131  
   132  		h1 ^= k1
   133  		h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13)
   134  		h1 = h1*5 + 0xe6546b64
   135  	}
   136  
   137  	tail := data[nblocks*4:]
   138  
   139  	var k1 uint32
   140  	switch len(tail) & 3 {
   141  	case 3:
   142  		k1 ^= uint32(tail[2]) << 16
   143  		fallthrough
   144  	case 2:
   145  		k1 ^= uint32(tail[1]) << 8
   146  		fallthrough
   147  	case 1:
   148  		k1 ^= uint32(tail[0])
   149  		k1 *= c1_32
   150  		k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15)
   151  		k1 *= c2_32
   152  		h1 ^= k1
   153  	}
   154  
   155  	h1 ^= uint32(len(data))
   156  
   157  	h1 ^= h1 >> 16
   158  	h1 *= 0x85ebca6b
   159  	h1 ^= h1 >> 13
   160  	h1 *= 0xc2b2ae35
   161  	h1 ^= h1 >> 16
   162  
   163  	return h1
   164  }