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