| //===- llvm/ADT/SmallBitVector.h - 'Normally small' bit vectors -*- C++ -*-===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements the SmallBitVector class. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLVM_ADT_SMALLBITVECTOR_H | |
| #define LLVM_ADT_SMALLBITVECTOR_H | |
| #include "llvm/ADT/BitVector.h" | |
| #include "llvm/Support/MathExtras.h" | |
| #include <cassert> | |
| namespace llvm { | |
| /// SmallBitVector - This is a 'bitvector' (really, a variable-sized bit array), | |
| /// optimized for the case when the array is small. It contains one | |
| /// pointer-sized field, which is directly used as a plain collection of bits | |
| /// when possible, or as a pointer to a larger heap-allocated array when | |
| /// necessary. This allows normal "small" cases to be fast without losing | |
| /// generality for large inputs. | |
| /// | |
| class SmallBitVector { | |
| // TODO: In "large" mode, a pointer to a BitVector is used, leading to an | |
| // unnecessary level of indirection. It would be more efficient to use a | |
| // pointer to memory containing size, allocation size, and the array of bits. | |
| uintptr_t X; | |
| enum { | |
| // The number of bits in this class. | |
| NumBaseBits = sizeof(uintptr_t) * CHAR_BIT, | |
| // One bit is used to discriminate between small and large mode. The | |
| // remaining bits are used for the small-mode representation. | |
| SmallNumRawBits = NumBaseBits - 1, | |
| // A few more bits are used to store the size of the bit set in small mode. | |
| // Theoretically this is a ceil-log2. These bits are encoded in the most | |
| // significant bits of the raw bits. | |
| SmallNumSizeBits = (NumBaseBits == 32 ? 5 : | |
| NumBaseBits == 64 ? 6 : | |
| SmallNumRawBits), | |
| // The remaining bits are used to store the actual set in small mode. | |
| SmallNumDataBits = SmallNumRawBits - SmallNumSizeBits | |
| }; | |
| public: | |
| // Encapsulation of a single bit. | |
| class reference { | |
| SmallBitVector &TheVector; | |
| unsigned BitPos; | |
| public: | |
| reference(SmallBitVector &b, unsigned Idx) : TheVector(b), BitPos(Idx) {} | |
| reference& operator=(reference t) { | |
| *this = bool(t); | |
| return *this; | |
| } | |
| reference& operator=(bool t) { | |
| if (t) | |
| TheVector.set(BitPos); | |
| else | |
| TheVector.reset(BitPos); | |
| return *this; | |
| } | |
| operator bool() const { | |
| return const_cast<const SmallBitVector &>(TheVector).operator[](BitPos); | |
| } | |
| }; | |
| private: | |
| bool isSmall() const { | |
| return X & uintptr_t(1); | |
| } | |
| BitVector *getPointer() const { | |
| assert(!isSmall()); | |
| return reinterpret_cast<BitVector *>(X); | |
| } | |
| void switchToSmall(uintptr_t NewSmallBits, size_t NewSize) { | |
| X = 1; | |
| setSmallSize(NewSize); | |
| setSmallBits(NewSmallBits); | |
| } | |
| void switchToLarge(BitVector *BV) { | |
| X = reinterpret_cast<uintptr_t>(BV); | |
| assert(!isSmall() && "Tried to use an unaligned pointer"); | |
| } | |
| // Return all the bits used for the "small" representation; this includes | |
| // bits for the size as well as the element bits. | |
| uintptr_t getSmallRawBits() const { | |
| assert(isSmall()); | |
| return X >> 1; | |
| } | |
| void setSmallRawBits(uintptr_t NewRawBits) { | |
| assert(isSmall()); | |
| X = (NewRawBits << 1) | uintptr_t(1); | |
| } | |
| // Return the size. | |
| size_t getSmallSize() const { | |
| return getSmallRawBits() >> SmallNumDataBits; | |
| } | |
| void setSmallSize(size_t Size) { | |
| setSmallRawBits(getSmallBits() | (Size << SmallNumDataBits)); | |
| } | |
| // Return the element bits. | |
| uintptr_t getSmallBits() const { | |
| return getSmallRawBits() & ~(~uintptr_t(0) << getSmallSize()); | |
| } | |
| void setSmallBits(uintptr_t NewBits) { | |
| setSmallRawBits((NewBits & ~(~uintptr_t(0) << getSmallSize())) | | |
| (getSmallSize() << SmallNumDataBits)); | |
| } | |
| public: | |
| /// SmallBitVector default ctor - Creates an empty bitvector. | |
| SmallBitVector() : X(1) {} | |
| /// SmallBitVector ctor - Creates a bitvector of specified number of bits. All | |
| /// bits are initialized to the specified value. | |
| explicit SmallBitVector(unsigned s, bool t = false) { | |
| if (s <= SmallNumDataBits) | |
| switchToSmall(t ? ~uintptr_t(0) : 0, s); | |
| else | |
| switchToLarge(new BitVector(s, t)); | |
| } | |
| /// SmallBitVector copy ctor. | |
| SmallBitVector(const SmallBitVector &RHS) { | |
| if (RHS.isSmall()) | |
| X = RHS.X; | |
| else | |
| switchToLarge(new BitVector(*RHS.getPointer())); | |
| } | |
| ~SmallBitVector() { | |
| if (!isSmall()) | |
| delete getPointer(); | |
| } | |
| /// empty - Tests whether there are no bits in this bitvector. | |
| bool empty() const { | |
| return isSmall() ? getSmallSize() == 0 : getPointer()->empty(); | |
| } | |
| /// size - Returns the number of bits in this bitvector. | |
| size_t size() const { | |
| return isSmall() ? getSmallSize() : getPointer()->size(); | |
| } | |
| /// count - Returns the number of bits which are set. | |
| unsigned count() const { | |
| if (isSmall()) { | |
| uintptr_t Bits = getSmallBits(); | |
| if (sizeof(uintptr_t) * CHAR_BIT == 32) | |
| return CountPopulation_32(Bits); | |
| if (sizeof(uintptr_t) * CHAR_BIT == 64) | |
| return CountPopulation_64(Bits); | |
| assert(0 && "Unsupported!"); | |
| } | |
| return getPointer()->count(); | |
| } | |
| /// any - Returns true if any bit is set. | |
| bool any() const { | |
| if (isSmall()) | |
| return getSmallBits() != 0; | |
| return getPointer()->any(); | |
| } | |
| /// all - Returns true if all bits are set. | |
| bool all() const { | |
| if (isSmall()) | |
| return getSmallBits() == (uintptr_t(1) << getSmallSize()) - 1; | |
| return getPointer()->all(); | |
| } | |
| /// none - Returns true if none of the bits are set. | |
| bool none() const { | |
| if (isSmall()) | |
| return getSmallBits() == 0; | |
| return getPointer()->none(); | |
| } | |
| /// find_first - Returns the index of the first set bit, -1 if none | |
| /// of the bits are set. | |
| int find_first() const { | |
| if (isSmall()) { | |
| uintptr_t Bits = getSmallBits(); | |
| if (Bits == 0) | |
| return -1; | |
| if (sizeof(uintptr_t) * CHAR_BIT == 32) | |
| return CountTrailingZeros_32(Bits); | |
| if (sizeof(uintptr_t) * CHAR_BIT == 64) | |
| return CountTrailingZeros_64(Bits); | |
| assert(0 && "Unsupported!"); | |
| } | |
| return getPointer()->find_first(); | |
| } | |
| /// find_next - Returns the index of the next set bit following the | |
| /// "Prev" bit. Returns -1 if the next set bit is not found. | |
| int find_next(unsigned Prev) const { | |
| if (isSmall()) { | |
| uintptr_t Bits = getSmallBits(); | |
| // Mask off previous bits. | |
| Bits &= ~uintptr_t(0) << (Prev + 1); | |
| if (Bits == 0 || Prev + 1 >= getSmallSize()) | |
| return -1; | |
| if (sizeof(uintptr_t) * CHAR_BIT == 32) | |
| return CountTrailingZeros_32(Bits); | |
| if (sizeof(uintptr_t) * CHAR_BIT == 64) | |
| return CountTrailingZeros_64(Bits); | |
| assert(0 && "Unsupported!"); | |
| } | |
| return getPointer()->find_next(Prev); | |
| } | |
| /// clear - Clear all bits. | |
| void clear() { | |
| if (!isSmall()) | |
| delete getPointer(); | |
| switchToSmall(0, 0); | |
| } | |
| /// resize - Grow or shrink the bitvector. | |
| void resize(unsigned N, bool t = false) { | |
| if (!isSmall()) { | |
| getPointer()->resize(N, t); | |
| } else if (SmallNumDataBits >= N) { | |
| uintptr_t NewBits = t ? ~uintptr_t(0) << getSmallSize() : 0; | |
| setSmallSize(N); | |
| setSmallBits(NewBits | getSmallBits()); | |
| } else { | |
| BitVector *BV = new BitVector(N, t); | |
| uintptr_t OldBits = getSmallBits(); | |
| for (size_t i = 0, e = getSmallSize(); i != e; ++i) | |
| (*BV)[i] = (OldBits >> i) & 1; | |
| switchToLarge(BV); | |
| } | |
| } | |
| void reserve(unsigned N) { | |
| if (isSmall()) { | |
| if (N > SmallNumDataBits) { | |
| uintptr_t OldBits = getSmallRawBits(); | |
| size_t SmallSize = getSmallSize(); | |
| BitVector *BV = new BitVector(SmallSize); | |
| for (size_t i = 0; i < SmallSize; ++i) | |
| if ((OldBits >> i) & 1) | |
| BV->set(i); | |
| BV->reserve(N); | |
| switchToLarge(BV); | |
| } | |
| } else { | |
| getPointer()->reserve(N); | |
| } | |
| } | |
| // Set, reset, flip | |
| SmallBitVector &set() { | |
| if (isSmall()) | |
| setSmallBits(~uintptr_t(0)); | |
| else | |
| getPointer()->set(); | |
| return *this; | |
| } | |
| SmallBitVector &set(unsigned Idx) { | |
| if (isSmall()) | |
| setSmallBits(getSmallBits() | (uintptr_t(1) << Idx)); | |
| else | |
| getPointer()->set(Idx); | |
| return *this; | |
| } | |
| SmallBitVector &reset() { | |
| if (isSmall()) | |
| setSmallBits(0); | |
| else | |
| getPointer()->reset(); | |
| return *this; | |
| } | |
| SmallBitVector &reset(unsigned Idx) { | |
| if (isSmall()) | |
| setSmallBits(getSmallBits() & ~(uintptr_t(1) << Idx)); | |
| else | |
| getPointer()->reset(Idx); | |
| return *this; | |
| } | |
| SmallBitVector &flip() { | |
| if (isSmall()) | |
| setSmallBits(~getSmallBits()); | |
| else | |
| getPointer()->flip(); | |
| return *this; | |
| } | |
| SmallBitVector &flip(unsigned Idx) { | |
| if (isSmall()) | |
| setSmallBits(getSmallBits() ^ (uintptr_t(1) << Idx)); | |
| else | |
| getPointer()->flip(Idx); | |
| return *this; | |
| } | |
| // No argument flip. | |
| SmallBitVector operator~() const { | |
| return SmallBitVector(*this).flip(); | |
| } | |
| // Indexing. | |
| reference operator[](unsigned Idx) { | |
| assert(Idx < size() && "Out-of-bounds Bit access."); | |
| return reference(*this, Idx); | |
| } | |
| bool operator[](unsigned Idx) const { | |
| assert(Idx < size() && "Out-of-bounds Bit access."); | |
| if (isSmall()) | |
| return ((getSmallBits() >> Idx) & 1) != 0; | |
| return getPointer()->operator[](Idx); | |
| } | |
| bool test(unsigned Idx) const { | |
| return (*this)[Idx]; | |
| } | |
| // Comparison operators. | |
| bool operator==(const SmallBitVector &RHS) const { | |
| if (size() != RHS.size()) | |
| return false; | |
| if (isSmall()) | |
| return getSmallBits() == RHS.getSmallBits(); | |
| else | |
| return *getPointer() == *RHS.getPointer(); | |
| } | |
| bool operator!=(const SmallBitVector &RHS) const { | |
| return !(*this == RHS); | |
| } | |
| // Intersection, union, disjoint union. | |
| SmallBitVector &operator&=(const SmallBitVector &RHS) { | |
| resize(std::max(size(), RHS.size())); | |
| if (isSmall()) | |
| setSmallBits(getSmallBits() & RHS.getSmallBits()); | |
| else if (!RHS.isSmall()) | |
| getPointer()->operator&=(*RHS.getPointer()); | |
| else { | |
| SmallBitVector Copy = RHS; | |
| Copy.resize(size()); | |
| getPointer()->operator&=(*Copy.getPointer()); | |
| } | |
| return *this; | |
| } | |
| SmallBitVector &operator|=(const SmallBitVector &RHS) { | |
| resize(std::max(size(), RHS.size())); | |
| if (isSmall()) | |
| setSmallBits(getSmallBits() | RHS.getSmallBits()); | |
| else if (!RHS.isSmall()) | |
| getPointer()->operator|=(*RHS.getPointer()); | |
| else { | |
| SmallBitVector Copy = RHS; | |
| Copy.resize(size()); | |
| getPointer()->operator|=(*Copy.getPointer()); | |
| } | |
| return *this; | |
| } | |
| SmallBitVector &operator^=(const SmallBitVector &RHS) { | |
| resize(std::max(size(), RHS.size())); | |
| if (isSmall()) | |
| setSmallBits(getSmallBits() ^ RHS.getSmallBits()); | |
| else if (!RHS.isSmall()) | |
| getPointer()->operator^=(*RHS.getPointer()); | |
| else { | |
| SmallBitVector Copy = RHS; | |
| Copy.resize(size()); | |
| getPointer()->operator^=(*Copy.getPointer()); | |
| } | |
| return *this; | |
| } | |
| // Assignment operator. | |
| const SmallBitVector &operator=(const SmallBitVector &RHS) { | |
| if (isSmall()) { | |
| if (RHS.isSmall()) | |
| X = RHS.X; | |
| else | |
| switchToLarge(new BitVector(*RHS.getPointer())); | |
| } else { | |
| if (!RHS.isSmall()) | |
| *getPointer() = *RHS.getPointer(); | |
| else { | |
| delete getPointer(); | |
| X = RHS.X; | |
| } | |
| } | |
| return *this; | |
| } | |
| void swap(SmallBitVector &RHS) { | |
| std::swap(X, RHS.X); | |
| } | |
| }; | |
| inline SmallBitVector | |
| operator&(const SmallBitVector &LHS, const SmallBitVector &RHS) { | |
| SmallBitVector Result(LHS); | |
| Result &= RHS; | |
| return Result; | |
| } | |
| inline SmallBitVector | |
| operator|(const SmallBitVector &LHS, const SmallBitVector &RHS) { | |
| SmallBitVector Result(LHS); | |
| Result |= RHS; | |
| return Result; | |
| } | |
| inline SmallBitVector | |
| operator^(const SmallBitVector &LHS, const SmallBitVector &RHS) { | |
| SmallBitVector Result(LHS); | |
| Result ^= RHS; | |
| return Result; | |
| } | |
| } // End llvm namespace | |
| namespace std { | |
| /// Implement std::swap in terms of BitVector swap. | |
| inline void | |
| swap(llvm::SmallBitVector &LHS, llvm::SmallBitVector &RHS) { | |
| LHS.swap(RHS); | |
| } | |
| } | |
| #endif |