Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:33

0001 
0002 //          Copyright Oliver Kowalke 2016.
0003 // Distributed under the Boost Software License, Version 1.0.
0004 //    (See accompanying file LICENSE_1_0.txt or copy at
0005 //          http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 #ifndef BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
0008 #define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
0009 
0010 #include <algorithm>
0011 #include <exception>
0012 #include <memory>
0013 #include <tuple>
0014 
0015 #include <boost/assert.hpp>
0016 #include <boost/config.hpp>
0017 #include <boost/context/detail/config.hpp>
0018 
0019 #include <boost/context/fiber.hpp>
0020 
0021 #include <boost/coroutine2/detail/config.hpp>
0022 #include <boost/coroutine2/detail/wrap.hpp>
0023 
0024 #ifdef BOOST_HAS_ABI_HEADERS
0025 #  include BOOST_ABI_PREFIX
0026 #endif
0027 
0028 namespace boost {
0029 namespace coroutines2 {
0030 namespace detail {
0031 
0032 // pull_coroutine< T >
0033 
0034 template< typename T >
0035 void
0036 pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
0037     boost::context::fiber c = std::move( cb->c);
0038     // destroy control structure
0039     cb->~control_block();
0040     // destroy coroutine's stack
0041     cb->state |= state_t::destroy;
0042 }
0043 
0044 template< typename T >
0045 template< typename StackAllocator, typename Fn >
0046 pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator && salloc,
0047                                                    Fn && fn) :
0048 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
0049     c{ std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
0050        wrap( [this](typename std::decay< Fn >::type & fn_,boost::context::fiber && c) mutable {
0051                // create synthesized push_coroutine< T >
0052                typename push_coroutine< T >::control_block synthesized_cb{ this, c };
0053                push_coroutine< T > synthesized{ & synthesized_cb };
0054                other = & synthesized_cb;
0055                if ( state_t::none == ( state & state_t::destroy) ) {
0056                    try {
0057                        auto fn = std::move( fn_);
0058                        // call coroutine-fn with synthesized push_coroutine as argument
0059                        fn( synthesized);
0060                    } catch ( boost::context::detail::forced_unwind const&) {
0061                        throw;
0062 #if defined( BOOST_CONTEXT_HAS_CXXABI_H )
0063                    } catch ( abi::__forced_unwind const&) {
0064                        throw;
0065 #endif
0066                    } catch (...) {
0067                        // store other exceptions in exception-pointer
0068                        except = std::current_exception();
0069                    }
0070                }
0071                // set termination flags
0072                state |= state_t::complete;
0073                // jump back
0074                return std::move( other->c).resume();
0075             },
0076             std::forward< Fn >( fn) ) },
0077 #else
0078     c{ std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
0079        [this,fn_=std::forward< Fn >( fn)](boost::context::fiber && c) mutable {
0080           // create synthesized push_coroutine< T >
0081           typename push_coroutine< T >::control_block synthesized_cb{ this, c };
0082           push_coroutine< T > synthesized{ & synthesized_cb };
0083           other = & synthesized_cb;
0084           if ( state_t::none == ( state & state_t::destroy) ) {
0085               try {
0086                   auto fn = std::move( fn_);
0087                   // call coroutine-fn with synthesized push_coroutine as argument
0088                   fn( synthesized);
0089               } catch ( boost::context::detail::forced_unwind const&) {
0090                   throw;
0091 #if defined( BOOST_CONTEXT_HAS_CXXABI_H )
0092               } catch ( abi::__forced_unwind const&) {
0093                   throw;
0094 #endif
0095               } catch (...) {
0096                   // store other exceptions in exception-pointer
0097                   except = std::current_exception();
0098               }
0099           }
0100           // set termination flags
0101           state |= state_t::complete;
0102           // jump back
0103           return std::move( other->c).resume();
0104        } },
0105 #endif
0106     other{ nullptr },
0107     state{ state_t::unwind },
0108     except{},
0109     bvalid{ false },
0110     storage{} {
0111         c = std::move( c).resume();
0112         if ( except) {
0113             std::rethrow_exception( except);
0114         }
0115 }
0116 
0117 template< typename T >
0118 pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
0119                                                    boost::context::fiber & c_) noexcept :
0120     c{ std::move( c_) },
0121     other{ cb },
0122     state{ state_t::none },
0123     except{},
0124     bvalid{ false },
0125     storage{} {
0126 }
0127 
0128 template< typename T >
0129 pull_coroutine< T >::control_block::~control_block() {
0130     // destroy data if set
0131     if ( bvalid) {
0132         reinterpret_cast< T * >( std::addressof( storage) )->~T();
0133     }
0134 }
0135 
0136 template< typename T >
0137 void
0138 pull_coroutine< T >::control_block::deallocate() noexcept {
0139     if ( state_t::none != ( state & state_t::unwind) ) {
0140         destroy( this);
0141     }
0142 }
0143 
0144 template< typename T >
0145 void
0146 pull_coroutine< T >::control_block::resume() {
0147     c = std::move( c).resume();
0148     if ( except) {
0149         std::rethrow_exception( except);
0150     }
0151 }
0152 
0153 template< typename T >
0154 void
0155 pull_coroutine< T >::control_block::set( T const& t) {
0156     // destroy data if set
0157     if ( bvalid) {
0158         reinterpret_cast< T * >( std::addressof( storage) )->~T();
0159     }
0160     ::new ( static_cast< void * >( std::addressof( storage) ) ) T( t);
0161     bvalid = true;
0162 }
0163 
0164 template< typename T >
0165 void
0166 pull_coroutine< T >::control_block::set( T && t) {
0167     // destroy data if set
0168     if ( bvalid) {
0169         reinterpret_cast< T * >( std::addressof( storage) )->~T();
0170     }
0171     ::new ( static_cast< void * >( std::addressof( storage) ) ) T( std::move( t) );
0172     bvalid = true;
0173 }
0174 
0175 template< typename T >
0176 T &
0177 pull_coroutine< T >::control_block::get() noexcept {
0178     return * reinterpret_cast< T * >( std::addressof( storage) );
0179 }
0180 
0181 template< typename T >
0182 bool
0183 pull_coroutine< T >::control_block::valid() const noexcept {
0184     return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid;
0185 }
0186 
0187 
0188 // pull_coroutine< T & >
0189 
0190 template< typename T >
0191 void
0192 pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
0193     boost::context::fiber c = std::move( cb->c);
0194     // destroy control structure
0195     cb->~control_block();
0196     // destroy coroutine's stack
0197     cb->state |= state_t::destroy;
0198 }
0199 
0200 template< typename T >
0201 template< typename StackAllocator, typename Fn >
0202 pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator && salloc,
0203                                                      Fn && fn) :
0204 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
0205     c{ std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
0206        wrap( [this](typename std::decay< Fn >::type & fn_,boost::context::fiber && c) mutable {
0207                // create synthesized push_coroutine< T & >
0208                typename push_coroutine< T & >::control_block synthesized_cb{ this, c };
0209                push_coroutine< T & > synthesized{ & synthesized_cb };
0210                other = & synthesized_cb;
0211                if ( state_t::none == ( state & state_t::destroy) ) {
0212                    try {
0213                        auto fn = std::move( fn_);
0214                        // call coroutine-fn with synthesized push_coroutine as argument
0215                        fn( synthesized);
0216                    } catch ( boost::context::detail::forced_unwind const&) {
0217                        throw;
0218 #if defined( BOOST_CONTEXT_HAS_CXXABI_H )
0219                    } catch ( abi::__forced_unwind const&) {
0220                        throw;
0221 #endif
0222                    } catch (...) {
0223                        // store other exceptions in exception-pointer
0224                        except = std::current_exception();
0225                    }
0226                }
0227                // set termination flags
0228                state |= state_t::complete;
0229                // jump back
0230                return std::move( other->c).resume();
0231             },
0232             std::forward< Fn >( fn) ) },
0233 #else
0234     c{ std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
0235        [this,fn_=std::forward< Fn >( fn)](boost::context::fiber && c) mutable {
0236           // create synthesized push_coroutine< T & >
0237           typename push_coroutine< T & >::control_block synthesized_cb{ this, c };
0238           push_coroutine< T & > synthesized{ & synthesized_cb };
0239           other = & synthesized_cb;
0240           if ( state_t::none == ( state & state_t::destroy) ) {
0241               try {
0242                   auto fn = std::move( fn_);
0243                   // call coroutine-fn with synthesized push_coroutine as argument
0244                   fn( synthesized);
0245               } catch ( boost::context::detail::forced_unwind const&) {
0246                   throw;
0247 #if defined( BOOST_CONTEXT_HAS_CXXABI_H )
0248               } catch ( abi::__forced_unwind const&) {
0249                   throw;
0250 #endif
0251               } catch (...) {
0252                   // store other exceptions in exception-pointer
0253                   except = std::current_exception();
0254               }
0255           }
0256           // set termination flags
0257           state |= state_t::complete;
0258           // jump back
0259           return std::move( other->c).resume();
0260        } },
0261 #endif
0262     other{ nullptr },
0263     state{ state_t::unwind },
0264     except{},
0265     bvalid{ false },
0266     storage{} {
0267         c = std::move( c).resume();
0268         if ( except) {
0269             std::rethrow_exception( except);
0270         }
0271 }
0272 
0273 template< typename T >
0274 pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
0275                                                      boost::context::fiber & c_) noexcept :
0276     c{ std::move( c_) },
0277     other{ cb },
0278     state{ state_t::none },
0279     except{},
0280     bvalid{ false },
0281     storage{} {
0282 }
0283 
0284 template< typename T >
0285 void
0286 pull_coroutine< T & >::control_block::deallocate() noexcept {
0287     if ( state_t::none != ( state & state_t::unwind) ) {
0288         destroy( this);
0289     }
0290 }
0291 
0292 template< typename T >
0293 void
0294 pull_coroutine< T & >::control_block::resume() {
0295     c = std::move( c).resume();
0296     if ( except) {
0297         std::rethrow_exception( except);
0298     }
0299 }
0300 
0301 template< typename T >
0302 void
0303 pull_coroutine< T & >::control_block::set( T & t) {
0304     ::new ( static_cast< void * >( std::addressof( storage) ) ) holder{ t };
0305     bvalid = true;
0306 }
0307 
0308 template< typename T >
0309 T &
0310 pull_coroutine< T & >::control_block::get() noexcept {
0311     return reinterpret_cast< holder * >( std::addressof( storage) )->t;
0312 }
0313 
0314 template< typename T >
0315 bool
0316 pull_coroutine< T & >::control_block::valid() const noexcept {
0317     return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid;
0318 }
0319 
0320 
0321 // pull_coroutine< void >
0322 
0323 inline
0324 void
0325 pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
0326     boost::context::fiber c = std::move( cb->c);
0327     // destroy control structure
0328     cb->~control_block();
0329     // destroy coroutine's stack
0330     cb->state |= state_t::destroy;
0331 }
0332 
0333 template< typename StackAllocator, typename Fn >
0334 pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator && salloc,
0335                                                       Fn && fn) :
0336 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
0337     c{ std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
0338        wrap( [this](typename std::decay< Fn >::type & fn_,boost::context::fiber && c) mutable {
0339                // create synthesized push_coroutine< void >
0340                typename push_coroutine< void >::control_block synthesized_cb{ this, c };
0341                push_coroutine< void > synthesized{ & synthesized_cb };
0342                other = & synthesized_cb;
0343                if ( state_t::none == ( state & state_t::destroy) ) {
0344                    try {
0345                        auto fn = std::move( fn_);
0346                        // call coroutine-fn with synthesized push_coroutine as argument
0347                        fn( synthesized);
0348                    } catch ( boost::context::detail::forced_unwind const&) {
0349                        throw;
0350 #if defined( BOOST_CONTEXT_HAS_CXXABI_H )
0351                    } catch ( abi::__forced_unwind const&) {
0352                        throw;
0353 #endif
0354                    } catch (...) {
0355                        // store other exceptions in exception-pointer
0356                        except = std::current_exception();
0357                    }
0358                }
0359                // set termination flags
0360                state |= state_t::complete;
0361                // jump back
0362                return std::move( other->c).resume();
0363             },
0364             std::forward< Fn >( fn) ) },
0365 #else
0366     c{ std::allocator_arg, palloc, std::forward< StackAllocator >( salloc),
0367        [this,fn_=std::forward< Fn >( fn)]( boost::context::fiber && c) mutable {
0368           // create synthesized push_coroutine< void >
0369           typename push_coroutine< void >::control_block synthesized_cb{ this, c };
0370           push_coroutine< void > synthesized{ & synthesized_cb };
0371           other = & synthesized_cb;
0372           if ( state_t::none == ( state & state_t::destroy) ) {
0373               try {
0374                   auto fn = std::move( fn_);
0375                   // call coroutine-fn with synthesized push_coroutine as argument
0376                   fn( synthesized);
0377               } catch ( boost::context::detail::forced_unwind const&) {
0378                   throw;
0379 #if defined( BOOST_CONTEXT_HAS_CXXABI_H )
0380               } catch ( abi::__forced_unwind const&) {
0381                   throw;
0382 #endif
0383               } catch (...) {
0384                   // store other exceptions in exception-pointer
0385                   except = std::current_exception();
0386               }
0387           }
0388           // set termination flags
0389           state |= state_t::complete;
0390           // jump back to ctx
0391           return std::move( other->c).resume();
0392        } },
0393 #endif
0394     other{ nullptr },
0395     state{ state_t::unwind },
0396     except{} {
0397         c = std::move( c).resume();
0398         if ( except) {
0399             std::rethrow_exception( except);
0400         }
0401 }
0402 
0403 inline
0404 pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
0405                                                       boost::context::fiber & c_) noexcept :
0406     c{ std::move( c_) },
0407     other{ cb },
0408     state{ state_t::none },
0409     except{} {
0410 }
0411 
0412 inline
0413 void
0414 pull_coroutine< void >::control_block::deallocate() noexcept {
0415     if ( state_t::none != ( state & state_t::unwind) ) {
0416         destroy( this);
0417     }
0418 }
0419 
0420 inline
0421 void
0422 pull_coroutine< void >::control_block::resume() {
0423     c = std::move( c).resume();
0424     if ( except) {
0425         std::rethrow_exception( except);
0426     }
0427 }
0428 
0429 inline
0430 bool
0431 pull_coroutine< void >::control_block::valid() const noexcept {
0432     return nullptr != other && state_t::none == ( state & state_t::complete);
0433 }
0434 
0435 }}}
0436 
0437 #ifdef BOOST_HAS_ABI_HEADERS
0438 #  include BOOST_ABI_SUFFIX
0439 #endif
0440 
0441 #endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP