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