summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>2014-07-15 18:32:30 +0000
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>2014-07-15 18:32:30 +0000
commitdb88e31e1aad26f1067017a88234e261f369c682 (patch)
treee26b50ca93480b39d06e61124f85ff1584f71a52 /llvm
parenteeb7e65c5fca09825cfcd7a24a7670bbcb010cbb (diff)
downloadbcm5719-llvm-db88e31e1aad26f1067017a88234e261f369c682.tar.gz
bcm5719-llvm-db88e31e1aad26f1067017a88234e261f369c682.zip
ADT: Fix MapVector::erase()
Actually update the changed indexes in the map portion of `MapVector` when erasing from the middle. Add a unit test that checks for this. Note that `MapVector::erase()` is a linear time operation (it was and still is). I'll commit a new method in a moment called `MapVector::remove_if()` that deletes multiple entries in linear time, which should be slightly less painful. llvm-svn: 213084
Diffstat (limited to 'llvm')
-rw-r--r--llvm/docs/ProgrammersManual.rst2
-rw-r--r--llvm/include/llvm/ADT/MapVector.h20
-rw-r--r--llvm/unittests/ADT/MapVectorTest.cpp15
3 files changed, 33 insertions, 4 deletions
diff --git a/llvm/docs/ProgrammersManual.rst b/llvm/docs/ProgrammersManual.rst
index a7b28b36ca1..e828e6bf501 100644
--- a/llvm/docs/ProgrammersManual.rst
+++ b/llvm/docs/ProgrammersManual.rst
@@ -1442,7 +1442,7 @@ iteration over maps of pointers.
It is implemented by mapping from key to an index in a vector of key,value
pairs. This provides fast lookup and iteration, but has two main drawbacks: The
-key is stored twice and it doesn't support removing elements.
+key is stored twice and removing elements takes linear time.
.. _dss_inteqclasses:
diff --git a/llvm/include/llvm/ADT/MapVector.h b/llvm/include/llvm/ADT/MapVector.h
index a89f4a76e44..0fa68245ff4 100644
--- a/llvm/include/llvm/ADT/MapVector.h
+++ b/llvm/include/llvm/ADT/MapVector.h
@@ -125,12 +125,26 @@ public:
}
/// \brief Remove the element given by Iterator.
+ ///
/// Returns an iterator to the element following the one which was removed,
/// which may be end().
+ ///
+ /// \note This is a deceivingly expensive operation (linear time). It's
+ /// usually better to use \a remove_if() if possible.
typename VectorType::iterator erase(typename VectorType::iterator Iterator) {
- typename MapType::iterator MapIterator = Map.find(Iterator->first);
- Map.erase(MapIterator);
- return Vector.erase(Iterator);
+ Map.erase(Iterator->first);
+ auto Next = Vector.erase(Iterator);
+ if (Next == Vector.end())
+ return Next;
+
+ // Update indices in the map.
+ size_t Index = Next - Vector.begin();
+ for (auto &I : Map) {
+ assert(I.second != Index && "Index was already erased!");
+ if (I.second > Index)
+ --I.second;
+ }
+ return Next;
}
};
diff --git a/llvm/unittests/ADT/MapVectorTest.cpp b/llvm/unittests/ADT/MapVectorTest.cpp
index 11178bc15e8..dd84e7ebd13 100644
--- a/llvm/unittests/ADT/MapVectorTest.cpp
+++ b/llvm/unittests/ADT/MapVectorTest.cpp
@@ -53,3 +53,18 @@ TEST(MapVectorTest, insert_pop) {
EXPECT_EQ(MV[1], 2);
EXPECT_EQ(MV[4], 7);
}
+
+TEST(MapVectorTest, erase) {
+ MapVector<int, int> MV;
+
+ MV.insert(std::make_pair(1, 2));
+ MV.insert(std::make_pair(3, 4));
+ MV.insert(std::make_pair(5, 6));
+ ASSERT_EQ(MV.size(), 3u);
+
+ MV.erase(MV.find(1));
+ ASSERT_EQ(MV.size(), 2u);
+ ASSERT_EQ(MV.find(1), MV.end());
+ ASSERT_EQ(MV[3], 4);
+ ASSERT_EQ(MV[5], 6);
+}
OpenPOWER on IntegriCloud