Chris@16
|
1
|
Chris@16
|
2 // Copyright 2005-2009 Daniel James.
|
Chris@16
|
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5
|
Chris@16
|
6 #if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP)
|
Chris@16
|
7 #define BOOST_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP
|
Chris@16
|
8
|
Chris@16
|
9 #include <boost/config.hpp>
|
Chris@101
|
10 #if defined(BOOST_HAS_PRAGMA_ONCE)
|
Chris@101
|
11 #pragma once
|
Chris@101
|
12 #endif
|
Chris@101
|
13
|
Chris@16
|
14 #include <boost/config/no_tr1/cmath.hpp>
|
Chris@16
|
15
|
Chris@16
|
16 // Set BOOST_HASH_CONFORMANT_FLOATS to 1 for libraries known to have
|
Chris@16
|
17 // sufficiently good floating point support to not require any
|
Chris@16
|
18 // workarounds.
|
Chris@16
|
19 //
|
Chris@16
|
20 // When set to 0, the library tries to automatically
|
Chris@16
|
21 // use the best available implementation. This normally works well, but
|
Chris@16
|
22 // breaks when ambiguities are created by odd namespacing of the functions.
|
Chris@16
|
23 //
|
Chris@16
|
24 // Note that if this is set to 0, the library should still take full
|
Chris@16
|
25 // advantage of the platform's floating point support.
|
Chris@16
|
26
|
Chris@16
|
27 #if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
|
Chris@16
|
28 # define BOOST_HASH_CONFORMANT_FLOATS 0
|
Chris@16
|
29 #elif defined(__LIBCOMO__)
|
Chris@16
|
30 # define BOOST_HASH_CONFORMANT_FLOATS 0
|
Chris@16
|
31 #elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
|
Chris@16
|
32 // Rogue Wave library:
|
Chris@16
|
33 # define BOOST_HASH_CONFORMANT_FLOATS 0
|
Chris@16
|
34 #elif defined(_LIBCPP_VERSION)
|
Chris@16
|
35 // libc++
|
Chris@16
|
36 # define BOOST_HASH_CONFORMANT_FLOATS 1
|
Chris@16
|
37 #elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
|
Chris@16
|
38 // GNU libstdc++ 3
|
Chris@16
|
39 # if defined(__GNUC__) && __GNUC__ >= 4
|
Chris@16
|
40 # define BOOST_HASH_CONFORMANT_FLOATS 1
|
Chris@16
|
41 # else
|
Chris@16
|
42 # define BOOST_HASH_CONFORMANT_FLOATS 0
|
Chris@16
|
43 # endif
|
Chris@16
|
44 #elif defined(__STL_CONFIG_H)
|
Chris@16
|
45 // generic SGI STL
|
Chris@16
|
46 # define BOOST_HASH_CONFORMANT_FLOATS 0
|
Chris@16
|
47 #elif defined(__MSL_CPP__)
|
Chris@16
|
48 // MSL standard lib:
|
Chris@16
|
49 # define BOOST_HASH_CONFORMANT_FLOATS 0
|
Chris@16
|
50 #elif defined(__IBMCPP__)
|
Chris@16
|
51 // VACPP std lib (probably conformant for much earlier version).
|
Chris@16
|
52 # if __IBMCPP__ >= 1210
|
Chris@16
|
53 # define BOOST_HASH_CONFORMANT_FLOATS 1
|
Chris@16
|
54 # else
|
Chris@16
|
55 # define BOOST_HASH_CONFORMANT_FLOATS 0
|
Chris@16
|
56 # endif
|
Chris@16
|
57 #elif defined(MSIPL_COMPILE_H)
|
Chris@16
|
58 // Modena C++ standard library
|
Chris@16
|
59 # define BOOST_HASH_CONFORMANT_FLOATS 0
|
Chris@16
|
60 #elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
|
Chris@16
|
61 // Dinkumware Library (this has to appear after any possible replacement libraries):
|
Chris@16
|
62 # if _CPPLIB_VER >= 405
|
Chris@16
|
63 # define BOOST_HASH_CONFORMANT_FLOATS 1
|
Chris@16
|
64 # else
|
Chris@16
|
65 # define BOOST_HASH_CONFORMANT_FLOATS 0
|
Chris@16
|
66 # endif
|
Chris@16
|
67 #else
|
Chris@16
|
68 # define BOOST_HASH_CONFORMANT_FLOATS 0
|
Chris@16
|
69 #endif
|
Chris@16
|
70
|
Chris@16
|
71 #if BOOST_HASH_CONFORMANT_FLOATS
|
Chris@16
|
72
|
Chris@16
|
73 // The standard library is known to be compliant, so don't use the
|
Chris@16
|
74 // configuration mechanism.
|
Chris@16
|
75
|
Chris@16
|
76 namespace boost {
|
Chris@16
|
77 namespace hash_detail {
|
Chris@16
|
78 template <typename Float>
|
Chris@16
|
79 struct call_ldexp {
|
Chris@16
|
80 typedef Float float_type;
|
Chris@16
|
81 inline Float operator()(Float x, int y) const {
|
Chris@16
|
82 return std::ldexp(x, y);
|
Chris@16
|
83 }
|
Chris@16
|
84 };
|
Chris@16
|
85
|
Chris@16
|
86 template <typename Float>
|
Chris@16
|
87 struct call_frexp {
|
Chris@16
|
88 typedef Float float_type;
|
Chris@16
|
89 inline Float operator()(Float x, int* y) const {
|
Chris@16
|
90 return std::frexp(x, y);
|
Chris@16
|
91 }
|
Chris@16
|
92 };
|
Chris@16
|
93
|
Chris@16
|
94 template <typename Float>
|
Chris@16
|
95 struct select_hash_type
|
Chris@16
|
96 {
|
Chris@16
|
97 typedef Float type;
|
Chris@16
|
98 };
|
Chris@16
|
99 }
|
Chris@16
|
100 }
|
Chris@16
|
101
|
Chris@16
|
102 #else // BOOST_HASH_CONFORMANT_FLOATS == 0
|
Chris@16
|
103
|
Chris@16
|
104 // The C++ standard requires that the C float functions are overloarded
|
Chris@16
|
105 // for float, double and long double in the std namespace, but some of the older
|
Chris@16
|
106 // library implementations don't support this. On some that don't, the C99
|
Chris@16
|
107 // float functions (frexpf, frexpl, etc.) are available.
|
Chris@16
|
108 //
|
Chris@16
|
109 // The following tries to automatically detect which are available.
|
Chris@16
|
110
|
Chris@16
|
111 namespace boost {
|
Chris@16
|
112 namespace hash_detail {
|
Chris@16
|
113
|
Chris@16
|
114 // Returned by dummy versions of the float functions.
|
Chris@16
|
115
|
Chris@16
|
116 struct not_found {
|
Chris@16
|
117 // Implicitly convertible to float and long double in order to avoid
|
Chris@16
|
118 // a compile error when the dummy float functions are used.
|
Chris@16
|
119
|
Chris@16
|
120 inline operator float() const { return 0; }
|
Chris@16
|
121 inline operator long double() const { return 0; }
|
Chris@16
|
122 };
|
Chris@16
|
123
|
Chris@16
|
124 // A type for detecting the return type of functions.
|
Chris@16
|
125
|
Chris@16
|
126 template <typename T> struct is;
|
Chris@16
|
127 template <> struct is<float> { char x[10]; };
|
Chris@16
|
128 template <> struct is<double> { char x[20]; };
|
Chris@16
|
129 template <> struct is<long double> { char x[30]; };
|
Chris@16
|
130 template <> struct is<boost::hash_detail::not_found> { char x[40]; };
|
Chris@16
|
131
|
Chris@16
|
132 // Used to convert the return type of a function to a type for sizeof.
|
Chris@16
|
133
|
Chris@16
|
134 template <typename T> is<T> float_type(T);
|
Chris@16
|
135
|
Chris@16
|
136 // call_ldexp
|
Chris@16
|
137 //
|
Chris@16
|
138 // This will get specialized for float and long double
|
Chris@16
|
139
|
Chris@16
|
140 template <typename Float> struct call_ldexp
|
Chris@16
|
141 {
|
Chris@16
|
142 typedef double float_type;
|
Chris@16
|
143
|
Chris@16
|
144 inline double operator()(double a, int b) const
|
Chris@16
|
145 {
|
Chris@16
|
146 using namespace std;
|
Chris@16
|
147 return ldexp(a, b);
|
Chris@16
|
148 }
|
Chris@16
|
149 };
|
Chris@16
|
150
|
Chris@16
|
151 // call_frexp
|
Chris@16
|
152 //
|
Chris@16
|
153 // This will get specialized for float and long double
|
Chris@16
|
154
|
Chris@16
|
155 template <typename Float> struct call_frexp
|
Chris@16
|
156 {
|
Chris@16
|
157 typedef double float_type;
|
Chris@16
|
158
|
Chris@16
|
159 inline double operator()(double a, int* b) const
|
Chris@16
|
160 {
|
Chris@16
|
161 using namespace std;
|
Chris@16
|
162 return frexp(a, b);
|
Chris@16
|
163 }
|
Chris@16
|
164 };
|
Chris@16
|
165 }
|
Chris@16
|
166 }
|
Chris@16
|
167
|
Chris@16
|
168 // A namespace for dummy functions to detect when the actual function we want
|
Chris@16
|
169 // isn't available. ldexpl, ldexpf etc. might be added tby the macros below.
|
Chris@16
|
170 //
|
Chris@16
|
171 // AFAICT these have to be outside of the boost namespace, as if they're in
|
Chris@16
|
172 // the boost namespace they'll always be preferable to any other function
|
Chris@16
|
173 // (since the arguments are built in types, ADL can't be used).
|
Chris@16
|
174
|
Chris@16
|
175 namespace boost_hash_detect_float_functions {
|
Chris@16
|
176 template <class Float> boost::hash_detail::not_found ldexp(Float, int);
|
Chris@16
|
177 template <class Float> boost::hash_detail::not_found frexp(Float, int*);
|
Chris@16
|
178 }
|
Chris@16
|
179
|
Chris@16
|
180 // Macros for generating specializations of call_ldexp and call_frexp.
|
Chris@16
|
181 //
|
Chris@16
|
182 // check_cpp and check_c99 check if the C++ or C99 functions are available.
|
Chris@16
|
183 //
|
Chris@16
|
184 // Then the call_* functions select an appropriate implementation.
|
Chris@16
|
185 //
|
Chris@16
|
186 // I used c99_func in a few places just to get a unique name.
|
Chris@16
|
187 //
|
Chris@16
|
188 // Important: when using 'using namespace' at namespace level, include as
|
Chris@16
|
189 // little as possible in that namespace, as Visual C++ has an odd bug which
|
Chris@16
|
190 // can cause the namespace to be imported at the global level. This seems to
|
Chris@16
|
191 // happen mainly when there's a template in the same namesapce.
|
Chris@16
|
192
|
Chris@16
|
193 #define BOOST_HASH_CALL_FLOAT_FUNC(cpp_func, c99_func, type1, type2) \
|
Chris@16
|
194 namespace boost_hash_detect_float_functions { \
|
Chris@16
|
195 template <class Float> \
|
Chris@16
|
196 boost::hash_detail::not_found c99_func(Float, type2); \
|
Chris@16
|
197 } \
|
Chris@16
|
198 \
|
Chris@16
|
199 namespace boost { \
|
Chris@16
|
200 namespace hash_detail { \
|
Chris@16
|
201 namespace c99_func##_detect { \
|
Chris@16
|
202 using namespace std; \
|
Chris@16
|
203 using namespace boost_hash_detect_float_functions; \
|
Chris@16
|
204 \
|
Chris@16
|
205 struct check { \
|
Chris@16
|
206 static type1 x; \
|
Chris@16
|
207 static type2 y; \
|
Chris@16
|
208 BOOST_STATIC_CONSTANT(bool, cpp = \
|
Chris@16
|
209 sizeof(float_type(cpp_func(x,y))) \
|
Chris@16
|
210 == sizeof(is<type1>)); \
|
Chris@16
|
211 BOOST_STATIC_CONSTANT(bool, c99 = \
|
Chris@16
|
212 sizeof(float_type(c99_func(x,y))) \
|
Chris@16
|
213 == sizeof(is<type1>)); \
|
Chris@16
|
214 }; \
|
Chris@16
|
215 } \
|
Chris@16
|
216 \
|
Chris@16
|
217 template <bool x> \
|
Chris@16
|
218 struct call_c99_##c99_func : \
|
Chris@16
|
219 boost::hash_detail::call_##cpp_func<double> {}; \
|
Chris@16
|
220 \
|
Chris@16
|
221 template <> \
|
Chris@16
|
222 struct call_c99_##c99_func<true> { \
|
Chris@16
|
223 typedef type1 float_type; \
|
Chris@16
|
224 \
|
Chris@16
|
225 template <typename T> \
|
Chris@16
|
226 inline type1 operator()(type1 a, T b) const \
|
Chris@16
|
227 { \
|
Chris@16
|
228 using namespace std; \
|
Chris@16
|
229 return c99_func(a, b); \
|
Chris@16
|
230 } \
|
Chris@16
|
231 }; \
|
Chris@16
|
232 \
|
Chris@16
|
233 template <bool x> \
|
Chris@16
|
234 struct call_cpp_##c99_func : \
|
Chris@16
|
235 call_c99_##c99_func< \
|
Chris@16
|
236 ::boost::hash_detail::c99_func##_detect::check::c99 \
|
Chris@16
|
237 > {}; \
|
Chris@16
|
238 \
|
Chris@16
|
239 template <> \
|
Chris@16
|
240 struct call_cpp_##c99_func<true> { \
|
Chris@16
|
241 typedef type1 float_type; \
|
Chris@16
|
242 \
|
Chris@16
|
243 template <typename T> \
|
Chris@16
|
244 inline type1 operator()(type1 a, T b) const \
|
Chris@16
|
245 { \
|
Chris@16
|
246 using namespace std; \
|
Chris@16
|
247 return cpp_func(a, b); \
|
Chris@16
|
248 } \
|
Chris@16
|
249 }; \
|
Chris@16
|
250 \
|
Chris@16
|
251 template <> \
|
Chris@16
|
252 struct call_##cpp_func<type1> : \
|
Chris@16
|
253 call_cpp_##c99_func< \
|
Chris@16
|
254 ::boost::hash_detail::c99_func##_detect::check::cpp \
|
Chris@16
|
255 > {}; \
|
Chris@16
|
256 } \
|
Chris@16
|
257 }
|
Chris@16
|
258
|
Chris@16
|
259 #define BOOST_HASH_CALL_FLOAT_MACRO(cpp_func, c99_func, type1, type2) \
|
Chris@16
|
260 namespace boost { \
|
Chris@16
|
261 namespace hash_detail { \
|
Chris@16
|
262 \
|
Chris@16
|
263 template <> \
|
Chris@16
|
264 struct call_##cpp_func<type1> { \
|
Chris@16
|
265 typedef type1 float_type; \
|
Chris@16
|
266 inline type1 operator()(type1 x, type2 y) const { \
|
Chris@16
|
267 return c99_func(x, y); \
|
Chris@16
|
268 } \
|
Chris@16
|
269 }; \
|
Chris@16
|
270 } \
|
Chris@16
|
271 }
|
Chris@16
|
272
|
Chris@16
|
273 #if defined(ldexpf)
|
Chris@16
|
274 BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpf, float, int)
|
Chris@16
|
275 #else
|
Chris@16
|
276 BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpf, float, int)
|
Chris@16
|
277 #endif
|
Chris@16
|
278
|
Chris@16
|
279 #if defined(ldexpl)
|
Chris@16
|
280 BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpl, long double, int)
|
Chris@16
|
281 #else
|
Chris@16
|
282 BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpl, long double, int)
|
Chris@16
|
283 #endif
|
Chris@16
|
284
|
Chris@16
|
285 #if defined(frexpf)
|
Chris@16
|
286 BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpf, float, int*)
|
Chris@16
|
287 #else
|
Chris@16
|
288 BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpf, float, int*)
|
Chris@16
|
289 #endif
|
Chris@16
|
290
|
Chris@16
|
291 #if defined(frexpl)
|
Chris@16
|
292 BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpl, long double, int*)
|
Chris@16
|
293 #else
|
Chris@16
|
294 BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpl, long double, int*)
|
Chris@16
|
295 #endif
|
Chris@16
|
296
|
Chris@16
|
297 #undef BOOST_HASH_CALL_FLOAT_MACRO
|
Chris@16
|
298 #undef BOOST_HASH_CALL_FLOAT_FUNC
|
Chris@16
|
299
|
Chris@16
|
300
|
Chris@16
|
301 namespace boost
|
Chris@16
|
302 {
|
Chris@16
|
303 namespace hash_detail
|
Chris@16
|
304 {
|
Chris@16
|
305 template <typename Float1, typename Float2>
|
Chris@16
|
306 struct select_hash_type_impl {
|
Chris@16
|
307 typedef double type;
|
Chris@16
|
308 };
|
Chris@16
|
309
|
Chris@16
|
310 template <>
|
Chris@16
|
311 struct select_hash_type_impl<float, float> {
|
Chris@16
|
312 typedef float type;
|
Chris@16
|
313 };
|
Chris@16
|
314
|
Chris@16
|
315 template <>
|
Chris@16
|
316 struct select_hash_type_impl<long double, long double> {
|
Chris@16
|
317 typedef long double type;
|
Chris@16
|
318 };
|
Chris@16
|
319
|
Chris@16
|
320
|
Chris@16
|
321 // select_hash_type
|
Chris@16
|
322 //
|
Chris@16
|
323 // If there is support for a particular floating point type, use that
|
Chris@16
|
324 // otherwise use double (there's always support for double).
|
Chris@16
|
325
|
Chris@16
|
326 template <typename Float>
|
Chris@16
|
327 struct select_hash_type : select_hash_type_impl<
|
Chris@16
|
328 BOOST_DEDUCED_TYPENAME call_ldexp<Float>::float_type,
|
Chris@16
|
329 BOOST_DEDUCED_TYPENAME call_frexp<Float>::float_type
|
Chris@16
|
330 > {};
|
Chris@16
|
331 }
|
Chris@16
|
332 }
|
Chris@16
|
333
|
Chris@16
|
334 #endif // BOOST_HASH_CONFORMANT_FLOATS
|
Chris@16
|
335
|
Chris@16
|
336 #endif
|