/*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2015 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/Optional.h>
#include <folly/MoveWrapper.h>
#include <folly/futures/Deprecated.h>
#include <folly/futures/DrivableExecutor.h>
template <class> struct Core;
template <class...> struct VariadicContext;
+template <class> struct CollectContext;
template<typename F, typename... Args>
using resultOf = decltype(std::declval<F>()(std::declval<Args>()...));
callableWith<F>::value,
detail::argResult<false, F>,
typename std::conditional<
- callableWith<F, Try<T>&&>::value,
- detail::argResult<true, F, Try<T>&&>,
+ callableWith<F, T&&>::value,
+ detail::argResult<false, F, T&&>,
typename std::conditional<
- callableWith<F, Try<T>&>::value,
- detail::argResult<true, F, Try<T>&>,
+ callableWith<F, T&>::value,
+ detail::argResult<false, F, T&>,
typename std::conditional<
- callableWith<F, T&&>::value,
- detail::argResult<false, F, T&&>,
- detail::argResult<false, F, T&>>::type>::type>::type>::type Arg;
+ callableWith<F, Try<T>&&>::value,
+ detail::argResult<true, F, Try<T>&&>,
+ detail::argResult<true, F, Try<T>&>>::type>::type>::type>::type Arg;
typedef isFuture<typename Arg::Result> ReturnsFuture;
typedef Future<typename ReturnsFuture::Inner> Return;
};
/// 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);
+
+ /// 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);
}
template <class T>
// movable
Future(Future&&) noexcept;
- Future& operator=(Future&&);
+ Future& operator=(Future&&) noexcept;
// makeFuture
template <class F = T>
/** 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();
/** A reference to the Try of the value */
Try<T>& getTry();
+ /// If the promise has been fulfilled, return an Optional with the Try<T>.
+ /// Otherwise return an empty Optional.
+ /// Note that this moves the Try<T> out.
+ Optional<Try<T>> poll();
+
/// Block until the future is fulfilled. Returns the value (moved out), or
/// throws the exception. The future must not already have a callback.
T get();
/// 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 one of:
(const) Try<T>&&
/// Variant where func is an member function
///
- /// struct Worker {
- /// R doWork(Try<T>&&); }
+ /// struct Worker { R doWork(Try<T>); }
///
/// Worker *w;
- /// Future<R> f2 = f1.then(w, &Worker::doWork);
- template <typename Caller, typename R, typename... Args>
- Future<typename isFuture<R>::Inner>
- then(Caller *instance, R(Caller::*func)(Args...));
+ /// Future<R> f2 = f1.then(&Worker::doWork, w);
+ ///
+ /// This is just sugar for
+ ///
+ /// 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);
+
+ /// 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... Args>
+ auto then(Executor* x, Args&&... args)
+ -> decltype(this->then(std::forward<Args>(args)...));
/// Convenience method for ignoring the value and creating a Future<void>.
/// Exceptions still propagate.
/// });
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
/// 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
Future<T>& waitVia(DrivableExecutor* e) &;
/// Overload of waitVia() for rvalue Futures
- Future<T> waitVia(DrivableExecutor* e) &&;
+ 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>&);
- private:
+ /// 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);
+
+ protected:
typedef detail::Core<T>* corePtr;
// shared core state object
void throwIfInvalid() const;
friend class Promise<T>;
+ template <class> friend class Future;
// 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...>);
+
+ Executor* getExecutor() { return core_->getExecutor(); }
+ void setExecutor(Executor* x) { core_->setExecutor(x); }
};
/**
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.
+ 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>>>
*/
typename std::decay<Fs>::type::value_type...>::type
whenAll(Fs&&... fs);
+/// Like whenAll, but will short circuit on the first exception. Thus, the
+/// type of the returned Future is std::vector<T> instead of
+/// std::vector<Try<T>>
+template <class InputIterator>
+Future<typename detail::CollectContext<
+ typename std::iterator_traits<InputIterator>::value_type::value_type
+>::result_type>
+collect(InputIterator first, InputIterator last);
+
/** 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.
Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>>
whenN(InputIterator first, InputIterator last, size_t n);
+template <typename F, typename T, typename ItT>
+using MaybeTryArg = typename std::conditional<
+ detail::callableWith<F, T&&, Try<ItT>&&>::value, Try<ItT>, ItT>::type;
+
+template<typename F, typename T, typename Arg>
+using isFutureResult = isFuture<typename std::result_of<F(T&&, Arg&&)>::type>;
+
+/** repeatedly calls func on every result, e.g.
+ reduce(reduce(reduce(T initial, result of first), result of second), ...)
+
+ The type of the final result is a Future of the type of the initial value.
+
+ Func can either return a T, or a Future<T>
+ */
+template <class It, class T, class F,
+ class ItT = typename std::iterator_traits<It>::value_type::value_type,
+ class Arg = MaybeTryArg<F, T, ItT>>
+typename std::enable_if<!isFutureResult<F, T, Arg>::value, Future<T>>::type
+reduce(It first, It last, T initial, F func);
+
+template <class It, class T, class F,
+ class ItT = typename std::iterator_traits<It>::value_type::value_type,
+ class Arg = MaybeTryArg<F, T, ItT>>
+typename std::enable_if<isFutureResult<F, T, Arg>::value, Future<T>>::type
+reduce(It first, It last, T initial, F func);
+
} // folly
#include <folly/futures/Future-inl.h>