Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / coroutine / test / test_asymmetric_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/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
28 namespace coro = boost::coroutines;
29
30 int value1 = 0;
31 std::string value2 = "";
32 bool value3 = false;
33 double value4 = .0;
34 int * value5 = 0;
35 int& value6 = value1;
36 int& value7 = value1;
37 int value8 = 0;
38 int value9 = 0;
39
40 struct X : private boost::noncopyable
41 {
42     X() { value1 = 7; }
43     ~X() { value1 = 0; }
44 };
45
46 class copyable
47 {
48 public:
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
63 class moveable
64 {
65 private:
66     BOOST_MOVABLE_BUT_NOT_COPYABLE( moveable)
67
68 public:
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( state, other.state); }
82
83     moveable & operator=( BOOST_RV_REF( moveable) other)
84     {
85         if ( this == & other) return * this;
86         moveable tmp( boost::move( other) );
87         std::swap( state, tmp.state);
88         return * this;
89     }
90
91     void operator()( coro::asymmetric_coroutine< int >::push_type &)
92     { value3 = state; }
93 };
94
95 struct my_exception {};
96
97 void f1( coro::asymmetric_coroutine< void >::push_type & c)
98 {
99     while ( c)
100         c();
101 }
102
103 void f2( coro::asymmetric_coroutine< void >::push_type &)
104 { ++value1; }
105
106 void f3( coro::asymmetric_coroutine< void >::push_type & c)
107 {
108     ++value1;
109     c();
110     ++value1;
111 }
112
113 void f4( coro::asymmetric_coroutine< int >::push_type & c)
114 {
115     c( 3);
116     c( 7);
117 }
118
119 void 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
127 void f6( coro::asymmetric_coroutine< int >::pull_type & c)
128 { value1 = c.get(); }
129
130 void f7( coro::asymmetric_coroutine< std::string >::pull_type & c)
131 { value2 = c.get(); }
132
133 void f8( coro::asymmetric_coroutine< boost::tuple< double, double > >::pull_type & c)
134 {
135     double x = 0, y = 0;
136     boost::tie( x, y) = c.get();
137     value4 = x + y;
138     c();
139     boost::tie( x, y) = c.get();
140     value4 = x + y;
141 }
142
143 void f9( coro::asymmetric_coroutine< int * >::pull_type & c)
144 { value5 = c.get(); }
145
146 void f91( coro::asymmetric_coroutine< int const* >::pull_type & c)
147 { value5 = const_cast< int * >( c.get() ); }
148
149 void f10( coro::asymmetric_coroutine< int & >::pull_type & c)
150 {
151     int const& i = c.get();
152     value5 = const_cast< int * >( & i);
153 }
154
155 void f101( coro::asymmetric_coroutine< int const& >::pull_type & c)
156 {
157     int const& i = c.get();
158     value5 = const_cast< int * >( & i);
159 }
160
161 void f11( coro::asymmetric_coroutine< boost::tuple< int, int > >::pull_type & c)
162 {
163     boost::tie( value8, value9) = c.get();
164 }
165
166 void f12( coro::asymmetric_coroutine< void >::pull_type & c)
167 {
168     X x_;
169     c();
170     c();
171 }
172
173 template< typename E >
174 void f14( coro::asymmetric_coroutine< void >::pull_type &, E const& e)
175 { throw e; }
176
177 void 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
186 void 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);
192         x = c().get();
193     }
194 }
195
196 void f19( coro::asymmetric_coroutine< int* >::push_type & c, std::vector< int * > & vec)
197 {
198     BOOST_FOREACH( int * ptr, vec)
199     { c( ptr); }
200 }
201
202 void f20( coro::asymmetric_coroutine< int >::push_type &)
203 {}
204
205 void f21( coro::asymmetric_coroutine< int >::pull_type & c)
206 {
207     while ( c)
208     {
209         value1 = c.get();
210         c();
211     }
212 }
213
214 void 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( 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( mv) );
244         BOOST_CHECK( ! mv.state);
245         BOOST_CHECK( value3);
246     }
247 }
248
249 void 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
258 void 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
270 void 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
284 void 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
298 void 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
309 void 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
320 void 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( 7.35, 3.14) );
327     BOOST_CHECK( coro);
328     BOOST_CHECK_EQUAL( ( double) 10.49, value4);
329
330     value4 = 0;
331     coro( boost::make_tuple( 1.15, 3.14) );
332     BOOST_CHECK( ! coro);
333     BOOST_CHECK_EQUAL( ( double) 4.29, value4);
334 }
335
336 void 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
348 void 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
360 void 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
372 void 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
384 void 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
401 void 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
417 void 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
437 void 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( f14< std::runtime_error >, _1, 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
458 void 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( 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( coro);
476         for (
477             coro::asymmetric_coroutine< int >::pull_type::iterator i = boost::begin( coro);
478             i != e; ++i)
479         { vec.push_back( * 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( & i1);
491         vec_in.push_back( & i2);
492         vec_in.push_back( & i3);
493         std::vector< int* > vec_out;
494         coro::asymmetric_coroutine< int* >::pull_type coro( boost::bind( f19, _1, boost::ref( vec_in) ) );
495         coro::asymmetric_coroutine< int* >::pull_type::iterator e = boost::end( coro);
496         for (
497             coro::asymmetric_coroutine< int* >::pull_type::iterator i = boost::begin( coro);
498             i != e; ++i)
499         {
500             int * p = * i;
501             vec_out.push_back( 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
510 void test_output_iterator()
511 {
512     int counter = 0;
513     std::vector< int > vec;
514     coro::asymmetric_coroutine< int >::push_type coro(
515         boost::bind( f17, _1, boost::ref( vec) ) );
516     coro::asymmetric_coroutine< int >::push_type::iterator e( boost::end( coro) );
517     for ( coro::asymmetric_coroutine< int >::push_type::iterator i( boost::begin( 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
529 void 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 }
545 void 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( 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( 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( coro1);
572     BOOST_CHECK( ! coro1);
573     BOOST_CHECK( coro2);
574
575     coro2( 4);
576     BOOST_CHECK_EQUAL( ( int)4, value1);
577 }
578
579 void foo( coro::asymmetric_coroutine< int >::push_type & yield)
580 {
581     yield( 1);
582 }
583
584 coro::asymmetric_coroutine< int >::pull_type make_range()
585 {
586     return coro::asymmetric_coroutine< int >::pull_type( foo);
587 }
588
589 template< typename Range >
590 void const_func( Range const& r)
591 {
592     begin( r);
593 }
594
595 void test_range()
596 {
597     const_func( make_range() );    
598 }
599
600 boost::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 }