[llvm] r218732 - Add an emplace(...) method to llvm::Optional<T>.

Jordan Rose jordan_rose at apple.com
Tue Sep 30 19:12:35 PDT 2014


Author: jrose
Date: Tue Sep 30 21:12:35 2014
New Revision: 218732

URL: http://llvm.org/viewvc/llvm-project?rev=218732&view=rev
Log:
Add an emplace(...) method to llvm::Optional<T>.

This can be used for in-place initialization of non-moveable types.
For compilers that don't support variadic templates, only up to four
arguments are supported. We can always add more, of course, but this
should be good enough until we move to a later MSVC that has full
support for variadic templates.

Inspired by std::experimental::optional from the "Library Fundamentals" C++ TS.
Reviewed by David Blaikie.

Modified:
    llvm/trunk/include/llvm/ADT/Optional.h
    llvm/trunk/unittests/ADT/OptionalTest.cpp

Modified: llvm/trunk/include/llvm/ADT/Optional.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/Optional.h?rev=218732&r1=218731&r2=218732&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/Optional.h (original)
+++ llvm/trunk/include/llvm/ADT/Optional.h Tue Sep 30 21:12:35 2014
@@ -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();
   }

Modified: llvm/trunk/unittests/ADT/OptionalTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/OptionalTest.cpp?rev=218732&r1=218731&r2=218732&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/OptionalTest.cpp (original)
+++ llvm/trunk/unittests/ADT/OptionalTest.cpp Tue Sep 30 21:12:35 2014
@@ -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, MoveOnlyAssigningAs
   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) {





More information about the llvm-commits mailing list