Skip to content

Commit 9783d75

Browse files
committed
use murmur2a hash
1 parent 3c80c09 commit 9783d75

File tree

1 file changed

+100
-9
lines changed

1 file changed

+100
-9
lines changed

include/boost/json/detail/digest.hpp

Lines changed: 100 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,122 @@
1010
#ifndef BOOST_JSON_DETAIL_DIGEST_HPP
1111
#define BOOST_JSON_DETAIL_DIGEST_HPP
1212

13+
#include <boost/json/detail/config.hpp>
14+
15+
#include <algorithm>
16+
#include <iterator>
17+
1318
namespace boost {
1419
namespace json {
1520
namespace detail {
1621

1722
// Calculate salted digest of string
23+
#if BOOST_JSON_ARCH == 64
24+
1825
template<class ForwardIterator>
1926
std::size_t
2027
digest(
2128
ForwardIterator b,
2229
ForwardIterator e,
2330
std::size_t salt) noexcept
2431
{
25-
#if BOOST_JSON_ARCH == 64
26-
std::uint64_t const prime = 0x100000001B3ULL;
27-
std::uint64_t hash = 0xcbf29ce484222325ULL;
32+
std::size_t len = std::distance(b, e);
33+
34+
using state_type = std::uint64_t;
35+
state_type const m = 0xc6a4a7935bd1e995ULL;
36+
int const r = 47;
37+
state_type hash = salt ^ (len * m);
38+
39+
constexpr std::size_t N = sizeof(state_type);
40+
e = std::next( b, len & (std::size_t(-1) ^ 7) );
41+
for( ; b != e; std::advance(b, N) )
42+
{
43+
state_type num;
44+
std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
45+
46+
num *= m;
47+
num ^= num >> r;
48+
num *= m;
49+
50+
hash ^= num;
51+
hash *= m;
52+
}
53+
54+
state_type num = 0;
55+
switch( len & 7 )
56+
{
57+
case 7: num |= state_type( *std::next(b, 6) ) << 48; // fall through
58+
case 6: num |= state_type( *std::next(b, 5) ) << 40; // fall through
59+
case 5: num |= state_type( *std::next(b, 4) ) << 32; // fall through
60+
case 4: num |= state_type( *std::next(b, 3) ) << 24; // fall through
61+
case 3: num |= state_type( *std::next(b, 2) ) << 16; // fall through
62+
case 2: num |= state_type( *std::next(b, 1) ) << 8; // fall through
63+
case 1: num |= state_type( *std::next(b, 0) ); // fall through
64+
default: break;
65+
};
66+
67+
hash ^= num;
68+
hash *= m;
69+
70+
hash ^= hash >> r;
71+
hash *= m;
72+
hash ^= hash >> r;
73+
74+
return hash;
75+
}
76+
2877
#else
29-
std::uint32_t const prime = 0x01000193UL;
30-
std::uint32_t hash = 0x811C9DC5UL;
31-
#endif
32-
hash += salt;
33-
for(; b != e; ++b)
34-
hash = (*b ^ hash) * prime;
78+
79+
template<class ForwardIterator>
80+
std::size_t
81+
digest(
82+
ForwardIterator b,
83+
ForwardIterator e,
84+
std::size_t salt) noexcept
85+
{
86+
std::size_t len = std::distance(b, e);
87+
88+
using state_type = std::uint32_t;
89+
state_type const m = 0x5bd1e995;
90+
int const r = 24;
91+
state_type hash = salt ^ len;
92+
93+
constexpr std::size_t N = sizeof(state_type);
94+
e = std::next( b, len & (std::size_t(-1) ^ 3) );
95+
for( ; len >= N ; len -= N, std::advance(b, N) )
96+
{
97+
state_type num;
98+
std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
99+
100+
num *= m;
101+
num ^= num >> r;
102+
num *= m;
103+
104+
hash *= m;
105+
hash ^= num;
106+
}
107+
108+
state_type num = 0;
109+
switch( len & 3 )
110+
{
111+
case 3: num |= state_type( *std::next(b, 2) ) << 16; // fall through
112+
case 2: num |= state_type( *std::next(b, 1) ) << 8; // fall through
113+
case 1: num |= state_type( *std::next(b, 0) ); // fall through
114+
default: break;
115+
};
116+
117+
hash ^= num;
118+
hash *= m;
119+
120+
hash ^= hash >> 13;
121+
hash *= m;
122+
hash ^= hash >> 15;
123+
35124
return hash;
36125
}
37126

127+
#endif
128+
38129
} // detail
39130
} // namespace json
40131
} // namespace boost

0 commit comments

Comments
 (0)