File indexing completed on 2025-09-17 08:33:42
0001 #ifndef BOOST_HASH2_MURMUR3_HPP_INCLUDED
0002 #define BOOST_HASH2_MURMUR3_HPP_INCLUDED
0003
0004
0005
0006
0007
0008
0009
0010 #include <boost/hash2/detail/read.hpp>
0011 #include <boost/hash2/detail/write.hpp>
0012 #include <boost/hash2/detail/rot.hpp>
0013 #include <boost/assert.hpp>
0014 #include <cstdint>
0015 #include <array>
0016 #include <cstring>
0017 #include <cstddef>
0018
0019 namespace boost
0020 {
0021 namespace hash2
0022 {
0023
0024 class murmur3_32
0025 {
0026 private:
0027
0028 std::uint32_t h_;
0029
0030 unsigned char buffer_[ 4 ];
0031 std::size_t m_;
0032
0033 std::size_t n_;
0034
0035 private:
0036
0037 static const std::uint32_t c1 = 0xcc9e2d51u;
0038 static const std::uint32_t c2 = 0x1b873593u;
0039
0040 private:
0041
0042 static BOOST_FORCEINLINE void mix( std::uint32_t & h, std::uint32_t k )
0043 {
0044 k *= c1;
0045 k = detail::rotl( k, 15 );
0046 k *= c2;
0047
0048 h ^= k;
0049 h = detail::rotl( h, 13 );
0050 h = h * 5 + 0xe6546b64;
0051 }
0052
0053 void update_( unsigned char const * p, std::size_t m )
0054 {
0055 std::uint32_t h = h_;
0056
0057 for( std::size_t i = 0; i < m; ++i, p += 4 )
0058 {
0059 std::uint32_t k = detail::read32le( p );
0060 mix( h, k );
0061 }
0062
0063 h_ = h;
0064 }
0065
0066 public:
0067
0068 typedef std::uint32_t result_type;
0069 typedef std::uint32_t size_type;
0070
0071 explicit murmur3_32( std::uint64_t seed = 0 ): m_( 0 ), n_( 0 )
0072 {
0073 h_ = static_cast<std::uint32_t>( seed );
0074
0075 std::uint32_t k = static_cast<std::uint32_t>( seed >> 32 );
0076
0077 if( k != 0 )
0078 {
0079 mix( h_, k );
0080 }
0081 }
0082
0083 murmur3_32( unsigned char const * p, std::size_t n ): m_( 0 ), n_( 0 )
0084 {
0085 if( n == 0 )
0086 {
0087 h_ = 0;
0088 }
0089 else if( n <= 4 )
0090 {
0091 unsigned char q[ 4 ] = {};
0092 std::memcpy( q, p, n );
0093
0094 h_ = detail::read32le( q );
0095 }
0096 else
0097 {
0098 h_ = detail::read32le( p );
0099
0100 p += 4;
0101 n -= 4;
0102
0103 update( p, n );
0104 result();
0105 }
0106 }
0107
0108 void update( void const * pv, std::size_t n )
0109 {
0110 unsigned char const* p = static_cast<unsigned char const*>( pv );
0111
0112 BOOST_ASSERT( m_ == n_ % 4 );
0113
0114 if( n == 0 ) return;
0115
0116 n_ += n;
0117
0118 if( m_ > 0 )
0119 {
0120 std::size_t k = 4 - m_;
0121
0122 if( n < k )
0123 {
0124 k = n;
0125 }
0126
0127 std::memcpy( buffer_ + m_, p, k );
0128
0129 p += k;
0130 n -= k;
0131 m_ += k;
0132
0133 if( m_ < 4 ) return;
0134
0135 BOOST_ASSERT( m_ == 4 );
0136
0137 update_( buffer_, 1 );
0138 m_ = 0;
0139 }
0140
0141 BOOST_ASSERT( m_ == 0 );
0142
0143 {
0144 std::size_t k = n / 4;
0145
0146 update_( p, k );
0147
0148 p += 4 * k;
0149 n -= 4 * k;
0150 }
0151
0152 BOOST_ASSERT( n < 4 );
0153
0154 if( n > 0 )
0155 {
0156 std::memcpy( buffer_, p, n );
0157 m_ = n;
0158 }
0159
0160 BOOST_ASSERT( m_ == n_ % 4 );
0161 }
0162
0163 std::uint32_t result()
0164 {
0165 BOOST_ASSERT( m_ == n_ % 4 );
0166
0167
0168
0169
0170 std::uint32_t k = 0;
0171
0172 switch( m_ )
0173 {
0174 case 1:
0175
0176 k = buffer_[0];
0177 break;
0178
0179 case 2:
0180
0181 k = buffer_[0] + (buffer_[1] << 8);
0182 break;
0183
0184 case 3:
0185
0186 k = buffer_[0] + (buffer_[1] << 8) + (buffer_[2] << 16);
0187 break;
0188 }
0189
0190 k *= c1;
0191 k = detail::rotl( k, 15 );
0192 k *= c2;
0193
0194 std::uint32_t h = h_;
0195
0196 h ^= k;
0197 h ^= static_cast<std::uint32_t>( n_ );
0198
0199 h ^= h >> 16;
0200 h *= 0x85ebca6b;
0201 h ^= h >> 13;
0202 h *= 0xc2b2ae35;
0203 h ^= h >> 16;
0204
0205 n_ += 4 - m_;
0206 m_ = 0;
0207
0208
0209 std::memset( buffer_, 0, 4 );
0210
0211 return h;
0212 }
0213 };
0214
0215 class murmur3_128
0216 {
0217 private:
0218
0219 std::uint64_t h1_, h2_;
0220
0221 unsigned char buffer_[ 16 ];
0222 std::size_t m_;
0223
0224 std::size_t n_;
0225
0226 private:
0227
0228 static const std::uint64_t c1 = 0x87c37b91114253d5ull;
0229 static const std::uint64_t c2 = 0x4cf5ad432745937full;
0230
0231 private:
0232
0233 void update_( unsigned char const * p, std::size_t k )
0234 {
0235 std::uint64_t h1 = h1_, h2 = h2_;
0236
0237 for( std::size_t i = 0; i < k; ++i, p += 16 )
0238 {
0239 std::uint64_t k1 = detail::read64le( p + 0 );
0240 std::uint64_t k2 = detail::read64le( p + 8 );
0241
0242 k1 *= c1; k1 = detail::rotl( k1, 31 ); k1 *= c2; h1 ^= k1;
0243
0244 h1 = detail::rotl( h1, 27 ); h1 += h2; h1 = h1 * 5 + 0x52dce729;
0245
0246 k2 *= c2; k2 = detail::rotl( k2, 33 ); k2 *= c1; h2 ^= k2;
0247
0248 h2 = detail::rotl( h2, 31 ); h2 += h1; h2 = h2 * 5 + 0x38495ab5;
0249 }
0250
0251 h1_ = h1; h2_ = h2;
0252 }
0253
0254 static std::uint64_t fmix( std::uint64_t k )
0255 {
0256 k ^= k >> 33;
0257 k *= 0xff51afd7ed558ccdull;
0258 k ^= k >> 33;
0259 k *= 0xc4ceb9fe1a85ec53ull;
0260 k ^= k >> 33;
0261
0262 return k;
0263 }
0264
0265 public:
0266
0267 typedef std::array<unsigned char, 16> result_type;
0268 typedef std::uint64_t size_type;
0269
0270 explicit murmur3_128( std::uint64_t seed = 0 ): m_( 0 ), n_( 0 )
0271 {
0272 h1_ = seed;
0273 h2_ = seed;
0274 }
0275
0276 murmur3_128( std::uint64_t seed1, std::uint64_t seed2 ): m_( 0 ), n_( 0 )
0277 {
0278 h1_ = seed1;
0279 h2_ = seed2;
0280 }
0281
0282 murmur3_128( unsigned char const * p, std::size_t n ): m_( 0 ), n_( 0 )
0283 {
0284 if( n == 0 )
0285 {
0286 h1_ = h2_ = 0;
0287 }
0288 else if( n <= 8 )
0289 {
0290 unsigned char q[ 8 ] = {};
0291 std::memcpy( q, p, n );
0292
0293 h1_ = h2_ = detail::read64le( q );
0294 }
0295 else if( n <= 16 )
0296 {
0297 unsigned char q[ 18 ] = {};
0298 std::memcpy( q, p, n );
0299
0300 h1_ = detail::read64le( q + 0 );
0301 h2_ = detail::read64le( q + 8 );
0302 }
0303 else
0304 {
0305 h1_ = detail::read64le( p + 0 );
0306 h2_ = detail::read64le( p + 8 );
0307
0308 p += 16;
0309 n -= 16;
0310
0311 update( p, n );
0312 result();
0313 }
0314 }
0315
0316 void update( void const * pv, std::size_t n )
0317 {
0318 unsigned char const* p = static_cast<unsigned char const*>( pv );
0319
0320 BOOST_ASSERT( m_ == n_ % 16 );
0321
0322 if( n == 0 ) return;
0323
0324 n_ += n;
0325
0326 if( m_ > 0 )
0327 {
0328 std::size_t k = 16 - m_;
0329
0330 if( n < k )
0331 {
0332 k = n;
0333 }
0334
0335 std::memcpy( buffer_ + m_, p, k );
0336
0337 p += k;
0338 n -= k;
0339 m_ += k;
0340
0341 if( m_ < 16 ) return;
0342
0343 BOOST_ASSERT( m_ == 16 );
0344
0345 update_( buffer_, 1 );
0346 m_ = 0;
0347 }
0348
0349 BOOST_ASSERT( m_ == 0 );
0350
0351 {
0352 std::size_t k = n / 16;
0353
0354 update_( p, k );
0355
0356 p += 16 * k;
0357 n -= 16 * k;
0358 }
0359
0360 BOOST_ASSERT( n < 16 );
0361
0362 if( n > 0 )
0363 {
0364 std::memcpy( buffer_, p, n );
0365 m_ = n;
0366 }
0367
0368 BOOST_ASSERT( m_ == n_ % 16 );
0369 }
0370
0371 result_type result()
0372 {
0373 BOOST_ASSERT( m_ == n_ % 16 );
0374
0375 std::memset( buffer_ + m_, 0, 16 - m_ );
0376
0377 std::uint64_t h1 = h1_, h2 = h2_;
0378
0379 std::uint64_t k1 = detail::read64le( buffer_ + 0 );
0380 std::uint64_t k2 = detail::read64le( buffer_ + 8 );
0381
0382 k1 *= c1; k1 = detail::rotl( k1, 31 ); k1 *= c2; h1 ^= k1;
0383 k2 *= c2; k2 = detail::rotl( k2, 33 ); k2 *= c1; h2 ^= k2;
0384
0385 h1 ^= n_;
0386 h2 ^= n_;
0387
0388 h1 += h2;
0389 h2 += h1;
0390
0391 h1 = fmix( h1 );
0392 h2 = fmix( h2 );
0393
0394 h1 += h2;
0395 h2 += h1;
0396
0397 n_ += 16 - m_;
0398 m_ = 0;
0399
0400
0401 std::memset( buffer_, 0, 16 );
0402
0403 result_type r;
0404
0405 detail::write64le( &r[ 0 ], h1 );
0406 detail::write64le( &r[ 8 ], h2 );
0407
0408 return r;
0409 }
0410 };
0411
0412 }
0413 }
0414
0415 #endif