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