1 //  Copyright (c) 2007-2017 Hartmut Kaiser
2 //  Copyright (c) 2013 Agustin Berge
3 //  Copyright (c) 2017 Denis Blank
4 //
5 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
6 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 
8 /// \file lcos/when_all.hpp
9 
10 #if !defined(HPX_LCOS_WHEN_ALL_APR_19_2012_1140AM)
11 #define HPX_LCOS_WHEN_ALL_APR_19_2012_1140AM
12 
13 #if defined(DOXYGEN)
14 namespace hpx
15 {
16     /// The function \a when_all is an operator allowing to join on the result
17     /// of all given futures. It AND-composes all future objects given and
18     /// returns a new future object representing the same list of futures
19     /// after they finished executing.
20     ///
21     /// \param first    [in] The iterator pointing to the first element of a
22     ///                 sequence of \a future or \a shared_future objects for
23     ///                 which \a when_all should wait.
24     /// \param last     [in] The iterator pointing to the last element of a
25     ///                 sequence of \a future or \a shared_future objects for
26     ///                 which \a when_all should wait.
27     ///
28     /// \return   Returns a future holding the same list of futures as has
29     ///           been passed to \a when_all.
30     ///           - future<Container<future<R>>>: If the input cardinality is
31     ///             unknown at compile time and the futures are all of the
32     ///             same type. The order of the futures in the output container
33     ///             will be the same as given by the input iterator.
34     ///
35     /// \note Calling this version of \a when_all where first == last, returns
36     ///       a future with an empty container that is immediately ready.
37     ///       Each future and shared_future is waited upon and then copied into
38     ///       the collection of the output (returned) future, maintaining the
39     ///       order of the futures in the input collection.
40     ///       The future returned by \a when_all will not throw an exception,
41     ///       but the futures held in the output collection may.
42     template <typename InputIter, typename Container =
43         vector<future<typename std::iterator_traits<InputIter>::value_type>>>
44     future<Container>
45     when_all(InputIter first, InputIter last);
46 
47     /// The function \a when_all is an operator allowing to join on the result
48     /// of all given futures. It AND-composes all future objects given and
49     /// returns a new future object representing the same list of futures
50     /// after they finished executing.
51     ///
52     /// \param values   [in] A range holding an arbitrary amount of \a future
53     ///                 or \a shared_future objects for which \a when_all
54     ///                 should wait.
55     ///
56     /// \return   Returns a future holding the same list of futures as has
57     ///           been passed to when_all.
58     ///           - future<Container<future<R>>>: If the input cardinality is
59     ///             unknown at compile time and the futures are all of the
60     ///             same type.
61     ///
62     /// \note Calling this version of \a when_all where the input container is
63     ///       empty, returns a future with an empty container that is immediately
64     ///       ready.
65     ///       Each future and shared_future is waited upon and then copied into
66     ///       the collection of the output (returned) future, maintaining the
67     ///       order of the futures in the input collection.
68     ///       The future returned by \a when_all will not throw an exception,
69     ///       but the futures held in the output collection may.
70     template <typename Range>
71     future<Range>
72     when_all(Range&& values);
73 
74     /// The function \a when_all is an operator allowing to join on the result
75     /// of all given futures. It AND-composes all future objects given and
76     /// returns a new future object representing the same list of futures
77     /// after they finished executing.
78     ///
79     /// \param futures  [in] An arbitrary number of \a future or \a shared_future
80     ///                 objects, possibly holding different types for which
81     ///                 \a when_all should wait.
82     ///
83     /// \return   Returns a future holding the same list of futures as has
84     ///           been passed to \a when_all.
85     ///           - future<tuple<future<T0>, future<T1>, future<T2>...>>: If
86     ///             inputs are fixed in number and are of heterogeneous types.
87     ///             The inputs can be any arbitrary number of future objects.
88     ///           - future<tuple<>> if \a when_all is called with zero arguments.
89     ///             The returned future will be initially ready.
90     ///
91     /// \note Each future and shared_future is waited upon and then copied into
92     ///       the collection of the output (returned) future, maintaining the
93     ///       order of the futures in the input collection.
94     ///       The future returned by \a when_all will not throw an exception,
95     ///       but the futures held in the output collection may.
96     template <typename ...T>
97     future<tuple<future<T>...>>
98     when_all(T &&... futures);
99 
100     /// The function \a when_all_n is an operator allowing to join on the result
101     /// of all given futures. It AND-composes all future objects given and
102     /// returns a new future object representing the same list of futures
103     /// after they finished executing.
104     ///
105     /// \param begin    [in] The iterator pointing to the first element of a
106     ///                 sequence of \a future or \a shared_future objects for
107     ///                 which \a wait_all_n should wait.
108     /// \param count    [in] The number of elements in the sequence starting at
109     ///                 \a first.
110     ///
111     /// \return   Returns a future holding the same list of futures as has
112     ///           been passed to \a when_all_n.
113     ///           - future<Container<future<R>>>: If the input cardinality is
114     ///             unknown at compile time and the futures are all of the
115     ///             same type. The order of the futures in the output vector
116     ///             will be the same as given by the input iterator.
117     ///
118     /// \throws This function will throw errors which are encountered while
119     ///         setting up the requested operation only. Errors encountered
120     ///         while executing the operations delivering the results to be
121     ///         stored in the futures are reported through the futures
122     ///         themselves.
123     ///
124     /// \note     As long as \a ec is not pre-initialized to \a hpx::throws this
125     ///           function doesn't throw but returns the result code using the
126     ///           parameter \a ec. Otherwise it throws an instance of
127     ///           hpx::exception.
128     ///
129     /// \note     None of the futures in the input sequence are invalidated.
130     template <typename InputIter, typename Container =
131         vector<future<typename std::iterator_traits<InputIter>::value_type>>>
132     future<Container>
133     when_all_n(InputIter begin, std::size_t count);
134 }
135 
136 #else // DOXYGEN
137 
138 #include <hpx/config.hpp>
139 #include <hpx/lcos/detail/future_data.hpp>
140 #include <hpx/lcos/detail/future_traits.hpp>
141 #include <hpx/lcos/detail/future_transforms.hpp>
142 #include <hpx/lcos/future.hpp>
143 #include <hpx/traits/acquire_future.hpp>
144 #include <hpx/traits/future_access.hpp>
145 #include <hpx/traits/is_future.hpp>
146 #include <hpx/traits/is_future_range.hpp>
147 #include <hpx/util/internal_allocator.hpp>
148 #include <hpx/util/pack_traversal_async.hpp>
149 #include <hpx/util/tuple.hpp>
150 
151 #include <cstddef>
152 #include <iterator>
153 #include <type_traits>
154 #include <utility>
155 #include <vector>
156 
157 ///////////////////////////////////////////////////////////////////////////////
158 namespace hpx { namespace lcos
159 {
160     namespace detail
161     {
162         ///////////////////////////////////////////////////////////////////////
163         template <typename T, typename Enable = void>
164         struct when_all_result
165         {
166             typedef T type;
167 
callhpx::lcos::detail::when_all_result168             static type call(T&& t)
169             {
170                 return std::move(t);
171             }
172         };
173 
174         template <typename T>
175         struct when_all_result<util::tuple<T>,
176             typename std::enable_if<
177                 traits::is_future_range<T>::value
178             >::type>
179         {
180             typedef T type;
181 
callhpx::lcos::detail::when_all_result182             static type call(util::tuple<T>&& t)
183             {
184                 return std::move(util::get<0>(t));
185             }
186         };
187 
188         template <typename Tuple>
189         class async_when_all_frame
190           : public future_data<typename when_all_result<Tuple>::type>
191         {
192         public:
193             typedef typename when_all_result<Tuple>::type result_type;
194             typedef hpx::lcos::future<result_type> type;
195             typedef hpx::lcos::detail::future_data<result_type> base_type;
196 
async_when_all_frame(typename base_type::init_no_addref no_addref)197             explicit async_when_all_frame(
198                 typename base_type::init_no_addref no_addref)
199               : future_data<typename when_all_result<Tuple>::type>(no_addref)
200             {
201             }
202 
203             template <typename T>
operator ()(util::async_traverse_visit_tag,T && current)204             auto operator()(util::async_traverse_visit_tag, T&& current)
205                 -> decltype(async_visit_future(std::forward<T>(current)))
206             {
207                 return async_visit_future(std::forward<T>(current));
208             }
209 
210             template <typename T, typename N>
operator ()(util::async_traverse_detach_tag,T && current,N && next)211             auto operator()(
212                 util::async_traverse_detach_tag, T&& current, N&& next)
213                 -> decltype(async_detach_future(
214                     std::forward<T>(current), std::forward<N>(next)))
215             {
216                 return async_detach_future(
217                     std::forward<T>(current), std::forward<N>(next));
218             }
219 
220             template <typename T>
operator ()(util::async_traverse_complete_tag,T && pack)221             void operator()(util::async_traverse_complete_tag, T&& pack)
222             {
223                 this->set_value(
224                     when_all_result<Tuple>::call(std::forward<T>(pack)));
225             }
226         };
227 
228         template <typename... T>
229         typename detail::async_when_all_frame<
230             util::tuple<
231                 typename traits::acquire_future<T>::type...
232             >
233         >::type
when_all_impl(T &&...args)234         when_all_impl(T&&... args)
235         {
236             typedef util::tuple<typename traits::acquire_future<T>::type...>
237                 result_type;
238             typedef detail::async_when_all_frame<result_type> frame_type;
239 
240             traits::acquire_future_disp func;
241 
242             typename frame_type::base_type::init_no_addref no_addref;
243 
244             auto frame = util::traverse_pack_async_allocator(
245                 util::internal_allocator<>{},
246                 util::async_traverse_in_place_tag<frame_type>{}, no_addref,
247                 func(std::forward<T>(args))...);
248 
249             using traits::future_access;
250             return future_access<typename frame_type::type>::create(
251                 std::move(frame));
252         }
253     }
254 
255     template <typename First, typename Second>
when_all(First && first,Second && second)256     auto when_all(First&& first, Second&& second)
257         -> decltype(detail::when_all_impl(
258             std::forward<First>(first), std::forward<Second>(second)))
259     {
260         return detail::when_all_impl(
261             std::forward<First>(first), std::forward<Second>(second));
262     }
263     template <typename Iterator,
264         typename Container = std::vector<
265             typename detail::future_iterator_traits<Iterator>::type>>
when_all(Iterator begin,Iterator end)266     future<Container> when_all(Iterator begin, Iterator end)
267     {
268         return detail::when_all_impl(
269             detail::acquire_future_iterators<Iterator, Container>(begin, end));
270     }
271 
272     inline lcos::future<util::tuple<> > //-V524
when_all()273     when_all()
274     {
275         typedef util::tuple<> result_type;
276         return lcos::make_ready_future(result_type());
277     }
278 
279     ///////////////////////////////////////////////////////////////////////////
280     template <typename Iterator,
281         typename Container = std::vector<
282             typename lcos::detail::future_iterator_traits<Iterator>::type>>
when_all_n(Iterator begin,std::size_t count)283     lcos::future<Container> when_all_n(Iterator begin, std::size_t count)
284     {
285         return detail::when_all_impl(
286             detail::acquire_future_n<Iterator, Container>(begin, count));
287     }
288 
289     ///////////////////////////////////////////////////////////////////////////
290     template <typename... Args,
291         typename std::enable_if<(sizeof...(Args) == 1U) ||
292             (sizeof...(Args) > 2U)>::type* = nullptr>
when_all(Args &&...args)293     auto when_all(Args&&... args)
294         -> decltype(detail::when_all_impl(std::forward<Args>(args)...))
295     {
296         return detail::when_all_impl(std::forward<Args>(args)...);
297     }
298 }}
299 
300 namespace hpx
301 {
302     using lcos::when_all;
303     using lcos::when_all_n;
304 }
305 
306 #endif // DOXYGEN
307 #endif
308