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

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