File indexing completed on 2026-08-17 08:46:48
0001 #ifndef BOOST_HASH2_XXH3_HPP_INCLUDED
0002 #define BOOST_HASH2_XXH3_HPP_INCLUDED
0003
0004
0005
0006
0007
0008
0009
0010 #include <boost/hash2/digest.hpp>
0011 #include <boost/hash2/detail/byteswap.hpp>
0012 #include <boost/hash2/detail/is_constant_evaluated.hpp>
0013 #include <boost/hash2/detail/memset.hpp>
0014 #include <boost/hash2/detail/memcpy.hpp>
0015 #include <boost/hash2/detail/mul128.hpp>
0016 #include <boost/hash2/detail/read.hpp>
0017 #include <boost/hash2/detail/rot.hpp>
0018 #include <boost/hash2/detail/write.hpp>
0019 #include <boost/assert.hpp>
0020 #include <boost/config.hpp>
0021 #include <boost/config/workaround.hpp>
0022 #include <cstdint>
0023 #include <cstring>
0024 #include <cstddef>
0025
0026 #if defined(BOOST_MSVC) && BOOST_MSVC < 1920
0027 # pragma warning(push)
0028 # pragma warning(disable: 4307)
0029 #endif
0030
0031 namespace boost
0032 {
0033 namespace hash2
0034 {
0035
0036 template<class = void>
0037 struct xxh3_128_constants
0038 {
0039 constexpr static unsigned char const default_secret[ 192 ] =
0040 {
0041 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
0042 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
0043 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,
0044 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,
0045 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,
0046 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,
0047 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,
0048 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,
0049 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
0050 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,
0051 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,
0052 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
0053 };
0054 };
0055
0056
0057 #if defined(BOOST_NO_CXX17_INLINE_VARIABLES)
0058
0059
0060
0061
0062
0063
0064 template<class T>
0065 constexpr unsigned char xxh3_128_constants<T>::default_secret[ 192 ];
0066
0067 #endif
0068
0069 class xxh3_128
0070 {
0071 private:
0072
0073 static constexpr std::size_t const default_secret_len = 192;
0074 static constexpr std::size_t const min_secret_len = 136;
0075 static constexpr std::size_t const buffer_size = 256;
0076
0077 static constexpr std::uint64_t const P32_1 = 0x9E3779B1U;
0078 static constexpr std::uint64_t const P32_2 = 0x85EBCA77U;
0079 static constexpr std::uint64_t const P32_3 = 0xC2B2AE3DU;
0080 static constexpr std::uint64_t const P64_1 = 0x9E3779B185EBCA87ULL;
0081 static constexpr std::uint64_t const P64_2 = 0xC2B2AE3D27D4EB4FULL;
0082 static constexpr std::uint64_t const P64_3 = 0x165667B19E3779F9ULL;
0083 static constexpr std::uint64_t const P64_4 = 0x85EBCA77C2B2AE63ULL;
0084 static constexpr std::uint64_t const P64_5 = 0x27D4EB2F165667C5ULL;
0085 static constexpr std::uint64_t const PRIME_MX1 = 0x165667919E3779F9ULL;
0086 static constexpr std::uint64_t const PRIME_MX2 = 0x9FB21C651E98DF25ULL;
0087
0088 BOOST_CXX14_CONSTEXPR void init_secret_from_seed( std::uint64_t seed )
0089 {
0090 auto const secret = xxh3_128_constants<>::default_secret;
0091
0092 std::size_t num_rounds = default_secret_len / 16;
0093 for( std::size_t i = 0; i < num_rounds; ++i )
0094 {
0095 auto low = detail::read64le( secret + 16 * i ) + seed;
0096 auto high = detail::read64le( secret + 16 * i + 8 ) - seed;
0097
0098 detail::write64le( secret_ + 16 * i, low );
0099 detail::write64le( secret_ + 16 * i + 8, high );
0100 }
0101 }
0102
0103 BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR static std::uint64_t avalanche( std::uint64_t x )
0104 {
0105 x ^= ( x >> 37 );
0106 x *= PRIME_MX1;
0107 x ^= ( x >> 32 );
0108 return x;
0109 }
0110
0111 BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR static std::uint64_t avalanche_xxh64( std::uint64_t x )
0112 {
0113 x ^= x >> 33;
0114 x *= P64_2;
0115 x ^= x >> 29;
0116 x *= P64_3;
0117 x ^= x >> 32;
0118 return x;
0119 }
0120
0121 BOOST_CXX14_CONSTEXPR std::uint64_t mix_step( unsigned char const* data, std::size_t secret_offset, std::uint64_t seed )
0122 {
0123 auto const secret = with_secret_? secret_: xxh3_128_constants<>::default_secret;
0124
0125 std::uint64_t data_words[ 2 ] = {};
0126 std::uint64_t secret_words[ 2 ] = {};
0127 for( int i = 0; i < 2; ++i )
0128 {
0129 data_words[ i ] = detail::read64le( data + 8 * i );
0130 secret_words[ i ] = detail::read64le( secret + secret_offset + 8 * i );
0131 }
0132
0133 detail::uint128 r = detail::mul128( data_words[ 0 ] ^ ( secret_words[ 0 ] + seed ), data_words[ 1 ] ^ ( secret_words[ 1 ] - seed ) );
0134 return r.low ^ r.high;
0135 }
0136
0137 BOOST_CXX14_CONSTEXPR void mix_two_chunks( unsigned char const* x, unsigned char const* y, std::size_t secret_offset, std::uint64_t seed, std::uint64_t (&acc)[ 2 ] )
0138 {
0139 std::uint64_t data_words1[ 2 ] = {};
0140 std::uint64_t data_words2[ 2 ] = {};
0141
0142 for( int i = 0; i < 2; ++i )
0143 {
0144 data_words1[ i ] = detail::read64le( x + 8 * i );
0145 data_words2[ i ] = detail::read64le( y + 8 * i );
0146 }
0147
0148 acc[ 0 ] += mix_step( x, secret_offset, seed );
0149 acc[ 1 ] += mix_step( y, secret_offset + 16, seed );
0150 acc[ 0 ] ^= ( data_words2[ 0 ] + data_words2[ 1 ] );
0151 acc[ 1 ] ^= ( data_words1[ 0 ] + data_words1[ 1 ] );
0152 }
0153
0154 BOOST_CXX14_CONSTEXPR void accumulate( std::uint64_t stripe[ 8 ], std::size_t secret_offset )
0155 {
0156 std::uint64_t secret_words[ 8 ] = {};
0157 for( int i = 0; i < 8; ++i )
0158 {
0159 secret_words[ i ] = detail::read64le( secret_ + secret_offset + 8 * i );
0160 }
0161
0162 for( int i = 0; i < 8; ++i )
0163 {
0164 std::uint64_t value = stripe[ i ] ^ secret_words[ i ];
0165 acc_[ i ^ 1 ] = acc_[ i ^ 1 ] + stripe[ i ];
0166 acc_[ i ] = acc_[ i ] + ( value & 0xffffffff ) * ( value >> 32 );
0167 }
0168 }
0169
0170 BOOST_CXX14_CONSTEXPR void scramble()
0171 {
0172 std::uint64_t secret_words[ 8 ] = {};
0173 for( int i = 0; i < 8; ++i )
0174 {
0175 secret_words[ i ] = detail::read64le( secret_ + ( secret_len_ - 64 ) + ( 8 * i ) );
0176 }
0177
0178 for( int i = 0; i < 8; ++i )
0179 {
0180 acc_[ i ] ^= acc_[ i ] >> 47;
0181 acc_[ i ] ^= secret_words[ i ];
0182 acc_[ i ] *= P32_1;
0183 }
0184 }
0185
0186 BOOST_CXX14_CONSTEXPR void last_round()
0187 {
0188 unsigned char last_stripe[ 64 ] = {};
0189 unsigned char* last_stripe_ptr = nullptr;
0190
0191 if( m_ >= 64 )
0192 {
0193 std::size_t num_stripes = ( m_ == 0 ? 0 : ( m_ - 1 ) / 64 );
0194 for( std::size_t n = 0; n < num_stripes; ++n )
0195 {
0196 std::uint64_t stripe[ 8 ] = {};
0197 for( int i = 0; i < 8; ++i )
0198 {
0199 stripe[ i ] = detail::read64le( buffer_ + ( 64 * n ) + ( 8 * i ) );
0200 }
0201 accumulate( stripe, 8 * num_stripes_++ );
0202
0203 std::size_t const stripes_per_block_ = ( secret_len_ - 64 ) / 8;
0204 (void)stripes_per_block_;
0205
0206 BOOST_ASSERT( num_stripes_ <= stripes_per_block_ );
0207 }
0208
0209 last_stripe_ptr = buffer_ + m_ - 64;
0210 }
0211 else
0212 {
0213 std::size_t len = 64 - m_;
0214
0215 detail::memcpy( last_stripe, buffer_ + buffer_size - len, len );
0216 detail::memcpy( last_stripe + len, buffer_, m_ );
0217
0218 last_stripe_ptr = last_stripe;
0219 }
0220
0221 std::uint64_t stripe[ 8 ] = {};
0222 for( int i = 0; i < 8; ++i )
0223 {
0224 stripe[ i ] = detail::read64le( last_stripe_ptr + ( 8 * i ) );
0225 }
0226
0227 accumulate( stripe, secret_len_ - 71 );
0228 }
0229
0230 BOOST_CXX14_CONSTEXPR std::uint64_t final_merge( std::uint64_t init_value, std::size_t secret_offset )
0231 {
0232 std::uint64_t secret_words[ 8 ] = {};
0233 for( int i = 0; i < 8; ++i )
0234 {
0235 secret_words[ i ] = detail::read64le( secret_ + secret_offset + 8 * i );
0236 }
0237
0238 std::uint64_t result = init_value;
0239 for( int i = 0; i < 4; ++i )
0240 {
0241 auto mul_result = detail::mul128( acc_[ 2 * i ] ^ secret_words[ 2 * i ], acc_[ 2 * i + 1 ] ^ secret_words[ 2 * i + 1 ] );
0242 result += mul_result.low ^ mul_result.high;
0243 }
0244
0245 return avalanche( result );
0246 }
0247
0248 BOOST_CXX14_CONSTEXPR digest<16> xxh3_128_digest_empty()
0249 {
0250 auto const secret = with_secret_? secret_: xxh3_128_constants<>::default_secret;
0251
0252 std::uint64_t secret_words[ 4 ] = {};
0253 for( int i = 0; i < 4; ++i )
0254 {
0255 secret_words[ i ] = detail::read64le( secret + 64 + 8 * i );
0256 }
0257
0258 digest<16> r;
0259 detail::write64be( r.data() + 8, avalanche_xxh64( seed_ ^ secret_words[ 0 ] ^ secret_words[ 1 ] ) );
0260 detail::write64be( r.data() + 0, avalanche_xxh64( seed_ ^ secret_words[ 2 ] ^ secret_words[ 3 ] ) );
0261 return r;
0262 }
0263
0264 BOOST_CXX14_CONSTEXPR digest<16> xxh3_128_digest_1to3()
0265 {
0266 auto const secret = with_secret_? secret_: xxh3_128_constants<>::default_secret;
0267
0268 std::uint32_t v1 = buffer_[ ( n_ - 1 ) ];
0269 std::uint32_t v2 = static_cast<std::uint32_t>( n_ << 8 );
0270 std::uint32_t v3 = buffer_[ 0 ] << 16;
0271 std::uint32_t v4 = buffer_[ ( n_ >> 1 ) ] << 24;
0272
0273 std::uint32_t combined = v1 | v2 | v3 | v4;
0274
0275 std::uint32_t secret_words[ 4 ] = {};
0276 for( int i = 0; i < 4; ++i )
0277 {
0278 secret_words[ i ] = detail::read32le( secret + 4 * i );
0279 }
0280
0281 std::uint64_t low = ( ( secret_words[ 0 ] ^ secret_words[ 1 ] ) + seed_ ) ^ combined;
0282 std::uint64_t high = ( ( secret_words[ 2 ] ^ secret_words[ 3 ] ) - seed_ ) ^ ( detail::rotl( detail::byteswap( combined ), 13 ) );
0283
0284 digest<16> r;
0285 detail::write64be( r.data() + 8, avalanche_xxh64( low ) );
0286 detail::write64be( r.data() + 0, avalanche_xxh64( high ) );
0287
0288 return r;
0289 }
0290
0291 BOOST_CXX14_CONSTEXPR digest<16> xxh3_128_digest_4to8()
0292 {
0293 auto const secret = with_secret_? secret_: xxh3_128_constants<>::default_secret;
0294
0295 std::uint32_t input_first = detail::read32le( buffer_ );
0296 std::uint32_t input_last = detail::read32le( buffer_ + ( n_ - 4 ) );
0297 std::uint64_t modified_seed = seed_ ^ ( std::uint64_t{ detail::byteswap( static_cast<std::uint32_t>( seed_ ) ) } << 32 );
0298
0299 std::uint64_t secret_words[ 2 ] = {};
0300 for( int i = 0; i < 2; ++i )
0301 {
0302 secret_words[ i ] = detail::read64le( secret + 16 + i * 8 );
0303 }
0304
0305 std::uint64_t combined = std::uint64_t{ input_first } | ( std::uint64_t{ input_last } << 32 );
0306 std::uint64_t value = ( ( secret_words[ 0 ] ^ secret_words[ 1 ] ) + modified_seed ) ^ combined;
0307
0308 detail::uint128 mul_result = detail::mul128( value, P64_1 + ( n_ << 2 ) );
0309 std::uint64_t high = mul_result.high;
0310 std::uint64_t low = mul_result.low;
0311
0312 high += ( low << 1 );
0313 low ^= ( high >> 3 );
0314 low ^= ( low >> 35 );
0315 low *= PRIME_MX2;
0316 low ^= ( low >> 28 );
0317
0318 high = avalanche( high );
0319
0320 digest<16> r;
0321 detail::write64be( r.data() + 0, high );
0322 detail::write64be( r.data() + 8, low );
0323
0324 return r;
0325 }
0326
0327 BOOST_CXX14_CONSTEXPR digest<16> xxh3_128_digest_9to16()
0328 {
0329 auto const secret = with_secret_? secret_: xxh3_128_constants<>::default_secret;
0330
0331 std::uint64_t input_first = detail::read64le( buffer_ );
0332 std::uint64_t input_last = detail::read64le( buffer_ + ( n_ - 8 ) );
0333
0334 std::uint64_t secret_words[ 4 ] = {};
0335 for( int i = 0; i < 4; ++i )
0336 {
0337 secret_words[ i ] = detail::read64le( secret + 32 + ( i * 8 ) );
0338 }
0339
0340 std::uint64_t val1 = ( ( secret_words[ 0 ] ^ secret_words[ 1 ] ) - seed_ ) ^ input_first ^ input_last;
0341 std::uint64_t val2 = ( ( secret_words[ 2 ] ^ secret_words[ 3 ] ) + seed_ ) ^ input_last;
0342
0343 detail::uint128 mul_result = detail::mul128( val1, P64_1 );
0344 std::uint64_t low = mul_result.low + ( std::uint64_t{ n_ - 1 } << 54 );
0345 std::uint64_t high = mul_result.high + val2 + ( val2 & 0x00000000ffffffff ) * ( P32_2 - 1 );
0346
0347 low ^= detail::byteswap( high );
0348
0349 detail::uint128 mul_result2 = detail::mul128( low, P64_2 );
0350 low = mul_result2.low;
0351 high = mul_result2.high + high * P64_2;
0352
0353 digest<16> r;
0354 detail::write64be( r.data() + 0, avalanche( high ) );
0355 detail::write64be( r.data() + 8, avalanche( low ) );
0356
0357 return r;
0358 }
0359
0360 BOOST_CXX14_CONSTEXPR digest<16> xxh3_128_digest_17to128()
0361 {
0362 std::uint64_t acc[ 2 ] = { n_ * P64_1, 0 };
0363
0364 std::uint64_t num_rounds = ( ( n_ - 1 ) >> 5 ) + 1;
0365 for( std::int64_t i = num_rounds - 1; i >= 0; --i )
0366 {
0367 std::size_t offset_start = static_cast<std::size_t>( 16 * i );
0368 std::size_t offset_end = n_ - static_cast<std::size_t>( 16 * i ) - 16;
0369
0370 mix_two_chunks( buffer_ + offset_start, buffer_ + offset_end, static_cast<std::size_t>( 32 * i ), seed_, acc );
0371 }
0372
0373 std::uint64_t low = acc[ 0 ] + acc[ 1 ];
0374 std::uint64_t high = ( acc[ 0 ] * P64_1 ) + ( acc[ 1 ] * P64_4 ) + ( ( std::uint64_t{ n_ } - seed_ ) * P64_2 );
0375
0376 digest<16> r;
0377 detail::write64be( r.data() + 0, std::uint64_t{ 0 } - avalanche( high ) );
0378 detail::write64be( r.data() + 8, avalanche( low ) );
0379
0380 return r;
0381 }
0382
0383 BOOST_CXX14_CONSTEXPR digest<16> xxh3_128_digest_129to240()
0384 {
0385 std::uint64_t acc[ 2 ] = { n_ * P64_1, 0 };
0386
0387 std::uint64_t num_chunks = n_ >> 5;
0388
0389 for( std::size_t i = 0; i < 4; ++i )
0390 {
0391 mix_two_chunks( buffer_ + 32 * i, buffer_ + ( 32 * i ) + 16, 32 * i, seed_, acc );
0392 }
0393
0394 acc[ 0 ] = avalanche( acc[ 0 ] );
0395 acc[ 1 ] = avalanche( acc[ 1 ] );
0396
0397 for( std::size_t i = 4; i < num_chunks; ++i )
0398 {
0399 mix_two_chunks( buffer_ + 32 * i, buffer_ + ( 32 * i ) + 16, ( i - 4 ) * 32 + 3, seed_, acc );
0400 }
0401
0402 mix_two_chunks( buffer_ + n_ - 16, buffer_ + n_ - 32, 103, std::uint64_t{ 0 } - seed_, acc );
0403
0404 std::uint64_t low = acc[ 0 ] + acc[ 1 ];
0405 std::uint64_t high = ( acc[ 0 ] * P64_1 ) + ( acc[ 1 ] * P64_4 ) + ( ( std::uint64_t{ n_ } - seed_ ) * P64_2 );
0406
0407 digest<16> r;
0408 detail::write64be( r.data() + 0, std::uint64_t{ 0 } - avalanche( high ) );
0409 detail::write64be( r.data() + 8, avalanche( low ) );
0410
0411 return r;
0412 }
0413
0414 BOOST_CXX14_CONSTEXPR digest<16> xxh3_128_digest_long()
0415 {
0416 last_round();
0417
0418 std::uint64_t low = final_merge( n_ * P64_1, 11 );
0419 std::uint64_t high = final_merge( ~( n_ * P64_2 ), secret_len_ - 75 );
0420
0421 digest<16> r;
0422 detail::write64be( r.data() + 0, high );
0423 detail::write64be( r.data() + 8, low );
0424
0425 return r;
0426 }
0427
0428 BOOST_CXX14_CONSTEXPR static std::uint64_t combine( std::uint64_t v1, std::uint64_t v2 )
0429 {
0430 return avalanche( v1 + v2 );
0431 }
0432
0433 private:
0434
0435 unsigned char secret_[ default_secret_len ] = {};
0436 std::uint64_t seed_ = 0;
0437 bool with_secret_ = false;
0438
0439 unsigned char buffer_[ buffer_size ] = {};
0440
0441 std::uint64_t acc_[ 8 ] = { P32_3, P64_1, P64_2, P64_3, P64_4, P32_2, P64_5, P32_1 };
0442
0443 std::size_t n_ = 0;
0444 std::size_t m_ = 0;
0445
0446 std::size_t secret_len_ = default_secret_len;
0447
0448 std::size_t num_stripes_ = 0;
0449
0450 public:
0451
0452 using result_type = digest<16>;
0453
0454 BOOST_CXX14_CONSTEXPR xxh3_128()
0455 {
0456 detail::memcpy( secret_, xxh3_128_constants<>::default_secret, default_secret_len );
0457 }
0458
0459 BOOST_CXX14_CONSTEXPR explicit xxh3_128( std::uint64_t seed ): seed_( seed )
0460 {
0461 init_secret_from_seed( seed );
0462 }
0463
0464 xxh3_128( void const* p, std::size_t n ): xxh3_128( static_cast<unsigned char const*>( p ), n )
0465 {
0466 }
0467
0468 BOOST_CXX14_CONSTEXPR xxh3_128( unsigned char const* p, std::size_t n )
0469 {
0470 detail::memcpy( secret_, xxh3_128_constants<>::default_secret, default_secret_len );
0471
0472 if( n == 0 ) return;
0473
0474 with_secret_ = true;
0475
0476 std::size_t const n2 = n;
0477 std::uint64_t seed = 0;
0478
0479 while( n >= default_secret_len )
0480 {
0481 for( std::size_t i = 0; i < default_secret_len / 8; ++i )
0482 {
0483 std::uint64_t v1 = detail::read64le( p + i * 8 );
0484 std::uint64_t v2 = detail::read64le( secret_ + i * 8 );
0485
0486 detail::write64le( secret_ + i * 8, combine( v1, v2 ) );
0487
0488 seed = combine( seed, v1 );
0489 }
0490
0491 p += default_secret_len;
0492 n -= default_secret_len;
0493 }
0494
0495 {
0496 std::size_t i = 0;
0497
0498 for( ; i < n / 8; ++i )
0499 {
0500 std::uint64_t v1 = detail::read64le( p + i * 8 );
0501 std::uint64_t v2 = detail::read64le( secret_ + i * 8 );
0502
0503 detail::write64le( secret_ + i * 8, combine( v1, v2 ) );
0504
0505 seed = combine( seed, v1 );
0506 }
0507
0508 n = n % 8;
0509
0510 if( n > 0 )
0511 {
0512 unsigned char w[ 8 ] = {};
0513 detail::memcpy( w, p + i * 8, n );
0514
0515 std::uint64_t v1 = detail::read64le( w );
0516 std::uint64_t v2 = detail::read64le( secret_ + i * 8 );
0517
0518 detail::write64le( secret_ + i * 8, combine( v1, v2 ) );
0519
0520 seed = combine( seed, v1 );
0521 }
0522 }
0523
0524 {
0525 std::size_t const i = 0;
0526
0527 std::uint64_t v1 = n2;
0528 std::uint64_t v2 = detail::read64le( secret_ + i * 8 );
0529
0530 detail::write64le( secret_ + i * 8, combine( v1, v2 ) );
0531
0532 seed = combine( seed, v1 );
0533 }
0534
0535 seed_ = seed;
0536 }
0537
0538 private:
0539
0540 BOOST_CXX14_CONSTEXPR xxh3_128( std::uint64_t seed, unsigned char const* p, std::size_t n, bool with_secret ): seed_( seed ), with_secret_( with_secret )
0541 {
0542 if( n < min_secret_len )
0543 {
0544
0545 detail::memcpy( secret_, xxh3_128_constants<>::default_secret, default_secret_len );
0546 secret_len_ = default_secret_len;
0547 }
0548 else if( n < default_secret_len )
0549 {
0550 secret_len_ = n;
0551 }
0552 else
0553 {
0554 secret_len_ = default_secret_len;
0555 }
0556
0557
0558
0559
0560
0561 while( n >= default_secret_len )
0562 {
0563 for( std::size_t i = 0; i < default_secret_len / 8; ++i )
0564 {
0565 std::uint64_t v1 = detail::read64le( p + i * 8 );
0566 std::uint64_t v2 = detail::read64le( secret_ + i * 8 );
0567
0568 detail::write64le( secret_ + i * 8, v1 + v2 );
0569 }
0570
0571 p += default_secret_len;
0572 n -= default_secret_len;
0573 }
0574
0575 {
0576 std::size_t i = 0;
0577
0578 for( ; i < n / 8; ++i )
0579 {
0580 std::uint64_t v1 = detail::read64le( p + i * 8 );
0581 std::uint64_t v2 = detail::read64le( secret_ + i * 8 );
0582
0583 detail::write64le( secret_ + i * 8, v1 + v2 );
0584 }
0585
0586 n = n % 8;
0587
0588 if( n > 0 )
0589 {
0590 unsigned char w[ 8 ] = {};
0591 detail::memcpy( w, p + i * 8, n );
0592
0593 std::uint64_t v1 = detail::read64le( w );
0594 std::uint64_t v2 = detail::read64le( secret_ + i * 8 );
0595
0596 detail::write64le( secret_ + i * 8, v1 + v2 );
0597 }
0598 }
0599 }
0600
0601 public:
0602
0603
0604
0605
0606 static BOOST_CXX14_CONSTEXPR xxh3_128 with_seed( std::uint64_t seed )
0607 {
0608 return xxh3_128( seed );
0609 }
0610
0611 static BOOST_CXX14_CONSTEXPR xxh3_128 with_secret( unsigned char const* p, std::size_t n )
0612 {
0613 return xxh3_128( 0, p, n, true );
0614 }
0615
0616 static xxh3_128 with_secret( void const* p, std::size_t n )
0617 {
0618 return with_secret( static_cast<unsigned char const*>( p ), n );
0619 }
0620
0621 static BOOST_CXX14_CONSTEXPR xxh3_128 with_secret_and_seed( unsigned char const* p, std::size_t n, std::uint64_t seed )
0622 {
0623 return xxh3_128( seed, p, n, false );
0624 }
0625
0626 static xxh3_128 with_secret_and_seed( void const* p, std::size_t n, std::uint64_t seed )
0627 {
0628 return with_secret_and_seed( static_cast<unsigned char const*>( p ), n, seed );
0629 }
0630
0631 void update( void const* p, std::size_t n )
0632 {
0633 update( static_cast<unsigned char const*>( p ), n );
0634 }
0635
0636 BOOST_CXX14_CONSTEXPR void update( unsigned char const* p, std::size_t n )
0637 {
0638 if( n == 0 ) return;
0639
0640 std::size_t const stripes_per_block_ = ( secret_len_ - 64 ) / 8;
0641
0642 n_ += n;
0643
0644 if( n <= buffer_size - m_ )
0645 {
0646 detail::memcpy( buffer_ + m_, p, n );
0647 m_ += n;
0648 return;
0649 }
0650
0651 if( m_ > 0 )
0652 {
0653 std::size_t k = buffer_size - m_;
0654 detail::memcpy( buffer_ + m_, p, k );
0655
0656 p += k;
0657 n -= k;
0658
0659 for( std::size_t i = 0; i < 4; ++i )
0660 {
0661 std::uint64_t stripe[ 8 ] = {};
0662 for( int j = 0; j < 8; ++j )
0663 {
0664 stripe[ j ] = detail::read64le( buffer_ + ( 64 * i) + ( 8 * j ) );
0665 }
0666 accumulate( stripe, 8 * num_stripes_ );
0667 ++num_stripes_;
0668
0669 if( num_stripes_ == stripes_per_block_ )
0670 {
0671 scramble();
0672 num_stripes_ = 0;
0673 }
0674 }
0675
0676 m_ = 0;
0677 }
0678
0679 if( n > buffer_size )
0680 {
0681 while( n > 64 )
0682 {
0683 std::uint64_t stripe[ 8 ] = {};
0684 for( int j = 0; j < 8; ++j )
0685 {
0686 stripe[ j ] = detail::read64le( p + ( 8 * j ) );
0687 }
0688 accumulate( stripe, 8 * num_stripes_ );
0689 ++num_stripes_;
0690
0691 if( num_stripes_ == stripes_per_block_ )
0692 {
0693 scramble();
0694 num_stripes_ = 0;
0695 }
0696
0697 p += 64;
0698 n -= 64;
0699 }
0700
0701 detail::memcpy( buffer_ + buffer_size - 64, p - 64, 64 );
0702
0703 BOOST_ASSERT( n <= 64 );
0704 }
0705
0706 if( n > 0 )
0707 {
0708 detail::memcpy( buffer_, p, n );
0709 m_ = n;
0710 }
0711 }
0712
0713 BOOST_CXX14_CONSTEXPR result_type result()
0714 {
0715 result_type r;
0716
0717 if( n_ == 0 )
0718 {
0719 r = xxh3_128_digest_empty();
0720
0721
0722 seed_ += P64_5;
0723 }
0724 else if( n_ < 4 )
0725 {
0726 r = xxh3_128_digest_1to3();
0727 }
0728 else if( n_ < 9 )
0729 {
0730 r = xxh3_128_digest_4to8();
0731 }
0732 else if( n_ < 17 )
0733 {
0734 r = xxh3_128_digest_9to16();
0735 }
0736 else if( n_ < 129 )
0737 {
0738 r = xxh3_128_digest_17to128();
0739 }
0740 else if( n_ < 241 )
0741 {
0742 r = xxh3_128_digest_129to240();
0743 }
0744 else
0745 {
0746 r = xxh3_128_digest_long();
0747
0748
0749 acc_[ 0 ] -= P64_1;
0750 acc_[ 1 ] += P64_1;
0751 acc_[ 2 ] -= P64_2;
0752 acc_[ 3 ] += P64_2;
0753 acc_[ 4 ] -= P64_3;
0754 acc_[ 5 ] += P64_3;
0755 acc_[ 6 ] -= P64_4;
0756 acc_[ 7 ] += P64_4;
0757 }
0758
0759
0760
0761 {
0762 std::uint64_t h1 = detail::read64le( r.data() + 0 );
0763 std::uint64_t h2 = detail::read64le( r.data() + 8 );
0764
0765 std::uint64_t v1 = detail::read64le( buffer_ + 0 );
0766 detail::write64le( buffer_ + 0, v1 + h1 );
0767
0768 std::uint64_t v2 = detail::read64le( buffer_ + 8 );
0769 detail::write64le( buffer_ + 8, v2 + h2 );
0770
0771 detail::memset( buffer_ + 16, 0, buffer_size - 16 );
0772 }
0773
0774 return r;
0775 }
0776 };
0777
0778 }
0779 }
0780
0781 #if defined(BOOST_MSVC) && BOOST_MSVC < 1920
0782 # pragma warning(pop)
0783 #endif
0784
0785 #endif