diff --git a/include/llvm/ADT/Optional.h b/include/llvm/ADT/Optional.h index 0386e57f05f..591872e6591 100644 --- a/include/llvm/ADT/Optional.h +++ b/include/llvm/ADT/Optional.h @@ -20,6 +20,7 @@ #include "llvm/Support/AlignOf.h" #include "llvm/Support/Compiler.h" #include +#include #include namespace llvm { @@ -69,6 +70,61 @@ public: return *this; } +#if LLVM_HAS_VARIADIC_TEMPLATES + + /// Create a new object by constructing it in place with the given arguments. + template + void emplace(ArgTypes &&...Args) { + reset(); + hasVal = true; + new (storage.buffer) T(std::forward(Args)...); + } + +#else + + /// Create a new object by default-constructing it in place. + void emplace() { + reset(); + hasVal = true; + new (storage.buffer) T(); + } + + /// Create a new object by constructing it in place with the given arguments. + template + void emplace(T1 &&A1) { + reset(); + hasVal = true; + new (storage.buffer) T(std::forward(A1)); + } + + /// Create a new object by constructing it in place with the given arguments. + template + void emplace(T1 &&A1, T2 &&A2) { + reset(); + hasVal = true; + new (storage.buffer) T(std::forward(A1), std::forward(A2)); + } + + /// Create a new object by constructing it in place with the given arguments. + template + void emplace(T1 &&A1, T2 &&A2, T3 &&A3) { + reset(); + hasVal = true; + new (storage.buffer) T(std::forward(A1), std::forward(A2), + std::forward(A3)); + } + + /// Create a new object by constructing it in place with the given arguments. + template + void emplace(T1 &&A1, T2 &&A2, T3 &&A3, T4 &&A4) { + reset(); + hasVal = true; + new (storage.buffer) T(std::forward(A1), std::forward(A2), + std::forward(A3), std::forward(A4)); + } + +#endif // LLVM_HAS_VARIADIC_TEMPLATES + static inline Optional create(const T* y) { return y ? Optional(*y) : Optional(); } diff --git a/unittests/ADT/OptionalTest.cpp b/unittests/ADT/OptionalTest.cpp index 51c54523b88..5a763d76f45 100644 --- a/unittests/ADT/OptionalTest.cpp +++ b/unittests/ADT/OptionalTest.cpp @@ -177,6 +177,44 @@ TEST_F(OptionalTest, GetValueOr) { EXPECT_EQ(5, A.getValueOr(42)); } +struct MultiArgConstructor { + int x, y; + MultiArgConstructor(int x, int y) : x(x), y(y) {} + explicit MultiArgConstructor(int x, bool positive) + : x(x), y(positive ? x : -x) {} + + MultiArgConstructor(const MultiArgConstructor &) = delete; + MultiArgConstructor(MultiArgConstructor &&) = delete; + MultiArgConstructor &operator=(const MultiArgConstructor &) = delete; + MultiArgConstructor &operator=(MultiArgConstructor &&) = delete; + + static unsigned Destructions; + ~MultiArgConstructor() { + ++Destructions; + } + static void ResetCounts() { + Destructions = 0; + } +}; +unsigned MultiArgConstructor::Destructions = 0; + +TEST_F(OptionalTest, Emplace) { + MultiArgConstructor::ResetCounts(); + Optional A; + + A.emplace(1, 2); + EXPECT_TRUE(A.hasValue()); + EXPECT_EQ(1, A->x); + EXPECT_EQ(2, A->y); + EXPECT_EQ(0u, MultiArgConstructor::Destructions); + + A.emplace(5, false); + EXPECT_TRUE(A.hasValue()); + EXPECT_EQ(5, A->x); + EXPECT_EQ(-5, A->y); + EXPECT_EQ(1u, MultiArgConstructor::Destructions); +} + struct MoveOnly { static unsigned MoveConstructions; static unsigned Destructions; @@ -286,6 +324,17 @@ TEST_F(OptionalTest, MoveOnlyAssigningAssignment) { EXPECT_EQ(1u, MoveOnly::Destructions); } +TEST_F(OptionalTest, MoveOnlyEmplace) { + Optional A; + MoveOnly::ResetCounts(); + A.emplace(4); + EXPECT_TRUE((bool)A); + EXPECT_EQ(4, A->val); + EXPECT_EQ(0u, MoveOnly::MoveConstructions); + EXPECT_EQ(0u, MoveOnly::MoveAssignments); + EXPECT_EQ(0u, MoveOnly::Destructions); +} + #if LLVM_HAS_RVALUE_REFERENCE_THIS TEST_F(OptionalTest, MoveGetValueOr) {