From efd63170c80d3f322f274552a2f04729b7cbb0fb Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Fri, 23 Jan 2015 06:25:17 +0000 Subject: [PATCH] [ADT] Add move operations to SmallVector from SmallVectorImpl. This makes it possible to move between SmallVectors of different sizes. Thanks to Dave Blaikie and Duncan Smith for patch feedback. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@226899 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ADT/SmallVector.h | 11 +++++ unittests/ADT/SmallVectorTest.cpp | 81 ++++++++++++++++++++++++++++--- 2 files changed, 86 insertions(+), 6 deletions(-) diff --git a/include/llvm/ADT/SmallVector.h b/include/llvm/ADT/SmallVector.h index 44a352119b0..da4ac10c0ba 100644 --- a/include/llvm/ADT/SmallVector.h +++ b/include/llvm/ADT/SmallVector.h @@ -921,6 +921,17 @@ public: SmallVectorImpl::operator=(::std::move(RHS)); return *this; } + + SmallVector(SmallVectorImpl &&RHS) : SmallVectorImpl(N) { + if (!RHS.empty()) + SmallVectorImpl::operator=(::std::move(RHS)); + } + + const SmallVector &operator=(SmallVectorImpl &&RHS) { + SmallVectorImpl::operator=(::std::move(RHS)); + return *this; + } + }; template diff --git a/unittests/ADT/SmallVectorTest.cpp b/unittests/ADT/SmallVectorTest.cpp index ba6c395e69f..f6e9bb965c6 100644 --- a/unittests/ADT/SmallVectorTest.cpp +++ b/unittests/ADT/SmallVectorTest.cpp @@ -153,17 +153,14 @@ LLVM_ATTRIBUTE_USED void CompileTest() { V.resize(42); } -// Test fixture class -template -class SmallVectorTest : public testing::Test { +class SmallVectorTestBase : public testing::Test { protected: - VectorT theVector; - VectorT otherVector; void SetUp() { Constructable::reset(); } + template void assertEmpty(VectorT & v) { // Size tests EXPECT_EQ(0u, v.size()); @@ -173,7 +170,8 @@ protected: EXPECT_TRUE(v.begin() == v.end()); } - // Assert that theVector contains the specified values, in order. + // Assert that v contains the specified values, in order. + template void assertValuesInOrder(VectorT & v, size_t size, ...) { EXPECT_EQ(size, v.size()); @@ -188,6 +186,7 @@ protected: } // Generate a sequence of values to initialize the vector. + template void makeSequence(VectorT & v, int start, int end) { for (int i = start; i <= end; ++i) { v.push_back(Constructable(i)); @@ -195,6 +194,15 @@ protected: } }; +// Test fixture class +template +class SmallVectorTest : public SmallVectorTestBase { +protected: + VectorT theVector; + VectorT otherVector; +}; + + typedef ::testing::Types, SmallVector, SmallVector, @@ -664,6 +672,67 @@ TYPED_TEST(SmallVectorTest, IteratorTest) { this->theVector.insert(this->theVector.end(), L.begin(), L.end()); } +template class DualSmallVectorsTest; + +template +class DualSmallVectorsTest> : public SmallVectorTestBase { +protected: + VectorT1 theVector; + VectorT2 otherVector; + + template + static unsigned NumBuiltinElts(const SmallVector&) { return N; } +}; + +typedef ::testing::Types< + // Small mode -> Small mode. + std::pair, SmallVector>, + // Small mode -> Big mode. + std::pair, SmallVector>, + // Big mode -> Small mode. + std::pair, SmallVector>, + // Big mode -> Big mode. + std::pair, SmallVector> + > DualSmallVectorTestTypes; + +TYPED_TEST_CASE(DualSmallVectorsTest, DualSmallVectorTestTypes); + +TYPED_TEST(DualSmallVectorsTest, MoveAssignment) { + SCOPED_TRACE("MoveAssignTest-DualVectorTypes"); + + // Set up our vector with four elements. + for (unsigned I = 0; I < 4; ++I) + this->otherVector.push_back(Constructable(I)); + + const Constructable *OrigDataPtr = this->otherVector.data(); + + // Move-assign from the other vector. + this->theVector = + std::move(static_cast&>(this->otherVector)); + + // Make sure we have the right result. + this->assertValuesInOrder(this->theVector, 4u, 0, 1, 2, 3); + + // Make sure the # of constructor/destructor calls line up. There + // are two live objects after clearing the other vector. + this->otherVector.clear(); + EXPECT_EQ(Constructable::getNumConstructorCalls()-4, + Constructable::getNumDestructorCalls()); + + // If the source vector (otherVector) was in small-mode, assert that we just + // moved the data pointer over. + EXPECT_TRUE(this->NumBuiltinElts(this->otherVector) == 4 || + this->theVector.data() == OrigDataPtr); + + // There shouldn't be any live objects any more. + this->theVector.clear(); + EXPECT_EQ(Constructable::getNumConstructorCalls(), + Constructable::getNumDestructorCalls()); + + // We shouldn't have copied anything in this whole process. + EXPECT_EQ(Constructable::getNumCopyConstructorCalls(), 0); +} + struct notassignable { int &x; notassignable(int &x) : x(x) {} -- 2.34.1