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