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_PULL_CONTROL_BLOCK_IPP
8 #define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
15 #include <boost/assert.hpp>
16 #include <boost/config.hpp>
18 #include <boost/context/execution_context.hpp>
20 #include <boost/coroutine2/detail/config.hpp>
21 #include <boost/coroutine2/detail/forced_unwind.hpp>
23 #ifdef BOOST_HAS_ABI_HEADERS
24 # include BOOST_ABI_PREFIX
28 namespace coroutines2 {
31 // pull_coroutine< T >
33 template< typename T >
35 pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
36 boost::context::execution_context< T * > ctx = std::move( cb->ctx);
37 // destroy control structure
39 // destroy coroutine's stack
40 cb->state |= state_t::destroy;
44 template< typename T >
45 template< typename StackAllocator, typename Fn >
46 pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
48 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
49 ctx{ std::allocator_arg, palloc, salloc,
52 [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< T * > ctx, T *) mutable {
53 // create synthesized push_coroutine< T >
54 typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
55 push_coroutine< T > synthesized{ & synthesized_cb };
56 other = & synthesized_cb;
57 if ( state_t::none == ( state & state_t::destroy) ) {
59 auto fn = std::move( fn_);
60 // call coroutine-fn with synthesized push_coroutine as argument
62 } catch ( boost::context::detail::forced_unwind const&) {
65 // store other exceptions in exception-pointer
66 except = std::current_exception();
69 // set termination flags
70 state |= state_t::complete;
72 auto result = other->ctx( nullptr);
73 other->ctx = std::move( std::get< 0 >( result) );
74 return std::move( other->ctx);
76 std::forward< Fn >( fn),
77 std::placeholders::_1,
78 std::placeholders::_2))},
80 ctx{ std::allocator_arg, palloc, salloc,
81 [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< T * > ctx, T *) mutable {
82 // create synthesized push_coroutine< T >
83 typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
84 push_coroutine< T > synthesized{ & synthesized_cb };
85 other = & synthesized_cb;
86 if ( state_t::none == ( state & state_t::destroy) ) {
88 auto fn = std::move( fn_);
89 // call coroutine-fn with synthesized push_coroutine as argument
91 } catch ( boost::context::detail::forced_unwind const&) {
94 // store other exceptions in exception-pointer
95 except = std::current_exception();
98 // set termination flags
99 state |= state_t::complete;
101 auto result = other->ctx( nullptr);
102 other->ctx = std::move( std::get< 0 >( result) );
103 return std::move( other->ctx);
107 state{ state_t::unwind },
111 // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
115 template< typename T >
116 pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
117 boost::context::execution_context< T * > & ctx_) noexcept :
118 ctx{ std::move( ctx_) },
120 state{ state_t::none },
126 template< typename T >
127 pull_coroutine< T >::control_block::~control_block() {
128 // destroy data if set
130 reinterpret_cast< T * >( std::addressof( storage) )->~T();
134 template< typename T >
136 pull_coroutine< T >::control_block::deallocate() noexcept {
137 if ( state_t::none != ( state & state_t::unwind) ) {
142 template< typename T >
144 pull_coroutine< T >::control_block::resume() {
145 auto result = ctx( nullptr);
146 ctx = std::move( std::get< 0 >( result) );
147 set( std::get< 1 >( result) );
149 std::rethrow_exception( except);
153 template< typename T >
155 pull_coroutine< T >::control_block::set( T * t) {
156 // destroy data if set
158 reinterpret_cast< T * >( std::addressof( storage) )->~T();
161 ::new ( static_cast< void * >( std::addressof( storage) ) ) T( std::move( * t) );
168 template< typename T >
170 pull_coroutine< T >::control_block::get() noexcept {
171 return * reinterpret_cast< T * >( std::addressof( storage) );
174 template< typename T >
176 pull_coroutine< T >::control_block::valid() const noexcept {
177 return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid;
181 // pull_coroutine< T & >
183 template< typename T >
185 pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
186 boost::context::execution_context< T * > ctx = std::move( cb->ctx);
187 // destroy control structure
188 cb->~control_block();
189 // destroy coroutine's stack
190 cb->state |= state_t::destroy;
194 template< typename T >
195 template< typename StackAllocator, typename Fn >
196 pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
198 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
199 ctx{ std::allocator_arg, palloc, salloc,
202 [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< T *> ctx, T *) mutable {
203 // create synthesized push_coroutine< T & >
204 typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
205 push_coroutine< T & > synthesized{ & synthesized_cb };
206 other = & synthesized_cb;
207 if ( state_t::none == ( state & state_t::destroy) ) {
209 auto fn = std::move( fn_);
210 // call coroutine-fn with synthesized push_coroutine as argument
212 } catch ( boost::context::detail::forced_unwind const&) {
215 // store other exceptions in exception-pointer
216 except = std::current_exception();
219 // set termination flags
220 state |= state_t::complete;
222 auto result = other->ctx( nullptr);
223 other->ctx = std::move( std::get< 0 >( result) );
224 return std::move( other->ctx);
226 std::forward< Fn >( fn),
227 std::placeholders::_1,
228 std::placeholders::_2))},
230 ctx{ std::allocator_arg, palloc, salloc,
231 [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< T * > ctx, T *) mutable {
232 // create synthesized push_coroutine< T & >
233 typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
234 push_coroutine< T & > synthesized{ & synthesized_cb };
235 other = & synthesized_cb;
236 if ( state_t::none == ( state & state_t::destroy) ) {
238 auto fn = std::move( fn_);
239 // call coroutine-fn with synthesized push_coroutine as argument
241 } catch ( boost::context::detail::forced_unwind const&) {
244 // store other exceptions in exception-pointer
245 except = std::current_exception();
248 // set termination flags
249 state |= state_t::complete;
251 auto result = other->ctx( nullptr);
252 other->ctx = std::move( std::get< 0 >( result) );
253 return std::move( other->ctx);
257 state{ state_t::unwind },
260 // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
264 template< typename T >
265 pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
266 boost::context::execution_context< T * > & ctx_) noexcept :
267 ctx{ std::move( ctx_) },
269 state{ state_t::none },
274 template< typename T >
276 pull_coroutine< T & >::control_block::deallocate() noexcept {
277 if ( state_t::none != ( state & state_t::unwind) ) {
282 template< typename T >
284 pull_coroutine< T & >::control_block::resume() {
285 auto result = ctx( nullptr);
286 ctx = std::move( std::get< 0 >( result) );
287 t = std::get< 1 >( result);
289 std::rethrow_exception( except);
293 template< typename T >
295 pull_coroutine< T & >::control_block::get() noexcept {
299 template< typename T >
301 pull_coroutine< T & >::control_block::valid() const noexcept {
302 return nullptr != other && state_t::none == ( state & state_t::complete) && nullptr != t;
306 // pull_coroutine< void >
310 pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
311 boost::context::execution_context< void > ctx = std::move( cb->ctx);
312 // destroy control structure
313 cb->~control_block();
314 // destroy coroutine's stack
315 cb->state |= state_t::destroy;
319 template< typename StackAllocator, typename Fn >
320 pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
322 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
323 ctx{ std::allocator_arg, palloc, salloc,
326 [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< void > ctx) mutable {
327 // create synthesized push_coroutine< void >
328 typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
329 push_coroutine< void > synthesized{ & synthesized_cb };
330 other = & synthesized_cb;
331 if ( state_t::none == ( state & state_t::destroy) ) {
333 auto fn = std::move( fn_);
334 // call coroutine-fn with synthesized push_coroutine as argument
336 } catch ( boost::context::detail::forced_unwind const&) {
339 // store other exceptions in exception-pointer
340 except = std::current_exception();
343 // set termination flags
344 state |= state_t::complete;
346 other->ctx = other->ctx();
347 return std::move( other->ctx);
349 std::forward< Fn >( fn),
350 std::placeholders::_1))},
352 ctx{ std::allocator_arg, palloc, salloc,
353 [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< void > ctx) mutable {
354 // create synthesized push_coroutine< void >
355 typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
356 push_coroutine< void > synthesized{ & synthesized_cb };
357 other = & synthesized_cb;
358 if ( state_t::none == ( state & state_t::destroy) ) {
360 auto fn = std::move( fn_);
361 // call coroutine-fn with synthesized push_coroutine as argument
363 } catch ( boost::context::detail::forced_unwind const&) {
366 // store other exceptions in exception-pointer
367 except = std::current_exception();
370 // set termination flags
371 state |= state_t::complete;
373 other->ctx = other->ctx();
374 return std::move( other->ctx);
378 state{ state_t::unwind },
380 // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
385 pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
386 boost::context::execution_context< void > & ctx_) noexcept :
387 ctx{ std::move( ctx_) },
389 state{ state_t::none },
395 pull_coroutine< void >::control_block::deallocate() noexcept {
396 if ( state_t::none != ( state & state_t::unwind) ) {
403 pull_coroutine< void >::control_block::resume() {
406 std::rethrow_exception( except);
412 pull_coroutine< void >::control_block::valid() const noexcept {
413 return nullptr != other && state_t::none == ( state & state_t::complete);
418 #ifdef BOOST_HAS_ABI_HEADERS
419 # include BOOST_ABI_SUFFIX
422 #endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP