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