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 | #if !defined(HPX_LCOS_FUTURE_MAR_06_2012_1059AM) | |
8 | #define HPX_LCOS_FUTURE_MAR_06_2012_1059AM | |
9 | ||
10 | #include <hpx/config.hpp> | |
11 | #include <hpx/error_code.hpp> | |
12 | #include <hpx/lcos/detail/future_data.hpp> | |
13 | #include <hpx/lcos_fwd.hpp> | |
14 | #include <hpx/runtime/actions/continuation_fwd.hpp> | |
15 | #include <hpx/runtime/launch_policy.hpp> | |
16 | #include <hpx/throw_exception.hpp> | |
17 | #include <hpx/traits/acquire_shared_state.hpp> | |
18 | #include <hpx/traits/concepts.hpp> | |
19 | #include <hpx/traits/future_access.hpp> | |
20 | #include <hpx/traits/future_traits.hpp> | |
21 | #include <hpx/traits/is_callable.hpp> | |
22 | #include <hpx/traits/is_executor.hpp> | |
23 | #include <hpx/traits/is_launch_policy.hpp> | |
24 | #include <hpx/util/always_void.hpp> | |
25 | #include <hpx/util/bind.hpp> | |
26 | #include <hpx/util/decay.hpp> | |
27 | #include <hpx/util/function.hpp> | |
28 | #include <hpx/util/identity.hpp> | |
29 | #include <hpx/util/invoke.hpp> | |
30 | #include <hpx/util/lazy_conditional.hpp> | |
31 | #include <hpx/util/lazy_enable_if.hpp> | |
32 | #include <hpx/util/result_of.hpp> | |
33 | #include <hpx/util/steady_clock.hpp> | |
34 | #include <hpx/util/void_guard.hpp> | |
35 | ||
36 | #if defined(HPX_HAVE_AWAIT) | |
37 | #include <hpx/lcos/detail/future_await_traits.hpp> | |
38 | #endif | |
39 | ||
40 | #include <boost/exception_ptr.hpp> | |
41 | #include <boost/intrusive_ptr.hpp> | |
42 | ||
43 | #include <iterator> | |
44 | #include <type_traits> | |
45 | #include <utility> | |
46 | ||
47 | namespace hpx { namespace lcos { namespace detail | |
48 | { | |
49 | /////////////////////////////////////////////////////////////////////////// | |
50 | enum future_state | |
51 | { | |
52 | invalid = 0, | |
53 | has_value = 1, | |
54 | has_exception = 2 | |
55 | }; | |
56 | ||
57 | template <typename Archive, typename Future> | |
58 | typename std::enable_if< | |
59 | !std::is_void<typename hpx::traits::future_traits<Future>::type>::value | |
60 | >::type serialize_future_load(Archive& ar, Future& f) | |
61 | { | |
62 | typedef typename hpx::traits::future_traits<Future>::type value_type; | |
63 | typedef lcos::detail::future_data<value_type> shared_state; | |
64 | ||
65 | int state = future_state::invalid; | |
66 | ar >> state; | |
67 | if (state == future_state::has_value) | |
68 | { | |
69 | value_type value; | |
70 | ar >> value; | |
71 | ||
72 | boost::intrusive_ptr<shared_state> p(new shared_state()); | |
73 | p->set_value(std::move(value)); | |
74 | ||
75 | f = hpx::traits::future_access<Future>::create(std::move(p)); | |
76 | } else if (state == future_state::has_exception) { | |
77 | boost::exception_ptr exception; | |
78 | ar >> exception; | |
79 | ||
80 | boost::intrusive_ptr<shared_state> p(new shared_state()); | |
81 | p->set_exception(exception); | |
82 | ||
83 | f = hpx::traits::future_access<Future>::create(std::move(p)); | |
84 | } else if (state == future_state::invalid) { | |
85 | f = Future(); | |
86 | } else { | |
87 | HPX_ASSERT(false); | |
88 | } | |
89 | } | |
90 | ||
91 | template <typename Archive, typename Future> | |
92 | typename std::enable_if< | |
93 | std::is_void<typename hpx::traits::future_traits<Future>::type>::value | |
94 | >::type serialize_future_load(Archive& ar, Future& f) //-V659 | |
95 | { | |
96 | typedef lcos::detail::future_data<void> shared_state; | |
97 | ||
98 | int state = future_state::invalid; | |
99 | ar >> state; | |
100 | if (state == future_state::has_value) | |
101 | { | |
102 | boost::intrusive_ptr<shared_state> p(new shared_state()); | |
103 | p->set_value(hpx::util::unused); | |
104 | ||
105 | f = hpx::traits::future_access<Future>::create(std::move(p)); | |
106 | } else if (state == future_state::has_exception) { | |
107 | boost::exception_ptr exception; | |
108 | ar >> exception; | |
109 | ||
110 | boost::intrusive_ptr<shared_state> p(new shared_state()); | |
111 | p->set_exception(exception); | |
112 | ||
113 | f = hpx::traits::future_access<Future>::create(std::move(p)); | |
114 | } else if (state == future_state::invalid) { | |
115 | f = Future(); | |
116 | } else { | |
117 | HPX_ASSERT(false); | |
118 | } | |
119 | } | |
120 | ||
121 | template <typename Archive, typename Future> | |
122 | typename std::enable_if< | |
123 | !std::is_void<typename hpx::traits::future_traits<Future>::type>::value | |
124 | >::type serialize_future_save(Archive& ar, Future const& f) | |
125 | { | |
126 | typedef typename hpx::traits::future_traits<Future>::result_type value_type; | |
127 | ||
128 | int state = future_state::invalid; | |
129 | if(ar.is_preprocessing()) | |
130 | { | |
131 | if(!f.is_ready()) | |
132 | { | |
133 | typename hpx::traits::detail::shared_state_ptr_for<Future>::type state | |
134 | = hpx::traits::future_access<Future>::get_shared_state(f); | |
135 | ||
136 | state->execute_deferred(); | |
137 | ||
138 | ar.await_future(f); | |
139 | } | |
140 | else | |
141 | { | |
142 | if(f.is_ready()) | |
143 | { | |
144 | if (f.has_value()) | |
145 | { | |
146 | value_type const & value = | |
147 | *hpx::traits::future_access<Future>:: | |
148 | get_shared_state(f)->get_result(); | |
149 | ar << state << value; //-V128 | |
150 | } else if (f.has_exception()) { | |
151 | state = future_state::has_exception; | |
152 | boost::exception_ptr exception = f.get_exception_ptr(); | |
153 | ar << state << exception; | |
154 | } else { | |
155 | state = future_state::invalid; | |
156 | ar << state; | |
157 | } | |
158 | } | |
159 | } | |
160 | return; | |
161 | } | |
162 | ||
163 | #if defined(HPX_DEBUG) | |
164 | if (f.valid()) | |
165 | { | |
166 | HPX_ASSERT(f.is_ready()); | |
167 | } | |
168 | #endif | |
169 | ||
170 | if (f.has_value()) | |
171 | { | |
172 | state = future_state::has_value; | |
173 | value_type const & value = | |
174 | *hpx::traits::future_access<Future>:: | |
175 | get_shared_state(f)->get_result(); | |
176 | ar << state << value; //-V128 | |
177 | } else if (f.has_exception()) { | |
178 | state = future_state::has_exception; | |
179 | boost::exception_ptr exception = f.get_exception_ptr(); | |
180 | ar << state << exception; | |
181 | } else { | |
182 | state = future_state::invalid; | |
183 | ar << state; | |
184 | } | |
185 | } | |
186 | ||
187 | template <typename Archive, typename Future> | |
188 | typename std::enable_if< | |
189 | std::is_void<typename hpx::traits::future_traits<Future>::type>::value | |
190 | >::type serialize_future_save(Archive& ar, Future const& f) //-V659 | |
191 | { | |
192 | int state = future_state::invalid; | |
193 | if(ar.is_preprocessing()) | |
194 | { | |
195 | if(!f.is_ready()) | |
196 | { | |
197 | typename | |
198 | hpx::traits::detail::shared_state_ptr_for<Future>::type state | |
199 | = hpx::traits::future_access<Future>::get_shared_state(f); | |
200 | ||
201 | state->execute_deferred(); | |
202 | ||
203 | ar.await_future(f); | |
204 | } | |
205 | else | |
206 | { | |
207 | if (f.has_value()) | |
208 | { | |
209 | state = future_state::has_value; | |
210 | ar << state; | |
211 | } | |
212 | else if (f.has_exception()) | |
213 | { | |
214 | state = future_state::has_exception; | |
215 | boost::exception_ptr exception = f.get_exception_ptr(); | |
216 | ar << state << exception; | |
217 | } | |
218 | else | |
219 | { | |
220 | state = future_state::invalid; | |
221 | ar << state; | |
222 | } | |
223 | } | |
224 | return; | |
225 | } | |
226 | ||
227 | #if defined(HPX_DEBUG) | |
228 | if (f.valid()) | |
229 | { | |
230 | HPX_ASSERT(f.is_ready()); | |
231 | } | |
232 | #endif | |
233 | ||
234 | if (f.has_value()) | |
235 | { | |
236 | state = future_state::has_value; | |
237 | ar << state; | |
238 | } | |
239 | else if (f.has_exception()) | |
240 | { | |
241 | state = future_state::has_exception; | |
242 | boost::exception_ptr exception = f.get_exception_ptr(); | |
243 | ar << state << exception; | |
244 | } | |
245 | else | |
246 | { | |
247 | state = future_state::invalid; | |
248 | ar << state; | |
249 | } | |
250 | } | |
251 | ||
252 | template <typename Future> | |
253 | void serialize_future(serialization::input_archive& ar, Future& f, unsigned) | |
254 | { | |
255 | serialize_future_load(ar, f); | |
256 | } | |
257 | ||
258 | template <typename Future> | |
259 | void serialize_future(serialization::output_archive& ar, Future& f, unsigned) | |
260 | { | |
261 | serialize_future_save(ar, f); | |
262 | } | |
263 | ||
264 | /////////////////////////////////////////////////////////////////////////// | |
265 | template <typename Future, typename F, typename Enable = void> | |
266 | struct future_then_result | |
267 | { | |
268 | typedef struct continuation_not_callable | |
269 | { | |
270 | void error(Future future, F& f) | |
271 | { | |
272 | f(future); | |
273 | } | |
274 | ||
275 | ~continuation_not_callable() | |
276 | { | |
277 | error(std::declval<Future>(), std::declval<F&>()); | |
278 | } | |
279 | } type; | |
280 | }; | |
281 | ||
282 | template <typename Future, typename F> | |
283 | struct future_then_result< | |
284 | Future, F | |
285 | , typename hpx::util::always_void< | |
286 | typename hpx::util::result_of<F(Future)>::type | |
287 | >::type | |
288 | > | |
289 | { | |
290 | typedef typename hpx::util::result_of<F(Future)>::type cont_result; | |
291 | ||
292 | typedef typename util::lazy_conditional< | |
293 | hpx::traits::detail::is_unique_future<cont_result>::value | |
294 | , hpx::traits::future_traits<cont_result> | |
295 | , hpx::util::identity<cont_result> | |
296 | >::type result_type; | |
297 | ||
298 | typedef lcos::future<result_type> type; | |
299 | }; | |
300 | ||
301 | /////////////////////////////////////////////////////////////////////////// | |
302 | template <typename Future, typename Enable = void> | |
303 | struct future_unwrap_result | |
304 | {}; | |
305 | ||
306 | template <template <typename> class Future, typename R> | |
307 | struct future_unwrap_result<Future<Future<R> > > | |
308 | { | |
309 | typedef R result_type; | |
310 | ||
311 | typedef Future<result_type> type; | |
312 | }; | |
313 | ||
314 | template <typename R> | |
315 | struct future_unwrap_result<future<shared_future<R> > > | |
316 | { | |
317 | typedef R result_type; | |
318 | ||
319 | typedef future<result_type> type; | |
320 | }; | |
321 | ||
322 | /////////////////////////////////////////////////////////////////////////// | |
323 | template <typename Iter, typename Enable = void> | |
324 | struct future_iterator_traits | |
325 | {}; | |
326 | ||
327 | template <typename Iterator> | |
328 | struct future_iterator_traits<Iterator, | |
329 | typename hpx::util::always_void< | |
330 | #if defined(HPX_MSVC) && HPX_MSVC <= 1800 // MSVC12 needs special help | |
331 | typename Iterator::iterator_category | |
332 | #else | |
333 | typename std::iterator_traits<Iterator>::value_type | |
334 | #endif | |
335 | >::type> | |
336 | { | |
337 | typedef | |
338 | typename std::iterator_traits<Iterator>::value_type | |
339 | type; | |
340 | ||
341 | typedef hpx::traits::future_traits<type> traits_type; | |
342 | }; | |
343 | ||
344 | /////////////////////////////////////////////////////////////////////////// | |
345 | template <typename T> | |
346 | struct future_value | |
347 | : future_data_result<T> | |
348 | { | |
349 | template <typename U> | |
350 | HPX_FORCEINLINE static | |
351 | U get(U && u) | |
352 | { | |
353 | return std::forward<U>(u); | |
354 | } | |
355 | ||
356 | static T get_default() | |
357 | { | |
358 | return T(); | |
359 | } | |
360 | }; | |
361 | ||
362 | template <typename T> | |
363 | struct future_value<T&> | |
364 | : future_data_result<T&> | |
365 | { | |
366 | HPX_FORCEINLINE static | |
367 | T& get(T* u) | |
368 | { | |
369 | return *u; | |
370 | } | |
371 | ||
372 | static T& get_default() | |
373 | { | |
374 | static T default_; | |
375 | return default_; | |
376 | } | |
377 | }; | |
378 | ||
379 | template <> | |
380 | struct future_value<void> | |
381 | : future_data_result<void> | |
382 | { | |
383 | HPX_FORCEINLINE static | |
384 | void get(hpx::util::unused_type) | |
385 | {} | |
386 | ||
387 | static void get_default() | |
388 | {} | |
389 | }; | |
390 | ||
391 | /////////////////////////////////////////////////////////////////////////// | |
392 | template <typename Future, typename F, typename ContResult> | |
393 | class continuation; | |
394 | ||
395 | template <typename ContResult> | |
396 | struct continuation_result; | |
397 | ||
398 | template <typename ContResult, typename Future, typename F> | |
399 | inline typename hpx::traits::detail::shared_state_ptr< | |
400 | typename continuation_result<ContResult>::type | |
401 | >::type | |
402 | make_continuation(Future const& future, launch policy, | |
403 | F && f); | |
404 | ||
405 | template <typename ContResult, typename Future, typename F> | |
406 | inline typename hpx::traits::detail::shared_state_ptr< | |
407 | typename continuation_result<ContResult>::type | |
408 | >::type | |
409 | make_continuation(Future const& future, threads::executor& sched, | |
410 | F && f); | |
411 | template <typename ContResult, typename Future, typename Executor, | |
412 | typename F> | |
413 | inline typename hpx::traits::detail::shared_state_ptr< | |
414 | typename continuation_result<ContResult>::type | |
415 | >::type | |
416 | make_continuation_exec(Future const& future, Executor& exec, F && f); | |
417 | ||
418 | /////////////////////////////////////////////////////////////////////////// | |
419 | template <typename Future> | |
420 | typename hpx::traits::detail::shared_state_ptr< | |
421 | typename future_unwrap_result<Future>::result_type>::type | |
422 | unwrap(Future&& future, error_code& ec = throws); | |
423 | ||
424 | /////////////////////////////////////////////////////////////////////////// | |
425 | class void_continuation; | |
426 | ||
427 | template <typename Future> | |
428 | inline typename hpx::traits::detail::shared_state_ptr<void>::type | |
429 | make_void_continuation(Future& future); | |
430 | ||
431 | /////////////////////////////////////////////////////////////////////////// | |
432 | template <typename Derived, typename R> | |
433 | class future_base | |
434 | { | |
435 | public: | |
436 | typedef R result_type; | |
437 | typedef future_data<R> shared_state_type; | |
438 | ||
439 | public: | |
440 | future_base() HPX_NOEXCEPT | |
441 | : shared_state_() | |
442 | {} | |
443 | ||
444 | explicit future_base( | |
445 | boost::intrusive_ptr<shared_state_type> const& p | |
446 | ) : shared_state_(p) | |
447 | {} | |
448 | ||
449 | explicit future_base( | |
450 | boost::intrusive_ptr<shared_state_type> && p | |
451 | ) : shared_state_(std::move(p)) | |
452 | {} | |
453 | ||
454 | future_base(future_base const& other) | |
455 | : shared_state_(other.shared_state_) | |
456 | {} | |
457 | ||
458 | future_base(future_base && other) HPX_NOEXCEPT | |
459 | : shared_state_(std::move(other.shared_state_)) | |
460 | { | |
461 | other.shared_state_ = nullptr; | |
462 | } | |
463 | ||
464 | void swap(future_base& other) | |
465 | { | |
466 | shared_state_.swap(other.shared_state_); | |
467 | } | |
468 | ||
469 | future_base& operator=(future_base const & other) | |
470 | { | |
471 | if (this != &other) | |
472 | { | |
473 | shared_state_ = other.shared_state_; | |
474 | } | |
475 | return *this; | |
476 | } | |
477 | ||
478 | future_base& operator=(future_base && other) HPX_NOEXCEPT | |
479 | { | |
480 | if (this != &other) | |
481 | { | |
482 | shared_state_ = std::move(other.shared_state_); | |
483 | other.shared_state_ = nullptr; | |
484 | } | |
485 | return *this; | |
486 | } | |
487 | ||
488 | // Returns: true only if *this refers to a shared state. | |
489 | bool valid() const HPX_NOEXCEPT | |
490 | { | |
491 | return shared_state_ != nullptr; | |
492 | } | |
493 | ||
494 | // Returns: true if the shared state is ready, false if it isn't. | |
495 | bool is_ready() const HPX_NOEXCEPT | |
496 | { | |
497 | return shared_state_ != nullptr && shared_state_->is_ready(); | |
498 | } | |
499 | ||
500 | // Returns: true if the shared state is ready and stores a value, | |
501 | // false if it isn't. | |
502 | bool has_value() const HPX_NOEXCEPT | |
503 | { | |
504 | return shared_state_ != nullptr && shared_state_->has_value(); | |
505 | } | |
506 | ||
507 | // Returns: true if the shared state is ready and stores an exception, | |
508 | // false if it isn't. | |
509 | bool has_exception() const HPX_NOEXCEPT | |
510 | { | |
511 | return shared_state_ != nullptr && shared_state_->has_exception(); | |
512 | } | |
513 | ||
514 | // Effects: | |
515 | // - Blocks until the future is ready. | |
516 | // Returns: The stored exception_ptr if has_exception(), a null | |
517 | // pointer otherwise. | |
518 | boost::exception_ptr get_exception_ptr() const | |
519 | { | |
520 | if (!shared_state_) | |
521 | { | |
522 | HPX_THROW_EXCEPTION(no_state, | |
523 | "future_base<R>::get_exception_ptr", | |
524 | "this future has no valid shared state"); | |
525 | } | |
526 | ||
527 | error_code ec(lightweight); | |
528 | this->shared_state_->get_result(ec); | |
529 | if (!ec) return boost::exception_ptr(); | |
530 | return hpx::detail::access_exception(ec); | |
531 | } | |
532 | ||
533 | // Notes: The three functions differ only by input parameters. | |
534 | // - The first only takes a callable object which accepts a future | |
535 | // object as a parameter. | |
536 | // - The second function takes an executor as the first parameter | |
537 | // and a callable object as the second parameter. | |
538 | // - The third function takes a launch policy as the first parameter | |
539 | // and a callable object as the second parameter. | |
540 | // In cases where 'decltype(func(*this))' is future<R>, the | |
541 | // resulting type is future<R> instead of future<future<R>>. | |
542 | // Effects: | |
543 | // - The continuation is called when the object's shared state is | |
544 | // ready (has a value or exception stored). | |
545 | // - The continuation launches according to the specified launch | |
546 | // policy or executor. | |
547 | // - When the executor or launch policy is not provided the | |
548 | // continuation inherits the parent's launch policy or executor. | |
549 | // - If the parent was created with std::promise or with a | |
550 | // packaged_task (has no associated launch policy), the | |
551 | // continuation behaves the same as the third overload with a | |
552 | // policy argument of launch::async | launch::deferred and the | |
553 | // same argument for func. | |
554 | // - If the parent has a policy of launch::deferred and the | |
555 | // continuation does not have a specified launch policy or | |
556 | // scheduler, then the parent is filled by immediately calling | |
557 | // .wait(), and the policy of the antecedent is launch::deferred | |
558 | // Returns: An object of type future<decltype(func(*this))> that | |
559 | // refers to the shared state created by the continuation. | |
560 | // Postcondition: | |
561 | // - The future object is moved to the parameter of the continuation | |
562 | // function. | |
563 | // - valid() == false on original future object immediately after it | |
564 | // returns. | |
565 | template <typename F> | |
566 | typename util::lazy_enable_if< | |
567 | !hpx::traits::is_launch_policy<F>::value && | |
568 | !hpx::traits::is_threads_executor<F>::value && | |
569 | !hpx::traits::is_executor<F>::value | |
570 | , future_then_result<Derived, F> | |
571 | >::type | |
572 | then(F && f, error_code& ec = throws) const | |
573 | { | |
574 | return then(launch::all, std::forward<F>(f), ec); | |
575 | } | |
576 | ||
577 | template <typename F> | |
578 | typename future_then_result<Derived, F>::type | |
579 | then(launch policy, F && f, error_code& ec = throws) const | |
580 | { | |
581 | typedef | |
582 | typename future_then_result<Derived, F>::result_type | |
583 | result_type; | |
584 | ||
585 | if (!shared_state_) | |
586 | { | |
587 | HPX_THROWS_IF(ec, no_state, | |
588 | "future_base<R>::then", | |
589 | "this future has no valid shared state"); | |
590 | return future<result_type>(); | |
591 | } | |
592 | ||
593 | typedef | |
594 | typename hpx::util::result_of<F(Derived)>::type | |
595 | continuation_result_type; | |
596 | typedef | |
597 | typename hpx::traits::detail::shared_state_ptr<result_type>::type | |
598 | shared_state_ptr; | |
599 | ||
600 | shared_state_ptr p = | |
601 | detail::make_continuation<continuation_result_type>( | |
602 | *static_cast<Derived const*>(this), policy, std::forward<F>(f)); | |
603 | return hpx::traits::future_access<future<result_type> >::create( | |
604 | std::move(p)); | |
605 | } | |
606 | ||
607 | template <typename F> | |
608 | typename future_then_result<Derived, F>::type | |
609 | then(threads::executor& sched, F && f, error_code& ec = throws) const | |
610 | { | |
611 | typedef | |
612 | typename future_then_result<Derived, F>::result_type | |
613 | result_type; | |
614 | ||
615 | if (!shared_state_) | |
616 | { | |
617 | HPX_THROWS_IF(ec, no_state, | |
618 | "future_base<R>::then", | |
619 | "this future has no valid shared state"); | |
620 | return future<result_type>(); | |
621 | } | |
622 | ||
623 | typedef | |
624 | typename hpx::util::result_of<F(Derived)>::type | |
625 | continuation_result_type; | |
626 | typedef | |
627 | typename hpx::traits::detail::shared_state_ptr<result_type>::type | |
628 | shared_state_ptr; | |
629 | ||
630 | shared_state_ptr p = | |
631 | detail::make_continuation<continuation_result_type>( | |
632 | *static_cast<Derived const*>(this), sched, std::forward<F>(f)); | |
633 | return hpx::traits::future_access<future<result_type> >::create( | |
634 | std::move(p)); | |
635 | } | |
636 | ||
637 | template <typename Executor, typename F> | |
638 | typename util::lazy_enable_if< | |
639 | hpx::traits::is_executor<Executor>::value | |
640 | , future_then_result<Derived, F> | |
641 | >::type | |
642 | then(Executor& exec, F && f, error_code& ec = throws) const | |
643 | { | |
644 | typedef | |
645 | typename future_then_result<Derived, F>::result_type | |
646 | result_type; | |
647 | ||
648 | if (!shared_state_) | |
649 | { | |
650 | HPX_THROWS_IF(ec, no_state, | |
651 | "future_base<R>::then", | |
652 | "this future has no valid shared state"); | |
653 | return future<result_type>(); | |
654 | } | |
655 | ||
656 | typedef | |
657 | typename hpx::util::result_of<F(Derived)>::type | |
658 | continuation_result_type; | |
659 | typedef | |
660 | typename hpx::traits::detail::shared_state_ptr<result_type>::type | |
661 | shared_state_ptr; | |
662 | ||
663 | shared_state_ptr p = | |
664 | detail::make_continuation_exec<continuation_result_type>( | |
665 | *static_cast<Derived const*>(this), exec, | |
666 | std::forward<F>(f)); | |
667 | return hpx::traits::future_access<future<result_type> >:: | |
668 | create(std::move(p)); | |
669 | } | |
670 | ||
671 | // Effects: blocks until the shared state is ready. | |
672 | void wait(error_code& ec = throws) const | |
673 | { | |
674 | if (!shared_state_) | |
675 | { | |
676 | HPX_THROWS_IF(ec, no_state, | |
677 | "future_base<R>::wait", | |
678 | "this future has no valid shared state"); | |
679 | return; | |
680 | } | |
681 | shared_state_->wait(ec); | |
682 | } | |
683 | ||
684 | // Effects: none if the shared state contains a deferred function | |
685 | // (30.6.8), otherwise blocks until the shared state is ready | |
686 | // or until the absolute timeout (30.2.4) specified by | |
687 | // abs_time has expired. | |
688 | // Returns: | |
689 | // - future_status::deferred if the shared state contains a deferred | |
690 | // function. | |
691 | // - future_status::ready if the shared state is ready. | |
692 | // - future_status::timeout if the function is returning because the | |
693 | // absolute timeout (30.2.4) specified by abs_time has expired. | |
694 | // Throws: timeout-related exceptions (30.2.4). | |
695 | future_status | |
696 | wait_until(hpx::util::steady_time_point const& abs_time, | |
697 | error_code& ec = throws) const | |
698 | { | |
699 | if (!shared_state_) | |
700 | { | |
701 | HPX_THROWS_IF(ec, no_state, | |
702 | "future_base<R>::wait_until", | |
703 | "this future has no valid shared state"); | |
704 | return future_status::uninitialized; | |
705 | } | |
706 | return shared_state_->wait_until(abs_time.value(), ec); | |
707 | } | |
708 | ||
709 | // Effects: none if the shared state contains a deferred function | |
710 | // (30.6.8), otherwise blocks until the shared state is ready | |
711 | // or until the relative timeout (30.2.4) specified by | |
712 | // rel_time has expired. | |
713 | // Returns: | |
714 | // - future_status::deferred if the shared state contains a deferred | |
715 | // function. | |
716 | // - future_status::ready if the shared state is ready. | |
717 | // - future_status::timeout if the function is returning because the | |
718 | // relative timeout (30.2.4) specified by rel_time has expired. | |
719 | // Throws: timeout-related exceptions (30.2.4). | |
720 | future_status | |
721 | wait_for(hpx::util::steady_duration const& rel_time, | |
722 | error_code& ec = throws) const | |
723 | { | |
724 | return wait_until(rel_time.from_now(), ec); | |
725 | } | |
726 | ||
727 | #if defined(HPX_HAVE_AWAIT) | |
728 | bool await_ready() const | |
729 | { | |
730 | return detail::await_ready(*static_cast<Derived const*>(this)); | |
731 | } | |
732 | ||
733 | template <typename Promise> | |
734 | void await_suspend(std::experimental::coroutine_handle<Promise> rh) | |
735 | { | |
736 | detail::await_suspend(*static_cast<Derived*>(this), rh); | |
737 | } | |
738 | ||
739 | R await_resume() | |
740 | { | |
741 | return detail::await_resume(*static_cast<Derived*>(this)); | |
742 | } | |
743 | #endif | |
744 | ||
745 | protected: | |
746 | boost::intrusive_ptr<shared_state_type> shared_state_; | |
747 | }; | |
748 | }}} | |
749 | ||
750 | namespace hpx { namespace lcos | |
751 | { | |
752 | /////////////////////////////////////////////////////////////////////////// | |
753 | template <typename R> | |
754 | class future : public detail::future_base<future<R>, R> | |
755 | { | |
756 | HPX_MOVABLE_ONLY(future); | |
757 | ||
758 | typedef detail::future_base<future<R>, R> base_type; | |
759 | ||
760 | public: | |
761 | typedef R result_type; | |
762 | typedef typename base_type::shared_state_type shared_state_type; | |
763 | ||
764 | private: | |
765 | struct invalidate | |
766 | { | |
767 | explicit invalidate(future& f) | |
768 | : f_(f) | |
769 | {} | |
770 | ||
771 | ~invalidate() | |
772 | { | |
773 | f_.shared_state_.reset(); | |
774 | } | |
775 | ||
776 | future& f_; | |
777 | }; | |
778 | ||
779 | private: | |
780 | template <typename Future> | |
781 | friend struct hpx::traits::future_access; | |
782 | ||
783 | template <typename Future, typename Enable> | |
784 | friend struct hpx::traits::detail::future_access_customization_point; | |
785 | ||
786 | // Effects: constructs a future object from an shared state | |
787 | explicit future( | |
788 | boost::intrusive_ptr<shared_state_type> const& state | |
789 | ) : base_type(state) | |
790 | {} | |
791 | ||
792 | explicit future( | |
793 | boost::intrusive_ptr<shared_state_type> && state | |
794 | ) : base_type(std::move(state)) | |
795 | {} | |
796 | ||
797 | template <typename SharedState> | |
798 | explicit future(boost::intrusive_ptr<SharedState> const& state) | |
799 | : base_type(boost::static_pointer_cast<shared_state_type>(state)) | |
800 | {} | |
801 | ||
802 | public: | |
803 | // Effects: constructs an empty future object that does not refer to | |
804 | // an shared state. | |
805 | // Postcondition: valid() == false. | |
806 | future() HPX_NOEXCEPT | |
807 | : base_type() | |
808 | {} | |
809 | ||
810 | // Effects: move constructs a future object that refers to the shared | |
811 | // state that was originally referred to by other (if any). | |
812 | // Postconditions: | |
813 | // - valid() returns the same value as other.valid() prior to the | |
814 | // constructor invocation. | |
815 | // - other.valid() == false. | |
816 | future(future && other) HPX_NOEXCEPT | |
817 | : base_type(std::move(other)) | |
818 | {} | |
819 | ||
820 | // Effects: constructs a future object by moving the instance referred | |
821 | // to by rhs and unwrapping the inner future. | |
822 | // Postconditions: | |
823 | // - valid() returns the same value as other.valid() prior to the | |
824 | // constructor invocation. | |
825 | // - other.valid() == false. | |
826 | future(future<future> && other) HPX_NOEXCEPT | |
827 | : base_type(other.valid() ? detail::unwrap(std::move(other)) : nullptr) | |
828 | {} | |
829 | ||
830 | // Effects: constructs a future object by moving the instance referred | |
831 | // to by rhs and unwrapping the inner future. | |
832 | // Postconditions: | |
833 | // - valid() returns the same value as other.valid() prior to the | |
834 | // constructor invocation. | |
835 | // - other.valid() == false. | |
836 | future(future<shared_future<R> > && other) HPX_NOEXCEPT | |
837 | : base_type(other.valid() ? detail::unwrap(std::move(other)) : nullptr) | |
838 | {} | |
839 | ||
840 | // Effects: constructs a future<void> object that will be ready when | |
841 | // the given future is ready | |
842 | // Postconditions: | |
843 | // - valid() returns the same value as other.valid() prior to the | |
844 | // constructor invocation. | |
845 | // - other.valid() == false. | |
846 | template <typename T> | |
847 | future(future<T>&& other, | |
848 | typename std::enable_if<std::is_void<R>::value, T>::type* = nullptr | |
849 | ) : base_type(other.valid() ? detail::make_void_continuation(other) : nullptr) | |
850 | { | |
851 | other = future<T>(); | |
852 | } | |
853 | ||
854 | // Effects: | |
855 | // - releases any shared state (30.6.4); | |
856 | // - destroys *this. | |
857 | ~future() | |
858 | {} | |
859 | ||
860 | // Effects: | |
861 | // - releases any shared state (30.6.4). | |
862 | // - move assigns the contents of other to *this. | |
863 | // Postconditions: | |
864 | // - valid() returns the same value as other.valid() prior to the | |
865 | // assignment. | |
866 | // - other.valid() == false. | |
867 | future& operator=(future && other) HPX_NOEXCEPT | |
868 | { | |
869 | base_type::operator=(std::move(other)); | |
870 | return *this; | |
871 | } | |
872 | ||
873 | // Returns: shared_future<R>(std::move(*this)). | |
874 | // Postcondition: valid() == false. | |
875 | shared_future<R> share() | |
876 | { | |
877 | return shared_future<R>(std::move(*this)); | |
878 | } | |
879 | ||
880 | // Effects: wait()s until the shared state is ready, then retrieves | |
881 | // the value stored in the shared state. | |
882 | // Returns: | |
883 | // - future::get() returns the value v stored in the object's | |
884 | // shared state as std::move(v). | |
885 | // - future<R&>::get() returns the reference stored as value in the | |
886 | // object's shared state. | |
887 | // - future<void>::get() returns nothing. | |
888 | // Throws: the stored exception, if an exception was stored in the | |
889 | // shared state. | |
890 | // Postcondition: valid() == false. | |
891 | typename hpx::traits::future_traits<future>::result_type | |
892 | get() | |
893 | { | |
894 | if (!this->shared_state_) | |
895 | { | |
896 | HPX_THROW_EXCEPTION(no_state, | |
897 | "future<R>::get", | |
898 | "this future has no valid shared state"); | |
899 | } | |
900 | ||
901 | invalidate on_exit(*this); | |
902 | ||
903 | typedef typename shared_state_type::result_type result_type; | |
904 | result_type* result = this->shared_state_->get_result(); | |
905 | ||
906 | // no error has been reported, return the result | |
907 | return detail::future_value<R>::get(std::move(*result)); | |
908 | } | |
909 | ||
910 | typename hpx::traits::future_traits<future>::result_type | |
911 | get(error_code& ec) | |
912 | { | |
913 | if (!this->shared_state_) | |
914 | { | |
915 | HPX_THROWS_IF(ec, no_state, | |
916 | "future<R>::get", | |
917 | "this future has no valid shared state"); | |
918 | return detail::future_value<R>::get_default(); | |
919 | } | |
920 | ||
921 | invalidate on_exit(*this); | |
922 | ||
923 | typedef typename shared_state_type::result_type result_type; | |
924 | result_type* result = this->shared_state_->get_result(ec); | |
925 | if (ec) return detail::future_value<R>::get_default(); | |
926 | ||
927 | // no error has been reported, return the result | |
928 | return detail::future_value<R>::get(std::move(*result)); | |
929 | } | |
930 | using base_type::get_exception_ptr; | |
931 | ||
932 | using base_type::valid; | |
933 | using base_type::is_ready; | |
934 | using base_type::has_value; | |
935 | using base_type::has_exception; | |
936 | ||
937 | template <typename F> | |
938 | typename util::lazy_enable_if< | |
939 | !hpx::traits::is_launch_policy<F>::value && | |
940 | !hpx::traits::is_threads_executor<F>::value && | |
941 | !hpx::traits::is_executor<F>::value | |
942 | , detail::future_then_result<future, F> | |
943 | >::type | |
944 | then(F && f, error_code& ec = throws) | |
945 | { | |
946 | invalidate on_exit(*this); | |
947 | return base_type::then(std::forward<F>(f), ec); | |
948 | } | |
949 | ||
950 | template <typename F> | |
951 | typename detail::future_then_result<future, F>::type | |
952 | then(launch policy, F && f, error_code& ec = throws) | |
953 | { | |
954 | invalidate on_exit(*this); | |
955 | return base_type::then(policy, std::forward<F>(f), ec); | |
956 | } | |
957 | ||
958 | template <typename F> | |
959 | typename detail::future_then_result<future, F>::type | |
960 | then(threads::executor& sched, F && f, error_code& ec = throws) | |
961 | { | |
962 | invalidate on_exit(*this); | |
963 | return base_type::then(sched, std::forward<F>(f), ec); | |
964 | } | |
965 | ||
966 | template <typename Executor, typename F> | |
967 | typename util::lazy_enable_if< | |
968 | hpx::traits::is_executor<Executor>::value | |
969 | , detail::future_then_result<future, F> | |
970 | >::type | |
971 | then(Executor& exec, F && f, error_code& ec = throws) | |
972 | { | |
973 | invalidate on_exit(*this); | |
974 | return base_type::then(exec, std::forward<F>(f), ec); | |
975 | } | |
976 | ||
977 | using base_type::wait; | |
978 | using base_type::wait_for; | |
979 | using base_type::wait_until; | |
980 | }; | |
981 | ||
982 | /////////////////////////////////////////////////////////////////////////// | |
983 | namespace detail | |
984 | { | |
985 | template <typename T, typename Future> | |
986 | typename std::enable_if< | |
987 | std::is_convertible<Future, hpx::future<T> >::value, | |
988 | hpx::future<T> | |
989 | >::type | |
990 | make_future_helper(Future && f) | |
991 | { | |
992 | return std::move(f); | |
993 | }; | |
994 | ||
995 | template <typename T, typename Future> | |
996 | typename std::enable_if< | |
997 | !std::is_convertible<Future, hpx::future<T> >::value, | |
998 | hpx::future<T> | |
999 | >::type | |
1000 | make_future_helper(Future && f) //-V659 | |
1001 | { | |
1002 | return f.then( | |
1003 | [](Future && f) -> T | |
1004 | { | |
1005 | return util::void_guard<T>(), f.get(); | |
1006 | }); | |
1007 | } | |
1008 | } | |
1009 | ||
1010 | // Allow to convert any future<U> into any other future<R> based on an | |
1011 | // existing conversion path U --> R. | |
1012 | template <typename R, typename U> | |
1013 | hpx::future<R> | |
1014 | make_future(hpx::future<U> && f) | |
1015 | { | |
1016 | static_assert( | |
1017 | std::is_convertible<R, U>::value || std::is_void<R>::value, | |
1018 | "the argument type must be implicitly convertible to the requested " | |
1019 | "result type"); | |
1020 | ||
1021 | return detail::make_future_helper<R>(std::move(f)); | |
1022 | } | |
1023 | ||
1024 | namespace detail | |
1025 | { | |
1026 | template <typename T, typename Future, typename Conv> | |
1027 | typename std::enable_if< | |
1028 | std::is_convertible<Future, hpx::future<T> >::value, | |
1029 | hpx::future<T> | |
1030 | >::type | |
1031 | convert_future_helper(Future && f, Conv && conv) | |
1032 | { | |
1033 | return std::move(f); | |
1034 | }; | |
1035 | ||
1036 | template <typename T, typename Future, typename Conv> | |
1037 | typename std::enable_if< | |
1038 | !std::is_convertible<Future, hpx::future<T> >::value, | |
1039 | hpx::future<T> | |
1040 | >::type | |
1041 | convert_future_helper(Future && f, Conv && conv) //-V659 | |
1042 | { | |
1043 | return f.then( | |
1044 | [conv](Future && f) -> T | |
1045 | { | |
1046 | return hpx::util::invoke(conv, f.get()); | |
1047 | }); | |
1048 | } | |
1049 | } | |
1050 | ||
1051 | // Allow to convert any future<U> into any other future<R> based on a given | |
1052 | // conversion function: R conv(U). | |
1053 | template <typename R, typename U, typename Conv> | |
1054 | hpx::future<R> | |
1055 | make_future(hpx::future<U> && f, Conv && conv) | |
1056 | { | |
1057 | return detail::convert_future_helper<R>( | |
1058 | std::move(f), std::forward<Conv>(conv)); | |
1059 | } | |
1060 | }} | |
1061 | ||
1062 | namespace hpx { namespace lcos | |
1063 | { | |
1064 | /////////////////////////////////////////////////////////////////////////// | |
1065 | template <typename R> | |
1066 | class shared_future : public detail::future_base<shared_future<R>, R> | |
1067 | { | |
1068 | typedef detail::future_base<shared_future<R>, R> base_type; | |
1069 | ||
1070 | public: | |
1071 | typedef R result_type; | |
1072 | typedef typename base_type::shared_state_type shared_state_type; | |
1073 | ||
1074 | private: | |
1075 | template <typename Future> | |
1076 | friend struct hpx::traits::future_access; | |
1077 | ||
1078 | template <typename Future, typename Enable> | |
1079 | friend struct hpx::traits::detail::future_access_customization_point; | |
1080 | ||
1081 | // Effects: constructs a future object from an shared state | |
1082 | explicit shared_future( | |
1083 | boost::intrusive_ptr<shared_state_type> const& state | |
1084 | ) : base_type(state) | |
1085 | {} | |
1086 | ||
1087 | explicit shared_future( | |
1088 | boost::intrusive_ptr<shared_state_type> && state | |
1089 | ) : base_type(std::move(state)) | |
1090 | {} | |
1091 | ||
1092 | template <typename SharedState> | |
1093 | explicit shared_future(boost::intrusive_ptr<SharedState> const& state) | |
1094 | : base_type(boost::static_pointer_cast<shared_state_type>(state)) | |
1095 | {} | |
1096 | ||
1097 | public: | |
1098 | // Effects: constructs an empty future object that does not refer to | |
1099 | // an shared state. | |
1100 | // Postcondition: valid() == false. | |
1101 | shared_future() HPX_NOEXCEPT | |
1102 | : base_type() | |
1103 | {} | |
1104 | ||
1105 | // Effects: constructs a shared_future object that refers to the same | |
1106 | // shared state as other (if any). | |
1107 | // Postcondition: valid() returns the same value as other.valid(). | |
1108 | shared_future(shared_future const& other) | |
1109 | : base_type(other) | |
1110 | {} | |
1111 | ||
1112 | // Effects: move constructs a future object that refers to the shared | |
1113 | // state that was originally referred to by other (if any). | |
1114 | // Postconditions: | |
1115 | // - valid() returns the same value as other.valid() prior to the | |
1116 | // constructor invocation. | |
1117 | // - other.valid() == false. | |
1118 | shared_future(shared_future && other) HPX_NOEXCEPT | |
1119 | : base_type(std::move(other)) | |
1120 | {} | |
1121 | ||
1122 | shared_future(future<R> && other) HPX_NOEXCEPT | |
1123 | : base_type(hpx::traits::detail::get_shared_state(other)) | |
1124 | { | |
1125 | other = future<R>(); | |
1126 | } | |
1127 | ||
1128 | // Effects: constructs a shared_future object by moving the instance | |
1129 | // referred to by rhs and unwrapping the inner future. | |
1130 | // Postconditions: | |
1131 | // - valid() returns the same value as other.valid() prior to the | |
1132 | // constructor invocation. | |
1133 | // - other.valid() == false. | |
1134 | shared_future(future<shared_future> && other) HPX_NOEXCEPT | |
1135 | : base_type(other.valid() ? detail::unwrap(other.share()) : nullptr) | |
1136 | {} | |
1137 | ||
1138 | // Effects: constructs a future<void> object that will be ready when | |
1139 | // the given future is ready | |
1140 | // Postconditions: | |
1141 | // - valid() returns the same value as other.valid() prior to the | |
1142 | // constructor invocation. | |
1143 | template <typename T> | |
1144 | shared_future(shared_future<T> const& other, | |
1145 | typename std::enable_if<std::is_void<R>::value, T>::type* = nullptr | |
1146 | ) : base_type(other.valid() ? detail::make_void_continuation(other) : nullptr) | |
1147 | {} | |
1148 | ||
1149 | // Effects: | |
1150 | // - releases any shared state (30.6.4); | |
1151 | // - destroys *this. | |
1152 | ~shared_future() | |
1153 | {} | |
1154 | ||
1155 | // Effects: | |
1156 | // - releases any shared state (30.6.4). | |
1157 | // - assigns the contents of other to *this. As a result, *this | |
1158 | // refers to the same shared state as other (if any). | |
1159 | // Postconditions: | |
1160 | // - valid() == other.valid(). | |
1161 | shared_future& operator=(shared_future const & other) | |
1162 | { | |
1163 | base_type::operator=(other); | |
1164 | return *this; | |
1165 | } | |
1166 | ||
1167 | // Effects: | |
1168 | // - releases any shared state (30.6.4). | |
1169 | // - move assigns the contents of other to *this. | |
1170 | // Postconditions: | |
1171 | // - valid() returns the same value as other.valid() prior to the | |
1172 | // assignment. | |
1173 | // - other.valid() == false. | |
1174 | shared_future& operator=(shared_future && other) HPX_NOEXCEPT | |
1175 | { | |
1176 | base_type::operator=(std::move(other)); | |
1177 | return *this; | |
1178 | } | |
1179 | ||
1180 | // Effects: wait()s until the shared state is ready, then retrieves | |
1181 | // the value stored in the shared state. | |
1182 | // Returns: | |
1183 | // - shared_future::get() returns a const reference to the value | |
1184 | // stored in the object's shared state. | |
1185 | // - shared_future<R&>::get() returns the reference stored as value | |
1186 | // in the object's shared state. | |
1187 | // - shared_future<void>::get() returns nothing. | |
1188 | // Throws: the stored exception, if an exception was stored in the | |
1189 | // shared state. | |
1190 | // Postcondition: valid() == false. | |
1191 | typename hpx::traits::future_traits<shared_future>::result_type | |
1192 | get() const //-V659 | |
1193 | { | |
1194 | if (!this->shared_state_) | |
1195 | { | |
1196 | HPX_THROW_EXCEPTION(no_state, | |
1197 | "shared_future<R>::get", | |
1198 | "this future has no valid shared state"); | |
1199 | } | |
1200 | ||
1201 | typedef typename shared_state_type::result_type result_type; | |
1202 | result_type* result = this->shared_state_->get_result(); | |
1203 | ||
1204 | // no error has been reported, return the result | |
1205 | return detail::future_value<R>::get(*result); | |
1206 | } | |
1207 | typename hpx::traits::future_traits<shared_future>::result_type | |
1208 | get(error_code& ec) const //-V659 | |
1209 | { | |
1210 | typedef typename shared_state_type::result_type result_type; | |
1211 | if (!this->shared_state_) | |
1212 | { | |
1213 | HPX_THROWS_IF(ec, no_state, | |
1214 | "shared_future<R>::get", | |
1215 | "this future has no valid shared state"); | |
1216 | static result_type res(detail::future_value<R>::get_default()); | |
1217 | return res; | |
1218 | } | |
1219 | ||
1220 | result_type* result = this->shared_state_->get_result(ec); | |
1221 | if (ec) | |
1222 | { | |
1223 | static result_type res(detail::future_value<R>::get_default()); | |
1224 | return res; | |
1225 | } | |
1226 | ||
1227 | // no error has been reported, return the result | |
1228 | return detail::future_value<R>::get(*result); | |
1229 | } | |
1230 | using base_type::get_exception_ptr; | |
1231 | ||
1232 | using base_type::valid; | |
1233 | using base_type::is_ready; | |
1234 | using base_type::has_value; | |
1235 | using base_type::has_exception; | |
1236 | ||
1237 | using base_type::then; | |
1238 | ||
1239 | using base_type::wait; | |
1240 | using base_type::wait_for; | |
1241 | using base_type::wait_until; | |
1242 | }; | |
1243 | ||
1244 | /////////////////////////////////////////////////////////////////////////// | |
1245 | // Allow to convert any shared_future<U> into any other future<R> based on | |
1246 | // an existing conversion path U --> R. | |
1247 | template <typename R, typename U> | |
1248 | hpx::future<R> | |
1249 | make_future(hpx::shared_future<U> f) | |
1250 | { | |
1251 | static_assert( | |
1252 | std::is_convertible<R, U>::value || std::is_void<R>::value, | |
1253 | "the argument type must be implicitly convertible to the requested " | |
1254 | "result type"); | |
1255 | ||
1256 | return detail::make_future_helper<R>(std::move(f)); | |
1257 | } | |
1258 | ||
1259 | // Allow to convert any future<U> into any other future<R> based on a given | |
1260 | // conversion function: R conv(U). | |
1261 | template <typename R, typename U, typename Conv> | |
1262 | hpx::future<R> | |
1263 | make_future(hpx::shared_future<U> const& f, Conv && conv) | |
1264 | { | |
1265 | static_assert( | |
1266 | hpx::traits::is_callable<Conv(U), R>::value, | |
1267 | "the argument type must be convertible to the requested " | |
1268 | "result type by using the supplied conversion function"); | |
1269 | ||
1270 | return f.then( | |
1271 | [conv](hpx::shared_future<U> const& f) | |
1272 | { | |
1273 | return hpx::util::invoke(conv, f.get()); | |
1274 | }); | |
1275 | } | |
1276 | }} | |
1277 | ||
1278 | namespace hpx { namespace lcos | |
1279 | { | |
1280 | /////////////////////////////////////////////////////////////////////////// | |
1281 | // extension: create a pre-initialized future object | |
1282 | template <typename Result> | |
1283 | future<typename hpx::util::decay_unwrap<Result>::type> | |
1284 | make_ready_future(Result && init) | |
1285 | { | |
1286 | typedef typename hpx::util::decay_unwrap<Result>::type result_type; | |
1287 | typedef lcos::detail::future_data<result_type> shared_state; | |
1288 | ||
1289 | boost::intrusive_ptr<shared_state> p(new shared_state()); | |
1290 | p->set_value(std::forward<Result>(init)); | |
1291 | ||
1292 | return hpx::traits::future_access<future<result_type> >::create(std::move(p)); | |
1293 | } | |
1294 | ||
1295 | // extension: create a pre-initialized future object which holds the | |
1296 | // given error | |
1297 | template <typename T> | |
1298 | future<T> make_exceptional_future(boost::exception_ptr const& e) | |
1299 | { | |
1300 | typedef lcos::detail::future_data<T> shared_state; | |
1301 | ||
1302 | boost::intrusive_ptr<shared_state> p(new shared_state()); | |
1303 | p->set_exception(e); | |
1304 | ||
1305 | return hpx::traits::future_access<future<T> >::create(std::move(p)); | |
1306 | } | |
1307 | ||
1308 | template <typename T, typename E> | |
1309 | future<T> make_exceptional_future(E e) | |
1310 | { | |
1311 | try | |
1312 | { | |
1313 | boost::throw_exception(e); | |
1314 | } catch (...) { | |
1315 | return lcos::make_exceptional_future<T>(boost::current_exception()); | |
1316 | } | |
1317 | ||
1318 | return future<T>(); | |
1319 | } | |
1320 | ||
1321 | // extension: create a pre-initialized future object which gets ready at | |
1322 | // a given point in time | |
1323 | template <typename Result> | |
1324 | future<typename hpx::util::decay_unwrap<Result>::type> | |
1325 | make_ready_future_at(hpx::util::steady_time_point const& abs_time, | |
1326 | Result&& init) | |
1327 | { | |
1328 | typedef typename hpx::util::decay_unwrap<Result>::type result_type; | |
1329 | typedef lcos::detail::timed_future_data<result_type> shared_state; | |
1330 | ||
1331 | return hpx::traits::future_access<future<result_type> >::create( | |
1332 | new shared_state(abs_time.value(), std::forward<Result>(init))); | |
1333 | } | |
1334 | ||
1335 | template <typename Result> | |
1336 | future<typename hpx::util::decay_unwrap<Result>::type> | |
1337 | make_ready_future_after(hpx::util::steady_duration const& rel_time, | |
1338 | Result && init) | |
1339 | { | |
1340 | return make_ready_future_at(rel_time.from_now(), | |
1341 | std::forward<Result>(init)); | |
1342 | } | |
1343 | ||
1344 | // extension: create a pre-initialized future object | |
1345 | inline future<void> make_ready_future() | |
1346 | { | |
1347 | typedef lcos::detail::future_data<void> shared_state; | |
1348 | ||
1349 | boost::intrusive_ptr<shared_state> p(new shared_state()); | |
1350 | p->set_value(hpx::util::unused); | |
1351 | ||
1352 | return hpx::traits::future_access<future<void> >::create(std::move(p)); | |
1353 | } | |
1354 | ||
1355 | // extension: create a pre-initialized future object which gets ready at | |
1356 | // a given point in time | |
1357 | inline future<void> make_ready_future_at( | |
1358 | hpx::util::steady_time_point const& abs_time) | |
1359 | { | |
1360 | typedef lcos::detail::timed_future_data<void> shared_state; | |
1361 | ||
1362 | return hpx::traits::future_access<future<void> >::create( | |
1363 | new shared_state(abs_time.value(), hpx::util::unused)); | |
1364 | } | |
1365 | ||
1366 | inline future<void> make_ready_future_after( | |
1367 | hpx::util::steady_duration const& rel_time) | |
1368 | { | |
1369 | return make_ready_future_at(rel_time.from_now()); | |
1370 | } | |
1371 | }} | |
1372 | ||
1373 | namespace hpx { namespace serialization | |
1374 | { | |
1375 | template <typename Archive, typename T> | |
1376 | HPX_FORCEINLINE | |
1377 | void serialize(Archive& ar, ::hpx::lcos::future<T>& f, unsigned version) | |
1378 | { | |
1379 | hpx::lcos::detail::serialize_future(ar, f, version); | |
1380 | } | |
1381 | ||
1382 | template <typename Archive, typename T> | |
1383 | HPX_FORCEINLINE | |
1384 | void serialize(Archive& ar, ::hpx::lcos::shared_future<T>& f, unsigned version) | |
1385 | { | |
1386 | hpx::lcos::detail::serialize_future(ar, f, version); | |
1387 | } | |
1388 | }} | |
1389 | ||
1390 | #include <hpx/lcos/local/packaged_continuation.hpp> | |
1391 | ||
1392 | /////////////////////////////////////////////////////////////////////////////// | |
1393 | // hoist names into main namespace | |
1394 | namespace hpx | |
1395 | { | |
1396 | using lcos::make_ready_future; | |
1397 | using lcos::make_exceptional_future; | |
1398 | using lcos::make_ready_future_at; | |
1399 | using lcos::make_ready_future_after; | |
1400 | ||
1401 | using lcos::make_future; | |
1402 | } | |
1403 | ||
1404 | #define HPX_MAKE_EXCEPTIONAL_FUTURE(T, errorcode, f, msg) \ | |
1405 | hpx::make_exceptional_future<T>(HPX_GET_EXCEPTION(errorcode, f, msg)) \ | |
1406 | /**/ | |
1407 | ||
1408 | #endif | |
1409 |
Copyright (c) 2006-2012 Rogue Wave Software, Inc. All Rights Reserved.
Patents pending.