Adds writer test case for RCU
[folly.git] / folly / detail / FingerprintPolynomial.h
1 /*
2  * Copyright 2012-present 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 #pragma once
18
19 #include <cstdint>
20
21 namespace folly {
22 namespace detail {
23
24 /**
25  * Representation of a polynomial of degree DEG over GF(2) (that is,
26  * with binary coefficients).
27  *
28  * Probably of no use outside of Fingerprint code; used by
29  * GenerateFingerprintTables and the unittest.
30  */
31 template <int DEG>
32 class FingerprintPolynomial {
33  public:
34   FingerprintPolynomial() {
35     for (int i = 0; i < size(); i++) {
36       val_[i] = 0;
37     }
38   }
39
40   explicit FingerprintPolynomial(const uint64_t* vals) {
41     for (int i = 0; i < size(); i++) {
42       val_[i] = vals[i];
43     }
44   }
45
46   void write(uint64_t* out) const {
47     for (int i = 0; i < size(); i++) {
48       out[i] = val_[i];
49     }
50   }
51
52   void add(const FingerprintPolynomial<DEG>& other) {
53     for (int i = 0; i < size(); i++) {
54       val_[i] ^= other.val_[i];
55     }
56   }
57
58   // Multiply by X.  The actual degree must be < DEG.
59   void mulX() {
60     CHECK_EQ(0u, val_[0] & (1ULL << 63));
61     uint64_t b = 0;
62     for (int i = size()-1; i >= 0; i--) {
63       uint64_t nb = val_[i] >> 63;
64       val_[i] = (val_[i] << 1) | b;
65       b = nb;
66     }
67   }
68
69   // Compute (this * X) mod P(X), where P(X) is a monic polynomial of degree
70   // DEG+1 (represented as a FingerprintPolynomial<DEG> object, with the
71   // implicit coefficient of X^(DEG+1)==1)
72   //
73   // This is a bit tricky. If k=DEG+1:
74   // Let P(X) = X^k + p_(k-1) * X^(k-1) + ... + p_1 * X + p_0
75   // Let this = A(X) = a_(k-1) * X^(k-1) + ... + a_1 * X + a_0
76   // Then:
77   //   A(X) * X
78   // = a_(k-1) * X^k + (a_(k-2) * X^(k-1) + ... + a_1 * X^2 + a_0 * X)
79   // = a_(k-1) * X^k + (the binary representation of A, left shift by 1)
80   //
81   // if a_(k-1) = 0, we can ignore the first term.
82   // if a_(k-1) = 1, then:
83   //   X^k mod P(X)
84   // = X^k - P(X)
85   // = P(X) - X^k
86   // = p_(k-1) * X^(k-1) + ... + p_1 * X + p_0
87   // = exactly the binary representation passed in as an argument to this
88   //   function!
89   //
90   // So A(X) * X mod P(X) is:
91   //   the binary representation of A, left shift by 1,
92   //   XOR p if a_(k-1) == 1
93   void mulXmod(const FingerprintPolynomial<DEG>& p) {
94     bool needXOR = (val_[0] & (1ULL<<63));
95     val_[0] &= ~(1ULL<<63);
96     mulX();
97     if (needXOR) {
98       add(p);
99     }
100   }
101
102   // Compute (this * X^k) mod P(X) by repeatedly multiplying by X (see above)
103   void mulXkmod(int k, const FingerprintPolynomial<DEG>& p) {
104     for (int i = 0; i < k; i++) {
105       mulXmod(p);
106     }
107   }
108
109   // add X^k, where k <= DEG
110   void addXk(int k) {
111     DCHECK_GE(k, 0);
112     DCHECK_LE(k, DEG);
113     int word_offset = (DEG - k) / 64;
114     int bit_offset = 63 - (DEG - k) % 64;
115     val_[word_offset] ^= (1ULL << bit_offset);
116   }
117
118   // Set the highest 8 bits to val.
119   // If val is interpreted as polynomial of degree 7, then this sets *this
120   // to val * X^(DEG-7)
121   void setHigh8Bits(uint8_t val) {
122     val_[0] = ((uint64_t)val) << (64-8);
123     for (int i = 1; i < size(); i++) {
124       val_[i] = 0;
125     }
126   }
127
128   static constexpr int size() {
129     return 1 + DEG/64;
130   }
131  private:
132   // Internal representation: big endian
133   // val_[0] contains the highest order coefficients, with bit 63 as the
134   // highest order coefficient
135   //
136   // If DEG+1 is not a multiple of 64,  val_[size()-1] only uses the highest
137   // order (DEG+1)%64 bits (the others are always 0)
138   uint64_t val_[1 + DEG/64];
139 };
140
141 } // namespace detail
142 } // namespace folly