2
0
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:
Dmitry Arkhipov
2024-04-08 17:27:26 +03:00
parent 3c80c097d2
commit e4023c05e4
2 changed files with 106 additions and 11 deletions

View File

@@ -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;
}

View File

@@ -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();
}
};