]>
Commit | Line | Data |
---|---|---|
1 | ||
2 | // Copyright Oliver Kowalke 2013. | |
3 | // Distributed under the Boost Software License, Version 1.0. | |
4 | // (See accompanying file LICENSE_1_0.txt or copy at | |
5 | // http://www.boost.org/LICENSE_1_0.txt) | |
6 | ||
7 | #ifndef BOOST_FIBERS_PROMISE_HPP | |
8 | #define BOOST_FIBERS_PROMISE_HPP | |
9 | ||
10 | #include <algorithm> | |
11 | #include <memory> | |
12 | #include <utility> | |
13 | ||
14 | #include <boost/config.hpp> | |
15 | ||
16 | #include <boost/fiber/detail/convert.hpp> | |
17 | #include <boost/fiber/exceptions.hpp> | |
18 | #include <boost/fiber/future/detail/shared_state.hpp> | |
19 | #include <boost/fiber/future/detail/shared_state_object.hpp> | |
20 | #include <boost/fiber/future/future.hpp> | |
21 | ||
22 | namespace boost { | |
23 | namespace fibers { | |
24 | namespace detail { | |
25 | ||
26 | template< typename R > | |
27 | struct promise_base { | |
28 | typedef typename shared_state< R >::ptr_t ptr_t; | |
29 | ||
30 | bool obtained_{ false }; | |
31 | ptr_t future_{}; | |
32 | ||
33 | promise_base() : | |
34 | promise_base{ std::allocator_arg, std::allocator< promise_base >{} } { | |
35 | } | |
36 | ||
37 | template< typename Allocator > | |
38 | promise_base( std::allocator_arg_t, Allocator alloc) { | |
39 | typedef detail::shared_state_object< R, Allocator > object_t; | |
40 | typedef std::allocator_traits< typename object_t::allocator_t > traits_t; | |
41 | typename object_t::allocator_t a{ alloc }; | |
42 | typename traits_t::pointer ptr{ traits_t::allocate( a, 1) }; | |
43 | ||
44 | try { | |
45 | traits_t::construct( a, ptr, a); | |
46 | } catch (...) { | |
47 | traits_t::deallocate( a, ptr, 1); | |
48 | throw; | |
49 | } | |
50 | future_.reset( convert( ptr) ); | |
51 | } | |
52 | ||
53 | ~promise_base() { | |
54 | if ( future_) { | |
55 | future_->owner_destroyed(); | |
56 | } | |
57 | } | |
58 | ||
59 | promise_base( promise_base const&) = delete; | |
60 | promise_base & operator=( promise_base const&) = delete; | |
61 | ||
62 | promise_base( promise_base && other) noexcept : | |
63 | obtained_{ other.obtained_ }, | |
64 | future_{ std::move( other.future_) } { | |
65 | other.obtained_ = false; | |
66 | } | |
67 | ||
68 | promise_base & operator=( promise_base && other) noexcept { | |
69 | if ( this == & other) return * this; | |
70 | promise_base tmp{ std::move( other) }; | |
71 | swap( tmp); | |
72 | return * this; | |
73 | } | |
74 | ||
75 | future< R > get_future() { | |
76 | if ( obtained_) { | |
77 | throw future_already_retrieved{}; | |
78 | } | |
79 | if ( ! future_) { | |
80 | throw promise_uninitialized{}; | |
81 | } | |
82 | obtained_ = true; | |
83 | return future< R >{ future_ }; | |
84 | } | |
85 | ||
86 | void swap( promise_base & other) noexcept { | |
87 | std::swap( obtained_, other.obtained_); | |
88 | future_.swap( other.future_); | |
89 | } | |
90 | ||
91 | void set_exception( std::exception_ptr p) { | |
92 | if ( ! future_) { | |
93 | throw promise_uninitialized{}; | |
94 | } | |
95 | future_->set_exception( p); | |
96 | } | |
97 | }; | |
98 | ||
99 | } | |
100 | ||
101 | template< typename R > | |
102 | class promise : private detail::promise_base< R > { | |
103 | private: | |
104 | typedef detail::promise_base< R > base_t; | |
105 | ||
106 | public: | |
107 | promise() = default; | |
108 | ||
109 | template< typename Allocator > | |
110 | promise( std::allocator_arg_t, Allocator alloc) : | |
111 | base_t{ std::allocator_arg, alloc } { | |
112 | } | |
113 | ||
114 | promise( promise const&) = delete; | |
115 | promise & operator=( promise const&) = delete; | |
116 | ||
117 | promise( promise && other) noexcept = default; | |
118 | promise & operator=( promise && other) = default; | |
119 | ||
120 | void set_value( R const& value) { | |
121 | if ( ! base_t::future_) { | |
122 | throw promise_uninitialized{}; | |
123 | } | |
124 | base_t::future_->set_value( value); | |
125 | } | |
126 | ||
127 | void set_value( R && value) { | |
128 | if ( ! base_t::future_) { | |
129 | throw promise_uninitialized{}; | |
130 | } | |
131 | base_t::future_->set_value( std::move( value) ); | |
132 | } | |
133 | ||
134 | void swap( promise & other) noexcept { | |
135 | base_t::swap( other); | |
136 | } | |
137 | ||
138 | using base_t::get_future; | |
139 | using base_t::set_exception; | |
140 | }; | |
141 | ||
142 | template< typename R > | |
143 | class promise< R & > : private detail::promise_base< R & > { | |
144 | private: | |
145 | typedef detail::promise_base< R & > base_t; | |
146 | ||
147 | public: | |
148 | promise() = default; | |
149 | ||
150 | template< typename Allocator > | |
151 | promise( std::allocator_arg_t, Allocator alloc) : | |
152 | base_t{ std::allocator_arg, alloc } { | |
153 | } | |
154 | ||
155 | promise( promise const&) = delete; | |
156 | promise & operator=( promise const&) = delete; | |
157 | ||
158 | promise( promise && other) noexcept = default; | |
159 | promise & operator=( promise && other) noexcept = default; | |
160 | ||
161 | void set_value( R & value) { | |
162 | if ( ! base_t::future_) { | |
163 | throw promise_uninitialized{}; | |
164 | } | |
165 | base_t::future_->set_value( value); | |
166 | } | |
167 | ||
168 | void swap( promise & other) noexcept { | |
169 | base_t::swap( other); | |
170 | } | |
171 | ||
172 | using base_t::get_future; | |
173 | using base_t::set_exception; | |
174 | }; | |
175 | ||
176 | template<> | |
177 | class promise< void > : private detail::promise_base< void > { | |
178 | private: | |
179 | typedef detail::promise_base< void > base_t; | |
180 | ||
181 | public: | |
182 | promise() = default; | |
183 | ||
184 | template< typename Allocator > | |
185 | promise( std::allocator_arg_t, Allocator alloc) : | |
186 | base_t{ std::allocator_arg, alloc } { | |
187 | } | |
188 | ||
189 | promise( promise const&) = delete; | |
190 | promise & operator=( promise const&) = delete; | |
191 | ||
192 | promise( promise && other) noexcept = default; | |
193 | promise & operator=( promise && other) noexcept = default; | |
194 | ||
195 | inline | |
196 | void set_value() { | |
197 | if ( ! base_t::future_) { | |
198 | throw promise_uninitialized{}; | |
199 | } | |
200 | base_t::future_->set_value(); | |
201 | } | |
202 | ||
203 | inline | |
204 | void swap( promise & other) noexcept { | |
205 | base_t::swap( other); | |
206 | } | |
207 | ||
208 | using base_t::get_future; | |
209 | using base_t::set_exception; | |
210 | }; | |
211 | ||
212 | template< typename R > | |
213 | void swap( promise< R > & l, promise< R > & r) noexcept { | |
214 | l.swap( r); | |
215 | } | |
216 | ||
217 | }} | |
218 | ||
219 | #endif // BOOST_FIBERS_PROMISE_HPP |