Index: include/llvm/ADT/StringMap.h =================================================================== --- include/llvm/ADT/StringMap.h +++ include/llvm/ADT/StringMap.h @@ -292,8 +292,10 @@ return ValueTy(); } + /// Lookup the ValueTy for the \p Key, or create a default constructed value + /// if the key is not in the map. ValueTy &operator[](StringRef Key) { - return insert(std::make_pair(Key, ValueTy())).first->second; + return emplace_second(Key).first->second; } /// count - Return 1 if the element is in the map, 0 otherwise. Index: unittests/ADT/StringMapTest.cpp =================================================================== --- unittests/ADT/StringMapTest.cpp +++ unittests/ADT/StringMapTest.cpp @@ -358,26 +358,28 @@ namespace { // Simple class that counts how many moves and copy happens when growing a map -struct CountCopyAndMove { +struct CountCtorCopyAndMove { + static unsigned Ctor; static unsigned Move; static unsigned Copy; int Data = 0; - CountCopyAndMove() {} - CountCopyAndMove(unsigned int Data) : Data(Data) {} + CountCtorCopyAndMove(unsigned int Data) : Data(Data) { Ctor++; } + CountCtorCopyAndMove() { Ctor++; } - CountCopyAndMove(const CountCopyAndMove &) { Copy++; } - CountCopyAndMove &operator=(const CountCopyAndMove &) { + CountCtorCopyAndMove(const CountCtorCopyAndMove &) { Copy++; } + CountCtorCopyAndMove &operator=(const CountCtorCopyAndMove &) { Copy++; return *this; } - CountCopyAndMove(CountCopyAndMove &&) { Move++; } - CountCopyAndMove &operator=(const CountCopyAndMove &&) { + CountCtorCopyAndMove(CountCtorCopyAndMove &&) { Move++; } + CountCtorCopyAndMove &operator=(const CountCtorCopyAndMove &&) { Move++; return *this; } }; -unsigned CountCopyAndMove::Copy = 0; -unsigned CountCopyAndMove::Move = 0; +unsigned CountCtorCopyAndMove::Copy = 0; +unsigned CountCtorCopyAndMove::Move = 0; +unsigned CountCtorCopyAndMove::Ctor = 0; } // anonymous namespace @@ -385,26 +387,40 @@ // buckets to insert N items without increasing allocation size. TEST(StringMapCustomTest, InitialSizeTest) { for (unsigned Size = 1; Size <= 1024; ++Size) { - StringMap Map(Size); - CountCopyAndMove::Copy = 0; - CountCopyAndMove::Move = 0; + StringMap Map(Size); + CountCtorCopyAndMove::Copy = 0; + CountCtorCopyAndMove::Move = 0; for (unsigned i = 0; i < Size; ++i) - Map.insert(std::make_pair(Twine(i).str(), CountCopyAndMove())); - EXPECT_EQ(Size * 2, CountCopyAndMove::Move); - EXPECT_EQ((unsigned)0, CountCopyAndMove::Copy); + Map.insert(std::make_pair(Twine(i).str(), CountCtorCopyAndMove())); + EXPECT_EQ(Size * 2, CountCtorCopyAndMove::Move); + EXPECT_EQ((unsigned)0, CountCtorCopyAndMove::Copy); } } // Test that we can "emplace" an element in the map without involving map/move TEST(StringMapCustomTest, EmplaceTest) { - StringMap Map(1); - CountCopyAndMove::Copy = 0; - CountCopyAndMove::Move = 0; + StringMap Map(1); + CountCtorCopyAndMove::Copy = 0; + CountCtorCopyAndMove::Move = 0; Map.emplace_second("abcd", 42); EXPECT_EQ(1u, Map.count("abcd")); - EXPECT_EQ(0u, CountCopyAndMove::Copy); - EXPECT_EQ(0u, CountCopyAndMove::Move); + EXPECT_EQ(0u, CountCtorCopyAndMove::Copy); + EXPECT_EQ(0u, CountCtorCopyAndMove::Move); + CountCtorCopyAndMove::Ctor = 0; EXPECT_EQ(42, Map["abcd"].Data); + EXPECT_EQ(0u, CountCtorCopyAndMove::Copy); + EXPECT_EQ(0u, CountCtorCopyAndMove::Move); +} + +TEST(StringMapCustomTest, BracketOperatorCtor) { + StringMap Map; + CountCtorCopyAndMove::Ctor = 0; + Map["abcd"]; + EXPECT_EQ(1u, CountCtorCopyAndMove::Ctor); + // Test that operator[] does not create a value when it is already in the map + CountCtorCopyAndMove::Ctor = 0; + Map["abcd"]; + EXPECT_EQ(0u, CountCtorCopyAndMove::Ctor); } } // end anonymous namespace