xref: /freebsd/contrib/llvm-project/lldb/include/lldb/Utility/RangeMap.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- RangeMap.h ----------------------------------------------*- 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 #ifndef LLDB_UTILITY_RANGEMAP_H
10 #define LLDB_UTILITY_RANGEMAP_H
11 
12 #include <algorithm>
13 #include <vector>
14 
15 #include "llvm/ADT/SmallVector.h"
16 
17 #include "lldb/lldb-private.h"
18 
19 // Uncomment to make sure all Range objects are sorted when needed
20 //#define ASSERT_RANGEMAP_ARE_SORTED
21 
22 namespace lldb_private {
23 
24 // Templatized classes for dealing with generic ranges and also collections of
25 // ranges, or collections of ranges that have associated data.
26 
27 // A simple range class where you get to define the type of the range
28 // base "B", and the type used for the range byte size "S".
29 template <typename B, typename S> struct Range {
30   typedef B BaseType;
31   typedef S SizeType;
32 
33   BaseType base;
34   SizeType size;
35 
RangeRange36   Range() : base(0), size(0) {}
37 
RangeRange38   Range(BaseType b, SizeType s) : base(b), size(s) {}
39 
40   void Clear(BaseType b = 0) {
41     base = b;
42     size = 0;
43   }
44 
GetRangeBaseRange45   BaseType GetRangeBase() const { return base; }
46 
47   /// Set the start value for the range, and keep the same size
SetRangeBaseRange48   void SetRangeBase(BaseType b) { base = b; }
49 
SlideRange50   void Slide(BaseType slide) { base += slide; }
51 
ShrinkFrontRange52   void ShrinkFront(S s) {
53     base += s;
54     size -= std::min(s, size);
55   }
56 
UnionRange57   bool Union(const Range &rhs) {
58     if (DoesAdjoinOrIntersect(rhs)) {
59       auto new_end = std::max<BaseType>(GetRangeEnd(), rhs.GetRangeEnd());
60       base = std::min<BaseType>(base, rhs.base);
61       size = new_end - base;
62       return true;
63     }
64     return false;
65   }
66 
IntersectRange67   Range Intersect(const Range &rhs) const {
68     const BaseType lhs_base = this->GetRangeBase();
69     const BaseType rhs_base = rhs.GetRangeBase();
70     const BaseType lhs_end = this->GetRangeEnd();
71     const BaseType rhs_end = rhs.GetRangeEnd();
72     Range range;
73     range.SetRangeBase(std::max(lhs_base, rhs_base));
74     range.SetRangeEnd(std::min(lhs_end, rhs_end));
75     return range;
76   }
77 
GetRangeEndRange78   BaseType GetRangeEnd() const { return base + size; }
79 
SetRangeEndRange80   void SetRangeEnd(BaseType end) {
81     if (end > base)
82       size = end - base;
83     else
84       size = 0;
85   }
86 
GetByteSizeRange87   SizeType GetByteSize() const { return size; }
88 
SetByteSizeRange89   void SetByteSize(SizeType s) { size = s; }
90 
IsValidRange91   bool IsValid() const { return size > 0; }
92 
ContainsRange93   bool Contains(BaseType r) const {
94     return (GetRangeBase() <= r) && (r < GetRangeEnd());
95   }
96 
ContainsEndInclusiveRange97   bool ContainsEndInclusive(BaseType r) const {
98     return (GetRangeBase() <= r) && (r <= GetRangeEnd());
99   }
100 
ContainsRange101   bool Contains(const Range &range) const {
102     return Contains(range.GetRangeBase()) &&
103            ContainsEndInclusive(range.GetRangeEnd());
104   }
105 
106   // Returns true if the two ranges adjoing or intersect
DoesAdjoinOrIntersectRange107   bool DoesAdjoinOrIntersect(const Range &rhs) const {
108     const BaseType lhs_base = this->GetRangeBase();
109     const BaseType rhs_base = rhs.GetRangeBase();
110     const BaseType lhs_end = this->GetRangeEnd();
111     const BaseType rhs_end = rhs.GetRangeEnd();
112     bool result = (lhs_base <= rhs_end) && (lhs_end >= rhs_base);
113     return result;
114   }
115 
116   // Returns true if the two ranges intersect
DoesIntersectRange117   bool DoesIntersect(const Range &rhs) const {
118     return Intersect(rhs).IsValid();
119   }
120 
121   bool operator<(const Range &rhs) const {
122     if (base == rhs.base)
123       return size < rhs.size;
124     return base < rhs.base;
125   }
126 
127   bool operator==(const Range &rhs) const {
128     return base == rhs.base && size == rhs.size;
129   }
130 
131   bool operator!=(const Range &rhs) const {
132     return base != rhs.base || size != rhs.size;
133   }
134 };
135 
136 template <typename B, typename S, unsigned N = 0> class RangeVector {
137 public:
138   typedef B BaseType;
139   typedef S SizeType;
140   typedef Range<B, S> Entry;
141   typedef llvm::SmallVector<Entry, N> Collection;
142 
143   RangeVector() = default;
144 
145   ~RangeVector() = default;
146 
GetOverlaps(const RangeVector & vec1,const RangeVector & vec2)147   static RangeVector GetOverlaps(const RangeVector &vec1,
148                                  const RangeVector &vec2) {
149 #ifdef ASSERT_RANGEMAP_ARE_SORTED
150     assert(vec1.IsSorted() && vec2.IsSorted());
151 #endif
152     RangeVector result;
153     auto pos1 = vec1.begin();
154     auto end1 = vec1.end();
155     auto pos2 = vec2.begin();
156     auto end2 = vec2.end();
157     while (pos1 != end1 && pos2 != end2) {
158       Entry entry = pos1->Intersect(*pos2);
159       if (entry.IsValid())
160         result.Append(entry);
161       if (pos1->GetRangeEnd() < pos2->GetRangeEnd())
162         ++pos1;
163       else
164         ++pos2;
165     }
166     return result;
167   }
168 
169   bool operator==(const RangeVector &rhs) const {
170     if (GetSize() != rhs.GetSize())
171       return false;
172     for (size_t i = 0; i < GetSize(); ++i) {
173       if (GetEntryRef(i) != rhs.GetEntryRef(i))
174         return false;
175     }
176     return true;
177   }
178 
Append(const Entry & entry)179   void Append(const Entry &entry) { m_entries.push_back(entry); }
180 
Append(B base,S size)181   void Append(B base, S size) { m_entries.emplace_back(base, size); }
182 
183   // Insert an item into a sorted list and optionally combine it with any
184   // adjacent blocks if requested.
Insert(const Entry & entry,bool combine)185   void Insert(const Entry &entry, bool combine) {
186     if (m_entries.empty()) {
187       m_entries.push_back(entry);
188       return;
189     }
190     auto begin = m_entries.begin();
191     auto end = m_entries.end();
192     auto pos = std::lower_bound(begin, end, entry);
193     if (combine) {
194       if (pos != end && pos->Union(entry)) {
195         CombinePrevAndNext(pos);
196         return;
197       }
198       if (pos != begin) {
199         auto prev = pos - 1;
200         if (prev->Union(entry)) {
201           CombinePrevAndNext(prev);
202           return;
203         }
204       }
205     }
206     m_entries.insert(pos, entry);
207   }
208 
RemoveEntryAtIndex(uint32_t idx)209   bool RemoveEntryAtIndex(uint32_t idx) {
210     if (idx < m_entries.size()) {
211       m_entries.erase(m_entries.begin() + idx);
212       return true;
213     }
214     return false;
215   }
216 
Sort()217   void Sort() {
218     if (m_entries.size() > 1)
219       llvm::stable_sort(m_entries);
220   }
221 
222 #ifdef ASSERT_RANGEMAP_ARE_SORTED
IsSorted()223   bool IsSorted() const {
224     typename Collection::const_iterator pos, end, prev;
225     // First we determine if we can combine any of the Entry objects so we
226     // don't end up allocating and making a new collection for no reason
227     for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end;
228          prev = pos++) {
229       if (prev != end && *pos < *prev)
230         return false;
231     }
232     return true;
233   }
234 #endif
235 
CombineConsecutiveRanges()236   void CombineConsecutiveRanges() {
237 #ifdef ASSERT_RANGEMAP_ARE_SORTED
238     assert(IsSorted());
239 #endif
240     auto first_intersect = std::adjacent_find(
241         m_entries.begin(), m_entries.end(), [](const Entry &a, const Entry &b) {
242           return a.DoesAdjoinOrIntersect(b);
243         });
244     if (first_intersect == m_entries.end())
245       return;
246 
247     // We can combine at least one entry, then we make a new collection and
248     // populate it accordingly, and then swap it into place.
249     auto pos = std::next(first_intersect);
250     Collection minimal_ranges(m_entries.begin(), pos);
251     for (; pos != m_entries.end(); ++pos) {
252       Entry &back = minimal_ranges.back();
253       if (back.DoesAdjoinOrIntersect(*pos))
254         back.SetRangeEnd(std::max(back.GetRangeEnd(), pos->GetRangeEnd()));
255       else
256         minimal_ranges.push_back(*pos);
257     }
258     m_entries.swap(minimal_ranges);
259   }
260 
GetMinRangeBase(BaseType fail_value)261   BaseType GetMinRangeBase(BaseType fail_value) const {
262 #ifdef ASSERT_RANGEMAP_ARE_SORTED
263     assert(IsSorted());
264 #endif
265     if (m_entries.empty())
266       return fail_value;
267     // m_entries must be sorted, so if we aren't empty, we grab the first
268     // range's base
269     return m_entries.front().GetRangeBase();
270   }
271 
GetMaxRangeEnd(BaseType fail_value)272   BaseType GetMaxRangeEnd(BaseType fail_value) const {
273 #ifdef ASSERT_RANGEMAP_ARE_SORTED
274     assert(IsSorted());
275 #endif
276     if (m_entries.empty())
277       return fail_value;
278     // m_entries must be sorted, so if we aren't empty, we grab the last
279     // range's end
280     return m_entries.back().GetRangeEnd();
281   }
282 
Slide(BaseType slide)283   void Slide(BaseType slide) {
284     typename Collection::iterator pos, end;
285     for (pos = m_entries.begin(), end = m_entries.end(); pos != end; ++pos)
286       pos->Slide(slide);
287   }
288 
Clear()289   void Clear() { m_entries.clear(); }
290 
Reserve(typename Collection::size_type size)291   void Reserve(typename Collection::size_type size) { m_entries.reserve(size); }
292 
IsEmpty()293   bool IsEmpty() const { return m_entries.empty(); }
294 
GetSize()295   size_t GetSize() const { return m_entries.size(); }
296 
GetEntryAtIndex(size_t i)297   const Entry *GetEntryAtIndex(size_t i) const {
298     return ((i < m_entries.size()) ? &m_entries[i] : nullptr);
299   }
300 
301   // Clients must ensure that "i" is a valid index prior to calling this
302   // function
GetEntryRef(size_t i)303   Entry &GetEntryRef(size_t i) { return m_entries[i]; }
GetEntryRef(size_t i)304   const Entry &GetEntryRef(size_t i) const { return m_entries[i]; }
305 
Back()306   Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); }
307 
Back()308   const Entry *Back() const {
309     return (m_entries.empty() ? nullptr : &m_entries.back());
310   }
311 
BaseLessThan(const Entry & lhs,const Entry & rhs)312   static bool BaseLessThan(const Entry &lhs, const Entry &rhs) {
313     return lhs.GetRangeBase() < rhs.GetRangeBase();
314   }
315 
FindEntryIndexThatContains(B addr)316   uint32_t FindEntryIndexThatContains(B addr) const {
317 #ifdef ASSERT_RANGEMAP_ARE_SORTED
318     assert(IsSorted());
319 #endif
320     if (!m_entries.empty()) {
321       Entry entry(addr, 1);
322       typename Collection::const_iterator begin = m_entries.begin();
323       typename Collection::const_iterator end = m_entries.end();
324       typename Collection::const_iterator pos =
325           std::lower_bound(begin, end, entry, BaseLessThan);
326 
327       if (pos != end && pos->Contains(addr)) {
328         return std::distance(begin, pos);
329       } else if (pos != begin) {
330         --pos;
331         if (pos->Contains(addr))
332           return std::distance(begin, pos);
333       }
334     }
335     return UINT32_MAX;
336   }
337 
FindEntryThatContains(B addr)338   const Entry *FindEntryThatContains(B addr) const {
339 #ifdef ASSERT_RANGEMAP_ARE_SORTED
340     assert(IsSorted());
341 #endif
342     if (!m_entries.empty()) {
343       Entry entry(addr, 1);
344       typename Collection::const_iterator begin = m_entries.begin();
345       typename Collection::const_iterator end = m_entries.end();
346       typename Collection::const_iterator pos =
347           std::lower_bound(begin, end, entry, BaseLessThan);
348 
349       if (pos != end && pos->Contains(addr)) {
350         return &(*pos);
351       } else if (pos != begin) {
352         --pos;
353         if (pos->Contains(addr)) {
354           return &(*pos);
355         }
356       }
357     }
358     return nullptr;
359   }
360 
FindEntryThatContains(const Entry & range)361   const Entry *FindEntryThatContains(const Entry &range) const {
362 #ifdef ASSERT_RANGEMAP_ARE_SORTED
363     assert(IsSorted());
364 #endif
365     if (!m_entries.empty()) {
366       typename Collection::const_iterator begin = m_entries.begin();
367       typename Collection::const_iterator end = m_entries.end();
368       typename Collection::const_iterator pos =
369           std::lower_bound(begin, end, range, BaseLessThan);
370 
371       if (pos != end && pos->Contains(range)) {
372         return &(*pos);
373       } else if (pos != begin) {
374         --pos;
375         if (pos->Contains(range)) {
376           return &(*pos);
377         }
378       }
379     }
380     return nullptr;
381   }
382 
FindEntryThatIntersects(const Entry & range)383   const Entry *FindEntryThatIntersects(const Entry &range) const {
384 #ifdef ASSERT_RANGEMAP_ARE_SORTED
385     assert(IsSorted());
386 #endif
387     if (!m_entries.empty()) {
388       typename Collection::const_iterator begin = m_entries.begin();
389       typename Collection::const_iterator end = m_entries.end();
390       typename Collection::const_iterator pos =
391           std::lower_bound(begin, end, range, BaseLessThan);
392 
393       while (pos != begin && pos[-1].DoesIntersect(range))
394         --pos;
395 
396       if (pos != end && pos->DoesIntersect(range))
397         return &(*pos);
398     }
399     return nullptr;
400   }
401 
402   using const_iterator = typename Collection::const_iterator;
begin()403   const_iterator begin() const { return m_entries.begin(); }
end()404   const_iterator end() const { return m_entries.end(); }
405 
406 protected:
CombinePrevAndNext(typename Collection::iterator pos)407   void CombinePrevAndNext(typename Collection::iterator pos) {
408     // Check if the prev or next entries in case they need to be unioned with
409     // the entry pointed to by "pos".
410     if (pos != m_entries.begin()) {
411       auto prev = pos - 1;
412       if (prev->Union(*pos))
413         m_entries.erase(pos);
414       pos = prev;
415     }
416 
417     auto end = m_entries.end();
418     if (pos != end) {
419       auto next = pos + 1;
420       if (next != end) {
421         if (pos->Union(*next))
422           m_entries.erase(next);
423       }
424     }
425   }
426 
427   Collection m_entries;
428 };
429 
430 // A simple range  with data class where you get to define the type of
431 // the range base "B", the type used for the range byte size "S", and the type
432 // for the associated data "T".
433 template <typename B, typename S, typename T>
434 struct RangeData : public Range<B, S> {
435   typedef T DataType;
436 
437   DataType data;
438 
RangeDataRangeData439   RangeData() : Range<B, S>(), data() {}
440 
RangeDataRangeData441   RangeData(B base, S size) : Range<B, S>(base, size), data() {}
442 
RangeDataRangeData443   RangeData(B base, S size, DataType d) : Range<B, S>(base, size), data(d) {}
444 };
445 
446 // We can treat the vector as a flattened Binary Search Tree, augmenting it
447 // with upper bounds (max of range endpoints) for every index allows us to
448 // query for range containment quicker.
449 template <typename B, typename S, typename T>
450 struct AugmentedRangeData : public RangeData<B, S, T> {
451   B upper_bound;
452 
AugmentedRangeDataAugmentedRangeData453   AugmentedRangeData(const RangeData<B, S, T> &rd)
454       : RangeData<B, S, T>(rd), upper_bound() {}
455 };
456 
457 template <typename B, typename S, typename T, unsigned N = 0,
458           class Compare = std::less<T>>
459 class RangeDataVector {
460 public:
461   typedef lldb_private::Range<B, S> Range;
462   typedef RangeData<B, S, T> Entry;
463   typedef AugmentedRangeData<B, S, T> AugmentedEntry;
464   typedef llvm::SmallVector<AugmentedEntry, N> Collection;
465 
m_compare(compare)466   RangeDataVector(Compare compare = Compare()) : m_compare(compare) {}
467 
468   ~RangeDataVector() = default;
469 
Append(const Entry & entry)470   void Append(const Entry &entry) { m_entries.emplace_back(entry); }
471 
472   /// Append a range with data to the vector
473   /// \param B The base of the memory range
474   /// \param S The size of the memory range
475   /// \param T The data associated with the memory range
Append(B && b,S && s,T && t)476   void Append(B &&b, S &&s, T &&t) { m_entries.emplace_back(Entry(b, s, t)); }
477 
Erase(uint32_t start,uint32_t end)478   bool Erase(uint32_t start, uint32_t end) {
479     if (start >= end || end > m_entries.size())
480       return false;
481     m_entries.erase(begin() + start, begin() + end);
482     return true;
483   }
484 
Sort()485   void Sort() {
486     if (m_entries.size() > 1)
487       llvm::stable_sort(m_entries,
488                         [&compare = m_compare](const Entry &a, const Entry &b) {
489                           if (a.base != b.base)
490                             return a.base < b.base;
491                           if (a.size != b.size)
492                             return a.size < b.size;
493                           return compare(a.data, b.data);
494                         });
495     if (!m_entries.empty())
496       ComputeUpperBounds(0, m_entries.size());
497   }
498 
499 #ifdef ASSERT_RANGEMAP_ARE_SORTED
IsSorted()500   bool IsSorted() const {
501     typename Collection::const_iterator pos, end, prev;
502     for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end;
503          prev = pos++) {
504       if (prev != end && *pos < *prev)
505         return false;
506     }
507     return true;
508   }
509 #endif
510 
CombineConsecutiveEntriesWithEqualData()511   void CombineConsecutiveEntriesWithEqualData() {
512 #ifdef ASSERT_RANGEMAP_ARE_SORTED
513     assert(IsSorted());
514 #endif
515     auto first_intersect = std::adjacent_find(
516         m_entries.begin(), m_entries.end(), [](const Entry &a, const Entry &b) {
517           return a.DoesAdjoinOrIntersect(b) && a.data == b.data;
518         });
519 
520     if (first_intersect == m_entries.end())
521       return;
522 
523     // We can combine at least one entry. Make a new collection and populate it
524     // accordingly, and then swap it into place.
525     auto pos = std::next(first_intersect);
526     Collection minimal_ranges(m_entries.begin(), pos);
527     for (; pos != m_entries.end(); ++pos) {
528       Entry &back = minimal_ranges.back();
529       if (back.DoesAdjoinOrIntersect(*pos) && back.data == pos->data)
530         back.SetRangeEnd(std::max(back.GetRangeEnd(), pos->GetRangeEnd()));
531       else
532         minimal_ranges.push_back(*pos);
533     }
534     m_entries.swap(minimal_ranges);
535     ComputeUpperBounds(0, m_entries.size());
536   }
537 
Clear()538   void Clear() { m_entries.clear(); }
539 
IsEmpty()540   bool IsEmpty() const { return m_entries.empty(); }
541 
GetSize()542   size_t GetSize() const { return m_entries.size(); }
543 
GetEntryAtIndex(size_t i)544   const Entry *GetEntryAtIndex(size_t i) const {
545     return ((i < m_entries.size()) ? &m_entries[i] : nullptr);
546   }
547 
GetMutableEntryAtIndex(size_t i)548   Entry *GetMutableEntryAtIndex(size_t i) {
549     return ((i < m_entries.size()) ? &m_entries[i] : nullptr);
550   }
551 
552   // Clients must ensure that "i" is a valid index prior to calling this
553   // function
GetEntryRef(size_t i)554   Entry &GetEntryRef(size_t i) { return m_entries[i]; }
GetEntryRef(size_t i)555   const Entry &GetEntryRef(size_t i) const { return m_entries[i]; }
556 
BaseLessThan(const Entry & lhs,const Entry & rhs)557   static bool BaseLessThan(const Entry &lhs, const Entry &rhs) {
558     return lhs.GetRangeBase() < rhs.GetRangeBase();
559   }
560 
FindEntryIndexThatContains(B addr)561   uint32_t FindEntryIndexThatContains(B addr) const {
562     const AugmentedEntry *entry =
563         static_cast<const AugmentedEntry *>(FindEntryThatContains(addr));
564     if (entry)
565       return std::distance(m_entries.begin(), entry);
566     return UINT32_MAX;
567   }
568 
FindEntryIndexesThatContain(B addr,std::vector<uint32_t> & indexes)569   uint32_t FindEntryIndexesThatContain(B addr, std::vector<uint32_t> &indexes) {
570 #ifdef ASSERT_RANGEMAP_ARE_SORTED
571     assert(IsSorted());
572 #endif
573     if (!m_entries.empty())
574       FindEntryIndexesThatContain(addr, 0, m_entries.size(), indexes);
575 
576     return indexes.size();
577   }
578 
FindEntryThatContains(B addr)579   Entry *FindEntryThatContains(B addr) {
580     return const_cast<Entry *>(
581         static_cast<const RangeDataVector *>(this)->FindEntryThatContains(
582             addr));
583   }
584 
FindEntryThatContains(B addr)585   const Entry *FindEntryThatContains(B addr) const {
586     return FindEntryThatContains(Entry(addr, 1));
587   }
588 
FindEntryThatContains(const Entry & range)589   const Entry *FindEntryThatContains(const Entry &range) const {
590 #ifdef ASSERT_RANGEMAP_ARE_SORTED
591     assert(IsSorted());
592 #endif
593     if (!m_entries.empty()) {
594       typename Collection::const_iterator begin = m_entries.begin();
595       typename Collection::const_iterator end = m_entries.end();
596       typename Collection::const_iterator pos =
597           std::lower_bound(begin, end, range, BaseLessThan);
598 
599       while (pos != begin && pos[-1].Contains(range))
600         --pos;
601 
602       if (pos != end && pos->Contains(range))
603         return &(*pos);
604     }
605     return nullptr;
606   }
607 
FindEntryStartsAt(B addr)608   const Entry *FindEntryStartsAt(B addr) const {
609 #ifdef ASSERT_RANGEMAP_ARE_SORTED
610     assert(IsSorted());
611 #endif
612     if (!m_entries.empty()) {
613       auto begin = m_entries.begin(), end = m_entries.end();
614       auto pos = std::lower_bound(begin, end, Entry(addr, 1), BaseLessThan);
615       if (pos != end && pos->base == addr)
616         return &(*pos);
617     }
618     return nullptr;
619   }
620 
621   // This method will return the entry that contains the given address, or the
622   // entry following that address.  If you give it an address of 0 and the
623   // first entry starts at address 0x100, you will get the entry at 0x100.
624   //
625   // For most uses, FindEntryThatContains is the correct one to use, this is a
626   // less commonly needed behavior.  It was added for core file memory regions,
627   // where we want to present a gap in the memory regions as a distinct region,
628   // so we need to know the start address of the next memory section that
629   // exists.
FindEntryThatContainsOrFollows(B addr)630   const Entry *FindEntryThatContainsOrFollows(B addr) const {
631 #ifdef ASSERT_RANGEMAP_ARE_SORTED
632     assert(IsSorted());
633 #endif
634     if (!m_entries.empty()) {
635       typename Collection::const_iterator begin = m_entries.begin();
636       typename Collection::const_iterator end = m_entries.end();
637       typename Collection::const_iterator pos = llvm::lower_bound(
638           m_entries, addr, [](const Entry &lhs, B rhs_base) -> bool {
639             return lhs.GetRangeEnd() <= rhs_base;
640           });
641 
642       while (pos != begin && pos[-1].Contains(addr))
643         --pos;
644 
645       if (pos != end)
646         return &(*pos);
647     }
648     return nullptr;
649   }
650 
FindEntryIndexThatContainsOrFollows(B addr)651   uint32_t FindEntryIndexThatContainsOrFollows(B addr) const {
652 #ifdef ASSERT_RANGEMAP_ARE_SORTED
653     assert(IsSorted());
654 #endif
655     const AugmentedEntry *entry = static_cast<const AugmentedEntry *>(
656         FindEntryThatContainsOrFollows(addr));
657     if (entry)
658       return std::distance(m_entries.begin(), entry);
659     return UINT32_MAX;
660   }
661 
Back()662   Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); }
663 
Back()664   const Entry *Back() const {
665     return (m_entries.empty() ? nullptr : &m_entries.back());
666   }
667 
668   using const_iterator = typename Collection::const_iterator;
begin()669   const_iterator begin() const { return m_entries.begin(); }
end()670   const_iterator end() const { return m_entries.end(); }
671 
672 protected:
673   Collection m_entries;
674   Compare m_compare;
675 
676 private:
677   // Compute extra information needed for search
ComputeUpperBounds(size_t lo,size_t hi)678   B ComputeUpperBounds(size_t lo, size_t hi) {
679     size_t mid = (lo + hi) / 2;
680     AugmentedEntry &entry = m_entries[mid];
681 
682     entry.upper_bound = entry.base + entry.size;
683 
684     if (lo < mid)
685       entry.upper_bound =
686           std::max(entry.upper_bound, ComputeUpperBounds(lo, mid));
687 
688     if (mid + 1 < hi)
689       entry.upper_bound =
690           std::max(entry.upper_bound, ComputeUpperBounds(mid + 1, hi));
691 
692     return entry.upper_bound;
693   }
694 
695   // This is based on the augmented tree implementation found at
696   // https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree
FindEntryIndexesThatContain(B addr,size_t lo,size_t hi,std::vector<uint32_t> & indexes)697   void FindEntryIndexesThatContain(B addr, size_t lo, size_t hi,
698                                    std::vector<uint32_t> &indexes) {
699     size_t mid = (lo + hi) / 2;
700     const AugmentedEntry &entry = m_entries[mid];
701 
702     // addr is greater than the rightmost point of any interval below mid
703     // so there are cannot be any matches.
704     if (addr > entry.upper_bound)
705       return;
706 
707     // Recursively search left subtree
708     if (lo < mid)
709       FindEntryIndexesThatContain(addr, lo, mid, indexes);
710 
711     // If addr is smaller than the start of the current interval it
712     // cannot contain it nor can any of its right subtree.
713     if (addr < entry.base)
714       return;
715 
716     if (entry.Contains(addr))
717       indexes.push_back(entry.data);
718 
719     // Recursively search right subtree
720     if (mid + 1 < hi)
721       FindEntryIndexesThatContain(addr, mid + 1, hi, indexes);
722   }
723 };
724 
725 // A simple range  with data class where you get to define the type of
726 // the range base "B", the type used for the range byte size "S", and the type
727 // for the associated data "T".
728 template <typename B, typename T> struct AddressData {
729   typedef B BaseType;
730   typedef T DataType;
731 
732   BaseType addr;
733   DataType data;
734 
AddressDataAddressData735   AddressData() : addr(), data() {}
736 
AddressDataAddressData737   AddressData(B a, DataType d) : addr(a), data(d) {}
738 
739   bool operator<(const AddressData &rhs) const {
740     if (this->addr == rhs.addr)
741       return this->data < rhs.data;
742     return this->addr < rhs.addr;
743   }
744 
745   bool operator==(const AddressData &rhs) const {
746     return this->addr == rhs.addr && this->data == rhs.data;
747   }
748 
749   bool operator!=(const AddressData &rhs) const {
750     return this->addr != rhs.addr || this->data == rhs.data;
751   }
752 };
753 
754 template <typename B, typename T, unsigned N> class AddressDataArray {
755 public:
756   typedef AddressData<B, T> Entry;
757   typedef llvm::SmallVector<Entry, N> Collection;
758 
759   AddressDataArray() = default;
760 
761   ~AddressDataArray() = default;
762 
Append(const Entry & entry)763   void Append(const Entry &entry) { m_entries.push_back(entry); }
764 
Sort()765   void Sort() {
766     if (m_entries.size() > 1)
767       std::stable_sort(m_entries.begin(), m_entries.end());
768   }
769 
770 #ifdef ASSERT_RANGEMAP_ARE_SORTED
IsSorted()771   bool IsSorted() const {
772     typename Collection::const_iterator pos, end, prev;
773     // First we determine if we can combine any of the Entry objects so we
774     // don't end up allocating and making a new collection for no reason
775     for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end;
776          prev = pos++) {
777       if (prev != end && *pos < *prev)
778         return false;
779     }
780     return true;
781   }
782 #endif
783 
Clear()784   void Clear() { m_entries.clear(); }
785 
IsEmpty()786   bool IsEmpty() const { return m_entries.empty(); }
787 
GetSize()788   size_t GetSize() const { return m_entries.size(); }
789 
GetEntryAtIndex(size_t i)790   const Entry *GetEntryAtIndex(size_t i) const {
791     return ((i < m_entries.size()) ? &m_entries[i] : nullptr);
792   }
793 
794   // Clients must ensure that "i" is a valid index prior to calling this
795   // function
GetEntryRef(size_t i)796   const Entry &GetEntryRef(size_t i) const { return m_entries[i]; }
797 
BaseLessThan(const Entry & lhs,const Entry & rhs)798   static bool BaseLessThan(const Entry &lhs, const Entry &rhs) {
799     return lhs.addr < rhs.addr;
800   }
801 
FindEntry(B addr,bool exact_match_only)802   Entry *FindEntry(B addr, bool exact_match_only) {
803 #ifdef ASSERT_RANGEMAP_ARE_SORTED
804     assert(IsSorted());
805 #endif
806     if (!m_entries.empty()) {
807       Entry entry;
808       entry.addr = addr;
809       typename Collection::iterator begin = m_entries.begin();
810       typename Collection::iterator end = m_entries.end();
811       typename Collection::iterator pos =
812           llvm::lower_bound(m_entries, entry, BaseLessThan);
813 
814       while (pos != begin && pos[-1].addr == addr)
815         --pos;
816 
817       if (pos != end) {
818         if (pos->addr == addr || !exact_match_only)
819           return &(*pos);
820       }
821     }
822     return nullptr;
823   }
824 
FindNextEntry(const Entry * entry)825   const Entry *FindNextEntry(const Entry *entry) {
826     if (entry >= &*m_entries.begin() && entry + 1 < &*m_entries.end())
827       return entry + 1;
828     return nullptr;
829   }
830 
Back()831   Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); }
832 
Back()833   const Entry *Back() const {
834     return (m_entries.empty() ? nullptr : &m_entries.back());
835   }
836 
837 protected:
838   Collection m_entries;
839 };
840 
841 } // namespace lldb_private
842 
843 #endif // LLDB_UTILITY_RANGEMAP_H
844