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

source code of boost/libs/coroutine/test/test_asymmetric_coroutine.cpp