Add move ctor/assignment to Optional<T>

Code review feedback for r175580 by Jordan Rose.

llvm-svn: 175729
This commit is contained in:
David Blaikie 2013-02-21 07:55:39 +00:00
parent ab5be26af5
commit 1bcb538c3f
2 changed files with 138 additions and 0 deletions

View File

@ -46,12 +46,41 @@ public:
Optional(T &&y) : hasVal(true) {
new (storage.buffer) T(std::forward<T>(y));
}
Optional(Optional<T> &&O) : hasVal(O) {
if (O) {
new (storage.buffer) T(std::move(*O));
O.reset();
}
}
Optional &operator=(T &&y) {
if (hasVal)
**this = std::move(y);
else {
new (storage.buffer) T(std::move(y));
hasVal = true;
}
return *this;
}
Optional &operator=(Optional &&O) {
if (!O)
reset();
else {
*this = std::move(*O);
O.reset();
}
return *this;
}
#endif
static inline Optional create(const T* y) {
return y ? Optional(*y) : Optional();
}
// FIXME: these assignments (& the equivalent const T&/const Optional& ctors)
// could be made more efficient by passing by value, possibly unifying them
// with the rvalue versions above - but this could place a different set of
// requirements (notably: the existence of a default ctor) when implemented
// in that way. Careful SFINAE to avoid such pitfalls would be required.
Optional &operator=(const T &y) {
if (hasVal)
**this = y;

View File

@ -40,6 +40,36 @@ unsigned NonDefaultConstructible::CopyConstructions = 0;
unsigned NonDefaultConstructible::Destructions = 0;
unsigned NonDefaultConstructible::CopyAssignments = 0;
struct MoveOnly {
static unsigned MoveConstructions;
static unsigned Destructions;
static unsigned MoveAssignments;
int val;
explicit MoveOnly(int val) : val(val) {
}
MoveOnly(MoveOnly&& other) {
val = other.val;
++MoveConstructions;
}
MoveOnly &operator=(MoveOnly&& other) {
val = other.val;
++MoveAssignments;
return *this;
}
~MoveOnly() {
++Destructions;
}
static void ResetCounts() {
MoveConstructions = 0;
Destructions = 0;
MoveAssignments = 0;
}
};
unsigned MoveOnly::MoveConstructions = 0;
unsigned MoveOnly::Destructions = 0;
unsigned MoveOnly::MoveAssignments = 0;
// Test fixture
class OptionalTest : public testing::Test {
};
@ -169,5 +199,84 @@ TEST_F(OptionalTest, NullCopyConstructionTest) {
EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
}
TEST_F(OptionalTest, MoveOnlyNull) {
MoveOnly::ResetCounts();
Optional<MoveOnly> O;
EXPECT_EQ(0u, MoveOnly::MoveConstructions);
EXPECT_EQ(0u, MoveOnly::MoveAssignments);
EXPECT_EQ(0u, MoveOnly::Destructions);
}
TEST_F(OptionalTest, MoveOnlyConstruction) {
MoveOnly::ResetCounts();
Optional<MoveOnly> O(MoveOnly(3));
EXPECT_TRUE((bool)O);
EXPECT_EQ(3, O->val);
EXPECT_EQ(1u, MoveOnly::MoveConstructions);
EXPECT_EQ(0u, MoveOnly::MoveAssignments);
EXPECT_EQ(1u, MoveOnly::Destructions);
}
TEST_F(OptionalTest, MoveOnlyMoveConstruction) {
Optional<MoveOnly> A(MoveOnly(3));
MoveOnly::ResetCounts();
Optional<MoveOnly> B(std::move(A));
EXPECT_FALSE((bool)A);
EXPECT_TRUE((bool)B);
EXPECT_EQ(3, B->val);
EXPECT_EQ(1u, MoveOnly::MoveConstructions);
EXPECT_EQ(0u, MoveOnly::MoveAssignments);
EXPECT_EQ(1u, MoveOnly::Destructions);
}
TEST_F(OptionalTest, MoveOnlyAssignment) {
MoveOnly::ResetCounts();
Optional<MoveOnly> O;
O = MoveOnly(3);
EXPECT_TRUE((bool)O);
EXPECT_EQ(3, O->val);
EXPECT_EQ(1u, MoveOnly::MoveConstructions);
EXPECT_EQ(0u, MoveOnly::MoveAssignments);
EXPECT_EQ(1u, MoveOnly::Destructions);
}
TEST_F(OptionalTest, MoveOnlyInitializingAssignment) {
Optional<MoveOnly> A(MoveOnly(3));
Optional<MoveOnly> B;
MoveOnly::ResetCounts();
B = std::move(A);
EXPECT_FALSE((bool)A);
EXPECT_TRUE((bool)B);
EXPECT_EQ(3, B->val);
EXPECT_EQ(1u, MoveOnly::MoveConstructions);
EXPECT_EQ(0u, MoveOnly::MoveAssignments);
EXPECT_EQ(1u, MoveOnly::Destructions);
}
TEST_F(OptionalTest, MoveOnlyNullingAssignment) {
Optional<MoveOnly> A;
Optional<MoveOnly> B(MoveOnly(3));
MoveOnly::ResetCounts();
B = std::move(A);
EXPECT_FALSE((bool)A);
EXPECT_FALSE((bool)B);
EXPECT_EQ(0u, MoveOnly::MoveConstructions);
EXPECT_EQ(0u, MoveOnly::MoveAssignments);
EXPECT_EQ(1u, MoveOnly::Destructions);
}
TEST_F(OptionalTest, MoveOnlyAssigningAssignment) {
Optional<MoveOnly> A(MoveOnly(3));
Optional<MoveOnly> B(MoveOnly(4));
MoveOnly::ResetCounts();
B = std::move(A);
EXPECT_FALSE((bool)A);
EXPECT_TRUE((bool)B);
EXPECT_EQ(3, B->val);
EXPECT_EQ(0u, MoveOnly::MoveConstructions);
EXPECT_EQ(1u, MoveOnly::MoveAssignments);
EXPECT_EQ(1u, MoveOnly::Destructions);
}
} // end anonymous namespace