diff options
Diffstat (limited to '3rdParty/Boost/src/boost/functional/hash/detail/hash_float.hpp')
-rw-r--r-- | 3rdParty/Boost/src/boost/functional/hash/detail/hash_float.hpp | 195 |
1 files changed, 181 insertions, 14 deletions
diff --git a/3rdParty/Boost/src/boost/functional/hash/detail/hash_float.hpp b/3rdParty/Boost/src/boost/functional/hash/detail/hash_float.hpp index ea1bc25..3edc6ab 100644 --- a/3rdParty/Boost/src/boost/functional/hash/detail/hash_float.hpp +++ b/3rdParty/Boost/src/boost/functional/hash/detail/hash_float.hpp @@ -1,5 +1,5 @@ -// Copyright 2005-2009 Daniel James. +// Copyright 2005-2012 Daniel James. // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,21 +13,19 @@ #include <boost/config.hpp> #include <boost/functional/hash/detail/float_functions.hpp> #include <boost/functional/hash/detail/limits.hpp> +#include <boost/utility/enable_if.hpp> #include <boost/integer/static_log2.hpp> #include <boost/cstdint.hpp> #include <boost/assert.hpp> +#include <boost/limits.hpp> +#include <cstring> -// Include hash implementation for the current platform. - -// Cygwn -#if defined(__CYGWIN__) -# if defined(__i386__) || defined(_M_IX86) -# include <boost/functional/hash/detail/hash_float_x86.hpp> -# else -# include <boost/functional/hash/detail/hash_float_generic.hpp> -# endif -#else -# include <boost/functional/hash/detail/hash_float_generic.hpp> +#if defined(BOOST_MSVC) +#pragma warning(push) +#if BOOST_MSVC >= 1400 +#pragma warning(disable:6294) // Ill-defined for-loop: initial condition does + // not satisfy test. Loop body not executed +#endif #endif // Can we use fpclassify? @@ -50,6 +48,157 @@ # define BOOST_HASH_USE_FPCLASSIFY 0 #endif +namespace boost +{ + namespace hash_detail + { + inline void hash_float_combine(std::size_t& seed, std::size_t value) + { + seed ^= value + (seed<<6) + (seed>>2); + } + + //////////////////////////////////////////////////////////////////////// + // Binary hash function + // + // Only used for floats with known iec559 floats, and certain values in + // numeric_limits + + inline std::size_t hash_binary(char* ptr, std::size_t length) + { + std::size_t seed = 0; + + if (length >= sizeof(std::size_t)) { + seed = *(std::size_t*) ptr; + length -= sizeof(std::size_t); + ptr += sizeof(std::size_t); + + while(length >= sizeof(std::size_t)) { + hash_float_combine(seed, *(std::size_t*) ptr); + length -= sizeof(std::size_t); + ptr += sizeof(std::size_t); + } + } + + if (length > 0) { + std::size_t buffer = 0; + std::memcpy(&buffer, ptr, length); + hash_float_combine(seed, buffer); + } + + return seed; + } + + template <typename Float> + inline std::size_t float_hash_impl(Float v, + BOOST_DEDUCED_TYPENAME boost::enable_if_c< + std::numeric_limits<Float>::is_iec559 && + std::numeric_limits<Float>::digits == 24 && + std::numeric_limits<Float>::radix == 2 && + std::numeric_limits<Float>::max_exponent == 128, + int>::type + ) + { + return hash_binary((char*) &v, 4); + } + + + template <typename Float> + inline std::size_t float_hash_impl(Float v, + BOOST_DEDUCED_TYPENAME boost::enable_if_c< + std::numeric_limits<Float>::is_iec559 && + std::numeric_limits<Float>::digits == 53 && + std::numeric_limits<Float>::radix == 2 && + std::numeric_limits<Float>::max_exponent == 1024, + int>::type + ) + { + return hash_binary((char*) &v, 8); + } + + template <typename Float> + inline std::size_t float_hash_impl(Float v, + BOOST_DEDUCED_TYPENAME boost::enable_if_c< + std::numeric_limits<Float>::is_iec559 && + std::numeric_limits<Float>::digits == 64 && + std::numeric_limits<Float>::radix == 2 && + std::numeric_limits<Float>::max_exponent == 16384, + int>::type + ) + { + return hash_binary((char*) &v, 10); + } + + template <typename Float> + inline std::size_t float_hash_impl(Float v, + BOOST_DEDUCED_TYPENAME boost::enable_if_c< + std::numeric_limits<Float>::is_iec559 && + std::numeric_limits<Float>::digits == 113 && + std::numeric_limits<Float>::radix == 2 && + std::numeric_limits<Float>::max_exponent == 16384, + int>::type + ) + { + return hash_binary((char*) &v, 16); + } + + //////////////////////////////////////////////////////////////////////// + // Portable hash function + // + // Used as a fallback when the binary hash function isn't supported. + + template <class T> + inline std::size_t float_hash_impl2(T v) + { + boost::hash_detail::call_frexp<T> frexp; + boost::hash_detail::call_ldexp<T> ldexp; + + int exp = 0; + + v = frexp(v, &exp); + + // A postive value is easier to hash, so combine the + // sign with the exponent and use the absolute value. + if(v < 0) { + v = -v; + exp += limits<T>::max_exponent - + limits<T>::min_exponent; + } + + v = ldexp(v, limits<std::size_t>::digits); + std::size_t seed = static_cast<std::size_t>(v); + v -= static_cast<T>(seed); + + // ceiling(digits(T) * log2(radix(T))/ digits(size_t)) - 1; + std::size_t const length + = (limits<T>::digits * + boost::static_log2<limits<T>::radix>::value + + limits<std::size_t>::digits - 1) + / limits<std::size_t>::digits; + + for(std::size_t i = 0; i != length; ++i) + { + v = ldexp(v, limits<std::size_t>::digits); + std::size_t part = static_cast<std::size_t>(v); + v -= static_cast<T>(part); + hash_float_combine(seed, part); + } + + hash_float_combine(seed, exp); + + return seed; + } + +#if !defined(BOOST_HASH_DETAIL_TEST_WITHOUT_GENERIC) + template <class T> + inline std::size_t float_hash_impl(T v, ...) + { + typedef BOOST_DEDUCED_TYPENAME select_hash_type<T>::type type; + return float_hash_impl2(static_cast<type>(v)); + } +#endif + } +} + #if BOOST_HASH_USE_FPCLASSIFY #include <boost/config/no_tr1/cmath.hpp> @@ -71,7 +220,7 @@ namespace boost return (std::size_t)(-3); case FP_NORMAL: case FP_SUBNORMAL: - return float_hash_impl(v); + return float_hash_impl(v, 0); default: BOOST_ASSERT(0); return 0; @@ -87,9 +236,23 @@ namespace boost namespace hash_detail { template <class T> + inline bool is_zero(T v) + { +#if !defined(__GNUC__) + return v == 0; +#else + // GCC's '-Wfloat-equal' will complain about comparing + // v to 0, but because it disables warnings for system + // headers it won't complain if you use std::equal_to to + // compare with 0. Resulting in this silliness: + return std::equal_to<T>()(v, 0); +#endif + } + + template <class T> inline std::size_t float_hash_value(T v) { - return v == 0 ? 0 : float_hash_impl(v); + return boost::hash_detail::is_zero(v) ? 0 : float_hash_impl(v, 0); } } } @@ -98,4 +261,8 @@ namespace boost #undef BOOST_HASH_USE_FPCLASSIFY +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + #endif |