File indexing completed on 2025-09-17 08:33:43
0001 #ifndef BOOST_HASH2_SPOOKY2_HPP_INCLUDED
0002 #define BOOST_HASH2_SPOOKY2_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 <utility>
0017 #include <cstring>
0018
0019 namespace boost
0020 {
0021 namespace hash2
0022 {
0023
0024 class spooky2_128
0025 {
0026 private:
0027
0028 static const std::uint64_t sc_const = 0xdeadbeefdeadbeefULL;
0029
0030 private:
0031
0032 static const int M = 12;
0033 std::uint64_t v_[ M ];
0034
0035 static const int N = 192;
0036 unsigned char buffer_[ N ];
0037
0038 std::size_t m_;
0039
0040 std::size_t n_;
0041
0042 private:
0043
0044 static inline void short_mix( std::uint64_t & h0, std::uint64_t & h1, std::uint64_t & h2, std::uint64_t & h3 )
0045 {
0046 h2 = detail::rotl( h2, 50 ); h2 += h3; h0 ^= h2;
0047 h3 = detail::rotl( h3, 52 ); h3 += h0; h1 ^= h3;
0048 h0 = detail::rotl( h0, 30 ); h0 += h1; h2 ^= h0;
0049 h1 = detail::rotl( h1, 41 ); h1 += h2; h3 ^= h1;
0050 h2 = detail::rotl( h2, 54 ); h2 += h3; h0 ^= h2;
0051 h3 = detail::rotl( h3, 48 ); h3 += h0; h1 ^= h3;
0052 h0 = detail::rotl( h0, 38 ); h0 += h1; h2 ^= h0;
0053 h1 = detail::rotl( h1, 37 ); h1 += h2; h3 ^= h1;
0054 h2 = detail::rotl( h2, 62 ); h2 += h3; h0 ^= h2;
0055 h3 = detail::rotl( h3, 34 ); h3 += h0; h1 ^= h3;
0056 h0 = detail::rotl( h0, 5 ); h0 += h1; h2 ^= h0;
0057 h1 = detail::rotl( h1, 36 ); h1 += h2; h3 ^= h1;
0058 }
0059
0060 static inline void short_end( std::uint64_t & h0, std::uint64_t & h1, std::uint64_t & h2, std::uint64_t & h3 )
0061 {
0062 h3 ^= h2; h2 = detail::rotl( h2, 15 ); h3 += h2;
0063 h0 ^= h3; h3 = detail::rotl( h3, 52 ); h0 += h3;
0064 h1 ^= h0; h0 = detail::rotl( h0, 26 ); h1 += h0;
0065 h2 ^= h1; h1 = detail::rotl( h1, 51 ); h2 += h1;
0066 h3 ^= h2; h2 = detail::rotl( h2, 28 ); h3 += h2;
0067 h0 ^= h3; h3 = detail::rotl( h3, 9 ); h0 += h3;
0068 h1 ^= h0; h0 = detail::rotl( h0, 47 ); h1 += h0;
0069 h2 ^= h1; h1 = detail::rotl( h1, 54 ); h2 += h1;
0070 h3 ^= h2; h2 = detail::rotl( h2, 32 ); h3 += h2;
0071 h0 ^= h3; h3 = detail::rotl( h3, 25 ); h0 += h3;
0072 h1 ^= h0; h0 = detail::rotl( h0, 63 ); h1 += h0;
0073 }
0074
0075 static void short_hash( unsigned char const * p, std::size_t n, std::uint64_t & hash1, std::uint64_t & hash2 )
0076 {
0077 std::uint64_t a = hash1;
0078 std::uint64_t b = hash2;
0079 std::uint64_t c = sc_const;
0080 std::uint64_t d = sc_const;
0081
0082 std::size_t m = n;
0083
0084 while( m >= 32 )
0085 {
0086 c += detail::read64le( p + 0 );
0087 d += detail::read64le( p + 8 );
0088
0089 short_mix( a, b, c, d );
0090
0091 a += detail::read64le( p + 16 );
0092 b += detail::read64le( p + 24 );
0093
0094 p += 32;
0095 m -= 32;
0096 }
0097
0098 if( m >= 16 )
0099 {
0100 c += detail::read64le( p + 0 );
0101 d += detail::read64le( p + 8 );
0102
0103 short_mix( a, b, c, d );
0104
0105 p += 16;
0106 m -= 16;
0107 }
0108
0109 if( m == 0 )
0110 {
0111 c += sc_const;
0112 d += sc_const;
0113 }
0114 else
0115 {
0116 BOOST_ASSERT( m < 16 );
0117
0118 unsigned char tmp[ 16 ] = { 0 };
0119 std::memcpy( tmp, p, m );
0120
0121 c += detail::read64le( tmp + 0 );
0122 d += detail::read64le( tmp + 8 );
0123 }
0124
0125 d += static_cast<std::uint64_t>( n ) << 56;
0126
0127 short_end( a, b, c, d );
0128
0129 hash1 = a;
0130 hash2 = b;
0131 }
0132
0133 private:
0134
0135 static inline void mix( unsigned char const * p,
0136 std::uint64_t & s0, std::uint64_t & s1, std::uint64_t & s2, std::uint64_t & s3,
0137 std::uint64_t & s4, std::uint64_t & s5, std::uint64_t & s6, std::uint64_t & s7,
0138 std::uint64_t & s8, std::uint64_t & s9, std::uint64_t & s10, std::uint64_t & s11 )
0139 {
0140 s0 += detail::read64le( p + 0 ); s2 ^= s10; s11 ^= s0; s0 = detail::rotl( s0, 11 ); s11 += s1;
0141 s1 += detail::read64le( p + 8 ); s3 ^= s11; s0 ^= s1; s1 = detail::rotl( s1, 32 ); s0 += s2;
0142 s2 += detail::read64le( p + 16 ); s4 ^= s0; s1 ^= s2; s2 = detail::rotl( s2, 43 ); s1 += s3;
0143 s3 += detail::read64le( p + 24 ); s5 ^= s1; s2 ^= s3; s3 = detail::rotl( s3, 31 ); s2 += s4;
0144 s4 += detail::read64le( p + 32 ); s6 ^= s2; s3 ^= s4; s4 = detail::rotl( s4, 17 ); s3 += s5;
0145 s5 += detail::read64le( p + 40 ); s7 ^= s3; s4 ^= s5; s5 = detail::rotl( s5, 28 ); s4 += s6;
0146 s6 += detail::read64le( p + 48 ); s8 ^= s4; s5 ^= s6; s6 = detail::rotl( s6, 39 ); s5 += s7;
0147 s7 += detail::read64le( p + 56 ); s9 ^= s5; s6 ^= s7; s7 = detail::rotl( s7, 57 ); s6 += s8;
0148 s8 += detail::read64le( p + 64 ); s10 ^= s6; s7 ^= s8; s8 = detail::rotl( s8, 55 ); s7 += s9;
0149 s9 += detail::read64le( p + 72 ); s11 ^= s7; s8 ^= s9; s9 = detail::rotl( s9, 54 ); s8 += s10;
0150 s10 += detail::read64le( p + 80 ); s0 ^= s8; s9 ^= s10; s10 = detail::rotl( s10, 22 ); s9 += s11;
0151 s11 += detail::read64le( p + 88 ); s1 ^= s9; s10 ^= s11; s11 = detail::rotl( s11, 46 ); s10 += s0;
0152 }
0153
0154 void update_( unsigned char const * p, std::size_t k )
0155 {
0156 std::uint64_t h0 = v_[ 0];
0157 std::uint64_t h1 = v_[ 1];
0158 std::uint64_t h2 = v_[ 2];
0159 std::uint64_t h3 = v_[ 3];
0160 std::uint64_t h4 = v_[ 4];
0161 std::uint64_t h5 = v_[ 5];
0162 std::uint64_t h6 = v_[ 6];
0163 std::uint64_t h7 = v_[ 7];
0164 std::uint64_t h8 = v_[ 8];
0165 std::uint64_t h9 = v_[ 9];
0166 std::uint64_t h10 = v_[10];
0167 std::uint64_t h11 = v_[11];
0168
0169 for( std::size_t i = 0; i < k; ++i, p += 96 )
0170 {
0171 mix( p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
0172 }
0173
0174 v_[ 0] = h0;
0175 v_[ 1] = h1;
0176 v_[ 2] = h2;
0177 v_[ 3] = h3;
0178 v_[ 4] = h4;
0179 v_[ 5] = h5;
0180 v_[ 6] = h6;
0181 v_[ 7] = h7;
0182 v_[ 8] = h8;
0183 v_[ 9] = h9;
0184 v_[10] = h10;
0185 v_[11] = h11;
0186 }
0187
0188 static inline void end_partial(
0189 std::uint64_t & h0, std::uint64_t & h1, std::uint64_t & h2, std::uint64_t & h3,
0190 std::uint64_t & h4, std::uint64_t & h5, std::uint64_t & h6, std::uint64_t & h7,
0191 std::uint64_t & h8, std::uint64_t & h9, std::uint64_t & h10, std::uint64_t & h11 )
0192 {
0193 h11 += h1; h2 ^= h11; h1 = detail::rotl( h1, 44 );
0194 h0 += h2; h3 ^= h0; h2 = detail::rotl( h2, 15 );
0195 h1 += h3; h4 ^= h1; h3 = detail::rotl( h3, 34 );
0196 h2 += h4; h5 ^= h2; h4 = detail::rotl( h4, 21);
0197 h3 += h5; h6 ^= h3; h5 = detail::rotl( h5, 38);
0198 h4 += h6; h7 ^= h4; h6 = detail::rotl( h6, 33);
0199 h5 += h7; h8 ^= h5; h7 = detail::rotl( h7, 10);
0200 h6 += h8; h9 ^= h6; h8 = detail::rotl( h8, 13);
0201 h7 += h9; h10 ^= h7; h9 = detail::rotl( h9, 38);
0202 h8 += h10; h11 ^= h8; h10 = detail::rotl( h10, 53);
0203 h9 += h11; h0 ^= h9; h11 = detail::rotl( h11, 42);
0204 h10 += h0; h1 ^= h10; h0 = detail::rotl( h0, 54);
0205 }
0206
0207 static inline void end( unsigned char const * p,
0208 std::uint64_t & h0, std::uint64_t & h1, std::uint64_t & h2, std::uint64_t & h3,
0209 std::uint64_t & h4, std::uint64_t & h5, std::uint64_t & h6, std::uint64_t & h7,
0210 std::uint64_t & h8, std::uint64_t & h9, std::uint64_t & h10, std::uint64_t & h11 )
0211 {
0212 h0 += detail::read64le( p + 0 );
0213 h1 += detail::read64le( p + 8 );
0214 h2 += detail::read64le( p + 16 );
0215 h3 += detail::read64le( p + 24 );
0216 h4 += detail::read64le( p + 32 );
0217 h5 += detail::read64le( p + 40 );
0218 h6 += detail::read64le( p + 48 );
0219 h7 += detail::read64le( p + 56 );
0220 h8 += detail::read64le( p + 64 );
0221 h9 += detail::read64le( p + 72 );
0222 h10 += detail::read64le( p + 80 );
0223 h11 += detail::read64le( p + 88 );
0224
0225 end_partial( h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
0226 end_partial( h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
0227 end_partial( h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
0228 }
0229
0230 void init( std::uint64_t seed1, std::uint64_t seed2 )
0231 {
0232 v_[ 0 ] = v_[ 3 ] = v_[ 6 ] = v_[ 9 ] = seed1;
0233 v_[ 1 ] = v_[ 4 ] = v_[ 7 ] = v_[ 10 ] = seed2;
0234 v_[ 2 ] = v_[ 5 ] = v_[ 8 ] = v_[ 11 ] = sc_const;
0235 }
0236
0237 public:
0238
0239 typedef std::array<unsigned char, 16> result_type;
0240 typedef std::uint64_t size_type;
0241
0242 explicit spooky2_128( std::uint64_t seed1 = 0, std::uint64_t seed2 = 0 ): m_( 0 ), n_( 0 )
0243 {
0244 init( seed1, seed2 );
0245 }
0246
0247 spooky2_128( unsigned char const * p, std::size_t n ): m_( 0 ), n_( 0 )
0248 {
0249 if( n == 0 )
0250 {
0251 init( 0, 0 );
0252 }
0253 else if( n <= 16 )
0254 {
0255 unsigned char q[ 18 ] = {};
0256 std::memcpy( q, p, n );
0257
0258 std::uint64_t seed1 = detail::read64le( q + 0 );
0259 std::uint64_t seed2 = detail::read64le( q + 8 );
0260
0261 init( seed1, seed2 );
0262 }
0263 else
0264 {
0265 std::uint64_t seed1 = detail::read64le( p + 0 );
0266 std::uint64_t seed2 = detail::read64le( p + 8 );
0267
0268 init( seed1, seed2 );
0269
0270 p += 16;
0271 n -= 16;
0272
0273 update( p, n );
0274 result();
0275 }
0276 }
0277
0278 void update( void const * pv, std::size_t n )
0279 {
0280 unsigned char const* p = static_cast<unsigned char const*>( pv );
0281
0282 BOOST_ASSERT( m_ == n_ % N );
0283
0284 if( n == 0 ) return;
0285
0286 n_ += n;
0287
0288 if( m_ > 0 )
0289 {
0290 std::size_t k = N - m_;
0291
0292 if( n < k )
0293 {
0294 k = n;
0295 }
0296
0297 std::memcpy( buffer_ + m_, p, k );
0298
0299 p += k;
0300 n -= k;
0301 m_ += k;
0302
0303 if( m_ < N ) return;
0304
0305 BOOST_ASSERT( m_ == N );
0306
0307 update_( buffer_, 2 );
0308 m_ = 0;
0309 }
0310
0311 BOOST_ASSERT( m_ == 0 );
0312
0313 {
0314 std::size_t k = n / N;
0315
0316 update_( p, k * 2 );
0317
0318 p += k * N;
0319 n -= k * N;
0320 }
0321
0322 BOOST_ASSERT( n < N );
0323
0324 if( n > 0 )
0325 {
0326 std::memcpy( buffer_, p, n );
0327 m_ = n;
0328 }
0329
0330 BOOST_ASSERT( m_ == n_ % N );
0331 }
0332
0333 result_type result()
0334 {
0335 BOOST_ASSERT( m_ == n_ % N );
0336
0337 std::uint64_t h0 = v_[ 0 ];
0338 std::uint64_t h1 = v_[ 1 ];
0339
0340 if( n_ < N )
0341 {
0342 short_hash( buffer_, n_, h0, h1 );
0343 }
0344 else
0345 {
0346 std::uint64_t h2 = v_[ 2 ];
0347 std::uint64_t h3 = v_[ 3 ];
0348 std::uint64_t h4 = v_[ 4 ];
0349 std::uint64_t h5 = v_[ 5 ];
0350 std::uint64_t h6 = v_[ 6 ];
0351 std::uint64_t h7 = v_[ 7 ];
0352 std::uint64_t h8 = v_[ 8 ];
0353 std::uint64_t h9 = v_[ 9 ];
0354 std::uint64_t h10 = v_[ 10 ];
0355 std::uint64_t h11 = v_[ 11 ];
0356
0357 unsigned char * p = buffer_;
0358 std::size_t m = m_;
0359
0360 if( m >= 96 )
0361 {
0362 mix( p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
0363
0364 p += 96;
0365 m -= 96;
0366 }
0367
0368 std::memset( p + m, 0, 96 - m );
0369 p[ 95 ] = static_cast<unsigned char>( m & 0xFF );
0370
0371 end( p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
0372
0373 v_[ 2 ] = h2;
0374 v_[ 3 ] = h3;
0375 v_[ 4 ] = h4;
0376 v_[ 5 ] = h5;
0377 v_[ 6 ] = h6;
0378 v_[ 7 ] = h7;
0379 v_[ 8 ] = h8;
0380 v_[ 9 ] = h9;
0381 v_[ 10 ] = h10;
0382 v_[ 11 ] = h11;
0383 }
0384
0385 v_[ 0 ] = h0;
0386 v_[ 1 ] = h1;
0387
0388 n_ += N - m_;
0389 m_ = 0;
0390
0391 if( n_ < N )
0392 {
0393 n_ = 0;
0394 }
0395
0396
0397 std::memset( buffer_, 0, N );
0398
0399 result_type r;
0400
0401 detail::write64le( &r[ 0 ], h0 );
0402 detail::write64le( &r[ 8 ], h1 );
0403
0404 return r;
0405 }
0406 };
0407
0408 }
0409 }
0410
0411 #endif