float_functions.hpp 11 KB

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