-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
Copy pathxor_fast_hash.hpp
65 lines (51 loc) · 1.68 KB
/
xor_fast_hash.hpp
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
#ifndef XOR_FAST_HASH_HPP
#define XOR_FAST_HASH_HPP
#include <boost/assert.hpp>
#include <algorithm>
#include <array>
#include <iterator>
#include <numeric>
#include <random>
#include <cstdint>
namespace osrm::util
{
/*
This is an implementation of Tabulation hashing, which has suprising properties like
universality.
The space requirement is 2*2^16 = 256 kb of memory, which fits into L2 cache.
Evaluation boils down to 10 or less assembly instruction on any recent X86 CPU:
1: movq table2(%rip), %rdx
2: movl %edi, %eax
3: movzwl %di, %edi
4: shrl $16, %eax
5: movzwl %ax, %eax
6: movzbl (%rdx,%rax), %eax
7: movq table1(%rip), %rdx
8: xorb (%rdx,%rdi), %al
9: movzbl %al, %eax
10: ret
*/
template <std::size_t MaxNumElements = (1u << 16u)> class XORFastHash
{
static_assert(MaxNumElements <= (1u << 16u), "only 65536 elements indexable with uint16_t");
std::array<std::uint16_t, MaxNumElements> table1;
std::array<std::uint16_t, MaxNumElements> table2;
public:
XORFastHash()
{
std::mt19937 generator(0xdeadbeef);
std::uniform_int_distribution<> distrib(0, UINT16_MAX);
std::fill(begin(table1), end(table1), distrib(generator));
std::fill(begin(table2), end(table2), distrib(generator));
}
inline std::uint16_t operator()(const std::uint32_t originalValue) const
{
std::uint16_t lsb = originalValue & 0xffffu;
std::uint16_t msb = originalValue >> 16u;
BOOST_ASSERT(lsb < table1.size());
BOOST_ASSERT(msb < table2.size());
return table1[lsb] ^ table2[msb];
}
};
} // namespace osrm::util
#endif // XOR_FAST_HASH_HPP