]> git.lyx.org Git - features.git/blob - boost/boost/functional/hash/detail/float_functions.hpp
boost: update to 1.42.0
[features.git] / boost / 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 #include <boost/config/no_tr1/cmath.hpp>
11
12 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
13 # pragma once
14 #endif
15
16 // The C++ standard requires that the C float functions are overloarded
17 // for float, double and long double in the std namespace, but some of the older
18 // library implementations don't support this. On some that don't, the C99
19 // float functions (frexpf, frexpl, etc.) are available.
20 //
21 // The following tries to automatically detect which are available.
22
23 namespace boost {
24     namespace hash_detail {
25
26         // Returned by dummy versions of the float functions.
27     
28         struct not_found {
29             // Implicitly convertible to float and long double in order to avoid
30             // a compile error when the dummy float functions are used.
31
32             inline operator float() const { return 0; }
33             inline operator long double() const { return 0; }
34         };
35           
36         // A type for detecting the return type of functions.
37
38         template <typename T> struct is;
39         template <> struct is<float> { char x[10]; };
40         template <> struct is<double> { char x[20]; };
41         template <> struct is<long double> { char x[30]; };
42         template <> struct is<boost::hash_detail::not_found> { char x[40]; };
43             
44         // Used to convert the return type of a function to a type for sizeof.
45
46         template <typename T> is<T> float_type(T);
47
48         // call_ldexp
49         //
50         // This will get specialized for float and long double
51         
52         template <typename Float> struct call_ldexp
53         {
54             typedef double float_type;
55             
56             inline double operator()(double a, int b) const
57             {
58                 using namespace std;
59                 return ldexp(a, b);
60             }
61         };
62
63         // call_frexp
64         //
65         // This will get specialized for float and long double
66
67         template <typename Float> struct call_frexp
68         {
69             typedef double float_type;
70             
71             inline double operator()(double a, int* b) const
72             {
73                 using namespace std;
74                 return frexp(a, b);
75             }
76         };
77     }
78 }
79             
80 // A namespace for dummy functions to detect when the actual function we want
81 // isn't available. ldexpl, ldexpf etc. might be added tby the macros below.
82 //
83 // AFAICT these have to be outside of the boost namespace, as if they're in
84 // the boost namespace they'll always be preferable to any other function
85 // (since the arguments are built in types, ADL can't be used).
86
87 namespace boost_hash_detect_float_functions {
88     template <class Float> boost::hash_detail::not_found ldexp(Float, int);
89     template <class Float> boost::hash_detail::not_found frexp(Float, int*);    
90 }
91
92 // Macros for generating specializations of call_ldexp and call_frexp.
93 //
94 // check_cpp and check_c99 check if the C++ or C99 functions are available.
95 //
96 // Then the call_* functions select an appropriate implementation.
97 //
98 // I used c99_func in a few places just to get a unique name.
99 //
100 // Important: when using 'using namespace' at namespace level, include as
101 // little as possible in that namespace, as Visual C++ has an odd bug which
102 // can cause the namespace to be imported at the global level. This seems to
103 // happen mainly when there's a template in the same namesapce.
104
105 #define BOOST_HASH_CALL_FLOAT_FUNC(cpp_func, c99_func, type1, type2)    \
106 namespace boost_hash_detect_float_functions {                           \
107     template <class Float>                                              \
108     boost::hash_detail::not_found c99_func(Float, type2);               \
109 }                                                                       \
110                                                                         \
111 namespace boost {                                                       \
112     namespace hash_detail {                                             \
113         namespace c99_func##_detect {                                   \
114             using namespace std;                                        \
115             using namespace boost_hash_detect_float_functions;          \
116                                                                         \
117             struct check {                                              \
118                 static type1 x;                                         \
119                 static type2 y;                                         \
120                 BOOST_STATIC_CONSTANT(bool, cpp =                       \
121                     sizeof(float_type(cpp_func(x,y)))                   \
122                         == sizeof(is<type1>));                          \
123                 BOOST_STATIC_CONSTANT(bool, c99 =                       \
124                     sizeof(float_type(c99_func(x,y)))                   \
125                         == sizeof(is<type1>));                          \
126             };                                                          \
127         }                                                               \
128                                                                         \
129         template <bool x>                                               \
130         struct call_c99_##c99_func :                                    \
131             boost::hash_detail::call_##cpp_func<double> {};             \
132                                                                         \
133         template <>                                                     \
134         struct call_c99_##c99_func<true> {                              \
135             typedef type1 float_type;                                   \
136                                                                         \
137             template <typename T>                                       \
138             inline type1 operator()(type1 a, T b)  const                \
139             {                                                           \
140                 using namespace std;                                    \
141                 return c99_func(a, b);                                  \
142             }                                                           \
143         };                                                              \
144                                                                         \
145         template <bool x>                                               \
146         struct call_cpp_##c99_func :                                    \
147             call_c99_##c99_func<                                        \
148                 ::boost::hash_detail::c99_func##_detect::check::c99     \
149             > {};                                                       \
150                                                                         \
151         template <>                                                     \
152         struct call_cpp_##c99_func<true> {                              \
153             typedef type1 float_type;                                   \
154                                                                         \
155             template <typename T>                                       \
156             inline type1 operator()(type1 a, T b)  const                \
157             {                                                           \
158                 using namespace std;                                    \
159                 return cpp_func(a, b);                                  \
160             }                                                           \
161         };                                                              \
162                                                                         \
163         template <>                                                     \
164         struct call_##cpp_func<type1> :                                 \
165             call_cpp_##c99_func<                                        \
166                 ::boost::hash_detail::c99_func##_detect::check::cpp     \
167             > {};                                                       \
168     }                                                                   \
169 }
170
171 #define BOOST_HASH_CALL_FLOAT_MACRO(cpp_func, c99_func, type1, type2)   \
172 namespace boost {                                                       \
173     namespace hash_detail {                                             \
174                                                                         \
175         template <>                                                     \
176         struct call_##cpp_func<type1> {                                 \
177             typedef type1 float_type;                                   \
178             inline type1 operator()(type1 x, type2 y) const {           \
179                 return c99_func(x, y);                                  \
180             }                                                           \
181         };                                                              \
182     }                                                                   \
183 }
184
185 #if defined(ldexpf)
186 BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpf, float, int)
187 #else
188 BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpf, float, int)
189 #endif
190
191 #if defined(ldexpl)
192 BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpl, long double, int)
193 #else
194 BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpl, long double, int)
195 #endif
196
197 #if defined(frexpf)
198 BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpf, float, int*)
199 #else
200 BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpf, float, int*)
201 #endif
202
203 #if defined(frexpl)
204 BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpl, long double, int*)
205 #else
206 BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpl, long double, int*)
207 #endif
208
209 #undef BOOST_HASH_CALL_FLOAT_MACRO
210 #undef BOOST_HASH_CALL_FLOAT_FUNC
211
212
213 namespace boost
214 {
215     namespace hash_detail
216     {
217         template <typename Float1, typename Float2>
218         struct select_hash_type_impl {
219             typedef double type;
220         };
221
222         template <>
223         struct select_hash_type_impl<float, float> {
224             typedef float type;
225         };
226
227         template <>
228         struct select_hash_type_impl<long double, long double> {
229             typedef long double type;
230         };
231
232
233         // select_hash_type
234         //
235         // If there is support for a particular floating point type, use that
236         // otherwise use double (there's always support for double).
237              
238         template <typename Float>
239         struct select_hash_type : select_hash_type_impl<
240                 BOOST_DEDUCED_TYPENAME call_ldexp<Float>::float_type,
241                 BOOST_DEDUCED_TYPENAME call_frexp<Float>::float_type
242             > {};            
243     }
244 }
245
246 #endif