From 06bd8ca8c276d9bc20b192188224e1e5215666a0 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Tue, 31 Jul 2012 09:42:24 +0000 Subject: [PATCH] Implement copy and move assignment for TinyPtrVector. These try to re-use allocated vectors as much as possible. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@161041 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ADT/TinyPtrVector.h | 77 ++++++++++--- unittests/ADT/TinyPtrVectorTest.cpp | 166 ++++++++++++++++++++++++++++ 2 files changed, 228 insertions(+), 15 deletions(-) diff --git a/include/llvm/ADT/TinyPtrVector.h b/include/llvm/ADT/TinyPtrVector.h index a02c10edf72..1038c784480 100644 --- a/include/llvm/ADT/TinyPtrVector.h +++ b/include/llvm/ADT/TinyPtrVector.h @@ -32,20 +32,73 @@ public: llvm::PointerUnion Val; TinyPtrVector() {} - TinyPtrVector(const TinyPtrVector &RHS) : Val(RHS.Val) { - if (VecTy *V = Val.template dyn_cast()) - Val = new VecTy(*V); - } -#if LLVM_USE_RVALUE_REFERENCES - TinyPtrVector(TinyPtrVector &&RHS) : Val(RHS.Val) { - RHS.Val = (EltTy)0; - } -#endif ~TinyPtrVector() { if (VecTy *V = Val.template dyn_cast()) delete V; } + TinyPtrVector(const TinyPtrVector &RHS) : Val(RHS.Val) { + if (VecTy *V = Val.template dyn_cast()) + Val = new VecTy(*V); + } + TinyPtrVector &operator=(const TinyPtrVector &RHS) { + if (this == &RHS) + return *this; + if (RHS.empty()) { + this->clear(); + return *this; + } + + // Try to squeeze into the single slot. If it won't fit, allocate a copied + // vector. + if (Val.template is()) { + if (RHS.size() == 1) + Val = RHS.front(); + else + Val = new VecTy(*RHS.Val.template get()); + return *this; + } + + // If we have a full vector allocated, try to re-use it. + if (RHS.Val.template is()) { + Val.template get()->clear(); + Val.template get()->push_back(RHS.front()); + } else { + *Val.template get() = *RHS.Val.template get(); + } + return *this; + } + +#if LLVM_USE_RVALUE_REFERENCES + TinyPtrVector(TinyPtrVector &&RHS) : Val(RHS.Val) { + RHS.Val = (EltTy)0; + } + TinyPtrVector &operator=(TinyPtrVector &&RHS) { + if (this == &RHS) + return *this; + if (RHS.empty()) { + this->clear(); + return *this; + } + + // If this vector has been allocated on the heap, re-use it if cheap. If it + // would require more copying, just delete it and we'll steal the other + // side. + if (VecTy *V = Val.template dyn_cast()) { + if (RHS.Val.template is()) { + V->clear(); + V->push_back(RHS.front()); + return *this; + } + delete V; + } + + Val = RHS.Val; + RHS.Val = (EltTy)0; + return *this; + } +#endif + // implicit conversion operator to ArrayRef. operator ArrayRef() const { if (Val.isNull()) @@ -173,12 +226,6 @@ public: } return end(); } - -private: - void operator=(const TinyPtrVector&); // NOT IMPLEMENTED YET. -#if LLVM_USE_RVALUE_REFERENCES - void operator=(TinyPtrVector&&); // NOT IMPLEMENTED YET. -#endif }; } // end namespace llvm diff --git a/unittests/ADT/TinyPtrVectorTest.cpp b/unittests/ADT/TinyPtrVectorTest.cpp index 9f02b3ce0f7..94939279c14 100644 --- a/unittests/ADT/TinyPtrVectorTest.cpp +++ b/unittests/ADT/TinyPtrVectorTest.cpp @@ -60,6 +60,13 @@ protected: V.push_back(Values[i]); } + void setVectors(ArrayRef Values1, ArrayRef Values2) { + V.clear(); + appendValues(V, Values1); + V2.clear(); + appendValues(V2, Values2); + } + void expectValues(const VectorT &V, ArrayRef Values) { EXPECT_EQ(Values.empty(), V.empty()); EXPECT_EQ(Values.size(), V.size()); @@ -157,6 +164,165 @@ TYPED_TEST(TinyPtrVectorTest, CopyAndMoveCtorTest) { #endif } +TYPED_TEST(TinyPtrVectorTest, CopyAndMoveTest) { + this->V = this->V2; + this->expectValues(this->V, this->testArray(0)); + this->expectValues(this->V2, this->testArray(0)); +#if LLVM_USE_RVALUE_REFERENCES + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(0)); +#endif + + this->setVectors(this->testArray(1), this->testArray(0)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(0)); + this->expectValues(this->V2, this->testArray(0)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(1), this->testArray(0)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(0)); +#endif + + this->setVectors(this->testArray(2), this->testArray(0)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(0)); + this->expectValues(this->V2, this->testArray(0)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(2), this->testArray(0)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(0)); +#endif + + this->setVectors(this->testArray(42), this->testArray(0)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(0)); + this->expectValues(this->V2, this->testArray(0)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(42), this->testArray(0)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(0)); +#endif + + this->setVectors(this->testArray(0), this->testArray(1)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(1)); + this->expectValues(this->V2, this->testArray(1)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(0), this->testArray(1)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(1)); +#endif + + this->setVectors(this->testArray(0), this->testArray(2)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(2)); + this->expectValues(this->V2, this->testArray(2)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(0), this->testArray(2)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(2)); +#endif + + this->setVectors(this->testArray(0), this->testArray(42)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(42)); + this->expectValues(this->V2, this->testArray(42)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(0), this->testArray(42)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(42)); +#endif + + this->setVectors(this->testArray(1), this->testArray(1)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(1)); + this->expectValues(this->V2, this->testArray(1)); +#if LLVM_USE_RVALUE_REFERENCES + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(1)); +#endif + + this->setVectors(this->testArray(1), this->testArray(2)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(2)); + this->expectValues(this->V2, this->testArray(2)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(1), this->testArray(2)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(2)); +#endif + + this->setVectors(this->testArray(1), this->testArray(42)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(42)); + this->expectValues(this->V2, this->testArray(42)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(1), this->testArray(42)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(42)); +#endif + + this->setVectors(this->testArray(2), this->testArray(1)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(1)); + this->expectValues(this->V2, this->testArray(1)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(2), this->testArray(1)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(1)); +#endif + + this->setVectors(this->testArray(2), this->testArray(2)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(2)); + this->expectValues(this->V2, this->testArray(2)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(2), this->testArray(2)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(2)); +#endif + + this->setVectors(this->testArray(2), this->testArray(42)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(42)); + this->expectValues(this->V2, this->testArray(42)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(2), this->testArray(42)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(42)); +#endif + + this->setVectors(this->testArray(42), this->testArray(1)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(1)); + this->expectValues(this->V2, this->testArray(1)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(42), this->testArray(1)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(1)); +#endif + + this->setVectors(this->testArray(42), this->testArray(2)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(2)); + this->expectValues(this->V2, this->testArray(2)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(42), this->testArray(2)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(2)); +#endif + + this->setVectors(this->testArray(42), this->testArray(42)); + this->V = this->V2; + this->expectValues(this->V, this->testArray(42)); + this->expectValues(this->V2, this->testArray(42)); +#if LLVM_USE_RVALUE_REFERENCES + this->setVectors(this->testArray(42), this->testArray(42)); + this->V = std::move(this->V2); + this->expectValues(this->V, this->testArray(42)); +#endif +} + TYPED_TEST(TinyPtrVectorTest, EraseTest) { this->appendValues(this->V, this->testArray(1)); this->expectValues(this->V, this->testArray(1));