Implement copy and move assignment for TinyPtrVector. These try to
authorChandler Carruth <chandlerc@gmail.com>
Tue, 31 Jul 2012 09:42:24 +0000 (09:42 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Tue, 31 Jul 2012 09:42:24 +0000 (09:42 +0000)
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
unittests/ADT/TinyPtrVectorTest.cpp

index a02c10edf7215db675d06f1b29f81b68f41aa895..1038c784480bf231053a6398bd92ecc0c047f3f7 100644 (file)
@@ -32,19 +32,72 @@ public:
   llvm::PointerUnion<EltTy, VecTy*> Val;
 
   TinyPtrVector() {}
+  ~TinyPtrVector() {
+    if (VecTy *V = Val.template dyn_cast<VecTy*>())
+      delete V;
+  }
+
   TinyPtrVector(const TinyPtrVector &RHS) : Val(RHS.Val) {
     if (VecTy *V = Val.template dyn_cast<VecTy*>())
       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<EltTy>()) {
+      if (RHS.size() == 1)
+        Val = RHS.front();
+      else
+        Val = new VecTy(*RHS.Val.template get<VecTy*>());
+      return *this;
+    }
+
+    // If we have a full vector allocated, try to re-use it.
+    if (RHS.Val.template is<EltTy>()) {
+      Val.template get<VecTy*>()->clear();
+      Val.template get<VecTy*>()->push_back(RHS.front());
+    } else {
+      *Val.template get<VecTy*>() = *RHS.Val.template get<VecTy*>();
+    }
+    return *this;
+  }
+
 #if LLVM_USE_RVALUE_REFERENCES
   TinyPtrVector(TinyPtrVector &&RHS) : Val(RHS.Val) {
     RHS.Val = (EltTy)0;
   }
-#endif
-  ~TinyPtrVector() {
-    if (VecTy *V = Val.template dyn_cast<VecTy*>())
+  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<VecTy*>()) {
+      if (RHS.Val.template is<EltTy>()) {
+        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<EltTy>() const {
@@ -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
 
index 9f02b3ce0f76407aab5952e7eca7eb021ee6478d..94939279c14771f6bfdfff69dd97517797ca35a7 100644 (file)
@@ -60,6 +60,13 @@ protected:
       V.push_back(Values[i]);
   }
 
+  void setVectors(ArrayRef<PtrT> Values1, ArrayRef<PtrT> Values2) {
+    V.clear();
+    appendValues(V, Values1);
+    V2.clear();
+    appendValues(V2, Values2);
+  }
+
   void expectValues(const VectorT &V, ArrayRef<PtrT> 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));