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/execution_context.hpp>
19 #include <boost/coroutine2/detail/config.hpp>
20 #include <boost/coroutine2/detail/forced_unwind.hpp>
22 #ifdef BOOST_HAS_ABI_HEADERS
23 # include BOOST_ABI_PREFIX
27 namespace coroutines2 {
30 // push_coroutine< T >
32 template< typename T >
34 push_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
35 boost::context::execution_context< T * > ctx = std::move( cb->ctx);
36 // destroy control structure
38 // destroy coroutine's stack
39 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,
47 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
48 ctx{ std::allocator_arg, palloc, salloc,
51 [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< T * > ctx, T * data) mutable {
52 // create synthesized pull_coroutine< T >
53 typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
54 pull_coroutine< T > synthesized{ & synthesized_cb };
55 other = & synthesized_cb;
56 // set transferred value
57 synthesized_cb.set( data);
58 if ( state_t::none == ( state & state_t::destroy) ) {
60 auto fn = std::move( fn_);
61 // call coroutine-fn with synthesized pull_coroutine as argument
63 } catch ( boost::context::detail::forced_unwind const&) {
66 // store other exceptions in exception-pointer
67 except = std::current_exception();
70 // set termination flags
71 state |= state_t::complete;
73 auto result = other->ctx( nullptr);
74 other->ctx = std::move( std::get< 0 >( result) );
75 return std::move( other->ctx);
77 std::forward< Fn >( fn),
78 std::placeholders::_1,
79 std::placeholders::_2))},
81 ctx{ std::allocator_arg, palloc, salloc,
82 [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< T * > ctx, T * data) mutable {
83 // create synthesized pull_coroutine< T >
84 typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
85 pull_coroutine< T > synthesized{ & synthesized_cb };
86 other = & synthesized_cb;
87 // set transferred value
88 synthesized_cb.set( data);
89 if ( state_t::none == ( state & state_t::destroy) ) {
91 auto fn = std::move( fn_);
92 // call coroutine-fn with synthesized pull_coroutine as argument
94 } catch ( boost::context::detail::forced_unwind const&) {
97 // store other exceptions in exception-pointer
98 except = std::current_exception();
101 // set termination flags
102 state |= state_t::complete;
104 auto result = other->ctx( nullptr);
105 other->ctx = std::move( std::get< 0 >( result) );
106 return std::move( other->ctx);
110 state{ state_t::unwind },
114 template< typename T >
115 push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
116 boost::context::execution_context< T * > & ctx_) noexcept :
117 ctx{ std::move( ctx_) },
119 state{ state_t::none },
123 template< typename T >
125 push_coroutine< T >::control_block::deallocate() noexcept {
126 if ( state_t::none != ( state & state_t::unwind) ) {
131 template< typename T >
133 push_coroutine< T >::control_block::resume( T const& data) {
134 // pass an pointer to other context
135 auto result = ctx( const_cast< T * >( & data) );
136 ctx = std::move( std::get< 0 >( result) );
138 std::rethrow_exception( except);
142 template< typename T >
144 push_coroutine< T >::control_block::resume( T && data) {
145 // pass an pointer to other context
146 auto result = ctx( std::addressof( data) );
147 ctx = std::move( std::get< 0 >( result) );
149 std::rethrow_exception( except);
153 template< typename T >
155 push_coroutine< T >::control_block::valid() const noexcept {
156 return state_t::none == ( state & state_t::complete );
160 // push_coroutine< T & >
162 template< typename T >
164 push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
165 boost::context::execution_context< T * > ctx = std::move( cb->ctx);
166 // destroy control structure
167 cb->~control_block();
168 // destroy coroutine's stack
169 cb->state |= state_t::destroy;
173 template< typename T >
174 template< typename StackAllocator, typename Fn >
175 push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
177 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
178 ctx{ std::allocator_arg, palloc, salloc,
181 [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< T * > ctx, T * data) mutable {
182 // create synthesized pull_coroutine< T & >
183 typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
184 pull_coroutine< T & > synthesized{ & synthesized_cb };
185 other = & synthesized_cb;
186 // set transferred value
187 synthesized_cb.t = data;
188 if ( state_t::none == ( state & state_t::destroy) ) {
190 auto fn = std::move( fn_);
191 // call coroutine-fn with synthesized pull_coroutine as argument
193 } catch ( boost::context::detail::forced_unwind const&) {
196 // store other exceptions in exception-pointer
197 except = std::current_exception();
200 // set termination flags
201 state |= state_t::complete;
203 auto result = other->ctx( nullptr);
204 other->ctx = std::move( std::get< 0 >( result) );
205 return std::move( other->ctx);
207 std::forward< Fn >( fn),
208 std::placeholders::_1,
209 std::placeholders::_2))},
211 ctx{ std::allocator_arg, palloc, salloc,
212 [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< T * > ctx, T * data) mutable {
213 // create synthesized pull_coroutine< T & >
214 typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
215 pull_coroutine< T & > synthesized{ & synthesized_cb };
216 other = & synthesized_cb;
217 // set transferred value
218 synthesized_cb.t = data;
219 if ( state_t::none == ( state & state_t::destroy) ) {
221 auto fn = std::move( fn_);
222 // call coroutine-fn with synthesized pull_coroutine as argument
224 } catch ( boost::context::detail::forced_unwind const&) {
227 // store other exceptions in exception-pointer
228 except = std::current_exception();
231 // set termination flags
232 state |= state_t::complete;
234 auto result = other->ctx( nullptr);
235 other->ctx = std::move( std::get< 0 >( result) );
236 return std::move( other->ctx);
240 state{ state_t::unwind },
244 template< typename T >
245 push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
246 boost::context::execution_context< T * > & ctx_) noexcept :
247 ctx{ std::move( ctx_) },
249 state{ state_t::none },
253 template< typename T >
255 push_coroutine< T & >::control_block::deallocate() noexcept {
256 if ( state_t::none != ( state & state_t::unwind) ) {
261 template< typename T >
263 push_coroutine< T & >::control_block::resume( T & t) {
264 // pass an pointer to other context
265 auto result = ctx( const_cast< typename std::remove_const< T >::type * >( std::addressof( t) ) );
266 ctx = std::move( std::get< 0 >( result) );
268 std::rethrow_exception( except);
272 template< typename T >
274 push_coroutine< T & >::control_block::valid() const noexcept {
275 return state_t::none == ( state & state_t::complete );
279 // push_coroutine< void >
283 push_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
284 boost::context::execution_context< void > ctx = std::move( cb->ctx);
285 // destroy control structure
286 cb->~control_block();
287 // destroy coroutine's stack
288 cb->state |= state_t::destroy;
292 template< typename StackAllocator, typename Fn >
293 push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) :
294 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
295 ctx{ std::allocator_arg, palloc, salloc,
298 [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< void > ctx) mutable {
299 // create synthesized pull_coroutine< void >
300 typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
301 pull_coroutine< void > synthesized{ & synthesized_cb };
302 other = & synthesized_cb;
303 if ( state_t::none == ( state & state_t::destroy) ) {
305 auto fn = std::move( fn_);
306 // call coroutine-fn with synthesized pull_coroutine as argument
308 } catch ( boost::context::detail::forced_unwind const&) {
311 // store other exceptions in exception-pointer
312 except = std::current_exception();
315 // set termination flags
316 state |= state_t::complete;
318 other->ctx = other->ctx();
319 return std::move( other->ctx);
321 std::forward< Fn >( fn),
322 std::placeholders::_1))},
324 ctx{ std::allocator_arg, palloc, salloc,
325 [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< void > ctx) mutable {
326 // create synthesized pull_coroutine< void >
327 typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx};
328 pull_coroutine< void > synthesized{ & synthesized_cb };
329 other = & synthesized_cb;
330 if ( state_t::none == ( state & state_t::destroy) ) {
332 auto fn = std::move( fn_);
333 // call coroutine-fn with synthesized pull_coroutine as argument
335 } catch ( boost::context::detail::forced_unwind const&) {
338 // store other exceptions in exception-pointer
339 except = std::current_exception();
342 // set termination flags
343 state |= state_t::complete;
345 other->ctx = other->ctx();
346 return std::move( other->ctx);
350 state{ state_t::unwind },
355 push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
356 boost::context::execution_context< void > & ctx_) noexcept :
357 ctx{ std::move( ctx_) },
359 state{ state_t::none },
365 push_coroutine< void >::control_block::deallocate() noexcept {
366 if ( state_t::none != ( state & state_t::unwind) ) {
373 push_coroutine< void >::control_block::resume() {
376 std::rethrow_exception( except);
382 push_coroutine< void >::control_block::valid() const noexcept {
383 return state_t::none == ( state & state_t::complete );
388 #ifdef BOOST_HAS_ABI_HEADERS
389 # include BOOST_ABI_SUFFIX
392 #endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP