hash.hpp 18 KB

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