1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "bit_vector.h"
18
19 #include <limits>
20 #include <sstream>
21
22 #include "allocator.h"
23 #include "bit_vector-inl.h"
24
25 namespace art {
26
BitVector(bool expandable,Allocator * allocator,uint32_t storage_size,uint32_t * storage)27 BitVector::BitVector(bool expandable,
28 Allocator* allocator,
29 uint32_t storage_size,
30 uint32_t* storage)
31 : storage_(storage),
32 storage_size_(storage_size),
33 allocator_(allocator),
34 expandable_(expandable) {
35 DCHECK(storage_ != nullptr);
36
37 static_assert(sizeof(*storage_) == kWordBytes, "word bytes");
38 static_assert(sizeof(*storage_) * 8u == kWordBits, "word bits");
39 }
40
BitVector(uint32_t start_bits,bool expandable,Allocator * allocator)41 BitVector::BitVector(uint32_t start_bits, bool expandable, Allocator* allocator)
42 : BitVector(expandable,
43 allocator,
44 BitsToWords(start_bits),
45 static_cast<uint32_t*>(allocator->Alloc(BitsToWords(start_bits) * kWordBytes))) {}
46
BitVector(const BitVector & src,bool expandable,Allocator * allocator)47 BitVector::BitVector(const BitVector& src,
48 bool expandable,
49 Allocator* allocator)
50 : BitVector(expandable,
51 allocator,
52 src.storage_size_,
53 static_cast<uint32_t*>(allocator->Alloc(src.storage_size_ * kWordBytes))) {
54 // Direct memcpy would be faster, but this should be fine too and is cleaner.
55 Copy(&src);
56 }
57
~BitVector()58 BitVector::~BitVector() {
59 if (storage_ != nullptr) {
60 // Only free if we haven't been moved out of.
61 allocator_->Free(storage_);
62 }
63 }
64
SameBitsSet(const BitVector * src) const65 bool BitVector::SameBitsSet(const BitVector *src) const {
66 int our_highest = GetHighestBitSet();
67 int src_highest = src->GetHighestBitSet();
68
69 // If the highest bit set is different, we are different.
70 if (our_highest != src_highest) {
71 return false;
72 }
73
74 // If the highest bit set is -1, both are cleared, we are the same.
75 // If the highest bit set is 0, both have a unique bit set, we are the same.
76 if (our_highest <= 0) {
77 return true;
78 }
79
80 // Get the highest bit set's cell's index
81 // No need of highest + 1 here because it can't be 0 so BitsToWords will work here.
82 int our_highest_index = BitsToWords(our_highest);
83
84 // This memcmp is enough: we know that the highest bit set is the same for both:
85 // - Therefore, min_size goes up to at least that, we are thus comparing at least what we need to, but not less.
86 // ie. we are comparing all storage cells that could have difference, if both vectors have cells above our_highest_index,
87 // they are automatically at 0.
88 return (memcmp(storage_, src->GetRawStorage(), our_highest_index * kWordBytes) == 0);
89 }
90
IsSubsetOf(const BitVector * other) const91 bool BitVector::IsSubsetOf(const BitVector *other) const {
92 int this_highest = GetHighestBitSet();
93 int other_highest = other->GetHighestBitSet();
94
95 // If the highest bit set is -1, this is empty and a trivial subset.
96 if (this_highest < 0) {
97 return true;
98 }
99
100 // If the highest bit set is higher, this cannot be a subset.
101 if (this_highest > other_highest) {
102 return false;
103 }
104
105 // Compare each 32-bit word.
106 size_t this_highest_index = BitsToWords(this_highest + 1);
107 for (size_t i = 0; i < this_highest_index; ++i) {
108 uint32_t this_storage = storage_[i];
109 uint32_t other_storage = other->storage_[i];
110 if ((this_storage | other_storage) != other_storage) {
111 return false;
112 }
113 }
114 return true;
115 }
116
Intersect(const BitVector * src)117 void BitVector::Intersect(const BitVector* src) {
118 uint32_t src_storage_size = src->storage_size_;
119
120 // Get the minimum size between us and source.
121 uint32_t min_size = (storage_size_ < src_storage_size) ? storage_size_ : src_storage_size;
122
123 uint32_t idx;
124 for (idx = 0; idx < min_size; idx++) {
125 storage_[idx] &= src->GetRawStorageWord(idx);
126 }
127
128 // Now, due to this being an intersection, there are two possibilities:
129 // - Either src was larger than us: we don't care, all upper bits would thus be 0.
130 // - Either we are larger than src: we don't care, all upper bits would have been 0 too.
131 // So all we need to do is set all remaining bits to 0.
132 for (; idx < storage_size_; idx++) {
133 storage_[idx] = 0;
134 }
135 }
136
Union(const BitVector * src)137 bool BitVector::Union(const BitVector* src) {
138 // Get the highest bit to determine how much we need to expand.
139 int highest_bit = src->GetHighestBitSet();
140 bool changed = false;
141
142 // If src has no bit set, we are done: there is no need for a union with src.
143 if (highest_bit == -1) {
144 return changed;
145 }
146
147 // Update src_size to how many cells we actually care about: where the bit is + 1.
148 uint32_t src_size = BitsToWords(highest_bit + 1);
149
150 // Is the storage size smaller than src's?
151 if (storage_size_ < src_size) {
152 changed = true;
153
154 EnsureSize(highest_bit);
155
156 // Check: storage size should be big enough to hold this bit now.
157 DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * kWordBits);
158 }
159
160 for (uint32_t idx = 0; idx < src_size; idx++) {
161 uint32_t existing = storage_[idx];
162 uint32_t update = existing | src->GetRawStorageWord(idx);
163 if (existing != update) {
164 changed = true;
165 storage_[idx] = update;
166 }
167 }
168 return changed;
169 }
170
UnionIfNotIn(const BitVector * union_with,const BitVector * not_in)171 bool BitVector::UnionIfNotIn(const BitVector* union_with, const BitVector* not_in) {
172 // Get the highest bit to determine how much we need to expand.
173 int highest_bit = union_with->GetHighestBitSet();
174 bool changed = false;
175
176 // If src has no bit set, we are done: there is no need for a union with src.
177 if (highest_bit == -1) {
178 return changed;
179 }
180
181 // Update union_with_size to how many cells we actually care about: where the bit is + 1.
182 uint32_t union_with_size = BitsToWords(highest_bit + 1);
183
184 // Is the storage size smaller than src's?
185 if (storage_size_ < union_with_size) {
186 EnsureSize(highest_bit);
187
188 // Check: storage size should be big enough to hold this bit now.
189 DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * kWordBits);
190 }
191
192 uint32_t not_in_size = not_in->GetStorageSize();
193
194 uint32_t idx = 0;
195 for (; idx < std::min(not_in_size, union_with_size); idx++) {
196 uint32_t existing = storage_[idx];
197 uint32_t update = existing |
198 (union_with->GetRawStorageWord(idx) & ~not_in->GetRawStorageWord(idx));
199 if (existing != update) {
200 changed = true;
201 storage_[idx] = update;
202 }
203 }
204
205 for (; idx < union_with_size; idx++) {
206 uint32_t existing = storage_[idx];
207 uint32_t update = existing | union_with->GetRawStorageWord(idx);
208 if (existing != update) {
209 changed = true;
210 storage_[idx] = update;
211 }
212 }
213 return changed;
214 }
215
Subtract(const BitVector * src)216 void BitVector::Subtract(const BitVector *src) {
217 uint32_t src_size = src->storage_size_;
218
219 // We only need to operate on bytes up to the smaller of the sizes of the two operands.
220 unsigned int min_size = (storage_size_ > src_size) ? src_size : storage_size_;
221
222 // Difference until max, we know both accept it:
223 // There is no need to do more:
224 // If we are bigger than src, the upper bits are unchanged.
225 // If we are smaller than src, the nonexistent upper bits are 0 and thus can't get subtracted.
226 for (uint32_t idx = 0; idx < min_size; idx++) {
227 storage_[idx] &= (~(src->GetRawStorageWord(idx)));
228 }
229 }
230
NumSetBits() const231 uint32_t BitVector::NumSetBits() const {
232 uint32_t count = 0;
233 for (uint32_t word = 0; word < storage_size_; word++) {
234 count += POPCOUNT(storage_[word]);
235 }
236 return count;
237 }
238
NumSetBits(uint32_t end) const239 uint32_t BitVector::NumSetBits(uint32_t end) const {
240 DCHECK_LE(end, storage_size_ * kWordBits);
241 return NumSetBits(storage_, end);
242 }
243
SetInitialBits(uint32_t num_bits)244 void BitVector::SetInitialBits(uint32_t num_bits) {
245 // If num_bits is 0, clear everything.
246 if (num_bits == 0) {
247 ClearAllBits();
248 return;
249 }
250
251 // Set the highest bit we want to set to get the BitVector allocated if need be.
252 SetBit(num_bits - 1);
253
254 uint32_t idx;
255 // We can set every storage element with -1.
256 for (idx = 0; idx < WordIndex(num_bits); idx++) {
257 storage_[idx] = std::numeric_limits<uint32_t>::max();
258 }
259
260 // Handle the potentially last few bits.
261 uint32_t rem_num_bits = num_bits & 0x1f;
262 if (rem_num_bits != 0) {
263 storage_[idx] = (1U << rem_num_bits) - 1;
264 ++idx;
265 }
266
267 // Now set the upper ones to 0.
268 for (; idx < storage_size_; idx++) {
269 storage_[idx] = 0;
270 }
271 }
272
GetHighestBitSet() const273 int BitVector::GetHighestBitSet() const {
274 unsigned int max = storage_size_;
275 for (int idx = max - 1; idx >= 0; idx--) {
276 // If not 0, we have more work: check the bits.
277 uint32_t value = storage_[idx];
278
279 if (value != 0) {
280 // Return highest bit set in value plus bits from previous storage indexes.
281 return 31 - CLZ(value) + (idx * kWordBits);
282 }
283 }
284
285 // All zero, therefore return -1.
286 return -1;
287 }
288
Copy(const BitVector * src)289 void BitVector::Copy(const BitVector *src) {
290 // Get highest bit set, we only need to copy till then.
291 int highest_bit = src->GetHighestBitSet();
292
293 // If nothing is set, clear everything.
294 if (highest_bit == -1) {
295 ClearAllBits();
296 return;
297 }
298
299 // Set upper bit to ensure right size before copy.
300 SetBit(highest_bit);
301
302 // Now set until highest bit's storage.
303 uint32_t size = 1 + (highest_bit / kWordBits);
304 memcpy(storage_, src->GetRawStorage(), kWordBytes * size);
305
306 // Set upper bits to 0.
307 uint32_t left = storage_size_ - size;
308
309 if (left > 0) {
310 memset(storage_ + size, 0, kWordBytes * left);
311 }
312 }
313
NumSetBits(const uint32_t * storage,uint32_t end)314 uint32_t BitVector::NumSetBits(const uint32_t* storage, uint32_t end) {
315 uint32_t word_end = WordIndex(end);
316 uint32_t partial_word_bits = end & 0x1f;
317
318 uint32_t count = 0u;
319 for (uint32_t word = 0u; word < word_end; word++) {
320 count += POPCOUNT(storage[word]);
321 }
322 if (partial_word_bits != 0u) {
323 count += POPCOUNT(storage[word_end] & ~(0xffffffffu << partial_word_bits));
324 }
325 return count;
326 }
327
Dump(std::ostream & os,const char * prefix) const328 void BitVector::Dump(std::ostream& os, const char *prefix) const {
329 std::ostringstream buffer;
330 DumpHelper(prefix, buffer);
331 os << buffer.str() << std::endl;
332 }
333
DumpHelper(const char * prefix,std::ostringstream & buffer) const334 void BitVector::DumpHelper(const char* prefix, std::ostringstream& buffer) const {
335 // Initialize it.
336 if (prefix != nullptr) {
337 buffer << prefix;
338 }
339
340 buffer << '(';
341 for (size_t i = 0; i < storage_size_ * kWordBits; i++) {
342 buffer << IsBitSet(i);
343 }
344 buffer << ')';
345 }
346
EnsureSize(uint32_t idx)347 void BitVector::EnsureSize(uint32_t idx) {
348 if (idx >= storage_size_ * kWordBits) {
349 DCHECK(expandable_) << "Attempted to expand a non-expandable bitmap to position " << idx;
350
351 /* Round up to word boundaries for "idx+1" bits */
352 uint32_t new_size = BitsToWords(idx + 1);
353 DCHECK_GT(new_size, storage_size_);
354 uint32_t *new_storage =
355 static_cast<uint32_t*>(allocator_->Alloc(new_size * kWordBytes));
356 memcpy(new_storage, storage_, storage_size_ * kWordBytes);
357 // Zero out the new storage words.
358 memset(&new_storage[storage_size_], 0, (new_size - storage_size_) * kWordBytes);
359 // TODO: collect stats on space wasted because of resize.
360
361 // Free old storage.
362 allocator_->Free(storage_);
363
364 // Set fields.
365 storage_ = new_storage;
366 storage_size_ = new_size;
367 }
368 }
369
GetAllocator() const370 Allocator* BitVector::GetAllocator() const {
371 return allocator_;
372 }
373
374 } // namespace art
375