Back to home page

EIC code displayed by LXR

 
 

    


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 // Copyright 2025 Christian Mazakas.
0005 // Distributed under the Boost Software License, Version 1.0.
0006 // https://www.boost.org/LICENSE_1_0.txt
0007 //
0008 // xxHash, https://cyan4973.github.io/xxHash/
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) // '+': integral constant overflow
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 // copy-paste from Boost.Unordered's prime_fmod approach
0057 #if defined(BOOST_NO_CXX17_INLINE_VARIABLES)
0058 
0059 // https://en.cppreference.com/w/cpp/language/static#Constant_static_members
0060 // If a const non-inline (since C++17) static data member or a constexpr
0061 // static data member (since C++11)(until C++17) is odr-used, a definition
0062 // at namespace scope is still required, but it cannot have an
0063 // initializer.
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; // current number of processed stripes
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: // supporting constructor for the static factory functions
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             // this is a precondition violation for XXH3, but we try to do something reasonable
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         // incorporate passed secret into secret_
0558         // in the case where min_secret_len <= n <= default_secret_len,
0559         //  this is a simple copy because the initial secret_ is {}
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     // XXH3-specific named constructors, matching the reference implementation
0604 
0605     // for completeness only
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             // perturb state to enable result extension
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             // perturb state to enable result extension
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         // finalize buffer to clear plainext and enable result extension
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 } // namespace hash2
0779 } // namespace boost
0780 
0781 #if defined(BOOST_MSVC) && BOOST_MSVC < 1920
0782 # pragma warning(pop)
0783 #endif
0784 
0785 #endif // #ifndef BOOST_HASH2_XXH3_HPP_INCLUDED