LCOV - code coverage report
Current view: directory - gfx/angle/src/compiler - spooky.h (source / functions) Found Hit Coverage
Test: app.info Lines: 66 0 0.0 %
Date: 2012-06-02 Functions: 7 0 0.0 %

       1                 : //
       2                 : // SpookyHash: a 128-bit noncryptographic hash function
       3                 : // By Bob Jenkins, public domain
       4                 : //   Oct 31 2010: alpha, framework + SpookyHash::Mix appears right
       5                 : //   Oct 31 2011: alpha again, Mix only good to 2^^69 but rest appears right
       6                 : //   Dec 31 2011: beta, improved Mix, tested it for 2-bit deltas
       7                 : //   Feb  2 2012: production, same bits as beta
       8                 : //   Feb  5 2012: adjusted definitions of uint* to be more portable
       9                 : // 
      10                 : // Up to 4 bytes/cycle for long messages.  Reasonably fast for short messages.
      11                 : // All 1 or 2 bit deltas achieve avalanche within 1% bias per output bit.
      12                 : //
      13                 : // This was developed for and tested on 64-bit x86-compatible processors.
      14                 : // It assumes the processor is little-endian.  There is a macro
      15                 : // controlling whether unaligned reads are allowed (by default they are).
      16                 : // This should be an equally good hash on big-endian machines, but it will
      17                 : // compute different results on them than on little-endian machines.
      18                 : //
      19                 : // Google's CityHash has similar specs to SpookyHash, and CityHash is faster
      20                 : // on some platforms.  MD4 and MD5 also have similar specs, but they are orders
      21                 : // of magnitude slower.  CRCs are two or more times slower, but unlike 
      22                 : // SpookyHash, they have nice math for combining the CRCs of pieces to form 
      23                 : // the CRCs of wholes.  There are also cryptographic hashes, but those are even 
      24                 : // slower than MD5.
      25                 : //
      26                 : 
      27                 : #include <stddef.h>
      28                 : 
      29                 : #ifdef _MSC_VER
      30                 : # define INLINE __forceinline
      31                 :   typedef  unsigned __int64 uint64;
      32                 :   typedef  unsigned __int32 uint32;
      33                 :   typedef  unsigned __int16 uint16;
      34                 :   typedef  unsigned __int8  uint8;
      35                 : #else
      36                 : # include <stdint.h>
      37                 : # define INLINE inline
      38                 :   typedef  uint64_t  uint64;
      39                 :   typedef  uint32_t  uint32;
      40                 :   typedef  uint16_t  uint16;
      41                 :   typedef  uint8_t   uint8;
      42                 : #endif
      43                 : 
      44                 : 
      45                 : class SpookyHash
      46                 : {
      47                 : public:
      48                 :     //
      49                 :     // SpookyHash: hash a single message in one call, produce 128-bit output
      50                 :     //
      51                 :     static void Hash128(
      52                 :         const void *message,  // message to hash
      53                 :         size_t length,        // length of message in bytes
      54                 :         uint64 *hash1,        // in/out: in seed 1, out hash value 1
      55                 :         uint64 *hash2);       // in/out: in seed 2, out hash value 2
      56                 : 
      57                 :     //
      58                 :     // Hash64: hash a single message in one call, return 64-bit output
      59                 :     //
      60               0 :     static uint64 Hash64(
      61                 :         const void *message,  // message to hash
      62                 :         size_t length,        // length of message in bytes
      63                 :         uint64 seed)          // seed
      64                 :     {
      65               0 :         uint64 hash1 = seed;
      66               0 :         Hash128(message, length, &hash1, &seed);
      67               0 :         return hash1;
      68                 :     }
      69                 : 
      70                 :     //
      71                 :     // Hash32: hash a single message in one call, produce 32-bit output
      72                 :     //
      73                 :     static uint32 Hash32(
      74                 :         const void *message,  // message to hash
      75                 :         size_t length,        // length of message in bytes
      76                 :         uint32 seed)          // seed
      77                 :     {
      78                 :         uint64 hash1 = seed, hash2 = seed;
      79                 :         Hash128(message, length, &hash1, &hash2);
      80                 :         return (uint32)hash1;
      81                 :     }
      82                 : 
      83                 :     //
      84                 :     // Init: initialize the context of a SpookyHash
      85                 :     //
      86                 :     void Init(
      87                 :         uint64 seed1,       // any 64-bit value will do, including 0
      88                 :         uint64 seed2);      // different seeds produce independent hashes
      89                 :     
      90                 :     //
      91                 :     // Update: add a piece of a message to a SpookyHash state
      92                 :     //
      93                 :     void Update(
      94                 :         const void *message,  // message fragment
      95                 :         size_t length);       // length of message fragment in bytes
      96                 : 
      97                 : 
      98                 :     //
      99                 :     // Final: compute the hash for the current SpookyHash state
     100                 :     //
     101                 :     // This does not modify the state; you can keep updating it afterward
     102                 :     //
     103                 :     // The result is the same as if SpookyHash() had been called with
     104                 :     // all the pieces concatenated into one message.
     105                 :     //
     106                 :     void Final(
     107                 :         uint64 *hash1,    // out only: first 64 bits of hash value.
     108                 :         uint64 *hash2);   // out only: second 64 bits of hash value.
     109                 : 
     110                 :     //
     111                 :     // left rotate a 64-bit value by k bytes
     112                 :     //
     113               0 :     static INLINE uint64 Rot64(uint64 x, int k)
     114                 :     {
     115               0 :         return (x << k) | (x >> (64 - k));
     116                 :     }
     117                 : 
     118                 :     //
     119                 :     // This is used if the input is 96 bytes long or longer.
     120                 :     //
     121                 :     // The internal state is fully overwritten every 96 bytes.
     122                 :     // Every input bit appears to cause at least 128 bits of entropy
     123                 :     // before 96 other bytes are combined, when run forward or backward
     124                 :     //   For every input bit,
     125                 :     //   Two inputs differing in just that input bit
     126                 :     //   Where "differ" means xor or subtraction
     127                 :     //   And the base value is random
     128                 :     //   When run forward or backwards one Mix
     129                 :     // I tried 3 pairs of each; they all differed by at least 212 bits.
     130                 :     //
     131               0 :     static INLINE void Mix(
     132                 :         const uint64 *data, 
     133                 :         uint64 &s0, uint64 &s1, uint64 &s2, uint64 &s3,
     134                 :         uint64 &s4, uint64 &s5, uint64 &s6, uint64 &s7,
     135                 :         uint64 &s8, uint64 &s9, uint64 &s10,uint64 &s11)
     136                 :     {
     137               0 :       s0 += data[0];    s2 ^= s10;    s11 ^= s0;    s0 = Rot64(s0,11);    s11 += s1;
     138               0 :       s1 += data[1];    s3 ^= s11;    s0 ^= s1;    s1 = Rot64(s1,32);    s0 += s2;
     139               0 :       s2 += data[2];    s4 ^= s0;    s1 ^= s2;    s2 = Rot64(s2,43);    s1 += s3;
     140               0 :       s3 += data[3];    s5 ^= s1;    s2 ^= s3;    s3 = Rot64(s3,31);    s2 += s4;
     141               0 :       s4 += data[4];    s6 ^= s2;    s3 ^= s4;    s4 = Rot64(s4,17);    s3 += s5;
     142               0 :       s5 += data[5];    s7 ^= s3;    s4 ^= s5;    s5 = Rot64(s5,28);    s4 += s6;
     143               0 :       s6 += data[6];    s8 ^= s4;    s5 ^= s6;    s6 = Rot64(s6,39);    s5 += s7;
     144               0 :       s7 += data[7];    s9 ^= s5;    s6 ^= s7;    s7 = Rot64(s7,57);    s6 += s8;
     145               0 :       s8 += data[8];    s10 ^= s6;    s7 ^= s8;    s8 = Rot64(s8,55);    s7 += s9;
     146               0 :       s9 += data[9];    s11 ^= s7;    s8 ^= s9;    s9 = Rot64(s9,54);    s8 += s10;
     147               0 :       s10 += data[10];    s0 ^= s8;    s9 ^= s10;    s10 = Rot64(s10,22);    s9 += s11;
     148               0 :       s11 += data[11];    s1 ^= s9;    s10 ^= s11;    s11 = Rot64(s11,46);    s10 += s0;
     149               0 :     }
     150                 : 
     151                 :     //
     152                 :     // Mix all 12 inputs together so that h0, h1 are a hash of them all.
     153                 :     //
     154                 :     // For two inputs differing in just the input bits
     155                 :     // Where "differ" means xor or subtraction
     156                 :     // And the base value is random, or a counting value starting at that bit
     157                 :     // The final result will have each bit of h0, h1 flip
     158                 :     // For every input bit,
     159                 :     // with probability 50 +- .3%
     160                 :     // For every pair of input bits,
     161                 :     // with probability 50 +- 3%
     162                 :     //
     163                 :     // This does not rely on the last Mix() call having already mixed some.
     164                 :     // Two iterations was almost good enough for a 64-bit result, but a
     165                 :     // 128-bit result is reported, so End() does three iterations.
     166                 :     //
     167               0 :     static INLINE void EndPartial(
     168                 :         uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3,
     169                 :         uint64 &h4, uint64 &h5, uint64 &h6, uint64 &h7, 
     170                 :         uint64 &h8, uint64 &h9, uint64 &h10,uint64 &h11)
     171                 :     {
     172               0 :         h11+= h1;    h2 ^= h11;   h1 = Rot64(h1,44);
     173               0 :         h0 += h2;    h3 ^= h0;    h2 = Rot64(h2,15);
     174               0 :         h1 += h3;    h4 ^= h1;    h3 = Rot64(h3,34);
     175               0 :         h2 += h4;    h5 ^= h2;    h4 = Rot64(h4,21);
     176               0 :         h3 += h5;    h6 ^= h3;    h5 = Rot64(h5,38);
     177               0 :         h4 += h6;    h7 ^= h4;    h6 = Rot64(h6,33);
     178               0 :         h5 += h7;    h8 ^= h5;    h7 = Rot64(h7,10);
     179               0 :         h6 += h8;    h9 ^= h6;    h8 = Rot64(h8,13);
     180               0 :         h7 += h9;    h10^= h7;    h9 = Rot64(h9,38);
     181               0 :         h8 += h10;   h11^= h8;    h10= Rot64(h10,53);
     182               0 :         h9 += h11;   h0 ^= h9;    h11= Rot64(h11,42);
     183               0 :         h10+= h0;    h1 ^= h10;   h0 = Rot64(h0,54);
     184               0 :     }
     185                 : 
     186               0 :     static INLINE void End(
     187                 :         uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3,
     188                 :         uint64 &h4, uint64 &h5, uint64 &h6, uint64 &h7, 
     189                 :         uint64 &h8, uint64 &h9, uint64 &h10,uint64 &h11)
     190                 :     {
     191               0 :         EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     192               0 :         EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     193               0 :         EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     194               0 :     }
     195                 : 
     196                 :     //
     197                 :     // The goal is for each bit of the input to expand into 128 bits of 
     198                 :     //   apparent entropy before it is fully overwritten.
     199                 :     // n trials both set and cleared at least m bits of h0 h1 h2 h3
     200                 :     //   n: 2   m: 29
     201                 :     //   n: 3   m: 46
     202                 :     //   n: 4   m: 57
     203                 :     //   n: 5   m: 107
     204                 :     //   n: 6   m: 146
     205                 :     //   n: 7   m: 152
     206                 :     // when run forwards or backwards
     207                 :     // for all 1-bit and 2-bit diffs
     208                 :     // with diffs defined by either xor or subtraction
     209                 :     // with a base of all zeros plus a counter, or plus another bit, or random
     210                 :     //
     211               0 :     static INLINE void ShortMix(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3)
     212                 :     {
     213               0 :         h2 = Rot64(h2,50);  h2 += h3;  h0 ^= h2;
     214               0 :         h3 = Rot64(h3,52);  h3 += h0;  h1 ^= h3;
     215               0 :         h0 = Rot64(h0,30);  h0 += h1;  h2 ^= h0;
     216               0 :         h1 = Rot64(h1,41);  h1 += h2;  h3 ^= h1;
     217               0 :         h2 = Rot64(h2,54);  h2 += h3;  h0 ^= h2;
     218               0 :         h3 = Rot64(h3,48);  h3 += h0;  h1 ^= h3;
     219               0 :         h0 = Rot64(h0,38);  h0 += h1;  h2 ^= h0;
     220               0 :         h1 = Rot64(h1,37);  h1 += h2;  h3 ^= h1;
     221               0 :         h2 = Rot64(h2,62);  h2 += h3;  h0 ^= h2;
     222               0 :         h3 = Rot64(h3,34);  h3 += h0;  h1 ^= h3;
     223               0 :         h0 = Rot64(h0,5);   h0 += h1;  h2 ^= h0;
     224               0 :         h1 = Rot64(h1,36);  h1 += h2;  h3 ^= h1;
     225               0 :     }
     226                 : 
     227                 :     //
     228                 :     // Mix all 4 inputs together so that h0, h1 are a hash of them all.
     229                 :     //
     230                 :     // For two inputs differing in just the input bits
     231                 :     // Where "differ" means xor or subtraction
     232                 :     // And the base value is random, or a counting value starting at that bit
     233                 :     // The final result will have each bit of h0, h1 flip
     234                 :     // For every input bit,
     235                 :     // with probability 50 +- .3% (it is probably better than that)
     236                 :     // For every pair of input bits,
     237                 :     // with probability 50 +- .75% (the worst case is approximately that)
     238                 :     //
     239               0 :     static INLINE void ShortEnd(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3)
     240                 :     {
     241               0 :         h3 ^= h2;  h2 = Rot64(h2,15);  h3 += h2;
     242               0 :         h0 ^= h3;  h3 = Rot64(h3,52);  h0 += h3;
     243               0 :         h1 ^= h0;  h0 = Rot64(h0,26);  h1 += h0;
     244               0 :         h2 ^= h1;  h1 = Rot64(h1,51);  h2 += h1;
     245               0 :         h3 ^= h2;  h2 = Rot64(h2,28);  h3 += h2;
     246               0 :         h0 ^= h3;  h3 = Rot64(h3,9);   h0 += h3;
     247               0 :         h1 ^= h0;  h0 = Rot64(h0,47);  h1 += h0;
     248               0 :         h2 ^= h1;  h1 = Rot64(h1,54);  h2 += h1;
     249               0 :         h3 ^= h2;  h2 = Rot64(h2,32);  h3 += h2;
     250               0 :         h0 ^= h3;  h3 = Rot64(h3,25);  h0 += h3;
     251               0 :         h1 ^= h0;  h0 = Rot64(h0,63);  h1 += h0;
     252               0 :     }
     253                 :     
     254                 : private:
     255                 : 
     256                 :     //
     257                 :     // Short is used for messages under 192 bytes in length
     258                 :     // Short has a low startup cost, the normal mode is good for long
     259                 :     // keys, the cost crossover is at about 192 bytes.  The two modes were
     260                 :     // held to the same quality bar.
     261                 :     // 
     262                 :     static void Short(
     263                 :         const void *message,
     264                 :         size_t length,
     265                 :         uint64 *hash1,
     266                 :         uint64 *hash2);
     267                 : 
     268                 :     // number of uint64's in internal state
     269                 :     static const size_t sc_numVars = 12;
     270                 : 
     271                 :     // size of the internal state
     272                 :     static const size_t sc_blockSize = sc_numVars*8;
     273                 : 
     274                 :     // size of buffer of unhashed data, in bytes
     275                 :     static const size_t sc_bufSize = 2*sc_blockSize;
     276                 : 
     277                 :     //
     278                 :     // sc_const: a constant which:
     279                 :     //  * is not zero
     280                 :     //  * is odd
     281                 :     //  * is a not-very-regular mix of 1's and 0's
     282                 :     //  * does not need any other special mathematical properties
     283                 :     //
     284                 :     static const uint64 sc_const = 0xdeadbeefdeadbeefLL;
     285                 : 
     286                 :     uint64 m_data[2*sc_numVars];   // unhashed data, for partial messages
     287                 :     uint64 m_state[sc_numVars];  // internal state of the hash
     288                 :     size_t m_length;             // total length of the input so far
     289                 :     uint8  m_remainder;          // length of unhashed data stashed in m_data
     290                 : };
     291                 : 
     292                 : 
     293                 : 

Generated by: LCOV version 1.7