xxhash.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. #ifndef BOOST_HASH2_XXHASH_HPP_INCLUDED
  2. #define BOOST_HASH2_XXHASH_HPP_INCLUDED
  3. // Copyright 2017, 2018 Peter Dimov.
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // https://www.boost.org/LICENSE_1_0.txt
  6. //
  7. // xxHash, https://cyan4973.github.io/xxHash/
  8. #include <boost/hash2/detail/read.hpp>
  9. #include <boost/hash2/detail/rot.hpp>
  10. #include <boost/hash2/detail/memset.hpp>
  11. #include <boost/hash2/detail/memcpy.hpp>
  12. #include <boost/assert.hpp>
  13. #include <boost/config.hpp>
  14. #include <cstdint>
  15. #include <cstring>
  16. #include <cstddef>
  17. #if defined(BOOST_MSVC) && BOOST_MSVC < 1920
  18. # pragma warning(push)
  19. # pragma warning(disable: 4307) // '+': integral constant overflow
  20. #endif
  21. namespace boost
  22. {
  23. namespace hash2
  24. {
  25. class xxhash_32
  26. {
  27. private:
  28. static constexpr std::uint32_t P1 = 2654435761U;
  29. static constexpr std::uint32_t P2 = 2246822519U;
  30. static constexpr std::uint32_t P3 = 3266489917U;
  31. static constexpr std::uint32_t P4 = 668265263U;
  32. static constexpr std::uint32_t P5 = 374761393U;
  33. private:
  34. std::uint32_t v1_ = P1 + P2;
  35. std::uint32_t v2_ = P2;
  36. std::uint32_t v3_ = 0;
  37. std::uint32_t v4_ = static_cast<std::uint32_t>( 0 ) - P1;
  38. unsigned char buffer_[ 16 ] = {};
  39. std::size_t m_ = 0; // == n_ % 16
  40. std::size_t n_ = 0;
  41. private:
  42. BOOST_CXX14_CONSTEXPR void init( std::uint32_t seed )
  43. {
  44. v1_ = seed + P1 + P2;
  45. v2_ = seed + P2;
  46. v3_ = seed;
  47. v4_ = seed - P1;
  48. }
  49. BOOST_CXX14_CONSTEXPR static std::uint32_t round( std::uint32_t seed, std::uint32_t input )
  50. {
  51. seed += input * P2;
  52. seed = detail::rotl( seed, 13 );
  53. seed *= P1;
  54. return seed;
  55. }
  56. BOOST_CXX14_CONSTEXPR void update_( unsigned char const * p, std::size_t k )
  57. {
  58. std::uint32_t v1 = v1_;
  59. std::uint32_t v2 = v2_;
  60. std::uint32_t v3 = v3_;
  61. std::uint32_t v4 = v4_;
  62. for( std::size_t i = 0; i < k; ++i, p += 16 )
  63. {
  64. v1 = round( v1, detail::read32le( p + 0 ) );
  65. v2 = round( v2, detail::read32le( p + 4 ) );
  66. v3 = round( v3, detail::read32le( p + 8 ) );
  67. v4 = round( v4, detail::read32le( p + 12 ) );
  68. }
  69. v1_ = v1;
  70. v2_ = v2;
  71. v3_ = v3;
  72. v4_ = v4;
  73. }
  74. public:
  75. using result_type = std::uint32_t;
  76. xxhash_32() = default;
  77. BOOST_CXX14_CONSTEXPR explicit xxhash_32( std::uint64_t seed )
  78. {
  79. std::uint32_t s0 = static_cast<std::uint32_t>( seed );
  80. std::uint32_t s1 = static_cast<std::uint32_t>( seed >> 32 );
  81. init( s0 );
  82. if( s1 != 0 )
  83. {
  84. v1_ = round( v1_, s1 );
  85. v2_ = round( v2_, s1 );
  86. v3_ = round( v3_, s1 );
  87. v4_ = round( v4_, s1 );
  88. }
  89. }
  90. BOOST_CXX14_CONSTEXPR xxhash_32( unsigned char const * p, std::size_t n )
  91. {
  92. if( n != 0 )
  93. {
  94. update( p, n );
  95. result();
  96. }
  97. }
  98. xxhash_32( void const * p, std::size_t n ): xxhash_32( static_cast<unsigned char const*>( p ), n )
  99. {
  100. }
  101. BOOST_CXX14_CONSTEXPR void update( unsigned char const* p, std::size_t n )
  102. {
  103. BOOST_ASSERT( m_ == n_ % 16 );
  104. if( n == 0 ) return;
  105. n_ += n;
  106. if( m_ > 0 )
  107. {
  108. std::size_t k = 16 - m_;
  109. if( n < k )
  110. {
  111. k = n;
  112. }
  113. detail::memcpy( buffer_ + m_, p, k );
  114. p += k;
  115. n -= k;
  116. m_ += k;
  117. if( m_ < 16 ) return;
  118. BOOST_ASSERT( m_ == 16 );
  119. update_( buffer_, 1 );
  120. m_ = 0;
  121. }
  122. BOOST_ASSERT( m_ == 0 );
  123. {
  124. std::size_t k = n / 16;
  125. update_( p, k );
  126. p += 16 * k;
  127. n -= 16 * k;
  128. }
  129. BOOST_ASSERT( n < 16 );
  130. if( n > 0 )
  131. {
  132. detail::memcpy( buffer_, p, n );
  133. m_ = n;
  134. }
  135. BOOST_ASSERT( m_ == n_ % 16 );
  136. }
  137. void update( void const* pv, std::size_t n )
  138. {
  139. unsigned char const* p = static_cast<unsigned char const*>( pv );
  140. update( p, n );
  141. }
  142. BOOST_CXX14_CONSTEXPR std::uint32_t result()
  143. {
  144. BOOST_ASSERT( m_ == n_ % 16 );
  145. std::uint32_t h = 0;
  146. if( n_ >= 16 )
  147. {
  148. h = detail::rotl( v1_, 1 ) + detail::rotl( v2_, 7 ) + detail::rotl( v3_, 12 ) + detail::rotl( v4_, 18 );
  149. }
  150. else
  151. {
  152. h = v3_ + P5;
  153. }
  154. h += static_cast<std::uint32_t>( n_ );
  155. unsigned char const * p = buffer_;
  156. std::size_t m = m_;
  157. while( m >= 4 )
  158. {
  159. h += detail::read32le( p ) * P3;
  160. h = detail::rotl( h, 17 ) * P4;
  161. p += 4;
  162. m -= 4;
  163. }
  164. while( m > 0 )
  165. {
  166. h += p[0] * P5;
  167. h = detail::rotl( h, 11 ) * P1;
  168. ++p;
  169. --m;
  170. }
  171. n_ += 16 - m_;
  172. m_ = 0;
  173. // clear buffered plaintext
  174. detail::memset( buffer_, 0, 16 );
  175. // perturb state
  176. v1_ += h;
  177. v2_ += h;
  178. v3_ -= h;
  179. v4_ -= h;
  180. // apply final mix
  181. h ^= h >> 15;
  182. h *= P2;
  183. h ^= h >> 13;
  184. h *= P3;
  185. h ^= h >> 16;
  186. return h;
  187. }
  188. };
  189. class xxhash_64
  190. {
  191. private:
  192. static constexpr std::uint64_t P1 = 11400714785074694791ULL;
  193. static constexpr std::uint64_t P2 = 14029467366897019727ULL;
  194. static constexpr std::uint64_t P3 = 1609587929392839161ULL;
  195. static constexpr std::uint64_t P4 = 9650029242287828579ULL;
  196. static constexpr std::uint64_t P5 = 2870177450012600261ULL;
  197. private:
  198. std::uint64_t v1_ = P1 + P2;
  199. std::uint64_t v2_ = P2;
  200. std::uint64_t v3_ = 0;
  201. std::uint64_t v4_ = static_cast<std::uint64_t>( 0 ) - P1;
  202. unsigned char buffer_[ 32 ] = {};
  203. std::size_t m_ = 0; // == n_ % 32
  204. std::uint64_t n_ = 0;
  205. private:
  206. BOOST_CXX14_CONSTEXPR void init( std::uint64_t seed )
  207. {
  208. v1_ = seed + P1 + P2;
  209. v2_ = seed + P2;
  210. v3_ = seed;
  211. v4_ = seed - P1;
  212. }
  213. BOOST_CXX14_CONSTEXPR static std::uint64_t round( std::uint64_t seed, std::uint64_t input )
  214. {
  215. seed += input * P2;
  216. seed = detail::rotl( seed, 31 );
  217. seed *= P1;
  218. return seed;
  219. }
  220. BOOST_CXX14_CONSTEXPR static std::uint64_t merge_round( std::uint64_t acc, std::uint64_t val )
  221. {
  222. val = round( 0, val );
  223. acc ^= val;
  224. acc = acc * P1 + P4;
  225. return acc;
  226. }
  227. BOOST_CXX14_CONSTEXPR void update_( unsigned char const * p, std::size_t k )
  228. {
  229. std::uint64_t v1 = v1_;
  230. std::uint64_t v2 = v2_;
  231. std::uint64_t v3 = v3_;
  232. std::uint64_t v4 = v4_;
  233. for( std::size_t i = 0; i < k; ++i, p += 32 )
  234. {
  235. v1 = round( v1, detail::read64le( p + 0 ) );
  236. v2 = round( v2, detail::read64le( p + 8 ) );
  237. v3 = round( v3, detail::read64le( p + 16 ) );
  238. v4 = round( v4, detail::read64le( p + 24 ) );
  239. }
  240. v1_ = v1;
  241. v2_ = v2;
  242. v3_ = v3;
  243. v4_ = v4;
  244. }
  245. public:
  246. typedef std::uint64_t result_type;
  247. xxhash_64() = default;
  248. BOOST_CXX14_CONSTEXPR explicit xxhash_64( std::uint64_t seed )
  249. {
  250. init( seed );
  251. }
  252. BOOST_CXX14_CONSTEXPR xxhash_64( unsigned char const * p, std::size_t n )
  253. {
  254. if( n != 0 )
  255. {
  256. update( p, n );
  257. result();
  258. }
  259. }
  260. xxhash_64( void const * p, std::size_t n ): xxhash_64( static_cast<unsigned char const*>( p ), n )
  261. {
  262. }
  263. BOOST_CXX14_CONSTEXPR void update( unsigned char const* p, std::size_t n )
  264. {
  265. BOOST_ASSERT( m_ == n_ % 32 );
  266. if( n == 0 ) return;
  267. n_ += n;
  268. if( m_ > 0 )
  269. {
  270. std::size_t k = 32 - m_;
  271. if( n < k )
  272. {
  273. k = n;
  274. }
  275. detail::memcpy( buffer_ + m_, p, k );
  276. p += k;
  277. n -= k;
  278. m_ += k;
  279. if( m_ < 32 ) return;
  280. BOOST_ASSERT( m_ == 32 );
  281. update_( buffer_, 1 );
  282. m_ = 0;
  283. }
  284. BOOST_ASSERT( m_ == 0 );
  285. {
  286. std::size_t k = n / 32;
  287. update_( p, k );
  288. p += 32 * k;
  289. n -= 32 * k;
  290. }
  291. BOOST_ASSERT( n < 32 );
  292. if( n > 0 )
  293. {
  294. detail::memcpy( buffer_, p, n );
  295. m_ = n;
  296. }
  297. BOOST_ASSERT( m_ == n_ % 32 );
  298. }
  299. void update( void const* pv, std::size_t n )
  300. {
  301. unsigned char const* p = static_cast<unsigned char const*>( pv );
  302. update( p, n );
  303. }
  304. BOOST_CXX14_CONSTEXPR std::uint64_t result()
  305. {
  306. BOOST_ASSERT( m_ == n_ % 32 );
  307. std::uint64_t h = 0;
  308. if( n_ >= 32 )
  309. {
  310. h = detail::rotl( v1_, 1 ) + detail::rotl( v2_, 7 ) + detail::rotl( v3_, 12 ) + detail::rotl( v4_, 18 );
  311. h = merge_round( h, v1_ );
  312. h = merge_round( h, v2_ );
  313. h = merge_round( h, v3_ );
  314. h = merge_round( h, v4_ );
  315. }
  316. else
  317. {
  318. h = v3_ + P5;
  319. }
  320. h += n_;
  321. unsigned char const * p = buffer_;
  322. std::size_t m = m_;
  323. while( m >= 8 )
  324. {
  325. std::uint64_t k1 = round( 0, detail::read64le( p ) );
  326. h ^= k1;
  327. h = detail::rotl( h, 27 ) * P1 + P4;
  328. p += 8;
  329. m -= 8;
  330. }
  331. while( m >= 4 )
  332. {
  333. h ^= static_cast<std::uint64_t>( detail::read32le( p ) ) * P1;
  334. h = detail::rotl( h, 23 ) * P2 + P3;
  335. p += 4;
  336. m -= 4;
  337. }
  338. while( m > 0 )
  339. {
  340. h ^= p[0] * P5;
  341. h = detail::rotl( h, 11 ) * P1;
  342. ++p;
  343. --m;
  344. }
  345. n_ += 32 - m_;
  346. m_ = 0;
  347. // clear buffered plaintext
  348. detail::memset( buffer_, 0, 32 );
  349. // perturb state
  350. v1_ += h;
  351. v2_ += h;
  352. v3_ -= h;
  353. v4_ -= h;
  354. // apply final mix
  355. h ^= h >> 33;
  356. h *= P2;
  357. h ^= h >> 29;
  358. h *= P3;
  359. h ^= h >> 32;
  360. return h;
  361. }
  362. };
  363. } // namespace hash2
  364. } // namespace boost
  365. #if defined(BOOST_MSVC) && BOOST_MSVC < 1920
  366. # pragma warning(pop)
  367. #endif
  368. #endif // #ifndef BOOST_HASH2_XXHASH_HPP_INCLUDED