diff --git a/include/llvm/ADT/StringMap.h b/include/llvm/ADT/StringMap.h index ed3685d7ddf..f7c9c6efbf6 100644 --- a/include/llvm/ADT/StringMap.h +++ b/include/llvm/ADT/StringMap.h @@ -53,6 +53,12 @@ protected: : TheTable(nullptr), // Initialize the map with zero buckets to allocation. NumBuckets(0), NumItems(0), NumTombstones(0), ItemSize(itemSize) {} + StringMapImpl(StringMapImpl &&RHS) : TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets), NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones), ItemSize(RHS.ItemSize) { + RHS.TheTable = nullptr; + RHS.NumBuckets = 0; + RHS.NumItems = 0; + RHS.NumTombstones = 0; + } StringMapImpl(unsigned InitSize, unsigned ItemSize); void RehashTable(); @@ -233,16 +239,15 @@ public: Allocator(A) {} StringMap(StringMap &&RHS) - : StringMapImpl(static_cast(sizeof(MapEntryTy))) { - assert(RHS.empty()); - } - StringMap &operator=(StringMap &&RHS) { - assert(RHS.empty()); - clear(); + : StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {} + + StringMap &operator=(StringMap RHS) { + StringMapImpl::swap(RHS); + std::swap(Allocator, RHS.Allocator); return *this; } - StringMap(const StringMap &RHS) LLVM_DELETED_FUNCTION; - void operator=(const StringMap &RHS) LLVM_DELETED_FUNCTION; + + // FIXME: Implement copy operations if/when they're needed. AllocatorTy &getAllocator() { return Allocator; } const AllocatorTy &getAllocator() const { return Allocator; } diff --git a/unittests/ADT/StringMapTest.cpp b/unittests/ADT/StringMapTest.cpp index 42a03886180..be166b15a90 100644 --- a/unittests/ADT/StringMapTest.cpp +++ b/unittests/ADT/StringMapTest.cpp @@ -234,4 +234,71 @@ TEST_F(StringMapTest, MoveOnlyKey) { StringMapEntry::Create(Key.begin(), Key.end(), MoveOnly(42))->Destroy(); } +TEST_F(StringMapTest, MoveConstruct) { + StringMap A; + A.GetOrCreateValue("x", 42); + StringMap B = std::move(A); + ASSERT_EQ(A.size(), 0u); + ASSERT_EQ(B.size(), 1u); + ASSERT_EQ(B["x"], 42); + ASSERT_EQ(B.count("y"), 0u); +} + +TEST_F(StringMapTest, MoveAssignment) { + StringMap A; + A["x"] = 42; + StringMap B; + B["y"] = 117; + A = std::move(B); + ASSERT_EQ(A.size(), 1u); + ASSERT_EQ(B.size(), 0u); + ASSERT_EQ(A["y"], 117); + ASSERT_EQ(B.count("x"), 0u); +} + +struct Countable { + int &InstanceCount; + int Number; + Countable(int Number, int &InstanceCount) :InstanceCount(InstanceCount), Number(Number) { + ++InstanceCount; + } + Countable(Countable &&C) : InstanceCount(C.InstanceCount), Number(C.Number) { + ++InstanceCount; + C.Number = -1; + } + Countable(const Countable &C) : InstanceCount(C.InstanceCount), Number(C.Number) { + ++InstanceCount; + } + Countable &operator=(Countable C) { + Number = C.Number; + return *this; + } + ~Countable() { + --InstanceCount; + } + +}; + +TEST_F(StringMapTest, MoveDtor) { + int InstanceCount = 0; + StringMap A; + A.GetOrCreateValue("x", Countable(42, InstanceCount)); + ASSERT_EQ(InstanceCount, 1); + auto I = A.find("x"); + ASSERT_NE(I, A.end()); + ASSERT_EQ(I->second.Number, 42); + + StringMap B; + B = std::move(A); + ASSERT_EQ(InstanceCount, 1); + ASSERT_TRUE(A.empty()); + I = B.find("x"); + ASSERT_NE(I, B.end()); + ASSERT_EQ(I->second.Number, 42); + + B = StringMap(); + ASSERT_EQ(InstanceCount, 0); + ASSERT_TRUE(B.empty()); +} + } // end anonymous namespace