xref: /freebsd/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Specializer BitVector implementation.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef SANITIZER_BITVECTOR_H
140b57cec5SDimitry Andric #define SANITIZER_BITVECTOR_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "sanitizer_common.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric namespace __sanitizer {
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric // Fixed size bit vector based on a single basic integer.
210b57cec5SDimitry Andric template <class basic_int_t = uptr>
220b57cec5SDimitry Andric class BasicBitVector {
230b57cec5SDimitry Andric  public:
240b57cec5SDimitry Andric   enum SizeEnum : uptr { kSize = sizeof(basic_int_t) * 8 };
250b57cec5SDimitry Andric 
size()260b57cec5SDimitry Andric   uptr size() const { return kSize; }
270b57cec5SDimitry Andric   // No CTOR.
clear()280b57cec5SDimitry Andric   void clear() { bits_ = 0; }
setAll()290b57cec5SDimitry Andric   void setAll() { bits_ = ~(basic_int_t)0; }
empty()300b57cec5SDimitry Andric   bool empty() const { return bits_ == 0; }
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric   // Returns true if the bit has changed from 0 to 1.
setBit(uptr idx)330b57cec5SDimitry Andric   bool setBit(uptr idx) {
340b57cec5SDimitry Andric     basic_int_t old = bits_;
350b57cec5SDimitry Andric     bits_ |= mask(idx);
360b57cec5SDimitry Andric     return bits_ != old;
370b57cec5SDimitry Andric   }
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   // Returns true if the bit has changed from 1 to 0.
clearBit(uptr idx)400b57cec5SDimitry Andric   bool clearBit(uptr idx) {
410b57cec5SDimitry Andric     basic_int_t old = bits_;
420b57cec5SDimitry Andric     bits_ &= ~mask(idx);
430b57cec5SDimitry Andric     return bits_ != old;
440b57cec5SDimitry Andric   }
450b57cec5SDimitry Andric 
getBit(uptr idx)460b57cec5SDimitry Andric   bool getBit(uptr idx) const { return (bits_ & mask(idx)) != 0; }
470b57cec5SDimitry Andric 
getAndClearFirstOne()480b57cec5SDimitry Andric   uptr getAndClearFirstOne() {
490b57cec5SDimitry Andric     CHECK(!empty());
500b57cec5SDimitry Andric     uptr idx = LeastSignificantSetBitIndex(bits_);
510b57cec5SDimitry Andric     clearBit(idx);
520b57cec5SDimitry Andric     return idx;
530b57cec5SDimitry Andric   }
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   // Do "this |= v" and return whether new bits have been added.
setUnion(const BasicBitVector & v)560b57cec5SDimitry Andric   bool setUnion(const BasicBitVector &v) {
570b57cec5SDimitry Andric     basic_int_t old = bits_;
580b57cec5SDimitry Andric     bits_ |= v.bits_;
590b57cec5SDimitry Andric     return bits_ != old;
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric   // Do "this &= v" and return whether any bits have been removed.
setIntersection(const BasicBitVector & v)630b57cec5SDimitry Andric   bool setIntersection(const BasicBitVector &v) {
640b57cec5SDimitry Andric     basic_int_t old = bits_;
650b57cec5SDimitry Andric     bits_ &= v.bits_;
660b57cec5SDimitry Andric     return bits_ != old;
670b57cec5SDimitry Andric   }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   // Do "this &= ~v" and return whether any bits have been removed.
setDifference(const BasicBitVector & v)700b57cec5SDimitry Andric   bool setDifference(const BasicBitVector &v) {
710b57cec5SDimitry Andric     basic_int_t old = bits_;
720b57cec5SDimitry Andric     bits_ &= ~v.bits_;
730b57cec5SDimitry Andric     return bits_ != old;
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric 
copyFrom(const BasicBitVector & v)760b57cec5SDimitry Andric   void copyFrom(const BasicBitVector &v) { bits_ = v.bits_; }
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   // Returns true if 'this' intersects with 'v'.
intersectsWith(const BasicBitVector & v)790b57cec5SDimitry Andric   bool intersectsWith(const BasicBitVector &v) const {
800b57cec5SDimitry Andric     return (bits_ & v.bits_) != 0;
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   // for (BasicBitVector<>::Iterator it(bv); it.hasNext();) {
840b57cec5SDimitry Andric   //   uptr idx = it.next();
850b57cec5SDimitry Andric   //   use(idx);
860b57cec5SDimitry Andric   // }
870b57cec5SDimitry Andric   class Iterator {
880b57cec5SDimitry Andric    public:
Iterator()890b57cec5SDimitry Andric     Iterator() { }
Iterator(const BasicBitVector & bv)900b57cec5SDimitry Andric     explicit Iterator(const BasicBitVector &bv) : bv_(bv) {}
hasNext()910b57cec5SDimitry Andric     bool hasNext() const { return !bv_.empty(); }
next()920b57cec5SDimitry Andric     uptr next() { return bv_.getAndClearFirstOne(); }
clear()930b57cec5SDimitry Andric     void clear() { bv_.clear(); }
940b57cec5SDimitry Andric    private:
950b57cec5SDimitry Andric     BasicBitVector bv_;
960b57cec5SDimitry Andric   };
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric  private:
mask(uptr idx)990b57cec5SDimitry Andric   basic_int_t mask(uptr idx) const {
1000b57cec5SDimitry Andric     CHECK_LT(idx, size());
1010b57cec5SDimitry Andric     return (basic_int_t)1UL << idx;
1020b57cec5SDimitry Andric   }
1030b57cec5SDimitry Andric   basic_int_t bits_;
1040b57cec5SDimitry Andric };
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric // Fixed size bit vector of (kLevel1Size*BV::kSize**2) bits.
1070b57cec5SDimitry Andric // The implementation is optimized for better performance on
1080b57cec5SDimitry Andric // sparse bit vectors, i.e. the those with few set bits.
1090b57cec5SDimitry Andric template <uptr kLevel1Size = 1, class BV = BasicBitVector<> >
1100b57cec5SDimitry Andric class TwoLevelBitVector {
1110b57cec5SDimitry Andric   // This is essentially a 2-level bit vector.
1120b57cec5SDimitry Andric   // Set bit in the first level BV indicates that there are set bits
1130b57cec5SDimitry Andric   // in the corresponding BV of the second level.
1140b57cec5SDimitry Andric   // This structure allows O(kLevel1Size) time for clear() and empty(),
1150b57cec5SDimitry Andric   // as well fast handling of sparse BVs.
1160b57cec5SDimitry Andric  public:
1170b57cec5SDimitry Andric   enum SizeEnum : uptr { kSize = BV::kSize * BV::kSize * kLevel1Size };
1180b57cec5SDimitry Andric   // No CTOR.
1190b57cec5SDimitry Andric 
size()1200b57cec5SDimitry Andric   uptr size() const { return kSize; }
1210b57cec5SDimitry Andric 
clear()1220b57cec5SDimitry Andric   void clear() {
1230b57cec5SDimitry Andric     for (uptr i = 0; i < kLevel1Size; i++)
1240b57cec5SDimitry Andric       l1_[i].clear();
1250b57cec5SDimitry Andric   }
1260b57cec5SDimitry Andric 
setAll()1270b57cec5SDimitry Andric   void setAll() {
1280b57cec5SDimitry Andric     for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
1290b57cec5SDimitry Andric       l1_[i0].setAll();
1300b57cec5SDimitry Andric       for (uptr i1 = 0; i1 < BV::kSize; i1++)
1310b57cec5SDimitry Andric         l2_[i0][i1].setAll();
1320b57cec5SDimitry Andric     }
1330b57cec5SDimitry Andric   }
1340b57cec5SDimitry Andric 
empty()1350b57cec5SDimitry Andric   bool empty() const {
1360b57cec5SDimitry Andric     for (uptr i = 0; i < kLevel1Size; i++)
1370b57cec5SDimitry Andric       if (!l1_[i].empty())
1380b57cec5SDimitry Andric         return false;
1390b57cec5SDimitry Andric     return true;
1400b57cec5SDimitry Andric   }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   // Returns true if the bit has changed from 0 to 1.
setBit(uptr idx)1430b57cec5SDimitry Andric   bool setBit(uptr idx) {
1440b57cec5SDimitry Andric     check(idx);
1450b57cec5SDimitry Andric     uptr i0 = idx0(idx);
1460b57cec5SDimitry Andric     uptr i1 = idx1(idx);
1470b57cec5SDimitry Andric     uptr i2 = idx2(idx);
1480b57cec5SDimitry Andric     if (!l1_[i0].getBit(i1)) {
1490b57cec5SDimitry Andric       l1_[i0].setBit(i1);
1500b57cec5SDimitry Andric       l2_[i0][i1].clear();
1510b57cec5SDimitry Andric     }
1520b57cec5SDimitry Andric     bool res = l2_[i0][i1].setBit(i2);
1530b57cec5SDimitry Andric     // Printf("%s: %zd => %zd %zd %zd; %d\n", __func__,
1540b57cec5SDimitry Andric     // idx, i0, i1, i2, res);
1550b57cec5SDimitry Andric     return res;
1560b57cec5SDimitry Andric   }
1570b57cec5SDimitry Andric 
clearBit(uptr idx)1580b57cec5SDimitry Andric   bool clearBit(uptr idx) {
1590b57cec5SDimitry Andric     check(idx);
1600b57cec5SDimitry Andric     uptr i0 = idx0(idx);
1610b57cec5SDimitry Andric     uptr i1 = idx1(idx);
1620b57cec5SDimitry Andric     uptr i2 = idx2(idx);
1630b57cec5SDimitry Andric     bool res = false;
1640b57cec5SDimitry Andric     if (l1_[i0].getBit(i1)) {
1650b57cec5SDimitry Andric       res = l2_[i0][i1].clearBit(i2);
1660b57cec5SDimitry Andric       if (l2_[i0][i1].empty())
1670b57cec5SDimitry Andric         l1_[i0].clearBit(i1);
1680b57cec5SDimitry Andric     }
1690b57cec5SDimitry Andric     return res;
1700b57cec5SDimitry Andric   }
1710b57cec5SDimitry Andric 
getBit(uptr idx)1720b57cec5SDimitry Andric   bool getBit(uptr idx) const {
1730b57cec5SDimitry Andric     check(idx);
1740b57cec5SDimitry Andric     uptr i0 = idx0(idx);
1750b57cec5SDimitry Andric     uptr i1 = idx1(idx);
1760b57cec5SDimitry Andric     uptr i2 = idx2(idx);
1770b57cec5SDimitry Andric     // Printf("%s: %zd => %zd %zd %zd\n", __func__, idx, i0, i1, i2);
1780b57cec5SDimitry Andric     return l1_[i0].getBit(i1) && l2_[i0][i1].getBit(i2);
1790b57cec5SDimitry Andric   }
1800b57cec5SDimitry Andric 
getAndClearFirstOne()1810b57cec5SDimitry Andric   uptr getAndClearFirstOne() {
1820b57cec5SDimitry Andric     for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
1830b57cec5SDimitry Andric       if (l1_[i0].empty()) continue;
1840b57cec5SDimitry Andric       uptr i1 = l1_[i0].getAndClearFirstOne();
1850b57cec5SDimitry Andric       uptr i2 = l2_[i0][i1].getAndClearFirstOne();
1860b57cec5SDimitry Andric       if (!l2_[i0][i1].empty())
1870b57cec5SDimitry Andric         l1_[i0].setBit(i1);
1880b57cec5SDimitry Andric       uptr res = i0 * BV::kSize * BV::kSize + i1 * BV::kSize + i2;
1890b57cec5SDimitry Andric       // Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res);
1900b57cec5SDimitry Andric       return res;
1910b57cec5SDimitry Andric     }
1920b57cec5SDimitry Andric     CHECK(0);
1930b57cec5SDimitry Andric     return 0;
1940b57cec5SDimitry Andric   }
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   // Do "this |= v" and return whether new bits have been added.
setUnion(const TwoLevelBitVector & v)1970b57cec5SDimitry Andric   bool setUnion(const TwoLevelBitVector &v) {
1980b57cec5SDimitry Andric     bool res = false;
1990b57cec5SDimitry Andric     for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
2000b57cec5SDimitry Andric       BV t = v.l1_[i0];
2010b57cec5SDimitry Andric       while (!t.empty()) {
2020b57cec5SDimitry Andric         uptr i1 = t.getAndClearFirstOne();
2030b57cec5SDimitry Andric         if (l1_[i0].setBit(i1))
2040b57cec5SDimitry Andric           l2_[i0][i1].clear();
2050b57cec5SDimitry Andric         if (l2_[i0][i1].setUnion(v.l2_[i0][i1]))
2060b57cec5SDimitry Andric           res = true;
2070b57cec5SDimitry Andric       }
2080b57cec5SDimitry Andric     }
2090b57cec5SDimitry Andric     return res;
2100b57cec5SDimitry Andric   }
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric   // Do "this &= v" and return whether any bits have been removed.
setIntersection(const TwoLevelBitVector & v)2130b57cec5SDimitry Andric   bool setIntersection(const TwoLevelBitVector &v) {
2140b57cec5SDimitry Andric     bool res = false;
2150b57cec5SDimitry Andric     for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
2160b57cec5SDimitry Andric       if (l1_[i0].setIntersection(v.l1_[i0]))
2170b57cec5SDimitry Andric         res = true;
2180b57cec5SDimitry Andric       if (!l1_[i0].empty()) {
2190b57cec5SDimitry Andric         BV t = l1_[i0];
2200b57cec5SDimitry Andric         while (!t.empty()) {
2210b57cec5SDimitry Andric           uptr i1 = t.getAndClearFirstOne();
2220b57cec5SDimitry Andric           if (l2_[i0][i1].setIntersection(v.l2_[i0][i1]))
2230b57cec5SDimitry Andric             res = true;
2240b57cec5SDimitry Andric           if (l2_[i0][i1].empty())
2250b57cec5SDimitry Andric             l1_[i0].clearBit(i1);
2260b57cec5SDimitry Andric         }
2270b57cec5SDimitry Andric       }
2280b57cec5SDimitry Andric     }
2290b57cec5SDimitry Andric     return res;
2300b57cec5SDimitry Andric   }
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   // Do "this &= ~v" and return whether any bits have been removed.
setDifference(const TwoLevelBitVector & v)2330b57cec5SDimitry Andric   bool setDifference(const TwoLevelBitVector &v) {
2340b57cec5SDimitry Andric     bool res = false;
2350b57cec5SDimitry Andric     for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
2360b57cec5SDimitry Andric       BV t = l1_[i0];
2370b57cec5SDimitry Andric       t.setIntersection(v.l1_[i0]);
2380b57cec5SDimitry Andric       while (!t.empty()) {
2390b57cec5SDimitry Andric         uptr i1 = t.getAndClearFirstOne();
2400b57cec5SDimitry Andric         if (l2_[i0][i1].setDifference(v.l2_[i0][i1]))
2410b57cec5SDimitry Andric           res = true;
2420b57cec5SDimitry Andric         if (l2_[i0][i1].empty())
2430b57cec5SDimitry Andric           l1_[i0].clearBit(i1);
2440b57cec5SDimitry Andric       }
2450b57cec5SDimitry Andric     }
2460b57cec5SDimitry Andric     return res;
2470b57cec5SDimitry Andric   }
2480b57cec5SDimitry Andric 
copyFrom(const TwoLevelBitVector & v)2490b57cec5SDimitry Andric   void copyFrom(const TwoLevelBitVector &v) {
2500b57cec5SDimitry Andric     clear();
2510b57cec5SDimitry Andric     setUnion(v);
2520b57cec5SDimitry Andric   }
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric   // Returns true if 'this' intersects with 'v'.
intersectsWith(const TwoLevelBitVector & v)2550b57cec5SDimitry Andric   bool intersectsWith(const TwoLevelBitVector &v) const {
2560b57cec5SDimitry Andric     for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
2570b57cec5SDimitry Andric       BV t = l1_[i0];
2580b57cec5SDimitry Andric       t.setIntersection(v.l1_[i0]);
2590b57cec5SDimitry Andric       while (!t.empty()) {
2600b57cec5SDimitry Andric         uptr i1 = t.getAndClearFirstOne();
2610b57cec5SDimitry Andric         if (!v.l1_[i0].getBit(i1)) continue;
2620b57cec5SDimitry Andric         if (l2_[i0][i1].intersectsWith(v.l2_[i0][i1]))
2630b57cec5SDimitry Andric           return true;
2640b57cec5SDimitry Andric       }
2650b57cec5SDimitry Andric     }
2660b57cec5SDimitry Andric     return false;
2670b57cec5SDimitry Andric   }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   // for (TwoLevelBitVector<>::Iterator it(bv); it.hasNext();) {
2700b57cec5SDimitry Andric   //   uptr idx = it.next();
2710b57cec5SDimitry Andric   //   use(idx);
2720b57cec5SDimitry Andric   // }
2730b57cec5SDimitry Andric   class Iterator {
2740b57cec5SDimitry Andric    public:
Iterator()2750b57cec5SDimitry Andric     Iterator() { }
Iterator(const TwoLevelBitVector & bv)2760b57cec5SDimitry Andric     explicit Iterator(const TwoLevelBitVector &bv) : bv_(bv), i0_(0), i1_(0) {
2770b57cec5SDimitry Andric       it1_.clear();
2780b57cec5SDimitry Andric       it2_.clear();
2790b57cec5SDimitry Andric     }
2800b57cec5SDimitry Andric 
hasNext()2810b57cec5SDimitry Andric     bool hasNext() const {
2820b57cec5SDimitry Andric       if (it1_.hasNext()) return true;
2830b57cec5SDimitry Andric       for (uptr i = i0_; i < kLevel1Size; i++)
2840b57cec5SDimitry Andric         if (!bv_.l1_[i].empty()) return true;
2850b57cec5SDimitry Andric       return false;
2860b57cec5SDimitry Andric     }
2870b57cec5SDimitry Andric 
next()2880b57cec5SDimitry Andric     uptr next() {
2890b57cec5SDimitry Andric       // Printf("++++: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
2900b57cec5SDimitry Andric       //       it2_.hasNext(), kSize);
2910b57cec5SDimitry Andric       if (!it1_.hasNext() && !it2_.hasNext()) {
2920b57cec5SDimitry Andric         for (; i0_ < kLevel1Size; i0_++) {
2930b57cec5SDimitry Andric           if (bv_.l1_[i0_].empty()) continue;
2940b57cec5SDimitry Andric           it1_ = typename BV::Iterator(bv_.l1_[i0_]);
2950b57cec5SDimitry Andric           // Printf("+i0: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
2960b57cec5SDimitry Andric           //   it2_.hasNext(), kSize);
2970b57cec5SDimitry Andric           break;
2980b57cec5SDimitry Andric         }
2990b57cec5SDimitry Andric       }
3000b57cec5SDimitry Andric       if (!it2_.hasNext()) {
3010b57cec5SDimitry Andric         CHECK(it1_.hasNext());
3020b57cec5SDimitry Andric         i1_ = it1_.next();
3030b57cec5SDimitry Andric         it2_ = typename BV::Iterator(bv_.l2_[i0_][i1_]);
3040b57cec5SDimitry Andric         // Printf("++i1: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
3050b57cec5SDimitry Andric         //       it2_.hasNext(), kSize);
3060b57cec5SDimitry Andric       }
3070b57cec5SDimitry Andric       CHECK(it2_.hasNext());
3080b57cec5SDimitry Andric       uptr i2 = it2_.next();
3090b57cec5SDimitry Andric       uptr res = i0_ * BV::kSize * BV::kSize + i1_ * BV::kSize + i2;
3100b57cec5SDimitry Andric       // Printf("+ret: %zd %zd; %d %d; size %zd; res: %zd\n", i0_, i1_,
3110b57cec5SDimitry Andric       //       it1_.hasNext(), it2_.hasNext(), kSize, res);
3120b57cec5SDimitry Andric       if (!it1_.hasNext() && !it2_.hasNext())
3130b57cec5SDimitry Andric         i0_++;
3140b57cec5SDimitry Andric       return res;
3150b57cec5SDimitry Andric     }
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric    private:
3180b57cec5SDimitry Andric     const TwoLevelBitVector &bv_;
3190b57cec5SDimitry Andric     uptr i0_, i1_;
3200b57cec5SDimitry Andric     typename BV::Iterator it1_, it2_;
3210b57cec5SDimitry Andric   };
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric  private:
check(uptr idx)324*0fca6ea1SDimitry Andric   void check(uptr idx) const { CHECK_LT(idx, size()); }
3250b57cec5SDimitry Andric 
idx0(uptr idx)3260b57cec5SDimitry Andric   uptr idx0(uptr idx) const {
3270b57cec5SDimitry Andric     uptr res = idx / (BV::kSize * BV::kSize);
328*0fca6ea1SDimitry Andric     CHECK_LT(res, kLevel1Size);
3290b57cec5SDimitry Andric     return res;
3300b57cec5SDimitry Andric   }
3310b57cec5SDimitry Andric 
idx1(uptr idx)3320b57cec5SDimitry Andric   uptr idx1(uptr idx) const {
3330b57cec5SDimitry Andric     uptr res = (idx / BV::kSize) % BV::kSize;
334*0fca6ea1SDimitry Andric     CHECK_LT(res, BV::kSize);
3350b57cec5SDimitry Andric     return res;
3360b57cec5SDimitry Andric   }
3370b57cec5SDimitry Andric 
idx2(uptr idx)3380b57cec5SDimitry Andric   uptr idx2(uptr idx) const {
3390b57cec5SDimitry Andric     uptr res = idx % BV::kSize;
340*0fca6ea1SDimitry Andric     CHECK_LT(res, BV::kSize);
3410b57cec5SDimitry Andric     return res;
3420b57cec5SDimitry Andric   }
3430b57cec5SDimitry Andric 
3440b57cec5SDimitry Andric   BV l1_[kLevel1Size];
3450b57cec5SDimitry Andric   BV l2_[kLevel1Size][BV::kSize];
3460b57cec5SDimitry Andric };
3470b57cec5SDimitry Andric 
3480b57cec5SDimitry Andric } // namespace __sanitizer
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric #endif // SANITIZER_BITVECTOR_H
351