*/
#pragma once
-#include <folly/futures/Future.h>
+#include <atomic>
+#include <tuple>
+#include <utility>
+
#include <folly/Portability.h>
+#include <folly/Try.h>
+#include <folly/futures/Future.h>
+#include <folly/futures/Promise.h>
namespace folly {
+namespace futures {
+namespace detail {
+template <typename... Ts>
+struct CollectAllVariadicContext {
+ CollectAllVariadicContext() {}
+ template <typename T, size_t I>
+ inline void setPartialResult(Try<T>& t) {
+ std::get<I>(results) = std::move(t);
+ }
+ ~CollectAllVariadicContext() {
+ p.setValue(std::move(results));
+ }
+ Promise<std::tuple<Try<Ts>...>> p;
+ std::tuple<Try<Ts>...> results;
+ typedef Future<std::tuple<Try<Ts>...>> type;
+};
+
+template <typename... Ts>
+struct CollectVariadicContext {
+ CollectVariadicContext() {}
+ template <typename T, size_t I>
+ inline void setPartialResult(Try<T>& t) {
+ if (t.hasException()) {
+ if (!threw.exchange(true)) {
+ p.setException(std::move(t.exception()));
+ }
+ } else if (!threw) {
+ std::get<I>(results) = std::move(t);
+ }
+ }
+ ~CollectVariadicContext() noexcept {
+ if (!threw.exchange(true)) {
+ p.setValue(unwrapTryTuple(std::move(results)));
+ }
+ }
+ Promise<std::tuple<Ts...>> p;
+ std::tuple<folly::Try<Ts>...> results;
+ std::atomic<bool> threw{false};
+ typedef Future<std::tuple<Ts...>> type;
+};
+} // namespace detail
+} // namespace futures
+
/// 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
* Set func as the callback for each input Future and return a vector of
* Futures containing the results in the input order.
*/
- template <class It, class F,
- class ItT = typename std::iterator_traits<It>::value_type,
- class Result
- = typename decltype(std::declval<ItT>().then(std::declval<F>()))::value_type>
+ template <
+ class It,
+ class F,
+ class ItT = typename std::iterator_traits<It>::value_type,
+ class Result = typename decltype(
+ std::declval<ItT>().then(std::declval<F>()))::value_type>
std::vector<Future<Result>> map(It first, It last, F func);
// Sugar for the most common case
/// is a Future<std::tuple<Try<T1>, Try<T2>, ...>>.
/// The Futures are moved in, so your copies are invalid.
template <typename... Fs>
-typename detail::CollectAllVariadicContext<
- typename std::decay<Fs>::type::value_type...>::type
+typename futures::detail::CollectAllVariadicContext<
+ typename std::decay<Fs>::type::value_type...>::type
collectAll(Fs&&... fs);
/// Like collectAll, 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>
+Future<typename futures::detail::CollectContext<typename std::iterator_traits<
+ InputIterator>::value_type::value_type>::result_type>
collect(InputIterator first, InputIterator last);
/// Sugar for the most common case
/// type of the returned Future is std::tuple<T1, T2, ...> instead of
/// std::tuple<Try<T1>, Try<T2>, ...>
template <typename... Fs>
-typename detail::CollectVariadicContext<
- typename std::decay<Fs>::type::value_type...>::type
+typename futures::detail::CollectVariadicContext<
+ typename std::decay<Fs>::type::value_type...>::type
collect(Fs&&... fs);
/** The result is a pair of the index of the first Future to complete and
func must return a Future for each value in input
*/
-template <class Collection, class F,
- class ItT = typename std::iterator_traits<
- typename Collection::iterator>::value_type,
- class Result = typename detail::resultOf<F, ItT&&>::value_type>
+template <
+ class Collection,
+ class F,
+ class ItT = typename std::iterator_traits<
+ typename Collection::iterator>::value_type,
+ class Result = typename futures::detail::resultOf<F, ItT&&>::value_type>
+std::vector<Future<Result>> window(Collection input, F func, size_t n);
+
+template <
+ class Collection,
+ class F,
+ class ItT = typename std::iterator_traits<
+ typename Collection::iterator>::value_type,
+ class Result = typename futures::detail::resultOf<F, ItT&&>::value_type>
std::vector<Future<Result>>
-window(Collection input, F func, size_t n);
+window(Executor* executor, Collection input, F func, 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;
+ futures::detail::callableWith<F, T&&, Try<ItT>&&>::value,
+ Try<ItT>,
+ ItT>::type;
-template<typename F, typename T, typename Arg>
+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.
/** like reduce, but calls func on finished futures as they complete
does NOT keep the order of the input
*/
-template <class It, class T, class F,
- class ItT = typename std::iterator_traits<It>::value_type::value_type,
- class Arg = MaybeTryArg<F, T, ItT>>
+template <
+ class It,
+ class T,
+ class F,
+ class ItT = typename std::iterator_traits<It>::value_type::value_type,
+ class Arg = MaybeTryArg<F, T, ItT>>
Future<T> unorderedReduce(It first, It last, T initial, F func);
/// Sugar for the most common case
std::forward<T>(initial),
std::forward<F>(func));
}
-
-namespace futures {
-
-/**
- * retrying
- *
- * Given a policy and a future-factory, creates futures according to the
- * policy.
- *
- * The policy must be moveable - retrying will move it a lot - and callable of
- * either of the two forms:
- * - Future<bool>(size_t, exception_wrapper)
- * - bool(size_t, exception_wrapper)
- * Internally, the latter is transformed into the former in the obvious way.
- * The first parameter is the attempt number of the next prospective attempt;
- * the second parameter is the most recent exception. The policy returns a
- * Future<bool> which, when completed with true, indicates that a retry is
- * desired.
- *
- * We provide a few generic policies:
- * - Basic
- * - CappedJitteredexponentialBackoff
- *
- * Custom policies may use the most recent try number and exception to decide
- * whether to retry and optionally to do something interesting like delay
- * before the retry. Users may pass inline lambda expressions as policies, or
- * may define their own data types meeting the above requirements. Users are
- * responsible for managing the lifetimes of anything pointed to or referred to
- * from inside the policy.
- *
- * For example, one custom policy may try up to k times, but only if the most
- * recent exception is one of a few types or has one of a few error codes
- * indicating that the failure was transitory.
- *
- * Cancellation is not supported.
- *
- * If both FF and Policy inline executes, then it is possible to hit a stack
- * overflow due to the recursive nature of the retry implementation
- */
-template <class Policy, class FF>
-typename std::result_of<FF(size_t)>::type
-retrying(Policy&& p, FF&& ff);
-
-/**
- * generic retrying policies
- */
-
-inline
-std::function<bool(size_t, const exception_wrapper&)>
-retryingPolicyBasic(
- size_t max_tries);
-
-template <class Policy, class URNG>
-std::function<Future<bool>(size_t, const exception_wrapper&)>
-retryingPolicyCappedJitteredExponentialBackoff(
- size_t max_tries,
- Duration backoff_min,
- Duration backoff_max,
- double jitter_param,
- URNG&& rng,
- Policy&& p);
-
-inline
-std::function<Future<bool>(size_t, const exception_wrapper&)>
-retryingPolicyCappedJitteredExponentialBackoff(
- size_t max_tries,
- Duration backoff_min,
- Duration backoff_max,
- double jitter_param);
-
-}
-
-} // namespace
+} // namespace folly