From ed6115361006240e3c7b02295599e4534cc55a13 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 19 Oct 2013 08:57:20 +0200 Subject: Update internal Boost subset to 1.54.0 --- .../boost/functional/hash/detail/hash_float.hpp | 206 +++++++++++++++++++-- 1 file changed, 191 insertions(+), 15 deletions(-) (limited to 'cutl/details/boost/functional/hash/detail/hash_float.hpp') 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 #include #include +#include #include #include #include +#include +#include -// Include hash implementation for the current platform. - -// Cygwn -#if defined(__CYGWIN__) -# if defined(__i386__) || defined(_M_IX86) -# include -# else -# include -# endif -#else -# include +#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 + inline std::size_t float_hash_impl(Float v, + BOOST_DEDUCED_TYPENAME cutl_details_boost::enable_if_c< + std::numeric_limits::is_iec559 && + std::numeric_limits::digits == 24 && + std::numeric_limits::radix == 2 && + std::numeric_limits::max_exponent == 128, + int>::type + ) + { + return hash_binary((char*) &v, 4); + } + + + template + inline std::size_t float_hash_impl(Float v, + BOOST_DEDUCED_TYPENAME cutl_details_boost::enable_if_c< + std::numeric_limits::is_iec559 && + std::numeric_limits::digits == 53 && + std::numeric_limits::radix == 2 && + std::numeric_limits::max_exponent == 1024, + int>::type + ) + { + return hash_binary((char*) &v, 8); + } + + template + inline std::size_t float_hash_impl(Float v, + BOOST_DEDUCED_TYPENAME cutl_details_boost::enable_if_c< + std::numeric_limits::is_iec559 && + std::numeric_limits::digits == 64 && + std::numeric_limits::radix == 2 && + std::numeric_limits::max_exponent == 16384, + int>::type + ) + { + return hash_binary((char*) &v, 10); + } + + template + inline std::size_t float_hash_impl(Float v, + BOOST_DEDUCED_TYPENAME cutl_details_boost::enable_if_c< + std::numeric_limits::is_iec559 && + std::numeric_limits::digits == 113 && + std::numeric_limits::radix == 2 && + std::numeric_limits::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 + inline std::size_t float_hash_impl2(T v) + { + cutl_details_boost::hash_detail::call_frexp frexp; + cutl_details_boost::hash_detail::call_ldexp 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::max_exponent - + limits::min_exponent; + } + + v = ldexp(v, limits::digits); + std::size_t seed = static_cast(v); + v -= static_cast(seed); + + // ceiling(digits(T) * log2(radix(T))/ digits(size_t)) - 1; + std::size_t const length + = (limits::digits * + cutl_details_boost::static_log2::radix>::value + + limits::digits - 1) + / limits::digits; + + for(std::size_t i = 0; i != length; ++i) + { + v = ldexp(v, limits::digits); + std::size_t part = static_cast(v); + v -= static_cast(part); + hash_float_combine(seed, part); + } + + hash_float_combine(seed, exp); + + return seed; + } + +#if !defined(BOOST_HASH_DETAIL_TEST_WITHOUT_GENERIC) + template + inline std::size_t float_hash_impl(T v, ...) + { + typedef BOOST_DEDUCED_TYPENAME select_hash_type::type type; + return float_hash_impl2(static_cast(v)); + } +#endif + } +} + #if BOOST_HASH_USE_FPCLASSIFY #include @@ -61,8 +212,15 @@ namespace cutl_details_boost template 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 + 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()(v, 0); +#endif + } + + template 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 -- cgit v1.1