2 // Copyright Oliver Kowalke 2009.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
7 #include <boost/coroutine/symmetric_coroutine.hpp>
18 #include <boost/assert.hpp>
19 #include <boost/bind.hpp>
20 #include <boost/foreach.hpp>
21 #include <boost/lexical_cast.hpp>
22 #include <boost/move/move.hpp>
23 #include <boost/range.hpp>
24 #include <boost/ref.hpp>
25 #include <boost/test/unit_test.hpp>
26 #include <boost/tuple/tuple.hpp>
27 #include <boost/utility.hpp>
29 namespace coro = boost::coroutines;
35 typedef void( * coro_fn_void)(coro::symmetric_coroutine< void* >::yield_type &);
37 coro::symmetric_coroutine< void >::call_type * term_coro = 0;
63 template< typename X, typename I >
64 void trampoline( coro::symmetric_coroutine< void* >::yield_type & yield)
66 void * vp = yield.get();
67 X * x = static_cast< X * >( vp);
78 virtual void foo() = 0;
85 coro::symmetric_coroutine< void* >::call_type call;
86 coro::symmetric_coroutine< void* >::yield_type * yield;
88 D( coro::symmetric_coroutine< void* >::yield_type & yield_) :
105 while ( yield && * yield)
135 void operator()( coro::symmetric_coroutine< bool >::yield_type & yield)
138 value1 = yield.get();
145 BOOST_MOVABLE_BUT_NOT_COPYABLE( moveable)
158 moveable( BOOST_RV_REF( moveable) other) :
160 { std::swap( state, other.state); }
162 moveable & operator=( BOOST_RV_REF( moveable) other)
164 if ( this == & other) return * this;
165 moveable tmp( boost::move( other) );
166 std::swap( state, tmp.state);
170 void operator()( coro::symmetric_coroutine< int >::yield_type &)
174 void empty( coro::symmetric_coroutine< void >::yield_type &) {}
176 void f2( coro::symmetric_coroutine< void >::yield_type &)
179 void f3( coro::symmetric_coroutine< X >::yield_type & yield)
180 { value2 = yield.get().i; }
182 void f4( coro::symmetric_coroutine< X& >::yield_type & yield)
188 void f5( coro::symmetric_coroutine< X* >::yield_type & yield)
191 void f6( coro::symmetric_coroutine< void >::yield_type & yield)
197 void f7( coro::symmetric_coroutine< int >::yield_type & yield)
199 value2 = yield.get();
201 value2 = yield.get();
204 template< typename E >
205 void f9( coro::symmetric_coroutine< void >::yield_type &, E const& e)
208 void f10( coro::symmetric_coroutine< int >::yield_type & yield,
209 coro::symmetric_coroutine< int >::call_type & other)
213 value2 = yield.get();
216 void f101( coro::symmetric_coroutine< int >::yield_type & yield)
217 { value2 = yield.get(); }
219 void f11( coro::symmetric_coroutine< void >::yield_type & yield,
220 coro::symmetric_coroutine< void >::call_type & other)
226 void f111( coro::symmetric_coroutine< void >::yield_type &)
229 void f12( coro::symmetric_coroutine< X& >::yield_type & yield,
230 coro::symmetric_coroutine< X& >::call_type & other)
232 yield( other, yield.get());
236 void f121( coro::symmetric_coroutine< X& >::yield_type & yield)
237 { p = & yield.get(); }
239 void f14( coro::symmetric_coroutine< int >::yield_type & yield,
240 coro::symmetric_coroutine< std::string >::call_type & other)
242 std::string str( boost::lexical_cast< std::string >( yield.get() ) );
244 value2 = yield.get();
247 void f141( coro::symmetric_coroutine< std::string >::yield_type & yield)
248 { value3 = yield.get(); }
250 void f15( coro::symmetric_coroutine< int >::yield_type & yield,
252 coro::symmetric_coroutine< int >::call_type & other)
255 value2 += x + offset;
258 value2 += x + offset;
262 void f151( coro::symmetric_coroutine< int >::yield_type & yield,
266 value2 += x + offset;
269 value2 += x + offset;
272 void f16( coro::symmetric_coroutine< int >::yield_type & yield)
276 value2 = yield.get();
284 coro::symmetric_coroutine< void >::call_type coro1;
285 coro::symmetric_coroutine< void >::call_type coro2( empty);
286 BOOST_CHECK( ! coro1);
288 coro1 = boost::move( coro2);
290 BOOST_CHECK( ! coro2);
296 BOOST_CHECK( cp.state);
297 BOOST_CHECK( ! value1);
298 coro::symmetric_coroutine< bool >::call_type coro( cp);
300 BOOST_CHECK( cp.state);
301 BOOST_CHECK( value1);
307 BOOST_CHECK( mv.state);
308 BOOST_CHECK( ! value1);
309 coro::symmetric_coroutine< int >::call_type coro( boost::move( mv) );
311 BOOST_CHECK( ! mv.state);
312 BOOST_CHECK( value1);
320 coro::symmetric_coroutine< void >::call_type coro( f2);
323 BOOST_CHECK( ! coro);
324 BOOST_CHECK_EQUAL( ( int)1, value2);
331 coro::symmetric_coroutine< int >::call_type coro3(
332 boost::bind( f151, _1, 3) );
334 coro::symmetric_coroutine< int >::call_type coro2(
335 boost::bind( f15, _1, 2, boost::ref( coro3) ) );
337 coro::symmetric_coroutine< int >::call_type coro1(
338 boost::bind( f15, _1, 1, boost::ref( coro2) ) );
341 BOOST_CHECK_EQUAL( ( int)0, value2);
346 BOOST_CHECK_EQUAL( ( int)9, value2);
348 BOOST_CHECK( ! coro3);
351 BOOST_CHECK_EQUAL( ( int)21, value2);
354 void test_pass_value()
359 BOOST_CHECK_EQUAL( ( int)7, x.i);
360 BOOST_CHECK_EQUAL( 0, value2);
361 coro::symmetric_coroutine< X >::call_type coro( f3);
364 BOOST_CHECK( ! coro);
365 BOOST_CHECK_EQUAL( ( int)7, x.i);
366 BOOST_CHECK_EQUAL( 7, value2);
369 void test_pass_reference()
374 coro::symmetric_coroutine< X& >::call_type coro( f4);
377 BOOST_CHECK( ! coro);
378 BOOST_CHECK( p == & x);
381 void test_pass_pointer()
386 coro::symmetric_coroutine< X* >::call_type coro( f5);
389 BOOST_CHECK( ! coro);
390 BOOST_CHECK( p == & x);
397 coro::symmetric_coroutine< void >::call_type coro( f6);
398 coro::symmetric_coroutine< void >::call_type coro_e( empty);
400 BOOST_CHECK( coro_e);
401 term_coro = & coro_e;
402 BOOST_CHECK_EQUAL( ( int) 0, value2);
405 BOOST_CHECK_EQUAL( ( int) 7, value2);
407 BOOST_CHECK_EQUAL( ( int) 0, value2);
410 void test_no_unwind()
414 coro::symmetric_coroutine< void >::call_type coro( f6,
416 coro::stack_allocator::traits_type::default_size(),
417 coro::no_stack_unwind) );
418 coro::symmetric_coroutine< void >::call_type coro_e( empty);
420 BOOST_CHECK( coro_e);
421 term_coro = & coro_e;
422 BOOST_CHECK_EQUAL( ( int) 0, value2);
425 BOOST_CHECK_EQUAL( ( int) 7, value2);
427 BOOST_CHECK_EQUAL( ( int) 7, value2);
430 void test_termination()
434 coro::symmetric_coroutine< int >::call_type coro( f7);
435 coro::symmetric_coroutine< void >::call_type coro_e( empty);
437 BOOST_CHECK( coro_e);
438 term_coro = & coro_e;
439 BOOST_CHECK_EQUAL( ( int) 0, value2);
442 BOOST_CHECK_EQUAL( ( int) 3, value2);
444 BOOST_CHECK( ! coro);
445 BOOST_CHECK_EQUAL( ( int) 7, value2);
448 void test_yield_to_void()
452 coro::symmetric_coroutine< void >::call_type coro_other( f111);
453 coro::symmetric_coroutine< void >::call_type coro( boost::bind( f11, _1, boost::ref( coro_other) ) );
454 BOOST_CHECK( coro_other);
456 BOOST_CHECK_EQUAL( ( int) 0, value2);
458 BOOST_CHECK( ! coro_other);
460 BOOST_CHECK_EQUAL( ( int) 3, value2);
462 BOOST_CHECK( ! coro_other);
463 BOOST_CHECK( ! coro);
464 BOOST_CHECK_EQUAL( ( int) 7, value2);
467 void test_yield_to_int()
471 coro::symmetric_coroutine< int >::call_type coro_other( f101);
472 coro::symmetric_coroutine< int >::call_type coro( boost::bind( f10, _1, boost::ref( coro_other) ) );
473 BOOST_CHECK( coro_other);
475 BOOST_CHECK_EQUAL( ( int) 0, value2);
477 BOOST_CHECK( ! coro_other);
479 BOOST_CHECK_EQUAL( ( int) 3, value2);
481 BOOST_CHECK( ! coro_other);
482 BOOST_CHECK( ! coro);
483 BOOST_CHECK_EQUAL( ( int) 7, value2);
486 void test_yield_to_ref()
490 coro::symmetric_coroutine< X& >::call_type coro_other( f121);
491 coro::symmetric_coroutine< X& >::call_type coro( boost::bind( f12, _1, boost::ref( coro_other) ) );
492 BOOST_CHECK( coro_other);
494 BOOST_CHECK( 0 == p);
497 BOOST_CHECK( ! coro_other);
499 BOOST_CHECK_EQUAL( p->i, x1.i);
500 BOOST_CHECK( p == & x1);
503 BOOST_CHECK( ! coro_other);
504 BOOST_CHECK( ! coro);
505 BOOST_CHECK_EQUAL( p->i, x2.i);
506 BOOST_CHECK( p == & x2);
509 void test_yield_to_different()
514 coro::symmetric_coroutine< std::string >::call_type coro_other( f141);
515 coro::symmetric_coroutine< int >::call_type coro( boost::bind( f14, _1, boost::ref( coro_other) ) );
516 BOOST_CHECK( coro_other);
518 BOOST_CHECK_EQUAL( ( int) 0, value2);
519 BOOST_CHECK( value3.empty() );
521 BOOST_CHECK( ! coro_other);
523 BOOST_CHECK_EQUAL( "3", value3);
525 BOOST_CHECK( ! coro_other);
526 BOOST_CHECK( ! coro);
527 BOOST_CHECK_EQUAL( ( int) 7, value2);
530 void test_move_coro()
534 coro::symmetric_coroutine< int >::call_type coro1( f16);
535 coro::symmetric_coroutine< int >::call_type coro2;
537 BOOST_CHECK( ! coro2);
540 BOOST_CHECK_EQUAL( ( int)1, value2);
542 coro2 = boost::move( coro1);
543 BOOST_CHECK( ! coro1);
547 BOOST_CHECK_EQUAL( ( int)2, value2);
549 coro1 = boost::move( coro2);
551 BOOST_CHECK( ! coro2);
554 BOOST_CHECK_EQUAL( ( int)3, value2);
556 coro2 = boost::move( coro1);
557 BOOST_CHECK( ! coro1);
561 BOOST_CHECK_EQUAL( ( int)4, value2);
568 coro_fn_void fn = trampoline< T, D >;
569 coro::symmetric_coroutine< void* >::call_type call( fn);
572 BOOST_CHECK( 0 != d);
573 d->call = boost::move( call);
575 BOOST_CHECK_EQUAL( ( int) 0, d->count);
577 BOOST_CHECK_EQUAL( ( int) 1, d->count);
579 BOOST_CHECK_EQUAL( ( int) 2, d->count);
582 boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
584 boost::unit_test::test_suite * test =
585 BOOST_TEST_SUITE("Boost.coroutine: symmetric coroutine test suite");
587 test->add( BOOST_TEST_CASE( & test_move) );
588 test->add( BOOST_TEST_CASE( & test_complete) );
589 test->add( BOOST_TEST_CASE( & test_yield) );
590 test->add( BOOST_TEST_CASE( & test_pass_value) );
591 test->add( BOOST_TEST_CASE( & test_pass_reference) );
592 test->add( BOOST_TEST_CASE( & test_pass_pointer) );
593 test->add( BOOST_TEST_CASE( & test_termination) );
594 test->add( BOOST_TEST_CASE( & test_unwind) );
595 test->add( BOOST_TEST_CASE( & test_no_unwind) );
596 test->add( BOOST_TEST_CASE( & test_yield_to_void) );
597 test->add( BOOST_TEST_CASE( & test_yield_to_int) );
598 test->add( BOOST_TEST_CASE( & test_yield_to_ref) );
599 test->add( BOOST_TEST_CASE( & test_yield_to_different) );
600 test->add( BOOST_TEST_CASE( & test_move_coro) );
601 test->add( BOOST_TEST_CASE( & test_vptr) );