| //===- llvm/ADT/SparseBitVector.h - Efficient Sparse BitVector -*- C++ -*- ===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the SparseBitVector class. See the doxygen comment for |
| // SparseBitVector for more details on the algorithm used. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_ADT_SPARSEBITVECTOR_H |
| #define LLVM_ADT_SPARSEBITVECTOR_H |
| |
| #include "llvm/ADT/ilist.h" |
| #include "llvm/ADT/ilist_node.h" |
| #include "llvm/Support/DataTypes.h" |
| #include "llvm/Support/MathExtras.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <cassert> |
| #include <climits> |
| #include <cstring> |
| |
| namespace llvm { |
| |
| /// SparseBitVector is an implementation of a bitvector that is sparse by only |
| /// storing the elements that have non-zero bits set. In order to make this |
| /// fast for the most common cases, SparseBitVector is implemented as a linked |
| /// list of SparseBitVectorElements. We maintain a pointer to the last |
| /// SparseBitVectorElement accessed (in the form of a list iterator), in order |
| /// to make multiple in-order test/set constant time after the first one is |
| /// executed. Note that using vectors to store SparseBitVectorElement's does |
| /// not work out very well because it causes insertion in the middle to take |
| /// enormous amounts of time with a large amount of bits. Other structures that |
| /// have better worst cases for insertion in the middle (various balanced trees, |
| /// etc) do not perform as well in practice as a linked list with this iterator |
| /// kept up to date. They are also significantly more memory intensive. |
| |
| |
| template <unsigned ElementSize = 128> |
| struct SparseBitVectorElement |
| : public ilist_node<SparseBitVectorElement<ElementSize> > { |
| public: |
| typedef unsigned long BitWord; |
| enum { |
| BITWORD_SIZE = sizeof(BitWord) * CHAR_BIT, |
| BITWORDS_PER_ELEMENT = (ElementSize + BITWORD_SIZE - 1) / BITWORD_SIZE, |
| BITS_PER_ELEMENT = ElementSize |
| }; |
| |
| private: |
| // Index of Element in terms of where first bit starts. |
| unsigned ElementIndex; |
| BitWord Bits[BITWORDS_PER_ELEMENT]; |
| // Needed for sentinels |
| friend struct ilist_sentinel_traits<SparseBitVectorElement>; |
| SparseBitVectorElement() { |
| ElementIndex = ~0U; |
| memset(&Bits[0], 0, sizeof (BitWord) * BITWORDS_PER_ELEMENT); |
| } |
| |
| public: |
| explicit SparseBitVectorElement(unsigned Idx) { |
| ElementIndex = Idx; |
| memset(&Bits[0], 0, sizeof (BitWord) * BITWORDS_PER_ELEMENT); |
| } |
| |
| // Comparison. |
| bool operator==(const SparseBitVectorElement &RHS) const { |
| if (ElementIndex != RHS.ElementIndex) |
| return false; |
| for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) |
| if (Bits[i] != RHS.Bits[i]) |
| return false; |
| return true; |
| } |
| |
| bool operator!=(const SparseBitVectorElement &RHS) const { |
| return !(*this == RHS); |
| } |
| |
| // Return the bits that make up word Idx in our element. |
| BitWord word(unsigned Idx) const { |
| assert (Idx < BITWORDS_PER_ELEMENT); |
| return Bits[Idx]; |
| } |
| |
| unsigned index() const { |
| return ElementIndex; |
| } |
| |
| bool empty() const { |
| for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) |
| if (Bits[i]) |
| return false; |
| return true; |
| } |
| |
| void set(unsigned Idx) { |
| Bits[Idx / BITWORD_SIZE] |= 1L << (Idx % BITWORD_SIZE); |
| } |
| |
| bool test_and_set (unsigned Idx) { |
| bool old = test(Idx); |
| if (!old) { |
| set(Idx); |
| return true; |
| } |
| return false; |
| } |
| |
| void reset(unsigned Idx) { |
| Bits[Idx / BITWORD_SIZE] &= ~(1L << (Idx % BITWORD_SIZE)); |
| } |
| |
| bool test(unsigned Idx) const { |
| return Bits[Idx / BITWORD_SIZE] & (1L << (Idx % BITWORD_SIZE)); |
| } |
| |
| unsigned count() const { |
| unsigned NumBits = 0; |
| for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) |
| if (sizeof(BitWord) == 4) |
| NumBits += CountPopulation_32(Bits[i]); |
| else if (sizeof(BitWord) == 8) |
| NumBits += CountPopulation_64(Bits[i]); |
| else |
| assert(0 && "Unsupported!"); |
| return NumBits; |
| } |
| |
| /// find_first - Returns the index of the first set bit. |
| int find_first() const { |
| for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) |
| if (Bits[i] != 0) { |
| if (sizeof(BitWord) == 4) |
| return i * BITWORD_SIZE + CountTrailingZeros_32(Bits[i]); |
| else if (sizeof(BitWord) == 8) |
| return i * BITWORD_SIZE + CountTrailingZeros_64(Bits[i]); |
| else |
| assert(0 && "Unsupported!"); |
| } |
| assert(0 && "Illegal empty element"); |
| return 0; // Not reached |
| } |
| |
| /// find_next - Returns the index of the next set bit starting from the |
| /// "Curr" bit. Returns -1 if the next set bit is not found. |
| int find_next(unsigned Curr) const { |
| if (Curr >= BITS_PER_ELEMENT) |
| return -1; |
| |
| unsigned WordPos = Curr / BITWORD_SIZE; |
| unsigned BitPos = Curr % BITWORD_SIZE; |
| BitWord Copy = Bits[WordPos]; |
| assert (WordPos <= BITWORDS_PER_ELEMENT |
| && "Word Position outside of element"); |
| |
| // Mask off previous bits. |
| Copy &= ~0L << BitPos; |
| |
| if (Copy != 0) { |
| if (sizeof(BitWord) == 4) |
| return WordPos * BITWORD_SIZE + CountTrailingZeros_32(Copy); |
| else if (sizeof(BitWord) == 8) |
| return WordPos * BITWORD_SIZE + CountTrailingZeros_64(Copy); |
| else |
| assert(0 && "Unsupported!"); |
| } |
| |
| // Check subsequent words. |
| for (unsigned i = WordPos+1; i < BITWORDS_PER_ELEMENT; ++i) |
| if (Bits[i] != 0) { |
| if (sizeof(BitWord) == 4) |
| return i * BITWORD_SIZE + CountTrailingZeros_32(Bits[i]); |
| else if (sizeof(BitWord) == 8) |
| return i * BITWORD_SIZE + CountTrailingZeros_64(Bits[i]); |
| else |
| assert(0 && "Unsupported!"); |
| } |
| return -1; |
| } |
| |
| // Union this element with RHS and return true if this one changed. |
| bool unionWith(const SparseBitVectorElement &RHS) { |
| bool changed = false; |
| for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) { |
| BitWord old = changed ? 0 : Bits[i]; |
| |
| Bits[i] |= RHS.Bits[i]; |
| if (!changed && old != Bits[i]) |
| changed = true; |
| } |
| return changed; |
| } |
| |
| // Return true if we have any bits in common with RHS |
| bool intersects(const SparseBitVectorElement &RHS) const { |
| for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) { |
| if (RHS.Bits[i] & Bits[i]) |
| return true; |
| } |
| return false; |
| } |
| |
| // Intersect this Element with RHS and return true if this one changed. |
| // BecameZero is set to true if this element became all-zero bits. |
| bool intersectWith(const SparseBitVectorElement &RHS, |
| bool &BecameZero) { |
| bool changed = false; |
| bool allzero = true; |
| |
| BecameZero = false; |
| for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) { |
| BitWord old = changed ? 0 : Bits[i]; |
| |
| Bits[i] &= RHS.Bits[i]; |
| if (Bits[i] != 0) |
| allzero = false; |
| |
| if (!changed && old != Bits[i]) |
| changed = true; |
| } |
| BecameZero = allzero; |
| return changed; |
| } |
| // Intersect this Element with the complement of RHS and return true if this |
| // one changed. BecameZero is set to true if this element became all-zero |
| // bits. |
| bool intersectWithComplement(const SparseBitVectorElement &RHS, |
| bool &BecameZero) { |
| bool changed = false; |
| bool allzero = true; |
| |
| BecameZero = false; |
| for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) { |
| BitWord old = changed ? 0 : Bits[i]; |
| |
| Bits[i] &= ~RHS.Bits[i]; |
| if (Bits[i] != 0) |
| allzero = false; |
| |
| if (!changed && old != Bits[i]) |
| changed = true; |
| } |
| BecameZero = allzero; |
| return changed; |
| } |
| // Three argument version of intersectWithComplement that intersects |
| // RHS1 & ~RHS2 into this element |
| void intersectWithComplement(const SparseBitVectorElement &RHS1, |
| const SparseBitVectorElement &RHS2, |
| bool &BecameZero) { |
| bool allzero = true; |
| |
| BecameZero = false; |
| for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) { |
| Bits[i] = RHS1.Bits[i] & ~RHS2.Bits[i]; |
| if (Bits[i] != 0) |
| allzero = false; |
| } |
| BecameZero = allzero; |
| } |
| |
| // Get a hash value for this element; |
| uint64_t getHashValue() const { |
| uint64_t HashVal = 0; |
| for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) { |
| HashVal ^= Bits[i]; |
| } |
| return HashVal; |
| } |
| }; |
| |
| template <unsigned ElementSize = 128> |
| class SparseBitVector { |
| typedef ilist<SparseBitVectorElement<ElementSize> > ElementList; |
| typedef typename ElementList::iterator ElementListIter; |
| typedef typename ElementList::const_iterator ElementListConstIter; |
| enum { |
| BITWORD_SIZE = SparseBitVectorElement<ElementSize>::BITWORD_SIZE |
| }; |
| |
| // Pointer to our current Element. |
| ElementListIter CurrElementIter; |
| ElementList Elements; |
| |
| // This is like std::lower_bound, except we do linear searching from the |
| // current position. |
| ElementListIter FindLowerBound(unsigned ElementIndex) { |
| |
| if (Elements.empty()) { |
| CurrElementIter = Elements.begin(); |
| return Elements.begin(); |
| } |
| |
| // Make sure our current iterator is valid. |
| if (CurrElementIter == Elements.end()) |
| --CurrElementIter; |
| |
| // Search from our current iterator, either backwards or forwards, |
| // depending on what element we are looking for. |
| ElementListIter ElementIter = CurrElementIter; |
| if (CurrElementIter->index() == ElementIndex) { |
| return ElementIter; |
| } else if (CurrElementIter->index() > ElementIndex) { |
| while (ElementIter != Elements.begin() |
| && ElementIter->index() > ElementIndex) |
| --ElementIter; |
| } else { |
| while (ElementIter != Elements.end() && |
| ElementIter->index() < ElementIndex) |
| ++ElementIter; |
| } |
| CurrElementIter = ElementIter; |
| return ElementIter; |
| } |
| |
| // Iterator to walk set bits in the bitmap. This iterator is a lot uglier |
| // than it would be, in order to be efficient. |
| class SparseBitVectorIterator { |
| private: |
| bool AtEnd; |
| |
| const SparseBitVector<ElementSize> *BitVector; |
| |
| // Current element inside of bitmap. |
| ElementListConstIter Iter; |
| |
| // Current bit number inside of our bitmap. |
| unsigned BitNumber; |
| |
| // Current word number inside of our element. |
| unsigned WordNumber; |
| |
| // Current bits from the element. |
| typename SparseBitVectorElement<ElementSize>::BitWord Bits; |
| |
| // Move our iterator to the first non-zero bit in the bitmap. |
| void AdvanceToFirstNonZero() { |
| if (AtEnd) |
| return; |
| if (BitVector->Elements.empty()) { |
| AtEnd = true; |
| return; |
| } |
| Iter = BitVector->Elements.begin(); |
| BitNumber = Iter->index() * ElementSize; |
| unsigned BitPos = Iter->find_first(); |
| BitNumber += BitPos; |
| WordNumber = (BitNumber % ElementSize) / BITWORD_SIZE; |
| Bits = Iter->word(WordNumber); |
| Bits >>= BitPos % BITWORD_SIZE; |
| } |
| |
| // Move our iterator to the next non-zero bit. |
| void AdvanceToNextNonZero() { |
| if (AtEnd) |
| return; |
| |
| while (Bits && !(Bits & 1)) { |
| Bits >>= 1; |
| BitNumber += 1; |
| } |
| |
| // See if we ran out of Bits in this word. |
| if (!Bits) { |
| int NextSetBitNumber = Iter->find_next(BitNumber % ElementSize) ; |
| // If we ran out of set bits in this element, move to next element. |
| if (NextSetBitNumber == -1 || (BitNumber % ElementSize == 0)) { |
| ++Iter; |
| WordNumber = 0; |
| |
| // We may run out of elements in the bitmap. |
| if (Iter == BitVector->Elements.end()) { |
| AtEnd = true; |
| return; |
| } |
| // Set up for next non zero word in bitmap. |
| BitNumber = Iter->index() * ElementSize; |
| NextSetBitNumber = Iter->find_first(); |
| BitNumber += NextSetBitNumber; |
| WordNumber = (BitNumber % ElementSize) / BITWORD_SIZE; |
| Bits = Iter->word(WordNumber); |
| Bits >>= NextSetBitNumber % BITWORD_SIZE; |
| } else { |
| WordNumber = (NextSetBitNumber % ElementSize) / BITWORD_SIZE; |
| Bits = Iter->word(WordNumber); |
| Bits >>= NextSetBitNumber % BITWORD_SIZE; |
| BitNumber = Iter->index() * ElementSize; |
| BitNumber += NextSetBitNumber; |
| } |
| } |
| } |
| public: |
| // Preincrement. |
| inline SparseBitVectorIterator& operator++() { |
| ++BitNumber; |
| Bits >>= 1; |
| AdvanceToNextNonZero(); |
| return *this; |
| } |
| |
| // Postincrement. |
| inline SparseBitVectorIterator operator++(int) { |
| SparseBitVectorIterator tmp = *this; |
| ++*this; |
| return tmp; |
| } |
| |
| // Return the current set bit number. |
| unsigned operator*() const { |
| return BitNumber; |
| } |
| |
| bool operator==(const SparseBitVectorIterator &RHS) const { |
| // If they are both at the end, ignore the rest of the fields. |
| if (AtEnd && RHS.AtEnd) |
| return true; |
| // Otherwise they are the same if they have the same bit number and |
| // bitmap. |
| return AtEnd == RHS.AtEnd && RHS.BitNumber == BitNumber; |
| } |
| bool operator!=(const SparseBitVectorIterator &RHS) const { |
| return !(*this == RHS); |
| } |
| SparseBitVectorIterator(): BitVector(NULL) { |
| } |
| |
| |
| SparseBitVectorIterator(const SparseBitVector<ElementSize> *RHS, |
| bool end = false):BitVector(RHS) { |
| Iter = BitVector->Elements.begin(); |
| BitNumber = 0; |
| Bits = 0; |
| WordNumber = ~0; |
| AtEnd = end; |
| AdvanceToFirstNonZero(); |
| } |
| }; |
| public: |
| typedef SparseBitVectorIterator iterator; |
| |
| SparseBitVector () { |
| CurrElementIter = Elements.begin (); |
| } |
| |
| ~SparseBitVector() { |
| } |
| |
| // SparseBitVector copy ctor. |
| SparseBitVector(const SparseBitVector &RHS) { |
| ElementListConstIter ElementIter = RHS.Elements.begin(); |
| while (ElementIter != RHS.Elements.end()) { |
| Elements.push_back(SparseBitVectorElement<ElementSize>(*ElementIter)); |
| ++ElementIter; |
| } |
| |
| CurrElementIter = Elements.begin (); |
| } |
| |
| // Clear. |
| void clear() { |
| Elements.clear(); |
| } |
| |
| // Assignment |
| SparseBitVector& operator=(const SparseBitVector& RHS) { |
| Elements.clear(); |
| |
| ElementListConstIter ElementIter = RHS.Elements.begin(); |
| while (ElementIter != RHS.Elements.end()) { |
| Elements.push_back(SparseBitVectorElement<ElementSize>(*ElementIter)); |
| ++ElementIter; |
| } |
| |
| CurrElementIter = Elements.begin (); |
| |
| return *this; |
| } |
| |
| // Test, Reset, and Set a bit in the bitmap. |
| bool test(unsigned Idx) { |
| if (Elements.empty()) |
| return false; |
| |
| unsigned ElementIndex = Idx / ElementSize; |
| ElementListIter ElementIter = FindLowerBound(ElementIndex); |
| |
| // If we can't find an element that is supposed to contain this bit, there |
| // is nothing more to do. |
| if (ElementIter == Elements.end() || |
| ElementIter->index() != ElementIndex) |
| return false; |
| return ElementIter->test(Idx % ElementSize); |
| } |
| |
| void reset(unsigned Idx) { |
| if (Elements.empty()) |
| return; |
| |
| unsigned ElementIndex = Idx / ElementSize; |
| ElementListIter ElementIter = FindLowerBound(ElementIndex); |
| |
| // If we can't find an element that is supposed to contain this bit, there |
| // is nothing more to do. |
| if (ElementIter == Elements.end() || |
| ElementIter->index() != ElementIndex) |
| return; |
| ElementIter->reset(Idx % ElementSize); |
| |
| // When the element is zeroed out, delete it. |
| if (ElementIter->empty()) { |
| ++CurrElementIter; |
| Elements.erase(ElementIter); |
| } |
| } |
| |
| void set(unsigned Idx) { |
| unsigned ElementIndex = Idx / ElementSize; |
| SparseBitVectorElement<ElementSize> *Element; |
| ElementListIter ElementIter; |
| if (Elements.empty()) { |
| Element = new SparseBitVectorElement<ElementSize>(ElementIndex); |
| ElementIter = Elements.insert(Elements.end(), Element); |
| |
| } else { |
| ElementIter = FindLowerBound(ElementIndex); |
| |
| if (ElementIter == Elements.end() || |
| ElementIter->index() != ElementIndex) { |
| Element = new SparseBitVectorElement<ElementSize>(ElementIndex); |
| // We may have hit the beginning of our SparseBitVector, in which case, |
| // we may need to insert right after this element, which requires moving |
| // the current iterator forward one, because insert does insert before. |
| if (ElementIter != Elements.end() && |
| ElementIter->index() < ElementIndex) |
| ElementIter = Elements.insert(++ElementIter, Element); |
| else |
| ElementIter = Elements.insert(ElementIter, Element); |
| } |
| } |
| CurrElementIter = ElementIter; |
| |
| ElementIter->set(Idx % ElementSize); |
| } |
| |
| bool test_and_set (unsigned Idx) { |
| bool old = test(Idx); |
| if (!old) { |
| set(Idx); |
| return true; |
| } |
| return false; |
| } |
| |
| bool operator!=(const SparseBitVector &RHS) const { |
| return !(*this == RHS); |
| } |
| |
| bool operator==(const SparseBitVector &RHS) const { |
| ElementListConstIter Iter1 = Elements.begin(); |
| ElementListConstIter Iter2 = RHS.Elements.begin(); |
| |
| for (; Iter1 != Elements.end() && Iter2 != RHS.Elements.end(); |
| ++Iter1, ++Iter2) { |
| if (*Iter1 != *Iter2) |
| return false; |
| } |
| return Iter1 == Elements.end() && Iter2 == RHS.Elements.end(); |
| } |
| |
| // Union our bitmap with the RHS and return true if we changed. |
| bool operator|=(const SparseBitVector &RHS) { |
| bool changed = false; |
| ElementListIter Iter1 = Elements.begin(); |
| ElementListConstIter Iter2 = RHS.Elements.begin(); |
| |
| // If RHS is empty, we are done |
| if (RHS.Elements.empty()) |
| return false; |
| |
| while (Iter2 != RHS.Elements.end()) { |
| if (Iter1 == Elements.end() || Iter1->index() > Iter2->index()) { |
| Elements.insert(Iter1, |
| new SparseBitVectorElement<ElementSize>(*Iter2)); |
| ++Iter2; |
| changed = true; |
| } else if (Iter1->index() == Iter2->index()) { |
| changed |= Iter1->unionWith(*Iter2); |
| ++Iter1; |
| ++Iter2; |
| } else { |
| ++Iter1; |
| } |
| } |
| CurrElementIter = Elements.begin(); |
| return changed; |
| } |
| |
| // Intersect our bitmap with the RHS and return true if ours changed. |
| bool operator&=(const SparseBitVector &RHS) { |
| bool changed = false; |
| ElementListIter Iter1 = Elements.begin(); |
| ElementListConstIter Iter2 = RHS.Elements.begin(); |
| |
| // Check if both bitmaps are empty. |
| if (Elements.empty() && RHS.Elements.empty()) |
| return false; |
| |
| // Loop through, intersecting as we go, erasing elements when necessary. |
| while (Iter2 != RHS.Elements.end()) { |
| if (Iter1 == Elements.end()) { |
| CurrElementIter = Elements.begin(); |
| return changed; |
| } |
| |
| if (Iter1->index() > Iter2->index()) { |
| ++Iter2; |
| } else if (Iter1->index() == Iter2->index()) { |
| bool BecameZero; |
| changed |= Iter1->intersectWith(*Iter2, BecameZero); |
| if (BecameZero) { |
| ElementListIter IterTmp = Iter1; |
| ++Iter1; |
| Elements.erase(IterTmp); |
| } else { |
| ++Iter1; |
| } |
| ++Iter2; |
| } else { |
| ElementListIter IterTmp = Iter1; |
| ++Iter1; |
| Elements.erase(IterTmp); |
| } |
| } |
| Elements.erase(Iter1, Elements.end()); |
| CurrElementIter = Elements.begin(); |
| return changed; |
| } |
| |
| // Intersect our bitmap with the complement of the RHS and return true |
| // if ours changed. |
| bool intersectWithComplement(const SparseBitVector &RHS) { |
| bool changed = false; |
| ElementListIter Iter1 = Elements.begin(); |
| ElementListConstIter Iter2 = RHS.Elements.begin(); |
| |
| // If either our bitmap or RHS is empty, we are done |
| if (Elements.empty() || RHS.Elements.empty()) |
| return false; |
| |
| // Loop through, intersecting as we go, erasing elements when necessary. |
| while (Iter2 != RHS.Elements.end()) { |
| if (Iter1 == Elements.end()) { |
| CurrElementIter = Elements.begin(); |
| return changed; |
| } |
| |
| if (Iter1->index() > Iter2->index()) { |
| ++Iter2; |
| } else if (Iter1->index() == Iter2->index()) { |
| bool BecameZero; |
| changed |= Iter1->intersectWithComplement(*Iter2, BecameZero); |
| if (BecameZero) { |
| ElementListIter IterTmp = Iter1; |
| ++Iter1; |
| Elements.erase(IterTmp); |
| } else { |
| ++Iter1; |
| } |
| ++Iter2; |
| } else { |
| ++Iter1; |
| } |
| } |
| CurrElementIter = Elements.begin(); |
| return changed; |
| } |
| |
| bool intersectWithComplement(const SparseBitVector<ElementSize> *RHS) const { |
| return intersectWithComplement(*RHS); |
| } |
| |
| |
| // Three argument version of intersectWithComplement. |
| // Result of RHS1 & ~RHS2 is stored into this bitmap. |
| void intersectWithComplement(const SparseBitVector<ElementSize> &RHS1, |
| const SparseBitVector<ElementSize> &RHS2) |
| { |
| Elements.clear(); |
| CurrElementIter = Elements.begin(); |
| ElementListConstIter Iter1 = RHS1.Elements.begin(); |
| ElementListConstIter Iter2 = RHS2.Elements.begin(); |
| |
| // If RHS1 is empty, we are done |
| // If RHS2 is empty, we still have to copy RHS1 |
| if (RHS1.Elements.empty()) |
| return; |
| |
| // Loop through, intersecting as we go, erasing elements when necessary. |
| while (Iter2 != RHS2.Elements.end()) { |
| if (Iter1 == RHS1.Elements.end()) |
| return; |
| |
| if (Iter1->index() > Iter2->index()) { |
| ++Iter2; |
| } else if (Iter1->index() == Iter2->index()) { |
| bool BecameZero = false; |
| SparseBitVectorElement<ElementSize> *NewElement = |
| new SparseBitVectorElement<ElementSize>(Iter1->index()); |
| NewElement->intersectWithComplement(*Iter1, *Iter2, BecameZero); |
| if (!BecameZero) { |
| Elements.push_back(NewElement); |
| } |
| else |
| delete NewElement; |
| ++Iter1; |
| ++Iter2; |
| } else { |
| SparseBitVectorElement<ElementSize> *NewElement = |
| new SparseBitVectorElement<ElementSize>(*Iter1); |
| Elements.push_back(NewElement); |
| ++Iter1; |
| } |
| } |
| |
| // copy the remaining elements |
| while (Iter1 != RHS1.Elements.end()) { |
| SparseBitVectorElement<ElementSize> *NewElement = |
| new SparseBitVectorElement<ElementSize>(*Iter1); |
| Elements.push_back(NewElement); |
| ++Iter1; |
| } |
| |
| return; |
| } |
| |
| void intersectWithComplement(const SparseBitVector<ElementSize> *RHS1, |
| const SparseBitVector<ElementSize> *RHS2) { |
| intersectWithComplement(*RHS1, *RHS2); |
| } |
| |
| bool intersects(const SparseBitVector<ElementSize> *RHS) const { |
| return intersects(*RHS); |
| } |
| |
| // Return true if we share any bits in common with RHS |
| bool intersects(const SparseBitVector<ElementSize> &RHS) const { |
| ElementListConstIter Iter1 = Elements.begin(); |
| ElementListConstIter Iter2 = RHS.Elements.begin(); |
| |
| // Check if both bitmaps are empty. |
| if (Elements.empty() && RHS.Elements.empty()) |
| return false; |
| |
| // Loop through, intersecting stopping when we hit bits in common. |
| while (Iter2 != RHS.Elements.end()) { |
| if (Iter1 == Elements.end()) |
| return false; |
| |
| if (Iter1->index() > Iter2->index()) { |
| ++Iter2; |
| } else if (Iter1->index() == Iter2->index()) { |
| if (Iter1->intersects(*Iter2)) |
| return true; |
| ++Iter1; |
| ++Iter2; |
| } else { |
| ++Iter1; |
| } |
| } |
| return false; |
| } |
| |
| // Return true iff all bits set in this SparseBitVector are |
| // also set in RHS. |
| bool contains(const SparseBitVector<ElementSize> &RHS) const { |
| SparseBitVector<ElementSize> Result(*this); |
| Result &= RHS; |
| return (Result == RHS); |
| } |
| |
| // Return the first set bit in the bitmap. Return -1 if no bits are set. |
| int find_first() const { |
| if (Elements.empty()) |
| return -1; |
| const SparseBitVectorElement<ElementSize> &First = *(Elements.begin()); |
| return (First.index() * ElementSize) + First.find_first(); |
| } |
| |
| // Return true if the SparseBitVector is empty |
| bool empty() const { |
| return Elements.empty(); |
| } |
| |
| unsigned count() const { |
| unsigned BitCount = 0; |
| for (ElementListConstIter Iter = Elements.begin(); |
| Iter != Elements.end(); |
| ++Iter) |
| BitCount += Iter->count(); |
| |
| return BitCount; |
| } |
| iterator begin() const { |
| return iterator(this); |
| } |
| |
| iterator end() const { |
| return iterator(this, true); |
| } |
| |
| // Get a hash value for this bitmap. |
| uint64_t getHashValue() const { |
| uint64_t HashVal = 0; |
| for (ElementListConstIter Iter = Elements.begin(); |
| Iter != Elements.end(); |
| ++Iter) { |
| HashVal ^= Iter->index(); |
| HashVal ^= Iter->getHashValue(); |
| } |
| return HashVal; |
| } |
| }; |
| |
| // Convenience functions to allow Or and And without dereferencing in the user |
| // code. |
| |
| template <unsigned ElementSize> |
| inline bool operator |=(SparseBitVector<ElementSize> &LHS, |
| const SparseBitVector<ElementSize> *RHS) { |
| return LHS |= *RHS; |
| } |
| |
| template <unsigned ElementSize> |
| inline bool operator |=(SparseBitVector<ElementSize> *LHS, |
| const SparseBitVector<ElementSize> &RHS) { |
| return LHS->operator|=(RHS); |
| } |
| |
| template <unsigned ElementSize> |
| inline bool operator &=(SparseBitVector<ElementSize> *LHS, |
| const SparseBitVector<ElementSize> &RHS) { |
| return LHS->operator&=(RHS); |
| } |
| |
| template <unsigned ElementSize> |
| inline bool operator &=(SparseBitVector<ElementSize> &LHS, |
| const SparseBitVector<ElementSize> *RHS) { |
| return LHS &= *RHS; |
| } |
| |
| // Convenience functions for infix union, intersection, difference operators. |
| |
| template <unsigned ElementSize> |
| inline SparseBitVector<ElementSize> |
| operator|(const SparseBitVector<ElementSize> &LHS, |
| const SparseBitVector<ElementSize> &RHS) { |
| SparseBitVector<ElementSize> Result(LHS); |
| Result |= RHS; |
| return Result; |
| } |
| |
| template <unsigned ElementSize> |
| inline SparseBitVector<ElementSize> |
| operator&(const SparseBitVector<ElementSize> &LHS, |
| const SparseBitVector<ElementSize> &RHS) { |
| SparseBitVector<ElementSize> Result(LHS); |
| Result &= RHS; |
| return Result; |
| } |
| |
| template <unsigned ElementSize> |
| inline SparseBitVector<ElementSize> |
| operator-(const SparseBitVector<ElementSize> &LHS, |
| const SparseBitVector<ElementSize> &RHS) { |
| SparseBitVector<ElementSize> Result; |
| Result.intersectWithComplement(LHS, RHS); |
| return Result; |
| } |
| |
| |
| |
| |
| // Dump a SparseBitVector to a stream |
| template <unsigned ElementSize> |
| void dump(const SparseBitVector<ElementSize> &LHS, raw_ostream &out) { |
| out << "["; |
| |
| typename SparseBitVector<ElementSize>::iterator bi = LHS.begin(), |
| be = LHS.end(); |
| if (bi != be) { |
| out << *bi; |
| for (++bi; bi != be; ++bi) { |
| out << " " << *bi; |
| } |
| } |
| out << "]\n"; |
| } |
| } // end namespace llvm |
| |
| #endif |