Add a LICENSE file for folly
[folly.git] / folly / Hash.h
1 /*
2  * Copyright 2012 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 #ifndef FOLLY_BASE_HASH_H_
18 #define FOLLY_BASE_HASH_H_
19
20 #include <stdint.h>
21 #include <cstring>
22 #include <string>
23
24 /*
25  * Various hashing functions.
26  */
27
28 namespace folly { namespace hash {
29
30 //////////////////////////////////////////////////////////////////////
31
32 /*
33  * Thomas Wang 64 bit mix hash function
34  */
35
36 inline uint64_t twang_mix64(uint64_t key) {
37   key = (~key) + (key << 21);
38   key = key ^ (key >> 24);
39   key = (key + (key << 3)) + (key << 8);
40   key = key ^ (key >> 14);
41   key = (key + (key << 2)) + (key << 4);
42   key = key ^ (key >> 28);
43   key = key + (key << 31);
44   return key;
45 }
46
47 /*
48  * Thomas Wang downscaling hash function
49  */
50
51 inline uint32_t twang_32from64(uint64_t key) {
52   key = (~key) + (key << 18);
53   key = key ^ (key >> 31);
54   key = key * 21;
55   key = key ^ (key >> 11);
56   key = key + (key << 6);
57   key = key ^ (key >> 22);
58   return (uint32_t) key;
59 }
60
61 /*
62  * Robert Jenkins' reversible 32 bit mix hash function
63  */
64
65 inline uint32_t jenkins_rev_mix32(uint32_t key) {
66   key += (key << 12);
67   key ^= (key >> 22);
68   key += (key << 4);
69   key ^= (key >> 9);
70   key += (key << 10);
71   key ^= (key >> 2);
72   key += (key << 7);
73   key += (key << 12);
74   return key;
75 }
76
77 /*
78  * Fowler / Noll / Vo (FNV) Hash
79  *     http://www.isthe.com/chongo/tech/comp/fnv/
80  */
81
82 const uint32_t FNV_32_HASH_START = 216613626UL;
83 const uint64_t FNV_64_HASH_START = 14695981039346656037ULL;
84
85 inline uint32_t fnv32(const char* s,
86                       uint32_t hash = FNV_32_HASH_START) {
87   for (; *s; ++s) {
88     hash += (hash << 1) + (hash << 4) + (hash << 7) +
89             (hash << 8) + (hash << 24);
90     hash ^= *s;
91   }
92   return hash;
93 }
94
95 inline uint32_t fnv32_buf(const void* buf,
96                           int n,
97                           uint32_t hash = FNV_32_HASH_START) {
98   const char* char_buf = reinterpret_cast<const char*>(buf);
99
100   for (int i = 0; i < n; ++i) {
101     hash += (hash << 1) + (hash << 4) + (hash << 7) +
102             (hash << 8) + (hash << 24);
103     hash ^= char_buf[i];
104   }
105
106   return hash;
107 }
108
109 inline uint32_t fnv32(const std::string& str,
110                       uint64_t hash = FNV_32_HASH_START) {
111   return fnv32_buf(str.data(), str.size(), hash);
112 }
113
114 inline uint64_t fnv64(const char* s,
115                       uint64_t hash = FNV_64_HASH_START) {
116   for (; *s; ++s) {
117     hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) +
118       (hash << 8) + (hash << 40);
119     hash ^= *s;
120   }
121   return hash;
122 }
123
124 inline uint64_t fnv64_buf(const void* buf,
125                           int n,
126                           uint64_t hash = FNV_64_HASH_START) {
127   const char* char_buf = reinterpret_cast<const char*>(buf);
128
129   for (int i = 0; i < n; ++i) {
130     hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) +
131       (hash << 8) + (hash << 40);
132     hash ^= char_buf[i];
133   }
134   return hash;
135 }
136
137 inline uint64_t fnv64(const std::string& str,
138                       uint64_t hash = FNV_64_HASH_START) {
139   return fnv64_buf(str.data(), str.size(), hash);
140 }
141
142 /*
143  * Paul Hsieh: http://www.azillionmonkeys.com/qed/hash.html
144  */
145
146 #define get16bits(d) (*((const uint16_t*) (d)))
147
148 inline uint32_t hsieh_hash32_buf(const void* buf, int len) {
149   const char* s = reinterpret_cast<const char*>(buf);
150   uint32_t hash = len;
151   uint32_t tmp;
152   int rem;
153
154   if (len <= 0 || buf == 0) {
155     return 0;
156   }
157
158   rem = len & 3;
159   len >>= 2;
160
161   /* Main loop */
162   for (;len > 0; len--) {
163     hash  += get16bits (s);
164     tmp    = (get16bits (s+2) << 11) ^ hash;
165     hash   = (hash << 16) ^ tmp;
166     s  += 2*sizeof (uint16_t);
167     hash  += hash >> 11;
168   }
169
170   /* Handle end cases */
171   switch (rem) {
172   case 3:
173     hash += get16bits(s);
174     hash ^= hash << 16;
175     hash ^= s[sizeof (uint16_t)] << 18;
176     hash += hash >> 11;
177     break;
178   case 2:
179     hash += get16bits(s);
180     hash ^= hash << 11;
181     hash += hash >> 17;
182     break;
183   case 1:
184     hash += *s;
185     hash ^= hash << 10;
186     hash += hash >> 1;
187   }
188
189   /* Force "avalanching" of final 127 bits */
190   hash ^= hash << 3;
191   hash += hash >> 5;
192   hash ^= hash << 4;
193   hash += hash >> 17;
194   hash ^= hash << 25;
195   hash += hash >> 6;
196
197   return hash;
198 };
199
200 #undef get16bits
201
202 inline uint32_t hsieh_hash32(const char* s) {
203   return hsieh_hash32_buf(s, std::strlen(s));
204 }
205
206 inline uint32_t hsieh_hash32_str(const std::string& str) {
207   return hsieh_hash32_buf(str.data(), str.size());
208 }
209
210 //////////////////////////////////////////////////////////////////////
211
212 } // namespace hash
213
214 template<class Key>
215 struct hasher;
216
217 template<> struct hasher<int32_t> {
218   size_t operator()(int32_t key) const {
219     return hash::jenkins_rev_mix32(uint32_t(key));
220   }
221 };
222
223 template<> struct hasher<uint32_t> {
224   size_t operator()(uint32_t key) const {
225     return hash::jenkins_rev_mix32(key);
226   }
227 };
228
229 template<> struct hasher<int64_t> {
230   size_t operator()(int64_t key) const {
231     return hash::twang_mix64(uint64_t(key));
232   }
233 };
234
235 template<> struct hasher<uint64_t> {
236   size_t operator()(uint64_t key) const {
237     return hash::twang_mix64(key);
238   }
239 };
240
241 } // namespace folly
242
243 #endif