| e8555c89 Andy McCall |
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 |
#ifndef XXHASH_HH |
| 43 |
#define XXHASH_HH |
| 44 |
|
| 45 |
#include <bit> |
| 46 |
#include <cassert> |
| 47 |
#include <cstdint> |
| 48 |
#include <cstring> |
| 49 |
#include <string_view> |
| 50 |
|
| 51 |
inline constexpr uint32_t PRIME32_1 = 2654435761; |
| 52 |
inline constexpr uint32_t PRIME32_2 = 2246822519; |
| 53 |
inline constexpr uint32_t PRIME32_3 = 3266489917; |
| 54 |
inline constexpr uint32_t PRIME32_4 = 668265263; |
| 55 |
inline constexpr uint32_t PRIME32_5 = 374761393; |
| 56 |
|
| 57 |
|
| 58 |
template<bool ALIGNED> |
| 59 |
[[nodiscard]] inline uint32_t read32(const uint8_t* ptr) |
| 60 |
{ |
| 61 |
if constexpr (ALIGNED) { |
| 62 |
#ifdef DEBUG |
| 63 |
assert((std::bit_cast<intptr_t>(ptr) & 3) == 0); |
| 64 |
#endif |
| 65 |
return *std::bit_cast<const uint32_t*>(ptr); |
| 66 |
} else { |
| 67 |
uint32_t result; |
| 68 |
memcpy(&result, ptr, sizeof(result)); |
| 69 |
return result; |
| 70 |
} |
| 71 |
} |
| 72 |
|
| 73 |
|
| 74 |
template<bool ALIGNED, uint8_t MASK8 = 0xFF, uint32_t SEED = 0> |
| 75 |
[[nodiscard]] inline uint32_t xxhash_impl(const uint8_t* p, size_t size) |
| 76 |
{ |
| 77 |
constexpr uint32_t MASK32 = MASK8 * 0x01010101U; |
| 78 |
|
| 79 |
const uint8_t* const bEnd = p + size; |
| 80 |
uint32_t h32; |
| 81 |
|
| 82 |
if (size >= 16) [[unlikely]] { |
| 83 |
const uint8_t* const limit = bEnd - 16; |
| 84 |
|
| 85 |
|
| 86 |
auto v1 = uint32_t(SEED + PRIME32_1 + uint64_t(PRIME32_2)); |
| 87 |
auto v2 = SEED + PRIME32_2; |
| 88 |
auto v3 = SEED + 0; |
| 89 |
auto v4 = SEED - PRIME32_1; |
| 90 |
|
| 91 |
do { |
| 92 |
uint32_t r1 = (read32<ALIGNED>(p + 0) & MASK32) * PRIME32_2; |
| 93 |
uint32_t r2 = (read32<ALIGNED>(p + 4) & MASK32) * PRIME32_2; |
| 94 |
uint32_t r3 = (read32<ALIGNED>(p + 8) & MASK32) * PRIME32_2; |
| 95 |
uint32_t r4 = (read32<ALIGNED>(p + 12) & MASK32) * PRIME32_2; |
| 96 |
p += 16; |
| 97 |
v1 = std::rotl(v1 + r1, 13) * PRIME32_1; |
| 98 |
v2 = std::rotl(v2 + r2, 13) * PRIME32_1; |
| 99 |
v3 = std::rotl(v3 + r3, 13) * PRIME32_1; |
| 100 |
v4 = std::rotl(v4 + r4, 13) * PRIME32_1; |
| 101 |
} while (p <= limit); |
| 102 |
|
| 103 |
h32 = std::rotl(v1, 1) + std::rotl(v2, 7) + std::rotl(v3, 12) + std::rotl(v4, 18); |
| 104 |
} else { |
| 105 |
h32 = SEED + PRIME32_5; |
| 106 |
} |
| 107 |
|
| 108 |
h32 += uint32_t(size); |
| 109 |
|
| 110 |
while ((p + 4) <= bEnd) { |
| 111 |
uint32_t r = (read32<ALIGNED>(p) & MASK32) * PRIME32_3; |
| 112 |
h32 = std::rotl(h32 + r, 17) * PRIME32_4; |
| 113 |
p += 4; |
| 114 |
} |
| 115 |
|
| 116 |
while (p < bEnd) { |
| 117 |
uint32_t r = (*p & MASK8) * PRIME32_5; |
| 118 |
h32 = std::rotl(h32 + r, 11) * PRIME32_1; |
| 119 |
p += 1; |
| 120 |
} |
| 121 |
|
| 122 |
h32 = (h32 ^ (h32 >> 15)) * PRIME32_2; |
| 123 |
h32 = (h32 ^ (h32 >> 13)) * PRIME32_3; |
| 124 |
return h32 ^ (h32 >> 16); |
| 125 |
} |
| 126 |
|
| 127 |
template<uint8_t MASK8> [[nodiscard]] inline uint32_t xxhash_impl(std::string_view key) |
| 128 |
{ |
| 129 |
const auto* data = std::bit_cast<const uint8_t*>(key.data()); |
| 130 |
auto size = key.size(); |
| 131 |
if (std::bit_cast<intptr_t>(data) & 3) { |
| 132 |
return xxhash_impl<false, MASK8>(data, size); |
| 133 |
} else { |
| 134 |
|
| 135 |
return xxhash_impl<true, MASK8>(data, size); |
| 136 |
} |
| 137 |
} |
| 138 |
|
| 139 |
[[nodiscard]] inline uint32_t xxhash(std::string_view key) |
| 140 |
{ |
| 141 |
return xxhash_impl<0xFF>(key); |
| 142 |
} |
| 143 |
[[nodiscard]] inline uint32_t xxhash_case(std::string_view key) |
| 144 |
{ |
| 145 |
return xxhash_impl<static_cast<uint8_t>(~('a' - 'A'))>(key); |
| 146 |
} |
| 147 |
|
| 148 |
struct XXHasher { |
| 149 |
[[nodiscard]] uint32_t operator()(std::string_view key) const { |
| 150 |
return xxhash(key); |
| 151 |
} |
| 152 |
}; |
| 153 |
|
| 154 |
struct XXHasher_IgnoreCase { |
| 155 |
[[nodiscard]] uint32_t operator()(std::string_view key) const { |
| 156 |
return xxhash_case(key); |
| 157 |
} |
| 158 |
}; |
| 159 |
|
| 160 |
#endif |