123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- // 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)
- #include <boost/coroutine/symmetric_coroutine.hpp>
- #include <algorithm>
- #include <iostream>
- #include <sstream>
- #include <stdexcept>
- #include <string>
- #include <vector>
- #include <cstdio>
- #include <boost/assert.hpp>
- #include <boost/bind.hpp>
- #include <boost/foreach.hpp>
- #include <boost/lexical_cast.hpp>
- #include <boost/move/move.hpp>
- #include <boost/range.hpp>
- #include <boost/ref.hpp>
- #include <boost/test/unit_test.hpp>
- #include <boost/tuple/tuple.hpp>
- #include <boost/utility.hpp>
- namespace coro = boost::coroutines;
- bool value1 = false;
- int value2 = 0;
- std::string value3;
- typedef void( * coro_fn_void)(coro::symmetric_coroutine< void* >::yield_type &);
- coro::symmetric_coroutine< void >::call_type * term_coro = 0;
- struct X
- {
- int i;
- X() :
- i( 0)
- {}
- X( int i_) :
- i( i_)
- {}
- };
- X * p = 0;
- struct Y
- {
- Y()
- { value2 = 7; }
- ~Y()
- { value2 = 0; }
- };
-
- template< typename X, typename I >
- void trampoline( coro::symmetric_coroutine< void* >::yield_type & yield)
- {
- void * vp = yield.get();
- X * x = static_cast< X * >( vp);
- I i( yield);
- x->d = & i;
- i.suspend();
- i.run();
- }
- struct B
- {
- virtual ~B() {}
- virtual void foo() = 0;
- };
- class D : public B
- {
- public:
- int count;
- coro::symmetric_coroutine< void* >::call_type call;
- coro::symmetric_coroutine< void* >::yield_type * yield;
- D( coro::symmetric_coroutine< void* >::yield_type & yield_) :
- B(),
- count( 0),
- call(),
- yield( & yield_)
- {}
- void foo() {}
- void resume()
- { call( 0); }
- void suspend()
- { ( *yield)(); }
- void run()
- {
- while ( yield && * yield)
- {
- ++count;
- suspend();
- }
- }
- };
- struct T
- {
- D * d;
- T() :
- d( 0)
- {}
- };
- class copyable
- {
- public:
- bool state;
- copyable() :
- state( false)
- {}
- copyable( int) :
- state( true)
- {}
- void operator()( coro::symmetric_coroutine< bool >::yield_type & yield)
- {
- if ( yield)
- value1 = yield.get();
- }
- };
- 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::symmetric_coroutine< int >::yield_type &)
- { value1 = state; }
- };
- void empty( coro::symmetric_coroutine< void >::yield_type &) {}
- void f2( coro::symmetric_coroutine< void >::yield_type &)
- { ++value2; }
- void f3( coro::symmetric_coroutine< X >::yield_type & yield)
- { value2 = yield.get().i; }
- void f4( coro::symmetric_coroutine< X& >::yield_type & yield)
- {
- X & x = yield.get();
- p = & x;
- }
- void f5( coro::symmetric_coroutine< X* >::yield_type & yield)
- { p = yield.get(); }
- void f6( coro::symmetric_coroutine< void >::yield_type & yield)
- {
- Y y;
- yield( *term_coro);
- }
- void f7( coro::symmetric_coroutine< int >::yield_type & yield)
- {
- value2 = yield.get();
- yield( *term_coro);
- value2 = yield.get();
- }
- template< typename E >
- void f9( coro::symmetric_coroutine< void >::yield_type &, E const& e)
- { throw e; }
- void f10( coro::symmetric_coroutine< int >::yield_type & yield,
- coro::symmetric_coroutine< int >::call_type & other)
- {
- int i = yield.get();
- yield( other, i);
- value2 = yield.get();
- }
- void f101( coro::symmetric_coroutine< int >::yield_type & yield)
- { value2 = yield.get(); }
- void f11( coro::symmetric_coroutine< void >::yield_type & yield,
- coro::symmetric_coroutine< void >::call_type & other)
- {
- yield( other);
- value2 = 7;
- }
- void f111( coro::symmetric_coroutine< void >::yield_type &)
- { value2 = 3; }
- void f12( coro::symmetric_coroutine< X& >::yield_type & yield,
- coro::symmetric_coroutine< X& >::call_type & other)
- {
- yield( other, yield.get());
- p = & yield.get();
- }
- void f121( coro::symmetric_coroutine< X& >::yield_type & yield)
- { p = & yield.get(); }
- void f14( coro::symmetric_coroutine< int >::yield_type & yield,
- coro::symmetric_coroutine< std::string >::call_type & other)
- {
- std::string str( boost::lexical_cast< std::string >( yield.get() ) );
- yield( other, str);
- value2 = yield.get();
- }
- void f141( coro::symmetric_coroutine< std::string >::yield_type & yield)
- { value3 = yield.get(); }
- void f15( coro::symmetric_coroutine< int >::yield_type & yield,
- int offset,
- coro::symmetric_coroutine< int >::call_type & other)
- {
- int x = yield.get();
- value2 += x + offset;
- yield( other, x);
- x = yield.get();
- value2 += x + offset;
- yield( other, x);
- }
- void f151( coro::symmetric_coroutine< int >::yield_type & yield,
- int offset)
- {
- int x = yield.get();
- value2 += x + offset;
- yield();
- x = yield.get();
- value2 += x + offset;
- }
- void f16( coro::symmetric_coroutine< int >::yield_type & yield)
- {
- while ( yield)
- {
- value2 = yield.get();
- yield();
- }
- }
- void test_move()
- {
- {
- coro::symmetric_coroutine< void >::call_type coro1;
- coro::symmetric_coroutine< void >::call_type coro2( empty);
- BOOST_CHECK( ! coro1);
- BOOST_CHECK( coro2);
- coro1 = boost::move( coro2);
- BOOST_CHECK( coro1);
- BOOST_CHECK( ! coro2);
- }
- {
- value1 = false;
- copyable cp( 3);
- BOOST_CHECK( cp.state);
- BOOST_CHECK( ! value1);
- coro::symmetric_coroutine< bool >::call_type coro( cp);
- coro( true);
- BOOST_CHECK( cp.state);
- BOOST_CHECK( value1);
- }
- {
- value1 = false;
- moveable mv( 7);
- BOOST_CHECK( mv.state);
- BOOST_CHECK( ! value1);
- coro::symmetric_coroutine< int >::call_type coro( boost::move( mv) );
- coro( 7);
- BOOST_CHECK( ! mv.state);
- BOOST_CHECK( value1);
- }
- }
- void test_complete()
- {
- value2 = 0;
- coro::symmetric_coroutine< void >::call_type coro( f2);
- BOOST_CHECK( coro);
- coro();
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( ( int)1, value2);
- }
- void test_yield()
- {
- value2 = 0;
- coro::symmetric_coroutine< int >::call_type coro3(
- boost::bind( f151, _1, 3) );
- BOOST_CHECK( coro3);
- coro::symmetric_coroutine< int >::call_type coro2(
- boost::bind( f15, _1, 2, boost::ref( coro3) ) );
- BOOST_CHECK( coro2);
- coro::symmetric_coroutine< int >::call_type coro1(
- boost::bind( f15, _1, 1, boost::ref( coro2) ) );
- BOOST_CHECK( coro1);
- BOOST_CHECK_EQUAL( ( int)0, value2);
- coro1( 1);
- BOOST_CHECK( coro3);
- BOOST_CHECK( coro2);
- BOOST_CHECK( coro1);
- BOOST_CHECK_EQUAL( ( int)9, value2);
- coro1( 2);
- BOOST_CHECK( ! coro3);
- BOOST_CHECK( coro2);
- BOOST_CHECK( coro1);
- BOOST_CHECK_EQUAL( ( int)21, value2);
- }
- void test_pass_value()
- {
- value2 = 0;
- X x(7);
- BOOST_CHECK_EQUAL( ( int)7, x.i);
- BOOST_CHECK_EQUAL( 0, value2);
- coro::symmetric_coroutine< X >::call_type coro( f3);
- BOOST_CHECK( coro);
- coro(7);
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( ( int)7, x.i);
- BOOST_CHECK_EQUAL( 7, value2);
- }
- void test_pass_reference()
- {
- p = 0;
- X x;
- coro::symmetric_coroutine< X& >::call_type coro( f4);
- BOOST_CHECK( coro);
- coro( x);
- BOOST_CHECK( ! coro);
- BOOST_CHECK( p == & x);
- }
- void test_pass_pointer()
- {
- p = 0;
- X x;
- coro::symmetric_coroutine< X* >::call_type coro( f5);
- BOOST_CHECK( coro);
- coro( & x);
- BOOST_CHECK( ! coro);
- BOOST_CHECK( p == & x);
- }
- void test_unwind()
- {
- value2 = 0;
- {
- coro::symmetric_coroutine< void >::call_type coro( f6);
- coro::symmetric_coroutine< void >::call_type coro_e( empty);
- BOOST_CHECK( coro);
- BOOST_CHECK( coro_e);
- term_coro = & coro_e;
- BOOST_CHECK_EQUAL( ( int) 0, value2);
- coro();
- BOOST_CHECK( coro);
- BOOST_CHECK_EQUAL( ( int) 7, value2);
- }
- BOOST_CHECK_EQUAL( ( int) 0, value2);
- }
- void test_no_unwind()
- {
- value2 = 0;
- {
- coro::symmetric_coroutine< void >::call_type coro( f6,
- coro::attributes(
- coro::stack_allocator::traits_type::default_size(),
- coro::no_stack_unwind) );
- coro::symmetric_coroutine< void >::call_type coro_e( empty);
- BOOST_CHECK( coro);
- BOOST_CHECK( coro_e);
- term_coro = & coro_e;
- BOOST_CHECK_EQUAL( ( int) 0, value2);
- coro();
- BOOST_CHECK( coro);
- BOOST_CHECK_EQUAL( ( int) 7, value2);
- }
- BOOST_CHECK_EQUAL( ( int) 7, value2);
- }
- void test_termination()
- {
- value2 = 0;
- coro::symmetric_coroutine< int >::call_type coro( f7);
- coro::symmetric_coroutine< void >::call_type coro_e( empty);
- BOOST_CHECK( coro);
- BOOST_CHECK( coro_e);
- term_coro = & coro_e;
- BOOST_CHECK_EQUAL( ( int) 0, value2);
- coro(3);
- BOOST_CHECK( coro);
- BOOST_CHECK_EQUAL( ( int) 3, value2);
- coro(7);
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( ( int) 7, value2);
- }
- void test_yield_to_void()
- {
- value2 = 0;
- coro::symmetric_coroutine< void >::call_type coro_other( f111);
- coro::symmetric_coroutine< void >::call_type coro( boost::bind( f11, _1, boost::ref( coro_other) ) );
- BOOST_CHECK( coro_other);
- BOOST_CHECK( coro);
- BOOST_CHECK_EQUAL( ( int) 0, value2);
- coro();
- BOOST_CHECK( ! coro_other);
- BOOST_CHECK( coro);
- BOOST_CHECK_EQUAL( ( int) 3, value2);
- coro();
- BOOST_CHECK( ! coro_other);
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( ( int) 7, value2);
- }
- void test_yield_to_int()
- {
- value2 = 0;
- coro::symmetric_coroutine< int >::call_type coro_other( f101);
- coro::symmetric_coroutine< int >::call_type coro( boost::bind( f10, _1, boost::ref( coro_other) ) );
- BOOST_CHECK( coro_other);
- BOOST_CHECK( coro);
- BOOST_CHECK_EQUAL( ( int) 0, value2);
- coro(3);
- BOOST_CHECK( ! coro_other);
- BOOST_CHECK( coro);
- BOOST_CHECK_EQUAL( ( int) 3, value2);
- coro(7);
- BOOST_CHECK( ! coro_other);
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( ( int) 7, value2);
- }
- void test_yield_to_ref()
- {
- p = 0;
- coro::symmetric_coroutine< X& >::call_type coro_other( f121);
- coro::symmetric_coroutine< X& >::call_type coro( boost::bind( f12, _1, boost::ref( coro_other) ) );
- BOOST_CHECK( coro_other);
- BOOST_CHECK( coro);
- BOOST_CHECK( 0 == p);
- X x1(3);
- coro( x1);
- BOOST_CHECK( ! coro_other);
- BOOST_CHECK( coro);
- BOOST_CHECK_EQUAL( p->i, x1.i);
- BOOST_CHECK( p == & x1);
- X x2(7);
- coro(x2);
- BOOST_CHECK( ! coro_other);
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( p->i, x2.i);
- BOOST_CHECK( p == & x2);
- }
- void test_yield_to_different()
- {
- value2 = 0;
- value3 = "";
- coro::symmetric_coroutine< std::string >::call_type coro_other( f141);
- coro::symmetric_coroutine< int >::call_type coro( boost::bind( f14, _1, boost::ref( coro_other) ) );
- BOOST_CHECK( coro_other);
- BOOST_CHECK( coro);
- BOOST_CHECK_EQUAL( ( int) 0, value2);
- BOOST_CHECK( value3.empty() );
- coro(3);
- BOOST_CHECK( ! coro_other);
- BOOST_CHECK( coro);
- BOOST_CHECK_EQUAL( "3", value3);
- coro(7);
- BOOST_CHECK( ! coro_other);
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( ( int) 7, value2);
- }
- void test_move_coro()
- {
- value2 = 0;
- coro::symmetric_coroutine< int >::call_type coro1( f16);
- coro::symmetric_coroutine< int >::call_type coro2;
- BOOST_CHECK( coro1);
- BOOST_CHECK( ! coro2);
- coro1( 1);
- BOOST_CHECK_EQUAL( ( int)1, value2);
- coro2 = boost::move( coro1);
- BOOST_CHECK( ! coro1);
- BOOST_CHECK( coro2);
- coro2( 2);
- BOOST_CHECK_EQUAL( ( int)2, value2);
- coro1 = boost::move( coro2);
- BOOST_CHECK( coro1);
- BOOST_CHECK( ! coro2);
- coro1( 3);
- BOOST_CHECK_EQUAL( ( int)3, value2);
- coro2 = boost::move( coro1);
- BOOST_CHECK( ! coro1);
- BOOST_CHECK( coro2);
- coro2( 4);
- BOOST_CHECK_EQUAL( ( int)4, value2);
- }
- void test_vptr()
- {
- D * d = 0;
- T t;
- coro_fn_void fn = trampoline< T, D >;
- coro::symmetric_coroutine< void* >::call_type call( fn);
- call( & t);
- d = t.d;
- BOOST_CHECK( 0 != d);
- d->call = boost::move( call);
- BOOST_CHECK_EQUAL( ( int) 0, d->count);
- d->resume();
- BOOST_CHECK_EQUAL( ( int) 1, d->count);
- d->resume();
- BOOST_CHECK_EQUAL( ( int) 2, d->count);
- }
- boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
- {
- boost::unit_test::test_suite * test =
- BOOST_TEST_SUITE("Boost.coroutine: symmetric coroutine test suite");
- test->add( BOOST_TEST_CASE( & test_move) );
- test->add( BOOST_TEST_CASE( & test_complete) );
- test->add( BOOST_TEST_CASE( & test_yield) );
- test->add( BOOST_TEST_CASE( & test_pass_value) );
- test->add( BOOST_TEST_CASE( & test_pass_reference) );
- test->add( BOOST_TEST_CASE( & test_pass_pointer) );
- test->add( BOOST_TEST_CASE( & test_termination) );
- test->add( BOOST_TEST_CASE( & test_unwind) );
- test->add( BOOST_TEST_CASE( & test_no_unwind) );
- test->add( BOOST_TEST_CASE( & test_yield_to_void) );
- test->add( BOOST_TEST_CASE( & test_yield_to_int) );
- test->add( BOOST_TEST_CASE( & test_yield_to_ref) );
- test->add( BOOST_TEST_CASE( & test_yield_to_different) );
- test->add( BOOST_TEST_CASE( & test_move_coro) );
- test->add( BOOST_TEST_CASE( & test_vptr) );
- return test;
- }
|