hash.hpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2005-2014 Daniel James.
  4. // Copyright 2021, 2022 Peter Dimov.
  5. // Copyright 2024 Ion Gaztanaga.
  6. // Distributed under the Boost Software License, Version 1.0.
  7. // https://www.boost.org/LICENSE_1_0.txt
  8. //
  9. // Based on Peter Dimov's proposal
  10. // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
  11. // issue 6.18.
  12. //
  13. // The original C++11 implementation was done by Peter Dimov
  14. // The C++03 porting was done by Ion Gaztanaga.
  15. //
  16. // The goal of this header is to avoid Intrusive's hard dependency on ContainerHash,
  17. // which adds additional dependencies and the minimum supported C++ standard can
  18. // differ between both libraries. However, a compatibility protocol is used so that
  19. // users compatible with ContainerHash are also compatible with Intrusive:
  20. //
  21. // - If users define `hash_value` (as required by boost::hash) for their classes
  22. // are automatically compatible with Intrusive unordered containers.
  23. //
  24. // - If users include boost/container_hash/hash.hpp in their headers, Intrusive
  25. // unordered containers will take advantage of boost::hash compatibility hash functions
  26. // (such as hashing functions for range-compatible types, standard containers, etc.)
  27. //
  28. // See http://www.boost.org/libs/intrusive for documentation.
  29. //
  30. /////////////////////////////////////////////////////////////////////////////
  31. #ifndef BOOST_INTRUSIVE_HASH_HASH_HPP
  32. #define BOOST_INTRUSIVE_HASH_HASH_HPP
  33. #include <boost/intrusive/detail/config_begin.hpp>
  34. #include <boost/intrusive/detail/workaround.hpp>
  35. #include <boost/intrusive/detail/hash_integral.hpp>
  36. #include <boost/intrusive/detail/hash_mix.hpp>
  37. #include <boost/intrusive/detail/hash_combine.hpp>
  38. #include <boost/cstdint.hpp>
  39. #include <climits>
  40. #include <cstring>
  41. #include <cfloat>
  42. #include <boost/intrusive/detail/mpl.hpp>
  43. namespace boost {
  44. template<class T>
  45. struct hash;
  46. } //namespace boost
  47. //Fallback function to call boost::hash if scalar type and ADL fail.
  48. //The user must include boost/container_hash/hash.hpp when to make this call work,
  49. //this allows boost::intrusive to be compatible with boost::hash without
  50. //a mandatory physical (header inclusion) dependency
  51. namespace boost_intrusive_adl
  52. {
  53. template<class T>
  54. inline std::size_t hash_value(const T& v)
  55. {
  56. return boost::hash<T>()(v);
  57. }
  58. }
  59. namespace boost {
  60. namespace intrusive {
  61. namespace detail {
  62. //ADL-based lookup hash call
  63. template <class T>
  64. inline typename detail::disable_if_c<detail::is_scalar<T>::value, std::size_t>::type
  65. hash_value_dispatch(const T& v)
  66. {
  67. //Try ADL lookup, if it fails, boost_intrusive_adl::hash_value will retry with boost::hash
  68. using boost_intrusive_adl::hash_value;
  69. return hash_value(v);
  70. }
  71. template <typename T>
  72. typename enable_if_c<is_enum<T>::value, std::size_t>::type
  73. hash_value( T v )
  74. {
  75. return static_cast<std::size_t>( v );
  76. }
  77. ////////////////////////////////////////////////////////////
  78. //
  79. // floating point types
  80. //
  81. ////////////////////////////////////////////////////////////
  82. template<class T, std::size_t Bits = sizeof(T) * CHAR_BIT>
  83. struct hash_float_impl;
  84. // float
  85. template<class T> struct hash_float_impl<T, 32>
  86. {
  87. static std::size_t fn( T v )
  88. {
  89. boost::uint32_t w;
  90. std::memcpy( &w, &v, sizeof( v ) );
  91. return w;
  92. }
  93. };
  94. // double
  95. template<class T> struct hash_float_impl<T, 64>
  96. {
  97. static std::size_t fn( T v )
  98. {
  99. boost::uint64_t w;
  100. std::memcpy( &w, &v, sizeof( v ) );
  101. return hash_value( w );
  102. }
  103. };
  104. // 80 bit long double in 12 bytes
  105. template<class T> struct hash_float_impl<T, 96>
  106. {
  107. static std::size_t fn( T v )
  108. {
  109. boost::uint64_t w[ 2 ] = {};
  110. std::memcpy( &w, &v, 80 / CHAR_BIT );
  111. std::size_t seed = 0;
  112. seed = hash_value( w[0] ) + (hash_mix)( seed );
  113. seed = hash_value( w[1] ) + (hash_mix)( seed );
  114. return seed;
  115. }
  116. };
  117. #if (LDBL_MAX_10_EXP == 4932)
  118. // 80 bit long double in 16 bytes
  119. template<class T> struct hash_float_impl<T, 128>
  120. {
  121. static std::size_t fn( T v )
  122. {
  123. boost::uint64_t w[ 2 ] = {};
  124. std::memcpy( &w, &v, 80 / CHAR_BIT );
  125. std::size_t seed = 0;
  126. seed = hash_value( w[0] ) + (hash_mix)( seed );
  127. seed = hash_value( w[1] ) + (hash_mix)( seed );
  128. return seed;
  129. }
  130. };
  131. #elif (LDBL_MAX_10_EXP > 4932)
  132. // 128 bit long double
  133. template<class T> struct hash_float_impl<T, 128>
  134. {
  135. static std::size_t fn( T v )
  136. {
  137. boost::uint64_t w[ 2 ];
  138. std::memcpy( &w, &v, sizeof( v ) );
  139. std::size_t seed = 0;
  140. #if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__
  141. seed = hash_value( w[1] ) + (hash_mix)( seed );
  142. seed = hash_value( w[0] ) + (hash_mix)( seed );
  143. #else
  144. seed = hash_value( w[0] ) + (hash_mix)( seed );
  145. seed = hash_value( w[1] ) + (hash_mix)( seed );
  146. #endif
  147. return seed;
  148. }
  149. };
  150. #endif //#if (LDBL_MAX_10_EXP == 4932)
  151. template <typename T>
  152. typename enable_if_c<is_floating_point<T>::value, std::size_t>::type
  153. hash_value( T v )
  154. {
  155. return boost::intrusive::detail::hash_float_impl<T>::fn( v + 0 );
  156. }
  157. ////////////////////////////////////////////////////////////
  158. //
  159. // pointer types
  160. //
  161. ////////////////////////////////////////////////////////////
  162. // `x + (x >> 3)` adjustment by Alberto Barbati and Dave Harris.
  163. template <class T> std::size_t hash_value( T* const& v )
  164. {
  165. std::size_t x = reinterpret_cast<std::size_t>( v );
  166. return hash_value( x + (x >> 3) );
  167. }
  168. ////////////////////////////////////////////////////////////
  169. //
  170. // std::nullptr_t
  171. //
  172. ////////////////////////////////////////////////////////////
  173. #if !defined(BOOST_NO_CXX11_NULLPTR)
  174. template <typename T>
  175. typename enable_if_c<is_same<T, std::nullptr_t>::value, std::size_t>::type
  176. hash_value( T const &)
  177. {
  178. return (hash_value)( static_cast<void*>( nullptr ) );
  179. }
  180. #endif
  181. ////////////////////////////////////////////////////////////
  182. //
  183. // Array types
  184. //
  185. ////////////////////////////////////////////////////////////
  186. //Forward declaration or internal hash functor, for array iteration
  187. template<class T>
  188. struct internal_hash_functor;
  189. template<class T, std::size_t N>
  190. inline std::size_t hash_value_dispatch( T const (&x)[ N ] )
  191. {
  192. std::size_t seed = 0;
  193. for(std::size_t i = 0; i != N; ++i){
  194. hash_combine_size_t(seed, internal_hash_functor<T>()(x[i]));
  195. }
  196. return seed;
  197. }
  198. template<class T, std::size_t N>
  199. inline std::size_t hash_value_dispatch( T (&x)[ N ] )
  200. {
  201. std::size_t seed = 0;
  202. for (std::size_t i = 0; i != N; ++i) {
  203. hash_combine_size_t(seed, internal_hash_functor<T>()(x[i]));
  204. }
  205. return seed;
  206. }
  207. ////////////////////////////////////////////////////////////
  208. //
  209. // Scalar types, calls proper overload
  210. //
  211. ////////////////////////////////////////////////////////////
  212. template <class T>
  213. inline typename detail::enable_if_c<detail::is_scalar<T>::value, std::size_t>::type
  214. hash_value_dispatch(const T &v)
  215. {
  216. return boost::intrusive::detail::hash_value(v);
  217. }
  218. //Internal "anonymous" hash functor, first selects between "built-in" scalar/array types
  219. //and ADL-based lookup
  220. template<class T>
  221. struct internal_hash_functor
  222. {
  223. inline std::size_t operator()(T const& val) const
  224. {
  225. return ::boost::intrusive::detail::hash_value_dispatch(val);
  226. }
  227. };
  228. } // namespace detail {
  229. } // namespace intrusive {
  230. } // namespace boost
  231. #include <boost/intrusive/detail/config_end.hpp>
  232. #endif // #ifndef BOOST_INTRUSIVE_HASH_HASH_HPP