| 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/wait_all.hpp | |
| 8 | ||
| 9 | #if !defined(HPX_LCOS_WAIT_ALL_APR_19_2012_1140AM) | |
| 10 | #define HPX_LCOS_WAIT_ALL_APR_19_2012_1140AM | |
| 11 | ||
| 12 | #if defined(DOXYGEN) | |
| 13 | namespace hpx | |
| 14 | { | |
| 15 | /// The function \a wait_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 after they finished executing. | |
| 18 | /// | |
| 19 | /// \param first The iterator pointing to the first element of a | |
| 20 | /// sequence of \a future or \a shared_future objects for | |
| 21 | /// which \a wait_all should wait. | |
| 22 | /// \param last The iterator pointing to the last element of a | |
| 23 | /// sequence of \a future or \a shared_future objects for | |
| 24 | /// which \a wait_all should wait. | |
| 25 | /// | |
| 26 | /// \note The function \a wait_all returns after all futures have become | |
| 27 | /// ready. All input futures are still valid after \a wait_all | |
| 28 | /// returns. | |
| 29 | /// | |
| 30 | template <typename InputIter> | |
| 31 | void wait_all(InputIter first, InputIter last); | |
| 32 | ||
| 33 | /// The function \a wait_all is an operator allowing to join on the result | |
| 34 | /// of all given futures. It AND-composes all future objects given and | |
| 35 | /// returns after they finished executing. | |
| 36 | /// | |
| 37 | /// \param futures A vector holding an arbitrary amount of \a future or | |
| 38 | /// \a shared_future objects for which \a wait_all should | |
| 39 | /// wait. | |
| 40 | /// | |
| 41 | /// \note The function \a wait_all returns after all futures have become | |
| 42 | /// ready. All input futures are still valid after \a wait_all | |
| 43 | /// returns. | |
| 44 | /// | |
| 45 | template <typename R> | |
| 46 | void wait_all(std::vector<future<R>>&& futures); | |
| 47 | ||
| 48 | /// The function \a wait_all is an operator allowing to join on the result | |
| 49 | /// of all given futures. It AND-composes all future objects given and | |
| 50 | /// returns after they finished executing. | |
| 51 | /// | |
| 52 | /// \param futures An arbitrary number of \a future or \a shared_future | |
| 53 | /// objects, possibly holding different types for which | |
| 54 | /// \a wait_all should wait. | |
| 55 | /// | |
| 56 | /// \note The function \a wait_all returns after all futures have become | |
| 57 | /// ready. All input futures are still valid after \a wait_all | |
| 58 | /// returns. | |
| 59 | /// | |
| 60 | template <typename ...T> | |
| 61 | void wait_all(T &&... futures); | |
| 62 | ||
| 63 | /// The function \a wait_all_n is an operator allowing to join on the result | |
| 64 | /// of all given futures. It AND-composes all future objects given and | |
| 65 | /// returns after they finished executing. | |
| 66 | /// | |
| 67 | /// \param begin The iterator pointing to the first element of a | |
| 68 | /// sequence of \a future or \a shared_future objects for | |
| 69 | /// which \a wait_all_n should wait. | |
| 70 | /// \param count The number of elements in the sequence starting at | |
| 71 | /// \a first. | |
| 72 | /// | |
| 73 | /// \return The function \a wait_all_n will return an iterator | |
| 74 | /// referring to the first element in the input sequence | |
| 75 | /// after the last processed element. | |
| 76 | /// | |
| 77 | /// \note The function \a wait_all_n returns after all futures have become | |
| 78 | /// ready. All input futures are still valid after \a wait_all_n | |
| 79 | /// returns. | |
| 80 | /// | |
| 81 | template <typename InputIter> | |
| 82 | InputIter wait_all_n(InputIter begin, std::size_t count); | |
| 83 | } | |
| 84 | ||
| 85 | #else // DOXYGEN | |
| 86 | ||
| 87 | #include <hpx/config.hpp> | |
| 88 | #include <hpx/lcos/detail/future_data.hpp> | |
| 89 | #include <hpx/lcos/future.hpp> | |
| 90 | #include <hpx/lcos/wait_some.hpp> | |
| 91 | #include <hpx/traits/acquire_shared_state.hpp> | |
| 92 | #include <hpx/traits/future_access.hpp> | |
| 93 | #include <hpx/traits/future_traits.hpp> | |
| 94 | #include <hpx/traits/is_future.hpp> | |
| 95 | #include <hpx/util/always_void.hpp> | |
| 96 | #include <hpx/util/decay.hpp> | |
| 97 | #include <hpx/util/deferred_call.hpp> | |
| 98 | #include <hpx/util/tuple.hpp> | |
| 99 | ||
| 100 | #include <boost/intrusive_ptr.hpp> | |
| 101 | #include <boost/range/functions.hpp> | |
| 102 | ||
| 103 | #include <algorithm> | |
| 104 | #include <cstddef> | |
| 105 | #include <iterator> | |
| 106 | #include <type_traits> | |
| 107 | #include <utility> | |
| 108 | #include <vector> | |
| 109 | ||
| 110 | /////////////////////////////////////////////////////////////////////////////// | |
| 111 | namespace hpx { namespace lcos | |
| 112 | { | |
| 113 | namespace detail | |
| 114 | { | |
| 115 | /////////////////////////////////////////////////////////////////////// | |
| 116 | template <typename Future, typename Enable = void> | |
| 117 | struct is_future_or_shared_state | |
| 118 | : traits::is_future<Future> | |
| 119 | {}; | |
| 120 | ||
| 121 | template <typename R> | |
| 122 | struct is_future_or_shared_state< | |
| 123 | boost::intrusive_ptr<future_data<R> > > | |
| 124 | : std::true_type | |
| 125 | {}; | |
| 126 | ||
| 127 | /////////////////////////////////////////////////////////////////////// | |
| 128 | template <typename Range, typename Enable = void> | |
| 129 | struct is_future_or_shared_state_range | |
| 130 | : std::false_type | |
| 131 | {}; | |
| 132 | ||
| 133 | template <typename T> | |
| 134 | struct is_future_or_shared_state_range<std::vector<T> > | |
| 135 | : is_future_or_shared_state<T> | |
| 136 | {}; | |
| 137 | ||
| 138 | /////////////////////////////////////////////////////////////////////// | |
| 139 | template <typename Future, typename Enable = void> | |
| 140 | struct future_or_shared_state_result; | |
| 141 | ||
| 142 | template <typename Future> | |
| 143 | struct future_or_shared_state_result<Future, | |
| 144 | typename std::enable_if<traits::is_future<Future>::value>::type> | |
| 145 | : traits::future_traits<Future> | |
| 146 | {}; | |
| 147 | ||
| 148 | template <typename R> | |
| 149 | struct future_or_shared_state_result< | |
| 150 | boost::intrusive_ptr<future_data<R> > > | |
| 151 | { | |
| 152 | typedef R type; | |
| 153 | }; | |
| 154 | ||
| 155 | /////////////////////////////////////////////////////////////////////// | |
| 156 | template <typename Tuple> | |
| 157 | struct wait_all_frame //-V690 | |
| 158 | : hpx::lcos::detail::future_data<void> | |
| 159 | { | |
| 160 | private: | |
| 161 | // workaround gcc regression wrongly instantiating constructors | |
| 162 | wait_all_frame(); | |
| 163 | wait_all_frame(wait_all_frame const&); | |
| 164 | ||
| 165 | template <std::size_t I> | |
| 166 | struct is_end | |
| 167 | : std::integral_constant< | |
| 168 | bool, | |
| 169 | util::tuple_size<Tuple>::value == I | |
| 170 | > | |
| 171 | {}; | |
| 172 | ||
| 173 | public: | |
| 174 | wait_all_frame(Tuple const& t) | |
| 175 | : t_(t) | |
| 176 | {} | |
| 177 | ||
| 178 | protected: | |
| 179 | // End of the tuple is reached | |
| 180 | template <std::size_t I> | |
| 181 | HPX_FORCEINLINE | |
| 182 | void do_await(std::true_type) | |
| 183 | { | |
| 184 | this->set_value(util::unused); // simply make ourself ready | |
| 185 | } | |
| 186 | ||
| 187 | // Current element is a range (vector) of futures | |
| 188 | template <std::size_t I, typename Iter> | |
| 189 | void await_range(Iter next, Iter end) | |
| 190 | { | |
| 191 | typedef typename std::iterator_traits<Iter>::value_type | |
| 192 | future_type; | |
| 193 | typedef typename detail::future_or_shared_state_result< | |
| 194 | future_type | |
| 195 | >::type future_result_type; | |
| 196 | ||
| 197 | void (wait_all_frame::*f)(Iter, Iter) = | |
| 198 | &wait_all_frame::await_range<I>; | |
| 199 | ||
| 200 | for (/**/; next != end; ++next) | |
| 201 | { | |
| 202 | boost::intrusive_ptr< | |
| 203 | lcos::detail::future_data<future_result_type> | |
| 204 | > next_future_data = | |
| 205 | traits::detail::get_shared_state(*next); | |
| 206 | ||
| 207 | if (!next_future_data->is_ready()) | |
| 208 | { | |
| 209 | next_future_data->execute_deferred(); | |
| 210 | ||
| 211 | // execute_deferred might have made the future ready | |
| 212 | if (!next_future_data->is_ready()) | |
| 213 | { | |
| 214 | // Attach a continuation to this future which will | |
| 215 | // re-evaluate it and continue to the next element | |
| 216 | // in the sequence (if any). | |
| 217 | boost::intrusive_ptr<wait_all_frame> this_(this); | |
| 218 | next_future_data->set_on_completed( | |
| 219 | util::deferred_call(f, std::move(this_), | |
| 220 | std::move(next), std::move(end))); | |
| 221 | return; | |
| 222 | } | |
| 223 | } | |
| 224 | } | |
| 225 | ||
| 226 | // All elements of the sequence are ready now, proceed to the | |
| 227 | // next argument. | |
| 228 | do_await<I + 1>(is_end<I + 1>()); | |
| 229 | } | |
| 230 | ||
| 231 | template <std::size_t I> | |
| 232 | HPX_FORCEINLINE | |
| 233 | void await_next(std::false_type, std::true_type) | |
| 234 | { | |
| 235 | await_range<I>( | |
| 236 | boost::begin(boost::unwrap_ref(util::get<I>(t_))), | |
| 237 | boost::end(boost::unwrap_ref(util::get<I>(t_)))); | |
| 238 | } | |
| 239 | ||
| 240 | // Current element is a simple future | |
| 241 | template <std::size_t I> | |
| 242 | HPX_FORCEINLINE | |
| 243 | void await_next(std::true_type, std::false_type) | |
| 244 | { | |
| 245 | typedef typename util::decay_unwrap< | |
| 246 | typename util::tuple_element<I, Tuple>::type | |
| 247 | >::type future_type; | |
| 248 | ||
| 249 | typedef typename detail::future_or_shared_state_result< | |
| 250 | future_type | |
| 251 | >::type future_result_type; | |
| 252 | ||
| 253 | boost::intrusive_ptr< | |
| 254 | lcos::detail::future_data<future_result_type> | |
| 255 | > next_future_data = traits::detail::get_shared_state( | |
| 256 | util::get<I>(t_)); | |
| 257 | ||
| 258 | if (!next_future_data->is_ready()) | |
| 259 | { | |
| 260 | next_future_data->execute_deferred(); | |
| 261 | ||
| 262 | // execute_deferred might have made the future ready | |
| 263 | if (!next_future_data->is_ready()) | |
| 264 | { | |
| 265 | // Attach a continuation to this future which will | |
| 266 | // re-evaluate it and continue to the next argument | |
| 267 | // (if any). | |
| 268 | void (wait_all_frame::*f)(std::true_type, std::false_type) = | |
| 269 | &wait_all_frame::await_next<I>; | |
| 270 | ||
| 271 | boost::intrusive_ptr<wait_all_frame> this_(this); | |
| 272 | next_future_data->set_on_completed(util::deferred_call( | |
| 273 | f, std::move(this_), std::true_type(), std::false_type())); | |
| 274 | return; | |
| 275 | } | |
| 276 | } | |
| 277 | ||
| 278 | do_await<I + 1>(is_end<I + 1>()); | |
| 279 | } | |
| 280 | ||
| 281 | template <std::size_t I> | |
| 282 | HPX_FORCEINLINE | |
| 283 | void do_await(std::false_type) | |
| 284 | { | |
| 285 | typedef typename util::decay_unwrap< | |
| 286 | typename util::tuple_element<I, Tuple>::type | |
| 287 | >::type future_type; | |
| 288 | ||
| 289 | typedef typename detail::is_future_or_shared_state<future_type>::type | |
| 290 | is_future; | |
| 291 | typedef typename detail::is_future_or_shared_state_range<future_type> | |
| 292 | ::type | |
| 293 | is_range; | |
| 294 | ||
| 295 | await_next<I>(is_future(), is_range()); | |
| 296 | } | |
| 297 | ||
| 298 | public: | |
| 299 | void wait_all() | |
| 300 | { | |
| 301 | do_await<0>(is_end<0>()); | |
| 302 | ||
| 303 | // If there are still futures which are not ready, suspend and | |
| 304 | // wait. | |
| 305 | if (!this->is_ready()) | |
| 306 | this->wait(); | |
| 307 | } | |
| 308 | ||
| 309 | private: | |
| 310 | Tuple const& t_; | |
| 311 | }; | |
| 312 | } | |
| 313 | ||
| 314 | /////////////////////////////////////////////////////////////////////////// | |
| 315 | template <typename Future> | |
| 316 | void wait_all(std::vector<Future> const& values) | |
| 317 | { | |
| 318 | typedef util::tuple<std::vector<Future> const&> result_type; | |
| 319 | typedef detail::wait_all_frame<result_type> frame_type; | |
| 320 | ||
| 321 | result_type data(values); | |
| 322 | boost::intrusive_ptr<frame_type> frame(new frame_type(data)); | |
| 323 | frame->wait_all(); | |
| 324 | } | |
| 325 | ||
| 326 | template <typename Future> | |
| 327 | HPX_FORCEINLINE void wait_all(std::vector<Future>& values) | |
| 328 | { | |
| 329 | lcos::wait_all(const_cast<std::vector<Future> const&>(values)); | |
| 330 | } | |
| 331 | ||
| 332 | template <typename Future> | |
| 333 | HPX_FORCEINLINE void wait_all(std::vector<Future>&& values) | |
| 334 | { | |
| 335 | lcos::wait_all(const_cast<std::vector<Future> const&>(values)); | |
| 336 | } | |
| 337 | ||
| 338 | template <typename Iterator> | |
| 339 | typename util::always_void< | |
| 340 | typename lcos::detail::future_iterator_traits<Iterator>::type | |
| 341 | >::type | |
| 342 | wait_all(Iterator begin, Iterator end) | |
| 343 | { | |
| 344 | typedef typename lcos::detail::future_iterator_traits<Iterator>::type | |
| 345 | future_type; | |
| 346 | typedef typename traits::detail::shared_state_ptr_for<future_type>::type | |
| 347 | shared_state_ptr; | |
| 348 | typedef std::vector<shared_state_ptr> result_type; | |
| 349 | ||
| 350 | result_type values; | |
| 351 | std::transform(begin, end, std::back_inserter(values), | |
| 352 | detail::wait_get_shared_state<future_type>()); | |
| 353 | ||
| 354 | lcos::wait_all(values); | |
| 355 | } | |
| 356 | ||
| 357 | template <typename Iterator> | |
| 358 | Iterator | |
| 359 | wait_all_n(Iterator begin, std::size_t count) | |
| 360 | { | |
| 361 | typedef typename lcos::detail::future_iterator_traits<Iterator>::type | |
| 362 | future_type; | |
| 363 | typedef typename traits::detail::shared_state_ptr_for<future_type>::type | |
| 364 | shared_state_ptr; | |
| 365 | typedef std::vector<shared_state_ptr> result_type; | |
| 366 | ||
| 367 | result_type values; | |
| 368 | values.reserve(count); | |
| 369 | ||
| 370 | detail::wait_get_shared_state<future_type> func; | |
| 371 | for (std::size_t i = 0; i != count; ++i) | |
| 372 | values.push_back(func(*begin++)); | |
| 373 | ||
| 374 | lcos::wait_all(std::move(values)); | |
| 375 | ||
| 376 | return begin; | |
| 377 | } | |
| 378 | ||
| 379 | inline void wait_all() | |
| 380 | { | |
| 381 | } | |
| 382 | ||
| 383 | /////////////////////////////////////////////////////////////////////////// | |
| 384 | template <typename... Ts> | |
| 385 | void wait_all(Ts&&... ts) | |
| 386 | { | |
| 387 | typedef util::tuple< | |
| 388 | typename traits::detail::shared_state_ptr_for<Ts>::type... | |
| 389 | > result_type; | |
| 390 | typedef detail::wait_all_frame<result_type> frame_type; | |
| 391 | ||
| 392 | result_type values = | |
| 393 | result_type(traits::detail::get_shared_state(ts)...); | |
| 394 | ||
| 395 | boost::intrusive_ptr<frame_type> frame(new frame_type(values)); | |
| 396 | frame->wait_all(); | |
| 397 | } | |
| 398 | }} | |
| 399 | ||
| 400 | namespace hpx | |
| 401 | { | |
| 402 | using lcos::wait_all; | |
| 403 | using lcos::wait_all_n; | |
| 404 | } | |
| 405 | ||
| 406 | #endif // DOXYGEN | |
| 407 | #endif | |
| 408 |
Copyright (c) 2006-2012 Rogue Wave Software, Inc. All Rights Reserved.
Patents pending.