Home | History | Annotate | Download | only in base
      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 namespace art {
     20 
     21 // TODO: profile to make sure this is still a win relative to just using shifted masks.
     22 static uint32_t check_masks[32] = {
     23   0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010,
     24   0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200,
     25   0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000,
     26   0x00008000, 0x00010000, 0x00020000, 0x00040000, 0x00080000,
     27   0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000,
     28   0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000,
     29   0x40000000, 0x80000000 };
     30 
     31 static inline uint32_t BitsToWords(uint32_t bits) {
     32   return (bits + 31) >> 5;
     33 }
     34 
     35 // TODO: replace excessive argument defaulting when we are at gcc 4.7
     36 // or later on host with delegating constructor support. Specifically,
     37 // starts_bits and storage_size/storage are mutually exclusive.
     38 BitVector::BitVector(uint32_t start_bits,
     39                      bool expandable,
     40                      Allocator* allocator,
     41                      uint32_t storage_size,
     42                      uint32_t* storage)
     43   : allocator_(allocator),
     44     expandable_(expandable),
     45     storage_size_(storage_size),
     46     storage_(storage) {
     47   COMPILE_ASSERT(sizeof(*storage_) == kWordBytes, check_word_bytes);
     48   COMPILE_ASSERT(sizeof(*storage_) * 8u == kWordBits, check_word_bits);
     49   if (storage_ == nullptr) {
     50     storage_size_ = BitsToWords(start_bits);
     51     storage_ = static_cast<uint32_t*>(allocator_->Alloc(storage_size_ * kWordBytes));
     52   }
     53 }
     54 
     55 BitVector::~BitVector() {
     56   allocator_->Free(storage_);
     57 }
     58 
     59 /*
     60  * Determine whether or not the specified bit is set.
     61  */
     62 bool BitVector::IsBitSet(uint32_t num) const {
     63   // If the index is over the size:
     64   if (num >= storage_size_ * kWordBits) {
     65     // Whether it is expandable or not, this bit does not exist: thus it is not set.
     66     return false;
     67   }
     68 
     69   return IsBitSet(storage_, num);
     70 }
     71 
     72 // Mark all bits bit as "clear".
     73 void BitVector::ClearAllBits() {
     74   memset(storage_, 0, storage_size_ * kWordBytes);
     75 }
     76 
     77 // Mark the specified bit as "set".
     78 /*
     79  * TUNING: this could have pathologically bad growth/expand behavior.  Make sure we're
     80  * not using it badly or change resize mechanism.
     81  */
     82 void BitVector::SetBit(uint32_t num) {
     83   if (num >= storage_size_ * kWordBits) {
     84     DCHECK(expandable_) << "Attempted to expand a non-expandable bitmap to position " << num;
     85 
     86     /* Round up to word boundaries for "num+1" bits */
     87     uint32_t new_size = BitsToWords(num + 1);
     88     DCHECK_GT(new_size, storage_size_);
     89     uint32_t *new_storage =
     90         static_cast<uint32_t*>(allocator_->Alloc(new_size * kWordBytes));
     91     memcpy(new_storage, storage_, storage_size_ * kWordBytes);
     92     // Zero out the new storage words.
     93     memset(&new_storage[storage_size_], 0, (new_size - storage_size_) * kWordBytes);
     94     // TOTO: collect stats on space wasted because of resize.
     95     storage_ = new_storage;
     96     storage_size_ = new_size;
     97   }
     98 
     99   storage_[num >> 5] |= check_masks[num & 0x1f];
    100 }
    101 
    102 // Mark the specified bit as "unset".
    103 void BitVector::ClearBit(uint32_t num) {
    104   // If the index is over the size, we don't have to do anything, it is cleared.
    105   if (num < storage_size_ * kWordBits) {
    106     // Otherwise, go ahead and clear it.
    107     storage_[num >> 5] &= ~check_masks[num & 0x1f];
    108   }
    109 }
    110 
    111 bool BitVector::SameBitsSet(const BitVector *src) {
    112   int our_highest = GetHighestBitSet();
    113   int src_highest = src->GetHighestBitSet();
    114 
    115   // If the highest bit set is different, we are different.
    116   if (our_highest != src_highest) {
    117     return false;
    118   }
    119 
    120   // If the highest bit set is -1, both are cleared, we are the same.
    121   // If the highest bit set is 0, both have a unique bit set, we are the same.
    122   if (our_highest <= 0) {
    123     return true;
    124   }
    125 
    126   // Get the highest bit set's cell's index
    127   // No need of highest + 1 here because it can't be 0 so BitsToWords will work here.
    128   int our_highest_index = BitsToWords(our_highest);
    129 
    130   // This memcmp is enough: we know that the highest bit set is the same for both:
    131   //   - Therefore, min_size goes up to at least that, we are thus comparing at least what we need to, but not less.
    132   //      ie. we are comparing all storage cells that could have difference, if both vectors have cells above our_highest_index,
    133   //          they are automatically at 0.
    134   return (memcmp(storage_, src->GetRawStorage(), our_highest_index * kWordBytes) == 0);
    135 }
    136 
    137 // Intersect with another bit vector.
    138 void BitVector::Intersect(const BitVector* src) {
    139   uint32_t src_storage_size = src->storage_size_;
    140 
    141   // Get the minimum size between us and source.
    142   uint32_t min_size = (storage_size_ < src_storage_size) ? storage_size_ : src_storage_size;
    143 
    144   uint32_t idx;
    145   for (idx = 0; idx < min_size; idx++) {
    146     storage_[idx] &= src->GetRawStorageWord(idx);
    147   }
    148 
    149   // Now, due to this being an intersection, there are two possibilities:
    150   //   - Either src was larger than us: we don't care, all upper bits would thus be 0.
    151   //   - Either we are larger than src: we don't care, all upper bits would have been 0 too.
    152   // So all we need to do is set all remaining bits to 0.
    153   for (; idx < storage_size_; idx++) {
    154     storage_[idx] = 0;
    155   }
    156 }
    157 
    158 /*
    159  * Union with another bit vector.
    160  */
    161 bool BitVector::Union(const BitVector* src) {
    162   // Get the highest bit to determine how much we need to expand.
    163   int highest_bit = src->GetHighestBitSet();
    164   bool changed = false;
    165 
    166   // If src has no bit set, we are done: there is no need for a union with src.
    167   if (highest_bit == -1) {
    168     return changed;
    169   }
    170 
    171   // Update src_size to how many cells we actually care about: where the bit is + 1.
    172   uint32_t src_size = BitsToWords(highest_bit + 1);
    173 
    174   // Is the storage size smaller than src's?
    175   if (storage_size_ < src_size) {
    176     changed = true;
    177 
    178     // Set it to reallocate.
    179     SetBit(highest_bit);
    180 
    181     // Paranoid: storage size should be big enough to hold this bit now.
    182     DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * kWordBits);
    183   }
    184 
    185   for (uint32_t idx = 0; idx < src_size; idx++) {
    186     uint32_t existing = storage_[idx];
    187     uint32_t update = existing | src->GetRawStorageWord(idx);
    188     if (existing != update) {
    189       changed = true;
    190       storage_[idx] = update;
    191     }
    192   }
    193   return changed;
    194 }
    195 
    196 bool BitVector::UnionIfNotIn(const BitVector* union_with, const BitVector* not_in) {
    197   // Get the highest bit to determine how much we need to expand.
    198   int highest_bit = union_with->GetHighestBitSet();
    199   bool changed = false;
    200 
    201   // If src has no bit set, we are done: there is no need for a union with src.
    202   if (highest_bit == -1) {
    203     return changed;
    204   }
    205 
    206   // Update union_with_size to how many cells we actually care about: where the bit is + 1.
    207   uint32_t union_with_size = BitsToWords(highest_bit + 1);
    208 
    209   // Is the storage size smaller than src's?
    210   if (storage_size_ < union_with_size) {
    211     changed = true;
    212 
    213     // Set it to reallocate.
    214     SetBit(highest_bit);
    215 
    216     // Paranoid: storage size should be big enough to hold this bit now.
    217     DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * kWordBits);
    218   }
    219 
    220   uint32_t not_in_size = not_in->GetStorageSize();
    221 
    222   uint32_t idx = 0;
    223   for (; idx < std::min(not_in_size, union_with_size); idx++) {
    224     uint32_t existing = storage_[idx];
    225     uint32_t update = existing |
    226         (union_with->GetRawStorageWord(idx) & ~not_in->GetRawStorageWord(idx));
    227     if (existing != update) {
    228       changed = true;
    229       storage_[idx] = update;
    230     }
    231   }
    232 
    233   for (; idx < union_with_size; idx++) {
    234     uint32_t existing = storage_[idx];
    235     uint32_t update = existing | union_with->GetRawStorageWord(idx);
    236     if (existing != update) {
    237       changed = true;
    238       storage_[idx] = update;
    239     }
    240   }
    241   return changed;
    242 }
    243 
    244 void BitVector::Subtract(const BitVector *src) {
    245     uint32_t src_size = src->storage_size_;
    246 
    247     // We only need to operate on bytes up to the smaller of the sizes of the two operands.
    248     unsigned int min_size = (storage_size_ > src_size) ? src_size : storage_size_;
    249 
    250     // Difference until max, we know both accept it:
    251     //   There is no need to do more:
    252     //     If we are bigger than src, the upper bits are unchanged.
    253     //     If we are smaller than src, the non-existant upper bits are 0 and thus can't get subtracted.
    254     for (uint32_t idx = 0; idx < min_size; idx++) {
    255         storage_[idx] &= (~(src->GetRawStorageWord(idx)));
    256     }
    257 }
    258 
    259 // Count the number of bits that are set.
    260 uint32_t BitVector::NumSetBits() const {
    261   uint32_t count = 0;
    262   for (uint32_t word = 0; word < storage_size_; word++) {
    263     count += POPCOUNT(storage_[word]);
    264   }
    265   return count;
    266 }
    267 
    268 // Count the number of bits that are set in range [0, end).
    269 uint32_t BitVector::NumSetBits(uint32_t end) const {
    270   DCHECK_LE(end, storage_size_ * kWordBits);
    271   return NumSetBits(storage_, end);
    272 }
    273 
    274 /*
    275  * Mark specified number of bits as "set". Cannot set all bits like ClearAll
    276  * since there might be unused bits - setting those to one will confuse the
    277  * iterator.
    278  */
    279 void BitVector::SetInitialBits(uint32_t num_bits) {
    280   // If num_bits is 0, clear everything.
    281   if (num_bits == 0) {
    282     ClearAllBits();
    283     return;
    284   }
    285 
    286   // Set the highest bit we want to set to get the BitVector allocated if need be.
    287   SetBit(num_bits - 1);
    288 
    289   uint32_t idx;
    290   // We can set every storage element with -1.
    291   for (idx = 0; idx < (num_bits >> 5); idx++) {
    292     storage_[idx] = -1;
    293   }
    294 
    295   // Handle the potentially last few bits.
    296   uint32_t rem_num_bits = num_bits & 0x1f;
    297   if (rem_num_bits != 0) {
    298     storage_[idx] = (1 << rem_num_bits) - 1;
    299     ++idx;
    300   }
    301 
    302   // Now set the upper ones to 0.
    303   for (; idx < storage_size_; idx++) {
    304     storage_[idx] = 0;
    305   }
    306 }
    307 
    308 int BitVector::GetHighestBitSet() const {
    309   unsigned int max = storage_size_;
    310   for (int idx = max - 1; idx >= 0; idx--) {
    311     // If not 0, we have more work: check the bits.
    312     uint32_t value = storage_[idx];
    313 
    314     if (value != 0) {
    315       // Shift right for the counting.
    316       value /= 2;
    317 
    318       int cnt = 0;
    319 
    320       // Count the bits.
    321       while (value > 0) {
    322         value /= 2;
    323         cnt++;
    324       }
    325 
    326       // Return cnt + how many storage units still remain * the number of bits per unit.
    327       int res = cnt + (idx * kWordBits);
    328       return res;
    329     }
    330   }
    331 
    332   // All zero, therefore return -1.
    333   return -1;
    334 }
    335 
    336 bool BitVector::EnsureSizeAndClear(unsigned int num) {
    337   // Check if the bitvector is expandable.
    338   if (IsExpandable() == false) {
    339     return false;
    340   }
    341 
    342   if (num > 0) {
    343     // Now try to expand by setting the last bit.
    344     SetBit(num - 1);
    345   }
    346 
    347   // We must clear all bits as per our specification.
    348   ClearAllBits();
    349 
    350   return true;
    351 }
    352 
    353 void BitVector::Copy(const BitVector *src) {
    354   // Get highest bit set, we only need to copy till then.
    355   int highest_bit = src->GetHighestBitSet();
    356 
    357   // If nothing is set, clear everything.
    358   if (highest_bit == -1) {
    359     ClearAllBits();
    360     return;
    361   }
    362 
    363   // Set upper bit to ensure right size before copy.
    364   SetBit(highest_bit);
    365 
    366   // Now set until highest bit's storage.
    367   uint32_t size = 1 + (highest_bit / kWordBits);
    368   memcpy(storage_, src->GetRawStorage(), kWordBytes * size);
    369 
    370   // Set upper bits to 0.
    371   uint32_t left = storage_size_ - size;
    372 
    373   if (left > 0) {
    374     memset(storage_ + size, 0, kWordBytes * left);
    375   }
    376 }
    377 
    378 bool BitVector::IsBitSet(const uint32_t* storage, uint32_t num) {
    379   uint32_t val = storage[num >> 5] & check_masks[num & 0x1f];
    380   return (val != 0);
    381 }
    382 
    383 uint32_t BitVector::NumSetBits(const uint32_t* storage, uint32_t end) {
    384   uint32_t word_end = end >> 5;
    385   uint32_t partial_word_bits = end & 0x1f;
    386 
    387   uint32_t count = 0u;
    388   for (uint32_t word = 0u; word < word_end; word++) {
    389     count += POPCOUNT(storage[word]);
    390   }
    391   if (partial_word_bits != 0u) {
    392     count += POPCOUNT(storage[word_end] & ~(0xffffffffu << partial_word_bits));
    393   }
    394   return count;
    395 }
    396 
    397 void BitVector::Dump(std::ostream& os, const char *prefix) const {
    398   std::ostringstream buffer;
    399   DumpHelper(prefix, buffer);
    400   os << buffer.str() << std::endl;
    401 }
    402 
    403 
    404 void BitVector::DumpDotHelper(bool last_entry, FILE* file, std::ostringstream& buffer) const {
    405   // Now print it to the file.
    406   fprintf(file, "    {%s}", buffer.str().c_str());
    407 
    408   // If it isn't the last entry, add a |.
    409   if (last_entry == false) {
    410     fprintf(file, "|");
    411   }
    412 
    413   // Add the \n.
    414   fprintf(file, "\\\n");
    415 }
    416 
    417 void BitVector::DumpDot(FILE* file, const char* prefix, bool last_entry) const {
    418   std::ostringstream buffer;
    419   DumpHelper(prefix, buffer);
    420   DumpDotHelper(last_entry, file, buffer);
    421 }
    422 
    423 void BitVector::DumpIndicesDot(FILE* file, const char* prefix, bool last_entry) const {
    424   std::ostringstream buffer;
    425   DumpIndicesHelper(prefix, buffer);
    426   DumpDotHelper(last_entry, file, buffer);
    427 }
    428 
    429 void BitVector::DumpIndicesHelper(const char* prefix, std::ostringstream& buffer) const {
    430   // Initialize it.
    431   if (prefix != nullptr) {
    432     buffer << prefix;
    433   }
    434 
    435   for (size_t i = 0; i < storage_size_ * kWordBits; i++) {
    436     if (IsBitSet(i)) {
    437       buffer << i << " ";
    438     }
    439   }
    440 }
    441 
    442 void BitVector::DumpHelper(const char* prefix, std::ostringstream& buffer) const {
    443   // Initialize it.
    444   if (prefix != nullptr) {
    445     buffer << prefix;
    446   }
    447 
    448   buffer << '(';
    449   for (size_t i = 0; i < storage_size_ * kWordBits; i++) {
    450     buffer << IsBitSet(i);
    451   }
    452   buffer << ')';
    453 }
    454 
    455 }  // namespace art
    456