[llvm] r210495 - SmallVector: support resize(N) with move-only types

David Blaikie dblaikie at gmail.com
Mon Jun 9 15:26:21 PDT 2014


Author: dblaikie
Date: Mon Jun  9 17:26:20 2014
New Revision: 210495

URL: http://llvm.org/viewvc/llvm-project?rev=210495&view=rev
Log:
SmallVector: support resize(N) with move-only types

Unfortunately there's no way to elegantly do this with pre-canned
algorithms. Using a generating iterator doesn't work because you default
construct for each element, then move construct into the actual slot
(bad for copy but non-movable types, and a little unneeded overhead even
in the move-only case), so just write it out manually.

This solution isn't exception safe (if one of the element's ctors calls
we don't fall back, destroy the constructed elements, and throw on -
which std::uninitialized_fill does do) but SmallVector (and LLVM) isn't
exception safe anyway.

Modified:
    llvm/trunk/include/llvm/ADT/SmallVector.h
    llvm/trunk/unittests/ADT/SmallVectorTest.cpp

Modified: llvm/trunk/include/llvm/ADT/SmallVector.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/SmallVector.h?rev=210495&r1=210494&r2=210495&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/SmallVector.h (original)
+++ llvm/trunk/include/llvm/ADT/SmallVector.h Mon Jun  9 17:26:20 2014
@@ -380,7 +380,8 @@ public:
     } else if (N > this->size()) {
       if (this->capacity() < N)
         this->grow(N);
-      std::uninitialized_fill(this->end(), this->begin()+N, T());
+      for (auto I = this->end(), E = this->begin() + N; I != E; ++I)
+        new (&*I) T();
       this->setEnd(this->begin()+N);
     }
   }

Modified: llvm/trunk/unittests/ADT/SmallVectorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/SmallVectorTest.cpp?rev=210495&r1=210494&r2=210495&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/SmallVectorTest.cpp (original)
+++ llvm/trunk/unittests/ADT/SmallVectorTest.cpp Mon Jun  9 17:26:20 2014
@@ -139,6 +139,19 @@ int Constructable::numAssignmentCalls;
 int Constructable::numCopyAssignmentCalls;
 int Constructable::numMoveAssignmentCalls;
 
+struct NonCopyable {
+  NonCopyable() {}
+  NonCopyable(NonCopyable &&) {}
+  NonCopyable &operator=(NonCopyable &&) { return *this; }
+  NonCopyable(const NonCopyable &) = delete;
+  NonCopyable &operator=(const NonCopyable &) = delete;
+};
+
+LLVM_ATTRIBUTE_USED void CompileTest() {
+  SmallVector<NonCopyable, 0> V;
+  V.resize(42);
+}
+
 // Test fixture class
 template <typename VectorT>
 class SmallVectorTest : public testing::Test {
@@ -277,13 +290,26 @@ TYPED_TEST(SmallVectorTest, ResizeGrowTe
 
   this->theVector.resize(2);
 
-  // The extra constructor/destructor calls come from the temporary object used
-  // to initialize the contents of the resized array (via copy construction).
-  EXPECT_EQ(3, Constructable::getNumConstructorCalls());
-  EXPECT_EQ(1, Constructable::getNumDestructorCalls());
+  EXPECT_EQ(2, Constructable::getNumConstructorCalls());
+  EXPECT_EQ(0, Constructable::getNumDestructorCalls());
   EXPECT_EQ(2u, this->theVector.size());
 }
 
+TYPED_TEST(SmallVectorTest, ResizeWithElementsTest) {
+  this->theVector.resize(2);
+
+  Constructable::reset();
+
+  this->theVector.resize(4);
+
+  size_t Ctors = Constructable::getNumConstructorCalls();
+  EXPECT_TRUE(Ctors == 2 || Ctors == 4);
+  size_t MoveCtors = Constructable::getNumMoveConstructorCalls();
+  EXPECT_TRUE(MoveCtors == 0 || MoveCtors == 2);
+  size_t Dtors = Constructable::getNumDestructorCalls();
+  EXPECT_TRUE(Dtors == 0 || Dtors == 2);
+}
+
 // Resize with fill value.
 TYPED_TEST(SmallVectorTest, ResizeFillTest) {
   SCOPED_TRACE("ResizeFillTest");





More information about the llvm-commits mailing list