File indexing completed on 2025-09-17 08:33:45
0001 #ifndef BOOST_HASH2_XXHASH_HPP_INCLUDED
0002 #define BOOST_HASH2_XXHASH_HPP_INCLUDED
0003
0004
0005
0006
0007
0008
0009
0010 #include <boost/hash2/detail/read.hpp>
0011 #include <boost/hash2/detail/rot.hpp>
0012 #include <boost/hash2/detail/memset.hpp>
0013 #include <boost/hash2/detail/memcpy.hpp>
0014 #include <boost/assert.hpp>
0015 #include <boost/config.hpp>
0016 #include <cstdint>
0017 #include <cstring>
0018 #include <cstddef>
0019
0020 #if defined(BOOST_MSVC) && BOOST_MSVC < 1920
0021 # pragma warning(push)
0022 # pragma warning(disable: 4307)
0023 #endif
0024
0025 namespace boost
0026 {
0027 namespace hash2
0028 {
0029
0030 class xxhash_32
0031 {
0032 private:
0033
0034 static constexpr std::uint32_t P1 = 2654435761U;
0035 static constexpr std::uint32_t P2 = 2246822519U;
0036 static constexpr std::uint32_t P3 = 3266489917U;
0037 static constexpr std::uint32_t P4 = 668265263U;
0038 static constexpr std::uint32_t P5 = 374761393U;
0039
0040 private:
0041
0042 std::uint32_t v1_ = P1 + P2;
0043 std::uint32_t v2_ = P2;
0044 std::uint32_t v3_ = 0;
0045 std::uint32_t v4_ = static_cast<std::uint32_t>( 0 ) - P1;
0046
0047 unsigned char buffer_[ 16 ] = {};
0048 std::size_t m_ = 0;
0049
0050 std::size_t n_ = 0;
0051
0052 private:
0053
0054 BOOST_CXX14_CONSTEXPR void init( std::uint32_t seed )
0055 {
0056 v1_ = seed + P1 + P2;
0057 v2_ = seed + P2;
0058 v3_ = seed;
0059 v4_ = seed - P1;
0060 }
0061
0062 BOOST_CXX14_CONSTEXPR static std::uint32_t round( std::uint32_t seed, std::uint32_t input )
0063 {
0064 seed += input * P2;
0065 seed = detail::rotl( seed, 13 );
0066 seed *= P1;
0067 return seed;
0068 }
0069
0070 BOOST_CXX14_CONSTEXPR void update_( unsigned char const * p, std::size_t k )
0071 {
0072 std::uint32_t v1 = v1_;
0073 std::uint32_t v2 = v2_;
0074 std::uint32_t v3 = v3_;
0075 std::uint32_t v4 = v4_;
0076
0077 for( std::size_t i = 0; i < k; ++i, p += 16 )
0078 {
0079 v1 = round( v1, detail::read32le( p + 0 ) );
0080 v2 = round( v2, detail::read32le( p + 4 ) );
0081 v3 = round( v3, detail::read32le( p + 8 ) );
0082 v4 = round( v4, detail::read32le( p + 12 ) );
0083 }
0084
0085 v1_ = v1;
0086 v2_ = v2;
0087 v3_ = v3;
0088 v4_ = v4;
0089 }
0090
0091 public:
0092
0093 using result_type = std::uint32_t;
0094
0095 xxhash_32() = default;
0096
0097 BOOST_CXX14_CONSTEXPR explicit xxhash_32( std::uint64_t seed )
0098 {
0099 std::uint32_t s0 = static_cast<std::uint32_t>( seed );
0100 std::uint32_t s1 = static_cast<std::uint32_t>( seed >> 32 );
0101
0102 init( s0 );
0103
0104 if( s1 != 0 )
0105 {
0106 v1_ = round( v1_, s1 );
0107 v2_ = round( v2_, s1 );
0108 v3_ = round( v3_, s1 );
0109 v4_ = round( v4_, s1 );
0110 }
0111 }
0112
0113 BOOST_CXX14_CONSTEXPR xxhash_32( unsigned char const * p, std::size_t n )
0114 {
0115 if( n != 0 )
0116 {
0117 update( p, n );
0118 result();
0119 }
0120 }
0121
0122 xxhash_32( void const * p, std::size_t n ): xxhash_32( static_cast<unsigned char const*>( p ), n )
0123 {
0124 }
0125
0126 BOOST_CXX14_CONSTEXPR void update( unsigned char const* p, std::size_t n )
0127 {
0128 BOOST_ASSERT( m_ == n_ % 16 );
0129
0130 if( n == 0 ) return;
0131
0132 n_ += n;
0133
0134 if( m_ > 0 )
0135 {
0136 std::size_t k = 16 - m_;
0137
0138 if( n < k )
0139 {
0140 k = n;
0141 }
0142
0143 detail::memcpy( buffer_ + m_, p, k );
0144
0145 p += k;
0146 n -= k;
0147 m_ += k;
0148
0149 if( m_ < 16 ) return;
0150
0151 BOOST_ASSERT( m_ == 16 );
0152
0153 update_( buffer_, 1 );
0154 m_ = 0;
0155 }
0156
0157 BOOST_ASSERT( m_ == 0 );
0158
0159 {
0160 std::size_t k = n / 16;
0161
0162 update_( p, k );
0163
0164 p += 16 * k;
0165 n -= 16 * k;
0166 }
0167
0168 BOOST_ASSERT( n < 16 );
0169
0170 if( n > 0 )
0171 {
0172 detail::memcpy( buffer_, p, n );
0173 m_ = n;
0174 }
0175
0176 BOOST_ASSERT( m_ == n_ % 16 );
0177 }
0178
0179 void update( void const* pv, std::size_t n )
0180 {
0181 unsigned char const* p = static_cast<unsigned char const*>( pv );
0182 update( p, n );
0183 }
0184
0185 BOOST_CXX14_CONSTEXPR std::uint32_t result()
0186 {
0187 BOOST_ASSERT( m_ == n_ % 16 );
0188
0189 std::uint32_t h = 0;
0190
0191 if( n_ >= 16 )
0192 {
0193 h = detail::rotl( v1_, 1 ) + detail::rotl( v2_, 7 ) + detail::rotl( v3_, 12 ) + detail::rotl( v4_, 18 );
0194 }
0195 else
0196 {
0197 h = v3_ + P5;
0198 }
0199
0200 h += static_cast<std::uint32_t>( n_ );
0201
0202 unsigned char const * p = buffer_;
0203
0204 std::size_t m = m_;
0205
0206 while( m >= 4 )
0207 {
0208 h += detail::read32le( p ) * P3;
0209 h = detail::rotl( h, 17 ) * P4;
0210
0211 p += 4;
0212 m -= 4;
0213 }
0214
0215 while( m > 0 )
0216 {
0217 h += p[0] * P5;
0218 h = detail::rotl( h, 11 ) * P1;
0219
0220 ++p;
0221 --m;
0222 }
0223
0224 n_ += 16 - m_;
0225 m_ = 0;
0226
0227
0228 detail::memset( buffer_, 0, 16 );
0229
0230
0231 v1_ += h;
0232 v2_ += h;
0233 v3_ -= h;
0234 v4_ -= h;
0235
0236
0237 h ^= h >> 15;
0238 h *= P2;
0239 h ^= h >> 13;
0240 h *= P3;
0241 h ^= h >> 16;
0242
0243 return h;
0244 }
0245 };
0246
0247 class xxhash_64
0248 {
0249 private:
0250
0251 static constexpr std::uint64_t P1 = 11400714785074694791ULL;
0252 static constexpr std::uint64_t P2 = 14029467366897019727ULL;
0253 static constexpr std::uint64_t P3 = 1609587929392839161ULL;
0254 static constexpr std::uint64_t P4 = 9650029242287828579ULL;
0255 static constexpr std::uint64_t P5 = 2870177450012600261ULL;
0256
0257 private:
0258
0259 std::uint64_t v1_ = P1 + P2;
0260 std::uint64_t v2_ = P2;
0261 std::uint64_t v3_ = 0;
0262 std::uint64_t v4_ = static_cast<std::uint64_t>( 0 ) - P1;
0263
0264 unsigned char buffer_[ 32 ] = {};
0265 std::size_t m_ = 0;
0266
0267 std::uint64_t n_ = 0;
0268
0269 private:
0270
0271 BOOST_CXX14_CONSTEXPR void init( std::uint64_t seed )
0272 {
0273 v1_ = seed + P1 + P2;
0274 v2_ = seed + P2;
0275 v3_ = seed;
0276 v4_ = seed - P1;
0277 }
0278
0279 BOOST_CXX14_CONSTEXPR static std::uint64_t round( std::uint64_t seed, std::uint64_t input )
0280 {
0281 seed += input * P2;
0282 seed = detail::rotl( seed, 31 );
0283 seed *= P1;
0284 return seed;
0285 }
0286
0287 BOOST_CXX14_CONSTEXPR static std::uint64_t merge_round( std::uint64_t acc, std::uint64_t val )
0288 {
0289 val = round( 0, val );
0290 acc ^= val;
0291 acc = acc * P1 + P4;
0292 return acc;
0293 }
0294
0295 BOOST_CXX14_CONSTEXPR void update_( unsigned char const * p, std::size_t k )
0296 {
0297 std::uint64_t v1 = v1_;
0298 std::uint64_t v2 = v2_;
0299 std::uint64_t v3 = v3_;
0300 std::uint64_t v4 = v4_;
0301
0302 for( std::size_t i = 0; i < k; ++i, p += 32 )
0303 {
0304 v1 = round( v1, detail::read64le( p + 0 ) );
0305 v2 = round( v2, detail::read64le( p + 8 ) );
0306 v3 = round( v3, detail::read64le( p + 16 ) );
0307 v4 = round( v4, detail::read64le( p + 24 ) );
0308 }
0309
0310 v1_ = v1;
0311 v2_ = v2;
0312 v3_ = v3;
0313 v4_ = v4;
0314 }
0315
0316 public:
0317
0318 typedef std::uint64_t result_type;
0319
0320 xxhash_64() = default;
0321
0322 BOOST_CXX14_CONSTEXPR explicit xxhash_64( std::uint64_t seed )
0323 {
0324 init( seed );
0325 }
0326
0327 BOOST_CXX14_CONSTEXPR xxhash_64( unsigned char const * p, std::size_t n )
0328 {
0329 if( n != 0 )
0330 {
0331 update( p, n );
0332 result();
0333 }
0334 }
0335
0336 xxhash_64( void const * p, std::size_t n ): xxhash_64( static_cast<unsigned char const*>( p ), n )
0337 {
0338 }
0339
0340 BOOST_CXX14_CONSTEXPR void update( unsigned char const* p, std::size_t n )
0341 {
0342 BOOST_ASSERT( m_ == n_ % 32 );
0343
0344 if( n == 0 ) return;
0345
0346 n_ += n;
0347
0348 if( m_ > 0 )
0349 {
0350 std::size_t k = 32 - m_;
0351
0352 if( n < k )
0353 {
0354 k = n;
0355 }
0356
0357 detail::memcpy( buffer_ + m_, p, k );
0358
0359 p += k;
0360 n -= k;
0361 m_ += k;
0362
0363 if( m_ < 32 ) return;
0364
0365 BOOST_ASSERT( m_ == 32 );
0366
0367 update_( buffer_, 1 );
0368 m_ = 0;
0369 }
0370
0371 BOOST_ASSERT( m_ == 0 );
0372
0373 {
0374 std::size_t k = n / 32;
0375
0376 update_( p, k );
0377
0378 p += 32 * k;
0379 n -= 32 * k;
0380 }
0381
0382 BOOST_ASSERT( n < 32 );
0383
0384 if( n > 0 )
0385 {
0386 detail::memcpy( buffer_, p, n );
0387 m_ = n;
0388 }
0389
0390 BOOST_ASSERT( m_ == n_ % 32 );
0391 }
0392
0393 void update( void const* pv, std::size_t n )
0394 {
0395 unsigned char const* p = static_cast<unsigned char const*>( pv );
0396 update( p, n );
0397 }
0398
0399 BOOST_CXX14_CONSTEXPR std::uint64_t result()
0400 {
0401 BOOST_ASSERT( m_ == n_ % 32 );
0402
0403 std::uint64_t h = 0;
0404
0405 if( n_ >= 32 )
0406 {
0407 h = detail::rotl( v1_, 1 ) + detail::rotl( v2_, 7 ) + detail::rotl( v3_, 12 ) + detail::rotl( v4_, 18 );
0408
0409 h = merge_round( h, v1_ );
0410 h = merge_round( h, v2_ );
0411 h = merge_round( h, v3_ );
0412 h = merge_round( h, v4_ );
0413 }
0414 else
0415 {
0416 h = v3_ + P5;
0417 }
0418
0419 h += n_;
0420
0421 unsigned char const * p = buffer_;
0422
0423 std::size_t m = m_;
0424
0425 while( m >= 8 )
0426 {
0427 std::uint64_t k1 = round( 0, detail::read64le( p ) );
0428
0429 h ^= k1;
0430 h = detail::rotl( h, 27 ) * P1 + P4;
0431
0432 p += 8;
0433 m -= 8;
0434 }
0435
0436 while( m >= 4 )
0437 {
0438 h ^= static_cast<std::uint64_t>( detail::read32le( p ) ) * P1;
0439 h = detail::rotl( h, 23 ) * P2 + P3;
0440
0441 p += 4;
0442 m -= 4;
0443 }
0444
0445 while( m > 0 )
0446 {
0447 h ^= p[0] * P5;
0448 h = detail::rotl( h, 11 ) * P1;
0449
0450 ++p;
0451 --m;
0452 }
0453
0454 n_ += 32 - m_;
0455 m_ = 0;
0456
0457
0458 detail::memset( buffer_, 0, 32 );
0459
0460
0461 v1_ += h;
0462 v2_ += h;
0463 v3_ -= h;
0464 v4_ -= h;
0465
0466
0467 h ^= h >> 33;
0468 h *= P2;
0469 h ^= h >> 29;
0470 h *= P3;
0471 h ^= h >> 32;
0472
0473 return h;
0474 }
0475 };
0476
0477 }
0478 }
0479
0480 #if defined(BOOST_MSVC) && BOOST_MSVC < 1920
0481 # pragma warning(pop)
0482 #endif
0483
0484 #endif