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 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
// Copyright 2017-2020 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#define _CRT_SECURE_NO_WARNINGS
#include <boost/hash2/fnv1a.hpp>
#include <boost/hash2/siphash.hpp>
#include <boost/hash2/xxhash.hpp>
#include <boost/hash2/xxh3.hpp>
#include <boost/hash2/hash_append.hpp>
#include <boost/hash2/get_integral_result.hpp>
#include <boost/core/type_name.hpp>
#include <cstdint>
#include <chrono>
#include <random>
#include <typeinfo>
#include <cstddef>
#include <cstdio>
#include <string>
#include <vector>
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
template<class T, class H> class hasher
{
private:
H h_;
private:
template<class = void> static void hash_append_impl( H& h, T const& v, std::false_type )
{
boost::hash2::hash_append( h, {}, v );
}
template<class = void> static void hash_append_impl( H& h, T const& v, std::true_type )
{
boost::hash2::hash_append_range( h, {}, v.data(), v.data() + v.size() );
}
public:
hasher(): h_()
{
}
explicit hasher( std::uint64_t seed ): h_( seed )
{
}
hasher( unsigned char const* seed, std::size_t n ): h_( seed, n )
{
}
std::size_t operator()( T const& v ) const
{
H h( h_ );
hash_append_impl( h, v, boost::container_hash::is_contiguous_range<T>() );
return boost::hash2::get_integral_result<std::size_t>( h );
}
};
template<class H, class V> void test3( int N, V const& v, std::size_t seed )
{
typedef std::chrono::steady_clock clock_type;
clock_type::time_point t1 = clock_type::now();
std::size_t q = 0;
hasher<std::string, H> const h( seed );
for( int i = 0; i < N; ++i )
{
q += h( v[i] );
}
clock_type::time_point t2 = clock_type::now();
long long ms1 = std::chrono::duration_cast<std::chrono::milliseconds>( t2 - t1 ).count();
std::string hash = boost::core::type_name<H>();
std::printf( "%s: q=%zu, %lld ms\n", hash.c_str(), q, ms1 );
}
template<class H, class V> void test2( int N, V const& v )
{
test3<H>( N, v, 0x9e3779b9 );
}
int main()
{
int const N = 16 * 1048576;
std::vector<std::string> v;
{
v.reserve( N );
std::mt19937_64 rnd;
for( int i = 0; i < N; ++i )
{
char buffer[ 64 ];
unsigned long long k = rnd();
if( k & 1 )
{
std::snprintf( buffer, sizeof( buffer ), "prefix_%llu_suffix", k );
}
else
{
std::snprintf( buffer, sizeof( buffer ), "{%u}", static_cast<unsigned>( k ) );
}
v.push_back( buffer );
}
}
using namespace boost::hash2;
test2<fnv1a_32>( N, v );
test2<fnv1a_64>( N, v );
test2<xxhash_32>( N, v );
test2<xxhash_64>( N, v );
test2<xxh3_128>( N, v );
test2<siphash_32>( N, v );
test2<siphash_64>( N, v );
std::puts( "" );
}
|