1 //===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Specializer BitVector implementation.
11 //===----------------------------------------------------------------------===//
13 #ifndef SANITIZER_BITVECTOR_H
14 #define SANITIZER_BITVECTOR_H
16 #include "sanitizer_common.h"
18 namespace __sanitizer
{
20 // Fixed size bit vector based on a single basic integer.
21 template <class basic_int_t
= uptr
>
22 class BasicBitVector
{
24 enum SizeEnum
: uptr
{ kSize
= sizeof(basic_int_t
) * 8 };
26 uptr
size() const { return kSize
; }
28 void clear() { bits_
= 0; }
29 void setAll() { bits_
= ~(basic_int_t
)0; }
30 bool empty() const { return bits_
== 0; }
32 // Returns true if the bit has changed from 0 to 1.
33 bool setBit(uptr idx
) {
34 basic_int_t old
= bits_
;
39 // Returns true if the bit has changed from 1 to 0.
40 bool clearBit(uptr idx
) {
41 basic_int_t old
= bits_
;
46 bool getBit(uptr idx
) const { return (bits_
& mask(idx
)) != 0; }
48 uptr
getAndClearFirstOne() {
50 uptr idx
= LeastSignificantSetBitIndex(bits_
);
55 // Do "this |= v" and return whether new bits have been added.
56 bool setUnion(const BasicBitVector
&v
) {
57 basic_int_t old
= bits_
;
62 // Do "this &= v" and return whether any bits have been removed.
63 bool setIntersection(const BasicBitVector
&v
) {
64 basic_int_t old
= bits_
;
69 // Do "this &= ~v" and return whether any bits have been removed.
70 bool setDifference(const BasicBitVector
&v
) {
71 basic_int_t old
= bits_
;
76 void copyFrom(const BasicBitVector
&v
) { bits_
= v
.bits_
; }
78 // Returns true if 'this' intersects with 'v'.
79 bool intersectsWith(const BasicBitVector
&v
) const {
80 return (bits_
& v
.bits_
) != 0;
83 // for (BasicBitVector<>::Iterator it(bv); it.hasNext();) {
84 // uptr idx = it.next();
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(); }
99 basic_int_t
mask(uptr idx
) const {
100 CHECK_LT(idx
, size());
101 return (basic_int_t
)1UL << idx
;
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.
117 enum SizeEnum
: uptr
{ kSize
= BV::kSize
* BV::kSize
* kLevel1Size
};
120 uptr
size() const { return kSize
; }
123 for (uptr i
= 0; i
< kLevel1Size
; i
++)
128 for (uptr i0
= 0; i0
< kLevel1Size
; i0
++) {
130 for (uptr i1
= 0; i1
< BV::kSize
; i1
++)
131 l2_
[i0
][i1
].setAll();
136 for (uptr i
= 0; i
< kLevel1Size
; i
++)
142 // Returns true if the bit has changed from 0 to 1.
143 bool setBit(uptr idx
) {
148 if (!l1_
[i0
].getBit(i1
)) {
152 bool res
= l2_
[i0
][i1
].setBit(i2
);
153 // Printf("%s: %zd => %zd %zd %zd; %d\n", __func__,
154 // idx, i0, i1, i2, res);
158 bool clearBit(uptr idx
) {
164 if (l1_
[i0
].getBit(i1
)) {
165 res
= l2_
[i0
][i1
].clearBit(i2
);
166 if (l2_
[i0
][i1
].empty())
167 l1_
[i0
].clearBit(i1
);
172 bool getBit(uptr idx
) const {
177 // Printf("%s: %zd => %zd %zd %zd\n", __func__, idx, i0, i1, i2);
178 return l1_
[i0
].getBit(i1
) && l2_
[i0
][i1
].getBit(i2
);
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())
188 uptr res
= i0
* BV::kSize
* BV::kSize
+ i1
* BV::kSize
+ i2
;
189 // Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res);
196 // Do "this |= v" and return whether new bits have been added.
197 bool setUnion(const TwoLevelBitVector
&v
) {
199 for (uptr i0
= 0; i0
< kLevel1Size
; i0
++) {
202 uptr i1
= t
.getAndClearFirstOne();
203 if (l1_
[i0
].setBit(i1
))
205 if (l2_
[i0
][i1
].setUnion(v
.l2_
[i0
][i1
]))
212 // Do "this &= v" and return whether any bits have been removed.
213 bool setIntersection(const TwoLevelBitVector
&v
) {
215 for (uptr i0
= 0; i0
< kLevel1Size
; i0
++) {
216 if (l1_
[i0
].setIntersection(v
.l1_
[i0
]))
218 if (!l1_
[i0
].empty()) {
221 uptr i1
= t
.getAndClearFirstOne();
222 if (l2_
[i0
][i1
].setIntersection(v
.l2_
[i0
][i1
]))
224 if (l2_
[i0
][i1
].empty())
225 l1_
[i0
].clearBit(i1
);
232 // Do "this &= ~v" and return whether any bits have been removed.
233 bool setDifference(const TwoLevelBitVector
&v
) {
235 for (uptr i0
= 0; i0
< kLevel1Size
; i0
++) {
237 t
.setIntersection(v
.l1_
[i0
]);
239 uptr i1
= t
.getAndClearFirstOne();
240 if (l2_
[i0
][i1
].setDifference(v
.l2_
[i0
][i1
]))
242 if (l2_
[i0
][i1
].empty())
243 l1_
[i0
].clearBit(i1
);
249 void copyFrom(const TwoLevelBitVector
&v
) {
254 // Returns true if 'this' intersects with 'v'.
255 bool intersectsWith(const TwoLevelBitVector
&v
) const {
256 for (uptr i0
= 0; i0
< kLevel1Size
; i0
++) {
258 t
.setIntersection(v
.l1_
[i0
]);
260 uptr i1
= t
.getAndClearFirstOne();
261 if (!v
.l1_
[i0
].getBit(i1
)) continue;
262 if (l2_
[i0
][i1
].intersectsWith(v
.l2_
[i0
][i1
]))
269 // for (TwoLevelBitVector<>::Iterator it(bv); it.hasNext();) {
270 // uptr idx = it.next();
276 explicit Iterator(const TwoLevelBitVector
&bv
) : bv_(bv
), i0_(0), i1_(0) {
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;
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);
300 if (!it2_
.hasNext()) {
301 CHECK(it1_
.hasNext());
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);
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())
318 const TwoLevelBitVector
&bv_
;
320 typename
BV::Iterator it1_
, it2_
;
324 void check(uptr idx
) const { CHECK_LE(idx
, size()); }
326 uptr
idx0(uptr idx
) const {
327 uptr res
= idx
/ (BV::kSize
* BV::kSize
);
328 CHECK_LE(res
, kLevel1Size
);
332 uptr
idx1(uptr idx
) const {
333 uptr res
= (idx
/ BV::kSize
) % BV::kSize
;
334 CHECK_LE(res
, BV::kSize
);
338 uptr
idx2(uptr idx
) const {
339 uptr res
= idx
% BV::kSize
;
340 CHECK_LE(res
, BV::kSize
);
345 BV l2_
[kLevel1Size
][BV::kSize
];
348 } // namespace __sanitizer
350 #endif // SANITIZER_BITVECTOR_H