| Line | % of fetches | Source |
|---|---|---|
| 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.