summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Blaikie <dblaikie@gmail.com>2014-06-09 22:26:20 +0000
committerDavid Blaikie <dblaikie@gmail.com>2014-06-09 22:26:20 +0000
commit78b4fd3a4b55d7f8b95fb56b5b4f76c83e369ae1 (patch)
tree01789910a929f80da6375b3dda1560e59982ff3c
parent8e38e862667e89ac928b8f5e7ce0a91c84fae4bc (diff)
downloadllvm-78b4fd3a4b55d7f8b95fb56b5b4f76c83e369ae1.tar.gz
llvm-78b4fd3a4b55d7f8b95fb56b5b4f76c83e369ae1.tar.bz2
llvm-78b4fd3a4b55d7f8b95fb56b5b4f76c83e369ae1.tar.xz
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@210495 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/ADT/SmallVector.h3
-rw-r--r--unittests/ADT/SmallVectorTest.cpp34
2 files changed, 32 insertions, 5 deletions
diff --git a/include/llvm/ADT/SmallVector.h b/include/llvm/ADT/SmallVector.h
index c00248dab5..82538e9bd1 100644
--- a/include/llvm/ADT/SmallVector.h
+++ b/include/llvm/ADT/SmallVector.h
@@ -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);
}
}
diff --git a/unittests/ADT/SmallVectorTest.cpp b/unittests/ADT/SmallVectorTest.cpp
index 760d734386..99deb0c68a 100644
--- a/unittests/ADT/SmallVectorTest.cpp
+++ b/unittests/ADT/SmallVectorTest.cpp
@@ -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, ResizeGrowTest) {
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");