/*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <type_traits>
#include <vector>
-#include <folly/MoveWrapper.h>
-#include <folly/futures/Deprecated.h>
-#include <folly/futures/DrivableExecutor.h>
-#include <folly/futures/Promise.h>
-#include <folly/futures/Try.h>
+#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>
#include <folly/futures/FutureException.h>
+#include <folly/futures/Promise.h>
#include <folly/futures/detail/Types.h>
+// boring predeclarations and details
+#include <folly/futures/Future-pre.h>
+
+// not-boring helpers, e.g. all in folly::futures, makeFuture variants, etc.
+// Needs to be included after Future-pre.h and before Future-inl.h
+#include <folly/futures/helpers.h>
+
namespace folly {
-template <class> struct Promise;
+template <class T>
+class Future;
-template <typename T>
-struct isFuture : std::false_type {
- typedef T Inner;
-};
+template <class T>
+class SemiFuture;
-template <typename T>
-struct isFuture<Future<T>> : std::true_type {
- typedef T Inner;
-};
+namespace futures {
+namespace detail {
+template <class T>
+class FutureBase {
+ public:
+ typedef T value_type;
-template <typename T>
-struct isTry : std::false_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>::type>
+ /* implicit */ FutureBase(T2&& val);
-template <typename T>
-struct isTry<Try<T>> : std::true_type {};
+ template <class T2 = T>
+ /* implicit */ FutureBase(
+ typename std::enable_if<std::is_same<Unit, T2>::value>::type*);
-namespace detail {
+ template <
+ class... Args,
+ typename std::enable_if<std::is_constructible<T, Args&&...>::value, int>::
+ type = 0>
+ explicit FutureBase(in_place_t, Args&&... args);
-template <class> struct Core;
-template <class...> struct VariadicContext;
+ FutureBase(FutureBase<T> const&) = delete;
+ FutureBase(SemiFuture<T>&&) noexcept;
+ FutureBase(Future<T>&&) noexcept;
-template<typename F, typename... Args>
-using resultOf = decltype(std::declval<F>()(std::declval<Args>()...));
+ // not copyable
+ FutureBase(Future<T> const&) = delete;
+ FutureBase(SemiFuture<T> const&) = delete;
-template <typename...>
-struct ArgType;
+ ~FutureBase();
-template <typename Arg, typename... Args>
-struct ArgType<Arg, Args...> {
- typedef Arg FirstArg;
-};
+ /// Returns a reference to the result, with a reference category and const-
+ /// qualification equivalent to the reference category and const-qualification
+ /// of the receiver.
+ ///
+ /// If moved-from, throws NoState.
+ ///
+ /// If !isReady(), throws FutureNotReady.
+ ///
+ /// If an exception has been captured, throws that exception.
+ T& value() &;
+ T const& value() const&;
+ T&& value() &&;
+ T const&& value() const&&;
-template <>
-struct ArgType<> {
- typedef void FirstArg;
-};
+ /** True when the result (or exception) is ready. */
+ bool isReady() const;
-template <bool isTry, typename F, typename... Args>
-struct argResult {
- typedef resultOf<F, Args...> Result;
-};
+ /// sugar for getTry().hasValue()
+ bool hasValue();
-template<typename F, typename... Args>
-struct callableWith {
- template<typename T,
- typename = detail::resultOf<T, Args...>>
- static constexpr std::true_type
- check(std::nullptr_t) { return std::true_type{}; };
+ /// sugar for getTry().hasException()
+ bool hasException();
- template<typename>
- static constexpr std::false_type
- check(...) { return std::false_type{}; };
+ /** A reference to the Try of the value */
+ Try<T>& getTry();
- typedef decltype(check<F>(nullptr)) type;
- static constexpr bool value = type::value;
-};
+ /// 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();
-template<typename T, typename F>
-struct callableResult {
- typedef typename std::conditional<
- callableWith<F>::value,
- detail::argResult<false, F>,
- typename std::conditional<
- callableWith<F, Try<T>&&>::value,
- detail::argResult<true, F, Try<T>&&>,
- typename std::conditional<
- callableWith<F, Try<T>&>::value,
- detail::argResult<true, F, Try<T>&>,
- typename std::conditional<
- callableWith<F, T&&>::value,
- detail::argResult<false, F, T&&>,
- detail::argResult<false, F, T&>>::type>::type>::type>::type Arg;
- typedef isFuture<typename Arg::Result> ReturnsFuture;
- typedef Future<typename ReturnsFuture::Inner> Return;
-};
+ /// 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
+ /// not worth listing all those and their fancy template signatures as
+ /// friends. But it's not for public consumption.
+ template <class F>
+ void setCallback_(F&& func);
-template<typename F>
-struct callableResult<void, F> {
- typedef typename std::conditional<
- callableWith<F>::value,
- detail::argResult<false, F>,
- typename std::conditional<
- callableWith<F, Try<void>&&>::value,
- detail::argResult<true, F, Try<void>&&>,
- detail::argResult<true, F, Try<void>&>>::type>::type Arg;
- typedef isFuture<typename Arg::Result> ReturnsFuture;
- typedef Future<typename ReturnsFuture::Inner> Return;
-};
+ bool isActive() {
+ return core_->isActive();
+ }
-template <typename L>
-struct Extract : Extract<decltype(&L::operator())> { };
+ template <class E>
+ void raise(E&& exception) {
+ raise(make_exception_wrapper<typename std::remove_reference<E>::type>(
+ std::forward<E>(exception)));
+ }
-template <typename Class, typename R, typename... Args>
-struct Extract<R(Class::*)(Args...) const> {
- typedef isFuture<R> ReturnsFuture;
- typedef Future<typename ReturnsFuture::Inner> Return;
- typedef typename ReturnsFuture::Inner RawReturn;
- typedef typename ArgType<Args...>::FirstArg FirstArg;
-};
+ /// Raise an interrupt. If the promise holder has an interrupt
+ /// handler it will be called and potentially stop asynchronous work from
+ /// being done. This is advisory only - a promise holder may not set an
+ /// interrupt handler, or may do anything including ignore. But, if you know
+ /// your future supports this the most likely result is stopping or
+ /// preventing the asynchronous operation (if in time), and the promise
+ /// holder setting an exception on the future. (That may happen
+ /// asynchronously, of course.)
+ void raise(exception_wrapper interrupt);
-template <typename Class, typename R, typename... Args>
-struct Extract<R(Class::*)(Args...)> {
- typedef isFuture<R> ReturnsFuture;
- typedef Future<typename ReturnsFuture::Inner> Return;
- typedef typename ReturnsFuture::Inner RawReturn;
- typedef typename ArgType<Args...>::FirstArg FirstArg;
-};
+ void cancel() {
+ raise(FutureCancellation());
+ }
-} // detail
+ protected:
+ friend class Promise<T>;
+ template <class>
+ friend class SemiFuture;
+ template <class>
+ friend class Future;
-struct Timekeeper;
+ using corePtr = futures::detail::Core<T>*;
-/// This namespace is for utility functions that would usually be static
-/// members of Future, except they don't make sense there because they don't
-/// depend on the template type (rather, on the type of their arguments in
-/// some cases). This is the least-bad naming scheme we could think of. Some
-/// of the functions herein have really-likely-to-collide names, like "map"
-/// and "sleep".
-namespace futures {
- /// Returns a Future that will complete after the specified duration. The
- /// Duration typedef of a `std::chrono` duration type indicates the
- /// resolution you can expect to be meaningful (milliseconds at the time of
- /// writing). Normally you wouldn't need to specify a Timekeeper, we will
- /// use the global futures timekeeper (we run a thread whose job it is to
- /// keep time for futures timeouts) but we provide the option for power
- /// users.
- ///
- /// The Timekeeper thread will be lazily created the first time it is
- /// needed. If your program never uses any timeouts or other time-based
- /// Futures you will pay no Timekeeper thread overhead.
- Future<void> sleep(Duration, Timekeeper* = nullptr);
+ // shared core state object
+ corePtr core_;
- /// 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<Z>
- /// becomes
- ///
- /// f.then(chain<A,Z>(a, b, c));
- // If anyone figures how to get chain to deduce A and Z, I'll buy you a drink.
- template <class A, class Z, class... Callbacks>
- std::function<Future<Z>(Try<A>)>
- chain(Callbacks... fns);
-}
+ explicit FutureBase(corePtr obj) : core_(obj) {}
-template <class T>
-class Future {
- public:
- typedef T value_type;
+ explicit FutureBase(futures::detail::EmptyConstruct) noexcept;
- // not copyable
- Future(Future const&) = delete;
- Future& operator=(Future const&) = delete;
+ void detach();
+
+ void throwIfInvalid() const;
+
+ template <class FutureType>
+ void assign(FutureType&) noexcept;
+
+ Executor* getExecutor() {
+ return core_->getExecutor();
+ }
+
+ void setExecutor(Executor* x, int8_t priority = Executor::MID_PRI) {
+ core_->setExecutor(x, priority);
+ }
+
+ // Variant: returns a value
+ // e.g. f.then([](Try<T> t){ return t.value(); });
+ template <typename F, typename R, bool isTry, typename... Args>
+ typename std::enable_if<!R::ReturnsFuture::value, typename R::Return>::type
+ thenImplementation(F&& func, futures::detail::argResult<isTry, F, Args...>);
+
+ // Variant: returns a Future
+ // e.g. f.then([](Try<T> t){ return makeFuture<T>(t); });
+ template <typename F, typename R, bool isTry, typename... Args>
+ 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 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
+
+ // 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>::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&&);
+ SemiFuture(SemiFuture<T>&&) noexcept;
+ // safe move-constructabilty from Future
+ /* implicit */ SemiFuture(Future<T>&&) noexcept;
+
+ using Base::cancel;
+ using Base::getTry;
+ using Base::hasException;
+ using Base::hasValue;
+ using Base::isActive;
+ using Base::isReady;
+ using Base::poll;
+ using Base::raise;
+ using Base::setCallback_;
+ using Base::value;
+
+ SemiFuture& operator=(SemiFuture const&) = delete;
+ SemiFuture& operator=(SemiFuture&&) noexcept;
+ SemiFuture& operator=(Future<T>&&) noexcept;
- // makeFuture
- template <class F = T>
- /* implicit */
- Future(const typename std::enable_if<!std::is_void<F>::value, F>::type& val);
+ /// 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() &&;
- template <class F = T>
- /* implicit */
- Future(typename std::enable_if<!std::is_void<F>::value, F>::type&& val);
+ /// 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) &&;
- template <class F = T,
- typename std::enable_if<std::is_void<F>::value, int>::type = 0>
- Future();
+ /// Block until this Future is complete. Returns a reference to this Future.
+ SemiFuture<T>& wait() &;
- ~Future();
+ /// Overload of wait() for rvalue Futures
+ SemiFuture<T>&& wait() &&;
- /** 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;
+ /// 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) &&;
/// Returns an inactive Future which will call back on the other side of
/// executor (when it is activated).
// 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) &&;
+
+ /**
+ * 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_();
- /// 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) &;
+ private:
+ template <class>
+ friend class futures::detail::FutureBase;
+ template <class>
+ friend class SemiFuture;
- /** True when the result (or exception) is ready. */
- bool isReady() const;
+ using typename Base::corePtr;
+ using Base::setExecutor;
+ using Base::throwIfInvalid;
- /** A reference to the Try of the value */
- Try<T>& getTry();
+ template <class T2>
+ friend SemiFuture<T2> makeSemiFuture(Try<T2>&&);
- /// 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();
+ explicit SemiFuture(corePtr obj) : Base(obj) {}
- /// 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);
+ 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>::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 <
+ class T2,
+ typename std::enable_if<
+ !std::is_same<T, typename std::decay<T2>::type>::value &&
+ std::is_constructible<T, T2&&>::value &&
+ std::is_convertible<T2&&, T>::value,
+ int>::type = 0>
+ /* implicit */ Future(Future<T2>&&);
+ template <
+ class T2,
+ typename std::enable_if<
+ !std::is_same<T, typename std::decay<T2>::type>::value &&
+ std::is_constructible<T, T2&&>::value &&
+ !std::is_convertible<T2&&, T>::value,
+ int>::type = 0>
+ explicit Future(Future<T2>&&);
+ template <
+ class T2,
+ typename std::enable_if<
+ !std::is_same<T, typename std::decay<T2>::type>::value &&
+ std::is_constructible<T, T2&&>::value,
+ int>::type = 0>
+ Future& operator=(Future<T2>&&);
+
+ using Base::cancel;
+ using Base::getTry;
+ using Base::hasException;
+ using Base::hasValue;
+ using Base::isActive;
+ using Base::isReady;
+ using Base::poll;
+ using Base::raise;
+ using Base::setCallback_;
+ using Base::value;
+
+ static Future<T> makeEmpty(); // equivalent to moved-from
+
+ // not copyable
+ Future& operator=(Future const&) = delete;
+
+ // 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);
+ /// 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();
+
+ /// 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:
(const) Try<T>&&
value(), which may rethrow if this has captured an exception. If func
throws, the exception will be captured in the Future that is returned.
*/
- /* TODO n3428 and other async frameworks have something like then(scheduler,
- Future), we might want to support a similar API which could be
- implemented a little more efficiently than
- f.via(executor).then(callback) */
- template <typename F, typename R = detail::callableResult<T, F>>
- typename R::Return then(F func) {
- typedef typename R::Arg Arguments;
- return thenImplementation<F, R>(std::move(func), Arguments());
+ template <typename F, typename R = futures::detail::callableResult<T, F>>
+ typename R::Return then(F&& func) {
+ return this->template thenImplementation<F, R>(
+ std::forward<F>(func), typename R::Arg());
}
/// Variant where func is an member function
///
/// 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.
+ ///
+ /// Contrast
+ ///
+ /// f.via(x).then(b).then(c)
+ ///
+ /// with
+ ///
+ /// f.then(x, b).then(c)
+ ///
+ /// 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 Executor, class Arg, class... Args>
+ auto then(Executor* x, Arg&& arg, Args&&... args) {
+ auto oldX = this->getExecutor();
+ this->setExecutor(x);
+ return this->then(std::forward<Arg>(arg), std::forward<Args>(args)...)
+ .via(oldX);
+ }
- /// Convenience method for ignoring the value and creating a Future<void>.
+ /// Convenience method for ignoring the value and creating a Future<Unit>.
/// Exceptions still propagate.
- Future<void> then();
+ /// This function is identical to .unit().
+ Future<Unit> then();
+
+ /// Convenience method for ignoring the value and creating a Future<Unit>.
+ /// Exceptions still propagate.
+ /// This function is identical to parameterless .then().
+ Future<Unit> unit() {
+ return then();
+ }
/// Set an error callback for this Future. The callback should take a single
/// argument of the type that you want to catch, and should return a value of
/// });
template <class F>
typename std::enable_if<
- !detail::Extract<F>::ReturnsFuture::value,
- Future<T>>::type
+ !futures::detail::callableWith<F, exception_wrapper>::value &&
+ !futures::detail::callableWith<F, exception_wrapper&>::value &&
+ !futures::detail::Extract<F>::ReturnsFuture::value,
+ Future<T>>::type
onError(F&& func);
/// Overload of onError where the error callback returns a Future<T>
template <class F>
typename std::enable_if<
- detail::Extract<F>::ReturnsFuture::value,
- Future<T>>::type
+ !futures::detail::callableWith<F, exception_wrapper>::value &&
+ !futures::detail::callableWith<F, exception_wrapper&>::value &&
+ futures::detail::Extract<F>::ReturnsFuture::value,
+ Future<T>>::type
onError(F&& func);
+ /// Overload of onError that takes exception_wrapper and returns Future<T>
+ template <class F>
+ typename std::enable_if<
+ futures::detail::callableWith<F, exception_wrapper>::value &&
+ futures::detail::Extract<F>::ReturnsFuture::value,
+ Future<T>>::type
+ onError(F&& func);
+
+ /// Overload of onError that takes exception_wrapper and returns T
+ template <class F>
+ typename std::enable_if<
+ futures::detail::callableWith<F, exception_wrapper>::value &&
+ !futures::detail::Extract<F>::ReturnsFuture::value,
+ Future<T>>::type
+ onError(F&& func);
+
+ /// func is like std::function<void()> and is executed unconditionally, and
+ /// the value/exception is passed through to the resulting Future.
+ /// func shouldn't throw, but if it does it will be captured and propagated,
+ /// and discard any value/exception that this Future has obtained.
+ template <class F>
+ Future<T> ensure(F&& func);
+
/// Like onError, but for timeouts. example:
///
/// Future<int> f = makeFuture<int>(42)
template <class F>
Future<T> onTimeout(Duration, F&& func, Timekeeper* = nullptr);
- /// 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
- /// not worth listing all those and their fancy template signatures as
- /// friends. But it's not for public consumption.
- template <class F>
- void setCallback_(F&& func);
-
/// A Future's callback is executed when all three of these conditions have
/// become true: it has a value (set by the Promise), it has a callback (set
/// by then), and it is active (active by default).
///
/// Inactive Futures will activate upon destruction.
- Future<T>& activate() & {
- core_->activate();
+ FOLLY_DEPRECATED("do not use") Future<T>& activate() & {
+ this->core_->activate();
return *this;
}
- Future<T>& deactivate() & {
- core_->deactivate();
+ FOLLY_DEPRECATED("do not use") Future<T>& deactivate() & {
+ this->core_->deactivate();
return *this;
}
- Future<T> activate() && {
- core_->activate();
+ FOLLY_DEPRECATED("do not use") Future<T> activate() && {
+ this->core_->activate();
return std::move(*this);
}
- Future<T> deactivate() && {
- core_->deactivate();
+ FOLLY_DEPRECATED("do not use") Future<T> deactivate() && {
+ this->core_->deactivate();
return std::move(*this);
}
- bool isActive() {
- return core_->isActive();
- }
-
- template <class E>
- void raise(E&& exception) {
- raise(make_exception_wrapper<typename std::remove_reference<E>::type>(
- std::move(exception)));
- }
-
- /// Raise an interrupt. If the promise holder has an interrupt
- /// handler it will be called and potentially stop asynchronous work from
- /// being done. This is advisory only - a promise holder may not set an
- /// interrupt handler, or may do anything including ignore. But, if you know
- /// your future supports this the most likely result is stopping or
- /// preventing the asynchronous operation (if in time), and the promise
- /// holder setting an exception on the future. (That may happen
- /// asynchronously, of course.)
- void raise(exception_wrapper interrupt);
-
- void cancel() {
- raise(FutureCancellation());
- }
-
/// Throw TimedOut if this Future does not complete within the given
/// duration from now. The optional Timeekeeper is as with futures::sleep().
Future<T> within(Duration, Timekeeper* = nullptr);
/// 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);
+
/// Block until this Future is complete. Returns a reference to this Future.
Future<T>& wait() &;
/// Overload of waitVia() for rvalue Futures
Future<T>&& waitVia(DrivableExecutor* e) &&;
- private:
- typedef detail::Core<T>* corePtr;
+ /// If the value in this Future is equal to the given Future, when they have
+ /// both completed, the value of the resulting Future<bool> will be true. It
+ /// will be false otherwise (including when one or both Futures have an
+ /// exception)
+ Future<bool> willEqual(Future<T>&);
- // shared core state object
- corePtr core_;
-
- explicit
- Future(corePtr obj) : core_(obj) {}
+ /// predicate behaves like std::function<bool(T const&)>
+ /// If the predicate does not obtain with the value, the result
+ /// is a folly::PredicateDoesNotObtain exception
+ template <class F>
+ Future<T> filter(F&& predicate);
- void detach();
+ /// 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);
- void throwIfInvalid() const;
+ /// 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) {
+ // thenMulti with two callbacks is just then(a).thenMulti(b, ...)
+ return then(std::forward<Callback>(fn))
+ .thenMulti(std::forward<Callbacks>(fns)...);
+ }
- friend class Promise<T>;
+ template <class Callback>
+ auto thenMulti(Callback&& fn) {
+ // thenMulti with one callback is just a then
+ return then(std::forward<Callback>(fn));
+ }
- // Variant: returns a value
- // e.g. f.then([](Try<T> t){ return t.value(); });
- template <typename F, typename R, bool isTry, typename... Args>
- typename std::enable_if<!R::ReturnsFuture::value, typename R::Return>::type
- thenImplementation(F func, detail::argResult<isTry, F, Args...>);
+ /// 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) {
+ // thenMultiExecutor with two callbacks is
+ // via(x).then(a).thenMulti(b, ...).via(oldX)
+ auto oldX = this->getExecutor();
+ this->setExecutor(x);
+ return then(std::forward<Callback>(fn))
+ .thenMulti(std::forward<Callbacks>(fns)...)
+ .via(oldX);
+ }
- // Variant: returns a Future
- // e.g. f.then([](Try<T> t){ return makeFuture<T>(t); });
- template <typename F, typename R, bool isTry, typename... Args>
- typename std::enable_if<R::ReturnsFuture::value, typename R::Return>::type
- thenImplementation(F func, detail::argResult<isTry, F, Args...>);
-};
+ template <class Callback>
+ auto thenMultiWithExecutor(Executor* x, Callback&& fn) {
+ // thenMulti with one callback is just a then with an executor
+ return then(x, std::forward<Callback>(fn));
+ }
-/**
- Make a completed Future by moving in a value. e.g.
+ // Convert this Future to a SemiFuture to safely export from a library
+ // without exposing a continuation interface
+ SemiFuture<T> semi() {
+ return SemiFuture<T>{std::move(*this)};
+ }
- string foo = "foo";
- auto f = makeFuture(std::move(foo));
+ protected:
+ friend class Promise<T>;
+ template <class>
+ friend class futures::detail::FutureBase;
+ template <class>
+ friend class Future;
+ template <class>
+ friend class SemiFuture;
- or
+ using Base::setExecutor;
+ using Base::throwIfInvalid;
+ using typename Base::corePtr;
- auto f = makeFuture<string>("foo");
-*/
-template <class T>
-Future<typename std::decay<T>::type> makeFuture(T&& t);
+ explicit Future(corePtr obj) : Base(obj) {}
-/** Make a completed void Future. */
-Future<void> makeFuture();
+ explicit Future(futures::detail::EmptyConstruct) noexcept
+ : Base(futures::detail::EmptyConstruct{}) {}
-/** Make a completed Future by executing a function. If the function throws
- we capture the exception, otherwise we capture the result. */
-template <class F>
-auto makeFutureTry(
- F&& func,
- typename std::enable_if<
- !std::is_reference<F>::value, bool>::type sdf = false)
- -> Future<decltype(func())>;
-
-template <class F>
-auto makeFutureTry(
- F const& func)
- -> Future<decltype(func())>;
-
-/// Make a failed Future from an exception_ptr.
-/// Because the Future's type cannot be inferred you have to specify it, e.g.
-///
-/// auto f = makeFuture<string>(std::current_exception());
-template <class T>
-Future<T> makeFuture(std::exception_ptr const& e) DEPRECATED;
+ template <class T2>
+ friend Future<T2> makeFuture(Try<T2>&&);
-/// Make a failed Future from an exception_wrapper.
-template <class T>
-Future<T> makeFuture(exception_wrapper ew);
+ /// Repeat the given future (i.e., the computation it contains)
+ /// n times.
+ ///
+ /// thunk behaves like std::function<Future<T2>(void)>
+ template <class F>
+ friend Future<Unit> times(int n, F&& thunk);
-/** Make a Future from an exception type E that can be passed to
- std::make_exception_ptr(). */
-template <class T, class E>
-typename std::enable_if<std::is_base_of<std::exception, E>::value,
- Future<T>>::type
-makeFuture(E const& e);
+ /// Carry out the computation contained in the given future if
+ /// the predicate holds.
+ ///
+ /// thunk behaves like std::function<Future<T2>(void)>
+ template <class F>
+ friend Future<Unit> when(bool p, F&& thunk);
-/** Make a Future out of a Try */
-template <class T>
-Future<T> makeFuture(Try<T>&& t);
+ /// Carry out the computation contained in the given future if
+ /// while the predicate continues to hold.
+ ///
+ /// thunk behaves like std::function<Future<T2>(void)>
+ ///
+ /// predicate behaves like std::function<bool(void)>
+ template <class P, class F>
+ friend Future<Unit> whileDo(P&& predicate, F&& thunk);
+};
-/*
- * Return a new Future that will call back on the given Executor.
- * This is just syntactic sugar for makeFuture().via(executor)
- *
- * @param executor the Executor to call back on
- *
- * @returns a void Future that will call back on the given executor
- */
-template <typename Executor>
-Future<void> via(Executor* executor);
-
-/** When all the input Futures complete, the returned Future will complete.
- Errors do not cause early termination; this Future will always succeed
- after all its Futures have finished (whether successfully or with an
- error).
-
- The Futures are moved in, so your copies are invalid. If you need to
- chain further from these Futures, use the variant with an output iterator.
-
- This function is thread-safe for Futures running on different threads. But
- if you are doing anything non-trivial after, you will probably want to
- follow with `via(executor)` because it will complete in whichever thread the
- last Future completes in.
-
- The return type for Future<T> input is a Future<std::vector<Try<T>>>
- */
-template <class InputIterator>
-Future<std::vector<Try<
- typename std::iterator_traits<InputIterator>::value_type::value_type>>>
-whenAll(InputIterator first, InputIterator last);
-
-/// This version takes a varying number of Futures instead of an iterator.
-/// The return type for (Future<T1>, Future<T2>, ...) input
-/// is a Future<std::tuple<Try<T1>, Try<T2>, ...>>.
-/// The Futures are moved in, so your copies are invalid.
-template <typename... Fs>
-typename detail::VariadicContext<
- typename std::decay<Fs>::type::value_type...>::type
-whenAll(Fs&&... fs);
-
-/** The result is a pair of the index of the first Future to complete and
- the Try. If multiple Futures complete at the same time (or are already
- complete when passed in), the "winner" is chosen non-deterministically.
-
- This function is thread-safe for Futures running on different threads.
- */
-template <class InputIterator>
-Future<std::pair<
- size_t,
- Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
-whenAny(InputIterator first, InputIterator last);
-
-/** when n Futures have completed, the Future completes with a vector of
- the index and Try of those n Futures (the indices refer to the original
- order, but the result vector will be in an arbitrary order)
-
- Not thread safe.
- */
-template <class InputIterator>
-Future<std::vector<std::pair<
- size_t,
- Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>>
-whenN(InputIterator first, InputIterator last, size_t n);
-
-} // folly
+} // namespace folly
#include <folly/futures/Future-inl.h>