/*
- * Copyright 2016 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 <folly/Optional.h>
#include <folly/Portability.h>
-#include <folly/MoveWrapper.h>
-#include <folly/futures/DrivableExecutor.h>
-#include <folly/futures/Promise.h>
-#include <folly/futures/Try.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
namespace folly {
template <class T>
-class Future {
+class Future;
+
+template <class T>
+class SemiFuture;
+
+namespace futures {
+namespace detail {
+template <class T>
+class FutureBase {
public:
typedef T 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 */ FutureBase(T2&& val);
+
+ template <class T2 = T>
+ /* 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 FutureBase(in_place_t, Args&&... args);
+
+ FutureBase(FutureBase<T> const&) = delete;
+ FutureBase(SemiFuture<T>&&) noexcept;
+ FutureBase(Future<T>&&) noexcept;
+
// not copyable
- Future(Future const&) = delete;
- Future& operator=(Future const&) = delete;
+ FutureBase(Future<T> const&) = delete;
+ FutureBase(SemiFuture<T> const&) = delete;
- // movable
- Future(Future&&) noexcept;
- Future& operator=(Future&&) noexcept;
+ ~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.
+ ///
+ /// 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&&;
+
+ /** True when the result (or exception) is ready. */
+ bool isReady() const;
+
+ /// sugar for getTry().hasValue()
+ bool hasValue();
+
+ /// 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();
+
+ /// 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);
+
+ bool isActive() {
+ return core_->isActive();
+ }
+
+ template <class E>
+ void raise(E&& exception) {
+ raise(make_exception_wrapper<typename std::remove_reference<E>::type>(
+ std::forward<E>(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());
+ }
+
+ protected:
+ 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 FutureBase(corePtr obj) : core_(obj) {}
+
+ explicit FutureBase(futures::detail::EmptyConstruct) noexcept;
+
+ 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 */ Future(T2&& val);
+ 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
+ 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;
+
+ /// 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() &;
- template <class T2 = T, typename =
- typename std::enable_if<
- std::is_same<Unit, T2>::value>::type>
- Future();
+ /// Overload of wait() for rvalue Futures
+ SemiFuture<T>&& wait() &&;
- ~Future();
+ /// Block until this Future is complete or until the given Duration passes.
+ /// Returns a reference to this Future
+ SemiFuture<T>& wait(Duration) &;
- /** 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;
+ /// 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).
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) &;
+ /**
+ * 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:
+ template <class>
+ friend class futures::detail::FutureBase;
+ template <class>
+ friend class SemiFuture;
+
+ using typename Base::corePtr;
+ using Base::setExecutor;
+ using Base::throwIfInvalid;
- /** True when the result (or exception) is ready. */
- bool isReady() const;
+ template <class T2>
+ friend SemiFuture<T2> makeSemiFuture(Try<T2>&&);
- /// sugar for getTry().hasValue()
- bool hasValue();
+ explicit SemiFuture(corePtr obj) : Base(obj) {}
- /// sugar for getTry().hasException()
- bool hasException();
+ explicit SemiFuture(futures::detail::EmptyConstruct) noexcept
+ : Base(futures::detail::EmptyConstruct{}) {}
+};
- /** A reference to the Try of the value */
- Try<T>& getTry();
+template <class T>
+class Future : private futures::detail::FutureBase<T> {
+ private:
+ using Base = futures::detail::FutureBase<T>;
- /// 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();
+ public:
+ // Export public interface of FutureBase
+ // FutureBase is inherited privately to avoid subclasses being cast to
+ // a FutureBase pointer
+ using typename Base::value_type;
- /// 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();
+ /// 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
- /// 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);
+ // 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
/// 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:
value(), which may rethrow if this has captured an exception. If func
throws, the exception will be captured in the Future that is returned.
*/
- 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.
///
/// 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)
- -> decltype(this->then(std::forward<Arg>(arg),
- std::forward<Args>(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<Unit>.
/// Exceptions still propagate.
+ /// 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
/// the same type as this Future, or a Future of that type (see overload
/// });
template <class F>
typename std::enable_if<
- !detail::callableWith<F, exception_wrapper>::value &&
- !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::callableWith<F, exception_wrapper>::value &&
- 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<
- detail::callableWith<F, exception_wrapper>::value &&
- detail::Extract<F>::ReturnsFuture::value,
- Future<T>>::type
+ 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<
- detail::callableWith<F, exception_wrapper>::value &&
- !detail::Extract<F>::ReturnsFuture::value,
- Future<T>>::type
+ 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
/// 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);
+ Future<T> ensure(F&& func);
/// Like onError, but for timeouts. example:
///
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.
FOLLY_DEPRECATED("do not use") Future<T>& activate() & {
- core_->activate();
+ this->core_->activate();
return *this;
}
FOLLY_DEPRECATED("do not use") Future<T>& deactivate() & {
- core_->deactivate();
+ this->core_->deactivate();
return *this;
}
FOLLY_DEPRECATED("do not use") Future<T> activate() && {
- core_->activate();
+ this->core_->activate();
return std::move(*this);
}
FOLLY_DEPRECATED("do not use") Future<T> deactivate() && {
- core_->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() &;
/// If the predicate does not obtain with the value, the result
/// is a folly::PredicateDoesNotObtain exception
template <class F>
- Future<T> filter(F predicate);
+ 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
///
/// 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)...));
+ 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)...);
+ }
- // Nothing to see here, just thenMulti's base case
template <class Callback>
- auto thenMulti(Callback&& fn)
- -> decltype(this->then(std::forward<Callback>(fn)));
+ auto thenMulti(Callback&& fn) {
+ // thenMulti with one callback is just a then
+ return then(std::forward<Callback>(fn));
+ }
/// Create a Future chain from a sequence of callbacks. i.e.
///
///
/// 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)...));
+ 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);
+ }
- // 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)));
+ auto thenMultiWithExecutor(Executor* x, Callback&& fn) {
+ // thenMulti with one callback is just a then with an executor
+ return then(x, std::forward<Callback>(fn));
+ }
- /// Discard a result, but propagate an exception.
- Future<Unit> unit() {
- return then([]{ return Unit{}; });
+ // 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)};
}
protected:
- typedef detail::Core<T>* corePtr;
-
- // shared core state object
- corePtr core_;
-
- explicit
- Future(corePtr obj) : core_(obj) {}
+ friend class Promise<T>;
+ template <class>
+ friend class futures::detail::FutureBase;
+ template <class>
+ friend class Future;
+ template <class>
+ friend class SemiFuture;
- void detach();
+ using Base::setExecutor;
+ using Base::throwIfInvalid;
+ using typename Base::corePtr;
- void throwIfInvalid() const;
+ explicit Future(corePtr obj) : Base(obj) {}
- friend class Promise<T>;
- template <class> friend class Future;
+ explicit Future(futures::detail::EmptyConstruct) noexcept
+ : Base(futures::detail::EmptyConstruct{}) {}
template <class T2>
friend Future<T2> makeFuture(Try<T2>&&);
///
/// thunk behaves like std::function<Future<T2>(void)>
template <class F>
- friend Future<Unit> times(const int n, F thunk);
+ friend Future<Unit> times(int n, F&& thunk);
/// 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);
+ friend Future<Unit> when(bool p, F&& thunk);
/// Carry out the computation contained in the given future if
/// while the predicate continues to hold.
///
/// predicate behaves like std::function<bool(void)>
template <class P, class F>
- friend Future<Unit> whileDo(P predicate, F thunk);
-
- // 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...>);
-
- // 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...>);
-
- Executor* getExecutor() { return core_->getExecutor(); }
- void setExecutor(Executor* x, int8_t priority = Executor::MID_PRI) {
- core_->setExecutor(x, priority);
- }
+ friend Future<Unit> whileDo(P&& predicate, F&& thunk);
};
-} // folly
+} // namespace folly
#include <folly/futures/Future-inl.h>