Dune Core Modules (2.5.0)

hash.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3#ifndef DUNE_COMMON_HASH_HH
4#define DUNE_COMMON_HASH_HH
5
6#include <functional>
7
9
22// ********************************************************************************
23// Doxygen documentation
24// ********************************************************************************
25
26#ifdef DOXYGEN
27
28namespace Dune {
29
31
36 template<typename T>
37 struct hash
38 {
39
41 std::size_t operator()(const T& t) const
42 {
43 return hash(t);
44 }
45
46 };
47
48}
49
51
98#define DUNE_DEFINE_HASH(template_args,type)
99
100
102
107#define DUNE_HASH_TEMPLATE_ARGS(...)
108
110
115#define DUNE_HASH_TYPE(...)
116
117#else // DOXYGEN - hide all the ugly implementation
118
119
120
121// ********************************************************************************
122// C++11 support
123// ********************************************************************************
124
125// import std::hash into Dune namespace
126namespace Dune {
127
128 using std::hash;
129
130}
131
132// Macro for defining a std::hash specialization for type.
133// This should not be called directly. Call DUNE_DEFINE_HASH
134// instead.
135#define DUNE_DEFINE_STD_HASH(template_args,type) \
136 namespace std { \
137 \
138 template<template_args> \
139 struct hash<type> \
140 { \
141 \
142 typedef type argument_type; \
143 typedef std::size_t result_type; \
144 \
145 std::size_t operator()(const type& arg) const \
146 { \
147 return hash_value(arg); \
148 } \
149 }; \
150 \
151 } \
152
153// Wrapper macro for template arguments.
154// This is required because the template arguments can contain commas,
155// which will create a macro argument list of unknown length. That in itself
156// would not be a problem, but DUNE_DEFINE_HASH has to be called with two argument
157// lists of unknown length. So this macro wraps its arguments with parentheses,
158// turning it into a single argument. The result is used as the parameter list of
159// an expansion macro in the calls to the implementation-specific macros
160// for C++11 and TR1. Noto that technically, this trick is only legal for C++11,
161// but pretty much every compiler supports variadic macros in C++03 mode, as they
162// are part of C99.
163#define DUNE_HASH_TEMPLATE_ARGS(...) (__VA_ARGS__)
164
165// Wrapper macro for type to be hashed.
166// See above for rationale.
167#define DUNE_HASH_TYPE(...) (__VA_ARGS__)
168
169// Expansion macro for the parenthesed argument lists created by
170// DUNE_HASH_TEMPLATE_ARGS and DUNE_HASH_TYPE.
171#define DUNE_HASH_EXPAND_VA_ARGS(...) __VA_ARGS__
172
173// Define specializations for all discovered hash implementations.
174#define DUNE_DEFINE_HASH(template_args,type) \
175 DUNE_DEFINE_STD_HASH(DUNE_HASH_EXPAND_VA_ARGS template_args, DUNE_HASH_EXPAND_VA_ARGS type) \
176
177
178#endif // DOXYGEN
179
180
181
182// ********************************************************************************
183// Some utility functions for combining hashes of member variables.
184// ********************************************************************************
185
186namespace Dune {
187
188 // The following functions are an implementation of the proposed hash extensions for
189 // the C++ standard by Peter Dimov
190 // (cf. http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf, issue 6.18).
191 // They are also contained in the boost::functional::hash library by Daniel James, but
192 // that implementation uses boost::hash internally, while we want to use Dune::hash. They
193 // are also considered for inclusion in TR2 (then based on std::hash, of course).
194
195#ifndef DOXYGEN
196
197 // helper struct for providing different hash combining algorithms dependent on
198 // the size of size_t.
199 // hash_combiner has to be specialized for the size (in bytes) of std::size_t.
200 // Specialized versions should provide a method
201 //
202 // template <typename typeof_size_t, typename T>
203 // void operator()(typeof_size_t& seed, const T& arg) const;
204 //
205 // that will be called by the interface function hash_combine() described further below.
206 // The redundant template parameter typeof_size_t is needed to avoid warnings for the
207 // unused 64-bit specialization on 32-bit systems.
208 //
209 // There is no default implementation!
210 template<int sizeof_size_t>
211 struct hash_combiner;
212
213
214 // hash combining for 64-bit platforms.
215 template<>
216 struct hash_combiner<8>
217 {
218
219 template<typename typeof_size_t, typename T>
220 void operator()(typeof_size_t& seed, const T& arg) const
221 {
222 static_assert(sizeof(typeof_size_t)==8, "hash_combiner::operator() instantiated with nonmatching type and size");
223
224 // The following algorithm for combining two 64-bit hash values is inspired by a similar
225 // function in CityHash (http://cityhash.googlecode.com/svn-history/r2/trunk/src/city.h),
226 // which is in turn based on ideas from the MurmurHash library. The basic idea is easy to
227 // grasp, though: New information is XORed into the existing hash multiple times at different
228 // places (using shift operations), and the resulting pattern is spread over the complete
229 // range of available bits via multiplication with a "magic" constant. The constants used
230 // below (47 and 0x9ddfea08eb382d69ULL) are taken from the CityHash implementation.
231 //
232 // We opted not to use the mixing algorithm proposed in the C++ working group defect list at
233 // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf, p. 57f. because it
234 // has very bad hash distribution properties if you apply it to lists of very small numbers,
235 // an application that is frequent in PDELab's ordering framework.
236
237 Dune::hash<T> hasher;
238 const typeof_size_t kMul = 0x9ddfea08eb382d69ULL;
239 typeof_size_t h = hasher(arg);
240 typeof_size_t a = (seed ^ h) * kMul;
241 a ^= (a >> 47);
242 typeof_size_t b = (h ^ a) * kMul;
243 b ^= (b >> 47);
244 b *= kMul;
245 seed = b;
246 }
247
248 };
249
250
251 // hash combining for 32-bit platforms.
252 template<>
253 struct hash_combiner<4>
254 {
255
256 template<typename typeof_size_t, typename T>
257 void operator()(typeof_size_t& seed, const T& arg) const
258 {
259 static_assert(sizeof(typeof_size_t)==4, "hash_combiner::operator() instantiated with nonmatching type and size");
260
261 // The default algorithm above requires a 64-bit std::size_t. The following algorithm is a
262 // 32-bit compatible fallback, again inspired by CityHash and MurmurHash
263 // (http://cityhash.googlecode.com/svn-history/r2/trunk/src/city.cc).
264 // It uses 32-bit constants and relies on rotation instead of multiplication to spread the
265 // mixed bits as that is apparently more efficient on IA-32. The constants used below are again
266 // taken from CityHash, in particular from the file referenced above.
267
268 Dune::hash<T> hasher;
269 const typeof_size_t c1 = 0xcc9e2d51;
270 const typeof_size_t c2 = 0x1b873593;
271 const typeof_size_t c3 = 0xe6546b64;
272 typeof_size_t h = hasher(arg);
273 typeof_size_t a = seed * c1;
274 a = (a >> 17) | (a << (32 - 17));
275 a *= c2;
276 h ^= a;
277 h = (h >> 19) | (h << (32 - 19));
278 seed = h * 5 + c3;
279 }
280
281 };
282
283#endif // DOXYGEN
284
286
291 template<typename T>
292 inline void hash_combine(std::size_t& seed, const T& arg)
293 {
294 hash_combiner<sizeof(std::size_t)>()(seed,arg);
295 }
296
298
306 template<typename It>
307 inline std::size_t hash_range(It first, It last)
308 {
309 std::size_t seed = 0;
310 for (; first != last; ++first)
311 {
312 hash_combine(seed,*first);
313 }
314 return seed;
315 }
316
318
325 template<typename It>
326 inline void hash_range(std::size_t& seed, It first, It last)
327 {
328 for (; first != last; ++first)
329 {
330 hash_combine(seed,*first);
331 }
332 }
333
334} // end namespace Dune
335
336#endif // DUNE_COMMON_HASH_HH
Dune namespace.
Definition: alignment.hh:11
std::size_t hash_range(It first, It last)
Hashes all elements in the range [first,last) and returns the combined hash.
Definition: hash.hh:307
void hash_combine(std::size_t &seed, const T &arg)
Calculates the hash value of arg and combines it in-place with seed.
Definition: hash.hh:292
Functor for hashing objects of type T.
Definition: hash.hh:38
std::size_t operator()(const T &t) const
Calculates the hash of t.
Definition: hash.hh:41
Traits for type conversions and type information.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 23, 23:29, 2024)