/*
- * Copyright 2015 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.
*/
#pragma once
+#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
} // namespace futures
+/**
+ Make a completed SemiFuture by moving in a value. e.g.
+
+ string foo = "foo";
+ auto f = makeSemiFuture(std::move(foo));
+
+ or
+
+ auto f = makeSemiFuture<string>("foo");
+*/
+template <class T>
+SemiFuture<typename std::decay<T>::type> makeSemiFuture(T&& t);
+
+/** Make a completed void SemiFuture. */
+SemiFuture<Unit> makeSemiFuture();
+
+/**
+ Make a SemiFuture by executing a function.
+
+ If the function returns a value of type T, makeSemiFutureWith
+ returns a completed SemiFuture<T>, capturing the value returned
+ by the function.
+
+ If the function returns a SemiFuture<T> already, makeSemiFutureWith
+ returns just that.
+
+ Either way, if the function throws, a failed Future is
+ returned that captures the exception.
+*/
+
+// makeSemiFutureWith(SemiFuture<T>()) -> SemiFuture<T>
+template <class F>
+typename std::enable_if<isSemiFuture<typename std::result_of<F()>::type>::value,
+ typename std::result_of<F()>::type>::type
+makeSemiFutureWith(F&& func);
+
+// makeSemiFutureWith(T()) -> SemiFuture<T>
+// makeSemiFutureWith(void()) -> SemiFuture<Unit>
+template <class F>
+typename std::enable_if<
+ !(isSemiFuture<typename std::result_of<F()>::type>::value),
+ SemiFuture<typename Unit::Lift<typename std::result_of<F()>::type>::type>>::type
+makeSemiFutureWith(F&& 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 = makeSemiFuture<string>(std::current_exception());
+template <class T>
+FOLLY_DEPRECATED("use makeSemiFuture(exception_wrapper)")
+SemiFuture<T> makeSemiFuture(std::exception_ptr const& e);
+
+/// Make a failed SemiFuture from an exception_wrapper.
+template <class T>
+SemiFuture<T> makeSemiFuture(exception_wrapper ew);
+
+/** Make a SemiFuture 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,
+ SemiFuture<T>>::type
+makeSemiFuture(E const& e);
+
+/** Make a Future out of a Try */
+template <class T>
+SemiFuture<T> makeSemiFuture(Try<T>&& t);
+
/**
Make a completed Future by moving in a value. e.g.
/** Make a completed void Future. */
Future<Unit> makeFuture();
-/** Make a completed Future by executing a function. If the function throws
- we capture the exception, otherwise we capture the result. */
+/**
+ Make a Future by executing a function.
+
+ If the function returns a value of type T, makeFutureWith
+ returns a completed Future<T>, capturing the value returned
+ by the function.
+
+ If the function returns a Future<T> already, makeFutureWith
+ returns just that.
+
+ Either way, if the function throws, a failed Future is
+ returned that captures the exception.
+
+ Calling makeFutureWith(func) is equivalent to calling
+ makeFuture().then(func).
+*/
+
+// makeFutureWith(Future<T>()) -> Future<T>
template <class F>
-auto makeFutureWith(
- F&& func,
- typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
- -> Future<typename Unit::Lift<decltype(func())>::type>;
+typename std::enable_if<isFuture<typename std::result_of<F()>::type>::value,
+ typename std::result_of<F()>::type>::type
+makeFutureWith(F&& func);
+// makeFutureWith(T()) -> Future<T>
+// makeFutureWith(void()) -> Future<Unit>
template <class F>
-auto makeFutureWith(F const& func)
- -> Future<typename Unit::Lift<decltype(func())>::type>;
+typename std::enable_if<
+ !(isFuture<typename std::result_of<F()>::type>::value),
+ Future<typename Unit::Lift<typename std::result_of<F()>::type>::type>>::type
+makeFutureWith(F&& 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;
+FOLLY_DEPRECATED("use makeFuture(exception_wrapper)")
+Future<T> makeFuture(std::exception_ptr const& e);
/// Make a failed Future from an exception_wrapper.
template <class T>
/// This is semantically equivalent to via(executor).then(func), but
/// easier to read and slightly more efficient.
template <class Func>
-auto via(Executor*, Func func)
- -> Future<typename isFuture<decltype(func())>::Inner>;
+auto via(Executor*, Func&& func)
+ -> Future<typename isFuture<decltype(std::declval<Func>()())>::Inner>;
/** When all the input Futures complete, the returned Future will complete.
Errors do not cause early termination; this Future will always succeed
/// 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
return collectAny(c.begin(), c.end());
}
+/** Similar to collectAny, collectAnyWithoutException return the first Future to
+ * complete without exceptions. If none of the future complete without
+ * excpetions, the last exception will be returned as a result.
+ */
+template <class InputIterator>
+Future<std::pair<
+ size_t,
+ typename std::iterator_traits<InputIterator>::value_type::value_type>>
+collectAnyWithoutException(InputIterator first, InputIterator last);
+
+/// Sugar for the most common case
+template <class Collection>
+auto collectAnyWithoutException(Collection&& c)
+ -> decltype(collectAnyWithoutException(c.begin(), c.end())) {
+ return collectAnyWithoutException(c.begin(), c.end());
+}
+
/** 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)
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
+} // namespace folly