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

       1                 : // Spooky Hash
       2                 : // A 128-bit noncryptographic hash, for checksums and table lookup
       3                 : // By Bob Jenkins.  Public domain.
       4                 : //   Oct 31 2010: published framework, disclaimer ShortHash isn't right
       5                 : //   Nov 7 2010: disabled ShortHash
       6                 : //   Oct 31 2011: replace End, ShortMix, ShortEnd, enable ShortHash again
       7                 : 
       8                 : #include <memory.h>
       9                 : #include <string.h>
      10                 : #include "spooky.h"
      11                 : 
      12                 : #define ALLOW_UNALIGNED_READS 1
      13                 : 
      14                 : //
      15                 : // short hash ... it could be used on any message, 
      16                 : // but it's used by Spooky just for short messages.
      17                 : //
      18               0 : void SpookyHash::Short(
      19                 :     const void *message,
      20                 :     size_t length,
      21                 :     uint64 *hash1,
      22                 :     uint64 *hash2)
      23                 : {
      24                 :     uint64 buf[sc_numVars];
      25                 :     union 
      26                 :     { 
      27                 :         const uint8 *p8; 
      28                 :         uint32 *p32;
      29                 :         uint64 *p64; 
      30                 :         size_t i; 
      31                 :     } u;
      32                 : 
      33               0 :     u.p8 = (const uint8 *)message;
      34                 :     
      35                 :     if (!ALLOW_UNALIGNED_READS && (u.i & 0x7))
      36                 :     {
      37                 :         memcpy(buf, message, length);
      38                 :         u.p64 = buf;
      39                 :     }
      40                 : 
      41               0 :     size_t remainder = length%32;
      42               0 :     uint64 a=*hash1;
      43               0 :     uint64 b=*hash2;
      44               0 :     uint64 c=sc_const;
      45               0 :     uint64 d=sc_const;
      46                 : 
      47               0 :     if (length > 15)
      48                 :     {
      49               0 :         const uint64 *end = u.p64 + (length/32)*4;
      50                 :         
      51                 :         // handle all complete sets of 32 bytes
      52               0 :         for (; u.p64 < end; u.p64 += 4)
      53                 :         {
      54               0 :             c += u.p64[0];
      55               0 :             d += u.p64[1];
      56               0 :             ShortMix(a,b,c,d);
      57               0 :             a += u.p64[2];
      58               0 :             b += u.p64[3];
      59                 :         }
      60                 :         
      61                 :         //Handle the case of 16+ remaining bytes.
      62               0 :         if (remainder >= 16)
      63                 :         {
      64               0 :             c += u.p64[0];
      65               0 :             d += u.p64[1];
      66               0 :             ShortMix(a,b,c,d);
      67               0 :             u.p64 += 2;
      68               0 :             remainder -= 16;
      69                 :         }
      70                 :     }
      71                 :     
      72                 :     // Handle the last 0..15 bytes, and its length
      73               0 :     d = ((uint64)length) << 56;
      74               0 :     switch (remainder)
      75                 :     {
      76                 :     case 15:
      77               0 :     d += ((uint64)u.p8[14]) << 48;
      78                 :     case 14:
      79               0 :         d += ((uint64)u.p8[13]) << 40;
      80                 :     case 13:
      81               0 :         d += ((uint64)u.p8[12]) << 32;
      82                 :     case 12:
      83               0 :         d += u.p32[2];
      84               0 :         c += u.p64[0];
      85               0 :         break;
      86                 :     case 11:
      87               0 :         d += ((uint64)u.p8[10]) << 16;
      88                 :     case 10:
      89               0 :         d += ((uint64)u.p8[9]) << 8;
      90                 :     case 9:
      91               0 :         d += (uint64)u.p8[8];
      92                 :     case 8:
      93               0 :         c += u.p64[0];
      94               0 :         break;
      95                 :     case 7:
      96               0 :         c += ((uint64)u.p8[6]) << 48;
      97                 :     case 6:
      98               0 :         c += ((uint64)u.p8[5]) << 40;
      99                 :     case 5:
     100               0 :         c += ((uint64)u.p8[4]) << 32;
     101                 :     case 4:
     102               0 :         c += u.p32[0];
     103               0 :         break;
     104                 :     case 3:
     105               0 :         c += ((uint64)u.p8[2]) << 16;
     106                 :     case 2:
     107               0 :         c += ((uint64)u.p8[1]) << 8;
     108                 :     case 1:
     109               0 :         c += (uint64)u.p8[0];
     110               0 :         break;
     111                 :     case 0:
     112               0 :         c += sc_const;
     113               0 :         d += sc_const;
     114                 :     }
     115               0 :     ShortEnd(a,b,c,d);
     116               0 :     *hash1 = a;
     117               0 :     *hash2 = b;
     118               0 : }
     119                 : 
     120                 : 
     121                 : 
     122                 : 
     123                 : // do the whole hash in one call
     124               0 : void SpookyHash::Hash128(
     125                 :     const void *message, 
     126                 :     size_t length, 
     127                 :     uint64 *hash1, 
     128                 :     uint64 *hash2)
     129                 : {
     130               0 :     if (length < sc_bufSize)
     131                 :     {
     132               0 :         Short(message, length, hash1, hash2);
     133               0 :         return;
     134                 :     }
     135                 : 
     136                 :     uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
     137                 :     uint64 buf[sc_numVars];
     138                 :     uint64 *end;
     139                 :     union 
     140                 :     { 
     141                 :         const uint8 *p8; 
     142                 :         uint64 *p64; 
     143                 :         size_t i; 
     144                 :     } u;
     145                 :     size_t remainder;
     146                 :     
     147               0 :     h0=h3=h6=h9  = *hash1;
     148               0 :     h1=h4=h7=h10 = *hash2;
     149               0 :     h2=h5=h8=h11 = sc_const;
     150                 :     
     151               0 :     u.p8 = (const uint8 *)message;
     152               0 :     end = u.p64 + (length/sc_blockSize)*sc_numVars;
     153                 : 
     154                 :     // handle all whole sc_blockSize blocks of bytes
     155                 :     if (ALLOW_UNALIGNED_READS || ((u.i & 0x7) == 0))
     156                 :     {
     157               0 :         while (u.p64 < end)
     158                 :         { 
     159               0 :             Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     160               0 :             u.p64 += sc_numVars;
     161                 :         }
     162                 :     }
     163                 :     else
     164                 :     {
     165                 :         while (u.p64 < end)
     166                 :         {
     167                 :             memcpy(buf, u.p64, sc_blockSize);
     168                 :             Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     169                 :             u.p64 += sc_numVars;
     170                 :         }
     171                 :     }
     172                 : 
     173                 :     // handle the last partial block of sc_blockSize bytes
     174               0 :     remainder = (length - ((const uint8 *)end-(const uint8 *)message));
     175               0 :     memcpy(buf, end, remainder);
     176               0 :     memset(((uint8 *)buf)+remainder, 0, sc_blockSize-remainder);
     177               0 :     ((uint8 *)buf)[sc_blockSize-1] = remainder;
     178               0 :     Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     179                 :     
     180                 :     // do some final mixing 
     181               0 :     End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     182               0 :     *hash1 = h0;
     183               0 :     *hash2 = h1;
     184                 : }
     185                 : 
     186                 : 
     187                 : 
     188                 : // init spooky state
     189               0 : void SpookyHash::Init(uint64 seed1, uint64 seed2)
     190                 : {
     191               0 :     m_length = 0;
     192               0 :     m_remainder = 0;
     193               0 :     m_state[0] = seed1;
     194               0 :     m_state[1] = seed2;
     195               0 : }
     196                 : 
     197                 : 
     198                 : // add a message fragment to the state
     199               0 : void SpookyHash::Update(const void *message, size_t length)
     200                 : {
     201                 :     uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
     202               0 :     size_t newLength = length + m_remainder;
     203                 :     uint8  remainder;
     204                 :     union 
     205                 :     { 
     206                 :         const uint8 *p8; 
     207                 :         uint64 *p64; 
     208                 :         size_t i; 
     209                 :     } u;
     210                 :     const uint64 *end;
     211                 :     
     212                 :     // Is this message fragment too short?  If it is, stuff it away.
     213               0 :     if (newLength < sc_bufSize)
     214                 :     {
     215               0 :         memcpy(&((uint8 *)m_data)[m_remainder], message, length);
     216               0 :         m_length = length + m_length;
     217               0 :         m_remainder = (uint8)newLength;
     218               0 :         return;
     219                 :     }
     220                 :     
     221                 :     // init the variables
     222               0 :     if (m_length < sc_bufSize)
     223                 :     {
     224               0 :         h0=h3=h6=h9  = m_state[0];
     225               0 :         h1=h4=h7=h10 = m_state[1];
     226               0 :         h2=h5=h8=h11 = sc_const;
     227                 :     }
     228                 :     else
     229                 :     {
     230               0 :         h0 = m_state[0];
     231               0 :         h1 = m_state[1];
     232               0 :         h2 = m_state[2];
     233               0 :         h3 = m_state[3];
     234               0 :         h4 = m_state[4];
     235               0 :         h5 = m_state[5];
     236               0 :         h6 = m_state[6];
     237               0 :         h7 = m_state[7];
     238               0 :         h8 = m_state[8];
     239               0 :         h9 = m_state[9];
     240               0 :         h10 = m_state[10];
     241               0 :         h11 = m_state[11];
     242                 :     }
     243               0 :     m_length = length + m_length;
     244                 :     
     245                 :     // if we've got anything stuffed away, use it now
     246               0 :     if (m_remainder)
     247                 :     {
     248               0 :         uint8 prefix = sc_bufSize-m_remainder;
     249               0 :         memcpy(&(((uint8 *)m_data)[m_remainder]), message, prefix);
     250               0 :         u.p64 = m_data;
     251               0 :         Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     252               0 :         Mix(&u.p64[sc_numVars], h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     253               0 :         u.p8 = ((const uint8 *)message) + prefix;
     254               0 :         length -= prefix;
     255                 :     }
     256                 :     else
     257                 :     {
     258               0 :         u.p8 = (const uint8 *)message;
     259                 :     }
     260                 :     
     261                 :     // handle all whole blocks of sc_blockSize bytes
     262               0 :     end = u.p64 + (length/sc_blockSize)*sc_numVars;
     263               0 :     remainder = (uint8)(length-((const uint8 *)end-u.p8));
     264                 :     if (ALLOW_UNALIGNED_READS || (u.i & 0x7) == 0)
     265                 :     {
     266               0 :         while (u.p64 < end)
     267                 :         { 
     268               0 :             Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     269               0 :             u.p64 += sc_numVars;
     270                 :         }
     271                 :     }
     272                 :     else
     273                 :     {
     274                 :         while (u.p64 < end)
     275                 :         { 
     276                 :             memcpy(m_data, u.p8, sc_blockSize);
     277                 :             Mix(m_data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     278                 :             u.p64 += sc_numVars;
     279                 :         }
     280                 :     }
     281                 : 
     282                 :     // stuff away the last few bytes
     283               0 :     m_remainder = remainder;
     284               0 :     memcpy(m_data, end, remainder);
     285                 :     
     286                 :     // stuff away the variables
     287               0 :     m_state[0] = h0;
     288               0 :     m_state[1] = h1;
     289               0 :     m_state[2] = h2;
     290               0 :     m_state[3] = h3;
     291               0 :     m_state[4] = h4;
     292               0 :     m_state[5] = h5;
     293               0 :     m_state[6] = h6;
     294               0 :     m_state[7] = h7;
     295               0 :     m_state[8] = h8;
     296               0 :     m_state[9] = h9;
     297               0 :     m_state[10] = h10;
     298               0 :     m_state[11] = h11;
     299                 : }
     300                 : 
     301                 : 
     302                 : // report the hash for the concatenation of all message fragments so far
     303               0 : void SpookyHash::Final(uint64 *hash1, uint64 *hash2)
     304                 : {
     305                 :     // init the variables
     306               0 :     if (m_length < sc_bufSize)
     307                 :     {
     308               0 :         Short( m_data, m_length, hash1, hash2);
     309               0 :         return;
     310                 :     }
     311                 :     
     312               0 :     const uint64 *data = (const uint64 *)m_data;
     313               0 :     uint8 remainder = m_remainder;
     314                 :     
     315               0 :     uint64 h0 = m_state[0];
     316               0 :     uint64 h1 = m_state[1];
     317               0 :     uint64 h2 = m_state[2];
     318               0 :     uint64 h3 = m_state[3];
     319               0 :     uint64 h4 = m_state[4];
     320               0 :     uint64 h5 = m_state[5];
     321               0 :     uint64 h6 = m_state[6];
     322               0 :     uint64 h7 = m_state[7];
     323               0 :     uint64 h8 = m_state[8];
     324               0 :     uint64 h9 = m_state[9];
     325               0 :     uint64 h10 = m_state[10];
     326               0 :     uint64 h11 = m_state[11];
     327                 : 
     328               0 :     if (remainder >= sc_blockSize)
     329                 :     {
     330                 :         // m_data can contain two blocks; handle any whole first block
     331               0 :         Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     332               0 :         data += sc_numVars;
     333               0 :         remainder -= sc_blockSize;
     334                 :     }
     335                 : 
     336                 :     // mix in the last partial block, and the length mod sc_blockSize
     337               0 :     memset(&((uint8 *)data)[remainder], 0, (sc_blockSize-remainder));
     338                 : 
     339               0 :     ((uint8 *)data)[sc_blockSize-1] = remainder;
     340               0 :     Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     341                 :     
     342                 :     // do some final mixing
     343               0 :     End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
     344                 : 
     345               0 :     *hash1 = h0;
     346               0 :     *hash2 = h1;
     347                 : }
     348                 : 

Generated by: LCOV version 1.7