123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679 |
- // Copyright Oliver Kowalke 2014.
- // 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 <algorithm>
- #include <cstdio>
- #include <iostream>
- #include <sstream>
- #include <stdexcept>
- #include <string>
- #include <tuple>
- #include <vector>
- #include <boost/assert.hpp>
- #include <boost/test/unit_test.hpp>
- #include <boost/coroutine2/coroutine.hpp>
- namespace coro = boost::coroutines2;
- int value1 = 0;
- std::string value2 = "";
- bool value3 = false;
- double value4 = .0;
- int * value5 = nullptr;
- int& value6 = value1;
- int& value7 = value1;
- int value8 = 0;
- int value9 = 0;
- struct X
- {
- X() { value1 = 7; }
- ~X() { value1 = 0; }
- X( X const&) = delete;
- X & operator=( X const&) = delete;
- };
- class copyable
- {
- public:
- bool state;
- copyable() :
- state( false)
- {}
- copyable( int) :
- state( true)
- {}
- void operator()( coro::coroutine< int >::push_type &)
- { value3 = state; }
- };
- class moveable
- {
- public:
- bool state;
- moveable() :
- state( false)
- {}
- moveable( int) :
- state( true)
- {}
- moveable( moveable const&) = delete;
- moveable & operator=( moveable const&) = delete;
- moveable( moveable && other) :
- state( false)
- { std::swap( state, other.state); }
- moveable & operator=( moveable && other)
- {
- if ( this != & other) {
- state = other.state;
- other.state = false;
- }
- return * this;
- }
- void operator()( coro::coroutine< int >::push_type &)
- { value3 = state; }
- };
- class movedata
- {
- public:
- int i;
- movedata( int i_) :
- i( i_)
- {}
- movedata( movedata const&) = delete;
- movedata & operator=( movedata const&) = delete;
- movedata( movedata && other) :
- i( 0)
- { std::swap( i, other.i); }
- movedata & operator=( movedata && other)
- {
- if ( this != & other) {
- i = other.i;
- other.i = 0;
- }
- return * this;
- }
- };
- struct my_exception {};
- void f1( coro::coroutine< void >::push_type & c)
- {
- while ( c)
- c();
- }
- void f2( coro::coroutine< void >::push_type &)
- { ++value1; }
- void f3( coro::coroutine< void >::push_type & c)
- {
- ++value1;
- c();
- ++value1;
- }
- void f4( coro::coroutine< int >::push_type & c)
- {
- c( 3);
- c( 7);
- }
- void f5( coro::coroutine< std::string >::push_type & c)
- {
- std::string res("abc");
- c( res);
- res = "xyz";
- c( res);
- }
- void f6( coro::coroutine< int >::pull_type & c)
- { value1 = c.get(); }
- void f7( coro::coroutine< std::string >::pull_type & c)
- { value2 = c.get(); }
- void f8( coro::coroutine< std::tuple< double, double > >::pull_type & c)
- {
- double x = 0, y = 0;
- std::tie( x, y) = c.get();
- value4 = x + y;
- c();
- std::tie( x, y) = c.get();
- value4 = x + y;
- }
- void f9( coro::coroutine< int * >::pull_type & c)
- { value5 = c.get(); }
- void f91( coro::coroutine< int const* >::pull_type & c)
- { value5 = const_cast< int * >( c.get() ); }
- void f10( coro::coroutine< int & >::pull_type & c)
- {
- int & i = c.get();
- value5 = const_cast< int * >( & i);
- }
- void f101( coro::coroutine< int const& >::pull_type & c)
- {
- int const& i = c.get();
- value5 = const_cast< int * >( & i);
- }
- void f11( coro::coroutine< std::tuple< int, int > >::pull_type & c)
- {
- std::tie( value8, value9) = c.get();
- }
- void f12( coro::coroutine< void >::pull_type & c)
- {
- value1 = 7;
- X x_;
- c();
- c();
- }
- void f16( coro::coroutine< int >::push_type & c)
- {
- c( 1);
- c( 2);
- c( 3);
- c( 4);
- c( 5);
- }
- void f17( coro::coroutine< int >::pull_type & c, std::vector< int > & vec)
- {
- int x = c.get();
- while ( 5 > x)
- {
- vec.push_back( x);
- x = c().get();
- }
- }
- void f20( coro::coroutine< int >::push_type &)
- {}
- void f21( coro::coroutine< int >::pull_type & c)
- {
- while ( c)
- {
- value1 = c.get();
- c();
- }
- }
- void f22( coro::coroutine< movedata >::pull_type & c)
- {
- movedata mv( c.get() );
- value1 = mv.i;
- }
- void test_move()
- {
- {
- coro::coroutine< int >::pull_type coro1( f20);
- coro::coroutine< int >::pull_type coro2( f16);
- BOOST_CHECK( ! coro1);
- BOOST_CHECK( coro2);
- BOOST_CHECK_EQUAL( 1, coro2.get() );
- coro2();
- BOOST_CHECK_EQUAL( 2, coro2.get() );
- coro1 = std::move( coro2);
- BOOST_CHECK( coro1);
- BOOST_CHECK( ! coro2);
- coro1();
- BOOST_CHECK_EQUAL( 3, coro1.get() );
- BOOST_CHECK( ! coro2);
- }
- {
- value3 = false;
- copyable cp( 3);
- BOOST_CHECK( cp.state);
- BOOST_CHECK( ! value3);
- coro::coroutine< int >::pull_type coro( cp);
- BOOST_CHECK( cp.state);
- BOOST_CHECK( value3);
- }
- {
- value3 = false;
- moveable mv( 7);
- BOOST_CHECK( mv.state);
- BOOST_CHECK( ! value3);
- coro::coroutine< int >::pull_type coro( std::move( mv) );
- BOOST_CHECK( ! mv.state);
- BOOST_CHECK( value3);
- }
- {
- value1 = 0;
- movedata mv( 7);
- BOOST_CHECK_EQUAL( 0, value1);
- BOOST_CHECK_EQUAL( 7, mv.i);
- coro::coroutine< movedata >::push_type coro( f22);
- coro( std::move( mv) );
- BOOST_CHECK_EQUAL( 7, value1);
- BOOST_CHECK_EQUAL( 0, mv.i);
- }
- }
- void test_complete()
- {
- value1 = 0;
- coro::coroutine< void >::pull_type coro( f2);
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( ( int)1, value1);
- }
- void test_bind()
- {
- value1 = 0;
- coro::coroutine< void >::pull_type coro( std::bind( f2, std::placeholders::_1) );
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( ( int)1, value1);
- }
- void test_jump()
- {
- value1 = 0;
- coro::coroutine< void >::pull_type 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::coroutine< int >::pull_type 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::coroutine< std::string >::pull_type 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::coroutine< int >::push_type coro( f6);
- BOOST_CHECK( coro);
- coro( 3);
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( 3, value1);
- }
- void test_arg_string()
- {
- value2 = "";
- coro::coroutine< std::string >::push_type 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::coroutine< std::tuple< double, double > >::push_type coro( f8);
- BOOST_CHECK( coro);
- coro( std::make_tuple( 7.35, 3.14) );
- BOOST_CHECK( coro);
- BOOST_CHECK_EQUAL( ( double) 10.49, value4);
- value4 = 0;
- coro( std::make_tuple( 1.15, 3.14) );
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( ( double) 4.29, value4);
- }
- void test_ptr()
- {
- value5 = nullptr;
- int a = 3;
- coro::coroutine< int * >::push_type coro( f9);
- BOOST_CHECK( coro);
- coro( & a);
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( & a, value5);
- }
- void test_const_ptr()
- {
- value5 = nullptr;
- int a = 3;
- coro::coroutine< int const* >::push_type coro( f91);
- BOOST_CHECK( coro);
- coro( & a);
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( & a, value5);
- }
- void test_ref()
- {
- value5 = nullptr;
- int a_ = 3;
- int & a = a_;
- coro::coroutine< int & >::push_type coro( f10);
- BOOST_CHECK( coro);
- coro( std::ref( a) );
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( & a, value5);
- }
- void test_const_ref()
- {
- value5 = nullptr;
- int a = 3;
- coro::coroutine< int const& >::push_type coro( f101);
- BOOST_CHECK( coro);
- coro( a);
- BOOST_CHECK( ! coro);
- BOOST_CHECK_EQUAL( & a, value5);
- }
- void test_no_result()
- {
- coro::coroutine< int >::pull_type coro( f20);
- BOOST_CHECK( ! coro);
- }
- void test_tuple()
- {
- value8 = 0;
- value9 = 0;
- int a = 3, b = 7;
- std::tuple< int, int > tpl( a, b);
- BOOST_CHECK_EQUAL( a, std::get< 0 >( tpl) );
- BOOST_CHECK_EQUAL( b, std::get< 1 >( tpl) );
- coro::coroutine< std::tuple< int, int > >::push_type 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::coroutine< void >::push_type 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);
- int i = 0;
- {
- coro::coroutine< void >::push_type coro(
- [&i](coro::coroutine< void >::pull_type &) mutable {
- i = 7;
- });
- }
- {
- BOOST_CHECK_EQUAL( ( int) 0, value1);
- auto * coro = new coro::coroutine< void >::pull_type(
- [](coro::coroutine< void >::push_type & coro) mutable {
- X x;
- coro();
- });
- BOOST_CHECK_EQUAL( ( int) 7, value1);
- delete coro;
- BOOST_CHECK_EQUAL( ( int) 0, value1);
- }
- {
- BOOST_CHECK_EQUAL( ( int) 0, value1);
- auto * coro = new coro::coroutine< void >::push_type(
- [](coro::coroutine< void >::pull_type & coro) mutable {
- X x;
- coro();
- });
- ( * coro)();
- BOOST_CHECK_EQUAL( ( int) 7, value1);
- delete coro;
- BOOST_CHECK_EQUAL( ( int) 0, value1);
- }
- }
- void test_exceptions()
- {
- std::string msg("abc"), value;
- std::runtime_error ex( msg);
- try
- {
- coro::coroutine< void >::push_type coro(
- [&msg]( coro::coroutine< void >::pull_type &) {
- throw std::runtime_error( msg);
- });
- BOOST_CHECK( coro);
- coro();
- BOOST_CHECK( ! coro);
- BOOST_CHECK( false);
- }
- catch ( std::runtime_error const& ex)
- { value = ex.what(); }
- BOOST_CHECK_EQUAL( value, msg);
- }
- void test_input_iterator()
- {
- {
- using std::begin;
- using std::end;
- std::vector< int > vec;
- coro::coroutine< int >::pull_type coro( f16);
- coro::coroutine< int >::pull_type::iterator e = end( coro);
- for (
- coro::coroutine< int >::pull_type::iterator i = 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] );
- }
- {
- std::vector< int > vec;
- coro::coroutine< int >::pull_type coro( f16);
- for ( auto 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] );
- }
- {
- int i1 = 1, i2 = 2, i3 = 3;
- coro::coroutine< int& >::pull_type coro(
- [&i1,&i2,&i3](coro::coroutine< int& >::push_type & c){
- c( i1);
- c( i2);
- c( i3);
- });
- int counter = 1;
- for ( int & i : coro) {
- switch ( counter) {
- case 1:
- BOOST_CHECK_EQUAL( & i1, & i);
- break;
- case 2:
- BOOST_CHECK_EQUAL( & i2, & i);
- break;
- case 3:
- BOOST_CHECK_EQUAL( & i3, & i);
- break;
- default:
- BOOST_ASSERT( false);
- }
- ++counter;
- }
- }
- }
- void test_output_iterator()
- {
- using std::begin;
- using std::end;
- int counter = 0;
- std::vector< int > vec;
- coro::coroutine< int >::push_type coro(
- [&vec]( coro::coroutine< int >::pull_type & c) {
- int x = c.get();
- while ( 5 > x)
- {
- vec.push_back( x);
- x = c().get();
- }
- });
- coro::coroutine< int >::push_type::iterator e( end( coro) );
- for ( coro::coroutine< int >::push_type::iterator i( 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] );
- }
- std::vector< int > vec;
- coro::coroutine< void >::pull_type * child = nullptr;
- void start_child_coroutine() {
- child = new coro::coroutine< void >::pull_type([](coro::coroutine< void >::push_type & yield) {
- vec.push_back( 2);
- yield();
- vec.push_back( 2);
- yield();
- vec.push_back( 2);
- yield();
- vec.push_back( 2);
- yield();
- vec.push_back( 2);
- yield();
- vec.push_back( 2);
- });
- }
- coro::coroutine< void >::pull_type start_parent_coroutine() {
- return coro::coroutine< void >::pull_type([=](coro::coroutine< void >::push_type & yield) {
- vec.push_back( 1);
- start_child_coroutine();
- yield();
- vec.push_back( 1);
- });
- }
- void test_chaining()
- {
- auto parent = start_parent_coroutine();
- while ( * child) {
- ( * child)();
- }
- BOOST_CHECK_EQUAL( 7, vec.size() );
- BOOST_CHECK_EQUAL( 1, vec[0]);
- BOOST_CHECK_EQUAL( 2, vec[1]);
- BOOST_CHECK_EQUAL( 2, vec[2]);
- BOOST_CHECK_EQUAL( 2, vec[3]);
- BOOST_CHECK_EQUAL( 2, vec[4]);
- BOOST_CHECK_EQUAL( 2, vec[5]);
- BOOST_CHECK_EQUAL( 2, vec[6]);
- }
- boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
- {
- boost::unit_test::test_suite * test =
- BOOST_TEST_SUITE("Boost.Coroutine2: coroutine test suite");
- test->add( BOOST_TEST_CASE( & test_move) );
- test->add( BOOST_TEST_CASE( & test_complete) );
- test->add( BOOST_TEST_CASE( & test_bind) );
- test->add( BOOST_TEST_CASE( & test_jump) );
- 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) );
- test->add( BOOST_TEST_CASE( & test_no_result) );
- 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_exceptions) );
- test->add( BOOST_TEST_CASE( & test_input_iterator) );
- test->add( BOOST_TEST_CASE( & test_output_iterator) );
- test->add( BOOST_TEST_CASE( & test_chaining) );
- return test;
- }
|