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