/home/users/khuck/src/hpx-lsu/hpx/lcos/when_all.hpp

Line% of fetchesSource
1  
//  Copyright (c) 2007-2015 Hartmut Kaiser
2  
//  Copyright (c) 2013 Agustin Berge
3  
//
4  
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
7  
/// \file lcos/when_all.hpp
8  
9  
#if !defined(HPX_LCOS_WHEN_ALL_APR_19_2012_1140AM)
10  
#define HPX_LCOS_WHEN_ALL_APR_19_2012_1140AM
11  
12  
#if defined(DOXYGEN)
13  
namespace hpx
14  
{
15  
    /// The function \a when_all is an operator allowing to join on the result
16  
    /// of all given futures. It AND-composes all future objects given and
17  
    /// returns a new future object representing the same list of futures
18  
    /// after they finished executing.
19  
    ///
20  
    /// \param first    [in] The iterator pointing to the first element of a
21  
    ///                 sequence of \a future or \a shared_future objects for
22  
    ///                 which \a when_all should wait.
23  
    /// \param last     [in] The iterator pointing to the last element of a
24  
    ///                 sequence of \a future or \a shared_future objects for
25  
    ///                 which \a when_all should wait.
26  
    ///
27  
    /// \return   Returns a future holding the same list of futures as has
28  
    ///           been passed to \a when_all.
29  
    ///           - future<Container<future<R>>>: If the input cardinality is
30  
    ///             unknown at compile time and the futures are all of the
31  
    ///             same type. The order of the futures in the output container
32  
    ///             will be the same as given by the input iterator.
33  
    ///
34  
    /// \note Calling this version of \a when_all where first == last, returns
35  
    ///       a future with an empty container that is immediately ready.
36  
    ///       Each future and shared_future is waited upon and then copied into
37  
    ///       the collection of the output (returned) future, maintaining the
38  
    ///       order of the futures in the input collection.
39  
    ///       The future returned by \a when_all will not throw an exception,
40  
    ///       but the futures held in the output collection may.
41  
    template <typename InputIter, typename Container =
42  
        vector<future<typename std::iterator_traits<InputIter>::value_type>>>
43  
    future<Container>
44  
    when_all(InputIter first, InputIter last);
45  
46  
    /// The function \a when_all is an operator allowing to join on the result
47  
    /// of all given futures. It AND-composes all future objects given and
48  
    /// returns a new future object representing the same list of futures
49  
    /// after they finished executing.
50  
    ///
51  
    /// \param values   [in] A range holding an arbitrary amount of \a future
52  
    ///                 or \a shared_future objects for which \a when_all
53  
    ///                 should wait.
54  
    ///
55  
    /// \return   Returns a future holding the same list of futures as has
56  
    ///           been passed to when_all.
57  
    ///           - future<Container<future<R>>>: If the input cardinality is
58  
    ///             unknown at compile time and the futures are all of the
59  
    ///             same type.
60  
    ///
61  
    /// \note Calling this version of \a when_all where the input container is
62  
    ///       empty, returns a future with an empty container that is immediately
63  
    ///       ready.
64  
    ///       Each future and shared_future is waited upon and then copied into
65  
    ///       the collection of the output (returned) future, maintaining the
66  
    ///       order of the futures in the input collection.
67  
    ///       The future returned by \a when_all will not throw an exception,
68  
    ///       but the futures held in the output collection may.
69  
    template <typename Range>
70  
    future<Range>
71  
    when_all(Range&& values);
72  
73  
    /// The function \a when_all is an operator allowing to join on the result
74  
    /// of all given futures. It AND-composes all future objects given and
75  
    /// returns a new future object representing the same list of futures
76  
    /// after they finished executing.
77  
    ///
78  
    /// \param futures  [in] An arbitrary number of \a future or \a shared_future
79  
    ///                 objects, possibly holding different types for which
80  
    ///                 \a when_all should wait.
81  
    ///
82  
    /// \return   Returns a future holding the same list of futures as has
83  
    ///           been passed to \a when_all.
84  
    ///           - future<tuple<future<T0>, future<T1>, future<T2>...>>: If
85  
    ///             inputs are fixed in number and are of heterogeneous types.
86  
    ///             The inputs can be any arbitrary number of future objects.
87  
    ///           - future<tuple<>> if \a when_all is called with zero arguments.
88  
    ///             The returned future will be initially ready.
89  
    ///
90  
    /// \note Each future and shared_future is waited upon and then copied into
91  
    ///       the collection of the output (returned) future, maintaining the
92  
    ///       order of the futures in the input collection.
93  
    ///       The future returned by \a when_all will not throw an exception,
94  
    ///       but the futures held in the output collection may.
95  
    template <typename ...T>
96  
    future<tuple<future<T>...>>
97  
    when_all(T &&... futures);
98  
99  
    /// The function \a when_all_n is an operator allowing to join on the result
100  
    /// of all given futures. It AND-composes all future objects given and
101  
    /// returns a new future object representing the same list of futures
102  
    /// after they finished executing.
103  
    ///
104  
    /// \param begin    [in] The iterator pointing to the first element of a
105  
    ///                 sequence of \a future or \a shared_future objects for
106  
    ///                 which \a wait_all_n should wait.
107  
    /// \param count    [in] The number of elements in the sequence starting at
108  
    ///                 \a first.
109  
    ///
110  
    /// \return   Returns a future holding the same list of futures as has
111  
    ///           been passed to \a when_all_n.
112  
    ///           - future<Container<future<R>>>: If the input cardinality is
113  
    ///             unknown at compile time and the futures are all of the
114  
    ///             same type. The order of the futures in the output vector
115  
    ///             will be the same as given by the input iterator.
116  
    ///
117  
    /// \throws This function will throw errors which are encountered while
118  
    ///         setting up the requested operation only. Errors encountered
119  
    ///         while executing the operations delivering the results to be
120  
    ///         stored in the futures are reported through the futures
121  
    ///         themselves.
122  
    ///
123  
    /// \note     As long as \a ec is not pre-initialized to \a hpx::throws this
124  
    ///           function doesn't throw but returns the result code using the
125  
    ///           parameter \a ec. Otherwise it throws an instance of
126  
    ///           hpx::exception.
127  
    ///
128  
    /// \note     None of the futures in the input sequence are invalidated.
129  
    template <typename InputIter, typename Container =
130  
        vector<future<typename std::iterator_traits<InputIter>::value_type>>>
131  
    future<Container>
132  
    when_all_n(InputIter begin, std::size_t count);
133  
}
134  
135  
#else // DOXYGEN
136  
137  
#include <hpx/config.hpp>
138  
#include <hpx/lcos/detail/future_data.hpp>
139  
#include <hpx/lcos/future.hpp>
140  
#include <hpx/lcos/when_some.hpp>
141  
#include <hpx/traits/acquire_future.hpp>
142  
#include <hpx/traits/acquire_shared_state.hpp>
143  
#include <hpx/traits/future_access.hpp>
144  
#include <hpx/traits/is_future.hpp>
145  
#include <hpx/traits/is_future_range.hpp>
146  
#include <hpx/util/decay.hpp>
147  
#include <hpx/util/deferred_call.hpp>
148  
#include <hpx/util/tuple.hpp>
149  
150  
#include <boost/intrusive_ptr.hpp>
151  
#include <boost/range/functions.hpp>
152  
153  
#include <algorithm>
154  
#include <cstddef>
155  
#include <iterator>
156  
#include <type_traits>
157  
#include <utility>
158  
#include <vector>
159  
160  
///////////////////////////////////////////////////////////////////////////////
161  
namespace hpx { namespace lcos
162  
{
163  
    namespace detail
164  
    {
165  
        ///////////////////////////////////////////////////////////////////////
166  
        template <typename T, typename Enable = void>
167  
        struct when_all_result
168  
        {
169  
            typedef T type;
170  
171  
            static type call(T&& t)
172  
            {
173  
                return std::move(t);
174  
            }
175  
        };
176  
177  
        template <typename T>
178  
        struct when_all_result<util::tuple<T>,
179  
            typename std::enable_if<
180  
                traits::is_future_range<T>::value
181  
            >::type>
182  
        {
183  
            typedef T type;
184  
185  
            static type call(util::tuple<T>&& t)
186  
            {
187  
                return std::move(util::get<0>(t));
188  
            }
189  
        };
190  
191  
        ///////////////////////////////////////////////////////////////////////
192  
        template <typename Tuple>
193  
        struct when_all_frame //-V690
194  
          : hpx::lcos::detail::future_data<typename when_all_result<Tuple>::type>
195  
        {
196  
            typedef typename when_all_result<Tuple>::type result_type;
197  
            typedef hpx::lcos::future<result_type> type;
198  
199  
        private:
200  
            // workaround gcc regression wrongly instantiating constructors
201  
            when_all_frame();
202  
            when_all_frame(when_all_frame const&);
203  
204  
            template <std::size_t I>
205  
            struct is_end
206  
              : std::integral_constant<
207  
                    bool,
208  
                    util::tuple_size<Tuple>::value == I
209  
                >
210  
            {};
211  
212  
        public:
213  
            template <typename Tuple_>
214  
            when_all_frame(Tuple_&& t)
215  
              : t_(std::forward<Tuple_>(t))
216  
            {}
217  
218  
        protected:
219  
            // End of the tuple is reached
220  
            template <std::size_t I>
221  
            HPX_FORCEINLINE
222  
            void do_await(std::true_type)
223  
            {
224  
                this->set_value(when_all_result<Tuple>::call(std::move(t_)));
225  
            }
226  
227  
            // Current element is a range of futures
228  
            template <std::size_t I, typename Iter>
229  
            void await_range(Iter next, Iter end)
230  
            {
231  
                typedef typename std::iterator_traits<Iter>::value_type
232  
                    future_type;
233  
                typedef typename traits::future_traits<future_type>::type
234  
                    future_result_type;
235  
236  
                void (when_all_frame::*f)(Iter, Iter) =
237  
                    &when_all_frame::await_range<I>;
238  
239  
                for (/**/; next != end; ++next)
240  
                {
241  
                    boost::intrusive_ptr<
242  
                        lcos::detail::future_data<future_result_type>
243  
                    > next_future_data =
244  
                        traits::detail::get_shared_state(*next);
245  
246  
                    if (!next_future_data->is_ready())
247  
                    {
248  
                        next_future_data->execute_deferred();
249  
250  
                        // execute_deferred might have made the future ready
251  
                        if (!next_future_data->is_ready())
252  
                        {
253  
                            // Attach a continuation to this future which will
254  
                            // re-evaluate it and continue to the next element
255  
                            // in the sequence (if any).
256  
                            boost::intrusive_ptr<when_all_frame> this_(this);
257  
                            next_future_data->set_on_completed(util::deferred_call(
258  
                                f, std::move(this_),
259  
                                std::move(next), std::move(end)));
260  
                            return;
261  
                        }
262  
                    }
263  
                }
264  
265  
                do_await<I + 1>(is_end<I + 1>());
266  
            }
267  
268  
            template <std::size_t I>
269  
            HPX_FORCEINLINE
270  
            void await_next(std::false_type, std::true_type)
271  
            {
272  
                await_range<I>(
273  
                    boost::begin(boost::unwrap_ref(util::get<I>(t_))),
274  
                    boost::end(boost::unwrap_ref(util::get<I>(t_))));
275  
            }
276  
277  
            // Current element is a simple future
278  
            template <std::size_t I>
279  
            HPX_FORCEINLINE
280  
            void await_next(std::true_type, std::false_type)
281  
            {
282  
                typedef typename util::decay_unwrap<
283  
                    typename util::tuple_element<I, Tuple>::type
284  
                >::type future_type;
285  
286  
                future_type& f_ = util::get<I>(t_);
287  
288  
                typedef typename traits::future_traits<future_type>::type
289  
                    future_result_type;
290  
291  
                boost::intrusive_ptr<
292  
                    lcos::detail::future_data<future_result_type>
293  
                > next_future_data =
294  
                    traits::detail::get_shared_state(f_);
295  
296  
                if (!next_future_data->is_ready())
297  
                {
298  
                    next_future_data->execute_deferred();
299  
300  
                    // execute_deferred might have made the future ready
301  
                    if (!next_future_data->is_ready())
302  
                    {
303  
                        // Attach a continuation to this future which will
304  
                        // re-evaluate it and continue to the next argument
305  
                        // (if any).
306  
                        void (when_all_frame::*f)(std::true_type, std::false_type) =
307  
                            &when_all_frame::await_next<I>;
308  
309  
                        boost::intrusive_ptr<when_all_frame> this_(this);
310  
                        next_future_data->set_on_completed(util::deferred_call(
311  
                            f, std::move(this_), std::true_type(), std::false_type()));
312  
                        return;
313  
                    }
314  
                }
315  
316  
                do_await<I + 1>(is_end<I + 1>());
317  
            }
318  
319  
            template <std::size_t I>
320  
            HPX_FORCEINLINE
321  
            void do_await(std::false_type)
322  
            {
323  
                typedef typename util::decay_unwrap<
324  
                    typename util::tuple_element<I, Tuple>::type
325  
                >::type future_type;
326  
327  
                typedef traits::is_future<future_type> is_future;
328  
                typedef traits::is_future_range<future_type> is_range;
329  
330  
                await_next<I>(is_future(), is_range());
331  
            }
332  
333  
        public:
334  
            HPX_FORCEINLINE void do_await()
335  
            {
336  
                do_await<0>(is_end<0>());
337  
            }
338  
339  
        private:
340  
            Tuple t_;
341  
        };
342  
    }
343  
344  
    ///////////////////////////////////////////////////////////////////////////
345  
    template <typename Range>
346  
    typename std::enable_if<traits::is_future_range<Range>::value,
347  
        lcos::future<typename std::decay<Range>::type> >::type //-V659
348  
    when_all(Range&& values)
349  
    {
350  
        typedef detail::when_all_frame<
351  
                util::tuple<Range>
352  
            > frame_type;
353  
354  
        boost::intrusive_ptr<frame_type> p(new frame_type(
355  
            util::forward_as_tuple(std::move(values))));
356  
        p->do_await();
357  
358  
        using traits::future_access;
359  
        return future_access<typename frame_type::type>::create(std::move(p));
360  
    }
361  
362  
    template <typename Range>
363  
    typename std::enable_if<traits::is_future_range<Range>::value,
364  
        lcos::future<typename std::decay<Range>::type> >::type
365  
    when_all(Range& values)
366  
    {
367  
        Range values_ = traits::acquire_future<Range>()(values);
368  
        return lcos::when_all(std::move(values_));
369  
    }
370  
371  
    template <typename Iterator, typename Container =
372  
        std::vector<typename lcos::detail::future_iterator_traits<Iterator>::type> >
373  
    lcos::future<Container>
374  
    when_all(Iterator begin, Iterator end)
375  
    {
376  
        Container values;
377  
378  
        typename std::iterator_traits<Iterator>::
379  
            difference_type difference = std::distance(begin, end);
380  
        if (difference > 0)
381  
            traits::detail::reserve_if_vector(
382  
                values, static_cast<std::size_t>(difference));
383  
384  
        std::transform(begin, end, std::back_inserter(values),
385  
            traits::acquire_future_disp());
386  
387  
        return lcos::when_all(std::move(values));
388  
    }
389  
390  
    inline lcos::future<util::tuple<> > //-V524
391  
    when_all()
392  
    {
393  
        typedef util::tuple<> result_type;
394  
        return lcos::make_ready_future(result_type());
395  
    }
396  
397  
    ///////////////////////////////////////////////////////////////////////////
398  
    template <typename Iterator, typename Container =
399  
        std::vector<typename lcos::detail::future_iterator_traits<Iterator>::type> >
400  
    lcos::future<Container>
401  
    when_all_n(Iterator begin, std::size_t count)
402  
    {
403  
        Container values;
404  
        traits::detail::reserve_if_vector(values, count);
405  
406  
        traits::acquire_future_disp func;
407  
        for (std::size_t i = 0; i != count; ++i)
408  
            values.push_back(func(*begin++));
409  
410  
        return lcos::when_all(std::move(values));
411  
    }
412  
413  
    ///////////////////////////////////////////////////////////////////////////
414  
    template <typename... Ts>
415  
    typename detail::when_all_frame<
416  
        util::tuple<typename traits::acquire_future<Ts>::type...>
417  
    >::type
418  
    when_all(Ts&&... ts)
419  
    {
420  
        typedef util::tuple<
421  
                typename traits::acquire_future<Ts>::type...
422  
            > result_type;
423  
        typedef detail::when_all_frame<result_type> frame_type;
424  
425  
        traits::acquire_future_disp func;
426  
        result_type values(func(std::forward<Ts>(ts))...);
427  
428  
        boost::intrusive_ptr<frame_type> p(new frame_type(std::move(values)));
429  
        p->do_await();
430  
431  
        using traits::future_access;
432  
        return future_access<typename frame_type::type>::create(std::move(p));
433  
    }
434  
}}
435  
436  
namespace hpx
437  
{
438  
    using lcos::when_all;
439  
    using lcos::when_all_n;
440  
}
441  
442  
#endif // DOXYGEN
443  
#endif
444  

Copyright (c) 2006-2012 Rogue Wave Software, Inc. All Rights Reserved.
Patents pending.