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 18 namespace __sanitizer { 19 20 // Fixed size bit vector based on a single basic integer. 21 template <class basic_int_t = uptr> 22 class 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. 109 template <uptr kLevel1Size = 1, class BV = BasicBitVector<> > 110 class 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_LE(idx, size()); } 325 326 uptr idx0(uptr idx) const { 327 uptr res = idx / (BV::kSize * BV::kSize); 328 CHECK_LE(res, kLevel1Size); 329 return res; 330 } 331 332 uptr idx1(uptr idx) const { 333 uptr res = (idx / BV::kSize) % BV::kSize; 334 CHECK_LE(res, BV::kSize); 335 return res; 336 } 337 338 uptr idx2(uptr idx) const { 339 uptr res = idx % BV::kSize; 340 CHECK_LE(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 351