hash.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. // Copyright 2005-2014 Daniel James.
  2. // Copyright 2021, 2022 Peter Dimov.
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // Based on Peter Dimov's proposal
  6. // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
  7. // issue 6.18.
  8. #ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
  9. #define BOOST_FUNCTIONAL_HASH_HASH_HPP
  10. #include <boost/container_hash/hash_fwd.hpp>
  11. #include <boost/container_hash/is_range.hpp>
  12. #include <boost/container_hash/is_contiguous_range.hpp>
  13. #include <boost/container_hash/is_unordered_range.hpp>
  14. #include <boost/container_hash/is_described_class.hpp>
  15. #include <boost/container_hash/detail/hash_integral.hpp>
  16. #include <boost/container_hash/detail/hash_tuple_like.hpp>
  17. #include <boost/container_hash/detail/hash_mix.hpp>
  18. #include <boost/container_hash/detail/hash_range.hpp>
  19. #include <boost/describe/bases.hpp>
  20. #include <boost/describe/members.hpp>
  21. #include <type_traits>
  22. #include <cstdint>
  23. #if defined(BOOST_DESCRIBE_CXX14)
  24. # include <boost/mp11/algorithm.hpp>
  25. #endif
  26. #include <string>
  27. #include <iterator>
  28. #include <complex>
  29. #include <utility>
  30. #include <limits>
  31. #include <climits>
  32. #include <cstring>
  33. #if !defined(BOOST_NO_CXX11_SMART_PTR)
  34. # include <memory>
  35. #endif
  36. #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
  37. #include <typeindex>
  38. #endif
  39. #if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
  40. #include <system_error>
  41. #endif
  42. #if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
  43. #include <optional>
  44. #endif
  45. #if !defined(BOOST_NO_CXX17_HDR_VARIANT)
  46. #include <variant>
  47. #endif
  48. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  49. # include <string_view>
  50. #endif
  51. namespace boost
  52. {
  53. //
  54. // boost::hash_value
  55. //
  56. // integral types
  57. // in detail/hash_integral.hpp
  58. // enumeration types
  59. template <typename T>
  60. typename std::enable_if<std::is_enum<T>::value, std::size_t>::type
  61. hash_value( T v )
  62. {
  63. // This should in principle return the equivalent of
  64. //
  65. // boost::hash_value( to_underlying(v) );
  66. //
  67. // However, the C++03 implementation of underlying_type,
  68. //
  69. // conditional<is_signed<T>, make_signed<T>, make_unsigned<T>>::type::type
  70. //
  71. // generates a legitimate -Wconversion warning in is_signed,
  72. // because -1 is not a valid enum value when all the enumerators
  73. // are nonnegative.
  74. //
  75. // So the legacy implementation will have to do for now.
  76. return static_cast<std::size_t>( v );
  77. }
  78. // floating point types
  79. namespace hash_detail
  80. {
  81. template<class T,
  82. std::size_t Bits = sizeof(T) * CHAR_BIT,
  83. int Digits = std::numeric_limits<T>::digits>
  84. struct hash_float_impl;
  85. // float
  86. template<class T, int Digits> struct hash_float_impl<T, 32, Digits>
  87. {
  88. static std::size_t fn( T v )
  89. {
  90. std::uint32_t w;
  91. std::memcpy( &w, &v, sizeof( v ) );
  92. return w;
  93. }
  94. };
  95. // double
  96. template<class T, int Digits> struct hash_float_impl<T, 64, Digits>
  97. {
  98. static std::size_t fn( T v )
  99. {
  100. std::uint64_t w;
  101. std::memcpy( &w, &v, sizeof( v ) );
  102. return hash_value( w );
  103. }
  104. };
  105. // 80 bit long double in 12 bytes
  106. template<class T> struct hash_float_impl<T, 96, 64>
  107. {
  108. static std::size_t fn( T v )
  109. {
  110. std::uint64_t w[ 2 ] = {};
  111. std::memcpy( &w, &v, 80 / CHAR_BIT );
  112. std::size_t seed = 0;
  113. seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
  114. seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
  115. return seed;
  116. }
  117. };
  118. // 80 bit long double in 16 bytes
  119. template<class T> struct hash_float_impl<T, 128, 64>
  120. {
  121. static std::size_t fn( T v )
  122. {
  123. std::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_detail::hash_mix( seed );
  127. seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
  128. return seed;
  129. }
  130. };
  131. // 128 bit long double
  132. template<class T, int Digits> struct hash_float_impl<T, 128, Digits>
  133. {
  134. static std::size_t fn( T v )
  135. {
  136. std::uint64_t w[ 2 ];
  137. std::memcpy( &w, &v, sizeof( v ) );
  138. std::size_t seed = 0;
  139. #if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__
  140. seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
  141. seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
  142. #else
  143. seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
  144. seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
  145. #endif
  146. return seed;
  147. }
  148. };
  149. } // namespace hash_detail
  150. template <typename T>
  151. typename std::enable_if<std::is_floating_point<T>::value, std::size_t>::type
  152. hash_value( T v )
  153. {
  154. return boost::hash_detail::hash_float_impl<T>::fn( v + 0 );
  155. }
  156. // pointer types
  157. // `x + (x >> 3)` adjustment by Alberto Barbati and Dave Harris.
  158. template <class T> std::size_t hash_value( T* const& v )
  159. {
  160. std::uintptr_t x = reinterpret_cast<std::uintptr_t>( v );
  161. return boost::hash_value( x + (x >> 3) );
  162. }
  163. // array types
  164. template<class T, std::size_t N>
  165. inline std::size_t hash_value( T const (&x)[ N ] )
  166. {
  167. return boost::hash_range( x, x + N );
  168. }
  169. template<class T, std::size_t N>
  170. inline std::size_t hash_value( T (&x)[ N ] )
  171. {
  172. return boost::hash_range( x, x + N );
  173. }
  174. // complex
  175. template <class T>
  176. std::size_t hash_value( std::complex<T> const& v )
  177. {
  178. std::size_t re = boost::hash<T>()( v.real() );
  179. std::size_t im = boost::hash<T>()( v.imag() );
  180. return re + hash_detail::hash_mix( im );
  181. }
  182. // pair
  183. template <class A, class B>
  184. std::size_t hash_value( std::pair<A, B> const& v )
  185. {
  186. std::size_t seed = 0;
  187. boost::hash_combine( seed, v.first );
  188. boost::hash_combine( seed, v.second );
  189. return seed;
  190. }
  191. // ranges (list, set, deque...)
  192. template <typename T>
  193. typename std::enable_if<container_hash::is_range<T>::value && !container_hash::is_contiguous_range<T>::value && !container_hash::is_unordered_range<T>::value, std::size_t>::type
  194. hash_value( T const& v )
  195. {
  196. return boost::hash_range( v.begin(), v.end() );
  197. }
  198. // contiguous ranges (string, vector, array)
  199. template <typename T>
  200. typename std::enable_if<container_hash::is_contiguous_range<T>::value, std::size_t>::type
  201. hash_value( T const& v )
  202. {
  203. return boost::hash_range( v.data(), v.data() + v.size() );
  204. }
  205. // unordered ranges (unordered_set, unordered_map)
  206. template <typename T>
  207. typename std::enable_if<container_hash::is_unordered_range<T>::value, std::size_t>::type
  208. hash_value( T const& v )
  209. {
  210. return boost::hash_unordered_range( v.begin(), v.end() );
  211. }
  212. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ( \
  213. ( defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142 ) || \
  214. ( !defined(_MSVC_STL_VERSION) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520 ) )
  215. // resolve ambiguity with unconstrained stdext::hash_value in <xhash> :-/
  216. template<template<class...> class L, class... T>
  217. typename std::enable_if<container_hash::is_range<L<T...>>::value && !container_hash::is_contiguous_range<L<T...>>::value && !container_hash::is_unordered_range<L<T...>>::value, std::size_t>::type
  218. hash_value( L<T...> const& v )
  219. {
  220. return boost::hash_range( v.begin(), v.end() );
  221. }
  222. // contiguous ranges (string, vector, array)
  223. template<template<class...> class L, class... T>
  224. typename std::enable_if<container_hash::is_contiguous_range<L<T...>>::value, std::size_t>::type
  225. hash_value( L<T...> const& v )
  226. {
  227. return boost::hash_range( v.data(), v.data() + v.size() );
  228. }
  229. template<template<class, std::size_t> class L, class T, std::size_t N>
  230. typename std::enable_if<container_hash::is_contiguous_range<L<T, N>>::value, std::size_t>::type
  231. hash_value( L<T, N> const& v )
  232. {
  233. return boost::hash_range( v.data(), v.data() + v.size() );
  234. }
  235. // unordered ranges (unordered_set, unordered_map)
  236. template<template<class...> class L, class... T>
  237. typename std::enable_if<container_hash::is_unordered_range<L<T...>>::value, std::size_t>::type
  238. hash_value( L<T...> const& v )
  239. {
  240. return boost::hash_unordered_range( v.begin(), v.end() );
  241. }
  242. #endif
  243. // described classes
  244. #if defined(BOOST_DESCRIBE_CXX14)
  245. #if defined(_MSC_VER) && _MSC_VER == 1900
  246. # pragma warning(push)
  247. # pragma warning(disable: 4100) // unreferenced formal parameter
  248. #endif
  249. template <typename T>
  250. typename std::enable_if<container_hash::is_described_class<T>::value, std::size_t>::type
  251. hash_value( T const& v )
  252. {
  253. static_assert( !std::is_union<T>::value, "described unions are not supported" );
  254. std::size_t r = 0;
  255. using Bd = describe::describe_bases<T, describe::mod_any_access>;
  256. mp11::mp_for_each<Bd>([&](auto D){
  257. using B = typename decltype(D)::type;
  258. boost::hash_combine( r, (B const&)v );
  259. });
  260. using Md = describe::describe_members<T, describe::mod_any_access>;
  261. mp11::mp_for_each<Md>([&](auto D){
  262. boost::hash_combine( r, v.*D.pointer );
  263. });
  264. return r;
  265. }
  266. #if defined(_MSC_VER) && _MSC_VER == 1900
  267. # pragma warning(pop)
  268. #endif
  269. #endif
  270. // std::unique_ptr, std::shared_ptr
  271. #if !defined(BOOST_NO_CXX11_SMART_PTR)
  272. template <typename T>
  273. std::size_t hash_value( std::shared_ptr<T> const& x )
  274. {
  275. return boost::hash_value( x.get() );
  276. }
  277. template <typename T, typename Deleter>
  278. std::size_t hash_value( std::unique_ptr<T, Deleter> const& x )
  279. {
  280. return boost::hash_value( x.get() );
  281. }
  282. #endif
  283. // std::type_index
  284. #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
  285. inline std::size_t hash_value( std::type_index const& v )
  286. {
  287. return v.hash_code();
  288. }
  289. #endif
  290. // std::error_code, std::error_condition
  291. #if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
  292. inline std::size_t hash_value( std::error_code const& v )
  293. {
  294. std::size_t seed = 0;
  295. boost::hash_combine( seed, v.value() );
  296. boost::hash_combine( seed, &v.category() );
  297. return seed;
  298. }
  299. inline std::size_t hash_value( std::error_condition const& v )
  300. {
  301. std::size_t seed = 0;
  302. boost::hash_combine( seed, v.value() );
  303. boost::hash_combine( seed, &v.category() );
  304. return seed;
  305. }
  306. #endif
  307. // std::nullptr_t
  308. #if !defined(BOOST_NO_CXX11_NULLPTR)
  309. template <typename T>
  310. typename std::enable_if<std::is_same<T, std::nullptr_t>::value, std::size_t>::type
  311. hash_value( T const& /*v*/ )
  312. {
  313. return boost::hash_value( static_cast<void*>( nullptr ) );
  314. }
  315. #endif
  316. // std::optional
  317. #if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
  318. template <typename T>
  319. std::size_t hash_value( std::optional<T> const& v )
  320. {
  321. if( !v )
  322. {
  323. // Arbitrary value for empty optional.
  324. return 0x12345678;
  325. }
  326. else
  327. {
  328. return boost::hash<T>()(*v);
  329. }
  330. }
  331. #endif
  332. // std::variant
  333. #if !defined(BOOST_NO_CXX17_HDR_VARIANT)
  334. inline std::size_t hash_value( std::monostate )
  335. {
  336. return 0x87654321;
  337. }
  338. template <typename... Types>
  339. std::size_t hash_value( std::variant<Types...> const& v )
  340. {
  341. std::size_t seed = 0;
  342. hash_combine( seed, v.index() );
  343. std::visit( [&seed](auto&& x) { hash_combine(seed, x); }, v );
  344. return seed;
  345. }
  346. #endif
  347. //
  348. // boost::hash_combine
  349. //
  350. template <class T>
  351. inline void hash_combine( std::size_t& seed, T const& v )
  352. {
  353. seed = boost::hash_detail::hash_mix( seed + 0x9e3779b9 + boost::hash<T>()( v ) );
  354. }
  355. //
  356. // boost::hash_range
  357. //
  358. template <class It>
  359. inline void hash_range( std::size_t& seed, It first, It last )
  360. {
  361. seed = hash_detail::hash_range( seed, first, last );
  362. }
  363. template <class It>
  364. inline std::size_t hash_range( It first, It last )
  365. {
  366. std::size_t seed = 0;
  367. hash_range( seed, first, last );
  368. return seed;
  369. }
  370. //
  371. // boost::hash_unordered_range
  372. //
  373. template <class It>
  374. inline void hash_unordered_range( std::size_t& seed, It first, It last )
  375. {
  376. std::size_t r = 0;
  377. std::size_t const s2( seed );
  378. for( ; first != last; ++first )
  379. {
  380. std::size_t s3( s2 );
  381. hash_combine<typename std::iterator_traits<It>::value_type>( s3, *first );
  382. r += s3;
  383. }
  384. seed += r;
  385. }
  386. template <class It>
  387. inline std::size_t hash_unordered_range( It first, It last )
  388. {
  389. std::size_t seed = 0;
  390. hash_unordered_range( seed, first, last );
  391. return seed;
  392. }
  393. //
  394. // boost::hash
  395. //
  396. template <class T> struct hash
  397. {
  398. typedef T argument_type;
  399. typedef std::size_t result_type;
  400. std::size_t operator()( T const& val ) const
  401. {
  402. return hash_value( val );
  403. }
  404. };
  405. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ( \
  406. ( defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142 ) || \
  407. ( !defined(_MSVC_STL_VERSION) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520 ) )
  408. // Dinkumware has stdext::hash_value for basic_string in <xhash> :-/
  409. template<class E, class T, class A> struct hash< std::basic_string<E, T, A> >
  410. {
  411. typedef std::basic_string<E, T, A> argument_type;
  412. typedef std::size_t result_type;
  413. std::size_t operator()( std::basic_string<E, T, A> const& val ) const
  414. {
  415. return boost::hash_value( val );
  416. }
  417. };
  418. #endif
  419. // boost::unordered::hash_is_avalanching
  420. namespace unordered
  421. {
  422. template<class T> struct hash_is_avalanching;
  423. template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string<Ch> > >: std::is_integral<Ch> {};
  424. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  425. template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string_view<Ch> > >: std::is_integral<Ch> {};
  426. #endif
  427. } // namespace unordered
  428. } // namespace boost
  429. #endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP