2 // Copyright Oliver Kowalke 2014.
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)
7 #ifndef BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP
8 #define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP
14 #include <boost/assert.hpp>
15 #include <boost/config.hpp>
17 #include <boost/context/continuation.hpp>
19 #include <boost/coroutine2/detail/config.hpp>
20 #include <boost/coroutine2/detail/forced_unwind.hpp>
21 #include <boost/coroutine2/detail/wrap.hpp>
23 #ifdef BOOST_HAS_ABI_HEADERS
24 # include BOOST_ABI_PREFIX
28 namespace coroutines2 {
31 // push_coroutine< T >
33 template< typename T >
35 push_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
36 boost::context::continuation c = std::move( cb->c);
37 // destroy control structure
39 // destroy coroutine's stack
40 cb->state |= state_t::destroy;
43 template< typename T >
44 template< typename StackAllocator, typename Fn >
45 push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator && salloc,
49 state{ state_t::unwind },
51 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
52 c = boost::context::callcc(
53 std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
54 wrap( [this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable {
55 // create synthesized pull_coroutine< T >
56 typename pull_coroutine< T >::control_block synthesized_cb{ this, c };
57 pull_coroutine< T > synthesized{ & synthesized_cb };
58 other = & synthesized_cb;
59 other->c = other->c.resume();
60 if ( state_t::none == ( state & state_t::destroy) ) {
62 auto fn = std::move( fn_);
63 // call coroutine-fn with synthesized pull_coroutine as argument
65 } catch ( boost::context::detail::forced_unwind const&) {
68 // store other exceptions in exception-pointer
69 except = std::current_exception();
72 // set termination flags
73 state |= state_t::complete;
75 return other->c.resume();
77 std::forward< Fn >( fn) ) );
79 c = boost::context::callcc(
80 std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
81 [this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable {
82 // create synthesized pull_coroutine< T >
83 typename pull_coroutine< T >::control_block synthesized_cb{ this, c };
84 pull_coroutine< T > synthesized{ & synthesized_cb };
85 other = & synthesized_cb;
86 other->c = other->c.resume();
87 if ( state_t::none == ( state & state_t::destroy) ) {
89 auto fn = std::move( fn_);
90 // call coroutine-fn with synthesized pull_coroutine as argument
92 } catch ( boost::context::detail::forced_unwind const&) {
95 // store other exceptions in exception-pointer
96 except = std::current_exception();
99 // set termination flags
100 state |= state_t::complete;
102 return other->c.resume();
107 template< typename T >
108 push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
109 boost::context::continuation & c_) noexcept :
112 state{ state_t::none },
116 template< typename T >
118 push_coroutine< T >::control_block::deallocate() noexcept {
119 if ( state_t::none != ( state & state_t::unwind) ) {
124 template< typename T >
126 push_coroutine< T >::control_block::resume( T const& data) {
127 // pass data to other context
129 // resume other context
132 std::rethrow_exception( except);
136 template< typename T >
138 push_coroutine< T >::control_block::resume( T && data) {
139 // pass data to other context
140 other->set( std::move( data) );
141 // resume other context
144 std::rethrow_exception( except);
148 template< typename T >
150 push_coroutine< T >::control_block::valid() const noexcept {
151 return state_t::none == ( state & state_t::complete );
155 // push_coroutine< T & >
157 template< typename T >
159 push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
160 boost::context::continuation c = std::move( cb->c);
161 // destroy control structure
162 cb->~control_block();
163 // destroy coroutine's stack
164 cb->state |= state_t::destroy;
167 template< typename T >
168 template< typename StackAllocator, typename Fn >
169 push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator && salloc,
173 state{ state_t::unwind },
175 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
176 c = boost::context::callcc(
177 std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
178 wrap( [this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable {
179 // create synthesized pull_coroutine< T & >
180 typename pull_coroutine< T & >::control_block synthesized_cb{ this, c };
181 pull_coroutine< T & > synthesized{ & synthesized_cb };
182 other = & synthesized_cb;
183 other->c = other->c.resume();
184 if ( state_t::none == ( state & state_t::destroy) ) {
186 auto fn = std::move( fn_);
187 // call coroutine-fn with synthesized pull_coroutine as argument
189 } catch ( boost::context::detail::forced_unwind const&) {
192 // store other exceptions in exception-pointer
193 except = std::current_exception();
196 // set termination flags
197 state |= state_t::complete;
199 return other->c.resume();
201 std::forward< Fn >( fn) ) );
203 c = boost::context::callcc(
204 std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
205 [this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable {
206 // create synthesized pull_coroutine< T & >
207 typename pull_coroutine< T & >::control_block synthesized_cb{ this, c };
208 pull_coroutine< T & > synthesized{ & synthesized_cb };
209 other = & synthesized_cb;
210 other->c = other->c.resume();
211 if ( state_t::none == ( state & state_t::destroy) ) {
213 auto fn = std::move( fn_);
214 // call coroutine-fn with synthesized pull_coroutine as argument
216 } catch ( boost::context::detail::forced_unwind const&) {
219 // store other exceptions in exception-pointer
220 except = std::current_exception();
223 // set termination flags
224 state |= state_t::complete;
226 return other->c.resume();
231 template< typename T >
232 push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
233 boost::context::continuation & c_) noexcept :
236 state{ state_t::none },
240 template< typename T >
242 push_coroutine< T & >::control_block::deallocate() noexcept {
243 if ( state_t::none != ( state & state_t::unwind) ) {
248 template< typename T >
250 push_coroutine< T & >::control_block::resume( T & data) {
251 // pass data to other context
253 // resume other context
256 std::rethrow_exception( except);
260 template< typename T >
262 push_coroutine< T & >::control_block::valid() const noexcept {
263 return state_t::none == ( state & state_t::complete );
267 // push_coroutine< void >
271 push_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
272 boost::context::continuation c = std::move( cb->c);
273 // destroy control structure
274 cb->~control_block();
275 // destroy coroutine's stack
276 cb->state |= state_t::destroy;
279 template< typename StackAllocator, typename Fn >
280 push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator && salloc, Fn && fn) :
283 state{ state_t::unwind },
285 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
286 c = boost::context::callcc(
287 std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
288 wrap( [this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable {
289 // create synthesized pull_coroutine< void >
290 typename pull_coroutine< void >::control_block synthesized_cb{ this, c };
291 pull_coroutine< void > synthesized{ & synthesized_cb };
292 other = & synthesized_cb;
293 other->c = other->c.resume();
294 if ( state_t::none == ( state & state_t::destroy) ) {
296 auto fn = std::move( fn_);
297 // call coroutine-fn with synthesized pull_coroutine as argument
299 } catch ( boost::context::detail::forced_unwind const&) {
302 // store other exceptions in exception-pointer
303 except = std::current_exception();
306 // set termination flags
307 state |= state_t::complete;
309 return other->c.resume();
311 std::forward< Fn >( fn) ) );
313 c = boost::context::callcc(
314 std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
315 [this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable {
316 // create synthesized pull_coroutine< void >
317 typename pull_coroutine< void >::control_block synthesized_cb{ this, c};
318 pull_coroutine< void > synthesized{ & synthesized_cb };
319 other = & synthesized_cb;
320 other->c = other->c.resume();
321 if ( state_t::none == ( state & state_t::destroy) ) {
323 auto fn = std::move( fn_);
324 // call coroutine-fn with synthesized pull_coroutine as argument
326 } catch ( boost::context::detail::forced_unwind const&) {
329 // store other exceptions in exception-pointer
330 except = std::current_exception();
333 // set termination flags
334 state |= state_t::complete;
336 return other->c.resume();
342 push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
343 boost::context::continuation & c_) noexcept :
346 state{ state_t::none },
352 push_coroutine< void >::control_block::deallocate() noexcept {
353 if ( state_t::none != ( state & state_t::unwind) ) {
360 push_coroutine< void >::control_block::resume() {
363 std::rethrow_exception( except);
369 push_coroutine< void >::control_block::valid() const noexcept {
370 return state_t::none == ( state & state_t::complete );
375 #ifdef BOOST_HAS_ABI_HEADERS
376 # include BOOST_ABI_SUFFIX
379 #endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP