Future: some fixes re: handling of universal references
authorSven Over <over@fb.com>
Wed, 31 May 2017 16:43:09 +0000 (09:43 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Wed, 31 May 2017 16:50:33 +0000 (09:50 -0700)
Summary:
Callables that are passed as rvalues to makeFutureWith should be
executed as rvalues.
Generally callables that get captured by value should be executed
as rvalues, to allow passing e.g. folly::Partial objects that contain
move-only objects like unique_ptr or folly::Promise.
`collect` would move out of parameters passed as lvalues.

Reviewed By: fugalh

Differential Revision: D5120420

fbshipit-source-id: 1633c6b7e3fbb562f4d31e21d28c98b053de9912

folly/futures/Future-inl.h
folly/futures/detail/Core.h
folly/futures/helpers.h

index c4f9ca2f307ab6b49e6c1286f1947346d72867f4..4089a67647ca1ea893f2d8c2fc32120c2696d0a9 100644 (file)
@@ -324,7 +324,7 @@ template <class T>
 template <class F>
 Future<T> Future<T>::ensure(F&& func) {
   return this->then([funcw = std::forward<F>(func)](Try<T> && t) mutable {
 template <class F>
 Future<T> Future<T>::ensure(F&& func) {
   return this->then([funcw = std::forward<F>(func)](Try<T> && t) mutable {
-    funcw();
+    std::move(funcw)();
     return makeFuture(std::move(t));
   });
 }
     return makeFuture(std::move(t));
   });
 }
@@ -333,7 +333,7 @@ template <class T>
 template <class F>
 Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) {
   return within(dur, tk).onError([funcw = std::forward<F>(func)](
 template <class F>
 Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) {
   return within(dur, tk).onError([funcw = std::forward<F>(func)](
-      TimedOut const&) { return funcw(); });
+      TimedOut const&) { return std::move(funcw)(); });
 }
 
 template <class T>
 }
 
 template <class T>
@@ -457,8 +457,7 @@ inline Future<T> Future<T>::via(Executor* executor, int8_t priority) & {
 
 template <class Func>
 auto via(Executor* x, Func&& func)
 
 template <class Func>
 auto via(Executor* x, Func&& func)
-  -> Future<typename isFuture<decltype(func())>::Inner>
-{
+    -> Future<typename isFuture<decltype(std::declval<Func>()())>::Inner> {
   // TODO make this actually more performant. :-P #7260175
   return via(x).then(std::forward<Func>(func));
 }
   // TODO make this actually more performant. :-P #7260175
   return via(x).then(std::forward<Func>(func));
 }
@@ -504,7 +503,7 @@ makeFutureWith(F&& func) {
   using InnerType =
       typename isFuture<typename std::result_of<F()>::type>::Inner;
   try {
   using InnerType =
       typename isFuture<typename std::result_of<F()>::type>::Inner;
   try {
-    return func();
+    return std::forward<F>(func)();
   } catch (std::exception& e) {
     return makeFuture<InnerType>(
         exception_wrapper(std::current_exception(), e));
   } catch (std::exception& e) {
     return makeFuture<InnerType>(
         exception_wrapper(std::current_exception(), e));
@@ -522,9 +521,8 @@ typename std::enable_if<
 makeFutureWith(F&& func) {
   using LiftedResult =
       typename Unit::Lift<typename std::result_of<F()>::type>::type;
 makeFutureWith(F&& func) {
   using LiftedResult =
       typename Unit::Lift<typename std::result_of<F()>::type>::type;
-  return makeFuture<LiftedResult>(makeTryWith([&func]() mutable {
-    return func();
-  }));
+  return makeFuture<LiftedResult>(
+      makeTryWith([&func]() mutable { return std::forward<F>(func)(); }));
 }
 
 template <class T>
 }
 
 template <class T>
@@ -574,7 +572,7 @@ collectAll(Fs&&... fs) {
   auto ctx = std::make_shared<detail::CollectAllVariadicContext<
     typename std::decay<Fs>::type::value_type...>>();
   detail::collectVariadicHelper<detail::CollectAllVariadicContext>(
   auto ctx = std::make_shared<detail::CollectAllVariadicContext<
     typename std::decay<Fs>::type::value_type...>>();
   detail::collectVariadicHelper<detail::CollectAllVariadicContext>(
-    ctx, std::forward<typename std::decay<Fs>::type>(fs)...);
+      ctx, std::forward<Fs>(fs)...);
   return ctx->p.getFuture();
 }
 
   return ctx->p.getFuture();
 }
 
@@ -677,7 +675,7 @@ collect(Fs&&... fs) {
   auto ctx = std::make_shared<detail::CollectVariadicContext<
     typename std::decay<Fs>::type::value_type...>>();
   detail::collectVariadicHelper<detail::CollectVariadicContext>(
   auto ctx = std::make_shared<detail::CollectVariadicContext<
     typename std::decay<Fs>::type::value_type...>>();
   detail::collectVariadicHelper<detail::CollectVariadicContext>(
-    ctx, std::forward<typename std::decay<Fs>::type>(fs)...);
+      ctx, std::forward<Fs>(fs)...);
   return ctx->p.getFuture();
 }
 
   return ctx->p.getFuture();
 }
 
index 3124cda343b5046d0b8c8faed54de80d8c8d3edc..b196b6649ee54b02233019af16cae891477ff55b 100644 (file)
@@ -470,9 +470,11 @@ template <template <typename ...> class T, typename... Ts,
           typename THead, typename... TTail>
 void collectVariadicHelper(const std::shared_ptr<T<Ts...>>& ctx,
                            THead&& head, TTail&&... tail) {
           typename THead, typename... TTail>
 void collectVariadicHelper(const std::shared_ptr<T<Ts...>>& ctx,
                            THead&& head, TTail&&... tail) {
-  head.setCallback_([ctx](Try<typename THead::value_type>&& t) {
-    ctx->template setPartialResult<typename THead::value_type,
-                                   sizeof...(Ts) - sizeof...(TTail) - 1>(t);
+  using ValueType = typename std::decay<THead>::type::value_type;
+  std::forward<THead>(head).setCallback_([ctx](Try<ValueType>&& t) {
+    ctx->template setPartialResult<
+        ValueType,
+        sizeof...(Ts) - sizeof...(TTail)-1>(t);
   });
   // template tail-recursion
   collectVariadicHelper(ctx, std::forward<TTail>(tail)...);
   });
   // template tail-recursion
   collectVariadicHelper(ctx, std::forward<TTail>(tail)...);
index bc0b8b950e6aa07739d4dc24d188062dd1820e78..26187b8fa0662316bf66ca97471edb7c3364c854 100644 (file)
@@ -148,7 +148,7 @@ inline Future<Unit> via(
 /// easier to read and slightly more efficient.
 template <class Func>
 auto via(Executor*, Func&& func)
 /// easier to read and slightly more efficient.
 template <class Func>
 auto via(Executor*, Func&& func)
-  -> Future<typename isFuture<decltype(func())>::Inner>;
+    -> Future<typename isFuture<decltype(std::declval<Func>()())>::Inner>;
 
 /** When all the input Futures complete, the returned Future will complete.
   Errors do not cause early termination; this Future will always succeed
 
 /** When all the input Futures complete, the returned Future will complete.
   Errors do not cause early termination; this Future will always succeed