• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_LIBARTBASE_BASE_BIT_VECTOR_H_
18 #define ART_LIBARTBASE_BASE_BIT_VECTOR_H_
19 
20 #include <stdint.h>
21 
22 #include <algorithm>
23 #include <iterator>
24 #include <limits>
25 
26 #include "bit_utils.h"
27 #include "globals.h"
28 #include "logging.h"
29 
30 namespace art {
31 
32 class Allocator;
33 
34 // A bit vector view encapsulating externally-provided fixed-size storage for bits.
35 //
36 // The size in bits does not need to specify whole number of storage words but the view
37 // is intended to work only on the specified number of bits. Single-bit functions
38 // `SetBit()`, `ClearBit()` and `IsBitSet()` verify the passed index with `DCHECK()`
39 // and do not care about trailing bits in the last storage word, if any. Multi-bit
40 // functions require that the trailing bits are cleared on entry, except for functions
41 // `ClearAllBits()` and `SetInitialBits()` that are used for storage initialization
42 // and clear the trailing bits, if any.
43 template <typename StorageType = size_t>
44 class BitVectorView {
45  public:
46   using WordType = StorageType;
47   static_assert(std::numeric_limits<WordType>::is_integer);
48   static_assert(!std::numeric_limits<WordType>::is_signed);
49   static constexpr size_t kWordBits = BitSizeOf<WordType>();
50   static_assert(IsPowerOfTwo(kWordBits));
51 
BitsToWords(size_t bits)52   static constexpr size_t BitsToWords(size_t bits) {
53     return (bits + /* round up */ (kWordBits - 1)) / kWordBits;
54   }
55 
56   // Construct an empty `BitVectorView`.
BitVectorView()57   constexpr BitVectorView()
58       : storage_(nullptr), size_in_bits_(0u) {}
59 
60   // Construct a `BitVectorView` referencing the provided backing storage.
BitVectorView(WordType * storage,size_t size_in_bits)61   constexpr BitVectorView(WordType* storage, size_t size_in_bits)
62       : storage_(storage), size_in_bits_(size_in_bits) {}
63 
64   // The `BitVectorView<>` can be copied and passed to functions by value.
65   // The new copy shall reference the same underlying data, similarly to `std::string_view`.
66   BitVectorView(const BitVectorView& src) = default;
67 
68   // Implicit conversion to a view with constant storage.
69   template <typename ST,
70             typename = std::enable_if_t<std::is_const_v<StorageType> &&
71                                         std::is_same_v<ST, std::remove_const_t<StorageType>>>>
BitVectorView(const BitVectorView<ST> & src)72   BitVectorView(const BitVectorView<ST>& src)
73       : storage_(src.storage_), size_in_bits_(src.size_in_bits_) {}
74 
75   // Get the size of the bit vector view in bits.
SizeInBits()76   constexpr size_t SizeInBits() const {
77     return size_in_bits_;
78   }
79 
80   // Get the size of the bit vector view in storage words.
SizeInWords()81   constexpr size_t SizeInWords() const {
82     return BitsToWords(SizeInBits());
83   }
84 
85   // Mark the specified bit as "set".
SetBit(size_t index)86   void SetBit(size_t index) {
87     DCHECK_LT(index, size_in_bits_);
88     storage_[WordIndex(index)] |= BitMask(index);
89   }
90 
91   // Mark the specified bit as "clear".
ClearBit(size_t index)92   void ClearBit(size_t index) {
93     DCHECK_LT(index, size_in_bits_);
94     storage_[WordIndex(index)] &= ~BitMask(index);
95   }
96 
97   // Determine whether or not the specified bit is set.
IsBitSet(size_t index)98   constexpr bool IsBitSet(size_t index) const {
99     DCHECK_LT(index, size_in_bits_);
100     return (storage_[WordIndex(index)] & BitMask(index)) != 0u;
101   }
102 
103   // Mark all bits as "clear".
104   void ClearAllBits();
105 
106   // Mark specified number of initial bits as "set" and clear all bits after that.
107   void SetInitialBits(uint32_t num_bits);
108 
109   // Return true if there are any bits set, false otherwise.
IsAnyBitSet()110   bool IsAnyBitSet() const {
111     DCheckTrailingBitsClear();
112     return std::any_of(storage_, storage_ + SizeInWords(), [](WordType w) { return w != 0u; });
113   }
114 
115   // Union with another bit vector view of the same size.
116   bool Union(BitVectorView<const StorageType> union_with);
117 
118   // Union with the bits in `union_with` but not in `not_in`. All views must have the same size.
119   bool UnionIfNotIn(BitVectorView<const StorageType> union_with,
120                     BitVectorView<const StorageType> not_in);
121 
122   // `BitVectorView` wrapper class for iteration across indexes of set bits.
123   class IndexContainerImpl;
124   using IndexContainer = BitVectorView<const StorageType>::IndexContainerImpl;
125 
126   IndexContainer Indexes() const;
127 
128  private:
WordIndex(size_t index)129   static constexpr size_t WordIndex(size_t index) {
130     return index >> WhichPowerOf2(kWordBits);
131   }
132 
BitMask(size_t index)133   static constexpr WordType BitMask(size_t index) {
134     return static_cast<WordType>(1) << (index % kWordBits);
135   }
136 
DCheckTrailingBitsClear()137   constexpr void DCheckTrailingBitsClear() const {
138     DCHECK_IMPLIES(SizeInBits() % kWordBits != 0u,
139                    (storage_[WordIndex(SizeInBits())] & ~(BitMask(SizeInBits()) - 1u)) == 0u);
140   }
141 
142   WordType* storage_;
143   size_t size_in_bits_;
144 
145   template <typename ST> friend class BitVectorIndexIterator;
146   template <typename ST> friend class BitVectorView;
147 };
148 
149 /**
150  * @brief Convenient iterator across the indexes of the bits in `BitVector` or `BitVectorView<>`.
151  *
152  * @details BitVectorIndexIterator is a Forward iterator (C++11: 24.2.5) from the lowest
153  * to the highest index of the BitVector's set bits. Instances can be retrieved
154  * only through `BitVector{,View}::Indexes()` which return an index container wrapper
155  * object with begin() and end() suitable for range-based loops:
156  *   for (uint32_t idx : bit_vector.Indexes()) {
157  *     // Use idx.
158  *   }
159  */
160 template <typename StorageType>
161 class BitVectorIndexIterator {
162   static_assert(std::is_const_v<StorageType>);
163 
164  public:
165   using iterator_category = std::forward_iterator_tag;
166   using value_type = size_t;
167   using difference_type = ptrdiff_t;
168   using pointer = void;
169   using reference = void;
170 
171   bool operator==(const BitVectorIndexIterator& other) const;
172   bool operator!=(const BitVectorIndexIterator& other) const;
173 
174   size_t operator*() const;
175 
176   BitVectorIndexIterator& operator++();
177   BitVectorIndexIterator operator++(int);
178 
179   // Helper function to check for end without comparing with bit_vector.Indexes().end().
Done()180   bool Done() const {
181     return bit_index_ == bit_vector_view_.SizeInBits();
182   }
183 
184  private:
185   struct begin_tag { };
186   struct end_tag { };
187 
188   BitVectorIndexIterator(BitVectorView<StorageType> bit_vector_view, begin_tag);
189   BitVectorIndexIterator(BitVectorView<StorageType> bit_vector_view, end_tag);
190 
191   size_t FindIndex(size_t start_index) const;
192 
193   static constexpr size_t kWordBits = BitVectorView<StorageType>::kWordBits;
194 
195   const BitVectorView<StorageType> bit_vector_view_;
196   size_t bit_index_;  // Current index (size in bits).
197 
198   template <typename ST>
199   friend class BitVectorView;
200 };
201 
202 /*
203  * Expanding bitmap. Bits are numbered starting from zero. All operations on a BitVector are
204  * unsynchronized. New BitVectors are not necessarily zeroed out. If the used allocator doesn't do
205  * clear the vector (e.g. ScopedArenaAllocator), the responsibility of clearing it relies on the
206  * caller (e.g. ArenaBitVector).
207  */
208 class BitVector {
209  public:
210   static constexpr uint32_t kWordBytes = sizeof(uint32_t);
211   static constexpr uint32_t kWordBits = kWordBytes * 8;
212 
213   using IndexContainer = BitVectorView<uint32_t>::IndexContainer;
214 
215   // MoveConstructible but not MoveAssignable, CopyConstructible or CopyAssignable.
216 
217   BitVector(const BitVector& other) = delete;
218   BitVector& operator=(const BitVector& other) = delete;
219 
BitVector(BitVector && other)220   BitVector(BitVector&& other) noexcept
221       : storage_(other.storage_),
222         storage_size_(other.storage_size_),
223         allocator_(other.allocator_),
224         expandable_(other.expandable_) {
225     other.storage_ = nullptr;
226     other.storage_size_ = 0u;
227   }
228 
229   BitVector(uint32_t start_bits,
230             bool expandable,
231             Allocator* allocator);
232 
233   BitVector(bool expandable,
234             Allocator* allocator,
235             uint32_t storage_size,
236             uint32_t* storage);
237 
238   BitVector(const BitVector& src,
239             bool expandable,
240             Allocator* allocator);
241 
242   virtual ~BitVector();
243 
244   // The number of words necessary to encode bits.
BitsToWords(uint32_t bits)245   static constexpr uint32_t BitsToWords(uint32_t bits) {
246     return RoundUp(bits, kWordBits) / kWordBits;
247   }
248 
249   // Mark the specified bit as "set".
SetBit(uint32_t idx)250   void SetBit(uint32_t idx) {
251     /*
252      * TUNING: this could have pathologically bad growth/expand behavior.  Make sure we're
253      * not using it badly or change resize mechanism.
254      */
255     if (idx >= storage_size_ * kWordBits) {
256       EnsureSize(idx);
257     }
258     AsView().SetBit(idx);
259   }
260 
261   // Mark the specified bit as "clear".
ClearBit(uint32_t idx)262   void ClearBit(uint32_t idx) {
263     // If the index is over the size, we don't have to do anything, it is cleared.
264     if (idx < storage_size_ * kWordBits) {
265       // Otherwise, go ahead and clear it.
266       AsView().ClearBit(idx);
267     }
268   }
269 
270   // Determine whether or not the specified bit is set.
IsBitSet(uint32_t idx)271   bool IsBitSet(uint32_t idx) const {
272     // If the index is over the size, whether it is expandable or not, this bit does not exist:
273     // thus it is not set.
274     return (idx < (storage_size_ * kWordBits)) && AsView().IsBitSet(idx);
275   }
276 
277   // Mark all bits as "clear".
278   void ClearAllBits();
279 
280   // Mark specified number of bits as "set". Cannot set all bits like ClearAll since there might
281   // be unused bits - setting those to one will confuse the iterator.
282   void SetInitialBits(uint32_t num_bits);
283 
284   void Copy(const BitVector* src);
285 
286   // Intersect with another bit vector.
287   void Intersect(const BitVector* src2);
288 
289   // Union with another bit vector.
290   bool Union(const BitVector* src);
291 
292   // Set bits of union_with that are not in not_in.
293   bool UnionIfNotIn(const BitVector* union_with, const BitVector* not_in);
294 
295   void Subtract(const BitVector* src);
296 
297   // Are we equal to another bit vector?  Note: expandability attributes must also match.
298   bool Equal(const BitVector* src) const;
299 
300   /**
301    * @brief Are all the bits set the same?
302    * @details expandability and size can differ as long as the same bits are set.
303    */
304   bool SameBitsSet(const BitVector *src) const;
305 
306   bool IsSubsetOf(const BitVector *other) const;
307 
308   // Count the number of bits that are set.
309   uint32_t NumSetBits() const;
310 
311   // Count the number of bits that are set in range [0, end).
312   uint32_t NumSetBits(uint32_t end) const;
313 
314   IndexContainer Indexes() const;
315 
GetStorageSize()316   uint32_t GetStorageSize() const {
317     return storage_size_;
318   }
319 
IsExpandable()320   bool IsExpandable() const {
321     return expandable_;
322   }
323 
GetRawStorageWord(size_t idx)324   uint32_t GetRawStorageWord(size_t idx) const {
325     return storage_[idx];
326   }
327 
GetRawStorage()328   uint32_t* GetRawStorage() {
329     return storage_;
330   }
331 
GetRawStorage()332   const uint32_t* GetRawStorage() const {
333     return storage_;
334   }
335 
GetSizeOf()336   size_t GetSizeOf() const {
337     return storage_size_ * kWordBytes;
338   }
339 
GetBitSizeOf()340   size_t GetBitSizeOf() const {
341     return storage_size_ * kWordBits;
342   }
343 
344   /**
345    * @return the highest bit set, -1 if none are set
346    */
347   int GetHighestBitSet() const;
348 
349   /**
350    * @return true if there are any bits set, false otherwise.
351    */
IsAnyBitSet()352   bool IsAnyBitSet() const {
353     return AsView().IsAnyBitSet();
354   }
355 
356   // Minimum number of bits required to store this vector, 0 if none are set.
GetNumberOfBits()357   size_t GetNumberOfBits() const {
358     return GetHighestBitSet() + 1;
359   }
360 
361   // Is bit set in storage. (No range check.)
IsBitSet(const uint32_t * storage,uint32_t idx)362   static bool IsBitSet(const uint32_t* storage, uint32_t idx) {
363     return (storage[WordIndex(idx)] & BitMask(idx)) != 0;
364   }
365 
366   // Number of bits set in range [0, end) in storage. (No range check.)
367   static uint32_t NumSetBits(const uint32_t* storage, uint32_t end);
368 
369   // Fill given memory region with the contents of the vector and zero padding.
CopyTo(void * dst,size_t len)370   void CopyTo(void* dst, size_t len) const {
371     DCHECK_LE(static_cast<size_t>(GetHighestBitSet() + 1), len * kBitsPerByte);
372     size_t vec_len = GetSizeOf();
373     if (vec_len < len) {
374       void* dst_padding = reinterpret_cast<uint8_t*>(dst) + vec_len;
375       memcpy(dst, storage_, vec_len);
376       memset(dst_padding, 0, len - vec_len);
377     } else {
378       memcpy(dst, storage_, len);
379     }
380   }
381 
382   void Dump(std::ostream& os, const char* prefix) const;
383 
384   Allocator* GetAllocator() const;
385 
386  private:
387   /**
388    * @brief Dump the bitvector into buffer in a 00101..01 format.
389    * @param buffer the ostringstream used to dump the bitvector into.
390    */
391   void DumpHelper(const char* prefix, std::ostringstream& buffer) const;
392 
AsView()393   BitVectorView<uint32_t> AsView() {
394     return {storage_, storage_size_ * kWordBits};
395   }
396 
AsView()397   BitVectorView<const uint32_t> AsView() const {
398     return {storage_, storage_size_ * kWordBits};
399   }
400 
401   // Ensure there is space for a bit at idx.
402   void EnsureSize(uint32_t idx);
403 
404   // The index of the word within storage.
WordIndex(uint32_t idx)405   static constexpr uint32_t WordIndex(uint32_t idx) {
406     return idx >> 5;
407   }
408 
409   // A bit mask to extract the bit for the given index.
BitMask(uint32_t idx)410   static constexpr uint32_t BitMask(uint32_t idx) {
411     return 1 << (idx & 0x1f);
412   }
413 
414   uint32_t*  storage_;            // The storage for the bit vector.
415   uint32_t   storage_size_;       // Current size, in 32-bit words.
416   Allocator* const allocator_;    // Allocator if expandable.
417   const bool expandable_;         // Should the bitmap expand if too small?
418 };
419 
420 }  // namespace art
421 
422 #endif  // ART_LIBARTBASE_BASE_BIT_VECTOR_H_
423