hash_integral.hpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // Copyright 2021-2023 Peter Dimov
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // https://www.boost.org/LICENSE_1_0.txt
  4. #ifndef BOOST_HASH_DETAIL_HASH_INTEGRAL_HPP
  5. #define BOOST_HASH_DETAIL_HASH_INTEGRAL_HPP
  6. #include <boost/container_hash/detail/hash_mix.hpp>
  7. #include <type_traits>
  8. #include <cstddef>
  9. #include <climits>
  10. namespace boost
  11. {
  12. namespace hash_detail
  13. {
  14. // libstdc++ doesn't provide support for __int128 in the standard traits
  15. template<class T> struct is_integral: public std::is_integral<T>
  16. {
  17. };
  18. template<class T> struct is_unsigned: public std::is_unsigned<T>
  19. {
  20. };
  21. template<class T> struct make_unsigned: public std::make_unsigned<T>
  22. {
  23. };
  24. #if defined(__SIZEOF_INT128__)
  25. template<> struct is_integral<__int128_t>: public std::true_type
  26. {
  27. };
  28. template<> struct is_integral<__uint128_t>: public std::true_type
  29. {
  30. };
  31. template<> struct is_unsigned<__int128_t>: public std::false_type
  32. {
  33. };
  34. template<> struct is_unsigned<__uint128_t>: public std::true_type
  35. {
  36. };
  37. template<> struct make_unsigned<__int128_t>
  38. {
  39. typedef __uint128_t type;
  40. };
  41. template<> struct make_unsigned<__uint128_t>
  42. {
  43. typedef __uint128_t type;
  44. };
  45. #endif
  46. template<class T,
  47. bool bigger_than_size_t = (sizeof(T) > sizeof(std::size_t)),
  48. bool is_unsigned = is_unsigned<T>::value,
  49. std::size_t size_t_bits = sizeof(std::size_t) * CHAR_BIT,
  50. std::size_t type_bits = sizeof(T) * CHAR_BIT>
  51. struct hash_integral_impl;
  52. template<class T, bool is_unsigned, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl<T, false, is_unsigned, size_t_bits, type_bits>
  53. {
  54. static std::size_t fn( T v )
  55. {
  56. return static_cast<std::size_t>( v );
  57. }
  58. };
  59. template<class T, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl<T, true, false, size_t_bits, type_bits>
  60. {
  61. static std::size_t fn( T v )
  62. {
  63. typedef typename make_unsigned<T>::type U;
  64. if( v >= 0 )
  65. {
  66. return hash_integral_impl<U>::fn( static_cast<U>( v ) );
  67. }
  68. else
  69. {
  70. return ~hash_integral_impl<U>::fn( static_cast<U>( ~static_cast<U>( v ) ) );
  71. }
  72. }
  73. };
  74. template<class T> struct hash_integral_impl<T, true, true, 32, 64>
  75. {
  76. static std::size_t fn( T v )
  77. {
  78. std::size_t seed = 0;
  79. seed = static_cast<std::size_t>( v >> 32 ) + hash_detail::hash_mix( seed );
  80. seed = static_cast<std::size_t>( v & 0xFFFFFFFF ) + hash_detail::hash_mix( seed );
  81. return seed;
  82. }
  83. };
  84. template<class T> struct hash_integral_impl<T, true, true, 32, 128>
  85. {
  86. static std::size_t fn( T v )
  87. {
  88. std::size_t seed = 0;
  89. seed = static_cast<std::size_t>( v >> 96 ) + hash_detail::hash_mix( seed );
  90. seed = static_cast<std::size_t>( v >> 64 ) + hash_detail::hash_mix( seed );
  91. seed = static_cast<std::size_t>( v >> 32 ) + hash_detail::hash_mix( seed );
  92. seed = static_cast<std::size_t>( v ) + hash_detail::hash_mix( seed );
  93. return seed;
  94. }
  95. };
  96. template<class T> struct hash_integral_impl<T, true, true, 64, 128>
  97. {
  98. static std::size_t fn( T v )
  99. {
  100. std::size_t seed = 0;
  101. seed = static_cast<std::size_t>( v >> 64 ) + hash_detail::hash_mix( seed );
  102. seed = static_cast<std::size_t>( v ) + hash_detail::hash_mix( seed );
  103. return seed;
  104. }
  105. };
  106. } // namespace hash_detail
  107. template <typename T>
  108. typename std::enable_if<hash_detail::is_integral<T>::value, std::size_t>::type
  109. hash_value( T v )
  110. {
  111. return hash_detail::hash_integral_impl<T>::fn( v );
  112. }
  113. } // namespace boost
  114. #endif // #ifndef BOOST_HASH_DETAIL_HASH_INTEGRAL_HPP