get_integral_result.hpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #ifndef BOOST_HASH2_GET_INTEGRAL_RESULT_HPP_INCLUDED
  2. #define BOOST_HASH2_GET_INTEGRAL_RESULT_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. #include <boost/hash2/detail/read.hpp>
  7. #include <type_traits>
  8. #include <limits>
  9. #include <cstddef>
  10. namespace boost
  11. {
  12. namespace hash2
  13. {
  14. namespace detail
  15. {
  16. // contraction
  17. // 2 -> 1, 4 -> x
  18. template<class R>
  19. constexpr typename std::enable_if<sizeof(R) <= 4, std::uint32_t>::type
  20. get_result_multiplier()
  21. {
  22. return 0xBF3D6763u;
  23. }
  24. // 8 -> x
  25. template<class R>
  26. constexpr typename std::enable_if<sizeof(R) == 8, std::uint64_t>::type
  27. get_result_multiplier()
  28. {
  29. return 0x99EBE72FE70129CBull;
  30. }
  31. } // namespace detail
  32. // contraction
  33. template<class T, class Hash, class R = typename Hash::result_type>
  34. typename std::enable_if<std::is_integral<R>::value && (sizeof(R) > sizeof(T)), T>::type
  35. get_integral_result( Hash& h )
  36. {
  37. static_assert( std::is_integral<T>::value, "T must be integral" );
  38. static_assert( !std::is_same<typename std::remove_cv<T>::type, bool>::value, "T must not be bool" );
  39. static_assert( std::is_unsigned<R>::value, "Hash::result_type must be unsigned" );
  40. typedef typename std::make_unsigned<T>::type U;
  41. constexpr auto m = detail::get_result_multiplier<R>();
  42. auto r = h.result();
  43. return static_cast<T>( static_cast<U>( ( r * m ) >> ( std::numeric_limits<R>::digits - std::numeric_limits<U>::digits ) ) );
  44. }
  45. // identity
  46. template<class T, class Hash, class R = typename Hash::result_type>
  47. typename std::enable_if<std::is_integral<R>::value && sizeof(R) == sizeof(T), T>::type
  48. get_integral_result( Hash& h )
  49. {
  50. static_assert( std::is_integral<T>::value, "T must be integral" );
  51. static_assert( !std::is_same<typename std::remove_cv<T>::type, bool>::value, "T must not be bool" );
  52. static_assert( std::is_unsigned<R>::value, "Hash::result_type must be unsigned" );
  53. typedef typename std::make_unsigned<T>::type U;
  54. auto r = h.result();
  55. return static_cast<T>( static_cast<U>( r ) );
  56. }
  57. // expansion
  58. template<class T, class Hash, class R = typename Hash::result_type>
  59. typename std::enable_if<std::is_integral<R>::value && (sizeof(R) < sizeof(T)), T>::type
  60. get_integral_result( Hash& h )
  61. {
  62. static_assert( std::is_integral<T>::value, "T must be integral" );
  63. static_assert( !std::is_same<typename std::remove_cv<T>::type, bool>::value, "T must not be bool" );
  64. static_assert( std::is_unsigned<R>::value, "Hash::result_type must be unsigned" );
  65. typedef typename std::make_unsigned<T>::type U;
  66. constexpr auto rd = std::numeric_limits<R>::digits;
  67. constexpr auto ud = std::numeric_limits<U>::digits;
  68. U u = 0;
  69. for( int i = 0; i < ud; i += rd )
  70. {
  71. auto r = h.result();
  72. u += static_cast<U>( r ) << i;
  73. }
  74. return static_cast<T>( u );
  75. }
  76. // array-like R
  77. template<class T, class Hash, class R = typename Hash::result_type>
  78. typename std::enable_if< !std::is_integral<R>::value, T >::type
  79. get_integral_result( Hash& h )
  80. {
  81. static_assert( std::is_integral<T>::value, "T must be integral" );
  82. static_assert( !std::is_same<typename std::remove_cv<T>::type, bool>::value, "T must not be bool" );
  83. static_assert( R().size() >= 8, "Array-like result type is too short" );
  84. auto r = h.result();
  85. return static_cast<T>( detail::read64le( r.data() ) );
  86. }
  87. } // namespace hash2
  88. } // namespace boost
  89. #endif // #ifndef BOOST_HASH2_GET_INTEGRAL_RESULT_HPP_INCLUDED