optimize makeFuture and Future<T>::Future()
[folly.git] / folly / futures / Future.h
index 06572c6306fc4818bfbfd5ff5966af8d5667b2c2..40687b42b4f5cc7deb7dabcf7ace69105ad42e91 100644 (file)
@@ -55,10 +55,10 @@ class Future {
   Future& operator=(Future&&) noexcept;
 
   /// Construct a Future from a value (perfect forwarding)
-  /* implicit */
-  template <class T2 = T,
-            typename std::enable_if<!isFuture<T2>::value, void*>::type = nullptr>
-  Future(T2&& val);
+  template <class T2 = T, typename =
+            typename std::enable_if<
+              !isFuture<typename std::decay<T2>::type>::value>::type>
+  /* implicit */ Future(T2&& val);
 
   template <class T2 = T,
             typename std::enable_if<
@@ -97,14 +97,16 @@ class Future {
   // The ref-qualifier allows for `this` to be moved out so we
   // don't get access-after-free situations in chaining.
   // https://akrzemi1.wordpress.com/2014/06/02/ref-qualifiers/
-  template <typename Executor>
-  Future<T> via(Executor* executor) &&;
+  inline Future<T> via(
+      Executor* executor,
+      int8_t priority = Executor::MID_PRI) &&;
 
   /// This variant creates a new future, where the ref-qualifier && version
   /// moves `this` out. This one is less efficient but avoids confusing users
   /// when "return f.via(x);" fails.
-  template <typename Executor>
-  Future<T> via(Executor* executor) &;
+  inline Future<T> via(
+      Executor* executor,
+      int8_t priority = Executor::MID_PRI) &;
 
   /** True when the result (or exception) is ready. */
   bool isReady() const;
@@ -182,8 +184,6 @@ class Future {
   Future<typename isFuture<R>::Inner>
   then(R(Caller::*func)(Args...), Caller *instance);
 
-// TODO(6838553)
-#ifndef __clang__
   /// Execute the callback via the given Executor. The executor doesn't stick.
   ///
   /// Contrast
@@ -196,10 +196,10 @@ class Future {
   ///
   /// In the former both b and c execute via x. In the latter, only b executes
   /// via x, and c executes via the same executor (if any) that f had.
-  template <class... Args>
-  auto then(Executor* x, Args&&... args)
-    -> decltype(this->then(std::forward<Args>(args)...));
-#endif
+  template <class Executor, class Arg, class... Args>
+  auto then(Executor* x, Arg&& arg, Args&&... args)
+    -> decltype(this->then(std::forward<Arg>(arg),
+                           std::forward<Args>(args)...));
 
   /// Convenience method for ignoring the value and creating a Future<void>.
   /// Exceptions still propagate.
@@ -286,19 +286,19 @@ class Future {
   /// by then), and it is active (active by default).
   ///
   /// Inactive Futures will activate upon destruction.
-  Future<T>& activate() & {
+  Future<T>& activate() & DEPRECATED {
     core_->activate();
     return *this;
   }
-  Future<T>& deactivate() & {
+  Future<T>& deactivate() & DEPRECATED {
     core_->deactivate();
     return *this;
   }
-  Future<T> activate() && {
+  Future<T> activate() && DEPRECATED {
     core_->activate();
     return std::move(*this);
   }
-  Future<T> deactivate() && {
+  Future<T> deactivate() && DEPRECATED {
     core_->deactivate();
     return std::move(*this);
   }
@@ -375,6 +375,47 @@ class Future {
   template <class F>
   Future<T> filter(F predicate);
 
+  /// Like reduce, but works on a Future<std::vector<T / Try<T>>>, for example
+  /// the result of collect or collectAll
+  template <class I, class F>
+  Future<I> reduce(I&& initial, F&& func);
+
+  /// Create a Future chain from a sequence of callbacks. i.e.
+  ///
+  ///   f.then(a).then(b).then(c)
+  ///
+  /// where f is a Future<A> and the result of the chain is a Future<D>
+  /// becomes
+  ///
+  ///   f.thenMulti(a, b, c);
+  template <class Callback, class... Callbacks>
+  auto thenMulti(Callback&& fn, Callbacks&&... fns)
+    -> decltype(this->then(std::forward<Callback>(fn)).
+                      thenMulti(std::forward<Callbacks>(fns)...));
+
+  // Nothing to see here, just thenMulti's base case
+  template <class Callback>
+  auto thenMulti(Callback&& fn)
+    -> decltype(this->then(std::forward<Callback>(fn)));
+
+  /// Create a Future chain from a sequence of callbacks. i.e.
+  ///
+  ///   f.via(executor).then(a).then(b).then(c).via(oldExecutor)
+  ///
+  /// where f is a Future<A> and the result of the chain is a Future<D>
+  /// becomes
+  ///
+  ///   f.thenMultiWithExecutor(executor, a, b, c);
+  template <class Callback, class... Callbacks>
+  auto thenMultiWithExecutor(Executor* x, Callback&& fn, Callbacks&&... fns)
+    -> decltype(this->then(std::forward<Callback>(fn)).
+                      thenMulti(std::forward<Callbacks>(fns)...));
+
+  // Nothing to see here, just thenMultiWithExecutor's base case
+  template <class Callback>
+  auto thenMultiWithExecutor(Executor* x, Callback&& fn)
+    -> decltype(this->then(std::forward<Callback>(fn)));
+
  protected:
   typedef detail::Core<T>* corePtr;
 
@@ -391,6 +432,9 @@ class Future {
   friend class Promise<T>;
   template <class> friend class Future;
 
+  template <class T2>
+  friend Future<T2> makeFuture(Try<T2>&&);
+
   // Variant: returns a value
   // e.g. f.then([](Try<T> t){ return t.value(); });
   template <typename F, typename R, bool isTry, typename... Args>
@@ -404,10 +448,11 @@ class Future {
   thenImplementation(F func, detail::argResult<isTry, F, Args...>);
 
   Executor* getExecutor() { return core_->getExecutor(); }
-  void setExecutor(Executor* x) { core_->setExecutor(x); }
+  void setExecutor(Executor* x, int8_t priority = Executor::MID_PRI) {
+    core_->setExecutor(x, priority);
+  }
 };
 
-
 } // folly
 
 #include <folly/futures/Future-inl.h>