master
  1//===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===//
  2//
  3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4// See https://llvm.org/LICENSE.txt for license information.
  5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6//
  7//===----------------------------------------------------------------------===//
  8//
  9// Specializer BitVector implementation.
 10//
 11//===----------------------------------------------------------------------===//
 12
 13#ifndef SANITIZER_BITVECTOR_H
 14#define SANITIZER_BITVECTOR_H
 15
 16#include "sanitizer_common.h"
 17
 18namespace __sanitizer {
 19
 20// Fixed size bit vector based on a single basic integer.
 21template <class basic_int_t = uptr>
 22class BasicBitVector {
 23 public:
 24  enum SizeEnum : uptr { kSize = sizeof(basic_int_t) * 8 };
 25
 26  uptr size() const { return kSize; }
 27  // No CTOR.
 28  void clear() { bits_ = 0; }
 29  void setAll() { bits_ = ~(basic_int_t)0; }
 30  bool empty() const { return bits_ == 0; }
 31
 32  // Returns true if the bit has changed from 0 to 1.
 33  bool setBit(uptr idx) {
 34    basic_int_t old = bits_;
 35    bits_ |= mask(idx);
 36    return bits_ != old;
 37  }
 38
 39  // Returns true if the bit has changed from 1 to 0.
 40  bool clearBit(uptr idx) {
 41    basic_int_t old = bits_;
 42    bits_ &= ~mask(idx);
 43    return bits_ != old;
 44  }
 45
 46  bool getBit(uptr idx) const { return (bits_ & mask(idx)) != 0; }
 47
 48  uptr getAndClearFirstOne() {
 49    CHECK(!empty());
 50    uptr idx = LeastSignificantSetBitIndex(bits_);
 51    clearBit(idx);
 52    return idx;
 53  }
 54
 55  // Do "this |= v" and return whether new bits have been added.
 56  bool setUnion(const BasicBitVector &v) {
 57    basic_int_t old = bits_;
 58    bits_ |= v.bits_;
 59    return bits_ != old;
 60  }
 61
 62  // Do "this &= v" and return whether any bits have been removed.
 63  bool setIntersection(const BasicBitVector &v) {
 64    basic_int_t old = bits_;
 65    bits_ &= v.bits_;
 66    return bits_ != old;
 67  }
 68
 69  // Do "this &= ~v" and return whether any bits have been removed.
 70  bool setDifference(const BasicBitVector &v) {
 71    basic_int_t old = bits_;
 72    bits_ &= ~v.bits_;
 73    return bits_ != old;
 74  }
 75
 76  void copyFrom(const BasicBitVector &v) { bits_ = v.bits_; }
 77
 78  // Returns true if 'this' intersects with 'v'.
 79  bool intersectsWith(const BasicBitVector &v) const {
 80    return (bits_ & v.bits_) != 0;
 81  }
 82
 83  // for (BasicBitVector<>::Iterator it(bv); it.hasNext();) {
 84  //   uptr idx = it.next();
 85  //   use(idx);
 86  // }
 87  class Iterator {
 88   public:
 89    Iterator() { }
 90    explicit Iterator(const BasicBitVector &bv) : bv_(bv) {}
 91    bool hasNext() const { return !bv_.empty(); }
 92    uptr next() { return bv_.getAndClearFirstOne(); }
 93    void clear() { bv_.clear(); }
 94   private:
 95    BasicBitVector bv_;
 96  };
 97
 98 private:
 99  basic_int_t mask(uptr idx) const {
100    CHECK_LT(idx, size());
101    return (basic_int_t)1UL << idx;
102  }
103  basic_int_t bits_;
104};
105
106// Fixed size bit vector of (kLevel1Size*BV::kSize**2) bits.
107// The implementation is optimized for better performance on
108// sparse bit vectors, i.e. the those with few set bits.
109template <uptr kLevel1Size = 1, class BV = BasicBitVector<> >
110class TwoLevelBitVector {
111  // This is essentially a 2-level bit vector.
112  // Set bit in the first level BV indicates that there are set bits
113  // in the corresponding BV of the second level.
114  // This structure allows O(kLevel1Size) time for clear() and empty(),
115  // as well fast handling of sparse BVs.
116 public:
117  enum SizeEnum : uptr { kSize = BV::kSize * BV::kSize * kLevel1Size };
118  // No CTOR.
119
120  uptr size() const { return kSize; }
121
122  void clear() {
123    for (uptr i = 0; i < kLevel1Size; i++)
124      l1_[i].clear();
125  }
126
127  void setAll() {
128    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
129      l1_[i0].setAll();
130      for (uptr i1 = 0; i1 < BV::kSize; i1++)
131        l2_[i0][i1].setAll();
132    }
133  }
134
135  bool empty() const {
136    for (uptr i = 0; i < kLevel1Size; i++)
137      if (!l1_[i].empty())
138        return false;
139    return true;
140  }
141
142  // Returns true if the bit has changed from 0 to 1.
143  bool setBit(uptr idx) {
144    check(idx);
145    uptr i0 = idx0(idx);
146    uptr i1 = idx1(idx);
147    uptr i2 = idx2(idx);
148    if (!l1_[i0].getBit(i1)) {
149      l1_[i0].setBit(i1);
150      l2_[i0][i1].clear();
151    }
152    bool res = l2_[i0][i1].setBit(i2);
153    // Printf("%s: %zd => %zd %zd %zd; %d\n", __func__,
154    // idx, i0, i1, i2, res);
155    return res;
156  }
157
158  bool clearBit(uptr idx) {
159    check(idx);
160    uptr i0 = idx0(idx);
161    uptr i1 = idx1(idx);
162    uptr i2 = idx2(idx);
163    bool res = false;
164    if (l1_[i0].getBit(i1)) {
165      res = l2_[i0][i1].clearBit(i2);
166      if (l2_[i0][i1].empty())
167        l1_[i0].clearBit(i1);
168    }
169    return res;
170  }
171
172  bool getBit(uptr idx) const {
173    check(idx);
174    uptr i0 = idx0(idx);
175    uptr i1 = idx1(idx);
176    uptr i2 = idx2(idx);
177    // Printf("%s: %zd => %zd %zd %zd\n", __func__, idx, i0, i1, i2);
178    return l1_[i0].getBit(i1) && l2_[i0][i1].getBit(i2);
179  }
180
181  uptr getAndClearFirstOne() {
182    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
183      if (l1_[i0].empty()) continue;
184      uptr i1 = l1_[i0].getAndClearFirstOne();
185      uptr i2 = l2_[i0][i1].getAndClearFirstOne();
186      if (!l2_[i0][i1].empty())
187        l1_[i0].setBit(i1);
188      uptr res = i0 * BV::kSize * BV::kSize + i1 * BV::kSize + i2;
189      // Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res);
190      return res;
191    }
192    CHECK(0);
193    return 0;
194  }
195
196  // Do "this |= v" and return whether new bits have been added.
197  bool setUnion(const TwoLevelBitVector &v) {
198    bool res = false;
199    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
200      BV t = v.l1_[i0];
201      while (!t.empty()) {
202        uptr i1 = t.getAndClearFirstOne();
203        if (l1_[i0].setBit(i1))
204          l2_[i0][i1].clear();
205        if (l2_[i0][i1].setUnion(v.l2_[i0][i1]))
206          res = true;
207      }
208    }
209    return res;
210  }
211
212  // Do "this &= v" and return whether any bits have been removed.
213  bool setIntersection(const TwoLevelBitVector &v) {
214    bool res = false;
215    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
216      if (l1_[i0].setIntersection(v.l1_[i0]))
217        res = true;
218      if (!l1_[i0].empty()) {
219        BV t = l1_[i0];
220        while (!t.empty()) {
221          uptr i1 = t.getAndClearFirstOne();
222          if (l2_[i0][i1].setIntersection(v.l2_[i0][i1]))
223            res = true;
224          if (l2_[i0][i1].empty())
225            l1_[i0].clearBit(i1);
226        }
227      }
228    }
229    return res;
230  }
231
232  // Do "this &= ~v" and return whether any bits have been removed.
233  bool setDifference(const TwoLevelBitVector &v) {
234    bool res = false;
235    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
236      BV t = l1_[i0];
237      t.setIntersection(v.l1_[i0]);
238      while (!t.empty()) {
239        uptr i1 = t.getAndClearFirstOne();
240        if (l2_[i0][i1].setDifference(v.l2_[i0][i1]))
241          res = true;
242        if (l2_[i0][i1].empty())
243          l1_[i0].clearBit(i1);
244      }
245    }
246    return res;
247  }
248
249  void copyFrom(const TwoLevelBitVector &v) {
250    clear();
251    setUnion(v);
252  }
253
254  // Returns true if 'this' intersects with 'v'.
255  bool intersectsWith(const TwoLevelBitVector &v) const {
256    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
257      BV t = l1_[i0];
258      t.setIntersection(v.l1_[i0]);
259      while (!t.empty()) {
260        uptr i1 = t.getAndClearFirstOne();
261        if (!v.l1_[i0].getBit(i1)) continue;
262        if (l2_[i0][i1].intersectsWith(v.l2_[i0][i1]))
263          return true;
264      }
265    }
266    return false;
267  }
268
269  // for (TwoLevelBitVector<>::Iterator it(bv); it.hasNext();) {
270  //   uptr idx = it.next();
271  //   use(idx);
272  // }
273  class Iterator {
274   public:
275    Iterator() { }
276    explicit Iterator(const TwoLevelBitVector &bv) : bv_(bv), i0_(0), i1_(0) {
277      it1_.clear();
278      it2_.clear();
279    }
280
281    bool hasNext() const {
282      if (it1_.hasNext()) return true;
283      for (uptr i = i0_; i < kLevel1Size; i++)
284        if (!bv_.l1_[i].empty()) return true;
285      return false;
286    }
287
288    uptr next() {
289      // Printf("++++: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
290      //       it2_.hasNext(), kSize);
291      if (!it1_.hasNext() && !it2_.hasNext()) {
292        for (; i0_ < kLevel1Size; i0_++) {
293          if (bv_.l1_[i0_].empty()) continue;
294          it1_ = typename BV::Iterator(bv_.l1_[i0_]);
295          // Printf("+i0: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
296          //   it2_.hasNext(), kSize);
297          break;
298        }
299      }
300      if (!it2_.hasNext()) {
301        CHECK(it1_.hasNext());
302        i1_ = it1_.next();
303        it2_ = typename BV::Iterator(bv_.l2_[i0_][i1_]);
304        // Printf("++i1: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
305        //       it2_.hasNext(), kSize);
306      }
307      CHECK(it2_.hasNext());
308      uptr i2 = it2_.next();
309      uptr res = i0_ * BV::kSize * BV::kSize + i1_ * BV::kSize + i2;
310      // Printf("+ret: %zd %zd; %d %d; size %zd; res: %zd\n", i0_, i1_,
311      //       it1_.hasNext(), it2_.hasNext(), kSize, res);
312      if (!it1_.hasNext() && !it2_.hasNext())
313        i0_++;
314      return res;
315    }
316
317   private:
318    const TwoLevelBitVector &bv_;
319    uptr i0_, i1_;
320    typename BV::Iterator it1_, it2_;
321  };
322
323 private:
324  void check(uptr idx) const { CHECK_LT(idx, size()); }
325
326  uptr idx0(uptr idx) const {
327    uptr res = idx / (BV::kSize * BV::kSize);
328    CHECK_LT(res, kLevel1Size);
329    return res;
330  }
331
332  uptr idx1(uptr idx) const {
333    uptr res = (idx / BV::kSize) % BV::kSize;
334    CHECK_LT(res, BV::kSize);
335    return res;
336  }
337
338  uptr idx2(uptr idx) const {
339    uptr res = idx % BV::kSize;
340    CHECK_LT(res, BV::kSize);
341    return res;
342  }
343
344  BV l1_[kLevel1Size];
345  BV l2_[kLevel1Size][BV::kSize];
346};
347
348} // namespace __sanitizer
349
350#endif // SANITIZER_BITVECTOR_H