test_asymmetric_coroutine.cpp 15 KB

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