digest.hpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/json
  8. //
  9. #ifndef BOOST_JSON_DETAIL_DIGEST_HPP
  10. #define BOOST_JSON_DETAIL_DIGEST_HPP
  11. #include <boost/json/detail/config.hpp>
  12. #include <algorithm>
  13. #include <iterator>
  14. namespace boost {
  15. namespace json {
  16. namespace detail {
  17. // Calculate salted digest of string
  18. template<class ForwardIterator>
  19. std::size_t
  20. digest(ForwardIterator b, ForwardIterator e, std::size_t salt) noexcept
  21. {
  22. std::size_t const len = std::distance(b, e);
  23. #if BOOST_JSON_ARCH == 64
  24. using state_type = std::uint64_t;
  25. state_type const m = 0xc6a4a7935bd1e995ULL;
  26. int const r = 47;
  27. state_type hash = salt ^ (len * m);
  28. constexpr std::size_t N = sizeof(state_type);
  29. e = std::next( b, len & ~std::size_t(N-1) );
  30. for( ; b != e; std::advance(b, N) )
  31. {
  32. state_type num;
  33. #ifdef _MSC_VER
  34. # pragma warning(push)
  35. # pragma warning(disable: 4996)
  36. #endif
  37. std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
  38. #ifdef _MSC_VER
  39. # pragma warning(pop)
  40. #endif
  41. num *= m;
  42. num ^= num >> r;
  43. num *= m;
  44. hash ^= num;
  45. hash *= m;
  46. }
  47. switch( len & (N - 1) )
  48. {
  49. case 7: hash ^= state_type( *std::next(b, 6) ) << 48; // fall through
  50. case 6: hash ^= state_type( *std::next(b, 5) ) << 40; // fall through
  51. case 5: hash ^= state_type( *std::next(b, 4) ) << 32; // fall through
  52. case 4: hash ^= state_type( *std::next(b, 3) ) << 24; // fall through
  53. case 3: hash ^= state_type( *std::next(b, 2) ) << 16; // fall through
  54. case 2: hash ^= state_type( *std::next(b, 1) ) << 8; // fall through
  55. case 1: hash ^= state_type( *std::next(b, 0) );
  56. hash *= m;
  57. };
  58. hash ^= hash >> r;
  59. hash *= m;
  60. hash ^= hash >> r;
  61. #else
  62. using state_type = std::uint32_t;
  63. state_type const m = 0x5bd1e995;
  64. int const r = 24;
  65. state_type hash = salt ^ len;
  66. constexpr std::size_t N = sizeof(state_type);
  67. e = std::next( b, len & ~std::size_t(N-1) );
  68. for( ; b != e; std::advance(b, N) )
  69. {
  70. state_type num;
  71. std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
  72. num *= m;
  73. num ^= num >> r;
  74. num *= m;
  75. hash *= m;
  76. hash ^= num;
  77. }
  78. switch( len & (N - 1) )
  79. {
  80. case 3: hash ^= state_type( *std::next(b, 2) ) << 16; // fall through
  81. case 2: hash ^= state_type( *std::next(b, 1) ) << 8; // fall through
  82. case 1: hash ^= state_type( *std::next(b, 0) );
  83. hash *= m;
  84. };
  85. hash ^= hash >> 13;
  86. hash *= m;
  87. hash ^= hash >> 15;
  88. #endif
  89. return hash;
  90. }
  91. } // detail
  92. } // namespace json
  93. } // namespace boost
  94. #endif