]> git.lyx.org Git - lyx.git/blob - boost/boost/functional/hash/hash.hpp
Update boost to 1.53.0
[lyx.git] / boost / boost / functional / hash / hash.hpp
1
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(BOOST_FUNCTIONAL_HASH_HASH_HPP)
11 #define BOOST_FUNCTIONAL_HASH_HASH_HPP
12
13 #include <boost/functional/hash/hash_fwd.hpp>
14 #include <functional>
15 #include <boost/functional/hash/detail/hash_float.hpp>
16 #include <string>
17 #include <boost/limits.hpp>
18 #include <boost/type_traits/is_enum.hpp>
19 #include <boost/type_traits/is_integral.hpp>
20 #include <boost/utility/enable_if.hpp>
21
22 #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
23 #include <boost/type_traits/is_pointer.hpp>
24 #endif
25
26 #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
27 #include <typeindex>
28 #endif
29
30 #if BOOST_WORKAROUND(__GNUC__, < 3) \
31     && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)
32 #define BOOST_HASH_CHAR_TRAITS string_char_traits
33 #else
34 #define BOOST_HASH_CHAR_TRAITS char_traits
35 #endif
36
37 namespace boost
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             boost::hash_detail::enable_hash_value {};
50         template <> struct basic_numbers<char> :
51             boost::hash_detail::enable_hash_value {};
52         template <> struct basic_numbers<unsigned char> :
53             boost::hash_detail::enable_hash_value {};
54         template <> struct basic_numbers<signed char> :
55             boost::hash_detail::enable_hash_value {};
56         template <> struct basic_numbers<short> :
57             boost::hash_detail::enable_hash_value {};
58         template <> struct basic_numbers<unsigned short> :
59             boost::hash_detail::enable_hash_value {};
60         template <> struct basic_numbers<int> :
61             boost::hash_detail::enable_hash_value {};
62         template <> struct basic_numbers<unsigned int> :
63             boost::hash_detail::enable_hash_value {};
64         template <> struct basic_numbers<long> :
65             boost::hash_detail::enable_hash_value {};
66         template <> struct basic_numbers<unsigned long> :
67             boost::hash_detail::enable_hash_value {};
68
69 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
70         template <> struct basic_numbers<wchar_t> :
71             boost::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(BOOST_NO_LONG_LONG)
83         template <> struct long_numbers<boost::long_long_type> :
84             boost::hash_detail::enable_hash_value {};
85         template <> struct ulong_numbers<boost::ulong_long_type> :
86             boost::hash_detail::enable_hash_value {};
87 #endif
88
89 #if defined(BOOST_HAS_INT128)
90         template <> struct long_numbers2<boost::int128_type> :
91             boost::hash_detail::enable_hash_value {};
92         template <> struct ulong_numbers2<boost::uint128_type> :
93             boost::hash_detail::enable_hash_value {};
94 #endif
95
96         template <> struct float_numbers<float> :
97             boost::hash_detail::enable_hash_value {};
98         template <> struct float_numbers<double> :
99             boost::hash_detail::enable_hash_value {};
100         template <> struct float_numbers<long double> :
101             boost::hash_detail::enable_hash_value {};
102     }
103
104     template <typename T>
105     typename boost::hash_detail::basic_numbers<T>::type hash_value(T);
106     template <typename T>
107     typename boost::hash_detail::long_numbers<T>::type hash_value(T);
108     template <typename T>
109     typename boost::hash_detail::ulong_numbers<T>::type hash_value(T);
110
111     template <typename T>
112     typename boost::enable_if<boost::is_enum<T>, std::size_t>::type
113         hash_value(T);
114
115 #if !BOOST_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(BOOST_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::BOOST_HASH_CHAR_TRAITS<Ch>, A> const&);
132
133     template <typename T>
134     typename boost::hash_detail::float_numbers<T>::type hash_value(T);
135
136 #if !defined(BOOST_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 boost::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 boost::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 boost::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 boost::enable_if<boost::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 !BOOST_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(BOOST_MSVC)
231 #pragma warning(push)
232 #if BOOST_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 BOOST_WORKAROUND(BOOST_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         boost::hash<T> hasher;
249         seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
250     }
251
252 #if defined(BOOST_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 BOOST_WORKAROUND(__BORLANDC__, BOOST_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             boost::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             boost::hash<T> hasher;
299             seed ^= hasher(*first) + 0x9e3779b9 + (seed<<6) + (seed>>2);
300         }
301     }
302 #endif
303
304 #if !defined(BOOST_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::BOOST_HASH_CHAR_TRAITS<Ch>, A> const& v)
321     {
322         return hash_range(v.begin(), v.end());
323     }
324
325     template <typename T>
326     typename boost::hash_detail::float_numbers<T>::type hash_value(T v)
327     {
328         return boost::hash_detail::float_hash_value(v);
329     }
330
331 #if !defined(BOOST_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     // boost::hash
340     //
341     
342     // Define the specializations required by the standard. The general purpose
343     // boost::hash is defined later in extensions.hpp if
344     // BOOST_HASH_NO_EXTENSIONS is not defined.
345     
346     // BOOST_HASH_SPECIALIZE - define a specialization for a type which is
347     // passed by copy.
348     //
349     // BOOST_HASH_SPECIALIZE_REF - define a specialization for a type which is
350     // passed by copy.
351     //
352     // These are undefined later.
353
354 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
355 #define BOOST_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 boost::hash_value(v); \
362         } \
363     };
364
365 #define BOOST_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 boost::hash_value(v); \
372         } \
373     };
374 #else
375 #define BOOST_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 boost::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 boost::hash_value(v); \
391         } \
392     };
393
394 #define BOOST_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 boost::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 boost::hash_value(v); \
410         } \
411     };
412 #endif
413
414     BOOST_HASH_SPECIALIZE(bool)
415     BOOST_HASH_SPECIALIZE(char)
416     BOOST_HASH_SPECIALIZE(signed char)
417     BOOST_HASH_SPECIALIZE(unsigned char)
418 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
419     BOOST_HASH_SPECIALIZE(wchar_t)
420 #endif
421     BOOST_HASH_SPECIALIZE(short)
422     BOOST_HASH_SPECIALIZE(unsigned short)
423     BOOST_HASH_SPECIALIZE(int)
424     BOOST_HASH_SPECIALIZE(unsigned int)
425     BOOST_HASH_SPECIALIZE(long)
426     BOOST_HASH_SPECIALIZE(unsigned long)
427
428     BOOST_HASH_SPECIALIZE(float)
429     BOOST_HASH_SPECIALIZE(double)
430     BOOST_HASH_SPECIALIZE(long double)
431
432     BOOST_HASH_SPECIALIZE_REF(std::string)
433 #if !defined(BOOST_NO_STD_WSTRING)
434     BOOST_HASH_SPECIALIZE_REF(std::wstring)
435 #endif
436
437 #if !defined(BOOST_NO_LONG_LONG)
438     BOOST_HASH_SPECIALIZE(boost::long_long_type)
439     BOOST_HASH_SPECIALIZE(boost::ulong_long_type)
440 #endif
441
442 #if defined(BOOST_HAS_INT128)
443     BOOST_HASH_SPECIALIZE(boost::int128_type)
444     BOOST_HASH_SPECIALIZE(boost::uint128_type)
445 #endif
446
447 #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
448     BOOST_HASH_SPECIALIZE(std::type_index)
449 #endif
450
451 #undef BOOST_HASH_SPECIALIZE
452 #undef BOOST_HASH_SPECIALIZE_REF
453
454 // Specializing boost::hash for pointers.
455
456 #if !defined(BOOST_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 !BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590)
465             return boost::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     // boost::hash for all remaining types. But hash_impl is only defined
479     // for pointers in 'extensions.hpp' - so when BOOST_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 !BOOST_WORKAROUND(__SUNPRO_CC, <= 590)
498                     return boost::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 boost::hash_detail::hash_impl<boost::is_pointer<T>::value>
512             ::BOOST_NESTED_TEMPLATE inner<T>
513     {
514     };
515
516 #endif
517 }
518
519 #undef BOOST_HASH_CHAR_TRAITS
520
521 #endif // BOOST_FUNCTIONAL_HASH_HASH_HPP
522
523 // Include this outside of the include guards in case the file is included
524 // twice - once with BOOST_HASH_NO_EXTENSIONS defined, and then with it
525 // undefined.
526
527 #if !defined(BOOST_HASH_NO_EXTENSIONS) \
528     && !defined(BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP)
529 #include <boost/functional/hash/extensions.hpp>
530 #endif