/*
- * Copyright 2017 Facebook, Inc.
+ * Copyright 2014-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.
* 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/executors/DrivableExecutor.h>
template <
class T2 = T,
typename = typename std::enable_if<
- !isFuture<typename std::decay<T2>::type>::value>::type>
+ !isFuture<typename std::decay<T2>::type>::value &&
+ !isSemiFuture<typename std::decay<T2>::type>::value>::type>
/* implicit */ FutureBase(T2&& val);
template <class T2 = T>
T&& value() &&;
T const&& value() const&&;
- /// 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) &&;
+ /// 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;
/// 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.
class SemiFuture : private futures::detail::FutureBase<T> {
private:
using Base = futures::detail::FutureBase<T>;
+ using DeferredExecutor = futures::detail::DeferredExecutor;
public:
static SemiFuture<T> makeEmpty(); // equivalent to moved-from
template <
class T2 = T,
typename = typename std::enable_if<
- !isFuture<typename std::decay<T2>::type>::value>::type>
+ !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(Future<T>&&) noexcept;
using Base::cancel;
- using Base::getTry;
using Base::hasException;
using Base::hasValue;
using Base::isActive;
using Base::raise;
using Base::setCallback_;
using Base::value;
- using Base::via;
+ using Base::result;
SemiFuture& operator=(SemiFuture const&) = delete;
SemiFuture& operator=(SemiFuture&&) noexcept;
/// 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(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>&&);
template <
class T2 = T,
typename = typename std::enable_if<
- !isFuture<typename std::decay<T2>::type>::value>::type>
+ !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>
Future& operator=(Future<T2>&&);
using Base::cancel;
- using Base::getTry;
using Base::hasException;
using Base::hasValue;
using Base::isActive;
using Base::raise;
using Base::setCallback_;
using Base::value;
- using Base::via;
+ using Base::result;
static Future<T> makeEmpty(); // equivalent to moved-from
// movable
Future& operator=(Future&&) noexcept;
- /// 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);
-
/// 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>
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.
/// 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() &;
friend class futures::detail::FutureBase;
template <class>
friend class Future;
+ template <class>
+ friend class SemiFuture;
+ using Base::setExecutor;
+ using Base::throwIfInvalid;
using typename Base::corePtr;
explicit Future(corePtr obj) : Base(obj) {}