| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 | 
							
- //          Copyright Oliver Kowalke 2017.
 
- // Distributed under the Boost Software License, Version 1.0.
 
- //    (See accompanying file LICENSE_1_0.txt or copy at
 
- //          http://www.boost.org/LICENSE_1_0.txt)
 
- #ifndef BOOST_CONTEXT_CONTINUATION_H
 
- #define BOOST_CONTEXT_CONTINUATION_H
 
- #include <boost/context/detail/config.hpp>
 
- #include <algorithm>
 
- #include <cstddef>
 
- #include <cstdint>
 
- #include <cstdlib>
 
- #include <exception>
 
- #include <functional>
 
- #include <memory>
 
- #include <ostream>
 
- #include <tuple>
 
- #include <utility>
 
- #include <boost/assert.hpp>
 
- #include <boost/config.hpp>
 
- #include <boost/intrusive_ptr.hpp>
 
- #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
 
- #include <boost/context/detail/exchange.hpp>
 
- #endif
 
- #if defined(BOOST_NO_CXX17_STD_INVOKE)
 
- #include <boost/context/detail/invoke.hpp>
 
- #endif
 
- #include <boost/context/detail/disable_overload.hpp>
 
- #include <boost/context/detail/exception.hpp>
 
- #include <boost/context/detail/fcontext.hpp>
 
- #include <boost/context/detail/tuple.hpp>
 
- #include <boost/context/fixedsize_stack.hpp>
 
- #include <boost/context/flags.hpp>
 
- #include <boost/context/preallocated.hpp>
 
- #include <boost/context/segmented_stack.hpp>
 
- #include <boost/context/stack_context.hpp>
 
- #ifdef BOOST_HAS_ABI_HEADERS
 
- # include BOOST_ABI_PREFIX
 
- #endif
 
- #if defined(BOOST_MSVC)
 
- # pragma warning(push)
 
- # pragma warning(disable: 4702)
 
- #endif
 
- namespace boost {
 
- namespace context {
 
- namespace detail {
 
- inline
 
- transfer_t context_unwind( transfer_t t) {
 
-     throw forced_unwind( t.fctx);
 
-     return { nullptr, nullptr };
 
- }
 
- template< typename Rec >
 
- transfer_t context_exit( transfer_t t) noexcept {
 
-     Rec * rec = static_cast< Rec * >( t.data);
 
-     // destroy context stack
 
-     rec->deallocate();
 
-     return { nullptr, nullptr };
 
- }
 
- template< typename Rec >
 
- void context_entry( transfer_t t) noexcept {
 
-     // transfer control structure to the context-stack
 
-     Rec * rec = static_cast< Rec * >( t.data);
 
-     BOOST_ASSERT( nullptr != t.fctx);
 
-     BOOST_ASSERT( nullptr != rec);
 
-     try {
 
-         // jump back to `create_context()`
 
-         t = jump_fcontext( t.fctx, nullptr);
 
-         // start executing
 
-         t.fctx = rec->run( t.fctx);
 
-     } catch ( forced_unwind const& ex) {
 
-         t = { ex.fctx, nullptr };
 
- #ifndef BOOST_ASSERT_IS_VOID
 
-         const_cast< forced_unwind & >( ex).caught = true;
 
- #endif
 
-     }
 
-     BOOST_ASSERT( nullptr != t.fctx);
 
-     // destroy context-stack of `this`context on next context
 
-     ontop_fcontext( t.fctx, rec, context_exit< Rec >);
 
-     BOOST_ASSERT_MSG( false, "context already terminated");
 
- }
 
- template< typename Ctx, typename Fn >
 
- transfer_t context_ontop( transfer_t t) {
 
-     auto p = static_cast< std::tuple< Fn > * >( t.data);
 
-     BOOST_ASSERT( nullptr != p);
 
-     typename std::decay< Fn >::type fn = std::get< 0 >( * p);
 
-     t.data = nullptr;
 
-     Ctx c{ t.fctx };
 
-     // execute function, pass continuation via reference
 
-     c = fn( std::move( c) );
 
- #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
 
-     return { exchange( c.fctx_, nullptr), nullptr };
 
- #else
 
-     return { std::exchange( c.fctx_, nullptr), nullptr };
 
- #endif
 
- }
 
- template< typename Ctx, typename StackAlloc, typename Fn >
 
- class record {
 
- private:
 
-     stack_context                                       sctx_;
 
-     typename std::decay< StackAlloc >::type             salloc_;
 
-     typename std::decay< Fn >::type                     fn_;
 
-     static void destroy( record * p) noexcept {
 
-         typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
 
-         stack_context sctx = p->sctx_;
 
-         // deallocate record
 
-         p->~record();
 
-         // destroy stack with stack allocator
 
-         salloc.deallocate( sctx);
 
-     }
 
- public:
 
-     record( stack_context sctx, StackAlloc && salloc,
 
-             Fn && fn) noexcept :
 
-         sctx_( sctx),
 
-         salloc_( std::forward< StackAlloc >( salloc)),
 
-         fn_( std::forward< Fn >( fn) ) {
 
-     }
 
-     record( record const&) = delete;
 
-     record & operator=( record const&) = delete;
 
-     void deallocate() noexcept {
 
-         destroy( this);
 
-     }
 
-     fcontext_t run( fcontext_t fctx) {
 
-         Ctx c{ fctx };
 
-         // invoke context-function
 
- #if defined(BOOST_NO_CXX17_STD_INVOKE)
 
-         c = boost::context::detail::invoke( fn_, std::move( c) );
 
- #else
 
-         c = std::invoke( fn_, std::move( c) );
 
- #endif
 
- #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
 
-         return exchange( c.fctx_, nullptr);
 
- #else
 
-         return std::exchange( c.fctx_, nullptr);
 
- #endif
 
-     }
 
- };
 
- template< typename Record, typename StackAlloc, typename Fn >
 
- fcontext_t create_context1( StackAlloc && salloc, Fn && fn) {
 
-     auto sctx = salloc.allocate();
 
-     // reserve space for control structure
 
- 	void * storage = reinterpret_cast< void * >(
 
- 			( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( Record) ) )
 
-             & ~static_cast< uintptr_t >( 0xff) );
 
-     // placment new for control structure on context stack
 
-     Record * record = new ( storage) Record{
 
-             sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
 
-     // 64byte gab between control structure and stack top
 
-     // should be 16byte aligned
 
-     void * stack_top = reinterpret_cast< void * >(
 
-             reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) );
 
-     void * stack_bottom = reinterpret_cast< void * >(
 
-             reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) );
 
-     // create fast-context
 
-     const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom);
 
-     const fcontext_t fctx = make_fcontext( stack_top, size, & context_entry< Record >);
 
-     BOOST_ASSERT( nullptr != fctx);
 
-     // transfer control structure to context-stack
 
-     return jump_fcontext( fctx, record).fctx;
 
- }
 
- template< typename Record, typename StackAlloc, typename Fn >
 
- fcontext_t create_context2( preallocated palloc, StackAlloc && salloc, Fn && fn) {
 
-     // reserve space for control structure
 
-     void * storage = reinterpret_cast< void * >(
 
-             ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( Record) ) )
 
-             & ~ static_cast< uintptr_t >( 0xff) );
 
-     // placment new for control structure on context-stack
 
-     Record * record = new ( storage) Record{
 
-             palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
 
-     // 64byte gab between control structure and stack top
 
-     void * stack_top = reinterpret_cast< void * >(
 
-             reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) );
 
-     void * stack_bottom = reinterpret_cast< void * >(
 
-             reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) );
 
-     // create fast-context
 
-     const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom);
 
-     const fcontext_t fctx = make_fcontext( stack_top, size, & context_entry< Record >);
 
-     BOOST_ASSERT( nullptr != fctx);
 
-     // transfer control structure to context-stack
 
-     return jump_fcontext( fctx, record).fctx;
 
- }
 
- }
 
- class continuation {
 
- private:
 
-     template< typename Ctx, typename StackAlloc, typename Fn >
 
-     friend class detail::record;
 
-     template< typename Ctx, typename Fn >
 
-     friend detail::transfer_t
 
-     detail::context_ontop( detail::transfer_t);
 
-     template< typename StackAlloc, typename Fn >
 
-     friend continuation
 
-     callcc( std::allocator_arg_t, StackAlloc &&, Fn &&);
 
-     template< typename StackAlloc, typename Fn >
 
-     friend continuation
 
-     callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&);
 
-     detail::fcontext_t  fctx_{ nullptr };
 
-     continuation( detail::fcontext_t fctx) noexcept :
 
-         fctx_{ fctx } {
 
-     }
 
- public:
 
-     continuation() noexcept = default;
 
-     ~continuation() {
 
-         if ( BOOST_UNLIKELY( nullptr != fctx_) ) {
 
-             detail::ontop_fcontext(
 
- #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
 
-                     detail::exchange( fctx_, nullptr),
 
- #else
 
-                     std::exchange( fctx_, nullptr),
 
- #endif
 
-                    nullptr,
 
-                    detail::context_unwind);
 
-         }
 
-     }
 
-     continuation( continuation && other) noexcept {
 
-         swap( other);
 
-     }
 
-     continuation & operator=( continuation && other) noexcept {
 
-         if ( BOOST_LIKELY( this != & other) ) {
 
-             continuation tmp = std::move( other);
 
-             swap( tmp);
 
-         }
 
-         return * this;
 
-     }
 
-     continuation( continuation const& other) noexcept = delete;
 
-     continuation & operator=( continuation const& other) noexcept = delete;
 
-     continuation resume() & {
 
-         return std::move( * this).resume();
 
-     }
 
-     continuation resume() && {
 
-         BOOST_ASSERT( nullptr != fctx_);
 
-         return { detail::jump_fcontext(
 
- #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
 
-                     detail::exchange( fctx_, nullptr),
 
- #else
 
-                     std::exchange( fctx_, nullptr),
 
- #endif
 
-                     nullptr).fctx };
 
-     }
 
-     template< typename Fn >
 
-     continuation resume_with( Fn && fn) & {
 
-         return std::move( * this).resume_with( std::forward< Fn >( fn) );
 
-     }
 
-     template< typename Fn >
 
-     continuation resume_with( Fn && fn) && {
 
-         BOOST_ASSERT( nullptr != fctx_);
 
-         auto p = std::make_tuple( std::forward< Fn >( fn) );
 
-         return { detail::ontop_fcontext(
 
- #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
 
-                     detail::exchange( fctx_, nullptr),
 
- #else
 
-                     std::exchange( fctx_, nullptr),
 
- #endif
 
-                     & p,
 
-                     detail::context_ontop< continuation, Fn >).fctx };
 
-     }
 
-     explicit operator bool() const noexcept {
 
-         return nullptr != fctx_;
 
-     }
 
-     bool operator!() const noexcept {
 
-         return nullptr == fctx_;
 
-     }
 
-     bool operator<( continuation const& other) const noexcept {
 
-         return fctx_ < other.fctx_;
 
-     }
 
-     template< typename charT, class traitsT >
 
-     friend std::basic_ostream< charT, traitsT > &
 
-     operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) {
 
-         if ( nullptr != other.fctx_) {
 
-             return os << other.fctx_;
 
-         } else {
 
-             return os << "{not-a-context}";
 
-         }
 
-     }
 
-     void swap( continuation & other) noexcept {
 
-         std::swap( fctx_, other.fctx_);
 
-     }
 
- };
 
- template<
 
-     typename Fn,
 
-     typename = detail::disable_overload< continuation, Fn >
 
- >
 
- continuation
 
- callcc( Fn && fn) {
 
-     return callcc(
 
-             std::allocator_arg, fixedsize_stack(),
 
-             std::forward< Fn >( fn) );
 
- }
 
- template< typename StackAlloc, typename Fn >
 
- continuation
 
- callcc( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) {
 
-     using Record = detail::record< continuation, StackAlloc, Fn >;
 
-     return continuation{
 
-                 detail::create_context1< Record >(
 
-                         std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume();
 
- }
 
- template< typename StackAlloc, typename Fn >
 
- continuation
 
- callcc( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) {
 
-     using Record = detail::record< continuation, StackAlloc, Fn >;
 
-     return continuation{
 
-                 detail::create_context2< Record >(
 
-                         palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume();
 
- }
 
- #if defined(BOOST_USE_SEGMENTED_STACKS)
 
- template< typename Fn >
 
- continuation
 
- callcc( std::allocator_arg_t, segmented_stack, Fn &&);
 
- template< typename StackAlloc, typename Fn >
 
- continuation
 
- callcc( std::allocator_arg_t, preallocated, segmented_stack, Fn &&);
 
- #endif
 
- inline
 
- void swap( continuation & l, continuation & r) noexcept {
 
-     l.swap( r);
 
- }
 
- }}
 
- #if defined(BOOST_MSVC)
 
- # pragma warning(pop)
 
- #endif
 
- #ifdef BOOST_HAS_ABI_HEADERS
 
- # include BOOST_ABI_SUFFIX
 
- #endif
 
- #endif // BOOST_CONTEXT_CONTINUATION_H
 
 
  |