Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:03

0001 //===- llvm/ADT/CoalescingBitVector.h - A coalescing bitvector --*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 ///
0009 /// \file
0010 /// A bitvector that uses an IntervalMap to coalesce adjacent elements
0011 /// into intervals.
0012 ///
0013 //===----------------------------------------------------------------------===//
0014 
0015 #ifndef LLVM_ADT_COALESCINGBITVECTOR_H
0016 #define LLVM_ADT_COALESCINGBITVECTOR_H
0017 
0018 #include "llvm/ADT/IntervalMap.h"
0019 #include "llvm/ADT/STLExtras.h"
0020 #include "llvm/ADT/SmallVector.h"
0021 #include "llvm/ADT/iterator_range.h"
0022 #include "llvm/Support/Debug.h"
0023 #include "llvm/Support/raw_ostream.h"
0024 
0025 #include <initializer_list>
0026 
0027 namespace llvm {
0028 
0029 /// A bitvector that, under the hood, relies on an IntervalMap to coalesce
0030 /// elements into intervals. Good for representing sets which predominantly
0031 /// contain contiguous ranges. Bad for representing sets with lots of gaps
0032 /// between elements.
0033 ///
0034 /// Compared to SparseBitVector, CoalescingBitVector offers more predictable
0035 /// performance for non-sequential find() operations.
0036 ///
0037 /// \tparam IndexT - The type of the index into the bitvector.
0038 template <typename IndexT> class CoalescingBitVector {
0039   static_assert(std::is_unsigned<IndexT>::value,
0040                 "Index must be an unsigned integer.");
0041 
0042   using ThisT = CoalescingBitVector<IndexT>;
0043 
0044   /// An interval map for closed integer ranges. The mapped values are unused.
0045   using MapT = IntervalMap<IndexT, char>;
0046 
0047   using UnderlyingIterator = typename MapT::const_iterator;
0048 
0049   using IntervalT = std::pair<IndexT, IndexT>;
0050 
0051 public:
0052   using Allocator = typename MapT::Allocator;
0053 
0054   /// Construct by passing in a CoalescingBitVector<IndexT>::Allocator
0055   /// reference.
0056   CoalescingBitVector(Allocator &Alloc)
0057       : Alloc(&Alloc), Intervals(Alloc) {}
0058 
0059   /// \name Copy/move constructors and assignment operators.
0060   /// @{
0061 
0062   CoalescingBitVector(const ThisT &Other)
0063       : Alloc(Other.Alloc), Intervals(*Other.Alloc) {
0064     set(Other);
0065   }
0066 
0067   ThisT &operator=(const ThisT &Other) {
0068     clear();
0069     set(Other);
0070     return *this;
0071   }
0072 
0073   CoalescingBitVector(ThisT &&Other) = delete;
0074   ThisT &operator=(ThisT &&Other) = delete;
0075 
0076   /// @}
0077 
0078   /// Clear all the bits.
0079   void clear() { Intervals.clear(); }
0080 
0081   /// Check whether no bits are set.
0082   bool empty() const { return Intervals.empty(); }
0083 
0084   /// Count the number of set bits.
0085   unsigned count() const {
0086     unsigned Bits = 0;
0087     for (auto It = Intervals.begin(), End = Intervals.end(); It != End; ++It)
0088       Bits += 1 + It.stop() - It.start();
0089     return Bits;
0090   }
0091 
0092   /// Set the bit at \p Index.
0093   ///
0094   /// This method does /not/ support setting a bit that has already been set,
0095   /// for efficiency reasons. If possible, restructure your code to not set the
0096   /// same bit multiple times, or use \ref test_and_set.
0097   void set(IndexT Index) {
0098     assert(!test(Index) && "Setting already-set bits not supported/efficient, "
0099                            "IntervalMap will assert");
0100     insert(Index, Index);
0101   }
0102 
0103   /// Set the bits set in \p Other.
0104   ///
0105   /// This method does /not/ support setting already-set bits, see \ref set
0106   /// for the rationale. For a safe set union operation, use \ref operator|=.
0107   void set(const ThisT &Other) {
0108     for (auto It = Other.Intervals.begin(), End = Other.Intervals.end();
0109          It != End; ++It)
0110       insert(It.start(), It.stop());
0111   }
0112 
0113   /// Set the bits at \p Indices. Used for testing, primarily.
0114   void set(std::initializer_list<IndexT> Indices) {
0115     for (IndexT Index : Indices)
0116       set(Index);
0117   }
0118 
0119   /// Check whether the bit at \p Index is set.
0120   bool test(IndexT Index) const {
0121     const auto It = Intervals.find(Index);
0122     if (It == Intervals.end())
0123       return false;
0124     assert(It.stop() >= Index && "Interval must end after Index");
0125     return It.start() <= Index;
0126   }
0127 
0128   /// Set the bit at \p Index. Supports setting an already-set bit.
0129   void test_and_set(IndexT Index) {
0130     if (!test(Index))
0131       set(Index);
0132   }
0133 
0134   /// Reset the bit at \p Index. Supports resetting an already-unset bit.
0135   void reset(IndexT Index) {
0136     auto It = Intervals.find(Index);
0137     if (It == Intervals.end())
0138       return;
0139 
0140     // Split the interval containing Index into up to two parts: one from
0141     // [Start, Index-1] and another from [Index+1, Stop]. If Index is equal to
0142     // either Start or Stop, we create one new interval. If Index is equal to
0143     // both Start and Stop, we simply erase the existing interval.
0144     IndexT Start = It.start();
0145     if (Index < Start)
0146       // The index was not set.
0147       return;
0148     IndexT Stop = It.stop();
0149     assert(Index <= Stop && "Wrong interval for index");
0150     It.erase();
0151     if (Start < Index)
0152       insert(Start, Index - 1);
0153     if (Index < Stop)
0154       insert(Index + 1, Stop);
0155   }
0156 
0157   /// Set union. If \p RHS is guaranteed to not overlap with this, \ref set may
0158   /// be a faster alternative.
0159   void operator|=(const ThisT &RHS) {
0160     // Get the overlaps between the two interval maps.
0161     SmallVector<IntervalT, 8> Overlaps;
0162     getOverlaps(RHS, Overlaps);
0163 
0164     // Insert the non-overlapping parts of all the intervals from RHS.
0165     for (auto It = RHS.Intervals.begin(), End = RHS.Intervals.end();
0166          It != End; ++It) {
0167       IndexT Start = It.start();
0168       IndexT Stop = It.stop();
0169       SmallVector<IntervalT, 8> NonOverlappingParts;
0170       getNonOverlappingParts(Start, Stop, Overlaps, NonOverlappingParts);
0171       for (IntervalT AdditivePortion : NonOverlappingParts)
0172         insert(AdditivePortion.first, AdditivePortion.second);
0173     }
0174   }
0175 
0176   /// Set intersection.
0177   void operator&=(const ThisT &RHS) {
0178     // Get the overlaps between the two interval maps (i.e. the intersection).
0179     SmallVector<IntervalT, 8> Overlaps;
0180     getOverlaps(RHS, Overlaps);
0181     // Rebuild the interval map, including only the overlaps.
0182     clear();
0183     for (IntervalT Overlap : Overlaps)
0184       insert(Overlap.first, Overlap.second);
0185   }
0186 
0187   /// Reset all bits present in \p Other.
0188   void intersectWithComplement(const ThisT &Other) {
0189     SmallVector<IntervalT, 8> Overlaps;
0190     if (!getOverlaps(Other, Overlaps)) {
0191       // If there is no overlap with Other, the intersection is empty.
0192       return;
0193     }
0194 
0195     // Delete the overlapping intervals. Split up intervals that only partially
0196     // intersect an overlap.
0197     for (IntervalT Overlap : Overlaps) {
0198       IndexT OlapStart, OlapStop;
0199       std::tie(OlapStart, OlapStop) = Overlap;
0200 
0201       auto It = Intervals.find(OlapStart);
0202       IndexT CurrStart = It.start();
0203       IndexT CurrStop = It.stop();
0204       assert(CurrStart <= OlapStart && OlapStop <= CurrStop &&
0205              "Expected some intersection!");
0206 
0207       // Split the overlap interval into up to two parts: one from [CurrStart,
0208       // OlapStart-1] and another from [OlapStop+1, CurrStop]. If OlapStart is
0209       // equal to CurrStart, the first split interval is unnecessary. Ditto for
0210       // when OlapStop is equal to CurrStop, we omit the second split interval.
0211       It.erase();
0212       if (CurrStart < OlapStart)
0213         insert(CurrStart, OlapStart - 1);
0214       if (OlapStop < CurrStop)
0215         insert(OlapStop + 1, CurrStop);
0216     }
0217   }
0218 
0219   bool operator==(const ThisT &RHS) const {
0220     // We cannot just use std::equal because it checks the dereferenced values
0221     // of an iterator pair for equality, not the iterators themselves. In our
0222     // case that results in comparison of the (unused) IntervalMap values.
0223     auto ItL = Intervals.begin();
0224     auto ItR = RHS.Intervals.begin();
0225     while (ItL != Intervals.end() && ItR != RHS.Intervals.end() &&
0226            ItL.start() == ItR.start() && ItL.stop() == ItR.stop()) {
0227       ++ItL;
0228       ++ItR;
0229     }
0230     return ItL == Intervals.end() && ItR == RHS.Intervals.end();
0231   }
0232 
0233   bool operator!=(const ThisT &RHS) const { return !operator==(RHS); }
0234 
0235   class const_iterator {
0236     friend class CoalescingBitVector;
0237 
0238   public:
0239     using iterator_category = std::forward_iterator_tag;
0240     using value_type = IndexT;
0241     using difference_type = std::ptrdiff_t;
0242     using pointer = value_type *;
0243     using reference = value_type &;
0244 
0245   private:
0246     // For performance reasons, make the offset at the end different than the
0247     // one used in \ref begin, to optimize the common `It == end()` pattern.
0248     static constexpr unsigned kIteratorAtTheEndOffset = ~0u;
0249 
0250     UnderlyingIterator MapIterator;
0251     unsigned OffsetIntoMapIterator = 0;
0252 
0253     // Querying the start/stop of an IntervalMap iterator can be very expensive.
0254     // Cache these values for performance reasons.
0255     IndexT CachedStart = IndexT();
0256     IndexT CachedStop = IndexT();
0257 
0258     void setToEnd() {
0259       OffsetIntoMapIterator = kIteratorAtTheEndOffset;
0260       CachedStart = IndexT();
0261       CachedStop = IndexT();
0262     }
0263 
0264     /// MapIterator has just changed, reset the cached state to point to the
0265     /// start of the new underlying iterator.
0266     void resetCache() {
0267       if (MapIterator.valid()) {
0268         OffsetIntoMapIterator = 0;
0269         CachedStart = MapIterator.start();
0270         CachedStop = MapIterator.stop();
0271       } else {
0272         setToEnd();
0273       }
0274     }
0275 
0276     /// Advance the iterator to \p Index, if it is contained within the current
0277     /// interval. The public-facing method which supports advancing past the
0278     /// current interval is \ref advanceToLowerBound.
0279     void advanceTo(IndexT Index) {
0280       assert(Index <= CachedStop && "Cannot advance to OOB index");
0281       if (Index < CachedStart)
0282         // We're already past this index.
0283         return;
0284       OffsetIntoMapIterator = Index - CachedStart;
0285     }
0286 
0287     const_iterator(UnderlyingIterator MapIt) : MapIterator(MapIt) {
0288       resetCache();
0289     }
0290 
0291   public:
0292     const_iterator() { setToEnd(); }
0293 
0294     bool operator==(const const_iterator &RHS) const {
0295       // Do /not/ compare MapIterator for equality, as this is very expensive.
0296       // The cached start/stop values make that check unnecessary.
0297       return std::tie(OffsetIntoMapIterator, CachedStart, CachedStop) ==
0298              std::tie(RHS.OffsetIntoMapIterator, RHS.CachedStart,
0299                       RHS.CachedStop);
0300     }
0301 
0302     bool operator!=(const const_iterator &RHS) const {
0303       return !operator==(RHS);
0304     }
0305 
0306     IndexT operator*() const { return CachedStart + OffsetIntoMapIterator; }
0307 
0308     const_iterator &operator++() { // Pre-increment (++It).
0309       if (CachedStart + OffsetIntoMapIterator < CachedStop) {
0310         // Keep going within the current interval.
0311         ++OffsetIntoMapIterator;
0312       } else {
0313         // We reached the end of the current interval: advance.
0314         ++MapIterator;
0315         resetCache();
0316       }
0317       return *this;
0318     }
0319 
0320     const_iterator operator++(int) { // Post-increment (It++).
0321       const_iterator tmp = *this;
0322       operator++();
0323       return tmp;
0324     }
0325 
0326     /// Advance the iterator to the first set bit AT, OR AFTER, \p Index. If
0327     /// no such set bit exists, advance to end(). This is like std::lower_bound.
0328     /// This is useful if \p Index is close to the current iterator position.
0329     /// However, unlike \ref find(), this has worst-case O(n) performance.
0330     void advanceToLowerBound(IndexT Index) {
0331       if (OffsetIntoMapIterator == kIteratorAtTheEndOffset)
0332         return;
0333 
0334       // Advance to the first interval containing (or past) Index, or to end().
0335       while (Index > CachedStop) {
0336         ++MapIterator;
0337         resetCache();
0338         if (OffsetIntoMapIterator == kIteratorAtTheEndOffset)
0339           return;
0340       }
0341 
0342       advanceTo(Index);
0343     }
0344   };
0345 
0346   const_iterator begin() const { return const_iterator(Intervals.begin()); }
0347 
0348   const_iterator end() const { return const_iterator(); }
0349 
0350   /// Return an iterator pointing to the first set bit AT, OR AFTER, \p Index.
0351   /// If no such set bit exists, return end(). This is like std::lower_bound.
0352   /// This has worst-case logarithmic performance (roughly O(log(gaps between
0353   /// contiguous ranges))).
0354   const_iterator find(IndexT Index) const {
0355     auto UnderlyingIt = Intervals.find(Index);
0356     if (UnderlyingIt == Intervals.end())
0357       return end();
0358     auto It = const_iterator(UnderlyingIt);
0359     It.advanceTo(Index);
0360     return It;
0361   }
0362 
0363   /// Return a range iterator which iterates over all of the set bits in the
0364   /// half-open range [Start, End).
0365   iterator_range<const_iterator> half_open_range(IndexT Start,
0366                                                  IndexT End) const {
0367     assert(Start < End && "Not a valid range");
0368     auto StartIt = find(Start);
0369     if (StartIt == end() || *StartIt >= End)
0370       return {end(), end()};
0371     auto EndIt = StartIt;
0372     EndIt.advanceToLowerBound(End);
0373     return {StartIt, EndIt};
0374   }
0375 
0376   void print(raw_ostream &OS) const {
0377     OS << "{";
0378     for (auto It = Intervals.begin(), End = Intervals.end(); It != End;
0379          ++It) {
0380       OS << "[" << It.start();
0381       if (It.start() != It.stop())
0382         OS << ", " << It.stop();
0383       OS << "]";
0384     }
0385     OS << "}";
0386   }
0387 
0388 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
0389   LLVM_DUMP_METHOD void dump() const {
0390     // LLDB swallows the first line of output after callling dump(). Add
0391     // newlines before/after the braces to work around this.
0392     dbgs() << "\n";
0393     print(dbgs());
0394     dbgs() << "\n";
0395   }
0396 #endif
0397 
0398 private:
0399   void insert(IndexT Start, IndexT End) { Intervals.insert(Start, End, 0); }
0400 
0401   /// Record the overlaps between \p this and \p Other in \p Overlaps. Return
0402   /// true if there is any overlap.
0403   bool getOverlaps(const ThisT &Other,
0404                    SmallVectorImpl<IntervalT> &Overlaps) const {
0405     for (IntervalMapOverlaps<MapT, MapT> I(Intervals, Other.Intervals);
0406          I.valid(); ++I)
0407       Overlaps.emplace_back(I.start(), I.stop());
0408     assert(llvm::is_sorted(Overlaps,
0409                            [](IntervalT LHS, IntervalT RHS) {
0410                              return LHS.second < RHS.first;
0411                            }) &&
0412            "Overlaps must be sorted");
0413     return !Overlaps.empty();
0414   }
0415 
0416   /// Given the set of overlaps between this and some other bitvector, and an
0417   /// interval [Start, Stop] from that bitvector, determine the portions of the
0418   /// interval which do not overlap with this.
0419   void getNonOverlappingParts(IndexT Start, IndexT Stop,
0420                               const SmallVectorImpl<IntervalT> &Overlaps,
0421                               SmallVectorImpl<IntervalT> &NonOverlappingParts) {
0422     IndexT NextUncoveredBit = Start;
0423     for (IntervalT Overlap : Overlaps) {
0424       IndexT OlapStart, OlapStop;
0425       std::tie(OlapStart, OlapStop) = Overlap;
0426 
0427       // [Start;Stop] and [OlapStart;OlapStop] overlap iff OlapStart <= Stop
0428       // and Start <= OlapStop.
0429       bool DoesOverlap = OlapStart <= Stop && Start <= OlapStop;
0430       if (!DoesOverlap)
0431         continue;
0432 
0433       // Cover the range [NextUncoveredBit, OlapStart). This puts the start of
0434       // the next uncovered range at OlapStop+1.
0435       if (NextUncoveredBit < OlapStart)
0436         NonOverlappingParts.emplace_back(NextUncoveredBit, OlapStart - 1);
0437       NextUncoveredBit = OlapStop + 1;
0438       if (NextUncoveredBit > Stop)
0439         break;
0440     }
0441     if (NextUncoveredBit <= Stop)
0442       NonOverlappingParts.emplace_back(NextUncoveredBit, Stop);
0443   }
0444 
0445   Allocator *Alloc;
0446   MapT Intervals;
0447 };
0448 
0449 } // namespace llvm
0450 
0451 #endif // LLVM_ADT_COALESCINGBITVECTOR_H