williamr@2: williamr@2: // Copyright Daniel James 2005-2006. Use, modification, and distribution are williamr@2: // subject to the Boost Software License, Version 1.0. (See accompanying williamr@2: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) williamr@2: williamr@2: // Based on Peter Dimov's proposal williamr@2: // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf williamr@2: // issue 6.18. williamr@2: williamr@2: #if !defined(BOOST_FUNCTIONAL_DETAIL_HASH_FLOAT_HEADER) williamr@2: #define BOOST_FUNCTIONAL_DETAIL_HASH_FLOAT_HEADER williamr@2: williamr@2: #if defined(_MSC_VER) && (_MSC_VER >= 1020) williamr@2: # pragma once williamr@2: #endif williamr@2: williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: williamr@2: // Don't use fpclassify or _fpclass for stlport. williamr@2: #if !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) williamr@2: # if defined(__GLIBCPP__) || defined(__GLIBCXX__) williamr@2: // GNU libstdc++ 3 williamr@2: # if (defined(__USE_ISOC99) || defined(_GLIBCXX_USE_C99_MATH)) && \ williamr@2: !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) williamr@2: # define BOOST_HASH_USE_FPCLASSIFY williamr@2: # endif williamr@2: # elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER) williamr@2: // Dinkumware Library, on Visual C++ williamr@2: # if defined(BOOST_MSVC) williamr@2: # define BOOST_HASH_USE_FPCLASS williamr@2: # endif williamr@2: # endif williamr@2: #endif williamr@2: williamr@2: namespace boost williamr@2: { williamr@2: namespace hash_detail williamr@2: { williamr@2: inline void hash_float_combine(std::size_t& seed, std::size_t value) williamr@2: { williamr@2: seed ^= value + (seed<<6) + (seed>>2); williamr@2: } williamr@2: williamr@2: template williamr@2: inline std::size_t float_hash_impl(T v) williamr@2: { williamr@2: int exp = 0; williamr@2: errno = 0; williamr@2: v = boost::hash_detail::call_frexp(v, &exp); williamr@2: if(errno) return 0; williamr@2: williamr@2: std::size_t seed = 0; williamr@2: williamr@2: std::size_t const length williamr@2: = (std::numeric_limits::digits + williamr@2: std::numeric_limits::digits - 1) williamr@2: / std::numeric_limits::digits; williamr@2: williamr@2: for(std::size_t i = 0; i < length; ++i) williamr@2: { williamr@2: v = boost::hash_detail::call_ldexp(v, std::numeric_limits::digits); williamr@2: int const part = static_cast(v); williamr@2: v -= part; williamr@2: hash_float_combine(seed, part); williamr@2: } williamr@2: williamr@2: hash_float_combine(seed, exp); williamr@2: williamr@2: return seed; williamr@2: } williamr@2: williamr@2: template williamr@2: inline std::size_t float_hash_value(T v) williamr@2: { williamr@2: #if defined(BOOST_HASH_USE_FPCLASSIFY) williamr@2: using namespace std; williamr@2: switch (fpclassify(v)) { williamr@2: case FP_ZERO: williamr@2: return 0; williamr@2: case FP_INFINITE: williamr@2: return (std::size_t)(v > 0 ? -1 : -2); williamr@2: case FP_NAN: williamr@2: return (std::size_t)(-3); williamr@2: case FP_NORMAL: williamr@2: case FP_SUBNORMAL: williamr@2: return float_hash_impl(v); williamr@2: default: williamr@2: BOOST_ASSERT(0); williamr@2: return 0; williamr@2: } williamr@2: #elif defined(BOOST_HASH_USE_FPCLASS) williamr@2: switch(_fpclass(v)) { williamr@2: case _FPCLASS_NZ: williamr@2: case _FPCLASS_PZ: williamr@2: return 0; williamr@2: case _FPCLASS_PINF: williamr@2: return (std::size_t)(-1); williamr@2: case _FPCLASS_NINF: williamr@2: return (std::size_t)(-2); williamr@2: case _FPCLASS_SNAN: williamr@2: case _FPCLASS_QNAN: williamr@2: return (std::size_t)(-3); williamr@2: case _FPCLASS_NN: williamr@2: case _FPCLASS_ND: williamr@2: return float_hash_impl(v); williamr@2: case _FPCLASS_PD: williamr@2: case _FPCLASS_PN: williamr@2: return float_hash_impl(v); williamr@2: default: williamr@2: BOOST_ASSERT(0); williamr@2: return 0; williamr@2: } williamr@2: #else williamr@2: return float_hash_impl(v); williamr@2: #endif williamr@2: } williamr@2: } williamr@2: } williamr@2: williamr@2: #endif