Imported Upstream version 1.64.0
[platform/upstream/boost.git] / libs / context / test / test_callcc.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 <stdio.h>
8 #include <stdlib.h>
9
10 #include <cmath>
11 #include <cstdint>
12 #include <cstdio>
13 #include <iostream>
14 #include <memory>
15 #include <sstream>
16 #include <stdexcept>
17 #include <string>
18 #include <thread>
19 #include <utility>
20 #include <vector>
21
22 #include <boost/array.hpp>
23 #include <boost/assert.hpp>
24 #include <boost/lexical_cast.hpp>
25 #include <boost/test/unit_test.hpp>
26 #include <boost/utility.hpp>
27 #include <boost/variant.hpp>
28
29 #include <boost/context/continuation.hpp>
30 #include <boost/context/detail/config.hpp>
31
32 #ifdef BOOST_WINDOWS
33 #include <windows.h>
34 #endif
35
36 #if defined(BOOST_MSVC)
37 # pragma warning(push)
38 # pragma warning(disable: 4723)
39 #endif
40
41 typedef boost::variant<int,std::string> variant_t;
42
43 namespace ctx = boost::context;
44
45 int value1 = 0;
46 std::string value2;
47 double value3 = 0.;
48
49 struct X {
50     ctx::continuation foo( ctx::continuation && c) {
51         value1 = c.get_data< int >();
52         return std::move( c);
53     }
54 };
55
56 struct Y {
57     Y() {
58         value1 = 3;
59     }
60
61     Y( Y const&) = delete;
62     Y & operator=( Y const&) = delete;
63
64     ~Y() {
65         value1 = 7;
66     }
67 };
68
69 class moveable {
70 public:
71     bool    state;
72     int     value;
73
74     moveable() :
75         state( false),
76         value( -1) {
77     }
78
79     moveable( int v) :
80         state( true),
81         value( v) {
82     }
83
84     moveable( moveable && other) :
85         state( other.state),
86         value( other.value) {
87         other.state = false;
88         other.value = -1;
89     }
90
91     moveable & operator=( moveable && other) {
92         if ( this == & other) return * this;
93         state = other.state;
94         value = other.value;
95         other.state = false;
96         other.value = -1;
97         return * this;
98     }
99
100     moveable( moveable const& other) = delete;
101     moveable & operator=( moveable const& other) = delete;
102
103     void operator()() {
104         value1 = value;
105     }
106 };
107
108 struct my_exception : public std::runtime_error {
109     ctx::continuation   c;
110     my_exception( ctx::continuation && c_, char const* what) :
111         std::runtime_error( what),
112         c{ std::move( c_) } {
113     }
114 };
115
116 #ifdef BOOST_MSVC
117 // Optimizations can remove the integer-divide-by-zero here.
118 #pragma optimize("", off)
119 void seh( bool & catched) {
120     __try {
121         int i = 1;
122         i /= 0;
123     } __except( EXCEPTION_EXECUTE_HANDLER) {
124         catched = true;
125     }
126 }
127 #pragma optimize("", on)
128 #endif
129
130 ctx::continuation fn1( ctx::continuation && c) {
131     value1 = c.get_data< int >();
132     return std::move( c);
133 }
134
135 ctx::continuation fn2( ctx::continuation && c) {
136     try {
137         throw std::runtime_error( c.get_data< const char * >() );
138     } catch ( std::runtime_error const& e) {
139         value2 = e.what();
140     }
141     return std::move( c);
142 }
143
144 ctx::continuation fn3( ctx::continuation && c) {
145     double d = c.get_data< double >();
146     d += 3.45;
147     value3 = d;
148     return std::move( c);
149 }
150
151 ctx::continuation fn5( ctx::continuation && c) {
152     value1 = 3;
153     return std::move( c);
154 }
155
156 ctx::continuation fn4( ctx::continuation && c) {
157     ctx::continuation c1 = ctx::callcc( fn5);
158     value3 = 3.14;
159     return std::move( c);
160 }
161
162 ctx::continuation fn6( ctx::continuation && c) {
163     try {
164         value1 = 3;
165         c = c.resume();
166         value1 = 7;
167         c = c.resume();
168     } catch ( my_exception & e) {
169         value2 = e.what();
170     }
171     return std::move( c);
172 }
173
174 ctx::continuation fn7( ctx::continuation && c) {
175     Y y;
176     return c.resume();
177 }
178
179 ctx::continuation fn8( ctx::continuation && c) {
180     value1 = c.get_data< int >();
181     return std::move( c);
182 }
183
184 ctx::continuation fn9( ctx::continuation && c) {
185     value1 = c.get_data< int >();
186     c = c.resume( value1);
187     value1 = c.get_data< int >();
188     return std::move( c);
189 }
190
191 ctx::continuation fn10( ctx::continuation && c) {
192     int & i = c.get_data< int & >();
193     return c.resume( std::ref( i) );
194 }
195
196 ctx::continuation fn11( ctx::continuation && c) {
197     moveable m = c.get_data< moveable >();
198     c = c.resume( std::move( m) );
199     m = c.get_data< moveable >();
200     return c.resume( std::move( m) );
201 }
202
203 ctx::continuation fn12( ctx::continuation && c) {
204     int i; std::string str;
205     std::tie( i, str) = c.get_data< int, std::string >();
206     return c.resume( i, str);
207 }
208
209 ctx::continuation fn13( ctx::continuation && c) {
210     int i; moveable m;
211     std::tie( i, m) = c.get_data< int, moveable >();
212     return c.resume( i, std::move( m) );
213 }
214
215 ctx::continuation fn14( ctx::continuation && c) {
216     variant_t data = c.get_data< variant_t >();
217     int i = boost::get< int >( data);
218     data = boost::lexical_cast< std::string >( i);
219     return c.resume( data);
220 }
221
222 ctx::continuation fn15( ctx::continuation && c) {
223     Y * py = c.get_data< Y * >();
224     return c.resume( py);
225 }
226
227 ctx::continuation fn16( ctx::continuation && c) {
228     int i = c.get_data< int >();
229     value1 = i;
230     c = c.resume( i);
231     value1 = c.get_data< int >();
232     return std::move( c);
233 }
234
235 ctx::continuation fn17( ctx::continuation && c) {
236     int i; int j;
237     std::tie( i, j) = c.get_data< int, int >();
238     for (;;) {
239         c = c.resume( i, j);
240         std::tie( i, j) = c.get_data< int, int >();
241     }
242     return std::move( c);
243 }
244
245 void test_move() {
246     value1 = 0;
247     ctx::continuation c;
248     BOOST_CHECK( ! c );
249     ctx::continuation c1 = ctx::callcc( fn9, 1);
250     ctx::continuation c2 = ctx::callcc( fn9, 3);
251     BOOST_CHECK( c1 );
252     BOOST_CHECK( c2 );
253     c1 = std::move( c2);
254     BOOST_CHECK( c1 );
255     BOOST_CHECK( ! c2 );
256     BOOST_CHECK_EQUAL( 3, value1);
257     c1.resume( 0);
258     BOOST_CHECK_EQUAL( 0, value1);
259     BOOST_CHECK( ! c1 );
260     BOOST_CHECK( ! c2 );
261 }
262
263 void test_bind() {
264     value1 = 0;
265     X x;
266     ctx::continuation c = ctx::callcc( std::bind( & X::foo, x, std::placeholders::_1), 7);
267     BOOST_CHECK_EQUAL( 7, value1);
268 }
269
270 void test_exception() {
271     {
272         const char * what = "hello world";
273         ctx::continuation c = ctx::callcc( fn2, what);
274         BOOST_CHECK_EQUAL( std::string( what), value2);
275         BOOST_CHECK( ! c );
276     }
277 #ifdef BOOST_MSVC
278     {
279         bool catched = false;
280         std::thread([&catched](){
281                 ctx::continuation c = ctx::callcc([&catched](ctx::continuation && c){
282                             c = c.resume();
283                             seh( catched);
284                             return std::move( c);
285                         });
286             BOOST_CHECK( c );
287             c.resume();
288         }).join();
289         BOOST_CHECK( catched);
290     }
291 #endif
292 }
293
294 void test_fp() {
295     double d = 7.13;
296     ctx::continuation c = ctx::callcc( fn3, d);
297     BOOST_CHECK_EQUAL( 10.58, value3);
298     BOOST_CHECK( ! c );
299 }
300
301 void test_stacked() {
302     value1 = 0;
303     value3 = 0.;
304     ctx::continuation c = ctx::callcc( fn4);
305     BOOST_CHECK_EQUAL( 3, value1);
306     BOOST_CHECK_EQUAL( 3.14, value3);
307     BOOST_CHECK( ! c );
308 }
309
310 void test_prealloc() {
311     value1 = 0;
312     ctx::default_stack alloc;
313     ctx::stack_context sctx( alloc.allocate() );
314     void * sp = static_cast< char * >( sctx.sp) - 10;
315     std::size_t size = sctx.size - 10;
316     ctx::continuation c = ctx::callcc( std::allocator_arg, ctx::preallocated( sp, size, sctx), alloc, fn1, 7);
317     BOOST_CHECK_EQUAL( 7, value1);
318     BOOST_CHECK( ! c );
319 }
320
321 void test_ontop() {
322     {
323         int i = 3, j = 0;
324         ctx::continuation c = ctx::callcc([](ctx::continuation && c) {
325                     int x = c.get_data< int >();
326                     for (;;) {
327                         c = c.resume( x*10);
328                         if ( c.data_available() ) {
329                             x = c.get_data< int >();
330                         }
331                     }
332                     return std::move( c);
333                 }, i);
334         c = c.resume_with(
335                [](ctx::continuation && c){
336                    int x = c.get_data< int >();
337                    return x-10;
338                },
339                i);
340         if ( c.data_available() ) {
341             j = c.get_data< int >();
342         }
343         BOOST_CHECK( c );
344         BOOST_CHECK_EQUAL( j, -70);
345     }
346     {
347         int i = 3, j = 1;
348         ctx::continuation c;
349         c = ctx::callcc( fn17, i, j);
350         c = c.resume_with(
351                [](ctx::continuation && c){
352                    int x, y;
353                    std::tie( x, y) = c.get_data< int, int >();
354                    return std::make_tuple( x - y, x + y);
355                },
356                i, j);
357         std::tie( i, j) = c.get_data< int, int >();
358         BOOST_CHECK_EQUAL( i, 2);
359         BOOST_CHECK_EQUAL( j, 4);
360     }
361     {
362         moveable m1( 7), m2, dummy;
363         ctx::continuation c =  ctx::callcc( fn11, std::move( dummy) );
364         BOOST_CHECK( 7 == m1.value);
365         BOOST_CHECK( m1.state);
366         BOOST_CHECK( -1 == m2.value);
367         BOOST_CHECK( ! m2.state);
368         c = c.resume_with(
369                [](ctx::continuation && c){
370                    moveable m = c.get_data< moveable >();
371                    BOOST_CHECK( m.state);
372                    BOOST_CHECK( 7 == m.value);
373                    return  m;
374                },
375                std::move( m1) );
376         m2 = c.get_data< moveable >();
377         BOOST_CHECK( ! m1.state);
378         BOOST_CHECK( -1 == m1.value);
379         BOOST_CHECK( m2.state);
380         BOOST_CHECK( 7 == m2.value);
381     }
382 }
383
384 void test_ontop_exception() {
385     {
386         value1 = 0;
387         value2 = "";
388         ctx::continuation c = ctx::callcc([](ctx::continuation && c){
389                 for (;;) {
390                     value1 = 3;
391                     try {
392                         c = c.resume();
393                     } catch ( my_exception & ex) {
394                         value2 = ex.what();
395                         return std::move( ex.c); 
396                     }
397                 }
398                 return std::move( c);
399         });
400         c = c.resume();
401         BOOST_CHECK_EQUAL( 3, value1);
402         const char * what = "hello world";
403         c.resume_with(
404            [what](ctx::continuation && c){
405                throw my_exception( std::move( c), what);
406            });
407         BOOST_CHECK_EQUAL( 3, value1);
408         BOOST_CHECK_EQUAL( std::string( what), value2);
409     }
410     {
411         value2 = "";
412         int i = 3, j = 1;
413         ctx::continuation c = ctx::callcc([]( ctx::continuation && c) {
414                 int x; int y;
415                 std::tie( x, y) = c.get_data< int, int >();
416                 for (;;) {
417                     try {
418                         c = c.resume( x+y,x-y);
419                         std::tie( x, y) = c.get_data< int, int >();
420                     } catch ( my_exception & ex) {
421                         value2 = ex.what();
422                         return std::move( ex.c); 
423                     }
424                 }
425                 return std::move( c);
426             },
427             i, j);
428         BOOST_CHECK( c );
429         std::tie( i, j) = c.get_data< int, int >();
430         BOOST_CHECK_EQUAL( i, 4);
431         BOOST_CHECK_EQUAL( j, 2);
432         char const * what = "hello world";
433         c = c.resume_with(
434                [](ctx::continuation && c) {
435                    char const * what = c.get_data< char const * >();
436                    throw my_exception( std::move( c), what);
437                    return what;
438                },
439                what);
440         BOOST_CHECK( ! c );
441         BOOST_CHECK_EQUAL( i, 4);
442         BOOST_CHECK_EQUAL( j, 2);
443         BOOST_CHECK_EQUAL( std::string( what), value2);
444     }
445 }
446
447 void test_termination() {
448     {
449         value1 = 0;
450         ctx::continuation c = ctx::callcc( fn7);
451         BOOST_CHECK_EQUAL( 3, value1);
452     }
453     BOOST_CHECK_EQUAL( 7, value1);
454     {
455         value1 = 0;
456         BOOST_CHECK_EQUAL( 0, value1);
457         ctx::continuation c = ctx::callcc( fn5);
458         BOOST_CHECK_EQUAL( 3, value1);
459         BOOST_CHECK( ! c );
460     }
461     {
462         value1 = 0;
463         BOOST_CHECK_EQUAL( 0, value1);
464         int i = 3;
465         ctx::continuation c;
466         BOOST_CHECK( ! c );
467         c = ctx::callcc( fn9, i);
468         BOOST_CHECK( c );
469         i = c.get_data< int >();
470         BOOST_CHECK_EQUAL( i, value1);
471         BOOST_CHECK( c );
472         i = 7;
473         c = c.resume( i);
474         BOOST_CHECK( ! c );
475         BOOST_CHECK_EQUAL( i, value1);
476     }
477 }
478
479 void test_one_arg() {
480     {
481         value1 = 0;
482         ctx::continuation c;
483         c = ctx::callcc( fn8, 7);
484         BOOST_CHECK_EQUAL( 7, value1);
485     }
486     {
487         int i = 3, j = 0;
488         ctx::continuation c;
489         c = ctx::callcc( fn9, i);
490         j = c.get_data< int >();
491         BOOST_CHECK_EQUAL( i, j);
492     }
493     {
494         int i_ = 3;
495         int & i = i_;
496         BOOST_CHECK_EQUAL( i, i_);
497         ctx::continuation c = ctx::callcc( fn10, std::ref( i) );
498         BOOST_CHECK( c.data_available() );
499         int & j = c.get_data< int & >();
500         BOOST_CHECK_EQUAL( i, i_);
501         BOOST_CHECK_EQUAL( j, i_);
502         BOOST_CHECK( & i == & j);
503     }
504     {
505         Y y;
506         Y * py = nullptr;
507         ctx::continuation c;
508         c = ctx::callcc( fn15, & y);
509         py = c.get_data< Y * >();
510         BOOST_CHECK( py == & y);
511     }
512     {
513         moveable m1( 7), m2;
514         BOOST_CHECK( 7 == m1.value);
515         BOOST_CHECK( m1.state);
516         BOOST_CHECK( -1 == m2.value);
517         BOOST_CHECK( ! m2.state);
518         ctx::continuation c;
519         c = ctx::callcc( fn11, std::move( m1) );
520         m2 = c.get_data< moveable >();
521         BOOST_CHECK( -1 == m1.value);
522         BOOST_CHECK( ! m1.state);
523         BOOST_CHECK( 7 == m2.value);
524         BOOST_CHECK( m2.state);
525     }
526 }
527
528 void test_two_args() {
529     {
530         int i1 = 3, i2 = 0;
531         std::string str1("abc"), str2;
532         ctx::continuation c = ctx::callcc( fn12, i1, str1);
533         std::tie( i2, str2) = c.get_data< int, std::string >();
534         BOOST_CHECK_EQUAL( i1, i2);
535         BOOST_CHECK_EQUAL( str1, str2);
536     }
537     {
538         int i1 = 3, i2 = 0;
539         moveable m1( 7), m2;
540         BOOST_CHECK( 7 == m1.value);
541         BOOST_CHECK( m1.state);
542         BOOST_CHECK( -1 == m2.value);
543         BOOST_CHECK( ! m2.state);
544         ctx::continuation c;
545         c = ctx::callcc( fn13, i1, std::move( m1) );
546         std::tie( i2, m2) = c.get_data< int, moveable >();
547         BOOST_CHECK_EQUAL( i1, i2);
548         BOOST_CHECK( -1 == m1.value);
549         BOOST_CHECK( ! m1.state);
550         BOOST_CHECK( 7 == m2.value);
551         BOOST_CHECK( m2.state);
552     }
553 }
554
555 void test_variant() {
556     {
557         int i = 7;
558         variant_t data1 = i, data2;
559         ctx::continuation c;
560         c = ctx::callcc( fn14, data1);
561         data2 = c.get_data< variant_t >();
562         std::string str = boost::get< std::string >( data2);
563         BOOST_CHECK_EQUAL( std::string("7"), str);
564     }
565 }
566
567 void test_sscanf() {
568     ctx::continuation c = ctx::callcc(
569                 []( ctx::continuation && c) {
570                         {
571                                 double n1 = 0;
572                                 double n2 = 0;
573                                 sscanf("3.14 7.13", "%lf %lf", & n1, & n2);
574                                 BOOST_CHECK( n1 == 3.14);
575                                 BOOST_CHECK( n2 == 7.13);
576                         }
577                         {
578                                 int n1=0;
579                                 int n2=0;
580                                 sscanf("1 23", "%d %d", & n1, & n2);
581                                 BOOST_CHECK( n1 == 1);
582                                 BOOST_CHECK( n2 == 23);
583                         }
584                         {
585                                 int n1=0;
586                                 int n2=0;
587                                 sscanf("1 jjj 23", "%d %*[j] %d", & n1, & n2);
588                                 BOOST_CHECK( n1 == 1);
589                                 BOOST_CHECK( n2 == 23);
590                         }
591                         return std::move( c);
592         });
593 }
594
595 void test_snprintf() {
596     ctx::continuation c = ctx::callcc(
597                 []( ctx::continuation && c) {
598             {
599                 const char *fmt = "sqrt(2) = %f";
600                 char buf[15];
601                 snprintf( buf, sizeof( buf), fmt, std::sqrt( 2) );
602                 BOOST_CHECK( 0 < sizeof( buf) );
603                 BOOST_ASSERT( std::string("sqrt(2) = 1.41") == std::string( buf) );
604             }
605             {
606                 std::uint64_t n = 0xbcdef1234567890;
607                 const char *fmt = "0x%016llX";
608                 char buf[100];
609                 snprintf( buf, sizeof( buf), fmt, n);
610                 BOOST_ASSERT( std::string("0x0BCDEF1234567890") == std::string( buf) );
611             }
612                         return std::move( c);
613         });
614 }
615
616 #ifdef BOOST_WINDOWS
617 void test_bug12215() {
618         ctx::continuation c = ctx::callcc(
619             [](ctx::continuation && c) {
620                 char buffer[MAX_PATH];
621                 GetModuleFileName( nullptr, buffer, MAX_PATH);
622                 return std::move( c);
623             });
624 }
625 #endif
626
627 boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
628 {
629     boost::unit_test::test_suite * test =
630         BOOST_TEST_SUITE("Boost.Context: callcc test suite");
631
632     test->add( BOOST_TEST_CASE( & test_move) );
633     test->add( BOOST_TEST_CASE( & test_bind) );
634     test->add( BOOST_TEST_CASE( & test_exception) );
635     test->add( BOOST_TEST_CASE( & test_fp) );
636     test->add( BOOST_TEST_CASE( & test_stacked) );
637     test->add( BOOST_TEST_CASE( & test_stacked) );
638     test->add( BOOST_TEST_CASE( & test_prealloc) );
639     test->add( BOOST_TEST_CASE( & test_ontop) );
640     test->add( BOOST_TEST_CASE( & test_ontop_exception) );
641     test->add( BOOST_TEST_CASE( & test_termination) );
642     test->add( BOOST_TEST_CASE( & test_one_arg) );
643     test->add( BOOST_TEST_CASE( & test_two_args) );
644     test->add( BOOST_TEST_CASE( & test_variant) );
645     test->add( BOOST_TEST_CASE( & test_sscanf) );
646     test->add( BOOST_TEST_CASE( & test_snprintf) );
647 #ifdef BOOST_WINDOWS
648     test->add( BOOST_TEST_CASE( & test_bug12215) );
649 #endif
650
651     return test;
652 }
653
654 #if defined(BOOST_MSVC)
655 # pragma warning(pop)
656 #endif