[Lldb-commits] [lldb] 81d7eba - [lldb/Utility] Fix a bug in RangeMap::CombineConsecutiveRanges

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Mon Jul 27 01:07:12 PDT 2020


Author: Pavel Labath
Date: 2020-07-27T10:06:56+02:00
New Revision: 81d7ebaf5c369d42b77f9e3e47e2ac22c306ec04

URL: https://github.com/llvm/llvm-project/commit/81d7ebaf5c369d42b77f9e3e47e2ac22c306ec04
DIFF: https://github.com/llvm/llvm-project/commit/81d7ebaf5c369d42b77f9e3e47e2ac22c306ec04.diff

LOG: [lldb/Utility] Fix a bug in RangeMap::CombineConsecutiveRanges

The function didn't combine a large entry which overlapped several other
entries, if those other entries were not overlapping among each other.

E.g., (0,20),(5,6),(10,11) produced (0,20),(10,11)

Now it just produced (0,20).

Added: 
    

Modified: 
    lldb/include/lldb/Utility/RangeMap.h
    lldb/unittests/Utility/RangeMapTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Utility/RangeMap.h b/lldb/include/lldb/Utility/RangeMap.h
index fb24c5a43479..118fdfd85fa9 100644
--- a/lldb/include/lldb/Utility/RangeMap.h
+++ b/lldb/include/lldb/Utility/RangeMap.h
@@ -194,41 +194,25 @@ template <typename B, typename S, unsigned N = 0> class RangeVector {
 #ifdef ASSERT_RANGEMAP_ARE_SORTED
     assert(IsSorted());
 #endif
-    // Can't combine if ranges if we have zero or one range
-    if (m_entries.size() > 1) {
-      // The list should be sorted prior to calling this function
-      typename Collection::iterator pos;
-      typename Collection::iterator end;
-      typename Collection::iterator prev;
-      bool can_combine = false;
-      // First we determine if we can combine any of the Entry objects so we
-      // don't end up allocating and making a new collection for no reason
-      for (pos = m_entries.begin(), end = m_entries.end(), prev = end;
-           pos != end; prev = pos++) {
-        if (prev != end && prev->DoesAdjoinOrIntersect(*pos)) {
-          can_combine = true;
-          break;
-        }
-      }
+    auto first_intersect = std::adjacent_find(
+        m_entries.begin(), m_entries.end(), [](const Entry &a, const Entry &b) {
+          return a.DoesAdjoinOrIntersect(b);
+        });
+    if (first_intersect == m_entries.end())
+      return;
 
-      // We we can combine at least one entry, then we make a new collection
-      // and populate it accordingly, and then swap it into place.
-      if (can_combine) {
-        Collection minimal_ranges;
-        for (pos = m_entries.begin(), end = m_entries.end(), prev = end;
-             pos != end; prev = pos++) {
-          if (prev != end && prev->DoesAdjoinOrIntersect(*pos))
-            minimal_ranges.back().SetRangeEnd(
-                std::max<BaseType>(prev->GetRangeEnd(), pos->GetRangeEnd()));
-          else
-            minimal_ranges.push_back(*pos);
-        }
-        // Use the swap technique in case our new vector is much smaller. We
-        // must swap when using the STL because std::vector objects never
-        // release or reduce the memory once it has been allocated/reserved.
-        m_entries.swap(minimal_ranges);
-      }
+    // We we can combine at least one entry, then we make a new collection and
+    // populate it accordingly, and then swap it into place.
+    auto pos = std::next(first_intersect);
+    Collection minimal_ranges(m_entries.begin(), pos);
+    for (; pos != m_entries.end(); ++pos) {
+      Entry &back = minimal_ranges.back();
+      if (back.DoesAdjoinOrIntersect(*pos))
+        back.SetRangeEnd(std::max(back.GetRangeEnd(), pos->GetRangeEnd()));
+      else
+        minimal_ranges.push_back(*pos);
     }
+    m_entries.swap(minimal_ranges);
   }
 
   BaseType GetMinRangeBase(BaseType fail_value) const {
@@ -353,6 +337,10 @@ template <typename B, typename S, unsigned N = 0> class RangeVector {
     return nullptr;
   }
 
+  using const_iterator = typename Collection::const_iterator;
+  const_iterator begin() const { return m_entries.begin(); }
+  const_iterator end() const { return m_entries.end(); }
+
 protected:
   void CombinePrevAndNext(typename Collection::iterator pos) {
     // Check if the prev or next entries in case they need to be unioned with

diff  --git a/lldb/unittests/Utility/RangeMapTest.cpp b/lldb/unittests/Utility/RangeMapTest.cpp
index 8a243b656218..97432dca983d 100644
--- a/lldb/unittests/Utility/RangeMapTest.cpp
+++ b/lldb/unittests/Utility/RangeMapTest.cpp
@@ -12,6 +12,32 @@
 
 using namespace lldb_private;
 
+TEST(RangeVector, CombineConsecutiveRanges) {
+  using RangeVector = RangeVector<uint32_t, uint32_t>;
+  using Entry = RangeVector::Entry;
+
+  RangeVector V;
+  V.Append(0, 1);
+  V.Append(5, 1);
+  V.Append(6, 1);
+  V.Append(10, 9);
+  V.Append(15, 1);
+  V.Append(20, 9);
+  V.Append(21, 9);
+  V.Sort();
+  V.CombineConsecutiveRanges();
+  EXPECT_THAT(V, testing::ElementsAre(Entry(0, 1), Entry(5, 2), Entry(10, 9),
+                                      Entry(20, 10)));
+
+  V.Clear();
+  V.Append(0, 20);
+  V.Append(5, 1);
+  V.Append(10, 1);
+  V.Sort();
+  V.CombineConsecutiveRanges();
+  EXPECT_THAT(V, testing::ElementsAre(Entry(0, 20)));
+}
+
 using RangeDataVectorT = RangeDataVector<uint32_t, uint32_t, uint32_t>;
 using EntryT = RangeDataVectorT::Entry;
 


        


More information about the lldb-commits mailing list