X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Ffutures%2Fhelpers.h;h=eb5412b2cb2935af9f0478153661746b1b743770;hb=7acba7e1a0a75d22087647b3e9e830c9b0e8d41e;hp=3b0ef2995767ba05c325e3f2564a07d1d54a5b15;hpb=6646f7f214504389cdd76147d415c24d0ee45b0f;p=folly.git diff --git a/folly/futures/helpers.h b/folly/futures/helpers.h index 3b0ef299..eb5412b2 100644 --- a/folly/futures/helpers.h +++ b/folly/futures/helpers.h @@ -1,5 +1,5 @@ /* - * 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. @@ -15,10 +15,60 @@ */ #pragma once +#include +#include +#include + +#include +#include #include +#include namespace folly { +namespace futures { +namespace detail { +template +struct CollectAllVariadicContext { + CollectAllVariadicContext() {} + template + inline void setPartialResult(Try& t) { + std::get(results) = std::move(t); + } + ~CollectAllVariadicContext() { + p.setValue(std::move(results)); + } + Promise...>> p; + std::tuple...> results; + typedef Future...>> type; +}; + +template +struct CollectVariadicContext { + CollectVariadicContext() {} + template + inline void setPartialResult(Try& t) { + if (t.hasException()) { + if (!threw.exchange(true)) { + p.setException(std::move(t.exception())); + } + } else if (!threw) { + std::get(results) = std::move(t); + } + } + ~CollectVariadicContext() noexcept { + if (!threw.exchange(true)) { + p.setValue(unwrapTryTuple(std::move(results))); + } + } + Promise> p; + std::tuple...> results; + std::atomic threw{false}; + typedef Future> 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 @@ -43,10 +93,12 @@ namespace futures { * Set func as the callback for each input Future and return a vector of * Futures containing the results in the input order. */ - template ::value_type, - class Result - = typename decltype(std::declval().then(std::declval()))::value_type> + template < + class It, + class F, + class ItT = typename std::iterator_traits::value_type, + class Result = typename decltype( + std::declval().then(std::declval()))::value_type> std::vector> map(It first, It last, F func); // Sugar for the most common case @@ -58,6 +110,73 @@ namespace futures { } // 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("foo"); +*/ +template +SemiFuture::type> makeSemiFuture(T&& t); + +/** Make a completed void SemiFuture. */ +SemiFuture makeSemiFuture(); + +/** + Make a SemiFuture by executing a function. + + If the function returns a value of type T, makeSemiFutureWith + returns a completed SemiFuture, capturing the value returned + by the function. + + If the function returns a SemiFuture already, makeSemiFutureWith + returns just that. + + Either way, if the function throws, a failed Future is + returned that captures the exception. +*/ + +// makeSemiFutureWith(SemiFuture()) -> SemiFuture +template +typename std::enable_if::type>::value, + typename std::result_of::type>::type +makeSemiFutureWith(F&& func); + +// makeSemiFutureWith(T()) -> SemiFuture +// makeSemiFutureWith(void()) -> SemiFuture +template +typename std::enable_if< + !(isSemiFuture::type>::value), + SemiFuture::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(std::current_exception()); +template +FOLLY_DEPRECATED("use makeSemiFuture(exception_wrapper)") +SemiFuture makeSemiFuture(std::exception_ptr const& e); + +/// Make a failed SemiFuture from an exception_wrapper. +template +SemiFuture makeSemiFuture(exception_wrapper ew); + +/** Make a SemiFuture from an exception type E that can be passed to + std::make_exception_ptr(). */ +template +typename std::enable_if::value, + SemiFuture>::type +makeSemiFuture(E const& e); + +/** Make a Future out of a Try */ +template +SemiFuture makeSemiFuture(Try&& t); + /** Make a completed Future by moving in a value. e.g. @@ -67,38 +186,92 @@ namespace futures { or auto f = makeFuture("foo"); + + NOTE: This function is deprecated. Please use makeSemiFuture and pass the + appropriate executor to .via on the returned SemiFuture to get a + valid Future where necessary. */ template Future::type> makeFuture(T&& t); -/** Make a completed void Future. */ +/** + Make a completed void Future. + + NOTE: This function is deprecated. Please use makeSemiFuture and pass the + appropriate executor to .via on the returned SemiFuture to get a + valid Future where necessary. + */ Future 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, capturing the value returned + by the function. + + If the function returns a Future 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). + + NOTE: This function is deprecated. Please use makeSemiFutureWith and pass the + appropriate executor to .via on the returned SemiFuture to get a + valid Future where necessary. +*/ + +// makeFutureWith(Future()) -> Future template -auto makeFutureWith(F&& func) - -> Future::type>; +typename std::enable_if::type>::value, + typename std::result_of::type>::type +makeFutureWith(F&& func); + +// makeFutureWith(T()) -> Future +// makeFutureWith(void()) -> Future +template +typename std::enable_if< + !(isFuture::type>::value), + Future::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(std::current_exception()); template -DEPRECATED Future makeFuture(std::exception_ptr const& e); +FOLLY_DEPRECATED("use makeSemiFuture(exception_wrapper)") +Future makeFuture(std::exception_ptr const& e); /// Make a failed Future from an exception_wrapper. +/// NOTE: This function is deprecated. Please use makeSemiFuture and pass the +/// appropriate executor to .via on the returned SemiFuture to get a +/// valid Future where necessary. template Future makeFuture(exception_wrapper ew); /** Make a Future from an exception type E that can be passed to - std::make_exception_ptr(). */ + std::make_exception_ptr(). + + NOTE: This function is deprecated. Please use makeSemiFuture and pass the + appropriate executor to .via on the returned SemiFuture to get a + valid Future where necessary. + */ template typename std::enable_if::value, Future>::type makeFuture(E const& e); -/** Make a Future out of a Try */ +/** + Make a Future out of a Try + + NOTE: This function is deprecated. Please use makeSemiFuture and pass the + appropriate executor to .via on the returned SemiFuture to get a + valid Future where necessary. + */ template Future makeFuture(Try&& t); @@ -120,8 +293,8 @@ inline Future via( /// This is semantically equivalent to via(executor).then(func), but /// easier to read and slightly more efficient. template -auto via(Executor*, Func func) - -> Future::Inner>; +auto via(Executor*, Func&& func) + -> Future()())>::Inner>; /** When all the input Futures complete, the returned Future will complete. Errors do not cause early termination; this Future will always succeed @@ -154,17 +327,16 @@ auto collectAll(Collection&& c) -> decltype(collectAll(c.begin(), c.end())) { /// is a Future, Try, ...>>. /// The Futures are moved in, so your copies are invalid. template -typename detail::CollectAllVariadicContext< - typename std::decay::type::value_type...>::type +typename futures::detail::CollectAllVariadicContext< + typename std::decay::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 instead of /// std::vector> template -Future::value_type::value_type ->::result_type> +Future::value_type::value_type>::result_type> collect(InputIterator first, InputIterator last); /// Sugar for the most common case @@ -177,8 +349,8 @@ auto collect(Collection&& c) -> decltype(collect(c.begin(), c.end())) { /// type of the returned Future is std::tuple instead of /// std::tuple, Try, ...> template -typename detail::CollectVariadicContext< - typename std::decay::type::value_type...>::type +typename futures::detail::CollectVariadicContext< + typename std::decay::type::value_type...>::type collect(Fs&&... fs); /** The result is a pair of the index of the first Future to complete and @@ -199,6 +371,23 @@ auto collectAny(Collection&& c) -> decltype(collectAny(c.begin(), c.end())) { 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 +Future::value_type::value_type>> +collectAnyWithoutException(InputIterator first, InputIterator last); + +/// Sugar for the most common case +template +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) @@ -226,18 +415,30 @@ auto collectN(Collection&& c, size_t n) func must return a Future for each value in input */ -template ::value_type, - class Result = typename detail::resultOf::value_type> +template < + class Collection, + class F, + class ItT = typename std::iterator_traits< + typename Collection::iterator>::value_type, + class Result = typename futures::detail::resultOf::value_type> +std::vector> 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::value_type> std::vector> -window(Collection input, F func, size_t n); +window(Executor* executor, Collection input, F func, size_t n); template using MaybeTryArg = typename std::conditional< - detail::callableWith&&>::value, Try, ItT>::type; + futures::detail::callableWith&&>::value, + Try, + ItT>::type; -template +template using isFutureResult = isFuture::type>; /** repeatedly calls func on every result, e.g. @@ -268,9 +469,12 @@ auto reduce(Collection&& c, T&& initial, F&& func) /** like reduce, but calls func on finished futures as they complete does NOT keep the order of the input */ -template ::value_type::value_type, - class Arg = MaybeTryArg> +template < + class It, + class T, + class F, + class ItT = typename std::iterator_traits::value_type::value_type, + class Arg = MaybeTryArg> Future unorderedReduce(It first, It last, T initial, F func); /// Sugar for the most common case @@ -284,5 +488,4 @@ auto unorderedReduce(Collection&& c, T&& initial, F&& func) std::forward(initial), std::forward(func)); } - -} // namespace +} // namespace folly