Path: blob/main/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h
35233 views
//===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Specializer BitVector implementation.9//10//===----------------------------------------------------------------------===//1112#ifndef SANITIZER_BITVECTOR_H13#define SANITIZER_BITVECTOR_H1415#include "sanitizer_common.h"1617namespace __sanitizer {1819// Fixed size bit vector based on a single basic integer.20template <class basic_int_t = uptr>21class BasicBitVector {22public:23enum SizeEnum : uptr { kSize = sizeof(basic_int_t) * 8 };2425uptr size() const { return kSize; }26// No CTOR.27void clear() { bits_ = 0; }28void setAll() { bits_ = ~(basic_int_t)0; }29bool empty() const { return bits_ == 0; }3031// Returns true if the bit has changed from 0 to 1.32bool setBit(uptr idx) {33basic_int_t old = bits_;34bits_ |= mask(idx);35return bits_ != old;36}3738// Returns true if the bit has changed from 1 to 0.39bool clearBit(uptr idx) {40basic_int_t old = bits_;41bits_ &= ~mask(idx);42return bits_ != old;43}4445bool getBit(uptr idx) const { return (bits_ & mask(idx)) != 0; }4647uptr getAndClearFirstOne() {48CHECK(!empty());49uptr idx = LeastSignificantSetBitIndex(bits_);50clearBit(idx);51return idx;52}5354// Do "this |= v" and return whether new bits have been added.55bool setUnion(const BasicBitVector &v) {56basic_int_t old = bits_;57bits_ |= v.bits_;58return bits_ != old;59}6061// Do "this &= v" and return whether any bits have been removed.62bool setIntersection(const BasicBitVector &v) {63basic_int_t old = bits_;64bits_ &= v.bits_;65return bits_ != old;66}6768// Do "this &= ~v" and return whether any bits have been removed.69bool setDifference(const BasicBitVector &v) {70basic_int_t old = bits_;71bits_ &= ~v.bits_;72return bits_ != old;73}7475void copyFrom(const BasicBitVector &v) { bits_ = v.bits_; }7677// Returns true if 'this' intersects with 'v'.78bool intersectsWith(const BasicBitVector &v) const {79return (bits_ & v.bits_) != 0;80}8182// for (BasicBitVector<>::Iterator it(bv); it.hasNext();) {83// uptr idx = it.next();84// use(idx);85// }86class Iterator {87public:88Iterator() { }89explicit Iterator(const BasicBitVector &bv) : bv_(bv) {}90bool hasNext() const { return !bv_.empty(); }91uptr next() { return bv_.getAndClearFirstOne(); }92void clear() { bv_.clear(); }93private:94BasicBitVector bv_;95};9697private:98basic_int_t mask(uptr idx) const {99CHECK_LT(idx, size());100return (basic_int_t)1UL << idx;101}102basic_int_t bits_;103};104105// Fixed size bit vector of (kLevel1Size*BV::kSize**2) bits.106// The implementation is optimized for better performance on107// sparse bit vectors, i.e. the those with few set bits.108template <uptr kLevel1Size = 1, class BV = BasicBitVector<> >109class TwoLevelBitVector {110// This is essentially a 2-level bit vector.111// Set bit in the first level BV indicates that there are set bits112// in the corresponding BV of the second level.113// This structure allows O(kLevel1Size) time for clear() and empty(),114// as well fast handling of sparse BVs.115public:116enum SizeEnum : uptr { kSize = BV::kSize * BV::kSize * kLevel1Size };117// No CTOR.118119uptr size() const { return kSize; }120121void clear() {122for (uptr i = 0; i < kLevel1Size; i++)123l1_[i].clear();124}125126void setAll() {127for (uptr i0 = 0; i0 < kLevel1Size; i0++) {128l1_[i0].setAll();129for (uptr i1 = 0; i1 < BV::kSize; i1++)130l2_[i0][i1].setAll();131}132}133134bool empty() const {135for (uptr i = 0; i < kLevel1Size; i++)136if (!l1_[i].empty())137return false;138return true;139}140141// Returns true if the bit has changed from 0 to 1.142bool setBit(uptr idx) {143check(idx);144uptr i0 = idx0(idx);145uptr i1 = idx1(idx);146uptr i2 = idx2(idx);147if (!l1_[i0].getBit(i1)) {148l1_[i0].setBit(i1);149l2_[i0][i1].clear();150}151bool res = l2_[i0][i1].setBit(i2);152// Printf("%s: %zd => %zd %zd %zd; %d\n", __func__,153// idx, i0, i1, i2, res);154return res;155}156157bool clearBit(uptr idx) {158check(idx);159uptr i0 = idx0(idx);160uptr i1 = idx1(idx);161uptr i2 = idx2(idx);162bool res = false;163if (l1_[i0].getBit(i1)) {164res = l2_[i0][i1].clearBit(i2);165if (l2_[i0][i1].empty())166l1_[i0].clearBit(i1);167}168return res;169}170171bool getBit(uptr idx) const {172check(idx);173uptr i0 = idx0(idx);174uptr i1 = idx1(idx);175uptr i2 = idx2(idx);176// Printf("%s: %zd => %zd %zd %zd\n", __func__, idx, i0, i1, i2);177return l1_[i0].getBit(i1) && l2_[i0][i1].getBit(i2);178}179180uptr getAndClearFirstOne() {181for (uptr i0 = 0; i0 < kLevel1Size; i0++) {182if (l1_[i0].empty()) continue;183uptr i1 = l1_[i0].getAndClearFirstOne();184uptr i2 = l2_[i0][i1].getAndClearFirstOne();185if (!l2_[i0][i1].empty())186l1_[i0].setBit(i1);187uptr res = i0 * BV::kSize * BV::kSize + i1 * BV::kSize + i2;188// Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res);189return res;190}191CHECK(0);192return 0;193}194195// Do "this |= v" and return whether new bits have been added.196bool setUnion(const TwoLevelBitVector &v) {197bool res = false;198for (uptr i0 = 0; i0 < kLevel1Size; i0++) {199BV t = v.l1_[i0];200while (!t.empty()) {201uptr i1 = t.getAndClearFirstOne();202if (l1_[i0].setBit(i1))203l2_[i0][i1].clear();204if (l2_[i0][i1].setUnion(v.l2_[i0][i1]))205res = true;206}207}208return res;209}210211// Do "this &= v" and return whether any bits have been removed.212bool setIntersection(const TwoLevelBitVector &v) {213bool res = false;214for (uptr i0 = 0; i0 < kLevel1Size; i0++) {215if (l1_[i0].setIntersection(v.l1_[i0]))216res = true;217if (!l1_[i0].empty()) {218BV t = l1_[i0];219while (!t.empty()) {220uptr i1 = t.getAndClearFirstOne();221if (l2_[i0][i1].setIntersection(v.l2_[i0][i1]))222res = true;223if (l2_[i0][i1].empty())224l1_[i0].clearBit(i1);225}226}227}228return res;229}230231// Do "this &= ~v" and return whether any bits have been removed.232bool setDifference(const TwoLevelBitVector &v) {233bool res = false;234for (uptr i0 = 0; i0 < kLevel1Size; i0++) {235BV t = l1_[i0];236t.setIntersection(v.l1_[i0]);237while (!t.empty()) {238uptr i1 = t.getAndClearFirstOne();239if (l2_[i0][i1].setDifference(v.l2_[i0][i1]))240res = true;241if (l2_[i0][i1].empty())242l1_[i0].clearBit(i1);243}244}245return res;246}247248void copyFrom(const TwoLevelBitVector &v) {249clear();250setUnion(v);251}252253// Returns true if 'this' intersects with 'v'.254bool intersectsWith(const TwoLevelBitVector &v) const {255for (uptr i0 = 0; i0 < kLevel1Size; i0++) {256BV t = l1_[i0];257t.setIntersection(v.l1_[i0]);258while (!t.empty()) {259uptr i1 = t.getAndClearFirstOne();260if (!v.l1_[i0].getBit(i1)) continue;261if (l2_[i0][i1].intersectsWith(v.l2_[i0][i1]))262return true;263}264}265return false;266}267268// for (TwoLevelBitVector<>::Iterator it(bv); it.hasNext();) {269// uptr idx = it.next();270// use(idx);271// }272class Iterator {273public:274Iterator() { }275explicit Iterator(const TwoLevelBitVector &bv) : bv_(bv), i0_(0), i1_(0) {276it1_.clear();277it2_.clear();278}279280bool hasNext() const {281if (it1_.hasNext()) return true;282for (uptr i = i0_; i < kLevel1Size; i++)283if (!bv_.l1_[i].empty()) return true;284return false;285}286287uptr next() {288// Printf("++++: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),289// it2_.hasNext(), kSize);290if (!it1_.hasNext() && !it2_.hasNext()) {291for (; i0_ < kLevel1Size; i0_++) {292if (bv_.l1_[i0_].empty()) continue;293it1_ = typename BV::Iterator(bv_.l1_[i0_]);294// Printf("+i0: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),295// it2_.hasNext(), kSize);296break;297}298}299if (!it2_.hasNext()) {300CHECK(it1_.hasNext());301i1_ = it1_.next();302it2_ = typename BV::Iterator(bv_.l2_[i0_][i1_]);303// Printf("++i1: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),304// it2_.hasNext(), kSize);305}306CHECK(it2_.hasNext());307uptr i2 = it2_.next();308uptr res = i0_ * BV::kSize * BV::kSize + i1_ * BV::kSize + i2;309// Printf("+ret: %zd %zd; %d %d; size %zd; res: %zd\n", i0_, i1_,310// it1_.hasNext(), it2_.hasNext(), kSize, res);311if (!it1_.hasNext() && !it2_.hasNext())312i0_++;313return res;314}315316private:317const TwoLevelBitVector &bv_;318uptr i0_, i1_;319typename BV::Iterator it1_, it2_;320};321322private:323void check(uptr idx) const { CHECK_LT(idx, size()); }324325uptr idx0(uptr idx) const {326uptr res = idx / (BV::kSize * BV::kSize);327CHECK_LT(res, kLevel1Size);328return res;329}330331uptr idx1(uptr idx) const {332uptr res = (idx / BV::kSize) % BV::kSize;333CHECK_LT(res, BV::kSize);334return res;335}336337uptr idx2(uptr idx) const {338uptr res = idx % BV::kSize;339CHECK_LT(res, BV::kSize);340return res;341}342343BV l1_[kLevel1Size];344BV l2_[kLevel1Size][BV::kSize];345};346347} // namespace __sanitizer348349#endif // SANITIZER_BITVECTOR_H350351352