mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
ae65e281f3
to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
893 lines
26 KiB
C++
893 lines
26 KiB
C++
//===- llvm/ADT/SparseBitVector.h - Efficient Sparse BitVector --*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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/Support/ErrorHandling.h"
|
|
#include "llvm/Support/MathExtras.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <cassert>
|
|
#include <climits>
|
|
#include <cstring>
|
|
#include <iterator>
|
|
#include <list>
|
|
|
|
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:
|
|
using BitWord = unsigned long;
|
|
using size_type = unsigned;
|
|
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];
|
|
|
|
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));
|
|
}
|
|
|
|
size_type count() const {
|
|
unsigned NumBits = 0;
|
|
for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i)
|
|
NumBits += countPopulation(Bits[i]);
|
|
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)
|
|
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
|
llvm_unreachable("Illegal empty element");
|
|
}
|
|
|
|
/// find_last - Returns the index of the last set bit.
|
|
int find_last() const {
|
|
for (unsigned I = 0; I < BITWORDS_PER_ELEMENT; ++I) {
|
|
unsigned Idx = BITWORDS_PER_ELEMENT - I - 1;
|
|
if (Bits[Idx] != 0)
|
|
return Idx * BITWORD_SIZE + BITWORD_SIZE -
|
|
countLeadingZeros(Bits[Idx]) - 1;
|
|
}
|
|
llvm_unreachable("Illegal empty element");
|
|
}
|
|
|
|
/// 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 &= ~0UL << BitPos;
|
|
|
|
if (Copy != 0)
|
|
return WordPos * BITWORD_SIZE + countTrailingZeros(Copy);
|
|
|
|
// Check subsequent words.
|
|
for (unsigned i = WordPos+1; i < BITWORDS_PER_ELEMENT; ++i)
|
|
if (Bits[i] != 0)
|
|
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
|
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;
|
|
}
|
|
};
|
|
|
|
template <unsigned ElementSize = 128>
|
|
class SparseBitVector {
|
|
using ElementList = std::list<SparseBitVectorElement<ElementSize>>;
|
|
using ElementListIter = typename ElementList::iterator;
|
|
using ElementListConstIter = typename ElementList::const_iterator;
|
|
enum {
|
|
BITWORD_SIZE = SparseBitVectorElement<ElementSize>::BITWORD_SIZE
|
|
};
|
|
|
|
ElementList Elements;
|
|
// Pointer to our current Element. This has no visible effect on the external
|
|
// state of a SparseBitVector, it's just used to improve performance in the
|
|
// common case of testing/modifying bits with similar indices.
|
|
mutable ElementListIter CurrElementIter;
|
|
|
|
// This is like std::lower_bound, except we do linear searching from the
|
|
// current position.
|
|
ElementListIter FindLowerBoundImpl(unsigned ElementIndex) const {
|
|
|
|
// We cache a non-const iterator so we're forced to resort to const_cast to
|
|
// get the begin/end in the case where 'this' is const. To avoid duplication
|
|
// of code with the only difference being whether the const cast is present
|
|
// 'this' is always const in this particular function and we sort out the
|
|
// difference in FindLowerBound and FindLowerBoundConst.
|
|
ElementListIter Begin =
|
|
const_cast<SparseBitVector<ElementSize> *>(this)->Elements.begin();
|
|
ElementListIter End =
|
|
const_cast<SparseBitVector<ElementSize> *>(this)->Elements.end();
|
|
|
|
if (Elements.empty()) {
|
|
CurrElementIter = Begin;
|
|
return CurrElementIter;
|
|
}
|
|
|
|
// Make sure our current iterator is valid.
|
|
if (CurrElementIter == 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 != Begin
|
|
&& ElementIter->index() > ElementIndex)
|
|
--ElementIter;
|
|
} else {
|
|
while (ElementIter != End &&
|
|
ElementIter->index() < ElementIndex)
|
|
++ElementIter;
|
|
}
|
|
CurrElementIter = ElementIter;
|
|
return ElementIter;
|
|
}
|
|
ElementListConstIter FindLowerBoundConst(unsigned ElementIndex) const {
|
|
return FindLowerBoundImpl(ElementIndex);
|
|
}
|
|
ElementListIter FindLowerBound(unsigned ElementIndex) {
|
|
return FindLowerBoundImpl(ElementIndex);
|
|
}
|
|
|
|
// 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 = nullptr;
|
|
|
|
// 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:
|
|
SparseBitVectorIterator() = default;
|
|
|
|
SparseBitVectorIterator(const SparseBitVector<ElementSize> *RHS,
|
|
bool end = false):BitVector(RHS) {
|
|
Iter = BitVector->Elements.begin();
|
|
BitNumber = 0;
|
|
Bits = 0;
|
|
WordNumber = ~0;
|
|
AtEnd = end;
|
|
AdvanceToFirstNonZero();
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
};
|
|
|
|
public:
|
|
using iterator = SparseBitVectorIterator;
|
|
|
|
SparseBitVector() : Elements(), CurrElementIter(Elements.begin()) {}
|
|
|
|
SparseBitVector(const SparseBitVector &RHS)
|
|
: Elements(RHS.Elements), CurrElementIter(Elements.begin()) {}
|
|
SparseBitVector(SparseBitVector &&RHS)
|
|
: Elements(std::move(RHS.Elements)), CurrElementIter(Elements.begin()) {}
|
|
|
|
// Clear.
|
|
void clear() {
|
|
Elements.clear();
|
|
}
|
|
|
|
// Assignment
|
|
SparseBitVector& operator=(const SparseBitVector& RHS) {
|
|
if (this == &RHS)
|
|
return *this;
|
|
|
|
Elements = RHS.Elements;
|
|
CurrElementIter = Elements.begin();
|
|
return *this;
|
|
}
|
|
SparseBitVector &operator=(SparseBitVector &&RHS) {
|
|
Elements = std::move(RHS.Elements);
|
|
CurrElementIter = Elements.begin();
|
|
return *this;
|
|
}
|
|
|
|
// Test, Reset, and Set a bit in the bitmap.
|
|
bool test(unsigned Idx) const {
|
|
if (Elements.empty())
|
|
return false;
|
|
|
|
unsigned ElementIndex = Idx / ElementSize;
|
|
ElementListConstIter ElementIter = FindLowerBoundConst(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;
|
|
ElementListIter ElementIter;
|
|
if (Elements.empty()) {
|
|
ElementIter = Elements.emplace(Elements.end(), ElementIndex);
|
|
} else {
|
|
ElementIter = FindLowerBound(ElementIndex);
|
|
|
|
if (ElementIter == Elements.end() ||
|
|
ElementIter->index() != 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;
|
|
ElementIter = Elements.emplace(ElementIter, ElementIndex);
|
|
}
|
|
}
|
|
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) {
|
|
if (this == &RHS)
|
|
return false;
|
|
|
|
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, *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) {
|
|
if (this == &RHS)
|
|
return false;
|
|
|
|
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);
|
|
changed = true;
|
|
}
|
|
}
|
|
if (Iter1 != Elements.end()) {
|
|
Elements.erase(Iter1, Elements.end());
|
|
changed = true;
|
|
}
|
|
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) {
|
|
if (this == &RHS) {
|
|
if (!empty()) {
|
|
clear();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (this == &RHS1) {
|
|
intersectWithComplement(RHS2);
|
|
return;
|
|
} else if (this == &RHS2) {
|
|
SparseBitVector RHS2Copy(RHS2);
|
|
intersectWithComplement(RHS1, RHS2Copy);
|
|
return;
|
|
}
|
|
|
|
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;
|
|
Elements.emplace_back(Iter1->index());
|
|
Elements.back().intersectWithComplement(*Iter1, *Iter2, BecameZero);
|
|
if (BecameZero)
|
|
Elements.pop_back();
|
|
++Iter1;
|
|
++Iter2;
|
|
} else {
|
|
Elements.push_back(*Iter1++);
|
|
}
|
|
}
|
|
|
|
// copy the remaining elements
|
|
std::copy(Iter1, RHS1.Elements.end(), std::back_inserter(Elements));
|
|
}
|
|
|
|
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 the last set bit in the bitmap. Return -1 if no bits are set.
|
|
int find_last() const {
|
|
if (Elements.empty())
|
|
return -1;
|
|
const SparseBitVectorElement<ElementSize> &Last = *(Elements.rbegin());
|
|
return (Last.index() * ElementSize) + Last.find_last();
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
};
|
|
|
|
// 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 // LLVM_ADT_SPARSEBITVECTOR_H
|