| 22 | internal static class MurmurHash3 |
| 23 | { |
| 24 | public static (ulong H1, ulong H2) X64_128(ReadOnlySpan<byte> bytes, ulong seed = 47) |
| 25 | { |
| 26 | const ulong c1 = 0x87c37b91114253d5; |
| 27 | const ulong c2 = 0x4cf5ad432745937f; |
| 28 | |
| 29 | ulong h1 = seed; |
| 30 | ulong h2 = seed; |
| 31 | |
| 32 | int length = bytes.Length; |
| 33 | int nblocks = length / 16; |
| 34 | for (int i = 0; i < nblocks; i++) |
| 35 | { |
| 36 | int offset = i * 16; |
| 37 | ulong k1 = BinaryPrimitives.ReadUInt64LittleEndian(bytes.Slice(offset, 8)); |
| 38 | ulong k2 = BinaryPrimitives.ReadUInt64LittleEndian(bytes.Slice(offset + 8, 8)); |
| 39 | |
| 40 | k1 *= c1; |
| 41 | k1 = RotateLeft(k1, 31); |
| 42 | k1 *= c2; |
| 43 | h1 ^= k1; |
| 44 | |
| 45 | h1 = RotateLeft(h1, 27); |
| 46 | h1 += h2; |
| 47 | h1 = h1 * 5 + 0x52dce729; |
| 48 | |
| 49 | k2 *= c2; |
| 50 | k2 = RotateLeft(k2, 33); |
| 51 | k2 *= c1; |
| 52 | h2 ^= k2; |
| 53 | |
| 54 | h2 = RotateLeft(h2, 31); |
| 55 | h2 += h1; |
| 56 | h2 = h2 * 5 + 0x38495ab5; |
| 57 | } |
| 58 | |
| 59 | ulong tk1 = 0; |
| 60 | ulong tk2 = 0; |
| 61 | int tailStart = nblocks * 16; |
| 62 | ReadOnlySpan<byte> tail = bytes.Slice(tailStart); |
| 63 | switch (length & 15) |
| 64 | { |
| 65 | case 15: |
| 66 | tk2 ^= (ulong)tail[14] << 48; |
| 67 | goto case 14; |
| 68 | case 14: |
| 69 | tk2 ^= (ulong)tail[13] << 40; |
| 70 | goto case 13; |
| 71 | case 13: |
| 72 | tk2 ^= (ulong)tail[12] << 32; |
| 73 | goto case 12; |
| 74 | case 12: |
| 75 | tk2 ^= (ulong)tail[11] << 24; |
| 76 | goto case 11; |
| 77 | case 11: |
| 78 | tk2 ^= (ulong)tail[10] << 16; |
| 79 | goto case 10; |
| 80 | case 10: |
| 81 | tk2 ^= (ulong)tail[9] << 8; |