diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2013-10-19 08:57:20 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2013-10-19 08:57:20 +0200 |
commit | ed6115361006240e3c7b02295599e4534cc55a13 (patch) | |
tree | 612f12d6c7c49421102041fceb7609db8ab8257e /cutl/details/boost/functional/hash/detail/hash_float.hpp | |
parent | af8d1a0139ca105c6830f4ac7c320aca2e1c1f5e (diff) |
Update internal Boost subset to 1.54.0
Diffstat (limited to 'cutl/details/boost/functional/hash/detail/hash_float.hpp')
-rw-r--r-- | cutl/details/boost/functional/hash/detail/hash_float.hpp | 206 |
1 files changed, 191 insertions, 15 deletions
diff --git a/cutl/details/boost/functional/hash/detail/hash_float.hpp b/cutl/details/boost/functional/hash/detail/hash_float.hpp index dafec9a..aaa49d9 100644 --- a/cutl/details/boost/functional/hash/detail/hash_float.hpp +++ b/cutl/details/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 <cutl/details/boost/config.hpp> #include <cutl/details/boost/functional/hash/detail/float_functions.hpp> #include <cutl/details/boost/functional/hash/detail/limits.hpp> +#include <cutl/details/boost/utility/enable_if.hpp> #include <cutl/details/boost/integer/static_log2.hpp> #include <cutl/details/boost/cstdint.hpp> #include <cutl/details/boost/assert.hpp> +#include <cutl/details/boost/limits.hpp> +#include <cstring> -// Include hash implementation for the current platform. - -// Cygwn -#if defined(__CYGWIN__) -# if defined(__i386__) || defined(_M_IX86) -# include <cutl/details/boost/functional/hash/detail/hash_float_x86.hpp> -# else -# include <cutl/details/boost/functional/hash/detail/hash_float_generic.hpp> -# endif -#else -# include <cutl/details/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,159 @@ # define BOOST_HASH_USE_FPCLASSIFY 0 #endif +namespace cutl_details_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)) { + std::size_t buffer = 0; + std::memcpy(&buffer, ptr, sizeof(std::size_t)); + hash_float_combine(seed, buffer); + 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 cutl_details_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 cutl_details_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 cutl_details_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 cutl_details_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) + { + cutl_details_boost::hash_detail::call_frexp<T> frexp; + cutl_details_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 * + cutl_details_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 <cutl/details/boost/config/no_tr1/cmath.hpp> @@ -61,8 +212,15 @@ namespace cutl_details_boost template <class T> inline std::size_t float_hash_value(T v) { +#if defined(fpclassify) + switch (fpclassify(v)) +#elif BOOST_HASH_CONFORMANT_FLOATS + switch (std::fpclassify(v)) +#else using namespace std; - switch (fpclassify(v)) { + switch (fpclassify(v)) +#endif + { case FP_ZERO: return 0; case FP_INFINITE: @@ -71,7 +229,7 @@ namespace cutl_details_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 +245,23 @@ namespace cutl_details_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 cutl_details_boost::hash_detail::is_zero(v) ? 0 : float_hash_impl(v, 0); } } } @@ -98,4 +270,8 @@ namespace cutl_details_boost #undef BOOST_HASH_USE_FPCLASSIFY +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + #endif |