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