CoalescingBitVector.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. //===- llvm/ADT/CoalescingBitVector.h - A coalescing bitvector --*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. ///
  9. /// \file A bitvector that uses an IntervalMap to coalesce adjacent elements
  10. /// into intervals.
  11. ///
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_ADT_COALESCINGBITVECTOR_H
  14. #define LLVM_ADT_COALESCINGBITVECTOR_H
  15. #include "llvm/ADT/IntervalMap.h"
  16. #include "llvm/ADT/SmallVector.h"
  17. #include "llvm/ADT/iterator_range.h"
  18. #include "llvm/Support/Debug.h"
  19. #include "llvm/Support/raw_ostream.h"
  20. #include <algorithm>
  21. #include <initializer_list>
  22. namespace llvm {
  23. /// A bitvector that, under the hood, relies on an IntervalMap to coalesce
  24. /// elements into intervals. Good for representing sets which predominantly
  25. /// contain contiguous ranges. Bad for representing sets with lots of gaps
  26. /// between elements.
  27. ///
  28. /// Compared to SparseBitVector, CoalescingBitVector offers more predictable
  29. /// performance for non-sequential find() operations.
  30. ///
  31. /// \tparam IndexT - The type of the index into the bitvector.
  32. template <typename IndexT> class CoalescingBitVector {
  33. static_assert(std::is_unsigned<IndexT>::value,
  34. "Index must be an unsigned integer.");
  35. using ThisT = CoalescingBitVector<IndexT>;
  36. /// An interval map for closed integer ranges. The mapped values are unused.
  37. using MapT = IntervalMap<IndexT, char>;
  38. using UnderlyingIterator = typename MapT::const_iterator;
  39. using IntervalT = std::pair<IndexT, IndexT>;
  40. public:
  41. using Allocator = typename MapT::Allocator;
  42. /// Construct by passing in a CoalescingBitVector<IndexT>::Allocator
  43. /// reference.
  44. CoalescingBitVector(Allocator &Alloc)
  45. : Alloc(&Alloc), Intervals(Alloc) {}
  46. /// \name Copy/move constructors and assignment operators.
  47. /// @{
  48. CoalescingBitVector(const ThisT &Other)
  49. : Alloc(Other.Alloc), Intervals(*Other.Alloc) {
  50. set(Other);
  51. }
  52. ThisT &operator=(const ThisT &Other) {
  53. clear();
  54. set(Other);
  55. return *this;
  56. }
  57. CoalescingBitVector(ThisT &&Other) = delete;
  58. ThisT &operator=(ThisT &&Other) = delete;
  59. /// @}
  60. /// Clear all the bits.
  61. void clear() { Intervals.clear(); }
  62. /// Check whether no bits are set.
  63. bool empty() const { return Intervals.empty(); }
  64. /// Count the number of set bits.
  65. unsigned count() const {
  66. unsigned Bits = 0;
  67. for (auto It = Intervals.begin(), End = Intervals.end(); It != End; ++It)
  68. Bits += 1 + It.stop() - It.start();
  69. return Bits;
  70. }
  71. /// Set the bit at \p Index.
  72. ///
  73. /// This method does /not/ support setting a bit that has already been set,
  74. /// for efficiency reasons. If possible, restructure your code to not set the
  75. /// same bit multiple times, or use \ref test_and_set.
  76. void set(IndexT Index) {
  77. assert(!test(Index) && "Setting already-set bits not supported/efficient, "
  78. "IntervalMap will assert");
  79. insert(Index, Index);
  80. }
  81. /// Set the bits set in \p Other.
  82. ///
  83. /// This method does /not/ support setting already-set bits, see \ref set
  84. /// for the rationale. For a safe set union operation, use \ref operator|=.
  85. void set(const ThisT &Other) {
  86. for (auto It = Other.Intervals.begin(), End = Other.Intervals.end();
  87. It != End; ++It)
  88. insert(It.start(), It.stop());
  89. }
  90. /// Set the bits at \p Indices. Used for testing, primarily.
  91. void set(std::initializer_list<IndexT> Indices) {
  92. for (IndexT Index : Indices)
  93. set(Index);
  94. }
  95. /// Check whether the bit at \p Index is set.
  96. bool test(IndexT Index) const {
  97. const auto It = Intervals.find(Index);
  98. if (It == Intervals.end())
  99. return false;
  100. assert(It.stop() >= Index && "Interval must end after Index");
  101. return It.start() <= Index;
  102. }
  103. /// Set the bit at \p Index. Supports setting an already-set bit.
  104. void test_and_set(IndexT Index) {
  105. if (!test(Index))
  106. set(Index);
  107. }
  108. /// Reset the bit at \p Index. Supports resetting an already-unset bit.
  109. void reset(IndexT Index) {
  110. auto It = Intervals.find(Index);
  111. if (It == Intervals.end())
  112. return;
  113. // Split the interval containing Index into up to two parts: one from
  114. // [Start, Index-1] and another from [Index+1, Stop]. If Index is equal to
  115. // either Start or Stop, we create one new interval. If Index is equal to
  116. // both Start and Stop, we simply erase the existing interval.
  117. IndexT Start = It.start();
  118. if (Index < Start)
  119. // The index was not set.
  120. return;
  121. IndexT Stop = It.stop();
  122. assert(Index <= Stop && "Wrong interval for index");
  123. It.erase();
  124. if (Start < Index)
  125. insert(Start, Index - 1);
  126. if (Index < Stop)
  127. insert(Index + 1, Stop);
  128. }
  129. /// Set union. If \p RHS is guaranteed to not overlap with this, \ref set may
  130. /// be a faster alternative.
  131. void operator|=(const ThisT &RHS) {
  132. // Get the overlaps between the two interval maps.
  133. SmallVector<IntervalT, 8> Overlaps;
  134. getOverlaps(RHS, Overlaps);
  135. // Insert the non-overlapping parts of all the intervals from RHS.
  136. for (auto It = RHS.Intervals.begin(), End = RHS.Intervals.end();
  137. It != End; ++It) {
  138. IndexT Start = It.start();
  139. IndexT Stop = It.stop();
  140. SmallVector<IntervalT, 8> NonOverlappingParts;
  141. getNonOverlappingParts(Start, Stop, Overlaps, NonOverlappingParts);
  142. for (IntervalT AdditivePortion : NonOverlappingParts)
  143. insert(AdditivePortion.first, AdditivePortion.second);
  144. }
  145. }
  146. /// Set intersection.
  147. void operator&=(const ThisT &RHS) {
  148. // Get the overlaps between the two interval maps (i.e. the intersection).
  149. SmallVector<IntervalT, 8> Overlaps;
  150. getOverlaps(RHS, Overlaps);
  151. // Rebuild the interval map, including only the overlaps.
  152. clear();
  153. for (IntervalT Overlap : Overlaps)
  154. insert(Overlap.first, Overlap.second);
  155. }
  156. /// Reset all bits present in \p Other.
  157. void intersectWithComplement(const ThisT &Other) {
  158. SmallVector<IntervalT, 8> Overlaps;
  159. if (!getOverlaps(Other, Overlaps)) {
  160. // If there is no overlap with Other, the intersection is empty.
  161. return;
  162. }
  163. // Delete the overlapping intervals. Split up intervals that only partially
  164. // intersect an overlap.
  165. for (IntervalT Overlap : Overlaps) {
  166. IndexT OlapStart, OlapStop;
  167. std::tie(OlapStart, OlapStop) = Overlap;
  168. auto It = Intervals.find(OlapStart);
  169. IndexT CurrStart = It.start();
  170. IndexT CurrStop = It.stop();
  171. assert(CurrStart <= OlapStart && OlapStop <= CurrStop &&
  172. "Expected some intersection!");
  173. // Split the overlap interval into up to two parts: one from [CurrStart,
  174. // OlapStart-1] and another from [OlapStop+1, CurrStop]. If OlapStart is
  175. // equal to CurrStart, the first split interval is unnecessary. Ditto for
  176. // when OlapStop is equal to CurrStop, we omit the second split interval.
  177. It.erase();
  178. if (CurrStart < OlapStart)
  179. insert(CurrStart, OlapStart - 1);
  180. if (OlapStop < CurrStop)
  181. insert(OlapStop + 1, CurrStop);
  182. }
  183. }
  184. bool operator==(const ThisT &RHS) const {
  185. // We cannot just use std::equal because it checks the dereferenced values
  186. // of an iterator pair for equality, not the iterators themselves. In our
  187. // case that results in comparison of the (unused) IntervalMap values.
  188. auto ItL = Intervals.begin();
  189. auto ItR = RHS.Intervals.begin();
  190. while (ItL != Intervals.end() && ItR != RHS.Intervals.end() &&
  191. ItL.start() == ItR.start() && ItL.stop() == ItR.stop()) {
  192. ++ItL;
  193. ++ItR;
  194. }
  195. return ItL == Intervals.end() && ItR == RHS.Intervals.end();
  196. }
  197. bool operator!=(const ThisT &RHS) const { return !operator==(RHS); }
  198. class const_iterator {
  199. friend class CoalescingBitVector;
  200. public:
  201. using iterator_category = std::forward_iterator_tag;
  202. using value_type = IndexT;
  203. using difference_type = std::ptrdiff_t;
  204. using pointer = value_type *;
  205. using reference = value_type &;
  206. private:
  207. // For performance reasons, make the offset at the end different than the
  208. // one used in \ref begin, to optimize the common `It == end()` pattern.
  209. static constexpr unsigned kIteratorAtTheEndOffset = ~0u;
  210. UnderlyingIterator MapIterator;
  211. unsigned OffsetIntoMapIterator = 0;
  212. // Querying the start/stop of an IntervalMap iterator can be very expensive.
  213. // Cache these values for performance reasons.
  214. IndexT CachedStart = IndexT();
  215. IndexT CachedStop = IndexT();
  216. void setToEnd() {
  217. OffsetIntoMapIterator = kIteratorAtTheEndOffset;
  218. CachedStart = IndexT();
  219. CachedStop = IndexT();
  220. }
  221. /// MapIterator has just changed, reset the cached state to point to the
  222. /// start of the new underlying iterator.
  223. void resetCache() {
  224. if (MapIterator.valid()) {
  225. OffsetIntoMapIterator = 0;
  226. CachedStart = MapIterator.start();
  227. CachedStop = MapIterator.stop();
  228. } else {
  229. setToEnd();
  230. }
  231. }
  232. /// Advance the iterator to \p Index, if it is contained within the current
  233. /// interval. The public-facing method which supports advancing past the
  234. /// current interval is \ref advanceToLowerBound.
  235. void advanceTo(IndexT Index) {
  236. assert(Index <= CachedStop && "Cannot advance to OOB index");
  237. if (Index < CachedStart)
  238. // We're already past this index.
  239. return;
  240. OffsetIntoMapIterator = Index - CachedStart;
  241. }
  242. const_iterator(UnderlyingIterator MapIt) : MapIterator(MapIt) {
  243. resetCache();
  244. }
  245. public:
  246. const_iterator() { setToEnd(); }
  247. bool operator==(const const_iterator &RHS) const {
  248. // Do /not/ compare MapIterator for equality, as this is very expensive.
  249. // The cached start/stop values make that check unnecessary.
  250. return std::tie(OffsetIntoMapIterator, CachedStart, CachedStop) ==
  251. std::tie(RHS.OffsetIntoMapIterator, RHS.CachedStart,
  252. RHS.CachedStop);
  253. }
  254. bool operator!=(const const_iterator &RHS) const {
  255. return !operator==(RHS);
  256. }
  257. IndexT operator*() const { return CachedStart + OffsetIntoMapIterator; }
  258. const_iterator &operator++() { // Pre-increment (++It).
  259. if (CachedStart + OffsetIntoMapIterator < CachedStop) {
  260. // Keep going within the current interval.
  261. ++OffsetIntoMapIterator;
  262. } else {
  263. // We reached the end of the current interval: advance.
  264. ++MapIterator;
  265. resetCache();
  266. }
  267. return *this;
  268. }
  269. const_iterator operator++(int) { // Post-increment (It++).
  270. const_iterator tmp = *this;
  271. operator++();
  272. return tmp;
  273. }
  274. /// Advance the iterator to the first set bit AT, OR AFTER, \p Index. If
  275. /// no such set bit exists, advance to end(). This is like std::lower_bound.
  276. /// This is useful if \p Index is close to the current iterator position.
  277. /// However, unlike \ref find(), this has worst-case O(n) performance.
  278. void advanceToLowerBound(IndexT Index) {
  279. if (OffsetIntoMapIterator == kIteratorAtTheEndOffset)
  280. return;
  281. // Advance to the first interval containing (or past) Index, or to end().
  282. while (Index > CachedStop) {
  283. ++MapIterator;
  284. resetCache();
  285. if (OffsetIntoMapIterator == kIteratorAtTheEndOffset)
  286. return;
  287. }
  288. advanceTo(Index);
  289. }
  290. };
  291. const_iterator begin() const { return const_iterator(Intervals.begin()); }
  292. const_iterator end() const { return const_iterator(); }
  293. /// Return an iterator pointing to the first set bit AT, OR AFTER, \p Index.
  294. /// If no such set bit exists, return end(). This is like std::lower_bound.
  295. /// This has worst-case logarithmic performance (roughly O(log(gaps between
  296. /// contiguous ranges))).
  297. const_iterator find(IndexT Index) const {
  298. auto UnderlyingIt = Intervals.find(Index);
  299. if (UnderlyingIt == Intervals.end())
  300. return end();
  301. auto It = const_iterator(UnderlyingIt);
  302. It.advanceTo(Index);
  303. return It;
  304. }
  305. /// Return a range iterator which iterates over all of the set bits in the
  306. /// half-open range [Start, End).
  307. iterator_range<const_iterator> half_open_range(IndexT Start,
  308. IndexT End) const {
  309. assert(Start < End && "Not a valid range");
  310. auto StartIt = find(Start);
  311. if (StartIt == end() || *StartIt >= End)
  312. return {end(), end()};
  313. auto EndIt = StartIt;
  314. EndIt.advanceToLowerBound(End);
  315. return {StartIt, EndIt};
  316. }
  317. void print(raw_ostream &OS) const {
  318. OS << "{";
  319. for (auto It = Intervals.begin(), End = Intervals.end(); It != End;
  320. ++It) {
  321. OS << "[" << It.start();
  322. if (It.start() != It.stop())
  323. OS << ", " << It.stop();
  324. OS << "]";
  325. }
  326. OS << "}";
  327. }
  328. #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
  329. LLVM_DUMP_METHOD void dump() const {
  330. // LLDB swallows the first line of output after callling dump(). Add
  331. // newlines before/after the braces to work around this.
  332. dbgs() << "\n";
  333. print(dbgs());
  334. dbgs() << "\n";
  335. }
  336. #endif
  337. private:
  338. void insert(IndexT Start, IndexT End) { Intervals.insert(Start, End, 0); }
  339. /// Record the overlaps between \p this and \p Other in \p Overlaps. Return
  340. /// true if there is any overlap.
  341. bool getOverlaps(const ThisT &Other,
  342. SmallVectorImpl<IntervalT> &Overlaps) const {
  343. for (IntervalMapOverlaps<MapT, MapT> I(Intervals, Other.Intervals);
  344. I.valid(); ++I)
  345. Overlaps.emplace_back(I.start(), I.stop());
  346. assert(llvm::is_sorted(Overlaps,
  347. [](IntervalT LHS, IntervalT RHS) {
  348. return LHS.second < RHS.first;
  349. }) &&
  350. "Overlaps must be sorted");
  351. return !Overlaps.empty();
  352. }
  353. /// Given the set of overlaps between this and some other bitvector, and an
  354. /// interval [Start, Stop] from that bitvector, determine the portions of the
  355. /// interval which do not overlap with this.
  356. void getNonOverlappingParts(IndexT Start, IndexT Stop,
  357. const SmallVectorImpl<IntervalT> &Overlaps,
  358. SmallVectorImpl<IntervalT> &NonOverlappingParts) {
  359. IndexT NextUncoveredBit = Start;
  360. for (IntervalT Overlap : Overlaps) {
  361. IndexT OlapStart, OlapStop;
  362. std::tie(OlapStart, OlapStop) = Overlap;
  363. // [Start;Stop] and [OlapStart;OlapStop] overlap iff OlapStart <= Stop
  364. // and Start <= OlapStop.
  365. bool DoesOverlap = OlapStart <= Stop && Start <= OlapStop;
  366. if (!DoesOverlap)
  367. continue;
  368. // Cover the range [NextUncoveredBit, OlapStart). This puts the start of
  369. // the next uncovered range at OlapStop+1.
  370. if (NextUncoveredBit < OlapStart)
  371. NonOverlappingParts.emplace_back(NextUncoveredBit, OlapStart - 1);
  372. NextUncoveredBit = OlapStop + 1;
  373. if (NextUncoveredBit > Stop)
  374. break;
  375. }
  376. if (NextUncoveredBit <= Stop)
  377. NonOverlappingParts.emplace_back(NextUncoveredBit, Stop);
  378. }
  379. Allocator *Alloc;
  380. MapT Intervals;
  381. };
  382. } // namespace llvm
  383. #endif // LLVM_ADT_COALESCINGBITVECTOR_H