/*
- * 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/Optional.h>
+#include <folly/Portability.h>
+#include <folly/futures/DrivableExecutor.h>
#include <folly/futures/Promise.h>
-#include <folly/futures/Try.h>
+#include <folly/Try.h>
#include <folly/futures/FutureException.h>
#include <folly/futures/detail/Types.h>
-namespace folly {
-
-template <class> struct Promise;
-
-namespace detail {
-
-template <class> struct Core;
-template <class...> struct VariadicContext;
-
-template <class T>
-struct AliasIfVoid {
- typedef typename std::conditional<
- std::is_same<T, void>::value,
- int,
- T>::type type;
-};
-
-
-template <typename T>
-struct IsFuture : std::integral_constant<bool, false> {
- typedef T Inner;
-};
-
-template <template <typename T> class Future, typename T>
-struct IsFuture<Future<T>> : std::integral_constant<bool, true> {
- typedef T Inner;
-};
-
-template <typename...>
-struct ArgType;
-
-template <typename Arg, typename... Args>
-struct ArgType<Arg, Args...> {
- typedef Arg FirstArg;
-};
-
-template <>
-struct ArgType<> {
- typedef void FirstArg;
-};
-
-template <typename L>
-struct Extract : Extract<decltype(&L::operator())> { };
+// boring predeclarations and details
+#include <folly/futures/Future-pre.h>
-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;
-};
-
-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;
-};
-
-
-} // detail
+// 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>
-struct Timekeeper;
-
-template <typename T> struct isFuture;
-
-/// 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);
-}
+namespace folly {
template <class T>
class Future {
// movable
Future(Future&&) noexcept;
- Future& operator=(Future&&);
+ Future& operator=(Future&&) 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>&&);
+
+ /// 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>
+ /* implicit */ Future(
+ typename std::enable_if<std::is_same<Unit, T2>::value>::type* = nullptr);
~Future();
/** Return the reference to result. Should not be called if !isReady().
Will rethrow the exception if an exception has been
captured.
-
- This function is not thread safe - the returned Future can only
- be executed from the thread that the executor runs it in.
- See below for a thread safe version
*/
typename std::add_lvalue_reference<T>::type
value();
// 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;
+ /// sugar for getTry().hasValue()
+ bool hasValue();
+
+ /// sugar for getTry().hasException()
+ bool hasException();
+
/** A reference to the Try of the value */
Try<T>& getTry();
+ /// 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);
+
+ /// 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();
/// exception).
T get(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);
+
+ /// 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();
+
/** When this Future has completed, execute func which is a function that
- takes a Try<T>&&. A Future for the return type of func is
- returned. e.g.
+ takes one of:
+ (const) Try<T>&&
+ (const) Try<T>&
+ (const) Try<T>
+ (const) T&&
+ (const) T&
+ (const) T
+ (void)
+
+ Func shall return either another Future or a value.
+
+ A Future for the return type of func is returned.
Future<string> f2 = f1.then([](Try<T>&&) { return string("foo"); });
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 <class F>
- typename std::enable_if<
- !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
- Future<typename std::result_of<F(Try<T>&&)>::type> >::type
- then(F&& func);
+ // gcc 4.8 requires that we cast function reference types to function pointer
+ // types. Fore more details see the comment on FunctionReferenceToPointer
+ // in Future-pre.h.
+ // gcc versions 4.9 and above (as well as clang) do not require this hack.
+ // For those, the FF tenplate parameter can be removed and occurences of FF
+ // replaced with F.
+ template <
+ typename F,
+ typename FF = typename detail::FunctionReferenceToPointer<F>::type,
+ typename R = detail::callableResult<T, FF>>
+ typename R::Return then(F&& func) {
+ typedef typename R::Arg Arguments;
+ return thenImplementation<FF, R>(std::forward<FF>(func), Arguments());
+ }
- /// Variant where func takes a T directly, bypassing a try. Any exceptions
- /// will be implicitly passed on to the resultant Future.
- ///
- /// Future<int> f = makeFuture<int>(42).then([](int i) { return i+1; });
- template <class F>
- typename std::enable_if<
- !std::is_same<T, void>::value &&
- !isFuture<typename std::result_of<
- F(typename detail::AliasIfVoid<T>::type&&)>::type>::value,
- Future<typename std::result_of<
- F(typename detail::AliasIfVoid<T>::type&&)>::type> >::type
- then(F&& func);
-
- /// Like the above variant, but for void futures. That is, func takes no
- /// argument.
+ /// Variant where func is an member function
///
- /// Future<int> f = makeFuture().then([] { return 42; });
- template <class F>
- typename std::enable_if<
- std::is_same<T, void>::value &&
- !isFuture<typename std::result_of<F()>::type>::value,
- Future<typename std::result_of<F()>::type> >::type
- then(F&& func);
-
- /// Variant where func returns a Future<T> instead of a T. e.g.
+ /// struct Worker { R doWork(Try<T>); }
///
- /// Future<string> f2 = f1.then(
- /// [](Try<T>&&) { return makeFuture<string>("foo"); });
- template <class F>
- typename std::enable_if<
- isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
- Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
- then(F&& func);
-
- /// Variant where func returns a Future<T2> and takes a T directly, bypassing
- /// a Try. Any exceptions will be implicitly passed on to the resultant
- /// Future. For example,
+ /// Worker *w;
+ /// Future<R> f2 = f1.then(&Worker::doWork, w);
///
- /// Future<int> f = makeFuture<int>(42).then(
- /// [](int i) { return makeFuture<int>(i+1); });
- template <class F>
- typename std::enable_if<
- !std::is_same<T, void>::value &&
- isFuture<typename std::result_of<
- F(typename detail::AliasIfVoid<T>::type&&)>::type>::value,
- Future<typename std::result_of<
- F(typename detail::AliasIfVoid<T>::type&&)>::type::value_type> >::type
- then(F&& func);
-
- /// Like the above variant, but for void futures. That is, func takes no
- /// argument and returns a future.
+ /// This is just sugar for
///
- /// Future<int> f = makeFuture().then(
- /// [] { return makeFuture<int>(42); });
- template <class F>
- typename std::enable_if<
- std::is_same<T, void>::value &&
- isFuture<typename std::result_of<F()>::type>::value,
- Future<typename std::result_of<F()>::type::value_type> >::type
- then(F&& func);
+ /// 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);
- /// Variant where func is an ordinary function (static method, method)
+ /// Execute the callback via the given Executor. The executor doesn't stick.
///
- /// R doWork(Try<T>&&);
+ /// Contrast
///
- /// Future<R> f2 = f1.then(doWork);
+ /// f.via(x).then(b).then(c)
///
- /// or
+ /// with
///
- /// struct Worker {
- /// static R doWork(Try<T>&&); }
+ /// f.then(x, b).then(c)
///
- /// Future<R> f2 = f1.then(&Worker::doWork);
- template <class = T, class R = std::nullptr_t>
- typename std::enable_if<!isFuture<R>::value, Future<R>>::type
- inline then(R(*func)(Try<T>&&)) {
- return then([func](Try<T>&& t) {
- return (*func)(std::move(t));
- });
+ /// 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 = getExecutor();
+ setExecutor(x);
+ return this->then(std::forward<Arg>(arg), std::forward<Args>(args)...)
+ .via(oldX);
}
- /// Variant where func returns a Future<R> instead of a R. e.g.
- ///
- /// struct Worker {
- /// Future<R> doWork(Try<T>&&); }
- ///
- /// Future<R> f2 = f1.then(&Worker::doWork);
- template <class = T, class R = std::nullptr_t>
- typename std::enable_if<isFuture<R>::value, R>::type
- inline then(R(*func)(Try<T>&&)) {
- return then([func](Try<T>&& t) {
- return (*func)(std::move(t));
- });
- }
-
- /// Variant where func is an member function
- ///
- /// struct Worker {
- /// R doWork(Try<T>&&); }
- ///
- /// Worker *w;
- /// Future<R> f2 = f1.then(w, &Worker::doWork);
- template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
- typename std::enable_if<!isFuture<R>::value, Future<R>>::type
- inline then(Caller *instance, R(Caller::*func)(Try<T>&&)) {
- return then([instance, func](Try<T>&& t) {
- return (instance->*func)(std::move(t));
- });
- }
-
- // Same as above, but func takes void instead of Try<void>&&
- template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
- typename std::enable_if<
- std::is_same<T, void>::value && !isFuture<R>::value, Future<R>>::type
- inline then(Caller *instance, R(Caller::*func)()) {
- return then([instance, func]() {
- return (instance->*func)();
- });
- }
-
- // Same as above, but func takes T&& instead of Try<T>&&
- template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
- typename std::enable_if<
- !std::is_same<T, void>::value && !isFuture<R>::value, Future<R>>::type
- inline then(
- Caller *instance,
- R(Caller::*func)(typename detail::AliasIfVoid<T>::type&&)) {
- return then([instance, func](T&& t) {
- return (instance->*func)(std::move(t));
- });
- }
-
- /// Variant where func returns a Future<R> instead of a R. e.g.
- ///
- /// struct Worker {
- /// Future<R> doWork(Try<T>&&); }
- ///
- /// Worker *w;
- /// Future<R> f2 = f1.then(w, &Worker::doWork);
- template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
- typename std::enable_if<isFuture<R>::value, R>::type
- inline then(Caller *instance, R(Caller::*func)(Try<T>&&)) {
- return then([instance, func](Try<T>&& t) {
- return (instance->*func)(std::move(t));
- });
- }
-
- // Same as above, but func takes void instead of Try<void>&&
- template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
- typename std::enable_if<
- std::is_same<T, void>::value && isFuture<R>::value, R>::type
- inline then(Caller *instance, R(Caller::*func)()) {
- return then([instance, func]() {
- return (instance->*func)();
- });
- }
-
- // Same as above, but func takes T&& instead of Try<T>&&
- template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
- typename std::enable_if<
- !std::is_same<T, void>::value && isFuture<R>::value, R>::type
- inline then(
- Caller *instance,
- R(Caller::*func)(typename detail::AliasIfVoid<T>::type&&)) {
- return then([instance, func](T&& t) {
- return (instance->*func)(std::move(t));
- });
- }
-
- /// 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();
+ Future<Unit> 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::callableWith<F, exception_wrapper>::value &&
!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
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
+ 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
+ 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)
+ /// .delayed(long_time)
+ /// .onTimeout(short_time,
+ /// []() -> int{ return -1; });
+ ///
+ /// or perhaps
+ ///
+ /// Future<int> f = makeFuture<int>(42)
+ /// .delayed(long_time)
+ /// .onTimeout(short_time,
+ /// []() { return makeFuture<int>(some_exception); });
+ 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
/// by then), and it is active (active by default).
///
/// Inactive Futures will activate upon destruction.
- Future<T>& activate() & {
+ FOLLY_DEPRECATED("do not use") Future<T>& activate() & {
core_->activate();
return *this;
}
- Future<T>& deactivate() & {
+ FOLLY_DEPRECATED("do not use") Future<T>& deactivate() & {
core_->deactivate();
return *this;
}
- Future<T> activate() && {
+ FOLLY_DEPRECATED("do not use") Future<T> activate() && {
core_->activate();
return std::move(*this);
}
- Future<T> deactivate() && {
+ FOLLY_DEPRECATED("do not use") Future<T> deactivate() && {
core_->deactivate();
return std::move(*this);
}
template <class E>
void raise(E&& exception) {
raise(make_exception_wrapper<typename std::remove_reference<E>::type>(
- std::move(exception)));
+ std::forward<E>(exception)));
}
/// Raise an interrupt. If the promise holder has an interrupt
/// now. The optional Timekeeper is as with futures::sleep().
Future<T> delayed(Duration, Timekeeper* = nullptr);
- /// Block until this Future is complete. Returns a new Future containing the
- /// result.
- Future<T> wait();
+ /// Block until this Future is complete. Returns a reference to this Future.
+ Future<T>& wait() &;
+
+ /// Overload of wait() for rvalue Futures
+ Future<T>&& wait() &&;
/// Block until this Future is complete or until the given Duration passes.
- /// Returns a new Future which either contains the result or is incomplete,
- /// depending on whether the Duration passed.
- Future<T> wait(Duration);
+ /// Returns a reference to this Future
+ Future<T>& wait(Duration) &;
+
+ /// Overload of wait(Duration) for rvalue Futures
+ Future<T>&& wait(Duration) &&;
+
+ /// Call e->drive() repeatedly until the future is fulfilled. Examples
+ /// of DrivableExecutor include EventBase and ManualExecutor. Returns a
+ /// reference to this Future so that you can chain calls if desired.
+ /// value (moved out), or throws the exception.
+ Future<T>& waitVia(DrivableExecutor* e) &;
+
+ /// Overload of waitVia() for rvalue Futures
+ Future<T>&& waitVia(DrivableExecutor* e) &&;
+
+ /// 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>&);
+
+ /// 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);
+
+ /// 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) {
+ // thenMulti with two callbacks is just then(a).thenMulti(b, ...)
+ return then(std::forward<Callback>(fn))
+ .thenMulti(std::forward<Callbacks>(fns)...);
+ }
- private:
+ template <class Callback>
+ 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.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 = getExecutor();
+ setExecutor(x);
+ return then(std::forward<Callback>(fn))
+ .thenMulti(std::forward<Callbacks>(fns)...)
+ .via(oldX);
+ }
+
+ 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));
+ }
+
+ /// Discard a result, but propagate an exception.
+ Future<Unit> unit() {
+ return then([]{ return Unit{}; });
+ }
+
+ protected:
typedef detail::Core<T>* corePtr;
// shared core state object
void throwIfInvalid() const;
friend class Promise<T>;
-};
-
-/**
- Make a completed Future by moving in a value. e.g.
-
- string foo = "foo";
- auto f = makeFuture(std::move(foo));
+ template <class> friend class Future;
- or
+ template <class T2>
+ friend Future<T2> makeFuture(Try<T2>&&);
- auto f = makeFuture<string>("foo");
-*/
-template <class T>
-Future<typename std::decay<T>::type> makeFuture(T&& t);
-
-/** Make a completed void Future. */
-Future<void> makeFuture();
-
-/** 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;
-
-/// Make a failed Future from an exception_wrapper.
-template <class T>
-Future<T> makeFuture(exception_wrapper ew);
-
-/** 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);
+ /// 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 out of a Try */
-template <class T>
-Future<T> makeFuture(Try<T>&& t);
+ /// 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);
-/*
- * 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.
-
- XXX is this still true?
- This function is thread-safe for Futures running on different threads.
-
- 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);
+ /// 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);
+
+ // 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);
+ }
+};
} // folly