• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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