Make consistent set of get and getTry methods on SemiFuture.
[folly.git] / folly / futures / Future.h
index 5159062db21454b7e60889bbb31b98f3a69e6794..5b2dc82f7b44b6c8f9a4a910f1f17fdb0c6c1204 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Facebook, Inc.
+ * Copyright 2017-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #pragma once
 
 #include <algorithm>
 
 #include <folly/Optional.h>
 #include <folly/Portability.h>
+#include <folly/ScopeGuard.h>
 #include <folly/Try.h>
 #include <folly/Utility.h>
-#include <folly/futures/DrivableExecutor.h>
+#include <folly/executors/DrivableExecutor.h>
 #include <folly/futures/FutureException.h>
 #include <folly/futures/Promise.h>
 #include <folly/futures/detail/Types.h>
@@ -45,82 +45,63 @@ template <class T>
 class Future;
 
 template <class T>
-class SemiFuture {
+class SemiFuture;
+
+namespace futures {
+namespace detail {
+template <class T>
+class FutureBase {
  public:
   typedef T value_type;
 
-  static SemiFuture<T> makeEmpty(); // equivalent to moved-from
-
-  // not copyable
-  SemiFuture(SemiFuture const&) = delete;
-  SemiFuture& operator=(SemiFuture const&) = delete;
-
-  // movable
-  SemiFuture(SemiFuture&&) noexcept;
-  SemiFuture& operator=(SemiFuture&&) noexcept;
-
-  // safe move-constructabilty from Future
-  /* implicit */ SemiFuture(Future<T>&&) noexcept;
-  SemiFuture& operator=(Future<T>&&) noexcept;
-
   /// Construct a Future from a value (perfect forwarding)
   template <
       class T2 = T,
       typename = typename std::enable_if<
-          !isFuture<typename std::decay<T2>::type>::value>::type>
-  /* implicit */ SemiFuture(T2&& val);
+          !isFuture<typename std::decay<T2>::type>::value &&
+          !isSemiFuture<typename std::decay<T2>::type>::value>::type>
+  /* implicit */ FutureBase(T2&& val);
 
   template <class T2 = T>
-  /* implicit */ SemiFuture(
-      typename std::enable_if<std::is_same<Unit, T2>::value>::type* = nullptr);
+  /* implicit */ FutureBase(
+      typename std::enable_if<std::is_same<Unit, T2>::value>::type*);
 
   template <
       class... Args,
       typename std::enable_if<std::is_constructible<T, Args&&...>::value, int>::
           type = 0>
-  explicit SemiFuture(in_place_t, Args&&... args);
+  explicit FutureBase(in_place_t, Args&&... args);
 
-  ~SemiFuture();
+  FutureBase(FutureBase<T> const&) = delete;
+  FutureBase(SemiFuture<T>&&) noexcept;
+  FutureBase(Future<T>&&) noexcept;
 
-  /** Return the reference to result. Should not be called if !isReady().
-    Will rethrow the exception if an exception has been
-    captured.
-    */
-  typename std::add_lvalue_reference<T>::type
-  value();
-  typename std::add_lvalue_reference<const T>::type
-  value() const;
+  // not copyable
+  FutureBase(Future<T> const&) = delete;
+  FutureBase(SemiFuture<T> const&) = delete;
 
-  /// Returns an inactive Future which will call back on the other side of
-  /// executor (when it is activated).
-  ///
-  /// NB remember that Futures activate when they destruct. This is good,
-  /// it means that this will work:
-  ///
-  ///   f.via(e).then(a).then(b);
+  ~FutureBase();
+
+  /// Returns a reference to the result, with a reference category and const-
+  /// qualification equivalent to the reference category and const-qualification
+  /// of the receiver.
   ///
-  /// a and b will execute in the same context (the far side of e), because
-  /// the Future (temporary variable) created by via(e) does not call back
-  /// until it destructs, which is after then(a) and then(b) have been wired
-  /// up.
+  /// If moved-from, throws NoState.
   ///
-  /// But this is still racy:
+  /// If !isReady(), throws FutureNotReady.
   ///
-  ///   f = f.via(e).then(a);
-  ///   f.then(b);
-  // 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/
-  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.
-  inline Future<T> via(
-      Executor* executor,
-      int8_t priority = Executor::MID_PRI) &;
+  /// If an exception has been captured, throws that exception.
+  T& value() &;
+  T const& value() const&;
+  T&& value() &&;
+  T const&& value() const&&;
+
+  /// Returns a reference to the try of the result. Throws as for value if
+  /// future is not valid.
+  Try<T>& result() &;
+  Try<T> const& result() const&;
+  Try<T>&& result() &&;
+  Try<T> const&& result() const&&;
 
   /** True when the result (or exception) is ready. */
   bool isReady() const;
@@ -131,36 +112,11 @@ class SemiFuture {
   /// sugar for getTry().hasException()
   bool hasException();
 
-  /** A reference to the Try of the value */
-  Try<T>& getTry();
-
   /// If the promise has been fulfilled, return an Optional with the Try<T>.
   /// Otherwise return an empty Optional.
   /// Note that this moves the Try<T> out.
   Optional<Try<T>> poll();
 
-  /// Block until the future is fulfilled. Returns the value (moved out), or
-  /// throws the exception. The future must not already have a callback.
-  T get();
-
-  /// Block until the future is fulfilled, or until timed out. Returns the
-  /// value (moved out), or throws the exception (which might be a TimedOut
-  /// exception).
-  T get(Duration dur);
-
-  /// Block until this Future is complete. Returns a reference to this Future.
-  SemiFuture<T>& wait() &;
-
-  /// Overload of wait() for rvalue Futures
-  SemiFuture<T>&& wait() &&;
-
-  /// Block until this Future is complete or until the given Duration passes.
-  /// Returns a reference to this Future
-  SemiFuture<T>& wait(Duration) &;
-
-  /// Overload of wait(Duration) for rvalue Futures
-  SemiFuture<T>&& wait(Duration) &&;
-
   /// This is not the method you're looking for.
   ///
   /// This needs to be public because it's used by make* and when*, and it's
@@ -194,25 +150,27 @@ class SemiFuture {
   }
 
  protected:
-  typedef futures::detail::Core<T>* corePtr;
+  friend class Promise<T>;
+  template <class>
+  friend class SemiFuture;
+  template <class>
+  friend class Future;
+
+  using corePtr = futures::detail::Core<T>*;
 
   // shared core state object
   corePtr core_;
 
-  explicit SemiFuture(corePtr obj) : core_(obj) {}
+  explicit FutureBase(corePtr obj) : core_(obj) {}
 
-  explicit SemiFuture(futures::detail::EmptyConstruct) noexcept;
+  explicit FutureBase(futures::detail::EmptyConstruct) noexcept;
 
   void detach();
 
   void throwIfInvalid() const;
 
-  friend class Promise<T>;
-  template <class>
-  friend class SemiFuture;
-
-  template <class T2>
-  friend SemiFuture<T2> makeSemiFuture(Try<T2>&&);
+  template <class FutureType>
+  void assign(FutureType&) noexcept;
 
   Executor* getExecutor() {
     return core_->getExecutor();
@@ -234,21 +192,209 @@ class SemiFuture {
   typename std::enable_if<R::ReturnsFuture::value, typename R::Return>::type
   thenImplementation(F&& func, futures::detail::argResult<isTry, F, Args...>);
 };
+} // namespace detail
+} // namespace futures
 
 template <class T>
-class Future : public SemiFuture<T> {
+class SemiFuture : private futures::detail::FutureBase<T> {
+ private:
+  using Base = futures::detail::FutureBase<T>;
+  using DeferredExecutor = futures::detail::DeferredExecutor;
+
  public:
-  typedef T value_type;
+  static SemiFuture<T> makeEmpty(); // equivalent to moved-from
 
-  static Future<T> makeEmpty(); // equivalent to moved-from
+  // Export public interface of FutureBase
+  // FutureBase is inherited privately to avoid subclasses being cast to
+  // a FutureBase pointer
+  using typename Base::value_type;
 
-  // not copyable
-  Future(Future const&) = delete;
-  Future& operator=(Future const&) = delete;
+  /// Construct a Future from a value (perfect forwarding)
+  template <
+      class T2 = T,
+      typename = typename std::enable_if<
+          !isFuture<typename std::decay<T2>::type>::value &&
+          !isSemiFuture<typename std::decay<T2>::type>::value>::type>
+  /* implicit */ SemiFuture(T2&& val) : Base(std::forward<T2>(val)) {}
 
+  template <class T2 = T>
+  /* implicit */ SemiFuture(
+      typename std::enable_if<std::is_same<Unit, T2>::value>::type* p = nullptr)
+      : Base(p) {}
+
+  template <
+      class... Args,
+      typename std::enable_if<std::is_constructible<T, Args&&...>::value, int>::
+          type = 0>
+  explicit SemiFuture(in_place_t, Args&&... args)
+      : Base(in_place, std::forward<Args>(args)...) {}
+
+  SemiFuture(SemiFuture<T> const&) = delete;
   // movable
-  Future(Future&&) noexcept;
-  Future& operator=(Future&&) noexcept;
+  SemiFuture(SemiFuture<T>&&) noexcept;
+  // safe move-constructabilty from Future
+  /* implicit */ SemiFuture(Future<T>&&) noexcept;
+
+  using Base::cancel;
+  using Base::hasException;
+  using Base::hasValue;
+  using Base::isActive;
+  using Base::isReady;
+  using Base::poll;
+  using Base::raise;
+  using Base::setCallback_;
+  using Base::value;
+  using Base::result;
+
+  SemiFuture& operator=(SemiFuture const&) = delete;
+  SemiFuture& operator=(SemiFuture&&) noexcept;
+  SemiFuture& operator=(Future<T>&&) noexcept;
+
+  /// Block until the future is fulfilled. Returns the value (moved out), or
+  /// throws the exception. The future must not already have a callback.
+  T get() &&;
+
+  /// Block until the future is fulfilled, or until timed out. Returns the
+  /// value (moved out), or throws the exception (which might be a TimedOut
+  /// exception).
+  T get(Duration dur) &&;
+
+  /// Block until the future is fulfilled, or until timed out. Returns the
+  /// Try of the value (moved out).
+  Try<T> getTry() &&;
+
+  /// Block until the future is fulfilled, or until timed out. Returns the
+  /// Try of the value (moved out) or may throw a TimedOut exception.
+  Try<T> getTry(Duration dur) &&;
+
+  /// Call e->drive() repeatedly until the future is fulfilled. Examples
+  /// of DrivableExecutor include EventBase and ManualExecutor. Returns the
+  /// value (moved out), or throws the exception.
+  T getVia(DrivableExecutor* e) &&;
+
+  /// Call e->drive() repeatedly until the future is fulfilled. Examples
+  /// of DrivableExecutor include EventBase and ManualExecutor. Returns the
+  /// Try of the value (moved out).
+  Try<T> getTryVia(DrivableExecutor* e) &&;
+
+  /// Block until this Future is complete. Returns a reference to this Future.
+  SemiFuture<T>& wait() &;
+
+  /// Overload of wait() for rvalue Futures
+  SemiFuture<T>&& wait() &&;
+
+  /// Block until this Future is complete or until the given Duration passes.
+  /// Returns a reference to this Future
+  SemiFuture<T>& wait(Duration) &;
+
+  /// Overload of wait(Duration) for rvalue Futures
+  SemiFuture<T>&& wait(Duration) &&;
+
+  /// Call e->drive() repeatedly until the future is fulfilled. Examples
+  /// of DrivableExecutor include EventBase and ManualExecutor. Returns a
+  /// reference to this SemiFuture so that you can chain calls if desired.
+  /// value (moved out), or throws the exception.
+  SemiFuture<T>& waitVia(DrivableExecutor* e) &;
+
+  /// Overload of waitVia() for rvalue Futures
+  SemiFuture<T>&& waitVia(DrivableExecutor* e) &&;
+
+  /// Returns an inactive Future which will call back on the other side of
+  /// executor (when it is activated).
+  ///
+  /// NB remember that Futures activate when they destruct. This is good,
+  /// it means that this will work:
+  ///
+  ///   f.via(e).then(a).then(b);
+  ///
+  /// a and b will execute in the same context (the far side of e), because
+  /// the Future (temporary variable) created by via(e) does not call back
+  /// until it destructs, which is after then(a) and then(b) have been wired
+  /// up.
+  ///
+  /// But this is still racy:
+  ///
+  ///   f = f.via(e).then(a);
+  ///   f.then(b);
+  // 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/
+  inline Future<T> via(
+      Executor* executor,
+      int8_t priority = Executor::MID_PRI) &&;
+
+  /**
+   * Defer work to run on the consumer of the future.
+   * This work will be run eithe ron an executor that the caller sets on the
+   * SemiFuture, or inline with the call to .get().
+   * NB: This is a custom method because boost-blocking executors is a
+   * special-case for work deferral in folly. With more general boost-blocking
+   * support all executors would boost block and we would simply use some form
+   * of driveable executor here.
+   */
+  template <typename F>
+  SemiFuture<typename futures::detail::callableResult<T, F>::Return::value_type>
+  defer(F&& func) &&;
+
+  // Public as for setCallback_
+  // Ensure that a boostable executor performs work to chain deferred work
+  // cleanly
+  void boost_();
+
+ private:
+  friend class Promise<T>;
+  template <class>
+  friend class futures::detail::FutureBase;
+  template <class>
+  friend class SemiFuture;
+
+  using typename Base::corePtr;
+  using Base::setExecutor;
+  using Base::throwIfInvalid;
+
+  template <class T2>
+  friend SemiFuture<T2> makeSemiFuture(Try<T2>&&);
+
+  explicit SemiFuture(corePtr obj) : Base(obj) {}
+
+  explicit SemiFuture(futures::detail::EmptyConstruct) noexcept
+      : Base(futures::detail::EmptyConstruct{}) {}
+};
+
+template <class T>
+class Future : private futures::detail::FutureBase<T> {
+ private:
+  using Base = futures::detail::FutureBase<T>;
+
+ public:
+  // Export public interface of FutureBase
+  // FutureBase is inherited privately to avoid subclasses being cast to
+  // a FutureBase pointer
+  using typename Base::value_type;
+
+  /// Construct a Future from a value (perfect forwarding)
+  template <
+      class T2 = T,
+      typename = typename std::enable_if<
+          !isFuture<typename std::decay<T2>::type>::value &&
+          !isSemiFuture<typename std::decay<T2>::type>::value>::type>
+  /* implicit */ Future(T2&& val) : Base(std::forward<T2>(val)) {}
+
+  template <class T2 = T>
+  /* implicit */ Future(
+      typename std::enable_if<std::is_same<Unit, T2>::value>::type* p = nullptr)
+      : Base(p) {}
+
+  template <
+      class... Args,
+      typename std::enable_if<std::is_constructible<T, Args&&...>::value, int>::
+          type = 0>
+  explicit Future(in_place_t, Args&&... args)
+      : Base(in_place, std::forward<Args>(args)...) {}
+
+  Future(Future<T> const&) = delete;
+  // movable
+  Future(Future<T>&&) noexcept;
 
   // converting move
   template <
@@ -275,42 +421,72 @@ class Future : public SemiFuture<T> {
           int>::type = 0>
   Future& operator=(Future<T2>&&);
 
-  /// Construct a Future from a value (perfect forwarding)
-  template <
-      class T2 = T,
-      typename = typename std::enable_if<
-          !isFuture<typename std::decay<T2>::type>::value &&
-          !isSemiFuture<typename std::decay<T2>::type>::value>::type>
-  /* implicit */ Future(T2&& val);
+  using Base::cancel;
+  using Base::hasException;
+  using Base::hasValue;
+  using Base::isActive;
+  using Base::isReady;
+  using Base::poll;
+  using Base::raise;
+  using Base::setCallback_;
+  using Base::value;
+  using Base::result;
 
-  template <class T2 = T>
-  /* 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);
+  static Future<T> makeEmpty(); // equivalent to moved-from
 
-  ~Future();
+  // not copyable
+  Future& operator=(Future const&) = delete;
 
-  /// Call e->drive() repeatedly until the future is fulfilled. Examples
-  /// of DrivableExecutor include EventBase and ManualExecutor. Returns a
-  /// reference to the Try of the value.
-  Try<T>& getTryVia(DrivableExecutor* e);
+  // movable
+  Future& operator=(Future&&) noexcept;
 
   /// Call e->drive() repeatedly until the future is fulfilled. Examples
   /// of DrivableExecutor include EventBase and ManualExecutor. Returns the
   /// value (moved out), or throws the exception.
   T getVia(DrivableExecutor* e);
 
+  /// Call e->drive() repeatedly until the future is fulfilled. Examples
+  /// of DrivableExecutor include EventBase and ManualExecutor. Returns a
+  /// reference to the Try of the value.
+  Try<T>& getTryVia(DrivableExecutor* e);
+
   /// Unwraps the case of a Future<Future<T>> instance, and returns a simple
   /// Future<T> instance.
   template <class F = T>
-  typename std::enable_if<isFuture<F>::value,
-                          Future<typename isFuture<T>::Inner>>::type
-  unwrap();
+  typename std::
+      enable_if<isFuture<F>::value, Future<typename isFuture<T>::Inner>>::type
+      unwrap();
+
+  /// Returns an inactive Future which will call back on the other side of
+  /// executor (when it is activated).
+  ///
+  /// NB remember that Futures activate when they destruct. This is good,
+  /// it means that this will work:
+  ///
+  ///   f.via(e).then(a).then(b);
+  ///
+  /// a and b will execute in the same context (the far side of e), because
+  /// the Future (temporary variable) created by via(e) does not call back
+  /// until it destructs, which is after then(a) and then(b) have been wired
+  /// up.
+  ///
+  /// But this is still racy:
+  ///
+  ///   f = f.via(e).then(a);
+  ///   f.then(b);
+  // 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/
+  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.
+  inline Future<T> via(
+      Executor* executor,
+      int8_t priority = Executor::MID_PRI) &;
 
   /** When this Future has completed, execute func which is a function that
     takes one of:
@@ -349,8 +525,9 @@ class Future : public SemiFuture<T> {
   ///
   ///   f1.then(std::bind(&Worker::doWork, w));
   template <typename R, typename Caller, typename... Args>
-  Future<typename isFuture<R>::Inner>
-  then(R(Caller::*func)(Args...), Caller *instance);
+  Future<typename isFuture<R>::Inner> then(
+      R (Caller::*func)(Args...),
+      Caller* instance);
 
   /// Execute the callback via the given Executor. The executor doesn't stick.
   ///
@@ -490,6 +667,18 @@ class Future : public SemiFuture<T> {
   /// now. The optional Timekeeper is as with futures::sleep().
   Future<T> delayed(Duration, Timekeeper* = nullptr);
 
+  /// Block until the future is fulfilled. Returns the value (moved out), or
+  /// throws the exception. The future must not already have a callback.
+  T get();
+
+  /// Block until the future is fulfilled, or until timed out. Returns the
+  /// value (moved out), or throws the exception (which might be a TimedOut
+  /// exception).
+  T get(Duration dur);
+
+  /** A reference to the Try of the value */
+  Try<T>& getTry();
+
   /// Block until this Future is complete. Returns a reference to this Future.
   Future<T>& wait() &;
 
@@ -582,15 +771,22 @@ class Future : public SemiFuture<T> {
   }
 
  protected:
-  typedef futures::detail::Core<T>* corePtr;
+  friend class Promise<T>;
+  template <class>
+  friend class futures::detail::FutureBase;
+  template <class>
+  friend class Future;
+  template <class>
+  friend class SemiFuture;
 
-  explicit Future(corePtr obj) : SemiFuture<T>(obj) {}
+  using Base::setExecutor;
+  using Base::throwIfInvalid;
+  using typename Base::corePtr;
 
-  explicit Future(futures::detail::EmptyConstruct) noexcept;
+  explicit Future(corePtr obj) : Base(obj) {}
 
-  friend class Promise<T>;
-  template <class> friend class Future;
-  friend class SemiFuture<T>;
+  explicit Future(futures::detail::EmptyConstruct) noexcept
+      : Base(futures::detail::EmptyConstruct{}) {}
 
   template <class T2>
   friend Future<T2> makeFuture(Try<T2>&&);