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)
6 #if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP)
7 #define BOOST_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP
9 #include <boost/config.hpp>
10 #include <boost/config/no_tr1/cmath.hpp>
12 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
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.
21 // The following tries to automatically detect which are available.
24 namespace hash_detail
{
26 // Returned by dummy versions of the float functions.
29 // Implicitly convertible to float and long double in order to avoid
30 // a compile error when the dummy float functions are used.
32 inline operator float() const { return 0; }
33 inline operator long double() const { return 0; }
36 // A type for detecting the return type of functions.
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]; };
44 // Used to convert the return type of a function to a type for sizeof.
46 template <typename T
> is
<T
> float_type(T
);
50 // This will get specialized for float and long double
52 template <typename Float
> struct call_ldexp
54 typedef double float_type
;
56 inline double operator()(double a
, int b
) const
65 // This will get specialized for float and long double
67 template <typename Float
> struct call_frexp
69 typedef double float_type
;
71 inline double operator()(double a
, int* b
) const
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.
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).
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*);
92 // Macros for generating specializations of call_ldexp and call_frexp.
94 // check_cpp and check_c99 check if the C++ or C99 functions are available.
96 // Then the call_* functions select an appropriate implementation.
98 // I used c99_func in a few places just to get a unique name.
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.
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); \
112 namespace hash_detail { \
113 namespace c99_func##_detect { \
114 using namespace std; \
115 using namespace boost_hash_detect_float_functions; \
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>)); \
130 struct call_c99_##c99_func : \
131 boost::hash_detail::call_##cpp_func<double> {}; \
134 struct call_c99_##c99_func<true> { \
135 typedef type1 float_type; \
137 template <typename T> \
138 inline type1 operator()(type1 a, T b) const \
140 using namespace std; \
141 return c99_func(a, b); \
146 struct call_cpp_##c99_func : \
147 call_c99_##c99_func< \
148 ::boost::hash_detail::c99_func##_detect::check::c99 \
152 struct call_cpp_##c99_func<true> { \
153 typedef type1 float_type; \
155 template <typename T> \
156 inline type1 operator()(type1 a, T b) const \
158 using namespace std; \
159 return cpp_func(a, b); \
164 struct call_##cpp_func<type1> : \
165 call_cpp_##c99_func< \
166 ::boost::hash_detail::c99_func##_detect::check::cpp \
171 #define BOOST_HASH_CALL_FLOAT_MACRO(cpp_func, c99_func, type1, type2) \
173 namespace hash_detail { \
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); \
186 BOOST_HASH_CALL_FLOAT_MACRO(ldexp
, ldexpf
, float, int)
188 BOOST_HASH_CALL_FLOAT_FUNC(ldexp
, ldexpf
, float, int)
192 BOOST_HASH_CALL_FLOAT_MACRO(ldexp
, ldexpl
, long double, int)
194 BOOST_HASH_CALL_FLOAT_FUNC(ldexp
, ldexpl
, long double, int)
198 BOOST_HASH_CALL_FLOAT_MACRO(frexp
, frexpf
, float, int*)
200 BOOST_HASH_CALL_FLOAT_FUNC(frexp
, frexpf
, float, int*)
204 BOOST_HASH_CALL_FLOAT_MACRO(frexp
, frexpl
, long double, int*)
206 BOOST_HASH_CALL_FLOAT_FUNC(frexp
, frexpl
, long double, int*)
209 #undef BOOST_HASH_CALL_FLOAT_MACRO
210 #undef BOOST_HASH_CALL_FLOAT_FUNC
215 namespace hash_detail
217 template <typename Float1
, typename Float2
>
218 struct select_hash_type_impl
{
223 struct select_hash_type_impl
<float, float> {
228 struct select_hash_type_impl
<long double, long double> {
229 typedef long double type
;
235 // If there is support for a particular floating point type, use that
236 // otherwise use double (there's always support for double).
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