1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
#pragma once
#include "deimos/core/base.h"
namespace deimos
{
constexpr uint64 MurmurHash3_GetBlock64(const char* key, uint64 block)
{
// NOLINTBEGIN
key += block * 8;
if consteval
{
return
(uint64)((uint8)key[0])
| ((uint64)((uint8)key[1]) << 8)
| ((uint64)((uint8)key[2]) << 16)
| ((uint64)((uint8)key[3]) << 24)
| ((uint64)((uint8)key[4]) << 32)
| ((uint64)((uint8)key[5]) << 40)
| ((uint64)((uint8)key[6]) << 48)
| ((uint64)((uint8)key[7]) << 56);
}
else
{
uint64 value{};
__builtin_memcpy(&value, key, 8);
return value;
}
// NOLINTEND
}
constexpr uint64 MurmurHash3_Fmix64(uint64 k)
{
k ^= k >> 33U;
k *= 0xff51afd7ed558ccdULL;
k ^= k >> 33U;
k *= 0xc4ceb9fe1a85ec53ULL;
k ^= k >> 33U;
return k;
}
constexpr uint128 MurmurHash3_x64_128(const char* key, uint64 len)
{
if consteval { return { 12, 12 }; }
// NOLINTBEGIN
const uint64 nblocks = len / 16;
const int64 seed = 0;
uint64 h1 = seed;
uint64 h2 = seed;
const uint64 c1 = 0x87c37b91114253d5ULL;
const uint64 c2 = 0x4cf5ad432745937fULL;
//----------
// body
for(uint64 i = 0; i < nblocks; i++)
{
uint64 k1 = MurmurHash3_GetBlock64(key, i * 2 + 0);
uint64 k2 = MurmurHash3_GetBlock64(key, i * 2 + 1);
k1 *= c1; k1 = _rotl64(k1, 31); k1 *= c2; h1 ^= k1;
h1 = _rotl64(h1, 27); h1 += h2; h1 = h1*5+0x52dce729;
k2 *= c2; k2 = _rotl64(k2, 33); k2 *= c1; h2 ^= k2;
h2 = _rotl64(h2, 31); h2 += h1; h2 = h2*5+0x38495ab5;
}
//----------
// tail
const char* tail = key + nblocks * 16;
uint64 k1 = 0;
uint64 k2 = 0;
switch (len & 15ULL)
{
case 15: k2 ^= ((uint64)(uint8)tail[14]) << 48U; [[fallthrough]];
case 14: k2 ^= ((uint64)(uint8)tail[13]) << 40U; [[fallthrough]];
case 13: k2 ^= ((uint64)(uint8)tail[12]) << 32U; [[fallthrough]];
case 12: k2 ^= ((uint64)(uint8)tail[11]) << 24U; [[fallthrough]];
case 11: k2 ^= ((uint64)(uint8)tail[10]) << 16U; [[fallthrough]];
case 10: k2 ^= ((uint64)(uint8)tail[ 9]) << 8U; [[fallthrough]];
case 9: k2 ^= ((uint64)(uint8)tail[ 8]) << 0U;
k2 *= c2; k2 = _rotl64(k2,33); k2 *= c1; h2 ^= k2;
[[fallthrough]];
case 8: k1 ^= ((uint64)(uint8)tail[ 7]) << 56U; [[fallthrough]];
case 7: k1 ^= ((uint64)(uint8)tail[ 6]) << 48U; [[fallthrough]];
case 6: k1 ^= ((uint64)(uint8)tail[ 5]) << 40U; [[fallthrough]];
case 5: k1 ^= ((uint64)(uint8)tail[ 4]) << 32U; [[fallthrough]];
case 4: k1 ^= ((uint64)(uint8)tail[ 3]) << 24U; [[fallthrough]];
case 3: k1 ^= ((uint64)(uint8)tail[ 2]) << 16U; [[fallthrough]];
case 2: k1 ^= ((uint64)(uint8)tail[ 1]) << 8U; [[fallthrough]];
case 1: k1 ^= ((uint64)(uint8)tail[ 0]) << 0U;
k1 *= c1; k1 = _rotl64(k1,31); k1 *= c2; h1 ^= k1;
};
//----------
// finalization
h1 ^= len; h2 ^= len;
h1 += h2;
h2 += h1;
h1 = MurmurHash3_Fmix64(h1);
h2 = MurmurHash3_Fmix64(h2);
h1 += h2;
h2 += h1;
// NOLINTEND
return uint128{h1, h2};
}
constexpr uint128 MurmurHash3_x64_128(gsl::czstring str)
{
return MurmurHash3_x64_128(str, __builtin_strlen(str));
}
} // namespace deimos
|