test_symmetric_coroutine.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  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/symmetric_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/lexical_cast.hpp>
  17. #include <boost/move/move.hpp>
  18. #include <boost/range.hpp>
  19. #include <boost/ref.hpp>
  20. #include <boost/test/unit_test.hpp>
  21. #include <boost/tuple/tuple.hpp>
  22. #include <boost/utility.hpp>
  23. namespace coro = boost::coroutines;
  24. bool value1 = false;
  25. int value2 = 0;
  26. std::string value3;
  27. typedef void( * coro_fn_void)(coro::symmetric_coroutine< void* >::yield_type &);
  28. coro::symmetric_coroutine< void >::call_type * term_coro = 0;
  29. struct X
  30. {
  31. int i;
  32. X() :
  33. i( 0)
  34. {}
  35. X( int i_) :
  36. i( i_)
  37. {}
  38. };
  39. X * p = 0;
  40. struct Y
  41. {
  42. Y()
  43. { value2 = 7; }
  44. ~Y()
  45. { value2 = 0; }
  46. };
  47. template< typename X, typename I >
  48. void trampoline( coro::symmetric_coroutine< void* >::yield_type & yield)
  49. {
  50. void * vp = yield.get();
  51. X * x = static_cast< X * >( vp);
  52. I i( yield);
  53. x->d = & i;
  54. i.suspend();
  55. i.run();
  56. }
  57. struct B
  58. {
  59. virtual ~B() {}
  60. virtual void foo() = 0;
  61. };
  62. class D : public B
  63. {
  64. public:
  65. int count;
  66. coro::symmetric_coroutine< void* >::call_type call;
  67. coro::symmetric_coroutine< void* >::yield_type * yield;
  68. D( coro::symmetric_coroutine< void* >::yield_type & yield_) :
  69. B(),
  70. count( 0),
  71. call(),
  72. yield( & yield_)
  73. {}
  74. void foo() {}
  75. void resume()
  76. { call( 0); }
  77. void suspend()
  78. { ( *yield)(); }
  79. void run()
  80. {
  81. while ( yield && * yield)
  82. {
  83. ++count;
  84. suspend();
  85. }
  86. }
  87. };
  88. struct T
  89. {
  90. D * d;
  91. T() :
  92. d( 0)
  93. {}
  94. };
  95. class copyable
  96. {
  97. public:
  98. bool state;
  99. copyable() :
  100. state( false)
  101. {}
  102. copyable( int) :
  103. state( true)
  104. {}
  105. void operator()( coro::symmetric_coroutine< bool >::yield_type & yield)
  106. {
  107. if ( yield)
  108. value1 = yield.get();
  109. }
  110. };
  111. class moveable
  112. {
  113. private:
  114. BOOST_MOVABLE_BUT_NOT_COPYABLE( moveable)
  115. public:
  116. bool state;
  117. moveable() :
  118. state( false)
  119. {}
  120. moveable( int) :
  121. state( true)
  122. {}
  123. moveable( BOOST_RV_REF( moveable) other) :
  124. state( false)
  125. { std::swap( state, other.state); }
  126. moveable & operator=( BOOST_RV_REF( moveable) other)
  127. {
  128. if ( this == & other) return * this;
  129. moveable tmp( boost::move( other) );
  130. std::swap( state, tmp.state);
  131. return * this;
  132. }
  133. void operator()( coro::symmetric_coroutine< int >::yield_type &)
  134. { value1 = state; }
  135. };
  136. void empty( coro::symmetric_coroutine< void >::yield_type &) {}
  137. void f2( coro::symmetric_coroutine< void >::yield_type &)
  138. { ++value2; }
  139. void f3( coro::symmetric_coroutine< X >::yield_type & yield)
  140. { value2 = yield.get().i; }
  141. void f4( coro::symmetric_coroutine< X& >::yield_type & yield)
  142. {
  143. X & x = yield.get();
  144. p = & x;
  145. }
  146. void f5( coro::symmetric_coroutine< X* >::yield_type & yield)
  147. { p = yield.get(); }
  148. void f6( coro::symmetric_coroutine< void >::yield_type & yield)
  149. {
  150. Y y;
  151. yield( *term_coro);
  152. }
  153. void f7( coro::symmetric_coroutine< int >::yield_type & yield)
  154. {
  155. value2 = yield.get();
  156. yield( *term_coro);
  157. value2 = yield.get();
  158. }
  159. template< typename E >
  160. void f9( coro::symmetric_coroutine< void >::yield_type &, E const& e)
  161. { throw e; }
  162. void f10( coro::symmetric_coroutine< int >::yield_type & yield,
  163. coro::symmetric_coroutine< int >::call_type & other)
  164. {
  165. int i = yield.get();
  166. yield( other, i);
  167. value2 = yield.get();
  168. }
  169. void f101( coro::symmetric_coroutine< int >::yield_type & yield)
  170. { value2 = yield.get(); }
  171. void f11( coro::symmetric_coroutine< void >::yield_type & yield,
  172. coro::symmetric_coroutine< void >::call_type & other)
  173. {
  174. yield( other);
  175. value2 = 7;
  176. }
  177. void f111( coro::symmetric_coroutine< void >::yield_type &)
  178. { value2 = 3; }
  179. void f12( coro::symmetric_coroutine< X& >::yield_type & yield,
  180. coro::symmetric_coroutine< X& >::call_type & other)
  181. {
  182. yield( other, yield.get());
  183. p = & yield.get();
  184. }
  185. void f121( coro::symmetric_coroutine< X& >::yield_type & yield)
  186. { p = & yield.get(); }
  187. void f14( coro::symmetric_coroutine< int >::yield_type & yield,
  188. coro::symmetric_coroutine< std::string >::call_type & other)
  189. {
  190. std::string str( boost::lexical_cast< std::string >( yield.get() ) );
  191. yield( other, str);
  192. value2 = yield.get();
  193. }
  194. void f141( coro::symmetric_coroutine< std::string >::yield_type & yield)
  195. { value3 = yield.get(); }
  196. void f15( coro::symmetric_coroutine< int >::yield_type & yield,
  197. int offset,
  198. coro::symmetric_coroutine< int >::call_type & other)
  199. {
  200. int x = yield.get();
  201. value2 += x + offset;
  202. yield( other, x);
  203. x = yield.get();
  204. value2 += x + offset;
  205. yield( other, x);
  206. }
  207. void f151( coro::symmetric_coroutine< int >::yield_type & yield,
  208. int offset)
  209. {
  210. int x = yield.get();
  211. value2 += x + offset;
  212. yield();
  213. x = yield.get();
  214. value2 += x + offset;
  215. }
  216. void f16( coro::symmetric_coroutine< int >::yield_type & yield)
  217. {
  218. while ( yield)
  219. {
  220. value2 = yield.get();
  221. yield();
  222. }
  223. }
  224. void test_move()
  225. {
  226. {
  227. coro::symmetric_coroutine< void >::call_type coro1;
  228. coro::symmetric_coroutine< void >::call_type coro2( empty);
  229. BOOST_CHECK( ! coro1);
  230. BOOST_CHECK( coro2);
  231. coro1 = boost::move( coro2);
  232. BOOST_CHECK( coro1);
  233. BOOST_CHECK( ! coro2);
  234. }
  235. {
  236. value1 = false;
  237. copyable cp( 3);
  238. BOOST_CHECK( cp.state);
  239. BOOST_CHECK( ! value1);
  240. coro::symmetric_coroutine< bool >::call_type coro( cp);
  241. coro( true);
  242. BOOST_CHECK( cp.state);
  243. BOOST_CHECK( value1);
  244. }
  245. {
  246. value1 = false;
  247. moveable mv( 7);
  248. BOOST_CHECK( mv.state);
  249. BOOST_CHECK( ! value1);
  250. coro::symmetric_coroutine< int >::call_type coro( boost::move( mv) );
  251. coro( 7);
  252. BOOST_CHECK( ! mv.state);
  253. BOOST_CHECK( value1);
  254. }
  255. }
  256. void test_complete()
  257. {
  258. value2 = 0;
  259. coro::symmetric_coroutine< void >::call_type coro( f2);
  260. BOOST_CHECK( coro);
  261. coro();
  262. BOOST_CHECK( ! coro);
  263. BOOST_CHECK_EQUAL( ( int)1, value2);
  264. }
  265. void test_yield()
  266. {
  267. value2 = 0;
  268. coro::symmetric_coroutine< int >::call_type coro3(
  269. boost::bind( f151, _1, 3) );
  270. BOOST_CHECK( coro3);
  271. coro::symmetric_coroutine< int >::call_type coro2(
  272. boost::bind( f15, _1, 2, boost::ref( coro3) ) );
  273. BOOST_CHECK( coro2);
  274. coro::symmetric_coroutine< int >::call_type coro1(
  275. boost::bind( f15, _1, 1, boost::ref( coro2) ) );
  276. BOOST_CHECK( coro1);
  277. BOOST_CHECK_EQUAL( ( int)0, value2);
  278. coro1( 1);
  279. BOOST_CHECK( coro3);
  280. BOOST_CHECK( coro2);
  281. BOOST_CHECK( coro1);
  282. BOOST_CHECK_EQUAL( ( int)9, value2);
  283. coro1( 2);
  284. BOOST_CHECK( ! coro3);
  285. BOOST_CHECK( coro2);
  286. BOOST_CHECK( coro1);
  287. BOOST_CHECK_EQUAL( ( int)21, value2);
  288. }
  289. void test_pass_value()
  290. {
  291. value2 = 0;
  292. X x(7);
  293. BOOST_CHECK_EQUAL( ( int)7, x.i);
  294. BOOST_CHECK_EQUAL( 0, value2);
  295. coro::symmetric_coroutine< X >::call_type coro( f3);
  296. BOOST_CHECK( coro);
  297. coro(7);
  298. BOOST_CHECK( ! coro);
  299. BOOST_CHECK_EQUAL( ( int)7, x.i);
  300. BOOST_CHECK_EQUAL( 7, value2);
  301. }
  302. void test_pass_reference()
  303. {
  304. p = 0;
  305. X x;
  306. coro::symmetric_coroutine< X& >::call_type coro( f4);
  307. BOOST_CHECK( coro);
  308. coro( x);
  309. BOOST_CHECK( ! coro);
  310. BOOST_CHECK( p == & x);
  311. }
  312. void test_pass_pointer()
  313. {
  314. p = 0;
  315. X x;
  316. coro::symmetric_coroutine< X* >::call_type coro( f5);
  317. BOOST_CHECK( coro);
  318. coro( & x);
  319. BOOST_CHECK( ! coro);
  320. BOOST_CHECK( p == & x);
  321. }
  322. void test_unwind()
  323. {
  324. value2 = 0;
  325. {
  326. coro::symmetric_coroutine< void >::call_type coro( f6);
  327. coro::symmetric_coroutine< void >::call_type coro_e( empty);
  328. BOOST_CHECK( coro);
  329. BOOST_CHECK( coro_e);
  330. term_coro = & coro_e;
  331. BOOST_CHECK_EQUAL( ( int) 0, value2);
  332. coro();
  333. BOOST_CHECK( coro);
  334. BOOST_CHECK_EQUAL( ( int) 7, value2);
  335. }
  336. BOOST_CHECK_EQUAL( ( int) 0, value2);
  337. }
  338. void test_no_unwind()
  339. {
  340. value2 = 0;
  341. {
  342. coro::symmetric_coroutine< void >::call_type coro( f6,
  343. coro::attributes(
  344. coro::stack_allocator::traits_type::default_size(),
  345. coro::no_stack_unwind) );
  346. coro::symmetric_coroutine< void >::call_type coro_e( empty);
  347. BOOST_CHECK( coro);
  348. BOOST_CHECK( coro_e);
  349. term_coro = & coro_e;
  350. BOOST_CHECK_EQUAL( ( int) 0, value2);
  351. coro();
  352. BOOST_CHECK( coro);
  353. BOOST_CHECK_EQUAL( ( int) 7, value2);
  354. }
  355. BOOST_CHECK_EQUAL( ( int) 7, value2);
  356. }
  357. void test_termination()
  358. {
  359. value2 = 0;
  360. coro::symmetric_coroutine< int >::call_type coro( f7);
  361. coro::symmetric_coroutine< void >::call_type coro_e( empty);
  362. BOOST_CHECK( coro);
  363. BOOST_CHECK( coro_e);
  364. term_coro = & coro_e;
  365. BOOST_CHECK_EQUAL( ( int) 0, value2);
  366. coro(3);
  367. BOOST_CHECK( coro);
  368. BOOST_CHECK_EQUAL( ( int) 3, value2);
  369. coro(7);
  370. BOOST_CHECK( ! coro);
  371. BOOST_CHECK_EQUAL( ( int) 7, value2);
  372. }
  373. void test_yield_to_void()
  374. {
  375. value2 = 0;
  376. coro::symmetric_coroutine< void >::call_type coro_other( f111);
  377. coro::symmetric_coroutine< void >::call_type coro( boost::bind( f11, _1, boost::ref( coro_other) ) );
  378. BOOST_CHECK( coro_other);
  379. BOOST_CHECK( coro);
  380. BOOST_CHECK_EQUAL( ( int) 0, value2);
  381. coro();
  382. BOOST_CHECK( ! coro_other);
  383. BOOST_CHECK( coro);
  384. BOOST_CHECK_EQUAL( ( int) 3, value2);
  385. coro();
  386. BOOST_CHECK( ! coro_other);
  387. BOOST_CHECK( ! coro);
  388. BOOST_CHECK_EQUAL( ( int) 7, value2);
  389. }
  390. void test_yield_to_int()
  391. {
  392. value2 = 0;
  393. coro::symmetric_coroutine< int >::call_type coro_other( f101);
  394. coro::symmetric_coroutine< int >::call_type coro( boost::bind( f10, _1, boost::ref( coro_other) ) );
  395. BOOST_CHECK( coro_other);
  396. BOOST_CHECK( coro);
  397. BOOST_CHECK_EQUAL( ( int) 0, value2);
  398. coro(3);
  399. BOOST_CHECK( ! coro_other);
  400. BOOST_CHECK( coro);
  401. BOOST_CHECK_EQUAL( ( int) 3, value2);
  402. coro(7);
  403. BOOST_CHECK( ! coro_other);
  404. BOOST_CHECK( ! coro);
  405. BOOST_CHECK_EQUAL( ( int) 7, value2);
  406. }
  407. void test_yield_to_ref()
  408. {
  409. p = 0;
  410. coro::symmetric_coroutine< X& >::call_type coro_other( f121);
  411. coro::symmetric_coroutine< X& >::call_type coro( boost::bind( f12, _1, boost::ref( coro_other) ) );
  412. BOOST_CHECK( coro_other);
  413. BOOST_CHECK( coro);
  414. BOOST_CHECK( 0 == p);
  415. X x1(3);
  416. coro( x1);
  417. BOOST_CHECK( ! coro_other);
  418. BOOST_CHECK( coro);
  419. BOOST_CHECK_EQUAL( p->i, x1.i);
  420. BOOST_CHECK( p == & x1);
  421. X x2(7);
  422. coro(x2);
  423. BOOST_CHECK( ! coro_other);
  424. BOOST_CHECK( ! coro);
  425. BOOST_CHECK_EQUAL( p->i, x2.i);
  426. BOOST_CHECK( p == & x2);
  427. }
  428. void test_yield_to_different()
  429. {
  430. value2 = 0;
  431. value3 = "";
  432. coro::symmetric_coroutine< std::string >::call_type coro_other( f141);
  433. coro::symmetric_coroutine< int >::call_type coro( boost::bind( f14, _1, boost::ref( coro_other) ) );
  434. BOOST_CHECK( coro_other);
  435. BOOST_CHECK( coro);
  436. BOOST_CHECK_EQUAL( ( int) 0, value2);
  437. BOOST_CHECK( value3.empty() );
  438. coro(3);
  439. BOOST_CHECK( ! coro_other);
  440. BOOST_CHECK( coro);
  441. BOOST_CHECK_EQUAL( "3", value3);
  442. coro(7);
  443. BOOST_CHECK( ! coro_other);
  444. BOOST_CHECK( ! coro);
  445. BOOST_CHECK_EQUAL( ( int) 7, value2);
  446. }
  447. void test_move_coro()
  448. {
  449. value2 = 0;
  450. coro::symmetric_coroutine< int >::call_type coro1( f16);
  451. coro::symmetric_coroutine< int >::call_type coro2;
  452. BOOST_CHECK( coro1);
  453. BOOST_CHECK( ! coro2);
  454. coro1( 1);
  455. BOOST_CHECK_EQUAL( ( int)1, value2);
  456. coro2 = boost::move( coro1);
  457. BOOST_CHECK( ! coro1);
  458. BOOST_CHECK( coro2);
  459. coro2( 2);
  460. BOOST_CHECK_EQUAL( ( int)2, value2);
  461. coro1 = boost::move( coro2);
  462. BOOST_CHECK( coro1);
  463. BOOST_CHECK( ! coro2);
  464. coro1( 3);
  465. BOOST_CHECK_EQUAL( ( int)3, value2);
  466. coro2 = boost::move( coro1);
  467. BOOST_CHECK( ! coro1);
  468. BOOST_CHECK( coro2);
  469. coro2( 4);
  470. BOOST_CHECK_EQUAL( ( int)4, value2);
  471. }
  472. void test_vptr()
  473. {
  474. D * d = 0;
  475. T t;
  476. coro_fn_void fn = trampoline< T, D >;
  477. coro::symmetric_coroutine< void* >::call_type call( fn);
  478. call( & t);
  479. d = t.d;
  480. BOOST_CHECK( 0 != d);
  481. d->call = boost::move( call);
  482. BOOST_CHECK_EQUAL( ( int) 0, d->count);
  483. d->resume();
  484. BOOST_CHECK_EQUAL( ( int) 1, d->count);
  485. d->resume();
  486. BOOST_CHECK_EQUAL( ( int) 2, d->count);
  487. }
  488. boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
  489. {
  490. boost::unit_test::test_suite * test =
  491. BOOST_TEST_SUITE("Boost.coroutine: symmetric coroutine test suite");
  492. test->add( BOOST_TEST_CASE( & test_move) );
  493. test->add( BOOST_TEST_CASE( & test_complete) );
  494. test->add( BOOST_TEST_CASE( & test_yield) );
  495. test->add( BOOST_TEST_CASE( & test_pass_value) );
  496. test->add( BOOST_TEST_CASE( & test_pass_reference) );
  497. test->add( BOOST_TEST_CASE( & test_pass_pointer) );
  498. test->add( BOOST_TEST_CASE( & test_termination) );
  499. test->add( BOOST_TEST_CASE( & test_unwind) );
  500. test->add( BOOST_TEST_CASE( & test_no_unwind) );
  501. test->add( BOOST_TEST_CASE( & test_yield_to_void) );
  502. test->add( BOOST_TEST_CASE( & test_yield_to_int) );
  503. test->add( BOOST_TEST_CASE( & test_yield_to_ref) );
  504. test->add( BOOST_TEST_CASE( & test_yield_to_different) );
  505. test->add( BOOST_TEST_CASE( & test_move_coro) );
  506. test->add( BOOST_TEST_CASE( & test_vptr) );
  507. return test;
  508. }