annotate DEPENDENCIES/generic/include/boost/functional/hash/detail/hash_float.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1
Chris@16 2 // Copyright 2005-2012 Daniel James.
Chris@16 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
Chris@16 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 5
Chris@16 6 #if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_HEADER)
Chris@16 7 #define BOOST_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_HEADER
Chris@16 8
Chris@101 9 #include <boost/config.hpp>
Chris@101 10 #if defined(BOOST_HAS_PRAGMA_ONCE)
Chris@101 11 #pragma once
Chris@16 12 #endif
Chris@16 13
Chris@16 14 #include <boost/functional/hash/detail/float_functions.hpp>
Chris@16 15 #include <boost/functional/hash/detail/limits.hpp>
Chris@16 16 #include <boost/utility/enable_if.hpp>
Chris@16 17 #include <boost/integer/static_log2.hpp>
Chris@16 18 #include <boost/cstdint.hpp>
Chris@16 19 #include <boost/assert.hpp>
Chris@16 20 #include <boost/limits.hpp>
Chris@16 21 #include <cstring>
Chris@16 22
Chris@16 23 #if defined(BOOST_MSVC)
Chris@16 24 #pragma warning(push)
Chris@16 25 #if BOOST_MSVC >= 1400
Chris@16 26 #pragma warning(disable:6294) // Ill-defined for-loop: initial condition does
Chris@16 27 // not satisfy test. Loop body not executed
Chris@16 28 #endif
Chris@16 29 #endif
Chris@16 30
Chris@16 31 // Can we use fpclassify?
Chris@16 32
Chris@16 33 // STLport
Chris@16 34 #if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
Chris@16 35 #define BOOST_HASH_USE_FPCLASSIFY 0
Chris@16 36
Chris@16 37 // GNU libstdc++ 3
Chris@16 38 #elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
Chris@16 39 # if (defined(__USE_ISOC99) || defined(_GLIBCXX_USE_C99_MATH)) && \
Chris@16 40 !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
Chris@16 41 # define BOOST_HASH_USE_FPCLASSIFY 1
Chris@16 42 # else
Chris@16 43 # define BOOST_HASH_USE_FPCLASSIFY 0
Chris@16 44 # endif
Chris@16 45
Chris@16 46 // Everything else
Chris@16 47 #else
Chris@16 48 # define BOOST_HASH_USE_FPCLASSIFY 0
Chris@16 49 #endif
Chris@16 50
Chris@16 51 namespace boost
Chris@16 52 {
Chris@16 53 namespace hash_detail
Chris@16 54 {
Chris@16 55 inline void hash_float_combine(std::size_t& seed, std::size_t value)
Chris@16 56 {
Chris@16 57 seed ^= value + (seed<<6) + (seed>>2);
Chris@16 58 }
Chris@16 59
Chris@16 60 ////////////////////////////////////////////////////////////////////////
Chris@16 61 // Binary hash function
Chris@16 62 //
Chris@16 63 // Only used for floats with known iec559 floats, and certain values in
Chris@16 64 // numeric_limits
Chris@16 65
Chris@16 66 inline std::size_t hash_binary(char* ptr, std::size_t length)
Chris@16 67 {
Chris@16 68 std::size_t seed = 0;
Chris@16 69
Chris@16 70 if (length >= sizeof(std::size_t)) {
Chris@101 71 std::memcpy(&seed, ptr, sizeof(std::size_t));
Chris@16 72 length -= sizeof(std::size_t);
Chris@16 73 ptr += sizeof(std::size_t);
Chris@16 74
Chris@16 75 while(length >= sizeof(std::size_t)) {
Chris@16 76 std::size_t buffer = 0;
Chris@16 77 std::memcpy(&buffer, ptr, sizeof(std::size_t));
Chris@16 78 hash_float_combine(seed, buffer);
Chris@16 79 length -= sizeof(std::size_t);
Chris@16 80 ptr += sizeof(std::size_t);
Chris@16 81 }
Chris@16 82 }
Chris@16 83
Chris@16 84 if (length > 0) {
Chris@16 85 std::size_t buffer = 0;
Chris@16 86 std::memcpy(&buffer, ptr, length);
Chris@16 87 hash_float_combine(seed, buffer);
Chris@16 88 }
Chris@16 89
Chris@16 90 return seed;
Chris@16 91 }
Chris@16 92
Chris@16 93 template <typename Float, unsigned digits, unsigned max_exponent>
Chris@16 94 struct enable_binary_hash
Chris@16 95 {
Chris@16 96 BOOST_STATIC_CONSTANT(bool, value =
Chris@16 97 std::numeric_limits<Float>::is_iec559 &&
Chris@16 98 std::numeric_limits<Float>::digits == digits &&
Chris@16 99 std::numeric_limits<Float>::radix == 2 &&
Chris@16 100 std::numeric_limits<Float>::max_exponent == max_exponent);
Chris@16 101 };
Chris@16 102
Chris@16 103 template <typename Float>
Chris@16 104 inline std::size_t float_hash_impl(Float v,
Chris@16 105 BOOST_DEDUCED_TYPENAME boost::enable_if_c<
Chris@16 106 enable_binary_hash<Float, 24, 128>::value,
Chris@16 107 std::size_t>::type)
Chris@16 108 {
Chris@16 109 return hash_binary((char*) &v, 4);
Chris@16 110 }
Chris@16 111
Chris@16 112
Chris@16 113 template <typename Float>
Chris@16 114 inline std::size_t float_hash_impl(Float v,
Chris@16 115 BOOST_DEDUCED_TYPENAME boost::enable_if_c<
Chris@16 116 enable_binary_hash<Float, 53, 1024>::value,
Chris@16 117 std::size_t>::type)
Chris@16 118 {
Chris@16 119 return hash_binary((char*) &v, 8);
Chris@16 120 }
Chris@16 121
Chris@16 122 template <typename Float>
Chris@16 123 inline std::size_t float_hash_impl(Float v,
Chris@16 124 BOOST_DEDUCED_TYPENAME boost::enable_if_c<
Chris@16 125 enable_binary_hash<Float, 64, 16384>::value,
Chris@16 126 std::size_t>::type)
Chris@16 127 {
Chris@16 128 return hash_binary((char*) &v, 10);
Chris@16 129 }
Chris@16 130
Chris@16 131 template <typename Float>
Chris@16 132 inline std::size_t float_hash_impl(Float v,
Chris@16 133 BOOST_DEDUCED_TYPENAME boost::enable_if_c<
Chris@16 134 enable_binary_hash<Float, 113, 16384>::value,
Chris@16 135 std::size_t>::type)
Chris@16 136 {
Chris@16 137 return hash_binary((char*) &v, 16);
Chris@16 138 }
Chris@16 139
Chris@16 140 ////////////////////////////////////////////////////////////////////////
Chris@16 141 // Portable hash function
Chris@16 142 //
Chris@16 143 // Used as a fallback when the binary hash function isn't supported.
Chris@16 144
Chris@16 145 template <class T>
Chris@16 146 inline std::size_t float_hash_impl2(T v)
Chris@16 147 {
Chris@16 148 boost::hash_detail::call_frexp<T> frexp;
Chris@16 149 boost::hash_detail::call_ldexp<T> ldexp;
Chris@16 150
Chris@16 151 int exp = 0;
Chris@16 152
Chris@16 153 v = frexp(v, &exp);
Chris@16 154
Chris@16 155 // A postive value is easier to hash, so combine the
Chris@16 156 // sign with the exponent and use the absolute value.
Chris@16 157 if(v < 0) {
Chris@16 158 v = -v;
Chris@16 159 exp += limits<T>::max_exponent -
Chris@16 160 limits<T>::min_exponent;
Chris@16 161 }
Chris@16 162
Chris@16 163 v = ldexp(v, limits<std::size_t>::digits);
Chris@16 164 std::size_t seed = static_cast<std::size_t>(v);
Chris@16 165 v -= static_cast<T>(seed);
Chris@16 166
Chris@16 167 // ceiling(digits(T) * log2(radix(T))/ digits(size_t)) - 1;
Chris@16 168 std::size_t const length
Chris@16 169 = (limits<T>::digits *
Chris@16 170 boost::static_log2<limits<T>::radix>::value
Chris@16 171 + limits<std::size_t>::digits - 1)
Chris@16 172 / limits<std::size_t>::digits;
Chris@16 173
Chris@16 174 for(std::size_t i = 0; i != length; ++i)
Chris@16 175 {
Chris@16 176 v = ldexp(v, limits<std::size_t>::digits);
Chris@16 177 std::size_t part = static_cast<std::size_t>(v);
Chris@16 178 v -= static_cast<T>(part);
Chris@16 179 hash_float_combine(seed, part);
Chris@16 180 }
Chris@16 181
Chris@16 182 hash_float_combine(seed, exp);
Chris@16 183
Chris@16 184 return seed;
Chris@16 185 }
Chris@16 186
Chris@16 187 #if !defined(BOOST_HASH_DETAIL_TEST_WITHOUT_GENERIC)
Chris@16 188 template <class T>
Chris@16 189 inline std::size_t float_hash_impl(T v, ...)
Chris@16 190 {
Chris@16 191 typedef BOOST_DEDUCED_TYPENAME select_hash_type<T>::type type;
Chris@16 192 return float_hash_impl2(static_cast<type>(v));
Chris@16 193 }
Chris@16 194 #endif
Chris@16 195 }
Chris@16 196 }
Chris@16 197
Chris@16 198 #if BOOST_HASH_USE_FPCLASSIFY
Chris@16 199
Chris@16 200 #include <boost/config/no_tr1/cmath.hpp>
Chris@16 201
Chris@16 202 namespace boost
Chris@16 203 {
Chris@16 204 namespace hash_detail
Chris@16 205 {
Chris@16 206 template <class T>
Chris@16 207 inline std::size_t float_hash_value(T v)
Chris@16 208 {
Chris@16 209 #if defined(fpclassify)
Chris@16 210 switch (fpclassify(v))
Chris@16 211 #elif BOOST_HASH_CONFORMANT_FLOATS
Chris@16 212 switch (std::fpclassify(v))
Chris@16 213 #else
Chris@16 214 using namespace std;
Chris@16 215 switch (fpclassify(v))
Chris@16 216 #endif
Chris@16 217 {
Chris@16 218 case FP_ZERO:
Chris@16 219 return 0;
Chris@16 220 case FP_INFINITE:
Chris@16 221 return (std::size_t)(v > 0 ? -1 : -2);
Chris@16 222 case FP_NAN:
Chris@16 223 return (std::size_t)(-3);
Chris@16 224 case FP_NORMAL:
Chris@16 225 case FP_SUBNORMAL:
Chris@16 226 return float_hash_impl(v, 0);
Chris@16 227 default:
Chris@16 228 BOOST_ASSERT(0);
Chris@16 229 return 0;
Chris@16 230 }
Chris@16 231 }
Chris@16 232 }
Chris@16 233 }
Chris@16 234
Chris@16 235 #else // !BOOST_HASH_USE_FPCLASSIFY
Chris@16 236
Chris@16 237 namespace boost
Chris@16 238 {
Chris@16 239 namespace hash_detail
Chris@16 240 {
Chris@16 241 template <class T>
Chris@16 242 inline bool is_zero(T v)
Chris@16 243 {
Chris@16 244 #if !defined(__GNUC__)
Chris@16 245 return v == 0;
Chris@16 246 #else
Chris@16 247 // GCC's '-Wfloat-equal' will complain about comparing
Chris@16 248 // v to 0, but because it disables warnings for system
Chris@16 249 // headers it won't complain if you use std::equal_to to
Chris@16 250 // compare with 0. Resulting in this silliness:
Chris@16 251 return std::equal_to<T>()(v, 0);
Chris@16 252 #endif
Chris@16 253 }
Chris@16 254
Chris@16 255 template <class T>
Chris@16 256 inline std::size_t float_hash_value(T v)
Chris@16 257 {
Chris@16 258 return boost::hash_detail::is_zero(v) ? 0 : float_hash_impl(v, 0);
Chris@16 259 }
Chris@16 260 }
Chris@16 261 }
Chris@16 262
Chris@16 263 #endif // BOOST_HASH_USE_FPCLASSIFY
Chris@16 264
Chris@16 265 #undef BOOST_HASH_USE_FPCLASSIFY
Chris@16 266
Chris@16 267 #if defined(BOOST_MSVC)
Chris@16 268 #pragma warning(pop)
Chris@16 269 #endif
Chris@16 270
Chris@16 271 #endif