Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h
35233 views
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_LT(idx, size()); }
325
326
uptr idx0(uptr idx) const {
327
uptr res = idx / (BV::kSize * BV::kSize);
328
CHECK_LT(res, kLevel1Size);
329
return res;
330
}
331
332
uptr idx1(uptr idx) const {
333
uptr res = (idx / BV::kSize) % BV::kSize;
334
CHECK_LT(res, BV::kSize);
335
return res;
336
}
337
338
uptr idx2(uptr idx) const {
339
uptr res = idx % BV::kSize;
340
CHECK_LT(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
352