Dune Core Modules (2.5.2)

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 
28 namespace 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
126 namespace 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 
186 namespace 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.80.0 (May 16, 22:29, 2024)