Merge c:/dyninst/pc_bluegene/dyninst into dyn_pc_integration
[dyninst.git] / external / boost / functional / detail / hash_float.hpp
1
2 // Copyright 2005-2008 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_DETAIL_HASH_FLOAT_HEADER)
11 #define BOOST_FUNCTIONAL_DETAIL_HASH_FLOAT_HEADER
12
13 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
14 # pragma once
15 #endif
16
17 #if defined(BOOST_MSVC)
18 #pragma warning(push)
19 #if BOOST_MSVC >= 1400
20 #pragma warning(disable:6294) // Ill-defined for-loop: initial condition does
21                               // not satisfy test. Loop body not executed 
22 #endif
23 #endif
24
25 #include <boost/functional/detail/float_functions.hpp>
26 #include <boost/integer/static_log2.hpp>
27 #include <boost/cstdint.hpp>
28 #include <boost/limits.hpp>
29 #include <boost/assert.hpp>
30
31 // Select implementation for the current platform.
32
33 // Cygwn
34 #if defined(__CYGWIN__)
35 #  if defined(__i386__) || defined(_M_IX86)
36 #    define BOOST_HASH_USE_x86_BINARY_HASH
37 #  endif
38
39 // STLport
40 #elif defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
41 // fpclassify aren't good enough on STLport.
42
43 // GNU libstdc++ 3
44 #elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
45 #  if (defined(__USE_ISOC99) || defined(_GLIBCXX_USE_C99_MATH)) && \
46       !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
47 #    define BOOST_HASH_USE_FPCLASSIFY
48 #  endif
49
50 // Dinkumware Library, on Visual C++ 
51 #elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
52
53 // Not using _fpclass because it is only available for double.
54
55 #endif
56
57 // On OpenBSD, numeric_limits is not reliable for long doubles, but
58 // the macros defined in <float.h> are.
59
60 #if defined(__OpenBSD__)
61 #include <float.h>
62 #endif
63
64 namespace boost
65 {
66     namespace hash_detail
67     {
68         template <class T>
69         struct limits : std::numeric_limits<T> {};
70
71 #if defined(__OpenBSD__)
72         template <>
73         struct limits<long double>
74              : std::numeric_limits<long double>
75         {
76             static long double epsilon() {
77                 return LDBL_EPSILON;
78             }
79
80             static long double (max)() {
81                 return LDBL_MAX;
82             }
83
84             static long double (min)() {
85                 return LDBL_MIN;
86             }
87
88             BOOST_STATIC_CONSTANT(int, digits = LDBL_MANT_DIG);
89             BOOST_STATIC_CONSTANT(int, max_exponent = LDBL_MAX_EXP);
90             BOOST_STATIC_CONSTANT(int, min_exponent = LDBL_MIN_EXP);
91         };
92 #endif // __OpenBSD__
93
94         inline void hash_float_combine(std::size_t& seed, std::size_t value)
95         {
96             seed ^= value + (seed<<6) + (seed>>2);
97         }
98
99 // A simple, non-portable hash algorithm for x86.
100 #if defined(BOOST_HASH_USE_x86_BINARY_HASH)
101         inline std::size_t float_hash_impl(float v)
102         {
103             boost::uint32_t* ptr = (boost::uint32_t*)&v;
104             std::size_t seed = *ptr;
105             return seed;
106         }
107
108         inline std::size_t float_hash_impl(double v)
109         {
110             boost::uint32_t* ptr = (boost::uint32_t*)&v;
111             std::size_t seed = *ptr++;
112             hash_float_combine(seed, *ptr);
113             return seed;
114         }
115
116         inline std::size_t float_hash_impl(long double v)
117         {
118             boost::uint32_t* ptr = (boost::uint32_t*)&v;
119             std::size_t seed = *ptr++;
120             hash_float_combine(seed, *ptr++);
121             hash_float_combine(seed, *(boost::uint16_t*)ptr);
122             return seed;
123         }
124
125 #else
126
127         template <class T>
128         inline std::size_t float_hash_impl(T v)
129         {
130             int exp = 0;
131
132             v = boost::hash_detail::call_frexp(v, &exp);
133
134             // A postive value is easier to hash, so combine the
135             // sign with the exponent.
136             if(v < 0) {
137                 v = -v;
138                 exp += limits<T>::max_exponent -
139                     limits<T>::min_exponent;
140             }
141
142             // The result of frexp is always between 0.5 and 1, so its
143             // top bit will always be 1. Subtract by 0.5 to remove that.
144             v -= T(0.5);
145             v = boost::hash_detail::call_ldexp(v,
146                     limits<std::size_t>::digits + 1);
147             std::size_t seed = static_cast<std::size_t>(v);
148             v -= seed;
149
150             // ceiling(digits(T) * log2(radix(T))/ digits(size_t)) - 1;
151             std::size_t const length
152                 = (limits<T>::digits *
153                         boost::static_log2<limits<T>::radix>::value - 1)
154                 / limits<std::size_t>::digits;
155
156             for(std::size_t i = 0; i != length; ++i)
157             {
158                 v = boost::hash_detail::call_ldexp(v,
159                         limits<std::size_t>::digits);
160                 std::size_t part = static_cast<std::size_t>(v);
161                 v -= part;
162                 hash_float_combine(seed, part);
163             }
164
165             hash_float_combine(seed, exp);
166
167             return seed;
168         }
169 #endif
170
171         template <class T>
172         inline std::size_t float_hash_value(T v)
173         {
174 #if defined(BOOST_HASH_USE_FPCLASSIFY)
175             using namespace std;
176             switch (fpclassify(v)) {
177             case FP_ZERO:
178                 return 0;
179             case FP_INFINITE:
180                 return (std::size_t)(v > 0 ? -1 : -2);
181             case FP_NAN:
182                 return (std::size_t)(-3);
183             case FP_NORMAL:
184             case FP_SUBNORMAL:
185                 return float_hash_impl(v);
186             default:
187                 BOOST_ASSERT(0);
188                 return 0;
189             }
190 #else
191             return v == 0 ? 0 : float_hash_impl(v);
192 #endif
193         }
194     }
195 }
196
197 #if defined(BOOST_MSVC)
198 #pragma warning(pop)
199 #endif
200
201 #endif