1*da0073e9SAndroid Build Coastguard Worker //===- llvm/ADT/SparseBitVector.h - Efficient Sparse BitVector --*- C++ -*-===// 2*da0073e9SAndroid Build Coastguard Worker // 3*da0073e9SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*da0073e9SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information. 5*da0073e9SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*da0073e9SAndroid Build Coastguard Worker // 7*da0073e9SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 8*da0073e9SAndroid Build Coastguard Worker // 9*da0073e9SAndroid Build Coastguard Worker // This file defines the SparseBitVector class. See the doxygen comment for 10*da0073e9SAndroid Build Coastguard Worker // SparseBitVector for more details on the algorithm used. 11*da0073e9SAndroid Build Coastguard Worker // 12*da0073e9SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 13*da0073e9SAndroid Build Coastguard Worker 14*da0073e9SAndroid Build Coastguard Worker #pragma once 15*da0073e9SAndroid Build Coastguard Worker #include <c10/macros/Macros.h> 16*da0073e9SAndroid Build Coastguard Worker #include <c10/util/llvmMathExtras.h> 17*da0073e9SAndroid Build Coastguard Worker #include <array> 18*da0073e9SAndroid Build Coastguard Worker #include <cassert> 19*da0073e9SAndroid Build Coastguard Worker #include <climits> 20*da0073e9SAndroid Build Coastguard Worker #include <iterator> 21*da0073e9SAndroid Build Coastguard Worker #include <list> 22*da0073e9SAndroid Build Coastguard Worker #include <ostream> 23*da0073e9SAndroid Build Coastguard Worker 24*da0073e9SAndroid Build Coastguard Worker namespace c10 { 25*da0073e9SAndroid Build Coastguard Worker 26*da0073e9SAndroid Build Coastguard Worker /// SparseBitVector is an implementation of a bitvector that is sparse by only 27*da0073e9SAndroid Build Coastguard Worker /// storing the elements that have non-zero bits set. In order to make this 28*da0073e9SAndroid Build Coastguard Worker /// fast for the most common cases, SparseBitVector is implemented as a linked 29*da0073e9SAndroid Build Coastguard Worker /// list of SparseBitVectorElements. We maintain a pointer to the last 30*da0073e9SAndroid Build Coastguard Worker /// SparseBitVectorElement accessed (in the form of a list iterator), in order 31*da0073e9SAndroid Build Coastguard Worker /// to make multiple in-order test/set constant time after the first one is 32*da0073e9SAndroid Build Coastguard Worker /// executed. Note that using vectors to store SparseBitVectorElement's does 33*da0073e9SAndroid Build Coastguard Worker /// not work out very well because it causes insertion in the middle to take 34*da0073e9SAndroid Build Coastguard Worker /// enormous amounts of time with a large amount of bits. Other structures that 35*da0073e9SAndroid Build Coastguard Worker /// have better worst cases for insertion in the middle (various balanced trees, 36*da0073e9SAndroid Build Coastguard Worker /// etc) do not perform as well in practice as a linked list with this iterator 37*da0073e9SAndroid Build Coastguard Worker /// kept up to date. They are also significantly more memory intensive. 38*da0073e9SAndroid Build Coastguard Worker 39*da0073e9SAndroid Build Coastguard Worker template <unsigned ElementSize = 128> 40*da0073e9SAndroid Build Coastguard Worker struct SparseBitVectorElement { 41*da0073e9SAndroid Build Coastguard Worker public: 42*da0073e9SAndroid Build Coastguard Worker using BitWord = unsigned long; 43*da0073e9SAndroid Build Coastguard Worker using size_type = unsigned; 44*da0073e9SAndroid Build Coastguard Worker enum { 45*da0073e9SAndroid Build Coastguard Worker BITWORD_SIZE = sizeof(BitWord) * CHAR_BIT, 46*da0073e9SAndroid Build Coastguard Worker BITWORDS_PER_ELEMENT = (ElementSize + BITWORD_SIZE - 1) / BITWORD_SIZE, 47*da0073e9SAndroid Build Coastguard Worker BITS_PER_ELEMENT = ElementSize 48*da0073e9SAndroid Build Coastguard Worker }; 49*da0073e9SAndroid Build Coastguard Worker 50*da0073e9SAndroid Build Coastguard Worker private: 51*da0073e9SAndroid Build Coastguard Worker // Index of Element in terms of where first bit starts. 52*da0073e9SAndroid Build Coastguard Worker unsigned ElementIndex; 53*da0073e9SAndroid Build Coastguard Worker std::array<BitWord, BITWORDS_PER_ELEMENT> Bits{}; 54*da0073e9SAndroid Build Coastguard Worker SparseBitVectorElementSparseBitVectorElement55*da0073e9SAndroid Build Coastguard Worker SparseBitVectorElement() : ElementIndex(~0U) {} 56*da0073e9SAndroid Build Coastguard Worker 57*da0073e9SAndroid Build Coastguard Worker public: SparseBitVectorElementSparseBitVectorElement58*da0073e9SAndroid Build Coastguard Worker explicit SparseBitVectorElement(unsigned Idx) : ElementIndex(Idx) {} 59*da0073e9SAndroid Build Coastguard Worker 60*da0073e9SAndroid Build Coastguard Worker // Comparison. 61*da0073e9SAndroid Build Coastguard Worker bool operator==(const SparseBitVectorElement& RHS) const { 62*da0073e9SAndroid Build Coastguard Worker if (ElementIndex != RHS.ElementIndex) 63*da0073e9SAndroid Build Coastguard Worker return false; 64*da0073e9SAndroid Build Coastguard Worker for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) 65*da0073e9SAndroid Build Coastguard Worker if (Bits[i] != RHS.Bits[i]) 66*da0073e9SAndroid Build Coastguard Worker return false; 67*da0073e9SAndroid Build Coastguard Worker return true; 68*da0073e9SAndroid Build Coastguard Worker } 69*da0073e9SAndroid Build Coastguard Worker 70*da0073e9SAndroid Build Coastguard Worker bool operator!=(const SparseBitVectorElement& RHS) const { 71*da0073e9SAndroid Build Coastguard Worker return !(*this == RHS); 72*da0073e9SAndroid Build Coastguard Worker } 73*da0073e9SAndroid Build Coastguard Worker 74*da0073e9SAndroid Build Coastguard Worker // Return the bits that make up word Idx in our element. wordSparseBitVectorElement75*da0073e9SAndroid Build Coastguard Worker BitWord word(unsigned Idx) const { 76*da0073e9SAndroid Build Coastguard Worker assert(Idx < BITWORDS_PER_ELEMENT); 77*da0073e9SAndroid Build Coastguard Worker return Bits[Idx]; 78*da0073e9SAndroid Build Coastguard Worker } 79*da0073e9SAndroid Build Coastguard Worker indexSparseBitVectorElement80*da0073e9SAndroid Build Coastguard Worker unsigned index() const { 81*da0073e9SAndroid Build Coastguard Worker return ElementIndex; 82*da0073e9SAndroid Build Coastguard Worker } 83*da0073e9SAndroid Build Coastguard Worker emptySparseBitVectorElement84*da0073e9SAndroid Build Coastguard Worker bool empty() const { 85*da0073e9SAndroid Build Coastguard Worker for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) 86*da0073e9SAndroid Build Coastguard Worker if (Bits[i]) 87*da0073e9SAndroid Build Coastguard Worker return false; 88*da0073e9SAndroid Build Coastguard Worker return true; 89*da0073e9SAndroid Build Coastguard Worker } 90*da0073e9SAndroid Build Coastguard Worker setSparseBitVectorElement91*da0073e9SAndroid Build Coastguard Worker void set(unsigned Idx) { 92*da0073e9SAndroid Build Coastguard Worker Bits[Idx / BITWORD_SIZE] |= 1L << (Idx % BITWORD_SIZE); 93*da0073e9SAndroid Build Coastguard Worker } 94*da0073e9SAndroid Build Coastguard Worker test_and_setSparseBitVectorElement95*da0073e9SAndroid Build Coastguard Worker bool test_and_set(unsigned Idx) { 96*da0073e9SAndroid Build Coastguard Worker bool old = test(Idx); 97*da0073e9SAndroid Build Coastguard Worker if (!old) { 98*da0073e9SAndroid Build Coastguard Worker set(Idx); 99*da0073e9SAndroid Build Coastguard Worker return true; 100*da0073e9SAndroid Build Coastguard Worker } 101*da0073e9SAndroid Build Coastguard Worker return false; 102*da0073e9SAndroid Build Coastguard Worker } 103*da0073e9SAndroid Build Coastguard Worker resetSparseBitVectorElement104*da0073e9SAndroid Build Coastguard Worker void reset(unsigned Idx) { 105*da0073e9SAndroid Build Coastguard Worker Bits[Idx / BITWORD_SIZE] &= ~(1L << (Idx % BITWORD_SIZE)); 106*da0073e9SAndroid Build Coastguard Worker } 107*da0073e9SAndroid Build Coastguard Worker testSparseBitVectorElement108*da0073e9SAndroid Build Coastguard Worker bool test(unsigned Idx) const { 109*da0073e9SAndroid Build Coastguard Worker return Bits[Idx / BITWORD_SIZE] & (1L << (Idx % BITWORD_SIZE)); 110*da0073e9SAndroid Build Coastguard Worker } 111*da0073e9SAndroid Build Coastguard Worker countSparseBitVectorElement112*da0073e9SAndroid Build Coastguard Worker size_type count() const { 113*da0073e9SAndroid Build Coastguard Worker unsigned NumBits = 0; 114*da0073e9SAndroid Build Coastguard Worker for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) 115*da0073e9SAndroid Build Coastguard Worker NumBits += llvm::countPopulation(Bits[i]); 116*da0073e9SAndroid Build Coastguard Worker return NumBits; 117*da0073e9SAndroid Build Coastguard Worker } 118*da0073e9SAndroid Build Coastguard Worker 119*da0073e9SAndroid Build Coastguard Worker /// find_first - Returns the index of the first set bit. find_firstSparseBitVectorElement120*da0073e9SAndroid Build Coastguard Worker int find_first() const { 121*da0073e9SAndroid Build Coastguard Worker for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) 122*da0073e9SAndroid Build Coastguard Worker if (Bits[i] != 0) 123*da0073e9SAndroid Build Coastguard Worker return i * BITWORD_SIZE + llvm::countTrailingZeros(Bits[i]); 124*da0073e9SAndroid Build Coastguard Worker throw std::runtime_error("Illegal empty element"); 125*da0073e9SAndroid Build Coastguard Worker } 126*da0073e9SAndroid Build Coastguard Worker 127*da0073e9SAndroid Build Coastguard Worker /// find_last - Returns the index of the last set bit. find_lastSparseBitVectorElement128*da0073e9SAndroid Build Coastguard Worker int find_last() const { 129*da0073e9SAndroid Build Coastguard Worker for (unsigned I = 0; I < BITWORDS_PER_ELEMENT; ++I) { 130*da0073e9SAndroid Build Coastguard Worker unsigned Idx = BITWORDS_PER_ELEMENT - I - 1; 131*da0073e9SAndroid Build Coastguard Worker if (Bits[Idx] != 0) 132*da0073e9SAndroid Build Coastguard Worker return Idx * BITWORD_SIZE + BITWORD_SIZE - 133*da0073e9SAndroid Build Coastguard Worker llvm::countLeadingZeros(Bits[Idx]); 134*da0073e9SAndroid Build Coastguard Worker } 135*da0073e9SAndroid Build Coastguard Worker throw std::runtime_error("Illegal empty element"); 136*da0073e9SAndroid Build Coastguard Worker } 137*da0073e9SAndroid Build Coastguard Worker 138*da0073e9SAndroid Build Coastguard Worker /// find_next - Returns the index of the next set bit starting from the 139*da0073e9SAndroid Build Coastguard Worker /// "Curr" bit. Returns -1 if the next set bit is not found. find_nextSparseBitVectorElement140*da0073e9SAndroid Build Coastguard Worker int find_next(unsigned Curr) const { 141*da0073e9SAndroid Build Coastguard Worker if (Curr >= BITS_PER_ELEMENT) 142*da0073e9SAndroid Build Coastguard Worker return -1; 143*da0073e9SAndroid Build Coastguard Worker 144*da0073e9SAndroid Build Coastguard Worker unsigned WordPos = Curr / BITWORD_SIZE; 145*da0073e9SAndroid Build Coastguard Worker unsigned BitPos = Curr % BITWORD_SIZE; 146*da0073e9SAndroid Build Coastguard Worker BitWord Copy = Bits[WordPos]; 147*da0073e9SAndroid Build Coastguard Worker assert( 148*da0073e9SAndroid Build Coastguard Worker WordPos <= BITWORDS_PER_ELEMENT && "Word Position outside of element"); 149*da0073e9SAndroid Build Coastguard Worker 150*da0073e9SAndroid Build Coastguard Worker // Mask off previous bits. 151*da0073e9SAndroid Build Coastguard Worker Copy &= ~0UL << BitPos; 152*da0073e9SAndroid Build Coastguard Worker 153*da0073e9SAndroid Build Coastguard Worker if (Copy != 0) 154*da0073e9SAndroid Build Coastguard Worker return WordPos * BITWORD_SIZE + llvm::countTrailingZeros(Copy); 155*da0073e9SAndroid Build Coastguard Worker 156*da0073e9SAndroid Build Coastguard Worker // Check subsequent words. 157*da0073e9SAndroid Build Coastguard Worker for (unsigned i = WordPos + 1; i < BITWORDS_PER_ELEMENT; ++i) 158*da0073e9SAndroid Build Coastguard Worker if (Bits[i] != 0) 159*da0073e9SAndroid Build Coastguard Worker return i * BITWORD_SIZE + llvm::countTrailingZeros(Bits[i]); 160*da0073e9SAndroid Build Coastguard Worker return -1; 161*da0073e9SAndroid Build Coastguard Worker } 162*da0073e9SAndroid Build Coastguard Worker 163*da0073e9SAndroid Build Coastguard Worker // Union this element with RHS and return true if this one changed. unionWithSparseBitVectorElement164*da0073e9SAndroid Build Coastguard Worker bool unionWith(const SparseBitVectorElement& RHS) { 165*da0073e9SAndroid Build Coastguard Worker bool changed = false; 166*da0073e9SAndroid Build Coastguard Worker for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) { 167*da0073e9SAndroid Build Coastguard Worker BitWord old = changed ? 0 : Bits[i]; 168*da0073e9SAndroid Build Coastguard Worker 169*da0073e9SAndroid Build Coastguard Worker Bits[i] |= RHS.Bits[i]; 170*da0073e9SAndroid Build Coastguard Worker if (!changed && old != Bits[i]) 171*da0073e9SAndroid Build Coastguard Worker changed = true; 172*da0073e9SAndroid Build Coastguard Worker } 173*da0073e9SAndroid Build Coastguard Worker return changed; 174*da0073e9SAndroid Build Coastguard Worker } 175*da0073e9SAndroid Build Coastguard Worker 176*da0073e9SAndroid Build Coastguard Worker // Return true if we have any bits in common with RHS intersectsSparseBitVectorElement177*da0073e9SAndroid Build Coastguard Worker bool intersects(const SparseBitVectorElement& RHS) const { 178*da0073e9SAndroid Build Coastguard Worker for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) { 179*da0073e9SAndroid Build Coastguard Worker if (RHS.Bits[i] & Bits[i]) 180*da0073e9SAndroid Build Coastguard Worker return true; 181*da0073e9SAndroid Build Coastguard Worker } 182*da0073e9SAndroid Build Coastguard Worker return false; 183*da0073e9SAndroid Build Coastguard Worker } 184*da0073e9SAndroid Build Coastguard Worker 185*da0073e9SAndroid Build Coastguard Worker // Intersect this Element with RHS and return true if this one changed. 186*da0073e9SAndroid Build Coastguard Worker // BecameZero is set to true if this element became all-zero bits. intersectWithSparseBitVectorElement187*da0073e9SAndroid Build Coastguard Worker bool intersectWith(const SparseBitVectorElement& RHS, bool& BecameZero) { 188*da0073e9SAndroid Build Coastguard Worker bool changed = false; 189*da0073e9SAndroid Build Coastguard Worker bool allzero = true; 190*da0073e9SAndroid Build Coastguard Worker 191*da0073e9SAndroid Build Coastguard Worker for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) { 192*da0073e9SAndroid Build Coastguard Worker BitWord old = changed ? 0 : Bits[i]; 193*da0073e9SAndroid Build Coastguard Worker 194*da0073e9SAndroid Build Coastguard Worker Bits[i] &= RHS.Bits[i]; 195*da0073e9SAndroid Build Coastguard Worker if (Bits[i] != 0) 196*da0073e9SAndroid Build Coastguard Worker allzero = false; 197*da0073e9SAndroid Build Coastguard Worker 198*da0073e9SAndroid Build Coastguard Worker if (!changed && old != Bits[i]) 199*da0073e9SAndroid Build Coastguard Worker changed = true; 200*da0073e9SAndroid Build Coastguard Worker } 201*da0073e9SAndroid Build Coastguard Worker BecameZero = allzero; 202*da0073e9SAndroid Build Coastguard Worker return changed; 203*da0073e9SAndroid Build Coastguard Worker } 204*da0073e9SAndroid Build Coastguard Worker 205*da0073e9SAndroid Build Coastguard Worker // Intersect this Element with the complement of RHS and return true if this 206*da0073e9SAndroid Build Coastguard Worker // one changed. BecameZero is set to true if this element became all-zero 207*da0073e9SAndroid Build Coastguard Worker // bits. intersectWithComplementSparseBitVectorElement208*da0073e9SAndroid Build Coastguard Worker bool intersectWithComplement( 209*da0073e9SAndroid Build Coastguard Worker const SparseBitVectorElement& RHS, 210*da0073e9SAndroid Build Coastguard Worker bool& BecameZero) { 211*da0073e9SAndroid Build Coastguard Worker bool changed = false; 212*da0073e9SAndroid Build Coastguard Worker bool allzero = true; 213*da0073e9SAndroid Build Coastguard Worker 214*da0073e9SAndroid Build Coastguard Worker for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) { 215*da0073e9SAndroid Build Coastguard Worker BitWord old = changed ? 0 : Bits[i]; 216*da0073e9SAndroid Build Coastguard Worker 217*da0073e9SAndroid Build Coastguard Worker Bits[i] &= ~RHS.Bits[i]; 218*da0073e9SAndroid Build Coastguard Worker if (Bits[i] != 0) 219*da0073e9SAndroid Build Coastguard Worker allzero = false; 220*da0073e9SAndroid Build Coastguard Worker 221*da0073e9SAndroid Build Coastguard Worker if (!changed && old != Bits[i]) 222*da0073e9SAndroid Build Coastguard Worker changed = true; 223*da0073e9SAndroid Build Coastguard Worker } 224*da0073e9SAndroid Build Coastguard Worker BecameZero = allzero; 225*da0073e9SAndroid Build Coastguard Worker return changed; 226*da0073e9SAndroid Build Coastguard Worker } 227*da0073e9SAndroid Build Coastguard Worker 228*da0073e9SAndroid Build Coastguard Worker // Three argument version of intersectWithComplement that intersects 229*da0073e9SAndroid Build Coastguard Worker // RHS1 & ~RHS2 into this element intersectWithComplementSparseBitVectorElement230*da0073e9SAndroid Build Coastguard Worker void intersectWithComplement( 231*da0073e9SAndroid Build Coastguard Worker const SparseBitVectorElement& RHS1, 232*da0073e9SAndroid Build Coastguard Worker const SparseBitVectorElement& RHS2, 233*da0073e9SAndroid Build Coastguard Worker bool& BecameZero) { 234*da0073e9SAndroid Build Coastguard Worker bool allzero = true; 235*da0073e9SAndroid Build Coastguard Worker 236*da0073e9SAndroid Build Coastguard Worker for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i) { 237*da0073e9SAndroid Build Coastguard Worker Bits[i] = RHS1.Bits[i] & ~RHS2.Bits[i]; 238*da0073e9SAndroid Build Coastguard Worker if (Bits[i] != 0) 239*da0073e9SAndroid Build Coastguard Worker allzero = false; 240*da0073e9SAndroid Build Coastguard Worker } 241*da0073e9SAndroid Build Coastguard Worker BecameZero = allzero; 242*da0073e9SAndroid Build Coastguard Worker } 243*da0073e9SAndroid Build Coastguard Worker }; 244*da0073e9SAndroid Build Coastguard Worker 245*da0073e9SAndroid Build Coastguard Worker template <unsigned ElementSize = 128> 246*da0073e9SAndroid Build Coastguard Worker class SparseBitVector { 247*da0073e9SAndroid Build Coastguard Worker using ElementList = std::list<SparseBitVectorElement<ElementSize>>; 248*da0073e9SAndroid Build Coastguard Worker using ElementListIter = typename ElementList::iterator; 249*da0073e9SAndroid Build Coastguard Worker using ElementListConstIter = typename ElementList::const_iterator; 250*da0073e9SAndroid Build Coastguard Worker enum { BITWORD_SIZE = SparseBitVectorElement<ElementSize>::BITWORD_SIZE }; 251*da0073e9SAndroid Build Coastguard Worker 252*da0073e9SAndroid Build Coastguard Worker ElementList Elements; 253*da0073e9SAndroid Build Coastguard Worker // Pointer to our current Element. This has no visible effect on the external 254*da0073e9SAndroid Build Coastguard Worker // state of a SparseBitVector, it's just used to improve performance in the 255*da0073e9SAndroid Build Coastguard Worker // common case of testing/modifying bits with similar indices. 256*da0073e9SAndroid Build Coastguard Worker mutable ElementListIter CurrElementIter; 257*da0073e9SAndroid Build Coastguard Worker 258*da0073e9SAndroid Build Coastguard Worker // This is like std::lower_bound, except we do linear searching from the 259*da0073e9SAndroid Build Coastguard Worker // current position. FindLowerBoundImpl(unsigned ElementIndex)260*da0073e9SAndroid Build Coastguard Worker ElementListIter FindLowerBoundImpl(unsigned ElementIndex) const { 261*da0073e9SAndroid Build Coastguard Worker // We cache a non-const iterator so we're forced to resort to const_cast to 262*da0073e9SAndroid Build Coastguard Worker // get the begin/end in the case where 'this' is const. To avoid duplication 263*da0073e9SAndroid Build Coastguard Worker // of code with the only difference being whether the const cast is present 264*da0073e9SAndroid Build Coastguard Worker // 'this' is always const in this particular function and we sort out the 265*da0073e9SAndroid Build Coastguard Worker // difference in FindLowerBound and FindLowerBoundConst. 266*da0073e9SAndroid Build Coastguard Worker ElementListIter Begin = 267*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) 268*da0073e9SAndroid Build Coastguard Worker const_cast<SparseBitVector<ElementSize>*>(this)->Elements.begin(); 269*da0073e9SAndroid Build Coastguard Worker ElementListIter End = 270*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) 271*da0073e9SAndroid Build Coastguard Worker const_cast<SparseBitVector<ElementSize>*>(this)->Elements.end(); 272*da0073e9SAndroid Build Coastguard Worker 273*da0073e9SAndroid Build Coastguard Worker if (Elements.empty()) { 274*da0073e9SAndroid Build Coastguard Worker CurrElementIter = Begin; 275*da0073e9SAndroid Build Coastguard Worker return CurrElementIter; 276*da0073e9SAndroid Build Coastguard Worker } 277*da0073e9SAndroid Build Coastguard Worker 278*da0073e9SAndroid Build Coastguard Worker // Make sure our current iterator is valid. 279*da0073e9SAndroid Build Coastguard Worker if (CurrElementIter == End) 280*da0073e9SAndroid Build Coastguard Worker --CurrElementIter; 281*da0073e9SAndroid Build Coastguard Worker 282*da0073e9SAndroid Build Coastguard Worker // Search from our current iterator, either backwards or forwards, 283*da0073e9SAndroid Build Coastguard Worker // depending on what element we are looking for. 284*da0073e9SAndroid Build Coastguard Worker ElementListIter ElementIter = CurrElementIter; 285*da0073e9SAndroid Build Coastguard Worker if (CurrElementIter->index() == ElementIndex) { 286*da0073e9SAndroid Build Coastguard Worker return ElementIter; 287*da0073e9SAndroid Build Coastguard Worker } else if (CurrElementIter->index() > ElementIndex) { 288*da0073e9SAndroid Build Coastguard Worker while (ElementIter != Begin && ElementIter->index() > ElementIndex) 289*da0073e9SAndroid Build Coastguard Worker --ElementIter; 290*da0073e9SAndroid Build Coastguard Worker } else { 291*da0073e9SAndroid Build Coastguard Worker while (ElementIter != End && ElementIter->index() < ElementIndex) 292*da0073e9SAndroid Build Coastguard Worker ++ElementIter; 293*da0073e9SAndroid Build Coastguard Worker } 294*da0073e9SAndroid Build Coastguard Worker CurrElementIter = ElementIter; 295*da0073e9SAndroid Build Coastguard Worker return ElementIter; 296*da0073e9SAndroid Build Coastguard Worker } FindLowerBoundConst(unsigned ElementIndex)297*da0073e9SAndroid Build Coastguard Worker ElementListConstIter FindLowerBoundConst(unsigned ElementIndex) const { 298*da0073e9SAndroid Build Coastguard Worker return FindLowerBoundImpl(ElementIndex); 299*da0073e9SAndroid Build Coastguard Worker } FindLowerBound(unsigned ElementIndex)300*da0073e9SAndroid Build Coastguard Worker ElementListIter FindLowerBound(unsigned ElementIndex) { 301*da0073e9SAndroid Build Coastguard Worker return FindLowerBoundImpl(ElementIndex); 302*da0073e9SAndroid Build Coastguard Worker } 303*da0073e9SAndroid Build Coastguard Worker 304*da0073e9SAndroid Build Coastguard Worker // Iterator to walk set bits in the bitmap. This iterator is a lot uglier 305*da0073e9SAndroid Build Coastguard Worker // than it would be, in order to be efficient. 306*da0073e9SAndroid Build Coastguard Worker class SparseBitVectorIterator { 307*da0073e9SAndroid Build Coastguard Worker private: 308*da0073e9SAndroid Build Coastguard Worker bool AtEnd{false}; 309*da0073e9SAndroid Build Coastguard Worker 310*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>* BitVector = nullptr; 311*da0073e9SAndroid Build Coastguard Worker 312*da0073e9SAndroid Build Coastguard Worker // Current element inside of bitmap. 313*da0073e9SAndroid Build Coastguard Worker ElementListConstIter Iter; 314*da0073e9SAndroid Build Coastguard Worker 315*da0073e9SAndroid Build Coastguard Worker // Current bit number inside of our bitmap. 316*da0073e9SAndroid Build Coastguard Worker unsigned BitNumber{0}; 317*da0073e9SAndroid Build Coastguard Worker 318*da0073e9SAndroid Build Coastguard Worker // Current word number inside of our element. 319*da0073e9SAndroid Build Coastguard Worker unsigned WordNumber{0}; 320*da0073e9SAndroid Build Coastguard Worker 321*da0073e9SAndroid Build Coastguard Worker // Current bits from the element. 322*da0073e9SAndroid Build Coastguard Worker typename SparseBitVectorElement<ElementSize>::BitWord Bits{0}; 323*da0073e9SAndroid Build Coastguard Worker 324*da0073e9SAndroid Build Coastguard Worker // Move our iterator to the first non-zero bit in the bitmap. AdvanceToFirstNonZero()325*da0073e9SAndroid Build Coastguard Worker void AdvanceToFirstNonZero() { 326*da0073e9SAndroid Build Coastguard Worker if (AtEnd) 327*da0073e9SAndroid Build Coastguard Worker return; 328*da0073e9SAndroid Build Coastguard Worker if (BitVector->Elements.empty()) { 329*da0073e9SAndroid Build Coastguard Worker AtEnd = true; 330*da0073e9SAndroid Build Coastguard Worker return; 331*da0073e9SAndroid Build Coastguard Worker } 332*da0073e9SAndroid Build Coastguard Worker Iter = BitVector->Elements.begin(); 333*da0073e9SAndroid Build Coastguard Worker BitNumber = Iter->index() * ElementSize; 334*da0073e9SAndroid Build Coastguard Worker unsigned BitPos = Iter->find_first(); 335*da0073e9SAndroid Build Coastguard Worker BitNumber += BitPos; 336*da0073e9SAndroid Build Coastguard Worker WordNumber = (BitNumber % ElementSize) / BITWORD_SIZE; 337*da0073e9SAndroid Build Coastguard Worker Bits = Iter->word(WordNumber); 338*da0073e9SAndroid Build Coastguard Worker Bits >>= BitPos % BITWORD_SIZE; 339*da0073e9SAndroid Build Coastguard Worker } 340*da0073e9SAndroid Build Coastguard Worker 341*da0073e9SAndroid Build Coastguard Worker // Move our iterator to the next non-zero bit. AdvanceToNextNonZero()342*da0073e9SAndroid Build Coastguard Worker void AdvanceToNextNonZero() { 343*da0073e9SAndroid Build Coastguard Worker if (AtEnd) 344*da0073e9SAndroid Build Coastguard Worker return; 345*da0073e9SAndroid Build Coastguard Worker 346*da0073e9SAndroid Build Coastguard Worker while (Bits && !(Bits & 1)) { 347*da0073e9SAndroid Build Coastguard Worker Bits >>= 1; 348*da0073e9SAndroid Build Coastguard Worker BitNumber += 1; 349*da0073e9SAndroid Build Coastguard Worker } 350*da0073e9SAndroid Build Coastguard Worker 351*da0073e9SAndroid Build Coastguard Worker // See if we ran out of Bits in this word. 352*da0073e9SAndroid Build Coastguard Worker if (!Bits) { 353*da0073e9SAndroid Build Coastguard Worker int NextSetBitNumber = Iter->find_next(BitNumber % ElementSize); 354*da0073e9SAndroid Build Coastguard Worker // If we ran out of set bits in this element, move to next element. 355*da0073e9SAndroid Build Coastguard Worker if (NextSetBitNumber == -1 || (BitNumber % ElementSize == 0)) { 356*da0073e9SAndroid Build Coastguard Worker ++Iter; 357*da0073e9SAndroid Build Coastguard Worker WordNumber = 0; 358*da0073e9SAndroid Build Coastguard Worker 359*da0073e9SAndroid Build Coastguard Worker // We may run out of elements in the bitmap. 360*da0073e9SAndroid Build Coastguard Worker if (Iter == BitVector->Elements.end()) { 361*da0073e9SAndroid Build Coastguard Worker AtEnd = true; 362*da0073e9SAndroid Build Coastguard Worker return; 363*da0073e9SAndroid Build Coastguard Worker } 364*da0073e9SAndroid Build Coastguard Worker // Set up for next non-zero word in bitmap. 365*da0073e9SAndroid Build Coastguard Worker BitNumber = Iter->index() * ElementSize; 366*da0073e9SAndroid Build Coastguard Worker NextSetBitNumber = Iter->find_first(); 367*da0073e9SAndroid Build Coastguard Worker BitNumber += NextSetBitNumber; 368*da0073e9SAndroid Build Coastguard Worker WordNumber = (BitNumber % ElementSize) / BITWORD_SIZE; 369*da0073e9SAndroid Build Coastguard Worker Bits = Iter->word(WordNumber); 370*da0073e9SAndroid Build Coastguard Worker Bits >>= NextSetBitNumber % BITWORD_SIZE; 371*da0073e9SAndroid Build Coastguard Worker } else { 372*da0073e9SAndroid Build Coastguard Worker WordNumber = (NextSetBitNumber % ElementSize) / BITWORD_SIZE; 373*da0073e9SAndroid Build Coastguard Worker Bits = Iter->word(WordNumber); 374*da0073e9SAndroid Build Coastguard Worker Bits >>= NextSetBitNumber % BITWORD_SIZE; 375*da0073e9SAndroid Build Coastguard Worker BitNumber = Iter->index() * ElementSize; 376*da0073e9SAndroid Build Coastguard Worker BitNumber += NextSetBitNumber; 377*da0073e9SAndroid Build Coastguard Worker } 378*da0073e9SAndroid Build Coastguard Worker } 379*da0073e9SAndroid Build Coastguard Worker } 380*da0073e9SAndroid Build Coastguard Worker 381*da0073e9SAndroid Build Coastguard Worker public: 382*da0073e9SAndroid Build Coastguard Worker SparseBitVectorIterator() = default; 383*da0073e9SAndroid Build Coastguard Worker 384*da0073e9SAndroid Build Coastguard Worker SparseBitVectorIterator( 385*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>* RHS, 386*da0073e9SAndroid Build Coastguard Worker bool end = false) AtEnd(end)387*da0073e9SAndroid Build Coastguard Worker : AtEnd(end), 388*da0073e9SAndroid Build Coastguard Worker BitVector(RHS), 389*da0073e9SAndroid Build Coastguard Worker Iter(BitVector->Elements.begin()), 390*da0073e9SAndroid Build Coastguard Worker WordNumber(~0) { 391*da0073e9SAndroid Build Coastguard Worker AdvanceToFirstNonZero(); 392*da0073e9SAndroid Build Coastguard Worker } 393*da0073e9SAndroid Build Coastguard Worker 394*da0073e9SAndroid Build Coastguard Worker // Preincrement. 395*da0073e9SAndroid Build Coastguard Worker inline SparseBitVectorIterator& operator++() { 396*da0073e9SAndroid Build Coastguard Worker ++BitNumber; 397*da0073e9SAndroid Build Coastguard Worker Bits >>= 1; 398*da0073e9SAndroid Build Coastguard Worker AdvanceToNextNonZero(); 399*da0073e9SAndroid Build Coastguard Worker return *this; 400*da0073e9SAndroid Build Coastguard Worker } 401*da0073e9SAndroid Build Coastguard Worker 402*da0073e9SAndroid Build Coastguard Worker // Postincrement. 403*da0073e9SAndroid Build Coastguard Worker inline SparseBitVectorIterator operator++(int) { 404*da0073e9SAndroid Build Coastguard Worker SparseBitVectorIterator tmp = *this; 405*da0073e9SAndroid Build Coastguard Worker ++*this; 406*da0073e9SAndroid Build Coastguard Worker return tmp; 407*da0073e9SAndroid Build Coastguard Worker } 408*da0073e9SAndroid Build Coastguard Worker 409*da0073e9SAndroid Build Coastguard Worker // Return the current set bit number. 410*da0073e9SAndroid Build Coastguard Worker unsigned operator*() const { 411*da0073e9SAndroid Build Coastguard Worker return BitNumber; 412*da0073e9SAndroid Build Coastguard Worker } 413*da0073e9SAndroid Build Coastguard Worker 414*da0073e9SAndroid Build Coastguard Worker bool operator==(const SparseBitVectorIterator& RHS) const { 415*da0073e9SAndroid Build Coastguard Worker // If they are both at the end, ignore the rest of the fields. 416*da0073e9SAndroid Build Coastguard Worker if (AtEnd && RHS.AtEnd) 417*da0073e9SAndroid Build Coastguard Worker return true; 418*da0073e9SAndroid Build Coastguard Worker // Otherwise they are the same if they have the same bit number and 419*da0073e9SAndroid Build Coastguard Worker // bitmap. 420*da0073e9SAndroid Build Coastguard Worker return AtEnd == RHS.AtEnd && RHS.BitNumber == BitNumber; 421*da0073e9SAndroid Build Coastguard Worker } 422*da0073e9SAndroid Build Coastguard Worker 423*da0073e9SAndroid Build Coastguard Worker bool operator!=(const SparseBitVectorIterator& RHS) const { 424*da0073e9SAndroid Build Coastguard Worker return !(*this == RHS); 425*da0073e9SAndroid Build Coastguard Worker } 426*da0073e9SAndroid Build Coastguard Worker }; 427*da0073e9SAndroid Build Coastguard Worker 428*da0073e9SAndroid Build Coastguard Worker public: 429*da0073e9SAndroid Build Coastguard Worker using iterator = SparseBitVectorIterator; 430*da0073e9SAndroid Build Coastguard Worker SparseBitVector()431*da0073e9SAndroid Build Coastguard Worker SparseBitVector() : Elements(), CurrElementIter(Elements.begin()) {} 432*da0073e9SAndroid Build Coastguard Worker SparseBitVector(const SparseBitVector & RHS)433*da0073e9SAndroid Build Coastguard Worker SparseBitVector(const SparseBitVector& RHS) 434*da0073e9SAndroid Build Coastguard Worker : Elements(RHS.Elements), CurrElementIter(Elements.begin()) {} SparseBitVector(SparseBitVector && RHS)435*da0073e9SAndroid Build Coastguard Worker SparseBitVector(SparseBitVector&& RHS) noexcept 436*da0073e9SAndroid Build Coastguard Worker : Elements(std::move(RHS.Elements)), CurrElementIter(Elements.begin()) {} 437*da0073e9SAndroid Build Coastguard Worker 438*da0073e9SAndroid Build Coastguard Worker // Clear. clear()439*da0073e9SAndroid Build Coastguard Worker void clear() { 440*da0073e9SAndroid Build Coastguard Worker Elements.clear(); 441*da0073e9SAndroid Build Coastguard Worker } 442*da0073e9SAndroid Build Coastguard Worker 443*da0073e9SAndroid Build Coastguard Worker // Assignment 444*da0073e9SAndroid Build Coastguard Worker SparseBitVector& operator=(const SparseBitVector& RHS) { 445*da0073e9SAndroid Build Coastguard Worker if (this == &RHS) 446*da0073e9SAndroid Build Coastguard Worker return *this; 447*da0073e9SAndroid Build Coastguard Worker 448*da0073e9SAndroid Build Coastguard Worker Elements = RHS.Elements; 449*da0073e9SAndroid Build Coastguard Worker CurrElementIter = Elements.begin(); 450*da0073e9SAndroid Build Coastguard Worker return *this; 451*da0073e9SAndroid Build Coastguard Worker } 452*da0073e9SAndroid Build Coastguard Worker SparseBitVector& operator=(SparseBitVector&& RHS) noexcept { 453*da0073e9SAndroid Build Coastguard Worker Elements = std::move(RHS.Elements); 454*da0073e9SAndroid Build Coastguard Worker CurrElementIter = Elements.begin(); 455*da0073e9SAndroid Build Coastguard Worker return *this; 456*da0073e9SAndroid Build Coastguard Worker } 457*da0073e9SAndroid Build Coastguard Worker 458*da0073e9SAndroid Build Coastguard Worker // Test, Reset, and Set a bit in the bitmap. test(unsigned Idx)459*da0073e9SAndroid Build Coastguard Worker bool test(unsigned Idx) const { 460*da0073e9SAndroid Build Coastguard Worker if (Elements.empty()) 461*da0073e9SAndroid Build Coastguard Worker return false; 462*da0073e9SAndroid Build Coastguard Worker 463*da0073e9SAndroid Build Coastguard Worker unsigned ElementIndex = Idx / ElementSize; 464*da0073e9SAndroid Build Coastguard Worker ElementListConstIter ElementIter = FindLowerBoundConst(ElementIndex); 465*da0073e9SAndroid Build Coastguard Worker 466*da0073e9SAndroid Build Coastguard Worker // If we can't find an element that is supposed to contain this bit, there 467*da0073e9SAndroid Build Coastguard Worker // is nothing more to do. 468*da0073e9SAndroid Build Coastguard Worker if (ElementIter == Elements.end() || ElementIter->index() != ElementIndex) 469*da0073e9SAndroid Build Coastguard Worker return false; 470*da0073e9SAndroid Build Coastguard Worker return ElementIter->test(Idx % ElementSize); 471*da0073e9SAndroid Build Coastguard Worker } 472*da0073e9SAndroid Build Coastguard Worker reset(unsigned Idx)473*da0073e9SAndroid Build Coastguard Worker void reset(unsigned Idx) { 474*da0073e9SAndroid Build Coastguard Worker if (Elements.empty()) 475*da0073e9SAndroid Build Coastguard Worker return; 476*da0073e9SAndroid Build Coastguard Worker 477*da0073e9SAndroid Build Coastguard Worker unsigned ElementIndex = Idx / ElementSize; 478*da0073e9SAndroid Build Coastguard Worker ElementListIter ElementIter = FindLowerBound(ElementIndex); 479*da0073e9SAndroid Build Coastguard Worker 480*da0073e9SAndroid Build Coastguard Worker // If we can't find an element that is supposed to contain this bit, there 481*da0073e9SAndroid Build Coastguard Worker // is nothing more to do. 482*da0073e9SAndroid Build Coastguard Worker if (ElementIter == Elements.end() || ElementIter->index() != ElementIndex) 483*da0073e9SAndroid Build Coastguard Worker return; 484*da0073e9SAndroid Build Coastguard Worker ElementIter->reset(Idx % ElementSize); 485*da0073e9SAndroid Build Coastguard Worker 486*da0073e9SAndroid Build Coastguard Worker // When the element is zeroed out, delete it. 487*da0073e9SAndroid Build Coastguard Worker if (ElementIter->empty()) { 488*da0073e9SAndroid Build Coastguard Worker ++CurrElementIter; 489*da0073e9SAndroid Build Coastguard Worker Elements.erase(ElementIter); 490*da0073e9SAndroid Build Coastguard Worker } 491*da0073e9SAndroid Build Coastguard Worker } 492*da0073e9SAndroid Build Coastguard Worker set(unsigned Idx)493*da0073e9SAndroid Build Coastguard Worker void set(unsigned Idx) { 494*da0073e9SAndroid Build Coastguard Worker unsigned ElementIndex = Idx / ElementSize; 495*da0073e9SAndroid Build Coastguard Worker ElementListIter ElementIter; 496*da0073e9SAndroid Build Coastguard Worker if (Elements.empty()) { 497*da0073e9SAndroid Build Coastguard Worker ElementIter = Elements.emplace(Elements.end(), ElementIndex); 498*da0073e9SAndroid Build Coastguard Worker } else { 499*da0073e9SAndroid Build Coastguard Worker ElementIter = FindLowerBound(ElementIndex); 500*da0073e9SAndroid Build Coastguard Worker 501*da0073e9SAndroid Build Coastguard Worker if (ElementIter == Elements.end() || 502*da0073e9SAndroid Build Coastguard Worker ElementIter->index() != ElementIndex) { 503*da0073e9SAndroid Build Coastguard Worker // We may have hit the beginning of our SparseBitVector, in which case, 504*da0073e9SAndroid Build Coastguard Worker // we may need to insert right after this element, which requires moving 505*da0073e9SAndroid Build Coastguard Worker // the current iterator forward one, because insert does insert before. 506*da0073e9SAndroid Build Coastguard Worker if (ElementIter != Elements.end() && 507*da0073e9SAndroid Build Coastguard Worker ElementIter->index() < ElementIndex) 508*da0073e9SAndroid Build Coastguard Worker ++ElementIter; 509*da0073e9SAndroid Build Coastguard Worker ElementIter = Elements.emplace(ElementIter, ElementIndex); 510*da0073e9SAndroid Build Coastguard Worker } 511*da0073e9SAndroid Build Coastguard Worker } 512*da0073e9SAndroid Build Coastguard Worker CurrElementIter = ElementIter; 513*da0073e9SAndroid Build Coastguard Worker 514*da0073e9SAndroid Build Coastguard Worker ElementIter->set(Idx % ElementSize); 515*da0073e9SAndroid Build Coastguard Worker } 516*da0073e9SAndroid Build Coastguard Worker test_and_set(unsigned Idx)517*da0073e9SAndroid Build Coastguard Worker bool test_and_set(unsigned Idx) { 518*da0073e9SAndroid Build Coastguard Worker bool old = test(Idx); 519*da0073e9SAndroid Build Coastguard Worker if (!old) { 520*da0073e9SAndroid Build Coastguard Worker set(Idx); 521*da0073e9SAndroid Build Coastguard Worker return true; 522*da0073e9SAndroid Build Coastguard Worker } 523*da0073e9SAndroid Build Coastguard Worker return false; 524*da0073e9SAndroid Build Coastguard Worker } 525*da0073e9SAndroid Build Coastguard Worker 526*da0073e9SAndroid Build Coastguard Worker bool operator!=(const SparseBitVector& RHS) const { 527*da0073e9SAndroid Build Coastguard Worker return !(*this == RHS); 528*da0073e9SAndroid Build Coastguard Worker } 529*da0073e9SAndroid Build Coastguard Worker 530*da0073e9SAndroid Build Coastguard Worker bool operator==(const SparseBitVector& RHS) const { 531*da0073e9SAndroid Build Coastguard Worker ElementListConstIter Iter1 = Elements.begin(); 532*da0073e9SAndroid Build Coastguard Worker ElementListConstIter Iter2 = RHS.Elements.begin(); 533*da0073e9SAndroid Build Coastguard Worker 534*da0073e9SAndroid Build Coastguard Worker for (; Iter1 != Elements.end() && Iter2 != RHS.Elements.end(); 535*da0073e9SAndroid Build Coastguard Worker ++Iter1, ++Iter2) { 536*da0073e9SAndroid Build Coastguard Worker if (*Iter1 != *Iter2) 537*da0073e9SAndroid Build Coastguard Worker return false; 538*da0073e9SAndroid Build Coastguard Worker } 539*da0073e9SAndroid Build Coastguard Worker return Iter1 == Elements.end() && Iter2 == RHS.Elements.end(); 540*da0073e9SAndroid Build Coastguard Worker } 541*da0073e9SAndroid Build Coastguard Worker 542*da0073e9SAndroid Build Coastguard Worker // Union our bitmap with the RHS and return true if we changed. 543*da0073e9SAndroid Build Coastguard Worker bool operator|=(const SparseBitVector& RHS) { 544*da0073e9SAndroid Build Coastguard Worker if (this == &RHS) 545*da0073e9SAndroid Build Coastguard Worker return false; 546*da0073e9SAndroid Build Coastguard Worker 547*da0073e9SAndroid Build Coastguard Worker if (empty()) { 548*da0073e9SAndroid Build Coastguard Worker *this = RHS; 549*da0073e9SAndroid Build Coastguard Worker return true; 550*da0073e9SAndroid Build Coastguard Worker } 551*da0073e9SAndroid Build Coastguard Worker 552*da0073e9SAndroid Build Coastguard Worker bool changed = false; 553*da0073e9SAndroid Build Coastguard Worker ElementListIter Iter1 = Elements.begin(); 554*da0073e9SAndroid Build Coastguard Worker ElementListConstIter Iter2 = RHS.Elements.begin(); 555*da0073e9SAndroid Build Coastguard Worker 556*da0073e9SAndroid Build Coastguard Worker // If RHS is empty, we are done 557*da0073e9SAndroid Build Coastguard Worker if (RHS.Elements.empty()) 558*da0073e9SAndroid Build Coastguard Worker return false; 559*da0073e9SAndroid Build Coastguard Worker 560*da0073e9SAndroid Build Coastguard Worker while (Iter2 != RHS.Elements.end()) { 561*da0073e9SAndroid Build Coastguard Worker if (Iter1 == Elements.end() || Iter1->index() > Iter2->index()) { 562*da0073e9SAndroid Build Coastguard Worker Elements.insert(Iter1, *Iter2); 563*da0073e9SAndroid Build Coastguard Worker ++Iter2; 564*da0073e9SAndroid Build Coastguard Worker changed = true; 565*da0073e9SAndroid Build Coastguard Worker } else if (Iter1->index() == Iter2->index()) { 566*da0073e9SAndroid Build Coastguard Worker changed |= Iter1->unionWith(*Iter2); 567*da0073e9SAndroid Build Coastguard Worker ++Iter1; 568*da0073e9SAndroid Build Coastguard Worker ++Iter2; 569*da0073e9SAndroid Build Coastguard Worker } else { 570*da0073e9SAndroid Build Coastguard Worker ++Iter1; 571*da0073e9SAndroid Build Coastguard Worker } 572*da0073e9SAndroid Build Coastguard Worker } 573*da0073e9SAndroid Build Coastguard Worker CurrElementIter = Elements.begin(); 574*da0073e9SAndroid Build Coastguard Worker return changed; 575*da0073e9SAndroid Build Coastguard Worker } 576*da0073e9SAndroid Build Coastguard Worker 577*da0073e9SAndroid Build Coastguard Worker // Intersect our bitmap with the RHS and return true if ours changed. 578*da0073e9SAndroid Build Coastguard Worker bool operator-=(const SparseBitVector& RHS) { 579*da0073e9SAndroid Build Coastguard Worker return intersectWithComplement(RHS); 580*da0073e9SAndroid Build Coastguard Worker } 581*da0073e9SAndroid Build Coastguard Worker 582*da0073e9SAndroid Build Coastguard Worker // Intersect our bitmap with the RHS and return true if ours changed. 583*da0073e9SAndroid Build Coastguard Worker bool operator&=(const SparseBitVector& RHS) { 584*da0073e9SAndroid Build Coastguard Worker if (this == &RHS) 585*da0073e9SAndroid Build Coastguard Worker return false; 586*da0073e9SAndroid Build Coastguard Worker 587*da0073e9SAndroid Build Coastguard Worker bool changed = false; 588*da0073e9SAndroid Build Coastguard Worker ElementListIter Iter1 = Elements.begin(); 589*da0073e9SAndroid Build Coastguard Worker ElementListConstIter Iter2 = RHS.Elements.begin(); 590*da0073e9SAndroid Build Coastguard Worker 591*da0073e9SAndroid Build Coastguard Worker // Check if both bitmaps are empty. 592*da0073e9SAndroid Build Coastguard Worker if (Elements.empty() && RHS.Elements.empty()) 593*da0073e9SAndroid Build Coastguard Worker return false; 594*da0073e9SAndroid Build Coastguard Worker 595*da0073e9SAndroid Build Coastguard Worker // Loop through, intersecting as we go, erasing elements when necessary. 596*da0073e9SAndroid Build Coastguard Worker while (Iter2 != RHS.Elements.end()) { 597*da0073e9SAndroid Build Coastguard Worker if (Iter1 == Elements.end()) { 598*da0073e9SAndroid Build Coastguard Worker CurrElementIter = Elements.begin(); 599*da0073e9SAndroid Build Coastguard Worker return changed; 600*da0073e9SAndroid Build Coastguard Worker } 601*da0073e9SAndroid Build Coastguard Worker 602*da0073e9SAndroid Build Coastguard Worker if (Iter1->index() > Iter2->index()) { 603*da0073e9SAndroid Build Coastguard Worker ++Iter2; 604*da0073e9SAndroid Build Coastguard Worker } else if (Iter1->index() == Iter2->index()) { 605*da0073e9SAndroid Build Coastguard Worker bool BecameZero = false; 606*da0073e9SAndroid Build Coastguard Worker changed |= Iter1->intersectWith(*Iter2, BecameZero); 607*da0073e9SAndroid Build Coastguard Worker if (BecameZero) { 608*da0073e9SAndroid Build Coastguard Worker ElementListIter IterTmp = Iter1; 609*da0073e9SAndroid Build Coastguard Worker ++Iter1; 610*da0073e9SAndroid Build Coastguard Worker Elements.erase(IterTmp); 611*da0073e9SAndroid Build Coastguard Worker } else { 612*da0073e9SAndroid Build Coastguard Worker ++Iter1; 613*da0073e9SAndroid Build Coastguard Worker } 614*da0073e9SAndroid Build Coastguard Worker ++Iter2; 615*da0073e9SAndroid Build Coastguard Worker } else { 616*da0073e9SAndroid Build Coastguard Worker ElementListIter IterTmp = Iter1; 617*da0073e9SAndroid Build Coastguard Worker ++Iter1; 618*da0073e9SAndroid Build Coastguard Worker Elements.erase(IterTmp); 619*da0073e9SAndroid Build Coastguard Worker changed = true; 620*da0073e9SAndroid Build Coastguard Worker } 621*da0073e9SAndroid Build Coastguard Worker } 622*da0073e9SAndroid Build Coastguard Worker if (Iter1 != Elements.end()) { 623*da0073e9SAndroid Build Coastguard Worker Elements.erase(Iter1, Elements.end()); 624*da0073e9SAndroid Build Coastguard Worker changed = true; 625*da0073e9SAndroid Build Coastguard Worker } 626*da0073e9SAndroid Build Coastguard Worker CurrElementIter = Elements.begin(); 627*da0073e9SAndroid Build Coastguard Worker return changed; 628*da0073e9SAndroid Build Coastguard Worker } 629*da0073e9SAndroid Build Coastguard Worker 630*da0073e9SAndroid Build Coastguard Worker // Intersect our bitmap with the complement of the RHS and return true 631*da0073e9SAndroid Build Coastguard Worker // if ours changed. intersectWithComplement(const SparseBitVector & RHS)632*da0073e9SAndroid Build Coastguard Worker bool intersectWithComplement(const SparseBitVector& RHS) { 633*da0073e9SAndroid Build Coastguard Worker if (this == &RHS) { 634*da0073e9SAndroid Build Coastguard Worker if (!empty()) { 635*da0073e9SAndroid Build Coastguard Worker clear(); 636*da0073e9SAndroid Build Coastguard Worker return true; 637*da0073e9SAndroid Build Coastguard Worker } 638*da0073e9SAndroid Build Coastguard Worker return false; 639*da0073e9SAndroid Build Coastguard Worker } 640*da0073e9SAndroid Build Coastguard Worker 641*da0073e9SAndroid Build Coastguard Worker bool changed = false; 642*da0073e9SAndroid Build Coastguard Worker ElementListIter Iter1 = Elements.begin(); 643*da0073e9SAndroid Build Coastguard Worker ElementListConstIter Iter2 = RHS.Elements.begin(); 644*da0073e9SAndroid Build Coastguard Worker 645*da0073e9SAndroid Build Coastguard Worker // If either our bitmap or RHS is empty, we are done 646*da0073e9SAndroid Build Coastguard Worker if (Elements.empty() || RHS.Elements.empty()) 647*da0073e9SAndroid Build Coastguard Worker return false; 648*da0073e9SAndroid Build Coastguard Worker 649*da0073e9SAndroid Build Coastguard Worker // Loop through, intersecting as we go, erasing elements when necessary. 650*da0073e9SAndroid Build Coastguard Worker while (Iter2 != RHS.Elements.end()) { 651*da0073e9SAndroid Build Coastguard Worker if (Iter1 == Elements.end()) { 652*da0073e9SAndroid Build Coastguard Worker CurrElementIter = Elements.begin(); 653*da0073e9SAndroid Build Coastguard Worker return changed; 654*da0073e9SAndroid Build Coastguard Worker } 655*da0073e9SAndroid Build Coastguard Worker 656*da0073e9SAndroid Build Coastguard Worker if (Iter1->index() > Iter2->index()) { 657*da0073e9SAndroid Build Coastguard Worker ++Iter2; 658*da0073e9SAndroid Build Coastguard Worker } else if (Iter1->index() == Iter2->index()) { 659*da0073e9SAndroid Build Coastguard Worker bool BecameZero = false; 660*da0073e9SAndroid Build Coastguard Worker changed |= Iter1->intersectWithComplement(*Iter2, BecameZero); 661*da0073e9SAndroid Build Coastguard Worker if (BecameZero) { 662*da0073e9SAndroid Build Coastguard Worker ElementListIter IterTmp = Iter1; 663*da0073e9SAndroid Build Coastguard Worker ++Iter1; 664*da0073e9SAndroid Build Coastguard Worker Elements.erase(IterTmp); 665*da0073e9SAndroid Build Coastguard Worker } else { 666*da0073e9SAndroid Build Coastguard Worker ++Iter1; 667*da0073e9SAndroid Build Coastguard Worker } 668*da0073e9SAndroid Build Coastguard Worker ++Iter2; 669*da0073e9SAndroid Build Coastguard Worker } else { 670*da0073e9SAndroid Build Coastguard Worker ++Iter1; 671*da0073e9SAndroid Build Coastguard Worker } 672*da0073e9SAndroid Build Coastguard Worker } 673*da0073e9SAndroid Build Coastguard Worker CurrElementIter = Elements.begin(); 674*da0073e9SAndroid Build Coastguard Worker return changed; 675*da0073e9SAndroid Build Coastguard Worker } 676*da0073e9SAndroid Build Coastguard Worker intersectWithComplement(const SparseBitVector<ElementSize> * RHS)677*da0073e9SAndroid Build Coastguard Worker bool intersectWithComplement(const SparseBitVector<ElementSize>* RHS) const { 678*da0073e9SAndroid Build Coastguard Worker return intersectWithComplement(*RHS); 679*da0073e9SAndroid Build Coastguard Worker } 680*da0073e9SAndroid Build Coastguard Worker 681*da0073e9SAndroid Build Coastguard Worker // Three argument version of intersectWithComplement. 682*da0073e9SAndroid Build Coastguard Worker // Result of RHS1 & ~RHS2 is stored into this bitmap. intersectWithComplement(const SparseBitVector<ElementSize> & RHS1,const SparseBitVector<ElementSize> & RHS2)683*da0073e9SAndroid Build Coastguard Worker void intersectWithComplement( 684*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>& RHS1, 685*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>& RHS2) { 686*da0073e9SAndroid Build Coastguard Worker if (this == &RHS1) { 687*da0073e9SAndroid Build Coastguard Worker intersectWithComplement(RHS2); 688*da0073e9SAndroid Build Coastguard Worker return; 689*da0073e9SAndroid Build Coastguard Worker } else if (this == &RHS2) { 690*da0073e9SAndroid Build Coastguard Worker SparseBitVector RHS2Copy(RHS2); 691*da0073e9SAndroid Build Coastguard Worker intersectWithComplement(RHS1, RHS2Copy); 692*da0073e9SAndroid Build Coastguard Worker return; 693*da0073e9SAndroid Build Coastguard Worker } 694*da0073e9SAndroid Build Coastguard Worker 695*da0073e9SAndroid Build Coastguard Worker Elements.clear(); 696*da0073e9SAndroid Build Coastguard Worker CurrElementIter = Elements.begin(); 697*da0073e9SAndroid Build Coastguard Worker ElementListConstIter Iter1 = RHS1.Elements.begin(); 698*da0073e9SAndroid Build Coastguard Worker ElementListConstIter Iter2 = RHS2.Elements.begin(); 699*da0073e9SAndroid Build Coastguard Worker 700*da0073e9SAndroid Build Coastguard Worker // If RHS1 is empty, we are done 701*da0073e9SAndroid Build Coastguard Worker // If RHS2 is empty, we still have to copy RHS1 702*da0073e9SAndroid Build Coastguard Worker if (RHS1.Elements.empty()) 703*da0073e9SAndroid Build Coastguard Worker return; 704*da0073e9SAndroid Build Coastguard Worker 705*da0073e9SAndroid Build Coastguard Worker // Loop through, intersecting as we go, erasing elements when necessary. 706*da0073e9SAndroid Build Coastguard Worker while (Iter2 != RHS2.Elements.end()) { 707*da0073e9SAndroid Build Coastguard Worker if (Iter1 == RHS1.Elements.end()) 708*da0073e9SAndroid Build Coastguard Worker return; 709*da0073e9SAndroid Build Coastguard Worker 710*da0073e9SAndroid Build Coastguard Worker if (Iter1->index() > Iter2->index()) { 711*da0073e9SAndroid Build Coastguard Worker ++Iter2; 712*da0073e9SAndroid Build Coastguard Worker } else if (Iter1->index() == Iter2->index()) { 713*da0073e9SAndroid Build Coastguard Worker bool BecameZero = false; 714*da0073e9SAndroid Build Coastguard Worker Elements.emplace_back(Iter1->index()); 715*da0073e9SAndroid Build Coastguard Worker Elements.back().intersectWithComplement(*Iter1, *Iter2, BecameZero); 716*da0073e9SAndroid Build Coastguard Worker if (BecameZero) 717*da0073e9SAndroid Build Coastguard Worker Elements.pop_back(); 718*da0073e9SAndroid Build Coastguard Worker ++Iter1; 719*da0073e9SAndroid Build Coastguard Worker ++Iter2; 720*da0073e9SAndroid Build Coastguard Worker } else { 721*da0073e9SAndroid Build Coastguard Worker Elements.push_back(*Iter1++); 722*da0073e9SAndroid Build Coastguard Worker } 723*da0073e9SAndroid Build Coastguard Worker } 724*da0073e9SAndroid Build Coastguard Worker 725*da0073e9SAndroid Build Coastguard Worker // copy the remaining elements 726*da0073e9SAndroid Build Coastguard Worker std::copy(Iter1, RHS1.Elements.end(), std::back_inserter(Elements)); 727*da0073e9SAndroid Build Coastguard Worker } 728*da0073e9SAndroid Build Coastguard Worker intersectWithComplement(const SparseBitVector<ElementSize> * RHS1,const SparseBitVector<ElementSize> * RHS2)729*da0073e9SAndroid Build Coastguard Worker void intersectWithComplement( 730*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>* RHS1, 731*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>* RHS2) { 732*da0073e9SAndroid Build Coastguard Worker intersectWithComplement(*RHS1, *RHS2); 733*da0073e9SAndroid Build Coastguard Worker } 734*da0073e9SAndroid Build Coastguard Worker intersects(const SparseBitVector<ElementSize> * RHS)735*da0073e9SAndroid Build Coastguard Worker bool intersects(const SparseBitVector<ElementSize>* RHS) const { 736*da0073e9SAndroid Build Coastguard Worker return intersects(*RHS); 737*da0073e9SAndroid Build Coastguard Worker } 738*da0073e9SAndroid Build Coastguard Worker 739*da0073e9SAndroid Build Coastguard Worker // Return true if we share any bits in common with RHS intersects(const SparseBitVector<ElementSize> & RHS)740*da0073e9SAndroid Build Coastguard Worker bool intersects(const SparseBitVector<ElementSize>& RHS) const { 741*da0073e9SAndroid Build Coastguard Worker ElementListConstIter Iter1 = Elements.begin(); 742*da0073e9SAndroid Build Coastguard Worker ElementListConstIter Iter2 = RHS.Elements.begin(); 743*da0073e9SAndroid Build Coastguard Worker 744*da0073e9SAndroid Build Coastguard Worker // Check if both bitmaps are empty. 745*da0073e9SAndroid Build Coastguard Worker if (Elements.empty() && RHS.Elements.empty()) 746*da0073e9SAndroid Build Coastguard Worker return false; 747*da0073e9SAndroid Build Coastguard Worker 748*da0073e9SAndroid Build Coastguard Worker // Loop through, intersecting stopping when we hit bits in common. 749*da0073e9SAndroid Build Coastguard Worker while (Iter2 != RHS.Elements.end()) { 750*da0073e9SAndroid Build Coastguard Worker if (Iter1 == Elements.end()) 751*da0073e9SAndroid Build Coastguard Worker return false; 752*da0073e9SAndroid Build Coastguard Worker 753*da0073e9SAndroid Build Coastguard Worker if (Iter1->index() > Iter2->index()) { 754*da0073e9SAndroid Build Coastguard Worker ++Iter2; 755*da0073e9SAndroid Build Coastguard Worker } else if (Iter1->index() == Iter2->index()) { 756*da0073e9SAndroid Build Coastguard Worker if (Iter1->intersects(*Iter2)) 757*da0073e9SAndroid Build Coastguard Worker return true; 758*da0073e9SAndroid Build Coastguard Worker ++Iter1; 759*da0073e9SAndroid Build Coastguard Worker ++Iter2; 760*da0073e9SAndroid Build Coastguard Worker } else { 761*da0073e9SAndroid Build Coastguard Worker ++Iter1; 762*da0073e9SAndroid Build Coastguard Worker } 763*da0073e9SAndroid Build Coastguard Worker } 764*da0073e9SAndroid Build Coastguard Worker return false; 765*da0073e9SAndroid Build Coastguard Worker } 766*da0073e9SAndroid Build Coastguard Worker 767*da0073e9SAndroid Build Coastguard Worker // Return true iff all bits set in this SparseBitVector are 768*da0073e9SAndroid Build Coastguard Worker // also set in RHS. contains(const SparseBitVector<ElementSize> & RHS)769*da0073e9SAndroid Build Coastguard Worker bool contains(const SparseBitVector<ElementSize>& RHS) const { 770*da0073e9SAndroid Build Coastguard Worker SparseBitVector<ElementSize> Result(*this); 771*da0073e9SAndroid Build Coastguard Worker Result &= RHS; 772*da0073e9SAndroid Build Coastguard Worker return (Result == RHS); 773*da0073e9SAndroid Build Coastguard Worker } 774*da0073e9SAndroid Build Coastguard Worker 775*da0073e9SAndroid Build Coastguard Worker // Return the first set bit in the bitmap. Return -1 if no bits are set. find_first()776*da0073e9SAndroid Build Coastguard Worker int find_first() const { 777*da0073e9SAndroid Build Coastguard Worker if (Elements.empty()) 778*da0073e9SAndroid Build Coastguard Worker return -1; 779*da0073e9SAndroid Build Coastguard Worker const SparseBitVectorElement<ElementSize>& First = *(Elements.begin()); 780*da0073e9SAndroid Build Coastguard Worker return (First.index() * ElementSize) + First.find_first(); 781*da0073e9SAndroid Build Coastguard Worker } 782*da0073e9SAndroid Build Coastguard Worker 783*da0073e9SAndroid Build Coastguard Worker // Return the last set bit in the bitmap. Return -1 if no bits are set. find_last()784*da0073e9SAndroid Build Coastguard Worker int find_last() const { 785*da0073e9SAndroid Build Coastguard Worker if (Elements.empty()) 786*da0073e9SAndroid Build Coastguard Worker return -1; 787*da0073e9SAndroid Build Coastguard Worker const SparseBitVectorElement<ElementSize>& Last = *(Elements.rbegin()); 788*da0073e9SAndroid Build Coastguard Worker return (Last.index() * ElementSize) + Last.find_last(); 789*da0073e9SAndroid Build Coastguard Worker } 790*da0073e9SAndroid Build Coastguard Worker 791*da0073e9SAndroid Build Coastguard Worker // Return true if the SparseBitVector is empty empty()792*da0073e9SAndroid Build Coastguard Worker bool empty() const { 793*da0073e9SAndroid Build Coastguard Worker return Elements.empty(); 794*da0073e9SAndroid Build Coastguard Worker } 795*da0073e9SAndroid Build Coastguard Worker count()796*da0073e9SAndroid Build Coastguard Worker unsigned count() const { 797*da0073e9SAndroid Build Coastguard Worker unsigned BitCount = 0; 798*da0073e9SAndroid Build Coastguard Worker for (ElementListConstIter Iter = Elements.begin(); Iter != Elements.end(); 799*da0073e9SAndroid Build Coastguard Worker ++Iter) 800*da0073e9SAndroid Build Coastguard Worker BitCount += Iter->count(); 801*da0073e9SAndroid Build Coastguard Worker 802*da0073e9SAndroid Build Coastguard Worker return BitCount; 803*da0073e9SAndroid Build Coastguard Worker } 804*da0073e9SAndroid Build Coastguard Worker begin()805*da0073e9SAndroid Build Coastguard Worker iterator begin() const { 806*da0073e9SAndroid Build Coastguard Worker return iterator(this); 807*da0073e9SAndroid Build Coastguard Worker } 808*da0073e9SAndroid Build Coastguard Worker end()809*da0073e9SAndroid Build Coastguard Worker iterator end() const { 810*da0073e9SAndroid Build Coastguard Worker return iterator(this, true); 811*da0073e9SAndroid Build Coastguard Worker } 812*da0073e9SAndroid Build Coastguard Worker }; 813*da0073e9SAndroid Build Coastguard Worker 814*da0073e9SAndroid Build Coastguard Worker // Convenience functions to allow Or and And without dereferencing in the user 815*da0073e9SAndroid Build Coastguard Worker // code. 816*da0073e9SAndroid Build Coastguard Worker 817*da0073e9SAndroid Build Coastguard Worker template <unsigned ElementSize> 818*da0073e9SAndroid Build Coastguard Worker inline bool operator|=( 819*da0073e9SAndroid Build Coastguard Worker SparseBitVector<ElementSize>& LHS, 820*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>* RHS) { 821*da0073e9SAndroid Build Coastguard Worker return LHS |= *RHS; 822*da0073e9SAndroid Build Coastguard Worker } 823*da0073e9SAndroid Build Coastguard Worker 824*da0073e9SAndroid Build Coastguard Worker template <unsigned ElementSize> 825*da0073e9SAndroid Build Coastguard Worker inline bool operator|=( 826*da0073e9SAndroid Build Coastguard Worker SparseBitVector<ElementSize>* LHS, 827*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>& RHS) { 828*da0073e9SAndroid Build Coastguard Worker return LHS->operator|=(RHS); 829*da0073e9SAndroid Build Coastguard Worker } 830*da0073e9SAndroid Build Coastguard Worker 831*da0073e9SAndroid Build Coastguard Worker template <unsigned ElementSize> 832*da0073e9SAndroid Build Coastguard Worker inline bool operator&=( 833*da0073e9SAndroid Build Coastguard Worker SparseBitVector<ElementSize>* LHS, 834*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>& RHS) { 835*da0073e9SAndroid Build Coastguard Worker return LHS->operator&=(RHS); 836*da0073e9SAndroid Build Coastguard Worker } 837*da0073e9SAndroid Build Coastguard Worker 838*da0073e9SAndroid Build Coastguard Worker template <unsigned ElementSize> 839*da0073e9SAndroid Build Coastguard Worker inline bool operator&=( 840*da0073e9SAndroid Build Coastguard Worker SparseBitVector<ElementSize>& LHS, 841*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>* RHS) { 842*da0073e9SAndroid Build Coastguard Worker return LHS &= *RHS; 843*da0073e9SAndroid Build Coastguard Worker } 844*da0073e9SAndroid Build Coastguard Worker 845*da0073e9SAndroid Build Coastguard Worker // Convenience functions for infix union, intersection, difference operators. 846*da0073e9SAndroid Build Coastguard Worker 847*da0073e9SAndroid Build Coastguard Worker template <unsigned ElementSize> 848*da0073e9SAndroid Build Coastguard Worker inline SparseBitVector<ElementSize> operator|( 849*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>& LHS, 850*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>& RHS) { 851*da0073e9SAndroid Build Coastguard Worker SparseBitVector<ElementSize> Result(LHS); 852*da0073e9SAndroid Build Coastguard Worker Result |= RHS; 853*da0073e9SAndroid Build Coastguard Worker return Result; 854*da0073e9SAndroid Build Coastguard Worker } 855*da0073e9SAndroid Build Coastguard Worker 856*da0073e9SAndroid Build Coastguard Worker template <unsigned ElementSize> 857*da0073e9SAndroid Build Coastguard Worker inline SparseBitVector<ElementSize> operator&( 858*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>& LHS, 859*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>& RHS) { 860*da0073e9SAndroid Build Coastguard Worker SparseBitVector<ElementSize> Result(LHS); 861*da0073e9SAndroid Build Coastguard Worker Result &= RHS; 862*da0073e9SAndroid Build Coastguard Worker return Result; 863*da0073e9SAndroid Build Coastguard Worker } 864*da0073e9SAndroid Build Coastguard Worker 865*da0073e9SAndroid Build Coastguard Worker template <unsigned ElementSize> 866*da0073e9SAndroid Build Coastguard Worker inline SparseBitVector<ElementSize> operator-( 867*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>& LHS, 868*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>& RHS) { 869*da0073e9SAndroid Build Coastguard Worker SparseBitVector<ElementSize> Result; 870*da0073e9SAndroid Build Coastguard Worker Result.intersectWithComplement(LHS, RHS); 871*da0073e9SAndroid Build Coastguard Worker return Result; 872*da0073e9SAndroid Build Coastguard Worker } 873*da0073e9SAndroid Build Coastguard Worker 874*da0073e9SAndroid Build Coastguard Worker template <unsigned ElementSize> 875*da0073e9SAndroid Build Coastguard Worker std::ostream& operator<<( 876*da0073e9SAndroid Build Coastguard Worker std::ostream& stream, 877*da0073e9SAndroid Build Coastguard Worker const SparseBitVector<ElementSize>& vec) { 878*da0073e9SAndroid Build Coastguard Worker bool first = true; 879*da0073e9SAndroid Build Coastguard Worker stream << "{"; 880*da0073e9SAndroid Build Coastguard Worker for (auto el : vec) { 881*da0073e9SAndroid Build Coastguard Worker if (first) { 882*da0073e9SAndroid Build Coastguard Worker first = false; 883*da0073e9SAndroid Build Coastguard Worker } else { 884*da0073e9SAndroid Build Coastguard Worker stream << ", "; 885*da0073e9SAndroid Build Coastguard Worker } 886*da0073e9SAndroid Build Coastguard Worker stream << el; 887*da0073e9SAndroid Build Coastguard Worker } 888*da0073e9SAndroid Build Coastguard Worker stream << "}"; 889*da0073e9SAndroid Build Coastguard Worker return stream; 890*da0073e9SAndroid Build Coastguard Worker } 891*da0073e9SAndroid Build Coastguard Worker 892*da0073e9SAndroid Build Coastguard Worker } // end namespace c10 893