1 //  Copyright (c) 2007-2013 Hartmut Kaiser
2 //
3 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #if !defined(HPX_LCOS_LOCAL_PROMISE_MAR_01_2012_0121PM)
7 #define HPX_LCOS_LOCAL_PROMISE_MAR_01_2012_0121PM
8 
9 #include <hpx/config.hpp>
10 #include <hpx/lcos_fwd.hpp>
11 #include <hpx/lcos/detail/future_data.hpp>
12 #include <hpx/lcos/future.hpp>
13 #include <hpx/throw_exception.hpp>
14 #include <hpx/traits/future_access.hpp>
15 #include <hpx/util/allocator_deleter.hpp>
16 #include <hpx/util/unused.hpp>
17 
18 #include <boost/intrusive_ptr.hpp>
19 #include <boost/utility/swap.hpp>
20 
21 #include <exception>
22 #include <memory>
23 #include <utility>
24 #include <type_traits>
25 
26 namespace hpx { namespace lcos { namespace local
27 {
28     namespace detail
29     {
30         template <typename R, typename SharedState>
31         class promise_base
32         {
33             typedef SharedState shared_state_type;
34             typedef typename shared_state_type::init_no_addref init_no_addref;
35 
36         public:
promise_base()37             promise_base()
38               : shared_state_(new shared_state_type(init_no_addref{}), false)
39               , future_retrieved_(false)
40             {}
41 
42             template <typename Allocator>
promise_base(std::allocator_arg_t,Allocator const & a)43             promise_base(std::allocator_arg_t, Allocator const& a)
44               : shared_state_()
45               , future_retrieved_(false)
46             {
47                 typedef typename traits::detail::shared_state_allocator<
48                         SharedState, Allocator
49                     >::type allocator_shared_state_type;
50 
51                 typedef typename
52                         std::allocator_traits<Allocator>::template
53                             rebind_alloc<allocator_shared_state_type>
54                     other_allocator;
55                 typedef std::allocator_traits<other_allocator> traits;
56                 typedef std::unique_ptr<
57                         allocator_shared_state_type,
58                         util::allocator_deleter<other_allocator>
59                     > unique_pointer;
60 
61                 other_allocator alloc(a);
62                 unique_pointer p (traits::allocate(alloc, 1),
63                     util::allocator_deleter<other_allocator>{alloc});
64 
65                 traits::construct(alloc, p.get(), init_no_addref{}, alloc);
66                 shared_state_.reset(p.release(), false);
67             }
68 
promise_base(promise_base && other)69             promise_base(promise_base&& other) noexcept
70               : shared_state_(std::move(other.shared_state_))
71               , future_retrieved_(other.future_retrieved_)
72             {
73                 other.shared_state_ = nullptr;
74                 other.future_retrieved_ = false;
75             }
76 
~promise_base()77             ~promise_base()
78             {
79                 check_abandon_shared_state(
80                     "local::detail::promise_base<R>::~promise_base()");
81             }
82 
operator =(promise_base && other)83             promise_base& operator=(promise_base&& other) noexcept
84             {
85                 if (this != &other)
86                 {
87                     this->check_abandon_shared_state(
88                         "local::detail::promise_base<R>::operator=");
89 
90                     shared_state_ = std::move(other.shared_state_);
91                     future_retrieved_ = other.future_retrieved_;
92 
93                     other.shared_state_ = nullptr;
94                     other.future_retrieved_ = false;
95                 }
96                 return *this;
97             }
98 
swap(promise_base & other)99             void swap(promise_base& other) noexcept
100             {
101                 boost::swap(shared_state_, other.shared_state_);
102                 boost::swap(future_retrieved_, other.future_retrieved_);
103             }
104 
valid() const105             bool valid() const noexcept
106             {
107                 return shared_state_ != nullptr;
108             }
109 
get_future(error_code & ec=throws)110             future<R> get_future(error_code& ec = throws)
111             {
112                 if (future_retrieved_)
113                 {
114                     HPX_THROWS_IF(ec, future_already_retrieved,
115                         "local::detail::promise_base<R>::get_future",
116                         "future has already been retrieved from this promise");
117                     return future<R>();
118                 }
119 
120                 if (shared_state_ == nullptr)
121                 {
122                     HPX_THROWS_IF(ec, no_state,
123                         "local::detail::promise_base<R>::get_future",
124                         "this promise has no valid shared state");
125                     return future<R>();
126                 }
127 
128                 future_retrieved_ = true;
129                 return traits::future_access<future<R> >::create(shared_state_);
130             }
131 
132             template <typename... Ts>
133             typename std::enable_if<
134                 std::is_constructible<R, Ts&&...>::value ||
135                     std::is_void<R>::value
136             >::type
set_value(Ts &&...ts)137             set_value(Ts&&... ts)
138             {
139                 if (shared_state_ == nullptr)
140                 {
141                     HPX_THROW_EXCEPTION(no_state,
142                         "local::detail::promise_base<R>::set_value",
143                         "this promise has no valid shared state");
144                     return;
145                 }
146 
147                 if (shared_state_->is_ready())
148                 {
149                     HPX_THROW_EXCEPTION(promise_already_satisfied,
150                         "local::detail::promise_base<R>::set_value",
151                         "result has already been stored for this promise");
152                     return;
153                 }
154 
155                 shared_state_->set_value(std::forward<Ts>(ts)...);
156             }
157 
158             template <typename T>
set_exception(T && value)159             void set_exception(T&& value)
160             {
161                 if (shared_state_ == nullptr)
162                 {
163                     HPX_THROW_EXCEPTION(no_state,
164                         "local::detail::promise_base<R>::set_exception",
165                         "this promise has no valid shared state");
166                     return;
167                 }
168 
169                 if (shared_state_->is_ready())
170                 {
171                     HPX_THROW_EXCEPTION(promise_already_satisfied,
172                         "local::detail::promise_base<R>::set_exception",
173                         "result has already been stored for this promise");
174                     return;
175                 }
176 
177                 shared_state_->set_exception(std::forward<T>(value));
178             }
179 
180         protected:
check_abandon_shared_state(const char * fun)181             void check_abandon_shared_state(const char* fun)
182             {
183                 if (shared_state_ != nullptr && future_retrieved_ &&
184                     !shared_state_->is_ready())
185                 {
186                     shared_state_->set_error(broken_promise, fun,
187                         "abandoning not ready shared state");
188                 }
189             }
190 
191             boost::intrusive_ptr<shared_state_type> shared_state_;
192             bool future_retrieved_;
193         };
194     }
195 
196     ///////////////////////////////////////////////////////////////////////////
197     template <typename R>
198     class promise : public detail::promise_base<R>
199     {
200         typedef detail::promise_base<R> base_type;
201 
202     public:
203         // Effects: constructs a promise object and a shared state.
promise()204         promise()
205           : base_type()
206         {}
207 
208         // Effects: constructs a promise object and a shared state. The
209         // constructor uses the allocator a to allocate the memory for the
210         // shared state.
211         template <typename Allocator>
promise(std::allocator_arg_t,Allocator const & a)212         promise(std::allocator_arg_t, Allocator const& a)
213           : base_type(std::allocator_arg, a)
214         {}
215 
216         // Effects: constructs a new promise object and transfers ownership of
217         //          the shared state of other (if any) to the newly-
218         //          constructed object.
219         // Postcondition: other has no shared state.
promise(promise && other)220         promise(promise&& other) noexcept
221           : base_type(std::move(other))
222         {}
223 
224         // Effects: Abandons any shared state
~promise()225         ~promise()
226         {}
227 
228         // Effects: Abandons any shared state (30.6.4) and then as if
229         //          promise(std::move(other)).swap(*this).
230         // Returns: *this.
operator =(promise && other)231         promise& operator=(promise&& other) noexcept
232         {
233             base_type::operator=(std::move(other));
234             return *this;
235         }
236 
237         // Effects: Exchanges the shared state of *this and other.
238         // Postcondition: *this has the shared state (if any) that other had
239         //                prior to the call to swap. other has the shared state
240         //                (if any) that *this had prior to the call to swap.
swap(promise & other)241         void swap(promise& other) noexcept
242         {
243             base_type::swap(other);
244         }
245 
246         // Returns: true only if *this refers to a shared state.
valid() const247         bool valid() const noexcept
248         {
249             return base_type::valid();
250         }
251 
252         // Returns: A future<R> object with the same shared state as *this.
253         // Throws: future_error if *this has no shared state or if get_future
254         //         has already been called on a promise with the same shared
255         //         state as *this.
256         // Error conditions:
257         //   - future_already_retrieved if get_future has already been called
258         //     on a promise with the same shared state as *this.
259         //   - no_state if *this has no shared state.
get_future(error_code & ec=throws)260         future<R> get_future(error_code& ec = throws)
261         {
262             return base_type::get_future(ec);
263         }
264 
265         // Effects: atomically stores the value r in the shared state and makes
266         //          that state ready (30.6.4).
267         // Throws:
268         //   - future_error if its shared state already has a stored value or
269         //     exception, or
270         //   - any exception thrown by the constructor selected to copy an
271         //     object of R.
272         // Error conditions:
273         //   - promise_already_satisfied if its shared state already has a
274         //     stored value or exception.
275         //   - no_state if *this has no shared state.
set_value(R const & r)276         void set_value(R const& r)
277         {
278             base_type::set_value(r);
279         }
280 
281         // Effects: atomically stores the value r in the shared state and makes
282         //          that state ready (30.6.4).
283         // Throws:
284         //   - future_error if its shared state already has a stored value or
285         //     exception, or
286         //   - any exception thrown by the constructor selected to move an
287         //     object of R.
288         // Error conditions:
289         //   - promise_already_satisfied if its shared state already has a
290         //     stored value or exception.
291         //   - no_state if *this has no shared state.
set_value(R && r)292         void set_value(R&& r)
293         {
294             base_type::set_value(std::move(r));
295         }
296 
297         // Extension (see wg21.link/P0319)
298         //
299         // Effects: atomically initializes the stored value as if
300         //          direct-non-list-initializing an object of type R with the
301         //          arguments forward<Args>(args)...) in the shared state and
302         //          makes that state ready.
303         // Requires:
304         //      - std::is_constructible<R, Ts&&...>::value == true
305         // Throws:
306         //   - future_error if its shared state already has a stored value or
307         //     exception, or
308         //   - any exception thrown by the constructor selected to move an
309         //     object of R.
310         // Error conditions:
311         //   - promise_already_satisfied if its shared state already has a
312         //     stored value or exception.
313         //   - no_state if *this has no shared state.
314         template <typename ... Ts>
set_value(Ts &&...ts)315         void set_value(Ts&&... ts)
316         {
317             base_type::set_value(std::forward<Ts>(ts)...);
318         }
319 
320         // Effects: atomically stores the exception pointer p in the shared
321         //          state and makes that state ready (30.6.4).
322         // Throws: future_error if its shared state already has a stored value
323         //         or exception.
324         // Error conditions:
325         //   - promise_already_satisfied if its shared state already has a
326         //     stored value or exception.
327         //   - no_state if *this has no shared state.
set_exception(std::exception_ptr e)328         void set_exception(std::exception_ptr e)
329         {
330             base_type::set_exception(std::move(e));
331         }
332     };
333 
334     template <typename R>
335     class promise<R&> : public detail::promise_base<R&>
336     {
337         typedef detail::promise_base<R&> base_type;
338 
339     public:
340         // Effects: constructs a promise object and a shared state.
promise()341         promise()
342           : base_type()
343         {}
344 
345         // Effects: constructs a promise object and a shared state. The
346         // constructor uses the allocator a to allocate the memory for the
347         // shared state.
348         template <typename Allocator>
promise(std::allocator_arg_t,Allocator const & a)349         promise(std::allocator_arg_t, Allocator const& a)
350           : base_type(std::allocator_arg, a)
351         {}
352 
353         // Effects: constructs a new promise object and transfers ownership of
354         //          the shared state of other (if any) to the newly-
355         //          constructed object.
356         // Postcondition: other has no shared state.
promise(promise && other)357         promise(promise&& other) noexcept
358           : base_type(std::move(other))
359         {}
360 
361         // Effects: Abandons any shared state
~promise()362         ~promise()
363         {}
364 
365         // Effects: Abandons any shared state (30.6.4) and then as if
366         //          promise(std::move(other)).swap(*this).
367         // Returns: *this.
operator =(promise && other)368         promise& operator=(promise&& other) noexcept
369         {
370             base_type::operator=(std::move(other));
371             return *this;
372         }
373 
374         // Effects: Exchanges the shared state of *this and other.
375         // Postcondition: *this has the shared state (if any) that other had
376         //                prior to the call to swap. other has the shared state
377         //                (if any) that *this had prior to the call to swap.
swap(promise & other)378         void swap(promise& other) noexcept
379         {
380             base_type::swap(other);
381         }
382 
383         // Returns: true only if *this refers to a shared state.
valid() const384         bool valid() const noexcept
385         {
386             return base_type::valid();
387         }
388 
389         // Returns: A future<R> object with the same shared state as *this.
390         // Throws: future_error if *this has no shared state or if get_future
391         //         has already been called on a promise with the same shared
392         //         state as *this.
393         // Error conditions:
394         //   - future_already_retrieved if get_future has already been called
395         //     on a promise with the same shared state as *this.
396         //   - no_state if *this has no shared state.
get_future(error_code & ec=throws)397         future<R&> get_future(error_code& ec = throws)
398         {
399             return base_type::get_future(ec);
400         }
401 
402         // Effects: atomically stores the value r in the shared state and makes
403         //          that state ready (30.6.4).
404         // Throws:
405         //   - future_error if its shared state already has a stored value or
406         //     exception.
407         // Error conditions:
408         //   - promise_already_satisfied if its shared state already has a
409         //     stored value or exception.
410         //   - no_state if *this has no shared state.
set_value(R & r)411         void set_value(R& r)
412         {
413             base_type::set_value(r);
414         }
415 
416         // Effects: atomically stores the exception pointer p in the shared
417         //          state and makes that state ready (30.6.4).
418         // Throws: future_error if its shared state already has a stored value
419         //         or exception.
420         // Error conditions:
421         //   - promise_already_satisfied if its shared state already has a
422         //     stored value or exception.
423         //   - no_state if *this has no shared state.
set_exception(std::exception_ptr e)424         void set_exception(std::exception_ptr e)
425         {
426             base_type::set_exception(std::move(e));
427         }
428     };
429 
430     template <>
431     class promise<void> : public detail::promise_base<void>
432     {
433         typedef detail::promise_base<void> base_type;
434 
435     public:
436         // Effects: constructs a promise object and a shared state.
promise()437         promise()
438           : base_type()
439         {}
440 
441         // Effects: constructs a promise object and a shared state. The
442         // constructor uses the allocator a to allocate the memory for the
443         // shared state.
444         template <typename Allocator>
promise(std::allocator_arg_t,Allocator const & a)445         promise(std::allocator_arg_t, Allocator const& a)
446           : base_type(std::allocator_arg, a)
447         {}
448 
449         // Effects: constructs a new promise object and transfers ownership of
450         //          the shared state of other (if any) to the newly-
451         //          constructed object.
452         // Postcondition: other has no shared state.
promise(promise && other)453         promise(promise&& other) noexcept
454           : base_type(std::move(other))
455         {}
456 
457         // Effects: Abandons any shared state
~promise()458         ~promise()
459         {}
460 
461         // Effects: Abandons any shared state (30.6.4) and then as if
462         //          promise(std::move(other)).swap(*this).
463         // Returns: *this.
operator =(promise && other)464         promise& operator=(promise&& other) noexcept
465         {
466             base_type::operator=(std::move(other));
467             return *this;
468         }
469 
470         // Effects: Exchanges the shared state of *this and other.
471         // Postcondition: *this has the shared state (if any) that other had
472         //                prior to the call to swap. other has the shared state
473         //                (if any) that *this had prior to the call to swap.
swap(promise & other)474         void swap(promise& other) noexcept
475         {
476             base_type::swap(other);
477         }
478 
479         // Returns: true only if *this refers to a shared state.
valid() const480         bool valid() const noexcept
481         {
482             return base_type::valid();
483         }
484 
485         // Returns: A future<R> object with the same shared state as *this.
486         // Throws: future_error if *this has no shared state or if get_future
487         //         has already been called on a promise with the same shared
488         //         state as *this.
489         // Error conditions:
490         //   - future_already_retrieved if get_future has already been called
491         //     on a promise with the same shared state as *this.
492         //   - no_state if *this has no shared state.
get_future(error_code & ec=throws)493         future<void> get_future(error_code& ec = throws)
494         {
495             return base_type::get_future(ec);
496         }
497 
498         // Effects: atomically stores the value r in the shared state and makes
499         //          that state ready (30.6.4).
500         // Throws:
501         //   - future_error if its shared state already has a stored value or
502         //     exception, or
503         //   - any exception thrown by the constructor selected to copy an
504         //     object of R.
505         // Error conditions:
506         //   - promise_already_satisfied if its shared state already has a
507         //     stored value or exception.
508         //   - no_state if *this has no shared state.
set_value()509         void set_value()
510         {
511             base_type::set_value(hpx::util::unused);
512         }
513 
514         // Effects: atomically stores the exception pointer p in the shared
515         //          state and makes that state ready (30.6.4).
516         // Throws: future_error if its shared state already has a stored value
517         //         or exception.
518         // Error conditions:
519         //   - promise_already_satisfied if its shared state already has a
520         //     stored value or exception.
521         //   - no_state if *this has no shared state.
set_exception(std::exception_ptr e)522         void set_exception(std::exception_ptr e)
523         {
524             base_type::set_exception(std::move(e));
525         }
526     };
527 
528     template <typename R>
swap(promise<R> & x,promise<R> & y)529     void swap(promise<R>& x, promise<R>& y) noexcept
530     {
531         x.swap(y);
532     }
533 }}}
534 
535 namespace std
536 {
537     // Requires: Allocator shall be an allocator (17.6.3.5)
538     template <typename R, typename Allocator>
539     struct uses_allocator<hpx::lcos::local::promise<R>, Allocator>
540       : std::true_type
541     {};
542 }
543 
544 #endif
545