In-place construction for Future v2017.07.10.00
authorYedidya Feldblum <yfeldblum@fb.com>
Sun, 9 Jul 2017 03:59:42 +0000 (20:59 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Sun, 9 Jul 2017 04:07:06 +0000 (21:07 -0700)
Summary:
[Folly] In-place construction for `Future`.

Using `in_place` as the first argument. Avoid constructing a contained object and then moving it into the `Future`, which may be more expensive, by providing an unambiguous way to specify perfect forwarding.

And a matching overload of `makeFuture` for no particularly good reason.

Differential Revision: D5362324

fbshipit-source-id: e612965f34ed0fae5fac17db631f7eab9984c696

folly/futures/Future-inl.h
folly/futures/Future.h
folly/futures/detail/Core.h
folly/futures/test/FutureTest.cpp

index ab70c38d7bd436fdf8bc8253f0ed5320640320d9..84bf33a1e87068bab6d1fc6ce30786735d475331 100644 (file)
@@ -184,6 +184,14 @@ template <typename T2>
 Future<T>::Future(typename std::enable_if<std::is_same<Unit, T2>::value>::type*)
     : core_(new detail::Core<T>(Try<T>(T()))) {}
 
+template <class T>
+template <
+    class... Args,
+    typename std::enable_if<std::is_constructible<T, Args&&...>::value, int>::
+        type>
+Future<T>::Future(in_place_t, Args&&... args)
+    : core_(new detail::Core<T>(in_place, std::forward<Args>(args)...)) {}
+
 template <class T>
 Future<T>::~Future() {
   detach();
index e5e1fbe82bf98bbd1ec04fd2ac7fe623410e77de..f4959ba753f30c3e4192e3f0aaf3f98dab46d59c 100644 (file)
 
 #include <folly/Optional.h>
 #include <folly/Portability.h>
-#include <folly/futures/DrivableExecutor.h>
-#include <folly/futures/Promise.h>
 #include <folly/Try.h>
+#include <folly/Utility.h>
+#include <folly/futures/DrivableExecutor.h>
 #include <folly/futures/FutureException.h>
+#include <folly/futures/Promise.h>
 #include <folly/futures/detail/Types.h>
 
 // boring predeclarations and details
@@ -90,6 +91,12 @@ class Future {
   /* implicit */ Future(
       typename std::enable_if<std::is_same<Unit, T2>::value>::type* = nullptr);
 
+  template <
+      class... Args,
+      typename std::enable_if<std::is_constructible<T, Args&&...>::value, int>::
+          type = 0>
+  explicit Future(in_place_t, Args&&... args);
+
   ~Future();
 
   /** Return the reference to result. Should not be called if !isReady().
index 30d421c05d249035aa7295e9a4d60b0b0ef27624..dc91729fad4b014dc7ab096d3cdea1dc17e887bc 100644 (file)
@@ -19,6 +19,7 @@
 #include <atomic>
 #include <mutex>
 #include <stdexcept>
+#include <utility>
 #include <vector>
 
 #include <folly/Executor.h>
@@ -27,6 +28,7 @@
 #include <folly/Optional.h>
 #include <folly/ScopeGuard.h>
 #include <folly/Try.h>
+#include <folly/Utility.h>
 #include <folly/futures/FutureException.h>
 #include <folly/futures/detail/FSM.h>
 
@@ -87,6 +89,13 @@ class Core final {
       fsm_(State::OnlyResult),
       attached_(1) {}
 
+  template <typename... Args>
+  explicit Core(in_place_t, Args&&... args) noexcept(
+      noexcept(::new (nullptr) T(std::declval<Args&&>()...)))
+      : result_(in_place, in_place, std::forward<Args>(args)...),
+        fsm_(State::OnlyResult),
+        attached_(1) {}
+
   ~Core() {
     DCHECK(attached_ == 0);
   }
index e886a21a74bcb9e43244debb4bc30076a8c0f827..4dd3f2dc574239d9c6c5d76c5b567c0fbe6e23cb 100644 (file)
@@ -810,6 +810,11 @@ TEST(Future, ImplicitConstructor) {
   //auto f2 = []() -> Future<Unit> { }();
 }
 
+TEST(Future, InPlaceConstructor) {
+  auto f = Future<std::pair<int, double>>(in_place, 5, 3.2);
+  EXPECT_EQ(5, f.value().first);
+}
+
 TEST(Future, thenDynamic) {
   // folly::dynamic has a constructor that takes any T, this test makes
   // sure that we call the then lambda with folly::dynamic and not