mirror of
https://github.com/boostorg/json.git
synced 2026-01-19 04:12:14 +00:00
use murmur2a hash
This commit is contained in:
@@ -10,6 +10,11 @@
|
||||
#ifndef BOOST_JSON_DETAIL_DIGEST_HPP
|
||||
#define BOOST_JSON_DETAIL_DIGEST_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
@@ -17,21 +22,82 @@ namespace detail {
|
||||
// Calculate salted digest of string
|
||||
template<class ForwardIterator>
|
||||
std::size_t
|
||||
digest(
|
||||
ForwardIterator b,
|
||||
ForwardIterator e,
|
||||
std::size_t salt) noexcept
|
||||
digest(ForwardIterator b, ForwardIterator e, std::size_t salt) noexcept
|
||||
{
|
||||
std::size_t const len = std::distance(b, e);
|
||||
|
||||
#if BOOST_JSON_ARCH == 64
|
||||
std::uint64_t const prime = 0x100000001B3ULL;
|
||||
std::uint64_t hash = 0xcbf29ce484222325ULL;
|
||||
|
||||
using state_type = std::uint64_t;
|
||||
state_type const m = 0xc6a4a7935bd1e995ULL;
|
||||
int const r = 47;
|
||||
state_type hash = salt ^ (len * m);
|
||||
|
||||
constexpr std::size_t N = sizeof(state_type);
|
||||
e = std::next( b, len & ~std::size_t(N-1) );
|
||||
for( ; b != e; std::advance(b, N) )
|
||||
{
|
||||
state_type num;
|
||||
std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
|
||||
|
||||
num *= m;
|
||||
num ^= num >> r;
|
||||
num *= m;
|
||||
hash ^= num;
|
||||
hash *= m;
|
||||
}
|
||||
|
||||
switch( len & (N - 1) )
|
||||
{
|
||||
case 7: hash ^= state_type( *std::next(b, 6) ) << 48; // fall through
|
||||
case 6: hash ^= state_type( *std::next(b, 5) ) << 40; // fall through
|
||||
case 5: hash ^= state_type( *std::next(b, 4) ) << 32; // fall through
|
||||
case 4: hash ^= state_type( *std::next(b, 3) ) << 24; // fall through
|
||||
case 3: hash ^= state_type( *std::next(b, 2) ) << 16; // fall through
|
||||
case 2: hash ^= state_type( *std::next(b, 1) ) << 8; // fall through
|
||||
case 1: hash ^= state_type( *std::next(b, 0) );
|
||||
hash *= m;
|
||||
};
|
||||
|
||||
hash ^= hash >> r;
|
||||
hash *= m;
|
||||
hash ^= hash >> r;
|
||||
|
||||
#else
|
||||
std::uint32_t const prime = 0x01000193UL;
|
||||
std::uint32_t hash = 0x811C9DC5UL;
|
||||
|
||||
using state_type = std::uint32_t;
|
||||
state_type const m = 0x5bd1e995;
|
||||
int const r = 24;
|
||||
state_type hash = salt ^ len;
|
||||
|
||||
constexpr std::size_t N = sizeof(state_type);
|
||||
e = std::next( b, len & ~std::size_t(N-1) );
|
||||
for( ; b != e; std::advance(b, N) )
|
||||
{
|
||||
state_type num;
|
||||
std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
|
||||
|
||||
num *= m;
|
||||
num ^= num >> r;
|
||||
num *= m;
|
||||
hash *= m;
|
||||
hash ^= num;
|
||||
}
|
||||
|
||||
switch( len & (N - 1) )
|
||||
{
|
||||
case 3: hash ^= state_type( *std::next(b, 2) ) << 16; // fall through
|
||||
case 2: hash ^= state_type( *std::next(b, 1) ) << 8; // fall through
|
||||
case 1: hash ^= state_type( *std::next(b, 0) );
|
||||
hash *= m;
|
||||
};
|
||||
|
||||
hash ^= hash >> 13;
|
||||
hash *= m;
|
||||
hash ^= hash >> 15;
|
||||
|
||||
#endif
|
||||
hash += salt;
|
||||
for(; b != e; ++b)
|
||||
hash = (*b ^ hash) * prime;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
@@ -362,6 +362,34 @@ public:
|
||||
BOOST_TEST( &*result == &jv );
|
||||
}
|
||||
|
||||
void
|
||||
testDigest()
|
||||
{
|
||||
value jv;
|
||||
object& jo = jv.emplace_object();
|
||||
for(auto i = 0; i < 100; ++i)
|
||||
jo[std::to_string(i)] = i;
|
||||
|
||||
for(auto i = 0; i < 4; ++i)
|
||||
{
|
||||
std::string key(i * 4, 'c');
|
||||
jo[key] = 1;
|
||||
BOOST_TEST( jv.at_pointer("/" + key) == 1 );
|
||||
|
||||
key += 'a';
|
||||
jo[key] = 1;
|
||||
BOOST_TEST( jv.at_pointer("/" + key) == 1 );
|
||||
|
||||
key += 'b';
|
||||
jo[key] = 1;
|
||||
BOOST_TEST( jv.at_pointer("/" + key) == 1 );
|
||||
|
||||
key += 'c';
|
||||
jo[key] = 1;
|
||||
BOOST_TEST( jv.at_pointer("/" + key) == 1 );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
@@ -376,6 +404,7 @@ public:
|
||||
testSetNonThrowing<system::error_code>();
|
||||
testSetNonThrowing<std::error_code>();
|
||||
testTry();
|
||||
testDigest();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user