boost/coroutine/v2/detail/push_coroutine_object.hpp
// Copyright Oliver Kowalke 2009.
// 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_COROUTINES_UNIDIRECT_DETAIL_PUSH_COROUTINE_OBJECT_H
#define BOOST_COROUTINES_UNIDIRECT_DETAIL_PUSH_COROUTINE_OBJECT_H
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/exception_ptr.hpp>
#include <boost/move/move.hpp>
#include <boost/ref.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/type_traits/function_traits.hpp>
#include <boost/utility.hpp>
#include <boost/coroutine/attributes.hpp>
#include <boost/coroutine/detail/config.hpp>
#include <boost/coroutine/exceptions.hpp>
#include <boost/coroutine/detail/flags.hpp>
#include <boost/coroutine/detail/holder.hpp>
#include <boost/coroutine/detail/param.hpp>
#include <boost/coroutine/detail/stack_tuple.hpp>
#include <boost/coroutine/detail/trampoline.hpp>
#include <boost/coroutine/flags.hpp>
#include <boost/coroutine/stack_context.hpp>
#include <boost/coroutine/v2/detail/push_coroutine_base.hpp>
#ifdef BOOST_MSVC
#pragma warning (push)
#pragma warning (disable: 4355) // using 'this' in initializer list
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace coroutines {
namespace detail {
template<
typename Arg, typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class push_coroutine_object : private stack_tuple< StackAllocator >,
public push_coroutine_base< Arg >
{
public:
typedef typename Allocator::template rebind<
push_coroutine_object<
Arg, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef push_coroutine_base< Arg > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, push_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
push_coroutine_object( push_coroutine_object &);
push_coroutine_object & operator=( push_coroutine_object const&);
void enter_()
{
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( this),
this->preserve_fpu() ) ) );
this->callee_ = * hldr_from->ctx;
if ( this->except_) rethrow_exception( this->except_);
}
void unwind_stack_() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! this->is_complete() );
this->flags_ |= flag_unwind_stack;
holder< Arg > hldr_to( & this->caller_, true);
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
this->flags_ &= ~flag_unwind_stack;
BOOST_ASSERT( this->is_complete() );
}
public:
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
push_coroutine_object( Fn && fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( forward< Fn >( fn) ),
alloc_( alloc)
{ enter_(); }
#else
push_coroutine_object( Fn fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
#endif
~push_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
holder< void > hldr_to( & caller);
holder< Arg > * hldr_from(
reinterpret_cast< holder< Arg > * >(
caller.jump(
this->caller_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
BOOST_ASSERT( hldr_from->data);
// create pull_coroutine
Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_, hldr_from->data);
try
{ fn_( c); }
catch ( forced_unwind const&)
{}
catch (...)
{ this->except_ = current_exception(); }
callee = c.impl_->callee_;
}
this->flags_ |= flag_complete;
holder< Arg > hldr_to( & caller);
caller.jump(
callee,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename Arg, typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class push_coroutine_object< Arg, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public push_coroutine_base< Arg >
{
public:
typedef typename Allocator::template rebind<
push_coroutine_object<
Arg, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef push_coroutine_base< Arg > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, push_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
push_coroutine_object( push_coroutine_object &);
push_coroutine_object & operator=( push_coroutine_object const&);
void enter_()
{
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( this),
this->preserve_fpu() ) ) );
this->callee_ = * hldr_from->ctx;
if ( this->except_) rethrow_exception( this->except_);
}
void unwind_stack_() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! this->is_complete() );
this->flags_ |= flag_unwind_stack;
holder< Arg > hldr_to( & this->caller_, true);
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
this->flags_ &= ~flag_unwind_stack;
BOOST_ASSERT( this->is_complete() );
}
public:
push_coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
~push_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
holder< void > hldr_to( & caller);
holder< Arg > * hldr_from(
reinterpret_cast< holder< Arg > * >(
caller.jump(
this->caller_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
BOOST_ASSERT( hldr_from->data);
// create pull_coroutine
Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_, hldr_from->data);
try
{ fn_( c); }
catch ( forced_unwind const&)
{}
catch (...)
{ this->except_ = current_exception(); }
callee = c.impl_->callee_;
}
this->flags_ |= flag_complete;
holder< Arg > hldr_to( & caller);
caller.jump(
callee,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename Arg, typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class push_coroutine_object< Arg, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public push_coroutine_base< Arg >
{
public:
typedef typename Allocator::template rebind<
push_coroutine_object<
Arg, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef push_coroutine_base< Arg > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, push_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
push_coroutine_object( push_coroutine_object &);
push_coroutine_object & operator=( push_coroutine_object const&);
void enter_()
{
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( this),
this->preserve_fpu() ) ) );
this->callee_ = * hldr_from->ctx;
if ( this->except_) rethrow_exception( this->except_);
}
void unwind_stack_() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! this->is_complete() );
this->flags_ |= flag_unwind_stack;
holder< Arg > hldr_to( & this->caller_, true);
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
this->flags_ &= ~flag_unwind_stack;
BOOST_ASSERT( this->is_complete() );
}
public:
push_coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
~push_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
holder< void > hldr_to( & caller);
holder< Arg > * hldr_from(
reinterpret_cast< holder< Arg > * >(
caller.jump(
this->caller_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
BOOST_ASSERT( hldr_from->data);
// create pull_coroutine
Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_, hldr_from->data);
try
{ fn_( c); }
catch ( forced_unwind const&)
{}
catch (...)
{ this->except_ = current_exception(); }
callee = c.impl_->callee_;
}
this->flags_ |= flag_complete;
holder< Arg > hldr_to( & caller);
caller.jump(
callee,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename Arg, typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class push_coroutine_object< Arg &, Fn, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public push_coroutine_base< Arg & >
{
public:
typedef typename Allocator::template rebind<
push_coroutine_object<
Arg &, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef push_coroutine_base< Arg & > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, push_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
push_coroutine_object( push_coroutine_object &);
push_coroutine_object & operator=( push_coroutine_object const&);
void enter_()
{
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( this),
this->preserve_fpu() ) ) );
this->callee_ = * hldr_from->ctx;
if ( this->except_) rethrow_exception( this->except_);
}
void unwind_stack_() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! this->is_complete() );
this->flags_ |= flag_unwind_stack;
holder< Arg * > hldr_to( & this->caller_, true);
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
this->flags_ &= ~flag_unwind_stack;
BOOST_ASSERT( this->is_complete() );
}
public:
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
push_coroutine_object( Fn && fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( forward< Fn >( fn) ),
alloc_( alloc)
{ enter_(); }
#else
push_coroutine_object( Fn fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
#endif
~push_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
holder< void > hldr_to( & caller);
holder< Arg * > * hldr_from(
reinterpret_cast< holder< Arg * > * >(
caller.jump(
this->caller_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
BOOST_ASSERT( hldr_from->data);
// create pull_coroutine
Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_, hldr_from->data);
try
{ fn_( c); }
catch ( forced_unwind const&)
{}
catch (...)
{ this->except_ = current_exception(); }
callee = c.impl_->callee_;
}
this->flags_ |= flag_complete;
holder< Arg * > hldr_to( & caller);
caller.jump(
callee,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename Arg, typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class push_coroutine_object< Arg &, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public push_coroutine_base< Arg & >
{
public:
typedef typename Allocator::template rebind<
push_coroutine_object<
Arg &, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef push_coroutine_base< Arg & > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, push_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
push_coroutine_object( push_coroutine_object &);
push_coroutine_object & operator=( push_coroutine_object const&);
void enter_()
{
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( this),
this->preserve_fpu() ) ) );
this->callee_ = * hldr_from->ctx;
if ( this->except_) rethrow_exception( this->except_);
}
void unwind_stack_() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! this->is_complete() );
this->flags_ |= flag_unwind_stack;
holder< Arg * > hldr_to( & this->caller_, true);
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
this->flags_ &= ~flag_unwind_stack;
BOOST_ASSERT( this->is_complete() );
}
public:
push_coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
~push_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
holder< void > hldr_to( & caller);
holder< Arg * > * hldr_from(
reinterpret_cast< holder< Arg * > * >(
caller.jump(
this->caller_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
BOOST_ASSERT( hldr_from->data);
// create pull_coroutine
Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_, hldr_from->data);
try
{ fn_( c); }
catch ( forced_unwind const&)
{}
catch (...)
{ this->except_ = current_exception(); }
callee = c.impl_->callee_;
}
this->flags_ |= flag_complete;
holder< Arg * > hldr_to( & caller);
caller.jump(
callee,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename Arg, typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class push_coroutine_object< Arg &, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public push_coroutine_base< Arg & >
{
public:
typedef typename Allocator::template rebind<
push_coroutine_object<
Arg, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef push_coroutine_base< Arg & > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, push_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
push_coroutine_object( push_coroutine_object &);
push_coroutine_object & operator=( push_coroutine_object const&);
void enter_()
{
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( this),
this->preserve_fpu() ) ) );
this->callee_ = * hldr_from->ctx;
if ( this->except_) rethrow_exception( this->except_);
}
void unwind_stack_() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! this->is_complete() );
this->flags_ |= flag_unwind_stack;
holder< Arg * > hldr_to( & this->caller_, true);
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
this->flags_ &= ~flag_unwind_stack;
BOOST_ASSERT( this->is_complete() );
}
public:
push_coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
~push_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
holder< void > hldr_to( & caller);
holder< Arg * > * hldr_from(
reinterpret_cast< holder< Arg * > * >(
caller.jump(
this->caller_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
BOOST_ASSERT( hldr_from->data);
// create pull_coroutine
Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_, hldr_from->data);
try
{ fn_( c); }
catch ( forced_unwind const&)
{}
catch (...)
{ this->except_ = current_exception(); }
callee = c.impl_->callee_;
}
this->flags_ |= flag_complete;
holder< Arg * > hldr_to( & caller);
caller.jump(
callee,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class push_coroutine_object< void, Fn, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public push_coroutine_base< void >
{
public:
typedef typename Allocator::template rebind<
push_coroutine_object<
void, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef push_coroutine_base< void > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, push_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
push_coroutine_object( push_coroutine_object &);
push_coroutine_object & operator=( push_coroutine_object const&);
void enter_()
{
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( this),
this->preserve_fpu() ) ) );
this->callee_ = * hldr_from->ctx;
if ( this->except_) rethrow_exception( this->except_);
}
void unwind_stack_() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! this->is_complete() );
this->flags_ |= flag_unwind_stack;
holder< void > hldr_to( & this->caller_, true);
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
this->flags_ &= ~flag_unwind_stack;
BOOST_ASSERT( this->is_complete() );
}
public:
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
push_coroutine_object( Fn && fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( forward< Fn >( fn) ),
alloc_( alloc)
{ enter_(); }
#else
push_coroutine_object( Fn fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
#endif
~push_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
holder< void > hldr_to( & caller);
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
caller.jump(
this->caller_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
// create pull_coroutine
Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_);
try
{ fn_( c); }
catch ( forced_unwind const&)
{}
catch (...)
{ this->except_ = current_exception(); }
callee = c.impl_->callee_;
}
this->flags_ |= flag_complete;
holder< void > hldr_to( & caller);
caller.jump(
callee,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class push_coroutine_object< void, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public push_coroutine_base< void >
{
public:
typedef typename Allocator::template rebind<
push_coroutine_object<
void, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef push_coroutine_base< void > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, push_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
push_coroutine_object( push_coroutine_object &);
push_coroutine_object & operator=( push_coroutine_object const&);
void enter_()
{
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( this),
this->preserve_fpu() ) ) );
this->callee_ = * hldr_from->ctx;
if ( this->except_) rethrow_exception( this->except_);
}
void unwind_stack_() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! this->is_complete() );
this->flags_ |= flag_unwind_stack;
holder< void > hldr_to( & this->caller_, true);
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
this->flags_ &= ~flag_unwind_stack;
BOOST_ASSERT( this->is_complete() );
}
public:
push_coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
~push_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
holder< void > hldr_to( & caller);
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
caller.jump(
this->caller_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
// create pull_coroutine
Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_);
try
{ fn_( c); }
catch ( forced_unwind const&)
{}
catch (...)
{ this->except_ = current_exception(); }
callee = c.impl_->callee_;
}
this->flags_ |= flag_complete;
holder< void > hldr_to( & caller);
caller.jump(
callee,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class push_coroutine_object< void, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public push_coroutine_base< void >
{
public:
typedef typename Allocator::template rebind<
push_coroutine_object<
void, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef push_coroutine_base< void > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, push_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
push_coroutine_object( push_coroutine_object &);
push_coroutine_object & operator=( push_coroutine_object const&);
void enter_()
{
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( this),
this->preserve_fpu() ) ) );
this->callee_ = * hldr_from->ctx;
if ( this->except_) rethrow_exception( this->except_);
}
void unwind_stack_() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! this->is_complete() );
this->flags_ |= flag_unwind_stack;
holder< void > hldr_to( & this->caller_, true);
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
this->flags_ &= ~flag_unwind_stack;
BOOST_ASSERT( this->is_complete() );
}
public:
push_coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< push_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
~push_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
holder< void > hldr_to( & caller);
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
caller.jump(
this->caller_,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
// create pull_coroutine
Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_);
try
{ fn_( c); }
catch ( forced_unwind const&)
{}
catch (...)
{ this->except_ = current_exception(); }
callee = c.impl_->callee_;
}
this->flags_ |= flag_complete;
holder< void > hldr_to( & caller);
caller.jump(
callee,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#ifdef BOOST_MSVC
#pragma warning (pop)
#endif
#endif // BOOST_COROUTINES_UNIDIRECT_DETAIL_PUSH_COROUTINE_OBJECT_H