Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / coroutine / test / test_symmetric_coroutine.cpp
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
29 namespace coro = boost::coroutines;
30
31 bool value1 = false;
32 int value2 = 0;
33 std::string value3;
34
35 typedef void( * coro_fn_void)(coro::symmetric_coroutine< void* >::yield_type &);
36
37 coro::symmetric_coroutine< void >::call_type * term_coro = 0;
38
39 struct X
40 {
41     int i;
42
43     X() :
44         i( 0)
45     {}
46
47     X( int i_) :
48         i( i_)
49     {}
50 };
51
52 X * p = 0;
53
54 struct Y
55 {
56     Y() 
57     { value2 = 7; }
58
59     ~Y() 
60     { value2 = 0; }
61 };
62    
63 template< typename X, typename I >
64 void 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
74 struct B
75 {
76     virtual ~B() {}
77
78     virtual void foo() = 0;
79 };
80
81 class D : public B
82 {
83 public:
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
113 struct T
114 {
115     D   *   d;
116
117     T() :
118         d( 0)
119     {}
120 };
121
122 class copyable
123 {
124 public:
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
142 class moveable
143 {
144 private:
145     BOOST_MOVABLE_BUT_NOT_COPYABLE( moveable)
146
147 public:
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( state, other.state); }
161
162     moveable & operator=( BOOST_RV_REF( moveable) other)
163     {
164         if ( this == & other) return * this;
165         moveable tmp( boost::move( other) );
166         std::swap( state, tmp.state);
167         return * this;
168     }
169
170     void operator()( coro::symmetric_coroutine< int >::yield_type &)
171     { value1 = state; }
172 };
173
174 void empty( coro::symmetric_coroutine< void >::yield_type &) {}
175
176 void f2( coro::symmetric_coroutine< void >::yield_type &)
177 { ++value2; }
178
179 void f3( coro::symmetric_coroutine< X >::yield_type & yield)
180 { value2 = yield.get().i; }
181
182 void f4( coro::symmetric_coroutine< X& >::yield_type & yield)
183 {
184     X & x = yield.get();
185     p = & x;
186 }
187
188 void f5( coro::symmetric_coroutine< X* >::yield_type & yield)
189 { p = yield.get(); }
190
191 void f6( coro::symmetric_coroutine< void >::yield_type & yield)
192 {
193     Y y;
194     yield( *term_coro);
195 }
196
197 void f7( coro::symmetric_coroutine< int >::yield_type & yield)
198 {
199     value2 = yield.get();
200     yield( *term_coro);
201     value2 = yield.get();
202 }
203
204 template< typename E >
205 void f9( coro::symmetric_coroutine< void >::yield_type &, E const& e)
206 { throw e; }
207
208 void 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
216 void f101( coro::symmetric_coroutine< int >::yield_type & yield)
217 { value2 = yield.get(); }
218
219 void 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
226 void f111( coro::symmetric_coroutine< void >::yield_type &)
227 { value2 = 3; }
228
229 void 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
236 void f121( coro::symmetric_coroutine< X& >::yield_type & yield)
237 { p = & yield.get(); }
238
239 void 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 >( yield.get() ) );
243     yield( other, str);
244     value2 = yield.get();
245 }
246
247 void f141( coro::symmetric_coroutine< std::string >::yield_type & yield)
248 { value3 = yield.get(); }
249
250 void 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
262 void 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
272 void f16( coro::symmetric_coroutine< int >::yield_type & yield)
273 {
274     while ( yield)
275     {
276         value2 = yield.get();
277         yield();
278     }
279 }
280
281 void 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( 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( mv) );
310         coro( 7);
311         BOOST_CHECK( ! mv.state);
312         BOOST_CHECK( value1);
313     }
314 }
315
316 void 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
327 void test_yield()
328 {
329     value2 = 0;
330
331     coro::symmetric_coroutine< int >::call_type coro3(
332         boost::bind( f151, _1, 3) );
333     BOOST_CHECK( coro3);
334     coro::symmetric_coroutine< int >::call_type coro2(
335         boost::bind( f15, _1, 2, boost::ref( coro3) ) );
336     BOOST_CHECK( coro2);
337     coro::symmetric_coroutine< int >::call_type coro1(
338         boost::bind( f15, _1, 1, boost::ref( 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
354 void 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
369 void 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
381 void 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
393 void 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
410 void 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
430 void 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
448 void 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( f11, _1, boost::ref( 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
467 void 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( f10, _1, boost::ref( 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
486 void 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( f12, _1, boost::ref( 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
509 void 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( f14, _1, boost::ref( 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
530 void 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( 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( 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( coro1);
557     BOOST_CHECK( ! coro1);
558     BOOST_CHECK( coro2);
559
560     coro2( 4);
561     BOOST_CHECK_EQUAL( ( int)4, value2);
562 }
563
564 void 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( 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
582 boost::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 }