$extrastylesheet
hashword.h
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 #ifndef LIBMESH_HASHWORD_H
00019 #define LIBMESH_HASHWORD_H
00020 
00021 // ::size_t is defined in the backward compatibility header stddef.h.
00022 // It's been part of ANSI/ISO C and ISO C++ since their very
00023 // beginning. Every C++ implementation has to ship with stddef.h
00024 // (compatibility) and cstddef where only the latter defines
00025 // std::size_t and not necessarily ::size_t. See Annex D of the C++
00026 // Standard.
00027 //
00028 // http://stackoverflow.com/questions/237370/does-stdsize-t-make-sense-in-c
00029 #include <stddef.h>
00030 #include <stdint.h> // uint32_t, uint64_t
00031 
00032 #include "libmesh_common.h" // libmesh_error_msg()
00033 
00034 // Anonymous namespace for utility functions used locally
00035 namespace
00036 {
00037 // Rotate x by k bits
00038 // @author Bob Jenkins, May 2006, Public Domain.
00039 // http://burtleburtle.net/bob/hash/index.html
00040 inline
00041 uint32_t rot(uint32_t x, uint32_t k)
00042 {
00043   return (x<<k) | (x>>(32-k));
00044 }
00045 
00046 
00047 
00048 // mix 3 32-bit values reversibly
00049 // @author Bob Jenkins, May 2006, Public Domain.
00050 // http://burtleburtle.net/bob/hash/index.html
00051 inline
00052 void mix(uint32_t& a, uint32_t& b, uint32_t& c)
00053 {
00054   a -= c;  a ^= rot(c, 4);  c += b;
00055   b -= a;  b ^= rot(a, 6);  a += c;
00056   c -= b;  c ^= rot(b, 8);  b += a;
00057   a -= c;  a ^= rot(c,16);  c += b;
00058   b -= a;  b ^= rot(a,19);  a += c;
00059   c -= b;  c ^= rot(b, 4);  b += a;
00060 }
00061 
00062 
00063 // 'final' mixing of 3 32-bit numbers, result is stored in c.
00064 // @author Bob Jenkins, May 2006, Public Domain.
00065 // http://burtleburtle.net/bob/hash/index.html
00066 inline
00067 void final(uint32_t& a, uint32_t& b, uint32_t& c)
00068 {
00069   c ^= b; c -= rot(b,14);
00070   a ^= c; a -= rot(c,11);
00071   b ^= a; b -= rot(a,25);
00072   c ^= b; c -= rot(b,16);
00073   a ^= c; a -= rot(c,4);
00074   b ^= a; b -= rot(a,14);
00075   c ^= b; c -= rot(b,24);
00076 }
00077 
00078 
00079 // fnv_64_buf - perform a 64 bit Fowler/Noll/Vo hash on a buffer.
00080 // http://www.isthe.com/chongo/tech/comp/fnv/index.html
00081 // Code is in the public domain.
00082 //
00083 // Authors:
00084 // Phong Vo (http://www.research.att.com/info/kpv/)
00085 // Glenn Fowler (http://www.research.att.com/~gsf/)
00086 // Landon Curt Noll (http://www.isthe.com/chongo/)
00087 //
00088 // input:
00089 // buf - start of buffer to hash
00090 // len - length of buffer in octets
00091 //
00092 // returns: 64 bit hash as a static hash type
00093 uint64_t fnv_64_buf(const void *buf, size_t len)
00094 {
00095   // Initializing hval with this value corresponds to the FNV-1 hash algorithm.
00096   uint64_t hval = static_cast<uint64_t>(0xcbf29ce484222325ULL);
00097 
00098   // start of buffer
00099   const unsigned char *bp = static_cast<const unsigned char *>(buf);
00100 
00101   // beyond end of buffer
00102   const unsigned char *be = bp + len;
00103 
00104   // FNV-1 hash each octet of the buffer
00105   while (bp < be)
00106     {
00107       hval +=
00108         (hval << 1) + (hval << 4) + (hval << 5) +
00109         (hval << 7) + (hval << 8) + (hval << 40);
00110 
00111       // xor the bottom with the current octet
00112       hval ^= static_cast<uint64_t>(*bp++);
00113     }
00114 
00115   // return our new hash value
00116   return hval;
00117 }
00118 
00119 } // end anonymous namespace
00120 
00121 
00122 
00123 namespace libMesh
00124 {
00125 namespace Utility
00126 {
00127 // The hashword function takes an array of uint32_t's of length 'length'
00128 // and computes a single key from it.
00129 // @author Bob Jenkins, May 2006, Public Domain.
00130 // http://burtleburtle.net/bob/hash/index.html
00131 inline
00132 uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval=0)
00133 {
00134   uint32_t a,b,c;
00135 
00136   // Set up the internal state
00137   a = b = c = 0xdeadbeef + ((static_cast<uint32_t>(length))<<2) + initval;
00138 
00139   //------------------------------------------------- handle most of the key
00140   while (length > 3)
00141     {
00142       a += k[0];
00143       b += k[1];
00144       c += k[2];
00145       mix(a,b,c);
00146       length -= 3;
00147       k += 3;
00148     }
00149 
00150   //------------------------------------------- handle the last 3 uint32_t's
00151   switch(length)                     // all the case statements fall through
00152     {
00153     case 3 : c+=k[2];
00154     case 2 : b+=k[1];
00155     case 1 : a+=k[0];
00156       final(a,b,c);
00157     default:     // case 0: nothing left to add
00158       break;
00159     }
00160 
00161   //------------------------------------------------------ report the result
00162   return c;
00163 }
00164 
00165 
00166 // This is a hard-coded version of hashword for hashing exactly 2 numbers
00167 // @author Bob Jenkins, May 2006, Public Domain.
00168 // http://burtleburtle.net/bob/hash/index.html
00169 inline
00170 uint32_t hashword2(const uint32_t& first, const uint32_t& second, uint32_t initval=0)
00171 {
00172   uint32_t a,b,c;
00173 
00174   // Set up the internal state
00175   a = b = c = 0xdeadbeef + 8 + initval;
00176 
00177   b+=second;
00178   a+=first;
00179   final(a,b,c);
00180 
00181   return c;
00182 }
00183 
00184 // Call the 64-bit FNV hash function.
00185 inline
00186 uint64_t hashword2(const uint64_t first, const uint64_t second)
00187 {
00188   // This isn't optimal (it would be nice to avoid this packing step)
00189   // but we are going to go ahead and conform to the 32-bit
00190   // hashword2() interface.
00191   uint64_t k[2] = {first, second};
00192 
00193   // len is the total number of bytes in two 64-bit ints
00194   return fnv_64_buf(k, /*len=*/8*2);
00195 }
00196 
00197 inline
00198 uint16_t hashword2(const uint16_t first, const uint16_t second)
00199 {
00200   return static_cast<uint16_t>(first%65449 + (second<<5)%65449);
00201 }
00202 
00203 // Call the 64-bit FNV hash function.
00204 inline
00205 uint64_t hashword(const uint64_t *k, size_t length)
00206 {
00207   return fnv_64_buf(k, 8*length);
00208 }
00209 
00210 // In a personal communication from Bob Jenkins, he recommended using
00211 // "Probably final() from lookup3.c... You could hash up to 6 16-bit
00212 // integers that way.  The output is c, or the top or bottom 16 bits
00213 // of c if you only need 16 bit hash values." [JWP]
00214 inline
00215 uint16_t hashword(const uint16_t *k, size_t length)
00216 {
00217   // Three values that will be passed to final() after they are initialized.
00218   uint32_t a = 0;
00219   uint32_t b = 0;
00220   uint32_t c = 0;
00221 
00222   switch (length)
00223     {
00224     case 3:
00225       {
00226         // Cast the inputs to 32 bit integers and call final().
00227         a = k[0];
00228         b = k[1];
00229         c = k[2];
00230         break;
00231       }
00232     case 4:
00233       {
00234         // Combine the 4 16-bit inputs, "w, x, y, z" into two 32-bit
00235         // inputs "wx" and "yz" using bit operations and call final.
00236         a = ((k[0]<<16) | (k[1] & 0xffff)); // wx
00237         b = ((k[2]<<16) | (k[3] & 0xffff)); // yz
00238         break;
00239       }
00240     default:
00241       libmesh_error_msg("Unsupported length: " << length);
00242     }
00243 
00244   // Result is returned in c
00245   final(a,b,c);
00246   return static_cast<uint16_t>(c);
00247 }
00248 
00249 } // end Utility namespace
00250 } // end libMesh namespace
00251 
00252 #endif // LIBMESH_HASHWORD_H