diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/ADT/Optional.h | 56 | ||||
-rw-r--r-- | llvm/unittests/ADT/OptionalTest.cpp | 49 |
2 files changed, 105 insertions, 0 deletions
diff --git a/llvm/include/llvm/ADT/Optional.h b/llvm/include/llvm/ADT/Optional.h index 0386e57f05f..591872e6591 100644 --- a/llvm/include/llvm/ADT/Optional.h +++ b/llvm/include/llvm/ADT/Optional.h @@ -20,6 +20,7 @@ #include "llvm/Support/AlignOf.h" #include "llvm/Support/Compiler.h" #include <cassert> +#include <new> #include <utility> 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<typename ...ArgTypes> + void emplace(ArgTypes &&...Args) { + reset(); + hasVal = true; + new (storage.buffer) T(std::forward<ArgTypes>(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<typename T1> + void emplace(T1 &&A1) { + reset(); + hasVal = true; + new (storage.buffer) T(std::forward<T1>(A1)); + } + + /// Create a new object by constructing it in place with the given arguments. + template<typename T1, typename T2> + void emplace(T1 &&A1, T2 &&A2) { + reset(); + hasVal = true; + new (storage.buffer) T(std::forward<T1>(A1), std::forward<T2>(A2)); + } + + /// Create a new object by constructing it in place with the given arguments. + template<typename T1, typename T2, typename T3> + void emplace(T1 &&A1, T2 &&A2, T3 &&A3) { + reset(); + hasVal = true; + new (storage.buffer) T(std::forward<T1>(A1), std::forward<T2>(A2), + std::forward<T3>(A3)); + } + + /// Create a new object by constructing it in place with the given arguments. + template<typename T1, typename T2, typename T3, typename T4> + void emplace(T1 &&A1, T2 &&A2, T3 &&A3, T4 &&A4) { + reset(); + hasVal = true; + new (storage.buffer) T(std::forward<T1>(A1), std::forward<T2>(A2), + std::forward<T3>(A3), std::forward<T4>(A4)); + } + +#endif // LLVM_HAS_VARIADIC_TEMPLATES + static inline Optional create(const T* y) { return y ? Optional(*y) : Optional(); } diff --git a/llvm/unittests/ADT/OptionalTest.cpp b/llvm/unittests/ADT/OptionalTest.cpp index 51c54523b88..5a763d76f45 100644 --- a/llvm/unittests/ADT/OptionalTest.cpp +++ b/llvm/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<MultiArgConstructor> 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<MoveOnly> 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) { |