|  | Home | Libraries | People | FAQ | More | 
| ![[Important]](../../../../../../doc/src/images/important.png) | Important | 
|---|---|
| captured_context requires C++11! | 
Class captured_context encapsulates fcontext_t and manages the context' stack (allocation/deallocation).
        captured_context allocates the context stack (using
        its StackAllocator argument) and creates a control structure
        on top of it. This structure controls the life time of the stack. The address
        of the control structure is stored in the first frame of context' stack (e.g.
        it can not accessed by instances of captured_context
        directly). In contrast to execution_context the ownership
        of the control structure is not shared A call ofcaptured_context::operator()
        enters the context represented by *this and invalidates *this. The context that has been suspended
        by calling captured_context::operator() is passed to
        the resumed context, e.g. as argument of the context-function if the context
        was resumed the first time or returned by captured_context::operator().
        captured_context is only move-constructible and move-assignable.
        If the last reference (captured_context) goes out of
        scope, the control structure is destroyed and the stack gets deallocated
        via the StackAllocator. captured_context
        maintains a static, thread-local pointer (smart pointer), accessed by execution_context::current(),
        pointing to the active context. On each context switch the static, thread-local
        pointer is updated. This makes the context switch a little bit slower, but
        enables faster context destruction (stack unwinding) compared to captured_context.
      
        captured_context expects a function/functor with signature
        captured_context(
        captured_context ctx, void *
        vp).
        The parameter ctx represents
        the context from which this context was resumed (e.g. that has called captured_context::operator()
        on *this)
        and vp is the data passed
        to captured_context::operator(). The function/functor
        has to return the captured_context that has to be resumed, while this context
        terminates.
      
| ![[Important]](../../../../../../doc/src/images/important.png) | Important | 
|---|---|
| Segemnted stacks are not supported together with captured_context. | 
/* * grammar: * P ---> E '\0' * E ---> T {('+'|'-') T} * T ---> S {('*'|'/') S} * S ---> digit | '(' E ')' */ class Parser{ // implementation omitted; see examples directory }; std::istringstream is("1+1"); bool done=false; std::exception_ptr except; // execute parser in new execution context boost::context::captured_context pctx( [&is,&done,&except](ctx::captured_context mctx,void* ignored){ // create parser with callback function Parser p( is, [&mctx](char ch){ // resume main execution context auto result = mctx( & ch); mctx = std::move( std::get<0>( result) ); }); try { // start recursive parsing p.run(); } catch ( ... ) { // store other exceptions in exception-pointer except = std::current_exception(); } // set termination flag done=true; // resume main execution context return mctx; }); // user-code pulls parsed data from parser // invert control flow auto result = pctx(); pctx = std::move( std::get<0>( result) ); void * vp = std::get<1>( result); if ( except) { std::rethrow_exception( except); } while( ! done) { printf("Parsed: %c\n",* static_cast< char* >( vp) ); std::tie(pctx,vp) = pctx(); if ( except) { std::rethrow_exception( except); } } output: Parsed: 1 Parsed: + Parsed: 1
In this example a recursive descent parser uses a callback to emit a newly passed symbol. Using captured_context the control flow can be inverted, e.g. the user-code pulls parsed symbols from the parser - instead to get pushed from the parser (via callback).
The data (character) is transferred between the two captured_context.
If the code executed by captured_context emits an exception, the application is terminated. std::exception_ptr can be used to transfer exceptions between different execution contexts.
Sometimes it is necessary to unwind the stack of an unfinished context to destroy local stack variables so they can release allocated resources (RAII pattern). The user is responsible for this task.
Allocating control structures on top of the stack requires to allocated the stack_context and create the control structure with placement new before captured_context is created.
| ![[Note]](../../../../../../doc/src/images/note.png) | Note | 
|---|---|
| The user is responsible for destructing the control structure at the top of the stack. | 
// stack-allocator used for (de-)allocating stack fixedsize_stack salloc( 4048); // allocate stack space stack_context sctx( salloc.allocate() ); // reserve space for control structure on top of the stack void * sp = static_cast< char * >( sctx.sp) - sizeof( my_control_structure); std::size_t size = sctx.size - sizeof( my_control_structure); // placement new creates control structure on reserved space my_control_structure * cs = new ( sp) my_control_structure( sp, size, sctx, salloc); ... // destructing the control structure cs->~my_control_structure(); ... struct my_control_structure { // captured context captured_context cctx; template< typename StackAllocator > my_control_structure( void * sp, std::size_t size, stack_context sctx, StackAllocator salloc) : // create captured context cctx( std::allocator_arg, preallocated( sp, size, sctx), salloc, entry_func) { } ... };
If the function executed inside a captured_context emits ans exception, the application is terminated by calling ['std::terminate(). std::exception_ptr can be used to transfer exceptions between different execution contexts.
The void pointer argument passed to captured_context::operator(), in one context, is passed as the last argument of the context-function if the context is started for the first time. In all following invocations of captured_context::operator() the void pointer passed to captured_context::operator(), in one context, is returned by captured_context::operator() in the other context.
class X { private: std::exception_ptr excptr_; boost::context::captured_context ctx_; public: X() : excptr_(), ctx_( [=](ctx::captured_context ctx, void * vp)->ctx::captured_context{ try { for (;;) { int i = * static_cast< int * >( vp); std::string str = boost::lexical_cast<std::string>(i); auto result = ctx( & str); ctx = std::move( std::get<0>( result) ); vp = std::get<1>( result); } } catch ( ctx::detail::forced_unwind const&) { throw; } catch (...) { excptr_=std::current_exception(); } return ctx; }) {} std::string operator()( int i) { auto result = ctx_( & i); ctx_ = std::move( std::get<0>( result) ); void * ret = std::get<1>( result); if(excptr_){ std::rethrow_exception(excptr_); } return * static_cast< std::string * >( ret); } }; X x; std::cout << x( 7) << std::endl; output: 7
captured_context
      class captured_context { public: template< typename Fn, typename ... Args > captured_context( Fn && fn, Args && ... args); template< typename StackAlloc, typename Fn, typename ... Args > captured_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args); template< typename StackAlloc, typename Fn, typename ... Args > captured_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args); ~captured_context(); captured_context( captured_context && other) noexcept; captured_context & operator=( captured_context && other) noexcept; captured_context( captured_context const& other) noexcept = delete; captured_context & operator=( captured_context const& other) noexcept = delete; explicit operator bool() const noexcept; bool operator!() const noexcept; std::tuple< captured_context, void * > operator()( void * data = nullptr); template< typename Fn, typename ... Args > std::tuple< captured_context, void * > operator()( exec_ontop_arg_t, Fn && fn, Args && ... args); template< typename Fn, typename ... Args > std::tuple< captured_context, void * > operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args); bool operator==( captured_context const& other) const noexcept; bool operator!=( captured_context const& other) const noexcept; bool operator<( captured_context const& other) const noexcept; bool operator>( captured_context const& other) const noexcept; bool operator<=( captured_context const& other) const noexcept; bool operator>=( captured_context const& other) const noexcept; template< typename charT, class traitsT > friend std::basic_ostream< charT, traitsT > & operator<<( std::basic_ostream< charT, traitsT > & os, captured_context const& other); };
template< typname Fn, typename ... Args > captured_context( Fn &&
        fn, Args &&
        ... args)
      
              Creates a new execution context and prepares the context to execute
              fn. fixedsize_stack
              is used as default stack allocator (stack size == fixedsize_stack::traits::default_size().
            
template< typename StackAlloc, typname Fn, typename
        ... Args
        > captured_context( std::allocator_arg_t,
        StackAlloc salloc, Fn &&
        fn, Args &&
        ... args)
      
              Creates a new execution context and prepares the context to execute
              fn.
            
template< typename StackAlloc, typname Fn, typename
        ... Args
        > captured_context( std::allocator_arg_t,
        preallocated palloc, StackAlloc
        salloc,
        Fn &&
        fn, Args &&
        ... args)
      
              Creates a new execution context and prepares the context to execute
              fn. Used to store control
              structures on top of the stack.
            
captured_context(
        captured_context &&
        other)
      
              Moves underlying capture record to *this.
            
Nothing.
captured_context &
        operator=(
        captured_context &&
        other)
      
              Moves the state of other
              to *this
              using move semantics.
            
Nothing.
explicit operator
        bool() const noexcept
      
              true if *this
              points to a capture record.
            
Nothing.
bool operator!() const noexcept
      
              true if *this
              does not point to a capture record.
            
Nothing.
void * operator()( void * vp)
      void * operator()( void * vp = nullptr); template< typename Fn, typename ... Args > void * operator()( exec_ontop_arg_t, Fn && fn, Args && ... args); template< typename Fn, typename ... Args > void * operator()( void * vp, exec_ontop_arg_t, Fn && fn, Args && ... args);
              Stores internally the current context data (stack pointer, instruction
              pointer, and CPU registers) to the current active context and restores
              the context data from *this, which implies jumping to *this's
              execution context. The void pointer argument, vp,
              is passed to the current context to be returned by the most recent
              call to captured_context::operator() in the same thread. [[Note:
            
              The behaviour is undefined if operator()() is called while captured_context::current() returns *this (e.g. resuming an already running
              context). If the top-level context function returns, std::exit()
              is called.
            
              The void pointer argument passed to the most recent call to captured_context::operator(),
              if any.
            
Nothing.
std::tuple< captured_context, void >
        operator()(
        void * vp)
      std::tuple< captured_context, void * > operator()( void * data = nullptr); template< typename Fn, typename ... Args > std::tuple< captured_context, void * > operator()( exec_ontop_arg_t, Fn && fn, Args && ... args); template< typename Fn, typename ... Args > std::tuple< captured_context, void * > operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args);
              Stores internally the current context data (stack pointer, instruction
              pointer, and CPU registers) of the current active context and restores
              the context data from *this, which implies jumping to *this's
              context. The void pointer argument, vp,
              is passed to the current context to be returned by the most recent
              call to captured_context::operator() in the same thread. fn is executed with arguments args on top of the stack of this. [[Note:
            
              The behaviour is undefined if operator()() is called while captured_context::current() returns *this (e.g. resuming an already running
              context). If the top-level context function returns, std::exit()
              is called.
            
              The tuple of void pointer argument passed to the most recent call to
              captured_context::operator(),
              if any and a captured_context representing the context that has been
              suspended .
            
operator==
      bool operator==( captured_context const& other) const noexcept;
              true if *this
              and other represent
              the same execution context, false
              otherwise.
            
Nothing.
operator!=
      bool operator!=( captured_context const& other) const noexcept;
[`! (other == * this)
[[Throws:] [Nothing.]] ]
operator<
      bool operator<( captured_context const& other) const noexcept;
              true if *this != other
              is true and the implementation-defined total order of captured_context values places *this
              before other, false
              otherwise.
            
Nothing.
operator>
      bool operator>( captured_context const& other) const noexcept;
              other <
              * this
            
Nothing.
operator<=
      bool operator<=( captured_context const& other) const noexcept;
              ! (other <
              * this)
            
Nothing.
operator>=
      bool operator>=( captured_context const& other) const noexcept;
              ! (*
              this <
              other)
            
Nothing.
operator<<
      template< typename charT, class traitsT > std::basic_ostream< charT, traitsT > & operator<<( std::basic_ostream< charT, traitsT > & os, captured_context const& other);
              Writes the representation of other
              to stream os.
            
              os
            
preallocated
      struct preallocated { void * sp; std::size_t size; stack_context sctx; preallocated( void * sp, std:size_t size, stack_allocator sctx) noexcept; };
preallocated(
        void * sp, std:size_t size, stack_allocator sctx)
      
Creates an object of preallocated.