Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / functional / hash / detail / float_functions.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 #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
76 namespace 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
111 namespace 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
175 namespace 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)    \
194 namespace boost_hash_detect_float_functions {                           \
195     template <class Float>                                              \
196     boost::hash_detail::not_found c99_func(Float, type2);               \
197 }                                                                       \
198                                                                         \
199 namespace 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)   \
260 namespace 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)
274 BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpf, float, int)
275 #else
276 BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpf, float, int)
277 #endif
278
279 #if defined(ldexpl)
280 BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpl, long double, int)
281 #else
282 BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpl, long double, int)
283 #endif
284
285 #if defined(frexpf)
286 BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpf, float, int*)
287 #else
288 BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpf, float, int*)
289 #endif
290
291 #if defined(frexpl)
292 BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpl, long double, int*)
293 #else
294 BOOST_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
301 namespace 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