forked from OSchip/llvm-project
Add move ctor/assignment to Optional<T>
Code review feedback for r175580 by Jordan Rose. llvm-svn: 175729
This commit is contained in:
parent
ab5be26af5
commit
1bcb538c3f
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue