coroutine: activate new interface V2

[SVN r84428]
This commit is contained in:
Oliver Kowalke 2013-05-22 20:15:43 +00:00
parent bcae158775
commit ce1270c353
25 changed files with 5903 additions and 179 deletions

View File

@ -69,18 +69,18 @@ exe same_fringe
: same_fringe.cpp
;
exe asio/stream_client
: asio/stream_client.cpp
;
#exe asio/stream_client
# : asio/stream_client.cpp
# ;
#
#exe asio/stream_server
# : asio/stream_server.cpp
# ;
exe asio/stream_server
: asio/stream_server.cpp
;
#exe same_fringe
#exe same_fringe11
# : c++11/same_fringe.cpp
# ;
#
#exe fibonacci
#exe fibonacci11
# : c++11/fibonacci.cpp
# ;

View File

@ -9,6 +9,29 @@
#include <boost/coroutine/all.hpp>
#ifdef BOOST_COROUTINES_V2
int main()
{
boost::coroutines::pull_coroutine< int > c(
[&]( boost::coroutines::push_coroutine< int > & c) {
int first = 1, second = 1;
for ( int i = 0; i < 10; ++i)
{
int third = first + second;
first = second;
second = third;
c( third);
}
});
for ( auto i : c)
std::cout << i << " ";
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}
#else
int main()
{
boost::coroutines::coroutine< int() > c(
@ -30,3 +53,4 @@ int main()
return EXIT_SUCCESS;
}
#endif

View File

@ -10,6 +10,71 @@
#include "tree.h"
node::ptr_t create_tree1()
{
return branch::create(
leaf::create( "A"),
branch::create(
leaf::create( "B"),
leaf::create( "C") ) );
}
node::ptr_t create_tree2()
{
return branch::create(
branch::create(
leaf::create( "A"),
leaf::create( "B") ),
leaf::create( "C") );
}
#ifdef BOOST_COROUTINES_V2
class coro_visitor : public visitor
{
private:
boost::coroutines::push_coroutine< leaf& > & c_;
public:
coro_visitor( boost::coroutines::push_coroutine< leaf& > & c) :
c_( c)
{}
void visit( branch & b)
{
if ( b.left) b.left->accept( * this);
if ( b.right) b.right->accept( * this);
}
void visit( leaf & l)
{ c_( l); }
};
int main()
{
node::ptr_t t1 = create_tree1();
boost::coroutines::pull_coroutine< leaf& > c1(
[&]( boost::coroutines::push_coroutine< leaf & > & c) {
coro_visitor v( c);
t1->accept( v);
});
node::ptr_t t2 = create_tree2();
boost::coroutines::pull_coroutine< leaf& > c2(
[&]( boost::coroutines::push_coroutine< leaf & > & c) {
coro_visitor v( c);
t2->accept( v);
});
bool result = std::equal(
boost::begin( c1),
boost::end( c1),
boost::begin( c2) );
std::cout << std::boolalpha << "same fringe == " << result << "\nDone" << std::endl;
return EXIT_SUCCESS;
}
#else
class coro_visitor : public visitor
{
private:
@ -30,24 +95,6 @@ public:
{ c_( l); }
};
node::ptr_t create_tree1()
{
return branch::create(
leaf::create( "A"),
branch::create(
leaf::create( "B"),
leaf::create( "C") ) );
}
node::ptr_t create_tree2()
{
return branch::create(
branch::create(
leaf::create( "A"),
leaf::create( "B") ),
leaf::create( "C") );
}
int main()
{
node::ptr_t t1 = create_tree1();
@ -73,3 +120,4 @@ int main()
return EXIT_SUCCESS;
}
#endif

View File

@ -10,6 +10,43 @@
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
#ifdef BOOST_COROUTINES_V2
typedef boost::coroutines::pull_coroutine< void > pull_coro_t;
typedef boost::coroutines::push_coroutine< void > push_coro_t;
void echo( pull_coro_t & c, int i)
{
std::cout << i;
c();
}
void runit( push_coro_t & ca)
{
std::cout << "started! ";
for ( int i = 0; i < 10; ++i)
{
push_coro_t c( boost::bind( echo, _1, i) );
while ( c)
c();
ca();
}
}
int main( int argc, char * argv[])
{
{
pull_coro_t c( runit);
while ( c) {
std::cout << "-";
c();
}
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}
#else
typedef boost::coroutines::coroutine< void() > coro_t;
void echo( coro_t & ca, int i)
@ -44,3 +81,4 @@ int main( int argc, char * argv[])
return EXIT_SUCCESS;
}
#endif

View File

@ -10,7 +10,8 @@
#include <boost/range.hpp>
#include <boost/coroutine/all.hpp>
void fibonacci( boost::coroutines::coroutine< void( int) > & c)
#ifdef BOOST_COROUTINES_V2
void fibonacci( boost::coroutines::push_coroutine< int > & c)
{
int first = 1, second = 1;
while ( true)
@ -22,6 +23,35 @@ void fibonacci( boost::coroutines::coroutine< void( int) > & c)
}
}
int main()
{
boost::coroutines::pull_coroutine< int > c( fibonacci);
boost::range_iterator<
boost::coroutines::pull_coroutine< int >
>::type it( boost::begin( c) );
for ( int i = 0; i < 10; ++i)
{
std::cout << * it << " ";
++it;
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}
#else
void fibonacci( boost::coroutines::coroutine< void( int) > & c)
{
int first = 1, second = 1;
while ( true)
{
int third = first + second;
first = second;
second = third;
c( third);
}
}
int main()
{
boost::coroutines::coroutine< int() > c( fibonacci);
@ -38,35 +68,4 @@ int main()
return EXIT_SUCCESS;
}
// C++11
#if 0
int main()
{
boost::coroutines::coroutine< int() > c(
[&]( boost::coroutines::coroutine< void( int) > & c) {
int first = 1, second = 1;
while ( true)
{
int third = first + second;
first = second;
second = third;
c( third);
}
});
boost::range_iterator<
boost::coroutines::coroutine< int() >
>::type it( boost::begin( c) );
for ( int i = 0; i < 10; ++i)
{
std::cout << * it << " ";
++it;
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}
#endif

View File

@ -10,6 +10,45 @@
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
#ifdef BOOST_COROUTINES_V2
void first( boost::coroutines::push_coroutine< void > & c)
{
std::cout << "started first! ";
for ( int i = 0; i < 10; ++i)
{
c();
std::cout << "a" << i;
}
}
void second( boost::coroutines::push_coroutine< void > & c)
{
std::cout << "started second! ";
for ( int i = 0; i < 10; ++i)
{
c();
std::cout << "b" << i;
}
}
int main( int argc, char * argv[])
{
{
boost::coroutines::pull_coroutine< void > c1( boost::bind( first, _1) );
boost::coroutines::pull_coroutine< void > c2( boost::bind( second, _1) );
while ( c1 && c2) {
c1();
std::cout << " ";
c2();
std::cout << " ";
}
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}
#else
typedef boost::coroutines::coroutine< void() > coroutine_t;
void first( coroutine_t::caller_type & self)
@ -49,3 +88,4 @@ int main( int argc, char * argv[])
return EXIT_SUCCESS;
}
#endif

View File

@ -12,6 +12,41 @@
#include <boost/range.hpp>
#include <boost/coroutine/all.hpp>
#ifdef BOOST_COROUTINES_V2
void power( boost::coroutines::push_coroutine< int > & c, int number, int exponent)
{
int counter = 0;
int result = 1;
while ( counter++ < exponent)
{
result = result * number;
c( result);
}
}
int main()
{
{
std::cout << "using range functions" << std::endl;
boost::coroutines::pull_coroutine< int > c( boost::bind( power, _1, 2, 8) );
boost::coroutines::pull_coroutine< int >::iterator e( boost::end( c) );
for ( boost::coroutines::pull_coroutine< int >::iterator i( boost::begin( c) );
i != e; ++i)
std::cout << * i << " ";
}
{
std::cout << "\nusing BOOST_FOREACH" << std::endl;
boost::coroutines::pull_coroutine< int > c( boost::bind( power, _1, 2, 8) );
BOOST_FOREACH( int i, c)
{ std::cout << i << " "; }
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}
#else
typedef boost::coroutines::coroutine< int() > coro1_t;
typedef boost::coroutines::coroutine< void( int) > coro2_t;
typedef boost::range_iterator< coro1_t >::type iterator_t;
@ -48,45 +83,4 @@ int main()
return EXIT_SUCCESS;
}
#if 0
int main()
{
{
std::cout << "using range functions" << std::endl;
boost::coroutines::coroutine< int() > c(
[&]( boost::coroutines::coroutine< void( int) > &c) {
int counter = 0;
int result = 1;
while ( counter++ < 8)
{
result = result * 2;
c( result);
}
});
iterator_t e( boost::end( c) );
for ( iterator_t i( boost::begin( c) ); i != e; ++i)
std::cout << * i << " ";
}
{
std::cout << "\nusing BOOST_FOREACH" << std::endl;
boost::coroutines::coroutine< int() > c(
[&]( boost::coroutines::coroutine< void( int) > &c) {
int counter = 0;
int result = 1;
while ( counter++ < 8)
{
result = result * 2;
c( result);
}
});
for ( int i : c) {
std::cout << i << " ";
}
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}
#endif

View File

@ -15,15 +15,6 @@
#include "tree.h"
bool match_trees( coro_t & c1, coro_t & c2)
{
typedef boost::range_iterator< coro_t >::type iterator_t;
iterator_t i1( boost::begin( c1) );
iterator_t e1( boost::end( c1) );
iterator_t i2( boost::begin( c2) );
return std::equal( i1, e1, i2);
}
std::pair< node::ptr_t, node::ptr_t > create_eq_trees()
{
branch::ptr_t tree1 = branch::create(
@ -58,6 +49,48 @@ std::pair< node::ptr_t, node::ptr_t > create_diff_trees()
return std::make_pair( tree1, tree2);
}
#ifdef BOOST_COROUTINES_V2
bool match_trees( boost::coroutines::pull_coroutine< leaf & > & c1,
boost::coroutines::pull_coroutine< leaf & > & c2)
{
typedef boost::range_iterator< boost::coroutines::pull_coroutine< leaf & > >::type iterator_t;
iterator_t i1( boost::begin( c1) );
iterator_t e1( boost::end( c1) );
iterator_t i2( boost::begin( c2) );
return std::equal( i1, e1, i2);
}
int main()
{
{
std::pair< node::ptr_t, node::ptr_t > pt = create_eq_trees();
boost::coroutines::pull_coroutine< leaf & > te1( boost::bind( enumerate_leafs, _1, pt.first) );
boost::coroutines::pull_coroutine< leaf & > te2( boost::bind( enumerate_leafs, _1, pt.second) );
bool result = match_trees( te1, te2);
std::cout << std::boolalpha << "eq. trees matched == " << result << std::endl;
}
{
std::pair< node::ptr_t, node::ptr_t > pt = create_diff_trees();
boost::coroutines::pull_coroutine< leaf & > te1( boost::bind( enumerate_leafs, _1, pt.first) );
boost::coroutines::pull_coroutine< leaf & > te2( boost::bind( enumerate_leafs, _1, pt.second) );
bool result = match_trees( te1, te2);
std::cout << std::boolalpha << "diff. trees matched == " << result << std::endl;
}
std::cout << "Done" << std::endl;
return EXIT_SUCCESS;
}
#else
bool match_trees( coro_t & c1, coro_t & c2)
{
typedef boost::range_iterator< coro_t >::type iterator_t;
iterator_t i1( boost::begin( c1) );
iterator_t e1( boost::end( c1) );
iterator_t i2( boost::begin( c2) );
return std::equal( i1, e1, i2);
}
int main()
{
{
@ -79,3 +112,4 @@ int main()
return EXIT_SUCCESS;
}
#endif

View File

@ -10,8 +10,6 @@
#include <boost/coroutine/all.hpp>
#include <boost/thread.hpp>
typedef boost::coroutines::coroutine< void() > coro_t;
int count = 20;
void access( char *buf) __attribute__ ((noinline));
@ -19,6 +17,7 @@ void access( char *buf)
{
buf[0] = '\0';
}
void bar( int i)
{
char buf[4 * 1024];
@ -31,6 +30,23 @@ void bar( int i)
}
}
#ifdef BOOST_COROUTINES_V2
void foo( boost::coroutines::pull_coroutine< void > & c)
{
bar( count);
c();
}
void thread_fn()
{
{
boost::coroutines::push_coroutine< void > c( foo);
c();
}
}
#else
typedef boost::coroutines::coroutine< void() > coro_t;
void foo( coro_t & c)
{
bar( count);
@ -42,9 +58,9 @@ void thread_fn()
{
coro_t c( foo);
c();
int i = 7;
}
}
#endif
int main( int argc, char * argv[])
{

View File

@ -91,6 +91,33 @@ inline
bool operator!=( leaf const& l, leaf const& r)
{ return l.value != r.value; }
#ifdef BOOST_COROUTINES_V2
class tree_visitor : public visitor
{
private:
boost::coroutines::push_coroutine< leaf & > & c_;
public:
tree_visitor( boost::coroutines::push_coroutine< leaf & > & c) :
c_( c)
{}
void visit( branch & b)
{
if ( b.left) b.left->accept( * this);
if ( b.right) b.right->accept( * this);
}
void visit( leaf & l)
{ c_( l); }
};
void enumerate_leafs( boost::coroutines::push_coroutine< leaf & > & c, node::ptr_t root)
{
tree_visitor v( c);
root->accept( v);
}
#else
typedef boost::coroutines::coroutine< leaf&() > coro_t;
class tree_visitor : public visitor
@ -118,6 +145,7 @@ void enumerate_leafs( coro_t::caller_type & c, node::ptr_t root)
tree_visitor v( c);
root->accept( v);
}
#endif
# if defined(BOOST_MSVC)
# pragma warning(pop)

View File

@ -10,6 +10,40 @@
#include <boost/bind.hpp>
#include <boost/coroutine/all.hpp>
#ifdef BOOST_COROUTINES_V2
struct X : private boost::noncopyable
{
X() { std::cout << "X()" << std::endl; }
~X() { std::cout << "~X()" << std::endl; }
};
void fn( boost::coroutines::push_coroutine< void > & c)
{
X x;
int i = 0;
while ( true)
{
std::cout << "fn() : " << ++i << std::endl;
c();
}
}
int main( int argc, char * argv[])
{
{
boost::coroutines::pull_coroutine< void > c( fn);
for ( int k = 0; k < 3; ++k)
{
c();
}
std::cout << "destroying coroutine and unwinding stack" << std::endl;
}
std::cout << "\nDone" << std::endl;
return EXIT_SUCCESS;
}
#else
typedef boost::coroutines::coroutine< void() > coro_t;
struct X : private boost::noncopyable
@ -44,3 +78,4 @@ int main( int argc, char * argv[])
return EXIT_SUCCESS;
}
#endif

View File

@ -46,8 +46,8 @@
# define BOOST_COROUTINES_SEGMENTS 10
#endif
//#ifndef BOOST_COROUTINES_V1
//# define BOOST_COROUTINES_V2
//#endif
#ifndef BOOST_COROUTINES_V1
# define BOOST_COROUTINES_V2
#endif
#endif // BOOST_COROUTINES_DETAIL_CONFIG_H

View File

@ -4,8 +4,8 @@
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_COROUTINES_DETAIL_EXCEPTIONs_H
#define BOOST_COROUTINES_DETAIL_EXCEPTIONs_H
#ifndef BOOST_COROUTINES_DETAIL_EXCEPTIONS_H
#define BOOST_COROUTINES_DETAIL_EXCEPTIONS_H
#include <boost/config.hpp>
@ -25,4 +25,4 @@ struct forced_unwind {};
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES_DETAIL_EXCEPTIONs_H
#endif // BOOST_COROUTINES_DETAIL_EXCEPTIONS_H

View File

@ -0,0 +1,47 @@
// 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_DETAIL_STACK_TUPLE_H
#define BOOST_COROUTINES_DETAIL_STACK_TUPLE_H
#include <cstddef>
#include <boost/config.hpp>
#include <boost/coroutine/detail/config.hpp>
#include <boost/coroutine/stack_context.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace coroutines {
namespace detail {
template< typename StackAllocator >
struct stack_tuple
{
coroutines::stack_context stack_ctx;
StackAllocator stack_alloc;
stack_tuple( StackAllocator const& stack_alloc_, std::size_t size) :
stack_ctx(),
stack_alloc( stack_alloc_)
{ stack_alloc.allocate( stack_ctx, size); }
~stack_tuple()
{ stack_alloc.deallocate( stack_ctx); }
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES_DETAIL_STACK_TUPLE_H

View File

@ -0,0 +1,52 @@
// 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_DETAIL_TRAMPOLINE_H
#define BOOST_COROUTINES_DETAIL_TRAMPOLINE_H
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/tuple/tuple.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace coroutines {
namespace detail {
template< typename Coroutine >
void trampoline1( intptr_t vp)
{
BOOST_ASSERT( vp);
reinterpret_cast< Coroutine * >( vp)->run();
}
template< typename Coroutine, typename Arg >
void trampoline2( intptr_t vp)
{
BOOST_ASSERT( vp);
tuple< Coroutine *, Arg > * tpl(
reinterpret_cast< tuple< Coroutine *, Arg > * >( vp) );
Coroutine * coro( get< 0 >( * tpl) );
Arg arg( get< 1 >( * tpl) );
coro->run( arg);
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES_DETAIL_TRAMPOLINE_H

View File

@ -25,8 +25,11 @@
#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/stack_context.hpp>
#include <boost/coroutine/v1/detail/arg.hpp>
#include <boost/coroutine/v1/detail/coroutine_base.hpp>
@ -43,46 +46,6 @@ namespace boost {
namespace coroutines {
namespace detail {
template< typename Coroutine >
void trampoline1( intptr_t vp)
{
BOOST_ASSERT( vp);
reinterpret_cast< Coroutine * >( vp)->run();
}
template< typename Coroutine, typename Arg >
void trampoline2( intptr_t vp)
{
BOOST_ASSERT( vp);
tuple< Coroutine *, Arg > * tpl(
reinterpret_cast< tuple< Coroutine *, Arg > * >( vp) );
Coroutine * coro( get< 0 >( * tpl) );
Arg arg( get< 1 >( * tpl) );
coro->run( arg);
}
template< typename StackAllocator >
struct stack_tuple
{
coroutines::stack_context stack_ctx;
StackAllocator stack_alloc;
stack_tuple( StackAllocator const& stack_alloc_, std::size_t size) :
stack_ctx(),
stack_alloc( stack_alloc_)
{
stack_alloc.allocate( stack_ctx, size);
}
~stack_tuple()
{
stack_alloc.deallocate( stack_ctx);
}
};
template<
typename Signature,
typename Fn, typename StackAllocator, typename Allocator,

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,232 @@
// 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_V2_DETAIL_PULL_COROUTINE_BASE_H
#define BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_BASE_H
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/context/fcontext.hpp>
#include <boost/exception_ptr.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/type_traits/function_traits.hpp>
#include <boost/utility.hpp>
#include <boost/coroutine/detail/config.hpp>
#include <boost/coroutine/detail/coroutine_context.hpp>
#include <boost/coroutine/detail/flags.hpp>
#include <boost/coroutine/detail/holder.hpp>
#include <boost/coroutine/detail/param.hpp>
#include <boost/coroutine/detail/exceptions.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace coroutines {
struct stack_context;
namespace detail {
template< typename R >
class pull_coroutine_base : private noncopyable
{
public:
typedef intrusive_ptr< pull_coroutine_base > ptr_t;
private:
template<
typename X, typename Y, typename Z, typename V, typename W
>
friend class push_coroutine_object;
unsigned int use_count_;
protected:
int flags_;
exception_ptr except_;
coroutine_context caller_;
coroutine_context callee_;
optional< R > result_;
virtual void deallocate_object() = 0;
public:
pull_coroutine_base( coroutine_context::ctx_fn fn,
stack_context * stack_ctx,
bool unwind, bool preserve_fpu) :
use_count_( 0),
flags_( 0),
except_(),
caller_(),
callee_( fn, stack_ctx),
result_()
{
if ( unwind) flags_ |= flag_force_unwind;
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
}
pull_coroutine_base( coroutine_context const& callee,
bool unwind, bool preserve_fpu,
optional< R > const& result) :
use_count_( 0),
flags_( 0),
except_(),
caller_(),
callee_( callee),
result_( result)
{
if ( unwind) flags_ |= flag_force_unwind;
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
}
virtual ~pull_coroutine_base()
{}
bool force_unwind() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_force_unwind); }
bool unwind_requested() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_unwind_stack); }
bool preserve_fpu() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_preserve_fpu); }
bool is_complete() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_complete); }
friend inline void intrusive_ptr_add_ref( pull_coroutine_base * p) BOOST_NOEXCEPT
{ ++p->use_count_; }
friend inline void intrusive_ptr_release( pull_coroutine_base * p) BOOST_NOEXCEPT
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
void pull()
{
BOOST_ASSERT( ! is_complete() );
holder< R > hldr_to( & caller_);
holder< R > * hldr_from(
reinterpret_cast< holder< R > * >(
hldr_to.ctx->jump(
callee_,
reinterpret_cast< intptr_t >( & hldr_to),
preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
callee_ = * hldr_from->ctx;
result_ = hldr_from->data;
if ( hldr_from->force_unwind) throw forced_unwind();
if ( except_) rethrow_exception( except_);
}
bool has_result() const
{ return result_; }
R get() const
{
BOOST_ASSERT( has_result() );
return result_.get();
}
};
template<>
class pull_coroutine_base< void > : private noncopyable
{
public:
typedef intrusive_ptr< pull_coroutine_base > ptr_t;
private:
template<
typename X, typename Y, typename Z, typename V, typename W
>
friend class push_coroutine_object;
unsigned int use_count_;
protected:
int flags_;
exception_ptr except_;
coroutine_context caller_;
coroutine_context callee_;
virtual void deallocate_object() = 0;
public:
pull_coroutine_base( coroutine_context::ctx_fn fn,
stack_context * stack_ctx,
bool unwind, bool preserve_fpu) :
use_count_( 0),
flags_( 0),
except_(),
caller_(),
callee_( fn, stack_ctx)
{
if ( unwind) flags_ |= flag_force_unwind;
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
}
pull_coroutine_base( coroutine_context const& callee,
bool unwind, bool preserve_fpu) :
use_count_( 0),
flags_( 0),
except_(),
caller_(),
callee_( callee)
{
if ( unwind) flags_ |= flag_force_unwind;
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
}
virtual ~pull_coroutine_base()
{}
bool force_unwind() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_force_unwind); }
bool unwind_requested() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_unwind_stack); }
bool preserve_fpu() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_preserve_fpu); }
bool is_complete() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_complete); }
friend inline void intrusive_ptr_add_ref( pull_coroutine_base * p) BOOST_NOEXCEPT
{ ++p->use_count_; }
friend inline void intrusive_ptr_release( pull_coroutine_base * p) BOOST_NOEXCEPT
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
void pull()
{
BOOST_ASSERT( ! is_complete() );
holder< void > hldr_to( & caller_);
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
hldr_to.ctx->jump(
callee_,
reinterpret_cast< intptr_t >( & hldr_to),
preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
callee_ = * hldr_from->ctx;
if ( hldr_from->force_unwind) throw forced_unwind();
if ( except_) rethrow_exception( except_);
}
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_BASE_H

View File

@ -0,0 +1,84 @@
// 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_V2_DETAIL_PULL_COROUTINE_CALLER_H
#define BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_CALLER_H
#include <boost/config.hpp>
#include <boost/context/fcontext.hpp>
#include <boost/optional.hpp>
#include <boost/coroutine/detail/config.hpp>
#include <boost/coroutine/v2/detail/pull_coroutine_base.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace coroutines {
namespace detail {
template< typename R, typename Allocator >
class pull_coroutine_caller : public pull_coroutine_base< R >
{
public:
typedef typename Allocator::template rebind<
pull_coroutine_caller< R, Allocator >
>::other allocator_t;
pull_coroutine_caller( coroutine_context const& callee, bool unwind, bool preserve_fpu,
allocator_t const& alloc, optional< R > const& data) BOOST_NOEXCEPT :
pull_coroutine_base< R >( callee, unwind, preserve_fpu, data),
alloc_( alloc)
{}
void deallocate_object()
{ destroy_( alloc_, this); }
private:
allocator_t alloc_;
static void destroy_( allocator_t & alloc, pull_coroutine_caller * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
};
template< typename Allocator >
class pull_coroutine_caller< void, Allocator > : public pull_coroutine_base< void >
{
public:
typedef typename Allocator::template rebind<
pull_coroutine_caller< void, Allocator >
>::other allocator_t;
pull_coroutine_caller( coroutine_context const& callee, bool unwind, bool preserve_fpu,
allocator_t const& alloc) BOOST_NOEXCEPT :
pull_coroutine_base< void >( callee, unwind, preserve_fpu),
alloc_( alloc)
{}
void deallocate_object()
{ destroy_( alloc_, this); }
private:
allocator_t alloc_;
static void destroy_( allocator_t & alloc, pull_coroutine_caller * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_CALLER_H

View File

@ -0,0 +1,768 @@
// 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_V2_DETAIL_PULL_COROUTINE_OBJECT_H
#define BOOST_COROUTINES_V2_DETAIL_PULL_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/detail/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/pull_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 R, typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class pull_coroutine_object : private stack_tuple< StackAllocator >,
public pull_coroutine_base< R >
{
public:
typedef typename Allocator::template rebind<
pull_coroutine_object<
R, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef pull_coroutine_base< R > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
pull_coroutine_object( pull_coroutine_object &);
pull_coroutine_object & operator=( pull_coroutine_object const&);
void enter_()
{
holder< R > * hldr_from(
reinterpret_cast< holder< R > * >(
this->caller_.jump(
this->callee_,
reinterpret_cast< intptr_t >( this),
this->preserve_fpu() ) ) );
this->callee_ = * hldr_from->ctx;
this->result_ = hldr_from->data;
if ( this->except_) rethrow_exception( this->except_);
}
void unwind_stack_() BOOST_NOEXCEPT
{
BOOST_ASSERT( ! this->is_complete() );
this->flags_ |= flag_unwind_stack;
holder< R > 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
pull_coroutine_object( Fn && fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< pull_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( forward< Fn >( fn) ),
alloc_( alloc)
{ enter_(); }
#else
pull_coroutine_object( Fn fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< pull_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
pull_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< pull_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
#endif
~pull_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
// create push_coroutine
Caller c( this->caller_, 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< R > hldr_to( & caller);
caller.jump(
callee,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename R, typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class pull_coroutine_object< R, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public pull_coroutine_base< R >
{
public:
typedef typename Allocator::template rebind<
pull_coroutine_object<
R, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef pull_coroutine_base< R > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
pull_coroutine_object( pull_coroutine_object &);
pull_coroutine_object & operator=( pull_coroutine_object const&);
void enter_()
{
holder< R > * hldr_from(
reinterpret_cast< holder< R > * >(
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< R > 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:
pull_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< pull_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
~pull_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
// create pull_coroutine
Caller c( this->caller_, 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< R > hldr_to( & caller);
caller.jump(
callee,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename R, typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class pull_coroutine_object< R, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public pull_coroutine_base< R >
{
public:
typedef typename Allocator::template rebind<
pull_coroutine_object<
R, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef pull_coroutine_base< R > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
pull_coroutine_object( pull_coroutine_object &);
pull_coroutine_object & operator=( pull_coroutine_object const&);
void enter_()
{
holder< R > * hldr_from(
reinterpret_cast< holder< R > * >(
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< R > 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:
pull_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< pull_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
~pull_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
// create pull_coroutine
Caller c( this->caller_, 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< R > hldr_to( & caller);
caller.jump(
callee,
reinterpret_cast< intptr_t >( & hldr_to),
this->preserve_fpu() );
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class pull_coroutine_object< void, Fn, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public pull_coroutine_base< void >
{
public:
typedef typename Allocator::template rebind<
pull_coroutine_object<
void, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef pull_coroutine_base< void > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
pull_coroutine_object( pull_coroutine_object &);
pull_coroutine_object & operator=( pull_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
pull_coroutine_object( Fn && fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< pull_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( forward< Fn >( fn) ),
alloc_( alloc)
{ enter_(); }
#else
pull_coroutine_object( Fn fn, attributes const& attr,
StackAllocator const& stack_alloc,
allocator_t const& alloc) :
pbase_type( stack_alloc, attr.size),
base_type(
trampoline1< pull_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
pull_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< pull_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
#endif
~pull_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
// create push_coroutine
Caller c( this->caller_, 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, "pull_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class pull_coroutine_object< void, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public pull_coroutine_base< void >
{
public:
typedef typename Allocator::template rebind<
pull_coroutine_object<
void, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef pull_coroutine_base< void > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
pull_coroutine_object( pull_coroutine_object &);
pull_coroutine_object & operator=( pull_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:
pull_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< pull_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
~pull_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
// create pull_coroutine
Caller c( this->caller_, 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, "pull_coroutine is complete");
}
void deallocate_object()
{ destroy_( alloc_, this); }
};
template<
typename Fn,
typename StackAllocator, typename Allocator,
typename Caller
>
class pull_coroutine_object< void, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
private stack_tuple< StackAllocator >,
public pull_coroutine_base< void >
{
public:
typedef typename Allocator::template rebind<
pull_coroutine_object<
void, Fn, StackAllocator, Allocator, Caller
>
>::other allocator_t;
private:
typedef stack_tuple< StackAllocator > pbase_type;
typedef pull_coroutine_base< void > base_type;
Fn fn_;
allocator_t alloc_;
static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
pull_coroutine_object( pull_coroutine_object &);
pull_coroutine_object & operator=( pull_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:
pull_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< pull_coroutine_object >,
& this->stack_ctx,
stack_unwind == attr.do_unwind,
fpu_preserved == attr.preserve_fpu),
fn_( fn),
alloc_( alloc)
{ enter_(); }
~pull_coroutine_object()
{
if ( ! this->is_complete() && this->force_unwind() )
unwind_stack_();
}
void run()
{
coroutine_context callee;
coroutine_context caller;
{
// create pull_coroutine
Caller c( this->caller_, 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, "pull_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_V2_DETAIL_PULL_COROUTINE_OBJECT_H

View File

@ -0,0 +1,441 @@
// 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_V2_DETAIL_PUSH_COROUTINE_BASE_H
#define BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_BASE_H
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/context/fcontext.hpp>
#include <boost/exception_ptr.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/type_traits/function_traits.hpp>
#include <boost/utility.hpp>
#include <boost/coroutine/detail/config.hpp>
#include <boost/coroutine/detail/coroutine_context.hpp>
#include <boost/coroutine/detail/exceptions.hpp>
#include <boost/coroutine/detail/flags.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace coroutines {
struct stack_context;
namespace detail {
template< typename Arg >
class push_coroutine_base : private noncopyable
{
public:
typedef intrusive_ptr< push_coroutine_base > ptr_t;
private:
template<
typename X, typename Y, typename Z, typename V, typename W
>
friend class pull_coroutine_object;
unsigned int use_count_;
protected:
int flags_;
exception_ptr except_;
coroutine_context caller_;
coroutine_context callee_;
virtual void deallocate_object() = 0;
public:
push_coroutine_base( coroutine_context::ctx_fn fn,
stack_context * stack_ctx,
bool unwind, bool preserve_fpu) :
use_count_( 0),
flags_( 0),
except_(),
caller_(),
callee_( fn, stack_ctx)
{
if ( unwind) flags_ |= flag_force_unwind;
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
}
push_coroutine_base( coroutine_context const& callee,
bool unwind, bool preserve_fpu) :
use_count_( 0),
flags_( 0),
except_(),
caller_(),
callee_( callee)
{
if ( unwind) flags_ |= flag_force_unwind;
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
}
virtual ~push_coroutine_base()
{}
bool force_unwind() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_force_unwind); }
bool unwind_requested() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_unwind_stack); }
bool preserve_fpu() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_preserve_fpu); }
bool is_complete() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_complete); }
friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT
{ ++p->use_count_; }
friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
void push( Arg const& arg)
{
BOOST_ASSERT( ! is_complete() );
holder< Arg > hldr_to( & caller_, arg);
holder< Arg > * hldr_from(
reinterpret_cast< holder< Arg > * >(
hldr_to.ctx->jump(
callee_,
reinterpret_cast< intptr_t >( & hldr_to),
preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
callee_ = * hldr_from->ctx;
if ( hldr_from->force_unwind) throw forced_unwind();
if ( except_) rethrow_exception( except_);
}
void push( Arg && arg)
{
BOOST_ASSERT( ! is_complete() );
holder< Arg > hldr_to( & caller_, arg);
holder< Arg > * hldr_from(
reinterpret_cast< holder< Arg > * >(
hldr_to.ctx->jump(
callee_,
reinterpret_cast< intptr_t >( & hldr_to),
preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
callee_ = * hldr_from->ctx;
if ( hldr_from->force_unwind) throw forced_unwind();
if ( except_) rethrow_exception( except_);
}
#else
void push( Arg arg)
{
BOOST_ASSERT( ! is_complete() );
holder< Arg > hldr_to( & caller_, arg);
holder< Arg > * hldr_from(
reinterpret_cast< holder< Arg > * >(
hldr_to.ctx->jump(
callee_,
reinterpret_cast< intptr_t >( & hldr_to),
preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
callee_ = * hldr_from->ctx;
if ( hldr_from->force_unwind) throw forced_unwind();
if ( except_) rethrow_exception( except_);
}
void push( BOOST_RV_REF( Arg) arg)
{
BOOST_ASSERT( ! is_complete() );
holder< Arg > hldr_to( & caller_, arg);
holder< Arg > * hldr_from(
reinterpret_cast< holder< Arg > * >(
hldr_to.ctx->jump(
callee_,
reinterpret_cast< intptr_t >( & hldr_to),
preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
callee_ = * hldr_from->ctx;
if ( hldr_from->force_unwind) throw forced_unwind();
if ( except_) rethrow_exception( except_);
}
#endif
};
template< typename Arg >
class push_coroutine_base< Arg & > : private noncopyable
{
public:
typedef intrusive_ptr< push_coroutine_base > ptr_t;
private:
template<
typename X, typename Y, typename Z, typename V, typename W
>
friend class pull_coroutine_object;
unsigned int use_count_;
protected:
int flags_;
exception_ptr except_;
coroutine_context caller_;
coroutine_context callee_;
virtual void deallocate_object() = 0;
public:
push_coroutine_base( coroutine_context::ctx_fn fn,
stack_context * stack_ctx,
bool unwind, bool preserve_fpu) :
use_count_( 0),
flags_( 0),
except_(),
caller_(),
callee_( fn, stack_ctx)
{
if ( unwind) flags_ |= flag_force_unwind;
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
}
push_coroutine_base( coroutine_context const& callee,
bool unwind, bool preserve_fpu) :
use_count_( 0),
flags_( 0),
except_(),
caller_(),
callee_( callee)
{
if ( unwind) flags_ |= flag_force_unwind;
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
}
virtual ~push_coroutine_base()
{}
bool force_unwind() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_force_unwind); }
bool unwind_requested() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_unwind_stack); }
bool preserve_fpu() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_preserve_fpu); }
bool is_complete() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_complete); }
friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT
{ ++p->use_count_; }
friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
void push( Arg & arg)
{
BOOST_ASSERT( ! is_complete() );
holder< Arg & > hldr_to( & caller_, arg);
holder< Arg & > * hldr_from(
reinterpret_cast< holder< Arg & > * >(
hldr_to.ctx->jump(
callee_,
reinterpret_cast< intptr_t >( & hldr_to),
preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
callee_ = * hldr_from->ctx;
if ( hldr_from->force_unwind) throw forced_unwind();
if ( except_) rethrow_exception( except_);
}
};
template< typename Arg >
class push_coroutine_base< Arg const& > : private noncopyable
{
public:
typedef intrusive_ptr< push_coroutine_base > ptr_t;
private:
template<
typename X, typename Y, typename Z, typename V, typename W
>
friend class pull_coroutine_object;
unsigned int use_count_;
protected:
int flags_;
exception_ptr except_;
coroutine_context caller_;
coroutine_context callee_;
virtual void deallocate_object() = 0;
public:
push_coroutine_base( coroutine_context::ctx_fn fn,
stack_context * stack_ctx,
bool unwind, bool preserve_fpu) :
use_count_( 0),
flags_( 0),
except_(),
caller_(),
callee_( fn, stack_ctx)
{
if ( unwind) flags_ |= flag_force_unwind;
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
}
push_coroutine_base( coroutine_context const& callee,
bool unwind, bool preserve_fpu) :
use_count_( 0),
flags_( 0),
except_(),
caller_(),
callee_( callee)
{
if ( unwind) flags_ |= flag_force_unwind;
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
}
virtual ~push_coroutine_base()
{}
bool force_unwind() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_force_unwind); }
bool unwind_requested() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_unwind_stack); }
bool preserve_fpu() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_preserve_fpu); }
bool is_complete() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_complete); }
friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT
{ ++p->use_count_; }
friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
void push( Arg const& arg)
{
BOOST_ASSERT( ! is_complete() );
holder< Arg const& > hldr_to( & caller_, arg);
holder< Arg const& > * hldr_from(
reinterpret_cast< holder< Arg const& > * >(
hldr_to.ctx->jump(
callee_,
reinterpret_cast< intptr_t >( & hldr_to),
preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
callee_ = * hldr_from->ctx;
if ( hldr_from->force_unwind) throw forced_unwind();
if ( except_) rethrow_exception( except_);
}
};
template<>
class push_coroutine_base< void > : private noncopyable
{
public:
typedef intrusive_ptr< push_coroutine_base > ptr_t;
private:
template<
typename X, typename Y, typename Z, typename V, typename W
>
friend class pull_coroutine_object;
unsigned int use_count_;
protected:
int flags_;
exception_ptr except_;
coroutine_context caller_;
coroutine_context callee_;
virtual void deallocate_object() = 0;
public:
push_coroutine_base( coroutine_context::ctx_fn fn,
stack_context * stack_ctx,
bool unwind, bool preserve_fpu) :
use_count_( 0),
flags_( 0),
except_(),
caller_(),
callee_( fn, stack_ctx)
{
if ( unwind) flags_ |= flag_force_unwind;
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
}
push_coroutine_base( coroutine_context const& callee,
bool unwind, bool preserve_fpu) :
use_count_( 0),
flags_( 0),
except_(),
caller_(),
callee_( callee)
{
if ( unwind) flags_ |= flag_force_unwind;
if ( preserve_fpu) flags_ |= flag_preserve_fpu;
}
virtual ~push_coroutine_base()
{}
bool force_unwind() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_force_unwind); }
bool unwind_requested() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_unwind_stack); }
bool preserve_fpu() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_preserve_fpu); }
bool is_complete() const BOOST_NOEXCEPT
{ return 0 != ( flags_ & flag_complete); }
friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT
{ ++p->use_count_; }
friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT
{ if ( --p->use_count_ == 0) p->deallocate_object(); }
void push()
{
BOOST_ASSERT( ! is_complete() );
holder< void > hldr_to( & caller_);
holder< void > * hldr_from(
reinterpret_cast< holder< void > * >(
hldr_to.ctx->jump(
callee_,
reinterpret_cast< intptr_t >( & hldr_to),
preserve_fpu() ) ) );
BOOST_ASSERT( hldr_from->ctx);
callee_ = * hldr_from->ctx;
if ( hldr_from->force_unwind) throw forced_unwind();
if ( except_) rethrow_exception( except_);
}
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_BASE_H

View File

@ -0,0 +1,56 @@
// 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_V2_DETAIL_PUSH_COROUTINE_CALLER_H
#define BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_CALLER_H
#include <boost/config.hpp>
#include <boost/context/fcontext.hpp>
#include <boost/coroutine/detail/config.hpp>
#include <boost/coroutine/v2/detail/push_coroutine_base.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace coroutines {
namespace detail {
template< typename Arg, typename Allocator >
class push_coroutine_caller : public push_coroutine_base< Arg >
{
public:
typedef typename Allocator::template rebind<
push_coroutine_caller< Arg, Allocator >
>::other allocator_t;
push_coroutine_caller( coroutine_context const& callee, bool unwind,
bool preserve_fpu, allocator_t const& alloc) BOOST_NOEXCEPT :
push_coroutine_base< Arg >( callee, unwind, preserve_fpu),
alloc_( alloc)
{}
void deallocate_object()
{ destroy_( alloc_, this); }
private:
allocator_t alloc_;
static void destroy_( allocator_t & alloc, push_coroutine_caller * p)
{
alloc.destroy( p);
alloc.deallocate( p, 1);
}
};
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_CALLER_H

View File

@ -0,0 +1,823 @@
// 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_V2_DETAIL_PUSH_COROUTINE_OBJECT_H
#define BOOST_COROUTINES_V2_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/detail/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 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_V2_DETAIL_PUSH_COROUTINE_OBJECT_H

View File

@ -27,25 +27,24 @@
namespace coro = boost::coroutines;
typedef coro::coroutine< void() > coro_t;
# define COUNTER BOOST_PP_LIMIT_MAG
#define COUNTER BOOST_PP_LIMIT_MAG
#define CALL_COROUTINE(z,n,unused) \
# define CALL_COROUTINE(z,n,unused) \
c();
void fn( coro_t::caller_type & c)
#ifdef BOOST_COROUTINES_V2
void fn( boost::coroutines::push_coroutine< void > & c)
{ while ( true) c(); }
#ifdef BOOST_CONTEXT_CYCLE
# ifdef BOOST_CONTEXT_CYCLE
cycle_t test_cycles( cycle_t ov, coro::flag_fpu_t preserve_fpu)
{
#if defined(BOOST_USE_SEGMENTED_STACKS)
coro_t c( fn, coro::attributes( preserve_fpu) );
#else
# if defined(BOOST_USE_SEGMENTED_STACKS)
boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu) );
# else
coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc;
coro_t c( fn, coro::attributes( preserve_fpu), alloc);
#endif
boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu), alloc);
# endif
// cache warum-up
BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~)
@ -61,17 +60,17 @@ BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~)
return total;
}
#endif
# endif
#if _POSIX_C_SOURCE >= 199309L
# if _POSIX_C_SOURCE >= 199309L
zeit_t test_zeit( zeit_t ov, coro::flag_fpu_t preserve_fpu)
{
#if defined(BOOST_USE_SEGMENTED_STACKS)
coro_t c( fn, coro::attributes( preserve_fpu) );
#else
# if defined(BOOST_USE_SEGMENTED_STACKS)
boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu) );
# else
coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc;
coro_t c( fn, coro::attributes( preserve_fpu), alloc);
#endif
boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu), alloc);
# endif
// cache warum-up
BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~)
@ -87,6 +86,64 @@ BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~)
return total;
}
# endif
#else
typedef coro::coroutine< void() > coro_t;
void fn( coro_t::caller_type & c)
{ while ( true) c(); }
# ifdef BOOST_CONTEXT_CYCLE
cycle_t test_cycles( cycle_t ov, coro::flag_fpu_t preserve_fpu)
{
# if defined(BOOST_USE_SEGMENTED_STACKS)
coro_t c( fn, coro::attributes( preserve_fpu) );
# else
coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc;
coro_t c( fn, coro::attributes( preserve_fpu), alloc);
# endif
// cache warum-up
BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~)
cycle_t start( cycles() );
BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~)
cycle_t total( cycles() - start);
// we have two jumps and two measuremt-overheads
total -= ov; // overhead of measurement
total /= COUNTER; // per call
total /= 2; // 2x jump_to c1->c2 && c2->c1
return total;
}
# endif
# if _POSIX_C_SOURCE >= 199309L
zeit_t test_zeit( zeit_t ov, coro::flag_fpu_t preserve_fpu)
{
# if defined(BOOST_USE_SEGMENTED_STACKS)
coro_t c( fn, coro::attributes( preserve_fpu) );
# else
coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc;
coro_t c( fn, coro::attributes( preserve_fpu), alloc);
# endif
// cache warum-up
BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~)
zeit_t start( zeit() );
BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~)
zeit_t total( zeit() - start);
// we have two jumps and two measuremt-overheads
total -= ov; // overhead of measurement
total /= BOOST_PP_LIMIT_MAG; // per call
total /= 2; // 2x jump_to c1->c2 && c2->c1
return total;
}
# endif
#endif
int main( int argc, char * argv[])

View File

@ -30,7 +30,487 @@ namespace coro = boost::coroutines;
int value1 = 0;
std::string value2 = "";
bool value3 = false;
double value4 = .0;
int * value5 = 0;
int& value6 = value1;
int& value7 = value1;
int value8 = 0;
int value9 = 0;
#ifdef BOOST_COROUTINES_V2
struct X : private boost::noncopyable
{
X() { value1 = 7; }
~X() { value1 = 0; }
};
class copyable
{
public:
bool state;
copyable() :
state( false)
{}
copyable( int) :
state( true)
{}
void operator()( coro::push_coroutine< int > &)
{ value3 = state; }
};
class moveable
{
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE( moveable);
public:
bool state;
moveable() :
state( false)
{}
moveable( int) :
state( true)
{}
moveable( BOOST_RV_REF( moveable) other) :
state( false)
{ std::swap( state, other.state); }
moveable & operator=( BOOST_RV_REF( moveable) other)
{
if ( this == & other) return * this;
moveable tmp( boost::move( other) );
std::swap( state, tmp.state);
return * this;
}
void operator()( coro::push_coroutine< int > &)
{ value3 = state; }
};
struct my_exception {};
void f1( coro::push_coroutine< void > & c)
{ c(); }
void f2( coro::push_coroutine< void > &)
{ ++value1; }
void f3( coro::push_coroutine< void > & c)
{
++value1;
c();
++value1;
}
void f4( coro::push_coroutine< int > & c)
{
c( 3);
c( 7);
}
void f5( coro::push_coroutine< std::string > & c)
{
std::string res("abc");
c( res);
res = "xyz";
c( res);
}
void f6( coro::pull_coroutine< int > & c)
{ value1 = c.get(); }
void f7( coro::pull_coroutine< std::string > & c)
{ value2 = c.get(); }
void f8( coro::pull_coroutine< boost::tuple< double, double > > & c)
{
double x = 0, y = 0;
boost::tie( x, y) = c.get();
value4 = x + y;
c();
boost::tie( x, y) = c.get();
value4 = x + y;
}
void f9( coro::pull_coroutine< int * > & c)
{ value5 = c.get(); }
void f91( coro::pull_coroutine< int const* > & c)
{ value5 = const_cast< int * >( c.get() ); }
void f10( coro::pull_coroutine< int & > & c)
{
int const& i = c.get();
value5 = const_cast< int * >( & i);
}
void f101( coro::pull_coroutine< int const& > & c)
{
int const& i = c.get();
value5 = const_cast< int * >( & i);
}
void f11( coro::pull_coroutine< boost::tuple< int, int > > & c)
{
boost::tie( value8, value9) = c.get();
}
void f12( coro::pull_coroutine< void > & c)
{
X x_;
c();
c();
}
template< typename E >
void f14( coro::pull_coroutine< void > &, E const& e)
{ throw e; }
void f16( coro::push_coroutine< int > & c)
{
c( 1);
c( 2);
c( 3);
c( 4);
c( 5);
}
void f17( coro::pull_coroutine< int > & c, std::vector< int > & vec)
{
int x = c.get();
while ( 5 > x)
{
vec.push_back( x);
x = c().get();
}
}
void f19( coro::push_coroutine< const int* > & c, std::vector< const int * > & vec)
{
BOOST_FOREACH( const int * ptr, vec)
{ c( ptr); }
}
void test_move()
{
{
coro::pull_coroutine< void > coro1;
coro::pull_coroutine< void > coro2( f1);
BOOST_CHECK( ! coro1);
BOOST_CHECK( coro1.empty() );
BOOST_CHECK( coro2);
BOOST_CHECK( ! coro2.empty() );
coro1 = boost::move( coro2);
BOOST_CHECK( coro1);
BOOST_CHECK( ! coro1.empty() );
BOOST_CHECK( ! coro2);
BOOST_CHECK( coro2.empty() );
}
{
value3 = false;
copyable cp( 3);
BOOST_CHECK( cp.state);
BOOST_CHECK( ! value3);
coro::pull_coroutine< int > coro( cp);
BOOST_CHECK( cp.state);
BOOST_CHECK( value3);
}
{
value3 = false;
moveable mv( 7);
BOOST_CHECK( mv.state);
BOOST_CHECK( ! value3);
coro::pull_coroutine< int > coro( boost::move( mv) );
BOOST_CHECK( ! mv.state);
BOOST_CHECK( value3);
}
}
void test_complete()
{
value1 = 0;
coro::pull_coroutine< void > coro( f2);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( ( int)1, value1);
}
void test_jump()
{
value1 = 0;
coro::pull_coroutine< void > coro( f3);
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( int)1, value1);
coro();
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( ( int)2, value1);
}
void test_result_int()
{
coro::pull_coroutine< int > coro( f4);
BOOST_CHECK( coro);
int result = coro.get();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( 3, result);
result = coro().get();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( 7, result);
coro();
BOOST_CHECK( ! coro);
}
void test_result_string()
{
coro::pull_coroutine< std::string > coro( f5);
BOOST_CHECK( coro);
std::string result = coro.get();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( std::string("abc"), result);
result = coro().get();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( std::string("xyz"), result);
coro();
BOOST_CHECK( ! coro);
}
void test_arg_int()
{
value1 = 0;
coro::push_coroutine< int > coro( f6);
BOOST_CHECK( coro);
coro( 3);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( 3, value1);
}
void test_arg_string()
{
value2 = "";
coro::push_coroutine< std::string > coro( f7);
BOOST_CHECK( coro);
coro( std::string("abc") );
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( std::string("abc"), value2);
}
void test_fp()
{
value4 = 0;
coro::push_coroutine< boost::tuple< double, double > > coro( f8);
BOOST_CHECK( coro);
coro( boost::make_tuple( 7.35, 3.14) );
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( double) 10.49, value4);
value4 = 0;
coro( boost::make_tuple( 1.15, 3.14) );
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( ( double) 4.29, value4);
}
void test_ptr()
{
value5 = 0;
int a = 3;
coro::push_coroutine< int * > coro( f9);
BOOST_CHECK( coro);
coro( & a);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5);
}
void test_const_ptr()
{
value5 = 0;
int a = 3;
coro::push_coroutine< int const* > coro( f91);
BOOST_CHECK( coro);
coro( & a);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5);
}
void test_ref()
{
value5 = 0;
int a = 3;
coro::push_coroutine< int & > coro( f10);
BOOST_CHECK( coro);
coro( a);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5);
}
void test_const_ref()
{
value5 = 0;
int a = 3;
coro::push_coroutine< int const& > coro( f101);
BOOST_CHECK( coro);
coro( a);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( & a, value5);
}
void test_tuple()
{
value8 = 0;
value9 = 0;
int a = 3, b = 7;
boost::tuple< int, int > tpl( a, b);
BOOST_CHECK_EQUAL( a, tpl.get< 0 >() );
BOOST_CHECK_EQUAL( b, tpl.get< 1 >() );
coro::push_coroutine< boost::tuple< int, int > > coro( f11);
BOOST_CHECK( coro);
coro( tpl);
BOOST_CHECK( ! coro);
BOOST_CHECK_EQUAL( a, value8);
BOOST_CHECK_EQUAL( b, value9);
}
void test_unwind()
{
value1 = 0;
{
coro::push_coroutine< void > coro( f12);
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( int) 0, value1);
coro();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( int) 7, value1);
coro();
BOOST_CHECK_EQUAL( ( int) 7, value1);
}
BOOST_CHECK_EQUAL( ( int) 0, value1);
}
void test_no_unwind()
{
value1 = 0;
{
coro::push_coroutine< void > coro(
f12,
coro::attributes(
coro::stack_allocator::default_stacksize(),
coro::no_stack_unwind) );
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( int) 0, value1);
coro();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( ( int) 7, value1);
coro();
BOOST_CHECK_EQUAL( ( int) 7, value1);
}
BOOST_CHECK_EQUAL( ( int) 7, value1);
}
void test_exceptions()
{
bool thrown = false;
std::runtime_error ex("abc");
try
{
coro::push_coroutine< void > coro( boost::bind( f14< std::runtime_error >, _1, ex) );
BOOST_CHECK( coro);
coro();
BOOST_CHECK( ! coro);
BOOST_CHECK( false);
}
catch ( std::runtime_error const&)
{ thrown = true; }
catch ( std::exception const&)
{}
catch (...)
{}
BOOST_CHECK( thrown);
}
void test_output_iterator()
{
{
std::vector< int > vec;
coro::pull_coroutine< int > coro( f16);
BOOST_FOREACH( int i, coro)
{ vec.push_back( i); }
BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() );
BOOST_CHECK_EQUAL( ( int)1, vec[0] );
BOOST_CHECK_EQUAL( ( int)2, vec[1] );
BOOST_CHECK_EQUAL( ( int)3, vec[2] );
BOOST_CHECK_EQUAL( ( int)4, vec[3] );
BOOST_CHECK_EQUAL( ( int)5, vec[4] );
}
{
std::vector< int > vec;
coro::pull_coroutine< int > coro( f16);
coro::pull_coroutine< int >::iterator e = boost::end( coro);
for (
coro::pull_coroutine< int >::iterator i = boost::begin( coro);
i != e; ++i)
{ vec.push_back( * i); }
BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() );
BOOST_CHECK_EQUAL( ( int)1, vec[0] );
BOOST_CHECK_EQUAL( ( int)2, vec[1] );
BOOST_CHECK_EQUAL( ( int)3, vec[2] );
BOOST_CHECK_EQUAL( ( int)4, vec[3] );
BOOST_CHECK_EQUAL( ( int)5, vec[4] );
}
{
int i1 = 1, i2 = 2, i3 = 3;
std::vector< const int* > vec_in;
vec_in.push_back( & i1);
vec_in.push_back( & i2);
vec_in.push_back( & i3);
std::vector< const int* > vec_out;
coro::pull_coroutine< const int* > coro( boost::bind( f19, _1, boost::ref( vec_in) ) );
coro::pull_coroutine< const int* >::const_iterator e = boost::const_end( coro);
for (
coro::pull_coroutine< const int* >::const_iterator i = boost::const_begin( coro);
i != e; ++i)
{ vec_out.push_back( * i); }
BOOST_CHECK_EQUAL( ( std::size_t)3, vec_out.size() );
BOOST_CHECK_EQUAL( & i1, vec_out[0] );
BOOST_CHECK_EQUAL( & i2, vec_out[1] );
BOOST_CHECK_EQUAL( & i3, vec_out[2] );
}
}
void test_input_iterator()
{
int counter = 0;
std::vector< int > vec;
coro::push_coroutine< int > coro(
boost::bind( f17, _1, boost::ref( vec) ) );
coro::push_coroutine< int >::iterator e( boost::end( coro) );
for ( coro::push_coroutine< int >::iterator i( boost::begin( coro) );
i != e; ++i)
{
i = ++counter;
}
BOOST_CHECK_EQUAL( ( std::size_t)4, vec.size() );
BOOST_CHECK_EQUAL( ( int)1, vec[0] );
BOOST_CHECK_EQUAL( ( int)2, vec[1] );
BOOST_CHECK_EQUAL( ( int)3, vec[2] );
BOOST_CHECK_EQUAL( ( int)4, vec[3] );
}
#else
typedef coro::coroutine< void() > coro_void_void;
typedef coro::coroutine< int() > coro_int_void;
typedef coro::coroutine< std::string() > coro_string_void;
@ -40,7 +520,9 @@ typedef coro::coroutine< double(double,double) > coro_double;
typedef coro::coroutine< int(int,int) > coro_int;
typedef coro::coroutine< int(int) > coro_int_int;
typedef coro::coroutine< int*(int*) > coro_ptr;
typedef coro::coroutine< int const&(int const&) > coro_ref;
typedef coro::coroutine< int const*(int const*) > coro_const_ptr;
typedef coro::coroutine< int&(int&) > coro_ref;
typedef coro::coroutine< int const&(int const&) > coro_const_ref;
typedef coro::coroutine< boost::tuple<int&,int&>(int&,int&) > coro_tuple;
typedef coro::coroutine< const int *() > coro_const_int_ptr_void;
@ -146,9 +628,15 @@ void f8( coro_double::caller_type & self)
void f9( coro_ptr::caller_type & self)
{ self( self.get() ); }
void f91( coro_const_ptr::caller_type & self)
{ self( self.get() ); }
void f10( coro_ref::caller_type & self)
{ self( self.get() ); }
void f101( coro_const_ref::caller_type & self)
{ self( self.get() ); }
void f11( coro_tuple::caller_type & self)
{
boost::tuple<int&,int&> tpl( self.get().get< 0 >(), self.get().get< 1 >() );
@ -338,6 +826,18 @@ void test_ptr()
BOOST_CHECK( ! coro);
}
void test_const_ptr()
{
int a = 3;
coro_const_ptr coro( f91, & a);
BOOST_CHECK( coro);
int const* res = coro.get();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( & a, res);
coro( & a);
BOOST_CHECK( ! coro);
}
void test_ref()
{
int a = 3;
@ -350,6 +850,18 @@ void test_ref()
BOOST_CHECK( ! coro);
}
void test_const_ref()
{
int a = 3;
coro_const_ref coro( f101, a);
BOOST_CHECK( coro);
int const& res = coro.get();
BOOST_CHECK( coro);
BOOST_CHECK_EQUAL( & a, & res);
coro( a);
BOOST_CHECK( ! coro);
}
void test_tuple()
{
int a = 3, b = 7;
@ -507,6 +1019,7 @@ void test_post()
coro( -1);
BOOST_CHECK( ! coro);
}
#endif
boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
{
@ -516,15 +1029,19 @@ boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
test->add( BOOST_TEST_CASE( & test_move) );
test->add( BOOST_TEST_CASE( & test_complete) );
test->add( BOOST_TEST_CASE( & test_jump) );
test->add( BOOST_TEST_CASE( & test_pre) );
test->add( BOOST_TEST_CASE( & test_post) );
test->add( BOOST_TEST_CASE( & test_result_int) );
test->add( BOOST_TEST_CASE( & test_result_string) );
test->add( BOOST_TEST_CASE( & test_arg_int) );
test->add( BOOST_TEST_CASE( & test_arg_string) );
test->add( BOOST_TEST_CASE( & test_fp) );
test->add( BOOST_TEST_CASE( & test_ptr) );
test->add( BOOST_TEST_CASE( & test_const_ptr) );
#ifndef BOOST_COROUTINES_V2
test->add( BOOST_TEST_CASE( & test_pre) );
test->add( BOOST_TEST_CASE( & test_post) );
#endif
test->add( BOOST_TEST_CASE( & test_ref) );
test->add( BOOST_TEST_CASE( & test_const_ref) );
test->add( BOOST_TEST_CASE( & test_tuple) );
test->add( BOOST_TEST_CASE( & test_unwind) );
test->add( BOOST_TEST_CASE( & test_no_unwind) );