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; operator ()boost::hash_detail::call_ldexp81 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; operator ()boost::hash_detail::call_frexp89 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 operator floatboost::hash_detail::not_found120 inline operator float() const { return 0; } operator long doubleboost::hash_detail::not_found121 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 operator ()boost::hash_detail::call_ldexp144 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 operator ()boost::hash_detail::call_frexp159 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 337