test_coroutine.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. // Copyright Oliver Kowalke 2014.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #include <algorithm>
  6. #include <cstdio>
  7. #include <iostream>
  8. #include <sstream>
  9. #include <stdexcept>
  10. #include <string>
  11. #include <tuple>
  12. #include <vector>
  13. #include <boost/assert.hpp>
  14. #include <boost/test/unit_test.hpp>
  15. #include <boost/coroutine2/coroutine.hpp>
  16. namespace coro = boost::coroutines2;
  17. int value1 = 0;
  18. std::string value2 = "";
  19. bool value3 = false;
  20. double value4 = .0;
  21. int * value5 = nullptr;
  22. int& value6 = value1;
  23. int& value7 = value1;
  24. int value8 = 0;
  25. int value9 = 0;
  26. struct X
  27. {
  28. X() { value1 = 7; }
  29. ~X() { value1 = 0; }
  30. X( X const&) = delete;
  31. X & operator=( X const&) = delete;
  32. };
  33. class copyable
  34. {
  35. public:
  36. bool state;
  37. copyable() :
  38. state( false)
  39. {}
  40. copyable( int) :
  41. state( true)
  42. {}
  43. void operator()( coro::coroutine< int >::push_type &)
  44. { value3 = state; }
  45. };
  46. class moveable
  47. {
  48. public:
  49. bool state;
  50. moveable() :
  51. state( false)
  52. {}
  53. moveable( int) :
  54. state( true)
  55. {}
  56. moveable( moveable const&) = delete;
  57. moveable & operator=( moveable const&) = delete;
  58. moveable( moveable && other) :
  59. state( false)
  60. { std::swap( state, other.state); }
  61. moveable & operator=( moveable && other)
  62. {
  63. if ( this != & other) {
  64. state = other.state;
  65. other.state = false;
  66. }
  67. return * this;
  68. }
  69. void operator()( coro::coroutine< int >::push_type &)
  70. { value3 = state; }
  71. };
  72. class movedata
  73. {
  74. public:
  75. int i;
  76. movedata( int i_) :
  77. i( i_)
  78. {}
  79. movedata( movedata const&) = delete;
  80. movedata & operator=( movedata const&) = delete;
  81. movedata( movedata && other) :
  82. i( 0)
  83. { std::swap( i, other.i); }
  84. movedata & operator=( movedata && other)
  85. {
  86. if ( this != & other) {
  87. i = other.i;
  88. other.i = 0;
  89. }
  90. return * this;
  91. }
  92. };
  93. struct my_exception {};
  94. void f1( coro::coroutine< void >::push_type & c)
  95. {
  96. while ( c)
  97. c();
  98. }
  99. void f2( coro::coroutine< void >::push_type &)
  100. { ++value1; }
  101. void f3( coro::coroutine< void >::push_type & c)
  102. {
  103. ++value1;
  104. c();
  105. ++value1;
  106. }
  107. void f4( coro::coroutine< int >::push_type & c)
  108. {
  109. c( 3);
  110. c( 7);
  111. }
  112. void f5( coro::coroutine< std::string >::push_type & c)
  113. {
  114. std::string res("abc");
  115. c( res);
  116. res = "xyz";
  117. c( res);
  118. }
  119. void f6( coro::coroutine< int >::pull_type & c)
  120. { value1 = c.get(); }
  121. void f7( coro::coroutine< std::string >::pull_type & c)
  122. { value2 = c.get(); }
  123. void f8( coro::coroutine< std::tuple< double, double > >::pull_type & c)
  124. {
  125. double x = 0, y = 0;
  126. std::tie( x, y) = c.get();
  127. value4 = x + y;
  128. c();
  129. std::tie( x, y) = c.get();
  130. value4 = x + y;
  131. }
  132. void f9( coro::coroutine< int * >::pull_type & c)
  133. { value5 = c.get(); }
  134. void f91( coro::coroutine< int const* >::pull_type & c)
  135. { value5 = const_cast< int * >( c.get() ); }
  136. void f10( coro::coroutine< int & >::pull_type & c)
  137. {
  138. int & i = c.get();
  139. value5 = const_cast< int * >( & i);
  140. }
  141. void f101( coro::coroutine< int const& >::pull_type & c)
  142. {
  143. int const& i = c.get();
  144. value5 = const_cast< int * >( & i);
  145. }
  146. void f11( coro::coroutine< std::tuple< int, int > >::pull_type & c)
  147. {
  148. std::tie( value8, value9) = c.get();
  149. }
  150. void f12( coro::coroutine< void >::pull_type & c)
  151. {
  152. value1 = 7;
  153. X x_;
  154. c();
  155. c();
  156. }
  157. void f16( coro::coroutine< int >::push_type & c)
  158. {
  159. c( 1);
  160. c( 2);
  161. c( 3);
  162. c( 4);
  163. c( 5);
  164. }
  165. void f17( coro::coroutine< int >::pull_type & c, std::vector< int > & vec)
  166. {
  167. int x = c.get();
  168. while ( 5 > x)
  169. {
  170. vec.push_back( x);
  171. x = c().get();
  172. }
  173. }
  174. void f20( coro::coroutine< int >::push_type &)
  175. {}
  176. void f21( coro::coroutine< int >::pull_type & c)
  177. {
  178. while ( c)
  179. {
  180. value1 = c.get();
  181. c();
  182. }
  183. }
  184. void f22( coro::coroutine< movedata >::pull_type & c)
  185. {
  186. movedata mv( c.get() );
  187. value1 = mv.i;
  188. }
  189. void test_move()
  190. {
  191. {
  192. coro::coroutine< int >::pull_type coro1( f20);
  193. coro::coroutine< int >::pull_type coro2( f16);
  194. BOOST_CHECK( ! coro1);
  195. BOOST_CHECK( coro2);
  196. BOOST_CHECK_EQUAL( 1, coro2.get() );
  197. coro2();
  198. BOOST_CHECK_EQUAL( 2, coro2.get() );
  199. coro1 = std::move( coro2);
  200. BOOST_CHECK( coro1);
  201. BOOST_CHECK( ! coro2);
  202. coro1();
  203. BOOST_CHECK_EQUAL( 3, coro1.get() );
  204. BOOST_CHECK( ! coro2);
  205. }
  206. {
  207. value3 = false;
  208. copyable cp( 3);
  209. BOOST_CHECK( cp.state);
  210. BOOST_CHECK( ! value3);
  211. coro::coroutine< int >::pull_type coro( cp);
  212. BOOST_CHECK( cp.state);
  213. BOOST_CHECK( value3);
  214. }
  215. {
  216. value3 = false;
  217. moveable mv( 7);
  218. BOOST_CHECK( mv.state);
  219. BOOST_CHECK( ! value3);
  220. coro::coroutine< int >::pull_type coro( std::move( mv) );
  221. BOOST_CHECK( ! mv.state);
  222. BOOST_CHECK( value3);
  223. }
  224. {
  225. value1 = 0;
  226. movedata mv( 7);
  227. BOOST_CHECK_EQUAL( 0, value1);
  228. BOOST_CHECK_EQUAL( 7, mv.i);
  229. coro::coroutine< movedata >::push_type coro( f22);
  230. coro( std::move( mv) );
  231. BOOST_CHECK_EQUAL( 7, value1);
  232. BOOST_CHECK_EQUAL( 0, mv.i);
  233. }
  234. }
  235. void test_complete()
  236. {
  237. value1 = 0;
  238. coro::coroutine< void >::pull_type coro( f2);
  239. BOOST_CHECK( ! coro);
  240. BOOST_CHECK_EQUAL( ( int)1, value1);
  241. }
  242. void test_bind()
  243. {
  244. value1 = 0;
  245. coro::coroutine< void >::pull_type coro( std::bind( f2, std::placeholders::_1) );
  246. BOOST_CHECK( ! coro);
  247. BOOST_CHECK_EQUAL( ( int)1, value1);
  248. }
  249. void test_jump()
  250. {
  251. value1 = 0;
  252. coro::coroutine< void >::pull_type coro( f3);
  253. BOOST_CHECK( coro);
  254. BOOST_CHECK_EQUAL( ( int)1, value1);
  255. coro();
  256. BOOST_CHECK( ! coro);
  257. BOOST_CHECK_EQUAL( ( int)2, value1);
  258. }
  259. void test_result_int()
  260. {
  261. coro::coroutine< int >::pull_type coro( f4);
  262. BOOST_CHECK( coro);
  263. int result = coro.get();
  264. BOOST_CHECK( coro);
  265. BOOST_CHECK_EQUAL( 3, result);
  266. result = coro().get();
  267. BOOST_CHECK( coro);
  268. BOOST_CHECK_EQUAL( 7, result);
  269. coro();
  270. BOOST_CHECK( ! coro);
  271. }
  272. void test_result_string()
  273. {
  274. coro::coroutine< std::string >::pull_type coro( f5);
  275. BOOST_CHECK( coro);
  276. std::string result = coro.get();
  277. BOOST_CHECK( coro);
  278. BOOST_CHECK_EQUAL( std::string("abc"), result);
  279. result = coro().get();
  280. BOOST_CHECK( coro);
  281. BOOST_CHECK_EQUAL( std::string("xyz"), result);
  282. coro();
  283. BOOST_CHECK( ! coro);
  284. }
  285. void test_arg_int()
  286. {
  287. value1 = 0;
  288. coro::coroutine< int >::push_type coro( f6);
  289. BOOST_CHECK( coro);
  290. coro( 3);
  291. BOOST_CHECK( ! coro);
  292. BOOST_CHECK_EQUAL( 3, value1);
  293. }
  294. void test_arg_string()
  295. {
  296. value2 = "";
  297. coro::coroutine< std::string >::push_type coro( f7);
  298. BOOST_CHECK( coro);
  299. coro( std::string("abc") );
  300. BOOST_CHECK( ! coro);
  301. BOOST_CHECK_EQUAL( std::string("abc"), value2);
  302. }
  303. void test_fp()
  304. {
  305. value4 = 0;
  306. coro::coroutine< std::tuple< double, double > >::push_type coro( f8);
  307. BOOST_CHECK( coro);
  308. coro( std::make_tuple( 7.35, 3.14) );
  309. BOOST_CHECK( coro);
  310. BOOST_CHECK_EQUAL( ( double) 10.49, value4);
  311. value4 = 0;
  312. coro( std::make_tuple( 1.15, 3.14) );
  313. BOOST_CHECK( ! coro);
  314. BOOST_CHECK_EQUAL( ( double) 4.29, value4);
  315. }
  316. void test_ptr()
  317. {
  318. value5 = nullptr;
  319. int a = 3;
  320. coro::coroutine< int * >::push_type coro( f9);
  321. BOOST_CHECK( coro);
  322. coro( & a);
  323. BOOST_CHECK( ! coro);
  324. BOOST_CHECK_EQUAL( & a, value5);
  325. }
  326. void test_const_ptr()
  327. {
  328. value5 = nullptr;
  329. int a = 3;
  330. coro::coroutine< int const* >::push_type coro( f91);
  331. BOOST_CHECK( coro);
  332. coro( & a);
  333. BOOST_CHECK( ! coro);
  334. BOOST_CHECK_EQUAL( & a, value5);
  335. }
  336. void test_ref()
  337. {
  338. value5 = nullptr;
  339. int a_ = 3;
  340. int & a = a_;
  341. coro::coroutine< int & >::push_type coro( f10);
  342. BOOST_CHECK( coro);
  343. coro( std::ref( a) );
  344. BOOST_CHECK( ! coro);
  345. BOOST_CHECK_EQUAL( & a, value5);
  346. }
  347. void test_const_ref()
  348. {
  349. value5 = nullptr;
  350. int a = 3;
  351. coro::coroutine< int const& >::push_type coro( f101);
  352. BOOST_CHECK( coro);
  353. coro( a);
  354. BOOST_CHECK( ! coro);
  355. BOOST_CHECK_EQUAL( & a, value5);
  356. }
  357. void test_no_result()
  358. {
  359. coro::coroutine< int >::pull_type coro( f20);
  360. BOOST_CHECK( ! coro);
  361. }
  362. void test_tuple()
  363. {
  364. value8 = 0;
  365. value9 = 0;
  366. int a = 3, b = 7;
  367. std::tuple< int, int > tpl( a, b);
  368. BOOST_CHECK_EQUAL( a, std::get< 0 >( tpl) );
  369. BOOST_CHECK_EQUAL( b, std::get< 1 >( tpl) );
  370. coro::coroutine< std::tuple< int, int > >::push_type coro( f11);
  371. BOOST_CHECK( coro);
  372. coro( tpl);
  373. BOOST_CHECK( ! coro);
  374. BOOST_CHECK_EQUAL( a, value8);
  375. BOOST_CHECK_EQUAL( b, value9);
  376. }
  377. void test_unwind()
  378. {
  379. value1 = 0;
  380. {
  381. coro::coroutine< void >::push_type coro( f12);
  382. BOOST_CHECK( coro);
  383. BOOST_CHECK_EQUAL( ( int) 0, value1);
  384. coro();
  385. BOOST_CHECK( coro);
  386. BOOST_CHECK_EQUAL( ( int) 7, value1);
  387. coro();
  388. BOOST_CHECK_EQUAL( ( int) 7, value1);
  389. }
  390. BOOST_CHECK_EQUAL( ( int) 0, value1);
  391. int i = 0;
  392. {
  393. coro::coroutine< void >::push_type coro(
  394. [&i](coro::coroutine< void >::pull_type &) mutable {
  395. i = 7;
  396. });
  397. }
  398. {
  399. BOOST_CHECK_EQUAL( ( int) 0, value1);
  400. auto * coro = new coro::coroutine< void >::pull_type(
  401. [](coro::coroutine< void >::push_type & coro) mutable {
  402. X x;
  403. coro();
  404. });
  405. BOOST_CHECK_EQUAL( ( int) 7, value1);
  406. delete coro;
  407. BOOST_CHECK_EQUAL( ( int) 0, value1);
  408. }
  409. {
  410. BOOST_CHECK_EQUAL( ( int) 0, value1);
  411. auto * coro = new coro::coroutine< void >::push_type(
  412. [](coro::coroutine< void >::pull_type & coro) mutable {
  413. X x;
  414. coro();
  415. });
  416. ( * coro)();
  417. BOOST_CHECK_EQUAL( ( int) 7, value1);
  418. delete coro;
  419. BOOST_CHECK_EQUAL( ( int) 0, value1);
  420. }
  421. }
  422. void test_exceptions()
  423. {
  424. std::string msg("abc"), value;
  425. std::runtime_error ex( msg);
  426. try
  427. {
  428. coro::coroutine< void >::push_type coro(
  429. [&msg]( coro::coroutine< void >::pull_type &) {
  430. throw std::runtime_error( msg);
  431. });
  432. BOOST_CHECK( coro);
  433. coro();
  434. BOOST_CHECK( ! coro);
  435. BOOST_CHECK( false);
  436. }
  437. catch ( std::runtime_error const& ex)
  438. { value = ex.what(); }
  439. BOOST_CHECK_EQUAL( value, msg);
  440. }
  441. void test_input_iterator()
  442. {
  443. {
  444. using std::begin;
  445. using std::end;
  446. std::vector< int > vec;
  447. coro::coroutine< int >::pull_type coro( f16);
  448. coro::coroutine< int >::pull_type::iterator e = end( coro);
  449. for (
  450. coro::coroutine< int >::pull_type::iterator i = begin( coro);
  451. i != e; ++i)
  452. { vec.push_back( * i); }
  453. BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() );
  454. BOOST_CHECK_EQUAL( ( int)1, vec[0] );
  455. BOOST_CHECK_EQUAL( ( int)2, vec[1] );
  456. BOOST_CHECK_EQUAL( ( int)3, vec[2] );
  457. BOOST_CHECK_EQUAL( ( int)4, vec[3] );
  458. BOOST_CHECK_EQUAL( ( int)5, vec[4] );
  459. }
  460. {
  461. std::vector< int > vec;
  462. coro::coroutine< int >::pull_type coro( f16);
  463. for ( auto i : coro)
  464. { vec.push_back( i); }
  465. BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() );
  466. BOOST_CHECK_EQUAL( ( int)1, vec[0] );
  467. BOOST_CHECK_EQUAL( ( int)2, vec[1] );
  468. BOOST_CHECK_EQUAL( ( int)3, vec[2] );
  469. BOOST_CHECK_EQUAL( ( int)4, vec[3] );
  470. BOOST_CHECK_EQUAL( ( int)5, vec[4] );
  471. }
  472. {
  473. int i1 = 1, i2 = 2, i3 = 3;
  474. coro::coroutine< int& >::pull_type coro(
  475. [&i1,&i2,&i3](coro::coroutine< int& >::push_type & c){
  476. c( i1);
  477. c( i2);
  478. c( i3);
  479. });
  480. int counter = 1;
  481. for ( int & i : coro) {
  482. switch ( counter) {
  483. case 1:
  484. BOOST_CHECK_EQUAL( & i1, & i);
  485. break;
  486. case 2:
  487. BOOST_CHECK_EQUAL( & i2, & i);
  488. break;
  489. case 3:
  490. BOOST_CHECK_EQUAL( & i3, & i);
  491. break;
  492. default:
  493. BOOST_ASSERT( false);
  494. }
  495. ++counter;
  496. }
  497. }
  498. }
  499. void test_output_iterator()
  500. {
  501. using std::begin;
  502. using std::end;
  503. int counter = 0;
  504. std::vector< int > vec;
  505. coro::coroutine< int >::push_type coro(
  506. [&vec]( coro::coroutine< int >::pull_type & c) {
  507. int x = c.get();
  508. while ( 5 > x)
  509. {
  510. vec.push_back( x);
  511. x = c().get();
  512. }
  513. });
  514. coro::coroutine< int >::push_type::iterator e( end( coro) );
  515. for ( coro::coroutine< int >::push_type::iterator i( begin( coro) );
  516. i != e; ++i)
  517. {
  518. i = ++counter;
  519. }
  520. BOOST_CHECK_EQUAL( ( std::size_t)4, vec.size() );
  521. BOOST_CHECK_EQUAL( ( int)1, vec[0] );
  522. BOOST_CHECK_EQUAL( ( int)2, vec[1] );
  523. BOOST_CHECK_EQUAL( ( int)3, vec[2] );
  524. BOOST_CHECK_EQUAL( ( int)4, vec[3] );
  525. }
  526. std::vector< int > vec;
  527. coro::coroutine< void >::pull_type * child = nullptr;
  528. void start_child_coroutine() {
  529. child = new coro::coroutine< void >::pull_type([](coro::coroutine< void >::push_type & yield) {
  530. vec.push_back( 2);
  531. yield();
  532. vec.push_back( 2);
  533. yield();
  534. vec.push_back( 2);
  535. yield();
  536. vec.push_back( 2);
  537. yield();
  538. vec.push_back( 2);
  539. yield();
  540. vec.push_back( 2);
  541. });
  542. }
  543. coro::coroutine< void >::pull_type start_parent_coroutine() {
  544. return coro::coroutine< void >::pull_type([=](coro::coroutine< void >::push_type & yield) {
  545. vec.push_back( 1);
  546. start_child_coroutine();
  547. yield();
  548. vec.push_back( 1);
  549. });
  550. }
  551. void test_chaining()
  552. {
  553. auto parent = start_parent_coroutine();
  554. while ( * child) {
  555. ( * child)();
  556. }
  557. BOOST_CHECK_EQUAL( 7, vec.size() );
  558. BOOST_CHECK_EQUAL( 1, vec[0]);
  559. BOOST_CHECK_EQUAL( 2, vec[1]);
  560. BOOST_CHECK_EQUAL( 2, vec[2]);
  561. BOOST_CHECK_EQUAL( 2, vec[3]);
  562. BOOST_CHECK_EQUAL( 2, vec[4]);
  563. BOOST_CHECK_EQUAL( 2, vec[5]);
  564. BOOST_CHECK_EQUAL( 2, vec[6]);
  565. }
  566. boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
  567. {
  568. boost::unit_test::test_suite * test =
  569. BOOST_TEST_SUITE("Boost.Coroutine2: coroutine test suite");
  570. test->add( BOOST_TEST_CASE( & test_move) );
  571. test->add( BOOST_TEST_CASE( & test_complete) );
  572. test->add( BOOST_TEST_CASE( & test_bind) );
  573. test->add( BOOST_TEST_CASE( & test_jump) );
  574. test->add( BOOST_TEST_CASE( & test_result_int) );
  575. test->add( BOOST_TEST_CASE( & test_result_string) );
  576. test->add( BOOST_TEST_CASE( & test_arg_int) );
  577. test->add( BOOST_TEST_CASE( & test_arg_string) );
  578. test->add( BOOST_TEST_CASE( & test_fp) );
  579. test->add( BOOST_TEST_CASE( & test_ptr) );
  580. test->add( BOOST_TEST_CASE( & test_const_ptr) );
  581. test->add( BOOST_TEST_CASE( & test_no_result) );
  582. test->add( BOOST_TEST_CASE( & test_ref) );
  583. test->add( BOOST_TEST_CASE( & test_const_ref) );
  584. test->add( BOOST_TEST_CASE( & test_tuple) );
  585. test->add( BOOST_TEST_CASE( & test_unwind) );
  586. test->add( BOOST_TEST_CASE( & test_exceptions) );
  587. test->add( BOOST_TEST_CASE( & test_input_iterator) );
  588. test->add( BOOST_TEST_CASE( & test_output_iterator) );
  589. test->add( BOOST_TEST_CASE( & test_chaining) );
  590. return test;
  591. }