diff --git a/include/boost/functional/detail/hash_float.hpp b/include/boost/functional/detail/hash_float.hpp index f6cb204..965ebf7 100644 --- a/include/boost/functional/detail/hash_float.hpp +++ b/include/boost/functional/detail/hash_float.hpp @@ -16,8 +16,16 @@ #endif #include -#include #include +#include +#include + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define BOOST_HASH_USE_FPCLASS +#elif (defined(__GLIBCPP__) || defined(__GLIBCXX__)) \ + && (defined(__USE_ISOC99) || defined(_GLIBCXX_USE_C99_MATH)) +# define BOOST_HASH_USE_FPCLASSIFY +#endif namespace boost { @@ -29,7 +37,7 @@ namespace boost } template - inline std::size_t float_hash_value(T v) + inline std::size_t float_hash_impl(T v) { int exp = 0; errno = 0; @@ -55,6 +63,52 @@ namespace boost return seed; } + + template + inline std::size_t float_hash_value(T v) + { +#if defined(BOOST_HASH_USE_FPCLASSIFY) + using namespace std; + switch (fpclassify(v)) { + case FP_ZERO: + return 0; + case FP_INFINITE: + return (std::size_t)(v > 0 ? -1 : -2); + case FP_NAN: + return (std::size_t)(-3); + case FP_NORMAL: + case FP_SUBNORMAL: + return float_hash_impl(v); + default: + BOOST_ASSERT(0); + return 0; + } +#elif defined(BOOST_HASH_USE_FPCLASS) + switch(_fpclass(v)) { + case _FPCLASS_NZ: + case _FPCLASS_PZ: + return 0; + case _FPCLASS_PINF: + return (std::size_t)(-1); + case _FPCLASS_NINF: + return (std::size_t)(-2); + case _FPCLASS_SNAN: + case _FPCLASS_QNAN: + return (std::size_t)(-3); + case _FPCLASS_NN: + case _FPCLASS_ND: + return float_hash_impl(v); + case _FPCLASS_PD: + case _FPCLASS_PN: + return float_hash_impl(v); + default: + BOOST_ASSERT(0); + return 0; + } +#else + return float_hash_impl(v); +#endif + } } }