folly: replace old-style header guards with "pragma once"
[folly.git] / folly / Fingerprint.h
1 /*
2  * Copyright 2016 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 /**
18  * Compute 64-, 96-, and 128-bit Rabin fingerprints, as described in
19  * Michael O. Rabin (1981)
20  *   Fingerprinting by Random Polynomials
21  *   Center for Research in Computing Technology, Harvard University
22  *   Tech Report TR-CSE-03-01
23  *
24  * The implementation follows the optimization described in
25  * Andrei Z. Broder (1993)
26  *   Some applications of Rabin's fingerprinting method
27  *
28  * extended for fingerprints larger than 64 bits, and modified to use
29  * 64-bit instead of 32-bit integers for computation.
30  *
31  * The precomputed tables are in FingerprintTable.cpp, which is automatically
32  * generated by ComputeFingerprintTable.cpp.
33  *
34  * Benchmarked on 10/13/2009 on a 2.5GHz quad-core Xeon L5420,
35  * - Fingerprint<64>::update64() takes about 12ns
36  * - Fingerprint<96>::update64() takes about 30ns
37  * - Fingerprint<128>::update128() takes about 30ns
38  * (unsurprisingly, Fingerprint<96> and Fingerprint<128> take the
39  * same amount of time, as they both use 128-bit operations; the least
40  * significant 32 bits of Fingerprint<96> will always be 0)
41  *
42  * @author Tudor Bosman (tudorb@facebook.com)
43  */
44
45 #pragma once
46
47 #include <cstdint>
48
49 #include <folly/Range.h>
50
51 namespace folly {
52
53 namespace detail {
54 template <int BITS>
55 struct FingerprintTable {
56   static const uint64_t poly[1 + (BITS-1)/64];
57   static const uint64_t table[8][256][1 + (BITS-1)/64];
58 };
59 }  // namespace detail
60
61 /**
62  * Compute the Rabin fingerprint.
63  *
64  * TODO(tudorb): Extend this to allow removing values from the computed
65  * fingerprint (so we can fingerprint a sliding window, as in the Rabin-Karp
66  * string matching algorithm)
67  *
68  * update* methods return *this, so you can chain them together:
69  * Fingerprint<96>().update8(x).update(str).update64(val).write(output);
70  */
71 template <int BITS>
72 class Fingerprint {
73  public:
74   Fingerprint() {
75     // Use a non-zero starting value. We'll use (1 << (BITS-1))
76     fp_[0] = 1ULL << 63;
77     for (int i = 1; i < size(); i++)
78       fp_[i] = 0;
79   }
80
81   Fingerprint& update8(uint8_t v) {
82     uint8_t out = shlor8(v);
83     xortab(detail::FingerprintTable<BITS>::table[0][out]);
84     return *this;
85   }
86
87   // update32 and update64 are convenience functions to update the fingerprint
88   // with 4 and 8 bytes at a time.  They are faster than calling update8
89   // in a loop.  They process the bytes in big-endian order.
90   Fingerprint& update32(uint32_t v) {
91     uint32_t out = shlor32(v);
92     for (int i = 0; i < 4; i++) {
93       xortab(detail::FingerprintTable<BITS>::table[i][out&0xff]);
94       out >>= 8;
95     }
96     return *this;
97   }
98
99   Fingerprint& update64(uint64_t v) {
100     uint64_t out = shlor64(v);
101     for (int i = 0; i < 8; i++) {
102       xortab(detail::FingerprintTable<BITS>::table[i][out&0xff]);
103       out >>= 8;
104     }
105     return *this;
106   }
107
108   Fingerprint& update(StringPiece str) {
109     // TODO(tudorb): We could be smart and do update64 or update32 if aligned
110     for (auto c : str) {
111       update8(uint8_t(c));
112     }
113     return *this;
114   }
115
116   /**
117    * Return the number of uint64s needed to hold the fingerprint value.
118    */
119   static int size() {
120     return 1 + (BITS-1)/64;
121   }
122
123   /**
124    * Write the computed fingeprint to an array of size() uint64_t's.
125    * For Fingerprint<64>,  size()==1; we write 64 bits in out[0]
126    * For Fingerprint<96>,  size()==2; we write 64 bits in out[0] and
127    *                                  the most significant 32 bits of out[1]
128    * For Fingerprint<128>, size()==2; we write 64 bits in out[0] and
129    *                                  64 bits in out[1].
130    */
131   void write(uint64_t* out) const {
132     for (int i = 0; i < size(); i++) {
133       out[i] = fp_[i];
134     }
135   }
136
137  private:
138   // XOR the fingerprint with a value from one of the tables.
139   void xortab(const uint64_t* tab) {
140     for (int i = 0; i < size(); i++) {
141       fp_[i] ^= tab[i];
142     }
143   }
144
145   // Helper functions: shift the fingerprint value left by 8/32/64 bits,
146   // return the "out" value (the bits that were shifted out), and add "v"
147   // in the bits on the right.
148   uint8_t  shlor8(uint8_t v);
149   uint32_t shlor32(uint32_t v);
150   uint64_t shlor64(uint64_t v);
151
152   uint64_t fp_[1 + (BITS-1)/64];
153 };
154
155 // Convenience functions
156
157 /**
158  * Return the 64-bit Rabin fingerprint of a string.
159  */
160 inline uint64_t fingerprint64(StringPiece str) {
161   uint64_t fp;
162   Fingerprint<64>().update(str).write(&fp);
163   return fp;
164 }
165
166 /**
167  * Compute the 96-bit Rabin fingerprint of a string.
168  * Return the 64 most significant bits in *msb, and the 32 least significant
169  * bits in *lsb.
170  */
171 inline void fingerprint96(StringPiece str,
172                           uint64_t* msb, uint32_t* lsb) {
173   uint64_t fp[2];
174   Fingerprint<96>().update(str).write(fp);
175   *msb = fp[0];
176   *lsb = (uint32_t)(fp[1] >> 32);
177 }
178
179 /**
180  * Compute the 128-bit Rabin fingerprint of a string.
181  * Return the 64 most significant bits in *msb, and the 64 least significant
182  * bits in *lsb.
183  */
184 inline void fingerprint128(StringPiece str,
185                            uint64_t* msb, uint64_t* lsb) {
186   uint64_t fp[2];
187   Fingerprint<128>().update(str).write(fp);
188   *msb = fp[0];
189   *lsb = fp[1];
190 }
191
192
193 template <>
194 inline uint8_t Fingerprint<64>::shlor8(uint8_t v) {
195   uint8_t out = (uint8_t)(fp_[0] >> 56);
196   fp_[0] = (fp_[0] << 8) | ((uint64_t)v);
197   return out;
198 }
199
200 template <>
201 inline uint32_t Fingerprint<64>::shlor32(uint32_t v) {
202   uint32_t out = (uint32_t)(fp_[0] >> 32);
203   fp_[0] = (fp_[0] << 32) | ((uint64_t)v);
204   return out;
205 }
206
207 template <>
208 inline uint64_t Fingerprint<64>::shlor64(uint64_t v) {
209   uint64_t out = fp_[0];
210   fp_[0] = v;
211   return out;
212 }
213
214 template <>
215 inline uint8_t Fingerprint<96>::shlor8(uint8_t v) {
216   uint8_t out = (uint8_t)(fp_[0] >> 56);
217   fp_[0] = (fp_[0] << 8) | (fp_[1] >> 56);
218   fp_[1] = (fp_[1] << 8) | ((uint64_t)v << 32);
219   return out;
220 }
221
222 template <>
223 inline uint32_t Fingerprint<96>::shlor32(uint32_t v) {
224   uint32_t out = (uint32_t)(fp_[0] >> 32);
225   fp_[0] = (fp_[0] << 32) | (fp_[1] >> 32);
226   fp_[1] = ((uint64_t)v << 32);
227   return out;
228 }
229
230 template <>
231 inline uint64_t Fingerprint<96>::shlor64(uint64_t v) {
232   uint64_t out = fp_[0];
233   fp_[0] = fp_[1] | (v >> 32);
234   fp_[1] = v << 32;
235   return out;
236 }
237
238 template <>
239 inline uint8_t Fingerprint<128>::shlor8(uint8_t v) {
240   uint8_t out = (uint8_t)(fp_[0] >> 56);
241   fp_[0] = (fp_[0] << 8) | (fp_[1] >> 56);
242   fp_[1] = (fp_[1] << 8) | ((uint64_t)v);
243   return out;
244 }
245
246 template <>
247 inline uint32_t Fingerprint<128>::shlor32(uint32_t v) {
248   uint32_t out = (uint32_t)(fp_[0] >> 32);
249   fp_[0] = (fp_[0] << 32) | (fp_[1] >> 32);
250   fp_[1] = (fp_[1] << 32) | ((uint64_t)v);
251   return out;
252 }
253
254 template <>
255 inline uint64_t Fingerprint<128>::shlor64(uint64_t v) {
256   uint64_t out = fp_[0];
257   fp_[0] = fp_[1];
258   fp_[1] = v;
259   return out;
260 }
261
262 }  // namespace folly