hash.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. // Copyright 2005-2009 Daniel James.
  2. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  3. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  4. // Based on Peter Dimov's proposal
  5. // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
  6. // issue 6.18.
  7. #if !defined(BOOST_FUNCTIONAL_HASH_HASH_HPP)
  8. #define BOOST_FUNCTIONAL_HASH_HASH_HPP
  9. #include <boost/functional/hash/hash_fwd.hpp>
  10. #include <functional>
  11. #include <boost/functional/hash/detail/hash_float.hpp>
  12. #include <string>
  13. #include <boost/limits.hpp>
  14. #include <boost/type_traits/is_enum.hpp>
  15. #include <boost/type_traits/is_integral.hpp>
  16. #include <boost/utility/enable_if.hpp>
  17. #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
  18. #include <boost/type_traits/is_pointer.hpp>
  19. #endif
  20. #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
  21. #include <typeindex>
  22. #endif
  23. #if defined(BOOST_MSVC)
  24. #pragma warning(push)
  25. #pragma warning(disable:6295) // Ill-defined for-loop : 'unsigned int' values
  26. // are always of range '0' to '4294967295'.
  27. // Loop executes infinitely.
  28. #endif
  29. #if BOOST_WORKAROUND(__GNUC__, < 3) \
  30. && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)
  31. #define BOOST_HASH_CHAR_TRAITS string_char_traits
  32. #else
  33. #define BOOST_HASH_CHAR_TRAITS char_traits
  34. #endif
  35. namespace boost
  36. {
  37. namespace hash_detail
  38. {
  39. struct enable_hash_value { typedef std::size_t type; };
  40. template <typename T> struct basic_numbers {};
  41. template <typename T> struct long_numbers;
  42. template <typename T> struct ulong_numbers;
  43. template <typename T> struct float_numbers {};
  44. template <> struct basic_numbers<bool> :
  45. boost::hash_detail::enable_hash_value {};
  46. template <> struct basic_numbers<char> :
  47. boost::hash_detail::enable_hash_value {};
  48. template <> struct basic_numbers<unsigned char> :
  49. boost::hash_detail::enable_hash_value {};
  50. template <> struct basic_numbers<signed char> :
  51. boost::hash_detail::enable_hash_value {};
  52. template <> struct basic_numbers<short> :
  53. boost::hash_detail::enable_hash_value {};
  54. template <> struct basic_numbers<unsigned short> :
  55. boost::hash_detail::enable_hash_value {};
  56. template <> struct basic_numbers<int> :
  57. boost::hash_detail::enable_hash_value {};
  58. template <> struct basic_numbers<unsigned int> :
  59. boost::hash_detail::enable_hash_value {};
  60. template <> struct basic_numbers<long> :
  61. boost::hash_detail::enable_hash_value {};
  62. template <> struct basic_numbers<unsigned long> :
  63. boost::hash_detail::enable_hash_value {};
  64. #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
  65. template <> struct basic_numbers<wchar_t> :
  66. boost::hash_detail::enable_hash_value {};
  67. #endif
  68. // long_numbers is defined like this to allow for separate
  69. // specialization for long_long and int128_type, in case
  70. // they conflict.
  71. template <typename T> struct long_numbers2 {};
  72. template <typename T> struct ulong_numbers2 {};
  73. template <typename T> struct long_numbers : long_numbers2<T> {};
  74. template <typename T> struct ulong_numbers : ulong_numbers2<T> {};
  75. #if !defined(BOOST_NO_LONG_LONG)
  76. template <> struct long_numbers<boost::long_long_type> :
  77. boost::hash_detail::enable_hash_value {};
  78. template <> struct ulong_numbers<boost::ulong_long_type> :
  79. boost::hash_detail::enable_hash_value {};
  80. #endif
  81. #if defined(BOOST_HAS_INT128)
  82. template <> struct long_numbers2<boost::int128_type> :
  83. boost::hash_detail::enable_hash_value {};
  84. template <> struct ulong_numbers2<boost::uint128_type> :
  85. boost::hash_detail::enable_hash_value {};
  86. #endif
  87. template <> struct float_numbers<float> :
  88. boost::hash_detail::enable_hash_value {};
  89. template <> struct float_numbers<double> :
  90. boost::hash_detail::enable_hash_value {};
  91. template <> struct float_numbers<long double> :
  92. boost::hash_detail::enable_hash_value {};
  93. }
  94. template <typename T>
  95. typename boost::hash_detail::basic_numbers<T>::type hash_value(T);
  96. template <typename T>
  97. typename boost::hash_detail::long_numbers<T>::type hash_value(T);
  98. template <typename T>
  99. typename boost::hash_detail::ulong_numbers<T>::type hash_value(T);
  100. template <typename T>
  101. typename boost::enable_if<boost::is_enum<T>, std::size_t>::type
  102. hash_value(T);
  103. #if !BOOST_WORKAROUND(__DMC__, <= 0x848)
  104. template <class T> std::size_t hash_value(T* const&);
  105. #else
  106. template <class T> std::size_t hash_value(T*);
  107. #endif
  108. #if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
  109. template< class T, unsigned N >
  110. std::size_t hash_value(const T (&x)[N]);
  111. template< class T, unsigned N >
  112. std::size_t hash_value(T (&x)[N]);
  113. #endif
  114. template <class Ch, class A>
  115. std::size_t hash_value(
  116. std::basic_string<Ch, std::BOOST_HASH_CHAR_TRAITS<Ch>, A> const&);
  117. template <typename T>
  118. typename boost::hash_detail::float_numbers<T>::type hash_value(T);
  119. #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
  120. std::size_t hash_value(std::type_index);
  121. #endif
  122. // Implementation
  123. namespace hash_detail
  124. {
  125. template <class T>
  126. inline std::size_t hash_value_signed(T val)
  127. {
  128. const int size_t_bits = std::numeric_limits<std::size_t>::digits;
  129. // ceiling(std::numeric_limits<T>::digits / size_t_bits) - 1
  130. const int length = (std::numeric_limits<T>::digits - 1)
  131. / size_t_bits;
  132. std::size_t seed = 0;
  133. T positive = val < 0 ? -1 - val : val;
  134. // Hopefully, this loop can be unrolled.
  135. for(unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits)
  136. {
  137. seed ^= (std::size_t) (positive >> i) + (seed<<6) + (seed>>2);
  138. }
  139. seed ^= (std::size_t) val + (seed<<6) + (seed>>2);
  140. return seed;
  141. }
  142. template <class T>
  143. inline std::size_t hash_value_unsigned(T val)
  144. {
  145. const int size_t_bits = std::numeric_limits<std::size_t>::digits;
  146. // ceiling(std::numeric_limits<T>::digits / size_t_bits) - 1
  147. const int length = (std::numeric_limits<T>::digits - 1)
  148. / size_t_bits;
  149. std::size_t seed = 0;
  150. // Hopefully, this loop can be unrolled.
  151. for(unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits)
  152. {
  153. seed ^= (std::size_t) (val >> i) + (seed<<6) + (seed>>2);
  154. }
  155. seed ^= (std::size_t) val + (seed<<6) + (seed>>2);
  156. return seed;
  157. }
  158. }
  159. template <typename T>
  160. typename boost::hash_detail::basic_numbers<T>::type hash_value(T v)
  161. {
  162. return static_cast<std::size_t>(v);
  163. }
  164. template <typename T>
  165. typename boost::hash_detail::long_numbers<T>::type hash_value(T v)
  166. {
  167. return hash_detail::hash_value_signed(v);
  168. }
  169. template <typename T>
  170. typename boost::hash_detail::ulong_numbers<T>::type hash_value(T v)
  171. {
  172. return hash_detail::hash_value_unsigned(v);
  173. }
  174. template <typename T>
  175. typename boost::enable_if<boost::is_enum<T>, std::size_t>::type
  176. hash_value(T v)
  177. {
  178. return static_cast<std::size_t>(v);
  179. }
  180. // Implementation by Alberto Barbati and Dave Harris.
  181. #if !BOOST_WORKAROUND(__DMC__, <= 0x848)
  182. template <class T> std::size_t hash_value(T* const& v)
  183. #else
  184. template <class T> std::size_t hash_value(T* v)
  185. #endif
  186. {
  187. #if defined(__VMS) && __INITIAL_POINTER_SIZE == 64
  188. // for some reason ptrdiff_t on OpenVMS compiler with
  189. // 64 bit is not 64 bit !!!
  190. std::size_t x = static_cast<std::size_t>(
  191. reinterpret_cast<long long int>(v));
  192. #else
  193. std::size_t x = static_cast<std::size_t>(
  194. reinterpret_cast<std::ptrdiff_t>(v));
  195. #endif
  196. return x + (x >> 3);
  197. }
  198. #if defined(BOOST_MSVC)
  199. #pragma warning(push)
  200. #if BOOST_MSVC <= 1400
  201. #pragma warning(disable:4267) // 'argument' : conversion from 'size_t' to
  202. // 'unsigned int', possible loss of data
  203. // A misguided attempt to detect 64-bit
  204. // incompatability.
  205. #endif
  206. #endif
  207. #if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
  208. template <class T>
  209. inline void hash_combine(std::size_t& seed, T& v)
  210. #else
  211. template <class T>
  212. inline void hash_combine(std::size_t& seed, T const& v)
  213. #endif
  214. {
  215. boost::hash<T> hasher;
  216. seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
  217. }
  218. #if defined(BOOST_MSVC)
  219. #pragma warning(pop)
  220. #endif
  221. template <class It>
  222. inline std::size_t hash_range(It first, It last)
  223. {
  224. std::size_t seed = 0;
  225. for(; first != last; ++first)
  226. {
  227. hash_combine(seed, *first);
  228. }
  229. return seed;
  230. }
  231. template <class It>
  232. inline void hash_range(std::size_t& seed, It first, It last)
  233. {
  234. for(; first != last; ++first)
  235. {
  236. hash_combine(seed, *first);
  237. }
  238. }
  239. #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551))
  240. template <class T>
  241. inline std::size_t hash_range(T* first, T* last)
  242. {
  243. std::size_t seed = 0;
  244. for(; first != last; ++first)
  245. {
  246. boost::hash<T> hasher;
  247. seed ^= hasher(*first) + 0x9e3779b9 + (seed<<6) + (seed>>2);
  248. }
  249. return seed;
  250. }
  251. template <class T>
  252. inline void hash_range(std::size_t& seed, T* first, T* last)
  253. {
  254. for(; first != last; ++first)
  255. {
  256. boost::hash<T> hasher;
  257. seed ^= hasher(*first) + 0x9e3779b9 + (seed<<6) + (seed>>2);
  258. }
  259. }
  260. #endif
  261. #if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
  262. template< class T, unsigned N >
  263. inline std::size_t hash_value(const T (&x)[N])
  264. {
  265. return hash_range(x, x + N);
  266. }
  267. template< class T, unsigned N >
  268. inline std::size_t hash_value(T (&x)[N])
  269. {
  270. return hash_range(x, x + N);
  271. }
  272. #endif
  273. template <class Ch, class A>
  274. inline std::size_t hash_value(
  275. std::basic_string<Ch, std::BOOST_HASH_CHAR_TRAITS<Ch>, A> const& v)
  276. {
  277. return hash_range(v.begin(), v.end());
  278. }
  279. template <typename T>
  280. typename boost::hash_detail::float_numbers<T>::type hash_value(T v)
  281. {
  282. return boost::hash_detail::float_hash_value(v);
  283. }
  284. #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
  285. inline std::size_t hash_value(std::type_index v)
  286. {
  287. return v.hash_code();
  288. }
  289. #endif
  290. //
  291. // boost::hash
  292. //
  293. // Define the specializations required by the standard. The general purpose
  294. // boost::hash is defined later in extensions.hpp if
  295. // BOOST_HASH_NO_EXTENSIONS is not defined.
  296. // BOOST_HASH_SPECIALIZE - define a specialization for a type which is
  297. // passed by copy.
  298. //
  299. // BOOST_HASH_SPECIALIZE_REF - define a specialization for a type which is
  300. // passed by copy.
  301. //
  302. // These are undefined later.
  303. #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
  304. #define BOOST_HASH_SPECIALIZE(type) \
  305. template <> struct hash<type> \
  306. : public std::unary_function<type, std::size_t> \
  307. { \
  308. std::size_t operator()(type v) const \
  309. { \
  310. return boost::hash_value(v); \
  311. } \
  312. };
  313. #define BOOST_HASH_SPECIALIZE_REF(type) \
  314. template <> struct hash<type> \
  315. : public std::unary_function<type, std::size_t> \
  316. { \
  317. std::size_t operator()(type const& v) const \
  318. { \
  319. return boost::hash_value(v); \
  320. } \
  321. };
  322. #else
  323. #define BOOST_HASH_SPECIALIZE(type) \
  324. template <> struct hash<type> \
  325. : public std::unary_function<type, std::size_t> \
  326. { \
  327. std::size_t operator()(type v) const \
  328. { \
  329. return boost::hash_value(v); \
  330. } \
  331. }; \
  332. \
  333. template <> struct hash<const type> \
  334. : public std::unary_function<const type, std::size_t> \
  335. { \
  336. std::size_t operator()(const type v) const \
  337. { \
  338. return boost::hash_value(v); \
  339. } \
  340. };
  341. #define BOOST_HASH_SPECIALIZE_REF(type) \
  342. template <> struct hash<type> \
  343. : public std::unary_function<type, std::size_t> \
  344. { \
  345. std::size_t operator()(type const& v) const \
  346. { \
  347. return boost::hash_value(v); \
  348. } \
  349. }; \
  350. \
  351. template <> struct hash<const type> \
  352. : public std::unary_function<const type, std::size_t> \
  353. { \
  354. std::size_t operator()(type const& v) const \
  355. { \
  356. return boost::hash_value(v); \
  357. } \
  358. };
  359. #endif
  360. BOOST_HASH_SPECIALIZE(bool)
  361. BOOST_HASH_SPECIALIZE(char)
  362. BOOST_HASH_SPECIALIZE(signed char)
  363. BOOST_HASH_SPECIALIZE(unsigned char)
  364. #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
  365. BOOST_HASH_SPECIALIZE(wchar_t)
  366. #endif
  367. BOOST_HASH_SPECIALIZE(short)
  368. BOOST_HASH_SPECIALIZE(unsigned short)
  369. BOOST_HASH_SPECIALIZE(int)
  370. BOOST_HASH_SPECIALIZE(unsigned int)
  371. BOOST_HASH_SPECIALIZE(long)
  372. BOOST_HASH_SPECIALIZE(unsigned long)
  373. BOOST_HASH_SPECIALIZE(float)
  374. BOOST_HASH_SPECIALIZE(double)
  375. BOOST_HASH_SPECIALIZE(long double)
  376. BOOST_HASH_SPECIALIZE_REF(std::string)
  377. #if !defined(BOOST_NO_STD_WSTRING)
  378. BOOST_HASH_SPECIALIZE_REF(std::wstring)
  379. #endif
  380. #if !defined(BOOST_NO_LONG_LONG)
  381. BOOST_HASH_SPECIALIZE(boost::long_long_type)
  382. BOOST_HASH_SPECIALIZE(boost::ulong_long_type)
  383. #endif
  384. #if defined(BOOST_HAS_INT128)
  385. BOOST_HASH_SPECIALIZE(boost::int128_type)
  386. BOOST_HASH_SPECIALIZE(boost::uint128_type)
  387. #endif
  388. #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
  389. BOOST_HASH_SPECIALIZE(std::type_index)
  390. #endif
  391. #undef BOOST_HASH_SPECIALIZE
  392. #undef BOOST_HASH_SPECIALIZE_REF
  393. // Specializing boost::hash for pointers.
  394. #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
  395. template <class T>
  396. struct hash<T*>
  397. : public std::unary_function<T*, std::size_t>
  398. {
  399. std::size_t operator()(T* v) const
  400. {
  401. #if !BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590)
  402. return boost::hash_value(v);
  403. #else
  404. std::size_t x = static_cast<std::size_t>(
  405. reinterpret_cast<std::ptrdiff_t>(v));
  406. return x + (x >> 3);
  407. #endif
  408. }
  409. };
  410. #else
  411. // For compilers without partial specialization, we define a
  412. // boost::hash for all remaining types. But hash_impl is only defined
  413. // for pointers in 'extensions.hpp' - so when BOOST_HASH_NO_EXTENSIONS
  414. // is defined there will still be a compile error for types not supported
  415. // in the standard.
  416. namespace hash_detail
  417. {
  418. template <bool IsPointer>
  419. struct hash_impl;
  420. template <>
  421. struct hash_impl<true>
  422. {
  423. template <class T>
  424. struct inner
  425. : public std::unary_function<T, std::size_t>
  426. {
  427. std::size_t operator()(T val) const
  428. {
  429. #if !BOOST_WORKAROUND(__SUNPRO_CC, <= 590)
  430. return boost::hash_value(val);
  431. #else
  432. std::size_t x = static_cast<std::size_t>(
  433. reinterpret_cast<std::ptrdiff_t>(val));
  434. return x + (x >> 3);
  435. #endif
  436. }
  437. };
  438. };
  439. }
  440. template <class T> struct hash
  441. : public boost::hash_detail::hash_impl<boost::is_pointer<T>::value>
  442. ::BOOST_NESTED_TEMPLATE inner<T>
  443. {
  444. };
  445. #endif
  446. }
  447. #undef BOOST_HASH_CHAR_TRAITS
  448. #if defined(BOOST_MSVC)
  449. #pragma warning(pop)
  450. #endif
  451. #endif // BOOST_FUNCTIONAL_HASH_HASH_HPP
  452. // Include this outside of the include guards in case the file is included
  453. // twice - once with BOOST_HASH_NO_EXTENSIONS defined, and then with it
  454. // undefined.
  455. #if !defined(BOOST_HASH_NO_EXTENSIONS) \
  456. && !defined(BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP)
  457. #include <boost/functional/hash/extensions.hpp>
  458. #endif