Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2013 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 #ifndef ART_RUNTIME_BASE_BIT_VECTOR_H_
     18 #define ART_RUNTIME_BASE_BIT_VECTOR_H_
     19 
     20 #include <stdint.h>
     21 #include <stddef.h>
     22 
     23 #include "allocator.h"
     24 #include "base/logging.h"
     25 #include "utils.h"
     26 
     27 namespace art {
     28 
     29 /*
     30  * Expanding bitmap, used for tracking resources.  Bits are numbered starting
     31  * from zero.  All operations on a BitVector are unsynchronized.
     32  */
     33 class BitVector {
     34   public:
     35     class IndexContainer;
     36 
     37     /**
     38      * @brief Convenient iterator across the indexes of the BitVector's set bits.
     39      *
     40      * @details IndexIterator is a Forward iterator (C++11: 24.2.5) from the lowest
     41      * to the highest index of the BitVector's set bits. Instances can be retrieved
     42      * only through BitVector::Indexes() which returns an IndexContainer wrapper
     43      * object with begin() and end() suitable for range-based loops:
     44      *   for (uint32_t idx : bit_vector.Indexes()) {
     45      *     // Use idx.
     46      *   }
     47      */
     48     class IndexIterator
     49         : std::iterator<std::forward_iterator_tag, uint32_t, ptrdiff_t, void, uint32_t> {
     50       public:
     51         bool operator==(const IndexIterator& other) const {
     52           DCHECK(bit_storage_ == other.bit_storage_);
     53           DCHECK_EQ(storage_size_, other.storage_size_);
     54           return bit_index_ == other.bit_index_;
     55         }
     56 
     57         bool operator!=(const IndexIterator& other) const {
     58           return !(*this == other);
     59         }
     60 
     61         int operator*() const {
     62           DCHECK_LT(bit_index_, BitSize());
     63           return bit_index_;
     64         }
     65 
     66         IndexIterator& operator++() {
     67           DCHECK_LT(bit_index_, BitSize());
     68           bit_index_ = FindIndex(bit_index_ + 1u);
     69           return *this;
     70         }
     71 
     72         IndexIterator operator++(int) {
     73           IndexIterator result(*this);
     74           ++*this;
     75           return result;
     76         }
     77 
     78         // Helper function to check for end without comparing with bit_vector.Indexes().end().
     79         bool Done() const {
     80           return bit_index_ == BitSize();
     81         }
     82 
     83       private:
     84         struct begin_tag { };
     85         struct end_tag { };
     86 
     87         IndexIterator(const BitVector* bit_vector, begin_tag)
     88           : bit_storage_(bit_vector->GetRawStorage()),
     89             storage_size_(bit_vector->storage_size_),
     90             bit_index_(FindIndex(0u)) { }
     91 
     92         IndexIterator(const BitVector* bit_vector, end_tag)
     93           : bit_storage_(bit_vector->GetRawStorage()),
     94             storage_size_(bit_vector->storage_size_),
     95             bit_index_(BitSize()) { }
     96 
     97         uint32_t BitSize() const {
     98           return storage_size_ * kWordBits;
     99         }
    100 
    101         uint32_t FindIndex(uint32_t start_index) const {
    102           DCHECK_LE(start_index, BitSize());
    103           uint32_t word_index = start_index / kWordBits;
    104           if (UNLIKELY(word_index == storage_size_)) {
    105             return start_index;
    106           }
    107           uint32_t word = bit_storage_[word_index];
    108           // Mask out any bits in the first word we've already considered.
    109           word &= static_cast<uint32_t>(-1) << (start_index & 0x1f);
    110           while (word == 0u) {
    111             ++word_index;
    112             if (UNLIKELY(word_index == storage_size_)) {
    113               return BitSize();
    114             }
    115             word = bit_storage_[word_index];
    116           }
    117           return word_index * 32u + CTZ(word);
    118         }
    119 
    120         const uint32_t* const bit_storage_;
    121         const uint32_t storage_size_;  // Size of vector in words.
    122         uint32_t bit_index_;           // Current index (size in bits).
    123 
    124         friend class BitVector::IndexContainer;
    125     };
    126 
    127     /**
    128      * @brief BitVector wrapper class for iteration across indexes of set bits.
    129      */
    130     class IndexContainer {
    131      public:
    132       explicit IndexContainer(const BitVector* bit_vector) : bit_vector_(bit_vector) { }
    133 
    134       IndexIterator begin() const {
    135         return IndexIterator(bit_vector_, IndexIterator::begin_tag());
    136       }
    137 
    138       IndexIterator end() const {
    139         return IndexIterator(bit_vector_, IndexIterator::end_tag());
    140       }
    141 
    142      private:
    143       const BitVector* const bit_vector_;
    144     };
    145 
    146     BitVector(uint32_t start_bits,
    147               bool expandable,
    148               Allocator* allocator,
    149               uint32_t storage_size = 0,
    150               uint32_t* storage = nullptr);
    151 
    152     virtual ~BitVector();
    153 
    154     void SetBit(uint32_t num);
    155     void ClearBit(uint32_t num);
    156     bool IsBitSet(uint32_t num) const;
    157     void ClearAllBits();
    158     void SetInitialBits(uint32_t num_bits);
    159 
    160     void Copy(const BitVector* src);
    161     void Intersect(const BitVector* src2);
    162     bool Union(const BitVector* src);
    163 
    164     // Set bits of union_with that are not in not_in.
    165     bool UnionIfNotIn(const BitVector* union_with, const BitVector* not_in);
    166 
    167     void Subtract(const BitVector* src);
    168     // Are we equal to another bit vector?  Note: expandability attributes must also match.
    169     bool Equal(const BitVector* src) {
    170       return (storage_size_ == src->GetStorageSize()) &&
    171         (expandable_ == src->IsExpandable()) &&
    172         (memcmp(storage_, src->GetRawStorage(), storage_size_ * sizeof(uint32_t)) == 0);
    173     }
    174 
    175     /**
    176      * @brief Are all the bits set the same?
    177      * @details expandability and size can differ as long as the same bits are set.
    178      */
    179     bool SameBitsSet(const BitVector *src);
    180 
    181     uint32_t NumSetBits() const;
    182 
    183     // Number of bits set in range [0, end).
    184     uint32_t NumSetBits(uint32_t end) const;
    185 
    186     IndexContainer Indexes() const {
    187       return IndexContainer(this);
    188     }
    189 
    190     uint32_t GetStorageSize() const { return storage_size_; }
    191     bool IsExpandable() const { return expandable_; }
    192     uint32_t GetRawStorageWord(size_t idx) const { return storage_[idx]; }
    193     uint32_t* GetRawStorage() { return storage_; }
    194     const uint32_t* GetRawStorage() const { return storage_; }
    195     size_t GetSizeOf() const { return storage_size_ * kWordBytes; }
    196 
    197     /**
    198      * @return the highest bit set, -1 if none are set
    199      */
    200     int GetHighestBitSet() const;
    201 
    202     // Is bit set in storage. (No range check.)
    203     static bool IsBitSet(const uint32_t* storage, uint32_t num);
    204     // Number of bits set in range [0, end) in storage. (No range check.)
    205     static uint32_t NumSetBits(const uint32_t* storage, uint32_t end);
    206 
    207     bool EnsureSizeAndClear(unsigned int num);
    208 
    209     void Dump(std::ostream& os, const char* prefix) const;
    210 
    211     /**
    212      * @brief last_entry is this the last entry for the dot dumping
    213      * @details if not, a "|" is appended to the dump.
    214      */
    215     void DumpDot(FILE* file, const char* prefix, bool last_entry = false) const;
    216 
    217     /**
    218      * @brief last_entry is this the last entry for the dot dumping
    219      * @details if not, a "|" is appended to the dump.
    220      */
    221     void DumpIndicesDot(FILE* file, const char* prefix, bool last_entry = false) const;
    222 
    223   protected:
    224     /**
    225      * @brief Dump the bitvector into buffer in a 00101..01 format.
    226      * @param buffer the ostringstream used to dump the bitvector into.
    227      */
    228     void DumpHelper(const char* prefix, std::ostringstream& buffer) const;
    229 
    230     /**
    231      * @brief Dump the bitvector in a 1 2 5 8 format, where the numbers are the bit set.
    232      * @param buffer the ostringstream used to dump the bitvector into.
    233      */
    234     void DumpIndicesHelper(const char* prefix, std::ostringstream& buffer) const;
    235 
    236     /**
    237      * @brief Wrapper to perform the bitvector dumping with the .dot format.
    238      * @param buffer the ostringstream used to dump the bitvector into.
    239      */
    240     void DumpDotHelper(bool last_entry, FILE* file, std::ostringstream& buffer) const;
    241 
    242   private:
    243     static constexpr uint32_t kWordBytes = sizeof(uint32_t);
    244     static constexpr uint32_t kWordBits = kWordBytes * 8;
    245 
    246     Allocator* const allocator_;
    247     const bool expandable_;         // expand bitmap if we run out?
    248     uint32_t   storage_size_;       // current size, in 32-bit words.
    249     uint32_t*  storage_;
    250 };
    251 
    252 
    253 }  // namespace art
    254 
    255 #endif  // ART_RUNTIME_BASE_BIT_VECTOR_H_
    256