1 //===-- RangeMap.h ----------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #ifndef liblldb_RangeMap_h_
11 #define liblldb_RangeMap_h_
18 // Other libraries and framework includes
19 #include "llvm/ADT/SmallVector.h"
22 #include "lldb/lldb-private.h"
24 // Uncomment to make sure all Range objects are sorted when needed
25 //#define ASSERT_RANGEMAP_ARE_SORTED
27 namespace lldb_private {
29 //----------------------------------------------------------------------
30 // Templatized classes for dealing with generic ranges and also collections of
31 // ranges, or collections of ranges that have associated data.
32 //----------------------------------------------------------------------
34 //----------------------------------------------------------------------
35 // A simple range class where you get to define the type of the range
36 // base "B", and the type used for the range byte size "S".
37 //----------------------------------------------------------------------
38 template <typename B, typename S> struct Range {
45 Range() : base(0), size(0) {}
47 Range(BaseType b, SizeType s) : base(b), size(s) {}
49 void Clear(BaseType b = 0) {
54 // Set the start value for the range, and keep the same size
55 BaseType GetRangeBase() const { return base; }
57 void SetRangeBase(BaseType b) { base = b; }
59 void Slide(BaseType slide) { base += slide; }
61 bool Union(const Range &rhs)
63 if (DoesAdjoinOrIntersect(rhs))
65 auto new_end = std::max<BaseType>(GetRangeEnd(), rhs.GetRangeEnd());
66 base = std::min<BaseType>(base, rhs.base);
67 size = new_end - base;
73 BaseType GetRangeEnd() const { return base + size; }
75 void SetRangeEnd(BaseType end) {
82 SizeType GetByteSize() const { return size; }
84 void SetByteSize(SizeType s) { size = s; }
86 bool IsValid() const { return size > 0; }
88 bool Contains(BaseType r) const {
89 return (GetRangeBase() <= r) && (r < GetRangeEnd());
92 bool ContainsEndInclusive(BaseType r) const {
93 return (GetRangeBase() <= r) && (r <= GetRangeEnd());
96 bool Contains(const Range &range) const {
97 return Contains(range.GetRangeBase()) &&
98 ContainsEndInclusive(range.GetRangeEnd());
101 // Returns true if the two ranges adjoing or intersect
102 bool DoesAdjoinOrIntersect(const Range &rhs) const {
103 const BaseType lhs_base = this->GetRangeBase();
104 const BaseType rhs_base = rhs.GetRangeBase();
105 const BaseType lhs_end = this->GetRangeEnd();
106 const BaseType rhs_end = rhs.GetRangeEnd();
107 bool result = (lhs_base <= rhs_end) && (lhs_end >= rhs_base);
111 // Returns true if the two ranges intersect
112 bool DoesIntersect(const Range &rhs) const {
113 const BaseType lhs_base = this->GetRangeBase();
114 const BaseType rhs_base = rhs.GetRangeBase();
115 const BaseType lhs_end = this->GetRangeEnd();
116 const BaseType rhs_end = rhs.GetRangeEnd();
117 bool result = (lhs_base < rhs_end) && (lhs_end > rhs_base);
121 bool operator<(const Range &rhs) const {
122 if (base == rhs.base)
123 return size < rhs.size;
124 return base < rhs.base;
127 bool operator==(const Range &rhs) const {
128 return base == rhs.base && size == rhs.size;
131 bool operator!=(const Range &rhs) const {
132 return base != rhs.base || size != rhs.size;
136 //----------------------------------------------------------------------
137 // A range array class where you get to define the type of the ranges
138 // that the collection contains.
139 //----------------------------------------------------------------------
141 template <typename B, typename S, unsigned N> class RangeArray {
145 typedef Range<B, S> Entry;
146 typedef llvm::SmallVector<Entry, N> Collection;
148 RangeArray() = default;
150 ~RangeArray() = default;
152 void Append(const Entry &entry) { m_entries.push_back(entry); }
154 void Append(B base, S size) { m_entries.emplace_back(base, size); }
156 bool RemoveEntrtAtIndex(uint32_t idx) {
157 if (idx < m_entries.size()) {
158 m_entries.erase(m_entries.begin() + idx);
165 if (m_entries.size() > 1)
166 std::stable_sort(m_entries.begin(), m_entries.end());
169 #ifdef ASSERT_RANGEMAP_ARE_SORTED
170 bool IsSorted() const {
171 typename Collection::const_iterator pos, end, prev;
172 // First we determine if we can combine any of the Entry objects so we
173 // don't end up allocating and making a new collection for no reason
174 for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end;
176 if (prev != end && *pos < *prev)
183 void CombineConsecutiveRanges() {
184 #ifdef ASSERT_RANGEMAP_ARE_SORTED
187 // Can't combine if ranges if we have zero or one range
188 if (m_entries.size() > 1) {
189 // The list should be sorted prior to calling this function
190 typename Collection::iterator pos;
191 typename Collection::iterator end;
192 typename Collection::iterator prev;
193 bool can_combine = false;
194 // First we determine if we can combine any of the Entry objects so we
195 // don't end up allocating and making a new collection for no reason
196 for (pos = m_entries.begin(), end = m_entries.end(), prev = end;
197 pos != end; prev = pos++) {
198 if (prev != end && prev->DoesAdjoinOrIntersect(*pos)) {
204 // We we can combine at least one entry, then we make a new collection
205 // and populate it accordingly, and then swap it into place.
207 Collection minimal_ranges;
208 for (pos = m_entries.begin(), end = m_entries.end(), prev = end;
209 pos != end; prev = pos++) {
210 if (prev != end && prev->DoesAdjoinOrIntersect(*pos))
211 minimal_ranges.back().SetRangeEnd(
212 std::max<BaseType>(prev->GetRangeEnd(), pos->GetRangeEnd()));
214 minimal_ranges.push_back(*pos);
216 // Use the swap technique in case our new vector is much smaller. We
217 // must swap when using the STL because std::vector objects never
218 // release or reduce the memory once it has been allocated/reserved.
219 m_entries.swap(minimal_ranges);
224 BaseType GetMinRangeBase(BaseType fail_value) const {
225 #ifdef ASSERT_RANGEMAP_ARE_SORTED
228 if (m_entries.empty())
230 // m_entries must be sorted, so if we aren't empty, we grab the first
232 return m_entries.front().GetRangeBase();
235 BaseType GetMaxRangeEnd(BaseType fail_value) const {
236 #ifdef ASSERT_RANGEMAP_ARE_SORTED
239 if (m_entries.empty())
241 // m_entries must be sorted, so if we aren't empty, we grab the last
243 return m_entries.back().GetRangeEnd();
246 void Slide(BaseType slide) {
247 typename Collection::iterator pos, end;
248 for (pos = m_entries.begin(), end = m_entries.end(); pos != end; ++pos)
252 void Clear() { m_entries.clear(); }
254 bool IsEmpty() const { return m_entries.empty(); }
256 size_t GetSize() const { return m_entries.size(); }
258 const Entry *GetEntryAtIndex(size_t i) const {
259 return ((i < m_entries.size()) ? &m_entries[i] : nullptr);
262 // Clients must ensure that "i" is a valid index prior to calling this
264 const Entry &GetEntryRef(size_t i) const { return m_entries[i]; }
266 Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); }
268 const Entry *Back() const {
269 return (m_entries.empty() ? nullptr : &m_entries.back());
272 static bool BaseLessThan(const Entry &lhs, const Entry &rhs) {
273 return lhs.GetRangeBase() < rhs.GetRangeBase();
276 uint32_t FindEntryIndexThatContains(B addr) const {
277 #ifdef ASSERT_RANGEMAP_ARE_SORTED
280 if (!m_entries.empty()) {
281 Entry entry(addr, 1);
282 typename Collection::const_iterator begin = m_entries.begin();
283 typename Collection::const_iterator end = m_entries.end();
284 typename Collection::const_iterator pos =
285 std::lower_bound(begin, end, entry, BaseLessThan);
287 if (pos != end && pos->Contains(addr)) {
288 return std::distance(begin, pos);
289 } else if (pos != begin) {
291 if (pos->Contains(addr))
292 return std::distance(begin, pos);
298 const Entry *FindEntryThatContains(B addr) const {
299 #ifdef ASSERT_RANGEMAP_ARE_SORTED
302 if (!m_entries.empty()) {
303 Entry entry(addr, 1);
304 typename Collection::const_iterator begin = m_entries.begin();
305 typename Collection::const_iterator end = m_entries.end();
306 typename Collection::const_iterator pos =
307 std::lower_bound(begin, end, entry, BaseLessThan);
309 if (pos != end && pos->Contains(addr)) {
311 } else if (pos != begin) {
313 if (pos->Contains(addr)) {
321 const Entry *FindEntryThatContains(const Entry &range) const {
322 #ifdef ASSERT_RANGEMAP_ARE_SORTED
325 if (!m_entries.empty()) {
326 typename Collection::const_iterator begin = m_entries.begin();
327 typename Collection::const_iterator end = m_entries.end();
328 typename Collection::const_iterator pos =
329 std::lower_bound(begin, end, range, BaseLessThan);
331 if (pos != end && pos->Contains(range)) {
333 } else if (pos != begin) {
335 if (pos->Contains(range)) {
344 Collection m_entries;
347 template <typename B, typename S> class RangeVector {
351 typedef Range<B, S> Entry;
352 typedef std::vector<Entry> Collection;
354 RangeVector() = default;
356 ~RangeVector() = default;
358 void Append(const Entry &entry) { m_entries.push_back(entry); }
360 void Append(B base, S size) { m_entries.emplace_back(base, size); }
362 // Insert an item into a sorted list and optionally combine it with any
363 // adjacent blocks if requested.
364 void Insert(const Entry &entry, bool combine) {
365 if (m_entries.empty()) {
366 m_entries.push_back(entry);
369 auto begin = m_entries.begin();
370 auto end = m_entries.end();
371 auto pos = std::lower_bound(begin, end, entry);
373 if (pos != end && pos->Union(entry)) {
374 CombinePrevAndNext(pos);
379 if (prev->Union(entry)) {
380 CombinePrevAndNext(prev);
385 m_entries.insert(pos, entry);
388 bool RemoveEntryAtIndex(uint32_t idx) {
389 if (idx < m_entries.size()) {
390 m_entries.erase(m_entries.begin() + idx);
397 if (m_entries.size() > 1)
398 std::stable_sort(m_entries.begin(), m_entries.end());
401 #ifdef ASSERT_RANGEMAP_ARE_SORTED
402 bool IsSorted() const {
403 typename Collection::const_iterator pos, end, prev;
404 // First we determine if we can combine any of the Entry objects so we
405 // don't end up allocating and making a new collection for no reason
406 for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end;
408 if (prev != end && *pos < *prev)
415 void CombineConsecutiveRanges() {
416 #ifdef ASSERT_RANGEMAP_ARE_SORTED
419 // Can't combine if ranges if we have zero or one range
420 if (m_entries.size() > 1) {
421 // The list should be sorted prior to calling this function
422 typename Collection::iterator pos;
423 typename Collection::iterator end;
424 typename Collection::iterator prev;
425 bool can_combine = false;
426 // First we determine if we can combine any of the Entry objects so we
427 // don't end up allocating and making a new collection for no reason
428 for (pos = m_entries.begin(), end = m_entries.end(), prev = end;
429 pos != end; prev = pos++) {
430 if (prev != end && prev->DoesAdjoinOrIntersect(*pos)) {
436 // We we can combine at least one entry, then we make a new collection
437 // and populate it accordingly, and then swap it into place.
439 Collection minimal_ranges;
440 for (pos = m_entries.begin(), end = m_entries.end(), prev = end;
441 pos != end; prev = pos++) {
442 if (prev != end && prev->DoesAdjoinOrIntersect(*pos))
443 minimal_ranges.back().SetRangeEnd(
444 std::max<BaseType>(prev->GetRangeEnd(), pos->GetRangeEnd()));
446 minimal_ranges.push_back(*pos);
448 // Use the swap technique in case our new vector is much smaller. We
449 // must swap when using the STL because std::vector objects never
450 // release or reduce the memory once it has been allocated/reserved.
451 m_entries.swap(minimal_ranges);
456 BaseType GetMinRangeBase(BaseType fail_value) const {
457 #ifdef ASSERT_RANGEMAP_ARE_SORTED
460 if (m_entries.empty())
462 // m_entries must be sorted, so if we aren't empty, we grab the first
464 return m_entries.front().GetRangeBase();
467 BaseType GetMaxRangeEnd(BaseType fail_value) const {
468 #ifdef ASSERT_RANGEMAP_ARE_SORTED
471 if (m_entries.empty())
473 // m_entries must be sorted, so if we aren't empty, we grab the last
475 return m_entries.back().GetRangeEnd();
478 void Slide(BaseType slide) {
479 typename Collection::iterator pos, end;
480 for (pos = m_entries.begin(), end = m_entries.end(); pos != end; ++pos)
484 void Clear() { m_entries.clear(); }
486 void Reserve(typename Collection::size_type size) { m_entries.reserve(size); }
488 bool IsEmpty() const { return m_entries.empty(); }
490 size_t GetSize() const { return m_entries.size(); }
492 const Entry *GetEntryAtIndex(size_t i) const {
493 return ((i < m_entries.size()) ? &m_entries[i] : nullptr);
496 // Clients must ensure that "i" is a valid index prior to calling this
498 Entry &GetEntryRef(size_t i) { return m_entries[i]; }
499 const Entry &GetEntryRef(size_t i) const { return m_entries[i]; }
501 Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); }
503 const Entry *Back() const {
504 return (m_entries.empty() ? nullptr : &m_entries.back());
507 static bool BaseLessThan(const Entry &lhs, const Entry &rhs) {
508 return lhs.GetRangeBase() < rhs.GetRangeBase();
511 uint32_t FindEntryIndexThatContains(B addr) const {
512 #ifdef ASSERT_RANGEMAP_ARE_SORTED
515 if (!m_entries.empty()) {
516 Entry entry(addr, 1);
517 typename Collection::const_iterator begin = m_entries.begin();
518 typename Collection::const_iterator end = m_entries.end();
519 typename Collection::const_iterator pos =
520 std::lower_bound(begin, end, entry, BaseLessThan);
522 if (pos != end && pos->Contains(addr)) {
523 return std::distance(begin, pos);
524 } else if (pos != begin) {
526 if (pos->Contains(addr))
527 return std::distance(begin, pos);
533 const Entry *FindEntryThatContains(B addr) const {
534 #ifdef ASSERT_RANGEMAP_ARE_SORTED
537 if (!m_entries.empty()) {
538 Entry entry(addr, 1);
539 typename Collection::const_iterator begin = m_entries.begin();
540 typename Collection::const_iterator end = m_entries.end();
541 typename Collection::const_iterator pos =
542 std::lower_bound(begin, end, entry, BaseLessThan);
544 if (pos != end && pos->Contains(addr)) {
546 } else if (pos != begin) {
548 if (pos->Contains(addr)) {
556 const Entry *FindEntryThatContains(const Entry &range) const {
557 #ifdef ASSERT_RANGEMAP_ARE_SORTED
560 if (!m_entries.empty()) {
561 typename Collection::const_iterator begin = m_entries.begin();
562 typename Collection::const_iterator end = m_entries.end();
563 typename Collection::const_iterator pos =
564 std::lower_bound(begin, end, range, BaseLessThan);
566 if (pos != end && pos->Contains(range)) {
568 } else if (pos != begin) {
570 if (pos->Contains(range)) {
580 void CombinePrevAndNext(typename Collection::iterator pos) {
581 // Check if the prev or next entries in case they need to be unioned with
582 // the entry pointed to by "pos".
583 if (pos != m_entries.begin()) {
585 if (prev->Union(*pos))
586 m_entries.erase(pos);
590 auto end = m_entries.end();
594 if (pos->Union(*next))
595 m_entries.erase(next);
601 Collection m_entries;
604 //----------------------------------------------------------------------
605 // A simple range with data class where you get to define the type of
606 // the range base "B", the type used for the range byte size "S", and the type
607 // for the associated data "T".
608 //----------------------------------------------------------------------
609 template <typename B, typename S, typename T>
610 struct RangeData : public Range<B, S> {
615 RangeData() : Range<B, S>(), data() {}
617 RangeData(B base, S size) : Range<B, S>(base, size), data() {}
619 RangeData(B base, S size, DataType d) : Range<B, S>(base, size), data(d) {}
621 bool operator<(const RangeData &rhs) const {
622 if (this->base == rhs.base) {
623 if (this->size == rhs.size)
624 return this->data < rhs.data;
626 return this->size < rhs.size;
628 return this->base < rhs.base;
631 bool operator==(const RangeData &rhs) const {
632 return this->GetRangeBase() == rhs.GetRangeBase() &&
633 this->GetByteSize() == rhs.GetByteSize() && this->data == rhs.data;
636 bool operator!=(const RangeData &rhs) const {
637 return this->GetRangeBase() != rhs.GetRangeBase() ||
638 this->GetByteSize() != rhs.GetByteSize() || this->data != rhs.data;
642 template <typename B, typename S, typename T, unsigned N> class RangeDataArray {
644 typedef RangeData<B, S, T> Entry;
645 typedef llvm::SmallVector<Entry, N> Collection;
647 RangeDataArray() = default;
649 ~RangeDataArray() = default;
651 void Append(const Entry &entry) { m_entries.push_back(entry); }
654 if (m_entries.size() > 1)
655 std::stable_sort(m_entries.begin(), m_entries.end());
658 #ifdef ASSERT_RANGEMAP_ARE_SORTED
659 bool IsSorted() const {
660 typename Collection::const_iterator pos, end, prev;
661 // First we determine if we can combine any of the Entry objects so we
662 // don't end up allocating and making a new collection for no reason
663 for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end;
665 if (prev != end && *pos < *prev)
672 void CombineConsecutiveEntriesWithEqualData() {
673 #ifdef ASSERT_RANGEMAP_ARE_SORTED
676 typename Collection::iterator pos;
677 typename Collection::iterator end;
678 typename Collection::iterator prev;
679 bool can_combine = false;
680 // First we determine if we can combine any of the Entry objects so we
681 // don't end up allocating and making a new collection for no reason
682 for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end;
684 if (prev != end && prev->data == pos->data) {
690 // We we can combine at least one entry, then we make a new collection and
691 // populate it accordingly, and then swap it into place.
693 Collection minimal_ranges;
694 for (pos = m_entries.begin(), end = m_entries.end(), prev = end;
695 pos != end; prev = pos++) {
696 if (prev != end && prev->data == pos->data)
697 minimal_ranges.back().SetRangeEnd(pos->GetRangeEnd());
699 minimal_ranges.push_back(*pos);
701 // Use the swap technique in case our new vector is much smaller. We must
702 // swap when using the STL because std::vector objects never release or
703 // reduce the memory once it has been allocated/reserved.
704 m_entries.swap(minimal_ranges);
708 void Clear() { m_entries.clear(); }
710 bool IsEmpty() const { return m_entries.empty(); }
712 size_t GetSize() const { return m_entries.size(); }
714 const Entry *GetEntryAtIndex(size_t i) const {
715 return ((i < m_entries.size()) ? &m_entries[i] : nullptr);
718 // Clients must ensure that "i" is a valid index prior to calling this
720 const Entry &GetEntryRef(size_t i) const { return m_entries[i]; }
722 static bool BaseLessThan(const Entry &lhs, const Entry &rhs) {
723 return lhs.GetRangeBase() < rhs.GetRangeBase();
726 uint32_t FindEntryIndexThatContains(B addr) const {
727 #ifdef ASSERT_RANGEMAP_ARE_SORTED
730 if (!m_entries.empty()) {
731 Entry entry(addr, 1);
732 typename Collection::const_iterator begin = m_entries.begin();
733 typename Collection::const_iterator end = m_entries.end();
734 typename Collection::const_iterator pos =
735 std::lower_bound(begin, end, entry, BaseLessThan);
737 if (pos != end && pos->Contains(addr)) {
738 return std::distance(begin, pos);
739 } else if (pos != begin) {
741 if (pos->Contains(addr))
742 return std::distance(begin, pos);
748 Entry *FindEntryThatContains(B addr) {
749 #ifdef ASSERT_RANGEMAP_ARE_SORTED
752 if (!m_entries.empty()) {
754 entry.SetRangeBase(addr);
755 entry.SetByteSize(1);
756 typename Collection::iterator begin = m_entries.begin();
757 typename Collection::iterator end = m_entries.end();
758 typename Collection::iterator pos =
759 std::lower_bound(begin, end, entry, BaseLessThan);
761 if (pos != end && pos->Contains(addr)) {
763 } else if (pos != begin) {
765 if (pos->Contains(addr)) {
773 const Entry *FindEntryThatContains(B addr) const {
774 #ifdef ASSERT_RANGEMAP_ARE_SORTED
777 if (!m_entries.empty()) {
779 entry.SetRangeBase(addr);
780 entry.SetByteSize(1);
781 typename Collection::const_iterator begin = m_entries.begin();
782 typename Collection::const_iterator end = m_entries.end();
783 typename Collection::const_iterator pos =
784 std::lower_bound(begin, end, entry, BaseLessThan);
786 if (pos != end && pos->Contains(addr)) {
788 } else if (pos != begin) {
790 if (pos->Contains(addr)) {
798 const Entry *FindEntryThatContains(const Entry &range) const {
799 #ifdef ASSERT_RANGEMAP_ARE_SORTED
802 if (!m_entries.empty()) {
803 typename Collection::const_iterator begin = m_entries.begin();
804 typename Collection::const_iterator end = m_entries.end();
805 typename Collection::const_iterator pos =
806 std::lower_bound(begin, end, range, BaseLessThan);
808 if (pos != end && pos->Contains(range)) {
810 } else if (pos != begin) {
812 if (pos->Contains(range)) {
820 Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); }
822 const Entry *Back() const {
823 return (m_entries.empty() ? nullptr : &m_entries.back());
827 Collection m_entries;
830 // Same as RangeDataArray, but uses std::vector as to not require static
831 // storage of N items in the class itself
832 template <typename B, typename S, typename T> class RangeDataVector {
834 typedef RangeData<B, S, T> Entry;
835 typedef std::vector<Entry> Collection;
837 RangeDataVector() = default;
839 ~RangeDataVector() = default;
841 void Append(const Entry &entry) { m_entries.push_back(entry); }
844 if (m_entries.size() > 1)
845 std::stable_sort(m_entries.begin(), m_entries.end());
848 #ifdef ASSERT_RANGEMAP_ARE_SORTED
849 bool IsSorted() const {
850 typename Collection::const_iterator pos, end, prev;
851 // First we determine if we can combine any of the Entry objects so we
852 // don't end up allocating and making a new collection for no reason
853 for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end;
855 if (prev != end && *pos < *prev)
862 void CombineConsecutiveEntriesWithEqualData() {
863 #ifdef ASSERT_RANGEMAP_ARE_SORTED
866 typename Collection::iterator pos;
867 typename Collection::iterator end;
868 typename Collection::iterator prev;
869 bool can_combine = false;
870 // First we determine if we can combine any of the Entry objects so we
871 // don't end up allocating and making a new collection for no reason
872 for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end;
874 if (prev != end && prev->data == pos->data) {
880 // We we can combine at least one entry, then we make a new collection and
881 // populate it accordingly, and then swap it into place.
883 Collection minimal_ranges;
884 for (pos = m_entries.begin(), end = m_entries.end(), prev = end;
885 pos != end; prev = pos++) {
886 if (prev != end && prev->data == pos->data)
887 minimal_ranges.back().SetRangeEnd(pos->GetRangeEnd());
889 minimal_ranges.push_back(*pos);
891 // Use the swap technique in case our new vector is much smaller. We must
892 // swap when using the STL because std::vector objects never release or
893 // reduce the memory once it has been allocated/reserved.
894 m_entries.swap(minimal_ranges);
898 // Calculate the byte size of ranges with zero byte sizes by finding the next
899 // entry with a base address > the current base address
900 void CalculateSizesOfZeroByteSizeRanges(S full_size = 0) {
901 #ifdef ASSERT_RANGEMAP_ARE_SORTED
904 typename Collection::iterator pos;
905 typename Collection::iterator end;
906 typename Collection::iterator next;
907 for (pos = m_entries.begin(), end = m_entries.end(); pos != end; ++pos) {
908 if (pos->GetByteSize() == 0) {
909 // Watch out for multiple entries with same address and make sure we
910 // find an entry that is greater than the current base address before
911 // we use that for the size
912 auto curr_base = pos->GetRangeBase();
913 for (next = pos + 1; next != end; ++next) {
914 auto next_base = next->GetRangeBase();
915 if (next_base > curr_base) {
916 pos->SetByteSize(next_base - curr_base);
920 if (next == end && full_size > curr_base)
921 pos->SetByteSize(full_size - curr_base);
926 void Clear() { m_entries.clear(); }
928 void Reserve(typename Collection::size_type size) { m_entries.resize(size); }
930 bool IsEmpty() const { return m_entries.empty(); }
932 size_t GetSize() const { return m_entries.size(); }
934 const Entry *GetEntryAtIndex(size_t i) const {
935 return ((i < m_entries.size()) ? &m_entries[i] : nullptr);
938 Entry *GetMutableEntryAtIndex(size_t i) {
939 return ((i < m_entries.size()) ? &m_entries[i] : nullptr);
942 // Clients must ensure that "i" is a valid index prior to calling this
944 const Entry &GetEntryRef(size_t i) const { return m_entries[i]; }
946 static bool BaseLessThan(const Entry &lhs, const Entry &rhs) {
947 return lhs.GetRangeBase() < rhs.GetRangeBase();
950 uint32_t FindEntryIndexThatContains(B addr) const {
951 #ifdef ASSERT_RANGEMAP_ARE_SORTED
954 if (!m_entries.empty()) {
955 Entry entry(addr, 1);
956 typename Collection::const_iterator begin = m_entries.begin();
957 typename Collection::const_iterator end = m_entries.end();
958 typename Collection::const_iterator pos =
959 std::lower_bound(begin, end, entry, BaseLessThan);
961 while (pos != begin && pos[-1].Contains(addr))
964 if (pos != end && pos->Contains(addr))
965 return std::distance(begin, pos);
970 uint32_t FindEntryIndexesThatContain(B addr,
971 std::vector<uint32_t> &indexes) const {
972 #ifdef ASSERT_RANGEMAP_ARE_SORTED
976 if (!m_entries.empty()) {
977 for (const auto &entry : m_entries) {
978 if (entry.Contains(addr))
979 indexes.push_back(entry.data);
982 return indexes.size();
985 Entry *FindEntryThatContains(B addr) {
986 #ifdef ASSERT_RANGEMAP_ARE_SORTED
989 if (!m_entries.empty()) {
991 entry.SetRangeBase(addr);
992 entry.SetByteSize(1);
993 typename Collection::iterator begin = m_entries.begin();
994 typename Collection::iterator end = m_entries.end();
995 typename Collection::iterator pos =
996 std::lower_bound(begin, end, entry, BaseLessThan);
998 while (pos != begin && pos[-1].Contains(addr))
1001 if (pos != end && pos->Contains(addr))
1007 const Entry *FindEntryThatContains(B addr) const {
1008 #ifdef ASSERT_RANGEMAP_ARE_SORTED
1011 if (!m_entries.empty()) {
1013 entry.SetRangeBase(addr);
1014 entry.SetByteSize(1);
1015 typename Collection::const_iterator begin = m_entries.begin();
1016 typename Collection::const_iterator end = m_entries.end();
1017 typename Collection::const_iterator pos =
1018 std::lower_bound(begin, end, entry, BaseLessThan);
1020 while (pos != begin && pos[-1].Contains(addr))
1023 if (pos != end && pos->Contains(addr))
1029 const Entry *FindEntryThatContains(const Entry &range) const {
1030 #ifdef ASSERT_RANGEMAP_ARE_SORTED
1033 if (!m_entries.empty()) {
1034 typename Collection::const_iterator begin = m_entries.begin();
1035 typename Collection::const_iterator end = m_entries.end();
1036 typename Collection::const_iterator pos =
1037 std::lower_bound(begin, end, range, BaseLessThan);
1039 while (pos != begin && pos[-1].Contains(range))
1042 if (pos != end && pos->Contains(range))
1048 const Entry *FindEntryStartsAt(B addr) const {
1049 #ifdef ASSERT_RANGEMAP_ARE_SORTED
1052 if (!m_entries.empty()) {
1053 auto begin = m_entries.begin(), end = m_entries.end();
1054 auto pos = std::lower_bound(begin, end, Entry(addr, 1), BaseLessThan);
1055 if (pos != end && pos->base == addr)
1061 // This method will return the entry that contains the given address, or the
1062 // entry following that address. If you give it an address of 0 and the
1063 // first entry starts at address 0x100, you will get the entry at 0x100.
1065 // For most uses, FindEntryThatContains is the correct one to use, this is a
1066 // less commonly needed behavior. It was added for core file memory regions,
1067 // where we want to present a gap in the memory regions as a distinct region,
1068 // so we need to know the start address of the next memory section that
1070 const Entry *FindEntryThatContainsOrFollows(B addr) const {
1071 #ifdef ASSERT_RANGEMAP_ARE_SORTED
1074 if (!m_entries.empty()) {
1075 typename Collection::const_iterator begin = m_entries.begin();
1076 typename Collection::const_iterator end = m_entries.end();
1077 typename Collection::const_iterator pos =
1078 std::lower_bound(m_entries.begin(), end, addr,
1079 [](const Entry &lhs, B rhs_base) -> bool {
1080 return lhs.GetRangeEnd() <= rhs_base;
1083 while (pos != begin && pos[-1].Contains(addr))
1092 Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); }
1094 const Entry *Back() const {
1095 return (m_entries.empty() ? nullptr : &m_entries.back());
1099 Collection m_entries;
1102 //----------------------------------------------------------------------
1103 // A simple range with data class where you get to define the type of
1104 // the range base "B", the type used for the range byte size "S", and the type
1105 // for the associated data "T".
1106 //----------------------------------------------------------------------
1107 template <typename B, typename T> struct AddressData {
1114 AddressData() : addr(), data() {}
1116 AddressData(B a, DataType d) : addr(a), data(d) {}
1118 bool operator<(const AddressData &rhs) const {
1119 if (this->addr == rhs.addr)
1120 return this->data < rhs.data;
1121 return this->addr < rhs.addr;
1124 bool operator==(const AddressData &rhs) const {
1125 return this->addr == rhs.addr && this->data == rhs.data;
1128 bool operator!=(const AddressData &rhs) const {
1129 return this->addr != rhs.addr || this->data == rhs.data;
1133 template <typename B, typename T, unsigned N> class AddressDataArray {
1135 typedef AddressData<B, T> Entry;
1136 typedef llvm::SmallVector<Entry, N> Collection;
1138 AddressDataArray() = default;
1140 ~AddressDataArray() = default;
1142 void Append(const Entry &entry) { m_entries.push_back(entry); }
1145 if (m_entries.size() > 1)
1146 std::stable_sort(m_entries.begin(), m_entries.end());
1149 #ifdef ASSERT_RANGEMAP_ARE_SORTED
1150 bool IsSorted() const {
1151 typename Collection::const_iterator pos, end, prev;
1152 // First we determine if we can combine any of the Entry objects so we
1153 // don't end up allocating and making a new collection for no reason
1154 for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end;
1156 if (prev != end && *pos < *prev)
1163 void Clear() { m_entries.clear(); }
1165 bool IsEmpty() const { return m_entries.empty(); }
1167 size_t GetSize() const { return m_entries.size(); }
1169 const Entry *GetEntryAtIndex(size_t i) const {
1170 return ((i < m_entries.size()) ? &m_entries[i] : nullptr);
1173 // Clients must ensure that "i" is a valid index prior to calling this
1175 const Entry &GetEntryRef(size_t i) const { return m_entries[i]; }
1177 static bool BaseLessThan(const Entry &lhs, const Entry &rhs) {
1178 return lhs.addr < rhs.addr;
1181 Entry *FindEntry(B addr, bool exact_match_only) {
1182 #ifdef ASSERT_RANGEMAP_ARE_SORTED
1185 if (!m_entries.empty()) {
1188 typename Collection::iterator begin = m_entries.begin();
1189 typename Collection::iterator end = m_entries.end();
1190 typename Collection::iterator pos =
1191 std::lower_bound(begin, end, entry, BaseLessThan);
1193 while (pos != begin && pos[-1].addr == addr)
1197 if (pos->addr == addr || !exact_match_only)
1204 const Entry *FindNextEntry(const Entry *entry) {
1205 if (entry >= &*m_entries.begin() && entry + 1 < &*m_entries.end())
1210 Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); }
1212 const Entry *Back() const {
1213 return (m_entries.empty() ? nullptr : &m_entries.back());
1217 Collection m_entries;
1220 } // namespace lldb_private
1222 #endif // liblldb_RangeMap_h_