~ubuntu-branches/ubuntu/saucy/deal.ii/saucy

« back to all changes in this revision

Viewing changes to contrib/boost/include/boost/functional/detail/hash_float.hpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam C. Powell, IV
  • Date: 2009-05-08 23:13:50 UTC
  • Revision ID: james.westby@ubuntu.com-20090508231350-rrh1ltgi0tifabwc
Tags: upstream-6.2.0
ImportĀ upstreamĀ versionĀ 6.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
// Copyright 2005-2008 Daniel James.
 
3
// Distributed under the Boost Software License, Version 1.0. (See accompanying
 
4
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
5
 
 
6
//  Based on Peter Dimov's proposal
 
7
//  http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
 
8
//  issue 6.18. 
 
9
 
 
10
#if !defined(BOOST_FUNCTIONAL_DETAIL_HASH_FLOAT_HEADER)
 
11
#define BOOST_FUNCTIONAL_DETAIL_HASH_FLOAT_HEADER
 
12
 
 
13
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
 
14
# pragma once
 
15
#endif
 
16
 
 
17
#if defined(BOOST_MSVC)
 
18
#pragma warning(push)
 
19
#if BOOST_MSVC >= 1400
 
20
#pragma warning(disable:6294) // Ill-defined for-loop: initial condition does
 
21
                              // not satisfy test. Loop body not executed 
 
22
#endif
 
23
#endif
 
24
 
 
25
#include <boost/functional/detail/float_functions.hpp>
 
26
#include <boost/integer/static_log2.hpp>
 
27
#include <boost/cstdint.hpp>
 
28
#include <boost/limits.hpp>
 
29
#include <boost/assert.hpp>
 
30
 
 
31
// Select implementation for the current platform.
 
32
 
 
33
// Cygwn
 
34
#if defined(__CYGWIN__)
 
35
#  if defined(__i386__) || defined(_M_IX86)
 
36
#    define BOOST_HASH_USE_x86_BINARY_HASH
 
37
#  endif
 
38
 
 
39
// STLport
 
40
#elif defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
 
41
// fpclassify aren't good enough on STLport.
 
42
 
 
43
// GNU libstdc++ 3
 
44
#elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
 
45
#  if (defined(__USE_ISOC99) || defined(_GLIBCXX_USE_C99_MATH)) && \
 
46
      !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
 
47
#    define BOOST_HASH_USE_FPCLASSIFY
 
48
#  endif
 
49
 
 
50
// Dinkumware Library, on Visual C++ 
 
51
#elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
 
52
 
 
53
// Not using _fpclass because it is only available for double.
 
54
 
 
55
#endif
 
56
 
 
57
// On OpenBSD, numeric_limits is not reliable for long doubles, but
 
58
// the macros defined in <float.h> are.
 
59
 
 
60
#if defined(__OpenBSD__)
 
61
#include <float.h>
 
62
#endif
 
63
 
 
64
namespace boost
 
65
{
 
66
    namespace hash_detail
 
67
    {
 
68
        template <class T>
 
69
        struct limits : std::numeric_limits<T> {};
 
70
 
 
71
#if defined(__OpenBSD__)
 
72
        template <>
 
73
        struct limits<long double>
 
74
             : std::numeric_limits<long double>
 
75
        {
 
76
            static long double epsilon() {
 
77
                return LDBL_EPSILON;
 
78
            }
 
79
 
 
80
            static long double (max)() {
 
81
                return LDBL_MAX;
 
82
            }
 
83
 
 
84
            static long double (min)() {
 
85
                return LDBL_MIN;
 
86
            }
 
87
 
 
88
            BOOST_STATIC_CONSTANT(int, digits = LDBL_MANT_DIG);
 
89
            BOOST_STATIC_CONSTANT(int, max_exponent = LDBL_MAX_EXP);
 
90
            BOOST_STATIC_CONSTANT(int, min_exponent = LDBL_MIN_EXP);
 
91
        };
 
92
#endif // __OpenBSD__
 
93
 
 
94
        inline void hash_float_combine(std::size_t& seed, std::size_t value)
 
95
        {
 
96
            seed ^= value + (seed<<6) + (seed>>2);
 
97
        }
 
98
 
 
99
// A simple, non-portable hash algorithm for x86.
 
100
#if defined(BOOST_HASH_USE_x86_BINARY_HASH)
 
101
        inline std::size_t float_hash_impl(float v)
 
102
        {
 
103
            boost::uint32_t* ptr = (boost::uint32_t*)&v;
 
104
            std::size_t seed = *ptr;
 
105
            return seed;
 
106
        }
 
107
 
 
108
        inline std::size_t float_hash_impl(double v)
 
109
        {
 
110
            boost::uint32_t* ptr = (boost::uint32_t*)&v;
 
111
            std::size_t seed = *ptr++;
 
112
            hash_float_combine(seed, *ptr);
 
113
            return seed;
 
114
        }
 
115
 
 
116
        inline std::size_t float_hash_impl(long double v)
 
117
        {
 
118
            boost::uint32_t* ptr = (boost::uint32_t*)&v;
 
119
            std::size_t seed = *ptr++;
 
120
            hash_float_combine(seed, *ptr++);
 
121
            hash_float_combine(seed, *(boost::uint16_t*)ptr);
 
122
            return seed;
 
123
        }
 
124
 
 
125
#else
 
126
 
 
127
        template <class T>
 
128
        inline std::size_t float_hash_impl(T v)
 
129
        {
 
130
            int exp = 0;
 
131
 
 
132
            v = boost::hash_detail::call_frexp(v, &exp);
 
133
 
 
134
            // A postive value is easier to hash, so combine the
 
135
            // sign with the exponent.
 
136
            if(v < 0) {
 
137
                v = -v;
 
138
                exp += limits<T>::max_exponent -
 
139
                    limits<T>::min_exponent;
 
140
            }
 
141
 
 
142
            // The result of frexp is always between 0.5 and 1, so its
 
143
            // top bit will always be 1. Subtract by 0.5 to remove that.
 
144
            v -= T(0.5);
 
145
            v = boost::hash_detail::call_ldexp(v,
 
146
                    limits<std::size_t>::digits + 1);
 
147
            std::size_t seed = static_cast<std::size_t>(v);
 
148
            v -= seed;
 
149
 
 
150
            // ceiling(digits(T) * log2(radix(T))/ digits(size_t)) - 1;
 
151
            std::size_t const length
 
152
                = (limits<T>::digits *
 
153
                        boost::static_log2<limits<T>::radix>::value - 1)
 
154
                / limits<std::size_t>::digits;
 
155
 
 
156
            for(std::size_t i = 0; i != length; ++i)
 
157
            {
 
158
                v = boost::hash_detail::call_ldexp(v,
 
159
                        limits<std::size_t>::digits);
 
160
                std::size_t part = static_cast<std::size_t>(v);
 
161
                v -= part;
 
162
                hash_float_combine(seed, part);
 
163
            }
 
164
 
 
165
            hash_float_combine(seed, exp);
 
166
 
 
167
            return seed;
 
168
        }
 
169
#endif
 
170
 
 
171
        template <class T>
 
172
        inline std::size_t float_hash_value(T v)
 
173
        {
 
174
#if defined(BOOST_HASH_USE_FPCLASSIFY)
 
175
            using namespace std;
 
176
            switch (fpclassify(v)) {
 
177
            case FP_ZERO:
 
178
                return 0;
 
179
            case FP_INFINITE:
 
180
                return (std::size_t)(v > 0 ? -1 : -2);
 
181
            case FP_NAN:
 
182
                return (std::size_t)(-3);
 
183
            case FP_NORMAL:
 
184
            case FP_SUBNORMAL:
 
185
                return float_hash_impl(v);
 
186
            default:
 
187
                BOOST_ASSERT(0);
 
188
                return 0;
 
189
            }
 
190
#else
 
191
            return v == 0 ? 0 : float_hash_impl(v);
 
192
#endif
 
193
        }
 
194
    }
 
195
}
 
196
 
 
197
#if defined(BOOST_MSVC)
 
198
#pragma warning(pop)
 
199
#endif
 
200
 
 
201
#endif