Back to home page

EIC code displayed by LXR

 
 

    


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 // Copyright 2017, 2018 Peter Dimov.
0005 // Distributed under the Boost Software License, Version 1.0.
0006 // https://www.boost.org/LICENSE_1_0.txt
0007 //
0008 // MurmurHash3, https://github.com/aappleby/smhasher/wiki/MurmurHash3
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_; // == n_ % 4
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         // std::memset( buffer_ + m_, 0, 4 - m_ );
0168         // std::uint32_t k = detail::read32le( buffer_ );
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         // clear buffered plaintext
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_; // == n_ % 16
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         // clear buffered plaintext
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 } // namespace hash2
0413 } // namespace boost
0414 
0415 #endif // #ifndef BOOST_HASH2_MURMUR3_HPP_INCLUDED