From 360ef6f5cd31dc0038f1d6ec8a4246150d5846ea Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Sun, 8 Apr 2018 08:48:58 +0000 Subject: [PATCH] [ADT] Fix MapVector when 'Map::mapped_type != unsigned'. Previously MapVector assumed `Map::mapped_type` was `unsigned`. This caused problems when using MapVector with a user-specified map where this didn't hold (For example StringMap). This patch adjusts MapVector to use the same type as the underlying map, avoiding reference binding errors in functions like `insert`. llvm-svn: 329523 --- llvm/include/llvm/ADT/MapVector.h | 16 +++++++----- llvm/unittests/ADT/MapVectorTest.cpp | 39 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/llvm/include/llvm/ADT/MapVector.h b/llvm/include/llvm/ADT/MapVector.h index f69f8fd1b1e0..86ffc2244a34 100644 --- a/llvm/include/llvm/ADT/MapVector.h +++ b/llvm/include/llvm/ADT/MapVector.h @@ -39,6 +39,10 @@ class MapVector { MapType Map; VectorType Vector; + static_assert( + std::is_integral::value, + "The mapped_type of the specified Map must be an integral type"); + public: using value_type = typename VectorType::value_type; using size_type = typename VectorType::size_type; @@ -93,9 +97,9 @@ public: } ValueT &operator[](const KeyT &Key) { - std::pair Pair = std::make_pair(Key, 0); + std::pair Pair = std::make_pair(Key, 0); std::pair Result = Map.insert(Pair); - unsigned &I = Result.first->second; + auto &I = Result.first->second; if (Result.second) { Vector.push_back(std::make_pair(Key, ValueT())); I = Vector.size() - 1; @@ -112,9 +116,9 @@ public: } std::pair insert(const std::pair &KV) { - std::pair Pair = std::make_pair(KV.first, 0); + std::pair Pair = std::make_pair(KV.first, 0); std::pair Result = Map.insert(Pair); - unsigned &I = Result.first->second; + auto &I = Result.first->second; if (Result.second) { Vector.push_back(std::make_pair(KV.first, KV.second)); I = Vector.size() - 1; @@ -125,9 +129,9 @@ public: std::pair insert(std::pair &&KV) { // Copy KV.first into the map, then move it into the vector. - std::pair Pair = std::make_pair(KV.first, 0); + std::pair Pair = std::make_pair(KV.first, 0); std::pair Result = Map.insert(Pair); - unsigned &I = Result.first->second; + auto &I = Result.first->second; if (Result.second) { Vector.push_back(std::move(KV)); I = Vector.size() - 1; diff --git a/llvm/unittests/ADT/MapVectorTest.cpp b/llvm/unittests/ADT/MapVectorTest.cpp index bd6602b030f6..16e9b5a74f42 100644 --- a/llvm/unittests/ADT/MapVectorTest.cpp +++ b/llvm/unittests/ADT/MapVectorTest.cpp @@ -157,6 +157,45 @@ TEST(MapVectorTest, NonCopyable) { ASSERT_EQ(*MV.find(2)->second, 2); } +template struct MapVectorMappedTypeTest : ::testing::Test { + using int_type = IntType; +}; + +using MapIntTypes = ::testing::Types; +TYPED_TEST_CASE(MapVectorMappedTypeTest, MapIntTypes); + +TYPED_TEST(MapVectorMappedTypeTest, DifferentDenseMap) { + // Test that using a map with a mapped type other than 'unsigned' compiles + // and works. + using IntType = typename TestFixture::int_type; + using MapVectorType = MapVector>; + + MapVectorType MV; + std::pair R; + + R = MV.insert(std::make_pair(1, 2)); + ASSERT_EQ(R.first, MV.begin()); + EXPECT_EQ(R.first->first, 1); + EXPECT_EQ(R.first->second, 2); + EXPECT_TRUE(R.second); + + const std::pair Elem(1, 3); + R = MV.insert(Elem); + ASSERT_EQ(R.first, MV.begin()); + EXPECT_EQ(R.first->first, 1); + EXPECT_EQ(R.first->second, 2); + EXPECT_FALSE(R.second); + + int& value = MV[4]; + EXPECT_EQ(value, 0); + value = 5; + + EXPECT_EQ(MV.size(), 2u); + EXPECT_EQ(MV[1], 2); + EXPECT_EQ(MV[4], 5); +} + TEST(SmallMapVectorSmallTest, insert_pop) { SmallMapVector MV; std::pair::iterator, bool> R;