2 // Copyright Oliver Kowalke 2016.
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/continuation.hpp>
20 #include <boost/coroutine2/detail/config.hpp>
21 #include <boost/coroutine2/detail/forced_unwind.hpp>
22 #include <boost/coroutine2/detail/wrap.hpp>
24 #ifdef BOOST_HAS_ABI_HEADERS
25 # include BOOST_ABI_PREFIX
29 namespace coroutines2 {
32 // pull_coroutine< T >
34 template< typename T >
36 pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
37 boost::context::continuation c = std::move( cb->c);
38 // destroy control structure
40 // destroy coroutine's stack
41 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,
50 state{ state_t::unwind },
54 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
55 c = boost::context::callcc(
56 std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
57 wrap( [this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable {
58 // create synthesized push_coroutine< T >
59 typename push_coroutine< T >::control_block synthesized_cb{ this, c };
60 push_coroutine< T > synthesized{ & synthesized_cb };
61 other = & synthesized_cb;
62 if ( state_t::none == ( state & state_t::destroy) ) {
64 auto fn = std::move( fn_);
65 // call coroutine-fn with synthesized push_coroutine as argument
67 } catch ( boost::context::detail::forced_unwind const&) {
70 // store other exceptions in exception-pointer
71 except = std::current_exception();
74 // set termination flags
75 state |= state_t::complete;
77 return other->c.resume();
79 std::forward< Fn >( fn) ) );
81 c = boost::context::callcc(
82 std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
83 [this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable {
84 // create synthesized push_coroutine< T >
85 typename push_coroutine< T >::control_block synthesized_cb{ this, c };
86 push_coroutine< T > synthesized{ & synthesized_cb };
87 other = & synthesized_cb;
88 if ( state_t::none == ( state & state_t::destroy) ) {
90 auto fn = std::move( fn_);
91 // call coroutine-fn with synthesized push_coroutine as argument
93 } catch ( boost::context::detail::forced_unwind const&) {
96 // store other exceptions in exception-pointer
97 except = std::current_exception();
100 // set termination flags
101 state |= state_t::complete;
103 return other->c.resume();
107 std::rethrow_exception( except);
111 template< typename T >
112 pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
113 boost::context::continuation & c_) noexcept :
116 state{ state_t::none },
122 template< typename T >
123 pull_coroutine< T >::control_block::~control_block() {
124 // destroy data if set
126 reinterpret_cast< T * >( std::addressof( storage) )->~T();
130 template< typename T >
132 pull_coroutine< T >::control_block::deallocate() noexcept {
133 if ( state_t::none != ( state & state_t::unwind) ) {
138 template< typename T >
140 pull_coroutine< T >::control_block::resume() {
143 std::rethrow_exception( except);
147 template< typename T >
149 pull_coroutine< T >::control_block::set( T const& t) {
150 // destroy data if set
152 reinterpret_cast< T * >( std::addressof( storage) )->~T();
154 ::new ( static_cast< void * >( std::addressof( storage) ) ) T( t);
158 template< typename T >
160 pull_coroutine< T >::control_block::set( T && t) {
161 // destroy data if set
163 reinterpret_cast< T * >( std::addressof( storage) )->~T();
165 ::new ( static_cast< void * >( std::addressof( storage) ) ) T( std::move( t) );
169 template< typename T >
171 pull_coroutine< T >::control_block::get() noexcept {
172 return * reinterpret_cast< T * >( std::addressof( storage) );
175 template< typename T >
177 pull_coroutine< T >::control_block::valid() const noexcept {
178 return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid;
182 // pull_coroutine< T & >
184 template< typename T >
186 pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
187 boost::context::continuation c = std::move( cb->c);
188 // destroy control structure
189 cb->~control_block();
190 // destroy coroutine's stack
191 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,
200 state{ state_t::unwind },
204 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
205 c = boost::context::callcc(
206 std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
207 wrap( [this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable {
208 // create synthesized push_coroutine< T & >
209 typename push_coroutine< T & >::control_block synthesized_cb{ this, c };
210 push_coroutine< T & > synthesized{ & synthesized_cb };
211 other = & synthesized_cb;
212 if ( state_t::none == ( state & state_t::destroy) ) {
214 auto fn = std::move( fn_);
215 // call coroutine-fn with synthesized push_coroutine as argument
217 } catch ( boost::context::detail::forced_unwind const&) {
220 // store other exceptions in exception-pointer
221 except = std::current_exception();
224 // set termination flags
225 state |= state_t::complete;
227 return other->c.resume();
229 std::forward< Fn >( fn) ) );
231 c = boost::context::callcc(
232 std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
233 [this,fn_=std::forward< Fn >( fn)](boost::context::continuation && c) mutable {
234 // create synthesized push_coroutine< T & >
235 typename push_coroutine< T & >::control_block synthesized_cb{ this, c };
236 push_coroutine< T & > synthesized{ & synthesized_cb };
237 other = & synthesized_cb;
238 if ( state_t::none == ( state & state_t::destroy) ) {
240 auto fn = std::move( fn_);
241 // call coroutine-fn with synthesized push_coroutine as argument
243 } catch ( boost::context::detail::forced_unwind const&) {
246 // store other exceptions in exception-pointer
247 except = std::current_exception();
250 // set termination flags
251 state |= state_t::complete;
253 return other->c.resume();
257 std::rethrow_exception( except);
261 template< typename T >
262 pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
263 boost::context::continuation & c_) noexcept :
266 state{ state_t::none },
272 template< typename T >
274 pull_coroutine< T & >::control_block::deallocate() noexcept {
275 if ( state_t::none != ( state & state_t::unwind) ) {
280 template< typename T >
282 pull_coroutine< T & >::control_block::resume() {
285 std::rethrow_exception( except);
289 template< typename T >
291 pull_coroutine< T & >::control_block::set( T & t) {
292 ::new ( static_cast< void * >( std::addressof( storage) ) ) holder{ t };
296 template< typename T >
298 pull_coroutine< T & >::control_block::get() noexcept {
299 return reinterpret_cast< holder * >( std::addressof( storage) )->t;
302 template< typename T >
304 pull_coroutine< T & >::control_block::valid() const noexcept {
305 return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid;
309 // pull_coroutine< void >
313 pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
314 boost::context::continuation c = std::move( cb->c);
315 // destroy control structure
316 cb->~control_block();
317 // destroy coroutine's stack
318 cb->state |= state_t::destroy;
321 template< typename StackAllocator, typename Fn >
322 pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator && salloc,
326 state{ state_t::unwind },
328 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
329 c = boost::context::callcc(
330 std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
331 wrap( [this](typename std::decay< Fn >::type & fn_,boost::context::continuation && c) mutable {
332 // create synthesized push_coroutine< void >
333 typename push_coroutine< void >::control_block synthesized_cb{ this, c };
334 push_coroutine< void > synthesized{ & synthesized_cb };
335 other = & synthesized_cb;
336 if ( state_t::none == ( state & state_t::destroy) ) {
338 auto fn = std::move( fn_);
339 // call coroutine-fn with synthesized push_coroutine as argument
341 } catch ( boost::context::detail::forced_unwind const&) {
344 // store other exceptions in exception-pointer
345 except = std::current_exception();
348 // set termination flags
349 state |= state_t::complete;
351 return other->c.resume();
353 std::forward< Fn >( fn) ) );
355 c = boost::context::callcc(
356 std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
357 [this,fn_=std::forward< Fn >( fn)]( boost::context::continuation && c) mutable {
358 // create synthesized push_coroutine< void >
359 typename push_coroutine< void >::control_block synthesized_cb{ this, c };
360 push_coroutine< void > synthesized{ & synthesized_cb };
361 other = & synthesized_cb;
362 if ( state_t::none == ( state & state_t::destroy) ) {
364 auto fn = std::move( fn_);
365 // call coroutine-fn with synthesized push_coroutine as argument
367 } catch ( boost::context::detail::forced_unwind const&) {
370 // store other exceptions in exception-pointer
371 except = std::current_exception();
374 // set termination flags
375 state |= state_t::complete;
377 return other->c.resume();
381 std::rethrow_exception( except);
386 pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
387 boost::context::continuation & c_) noexcept :
390 state{ state_t::none },
396 pull_coroutine< void >::control_block::deallocate() noexcept {
397 if ( state_t::none != ( state & state_t::unwind) ) {
404 pull_coroutine< void >::control_block::resume() {
407 std::rethrow_exception( except);
413 pull_coroutine< void >::control_block::valid() const noexcept {
414 return nullptr != other && state_t::none == ( state & state_t::complete);
419 #ifdef BOOST_HAS_ABI_HEADERS
420 # include BOOST_ABI_SUFFIX
423 #endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP