Skip to content

Commit e4023c0

Browse files
committed
use murmur2a hash
1 parent 3c80c09 commit e4023c0

File tree

2 files changed

+106
-11
lines changed

2 files changed

+106
-11
lines changed

include/boost/json/detail/digest.hpp

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,94 @@
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
1823
template<class ForwardIterator>
1924
std::size_t
20-
digest(
21-
ForwardIterator b,
22-
ForwardIterator e,
23-
std::size_t salt) noexcept
25+
digest(ForwardIterator b, ForwardIterator e, std::size_t salt) noexcept
2426
{
27+
std::size_t const len = std::distance(b, e);
28+
2529
#if BOOST_JSON_ARCH == 64
26-
std::uint64_t const prime = 0x100000001B3ULL;
27-
std::uint64_t hash = 0xcbf29ce484222325ULL;
30+
31+
using state_type = std::uint64_t;
32+
state_type const m = 0xc6a4a7935bd1e995ULL;
33+
int const r = 47;
34+
state_type hash = salt ^ (len * m);
35+
36+
constexpr std::size_t N = sizeof(state_type);
37+
e = std::next( b, len & ~std::size_t(N-1) );
38+
for( ; b != e; std::advance(b, N) )
39+
{
40+
state_type num;
41+
std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
42+
43+
num *= m;
44+
num ^= num >> r;
45+
num *= m;
46+
hash ^= num;
47+
hash *= m;
48+
}
49+
50+
switch( len & (N - 1) )
51+
{
52+
case 7: hash ^= state_type( *std::next(b, 6) ) << 48; // fall through
53+
case 6: hash ^= state_type( *std::next(b, 5) ) << 40; // fall through
54+
case 5: hash ^= state_type( *std::next(b, 4) ) << 32; // fall through
55+
case 4: hash ^= state_type( *std::next(b, 3) ) << 24; // fall through
56+
case 3: hash ^= state_type( *std::next(b, 2) ) << 16; // fall through
57+
case 2: hash ^= state_type( *std::next(b, 1) ) << 8; // fall through
58+
case 1: hash ^= state_type( *std::next(b, 0) );
59+
hash *= m;
60+
};
61+
62+
hash ^= hash >> r;
63+
hash *= m;
64+
hash ^= hash >> r;
65+
2866
#else
29-
std::uint32_t const prime = 0x01000193UL;
30-
std::uint32_t hash = 0x811C9DC5UL;
67+
68+
using state_type = std::uint32_t;
69+
state_type const m = 0x5bd1e995;
70+
int const r = 24;
71+
state_type hash = salt ^ len;
72+
73+
constexpr std::size_t N = sizeof(state_type);
74+
e = std::next( b, len & ~std::size_t(N-1) );
75+
for( ; b != e; std::advance(b, N) )
76+
{
77+
state_type num;
78+
std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
79+
80+
num *= m;
81+
num ^= num >> r;
82+
num *= m;
83+
hash *= m;
84+
hash ^= num;
85+
}
86+
87+
switch( len & (N - 1) )
88+
{
89+
case 3: hash ^= state_type( *std::next(b, 2) ) << 16; // fall through
90+
case 2: hash ^= state_type( *std::next(b, 1) ) << 8; // fall through
91+
case 1: hash ^= state_type( *std::next(b, 0) );
92+
hash *= m;
93+
};
94+
95+
hash ^= hash >> 13;
96+
hash *= m;
97+
hash ^= hash >> 15;
98+
3199
#endif
32-
hash += salt;
33-
for(; b != e; ++b)
34-
hash = (*b ^ hash) * prime;
100+
35101
return hash;
36102
}
37103

test/pointer.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,34 @@ class pointer_test
362362
BOOST_TEST( &*result == &jv );
363363
}
364364

365+
void
366+
testDigest()
367+
{
368+
value jv;
369+
object& jo = jv.emplace_object();
370+
for(auto i = 0; i < 100; ++i)
371+
jo[std::to_string(i)] = i;
372+
373+
for(auto i = 0; i < 4; ++i)
374+
{
375+
std::string key(i * 4, 'c');
376+
jo[key] = 1;
377+
BOOST_TEST( jv.at_pointer("/" + key) == 1 );
378+
379+
key += 'a';
380+
jo[key] = 1;
381+
BOOST_TEST( jv.at_pointer("/" + key) == 1 );
382+
383+
key += 'b';
384+
jo[key] = 1;
385+
BOOST_TEST( jv.at_pointer("/" + key) == 1 );
386+
387+
key += 'c';
388+
jo[key] = 1;
389+
BOOST_TEST( jv.at_pointer("/" + key) == 1 );
390+
}
391+
}
392+
365393
void
366394
run()
367395
{
@@ -376,6 +404,7 @@ class pointer_test
376404
testSetNonThrowing<system::error_code>();
377405
testSetNonThrowing<std::error_code>();
378406
testTry();
407+
testDigest();
379408
}
380409
};
381410

0 commit comments

Comments
 (0)