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)
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>
29 #include <boost/context/continuation.hpp>
30 #include <boost/context/detail/config.hpp>
36 #if defined(BOOST_MSVC)
37 # pragma warning(push)
38 # pragma warning(disable: 4723)
41 typedef boost::variant<int,std::string> variant_t;
43 namespace ctx = boost::context;
50 ctx::continuation foo( ctx::continuation && c) {
51 value1 = c.get_data< int >();
61 Y( Y const&) = delete;
62 Y & operator=( Y const&) = delete;
84 moveable( moveable && other) :
91 moveable & operator=( moveable && other) {
92 if ( this == & other) return * this;
100 moveable( moveable const& other) = delete;
101 moveable & operator=( moveable const& other) = delete;
108 struct my_exception : public std::runtime_error {
110 my_exception( ctx::continuation && c_, char const* what) :
111 std::runtime_error( what),
112 c{ std::move( c_) } {
117 // Optimizations can remove the integer-divide-by-zero here.
118 #pragma optimize("", off)
119 void seh( bool & catched) {
123 } __except( EXCEPTION_EXECUTE_HANDLER) {
127 #pragma optimize("", on)
130 ctx::continuation fn1( ctx::continuation && c) {
131 value1 = c.get_data< int >();
132 return std::move( c);
135 ctx::continuation fn2( ctx::continuation && c) {
137 throw std::runtime_error( c.get_data< const char * >() );
138 } catch ( std::runtime_error const& e) {
141 return std::move( c);
144 ctx::continuation fn3( ctx::continuation && c) {
145 double d = c.get_data< double >();
148 return std::move( c);
151 ctx::continuation fn5( ctx::continuation && c) {
153 return std::move( c);
156 ctx::continuation fn4( ctx::continuation && c) {
157 ctx::continuation c1 = ctx::callcc( fn5);
159 return std::move( c);
162 ctx::continuation fn6( ctx::continuation && c) {
168 } catch ( my_exception & e) {
171 return std::move( c);
174 ctx::continuation fn7( ctx::continuation && c) {
179 ctx::continuation fn8( ctx::continuation && c) {
180 value1 = c.get_data< int >();
181 return std::move( c);
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);
191 ctx::continuation fn10( ctx::continuation && c) {
192 int & i = c.get_data< int & >();
193 return c.resume( std::ref( i) );
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) );
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);
209 ctx::continuation fn13( ctx::continuation && c) {
211 std::tie( i, m) = c.get_data< int, moveable >();
212 return c.resume( i, std::move( m) );
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);
222 ctx::continuation fn15( ctx::continuation && c) {
223 Y * py = c.get_data< Y * >();
224 return c.resume( py);
227 ctx::continuation fn16( ctx::continuation && c) {
228 int i = c.get_data< int >();
231 value1 = c.get_data< int >();
232 return std::move( c);
235 ctx::continuation fn17( ctx::continuation && c) {
237 std::tie( i, j) = c.get_data< int, int >();
240 std::tie( i, j) = c.get_data< int, int >();
242 return std::move( c);
249 ctx::continuation c1 = ctx::callcc( fn9, 1);
250 ctx::continuation c2 = ctx::callcc( fn9, 3);
256 BOOST_CHECK_EQUAL( 3, value1);
258 BOOST_CHECK_EQUAL( 0, value1);
266 ctx::continuation c = ctx::callcc( std::bind( & X::foo, x, std::placeholders::_1), 7);
267 BOOST_CHECK_EQUAL( 7, value1);
270 void test_exception() {
272 const char * what = "hello world";
273 ctx::continuation c = ctx::callcc( fn2, what);
274 BOOST_CHECK_EQUAL( std::string( what), value2);
279 bool catched = false;
280 std::thread([&catched](){
281 ctx::continuation c = ctx::callcc([&catched](ctx::continuation && c){
284 return std::move( c);
289 BOOST_CHECK( catched);
296 ctx::continuation c = ctx::callcc( fn3, d);
297 BOOST_CHECK_EQUAL( 10.58, value3);
301 void test_stacked() {
304 ctx::continuation c = ctx::callcc( fn4);
305 BOOST_CHECK_EQUAL( 3, value1);
306 BOOST_CHECK_EQUAL( 3.14, value3);
310 void test_prealloc() {
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);
324 ctx::continuation c = ctx::callcc([](ctx::continuation && c) {
325 int x = c.get_data< int >();
328 if ( c.data_available() ) {
329 x = c.get_data< int >();
332 return std::move( c);
335 [](ctx::continuation && c){
336 int x = c.get_data< int >();
340 if ( c.data_available() ) {
341 j = c.get_data< int >();
344 BOOST_CHECK_EQUAL( j, -70);
349 c = ctx::callcc( fn17, i, j);
351 [](ctx::continuation && c){
353 std::tie( x, y) = c.get_data< int, int >();
354 return std::make_tuple( x - y, x + y);
357 std::tie( i, j) = c.get_data< int, int >();
358 BOOST_CHECK_EQUAL( i, 2);
359 BOOST_CHECK_EQUAL( j, 4);
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);
369 [](ctx::continuation && c){
370 moveable m = c.get_data< moveable >();
371 BOOST_CHECK( m.state);
372 BOOST_CHECK( 7 == m.value);
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);
384 void test_ontop_exception() {
388 ctx::continuation c = ctx::callcc([](ctx::continuation && c){
393 } catch ( my_exception & ex) {
395 return std::move( ex.c);
398 return std::move( c);
401 BOOST_CHECK_EQUAL( 3, value1);
402 const char * what = "hello world";
404 [what](ctx::continuation && c){
405 throw my_exception( std::move( c), what);
407 BOOST_CHECK_EQUAL( 3, value1);
408 BOOST_CHECK_EQUAL( std::string( what), value2);
413 ctx::continuation c = ctx::callcc([]( ctx::continuation && c) {
415 std::tie( x, y) = c.get_data< int, int >();
418 c = c.resume( x+y,x-y);
419 std::tie( x, y) = c.get_data< int, int >();
420 } catch ( my_exception & ex) {
422 return std::move( ex.c);
425 return std::move( 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";
434 [](ctx::continuation && c) {
435 char const * what = c.get_data< char const * >();
436 throw my_exception( std::move( c), what);
441 BOOST_CHECK_EQUAL( i, 4);
442 BOOST_CHECK_EQUAL( j, 2);
443 BOOST_CHECK_EQUAL( std::string( what), value2);
447 void test_termination() {
450 ctx::continuation c = ctx::callcc( fn7);
451 BOOST_CHECK_EQUAL( 3, value1);
453 BOOST_CHECK_EQUAL( 7, value1);
456 BOOST_CHECK_EQUAL( 0, value1);
457 ctx::continuation c = ctx::callcc( fn5);
458 BOOST_CHECK_EQUAL( 3, value1);
463 BOOST_CHECK_EQUAL( 0, value1);
467 c = ctx::callcc( fn9, i);
469 i = c.get_data< int >();
470 BOOST_CHECK_EQUAL( i, value1);
475 BOOST_CHECK_EQUAL( i, value1);
479 void test_one_arg() {
483 c = ctx::callcc( fn8, 7);
484 BOOST_CHECK_EQUAL( 7, value1);
489 c = ctx::callcc( fn9, i);
490 j = c.get_data< int >();
491 BOOST_CHECK_EQUAL( i, j);
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);
508 c = ctx::callcc( fn15, & y);
509 py = c.get_data< Y * >();
510 BOOST_CHECK( py == & y);
514 BOOST_CHECK( 7 == m1.value);
515 BOOST_CHECK( m1.state);
516 BOOST_CHECK( -1 == m2.value);
517 BOOST_CHECK( ! m2.state);
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);
528 void test_two_args() {
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);
540 BOOST_CHECK( 7 == m1.value);
541 BOOST_CHECK( m1.state);
542 BOOST_CHECK( -1 == m2.value);
543 BOOST_CHECK( ! m2.state);
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);
555 void test_variant() {
558 variant_t data1 = i, data2;
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);
568 ctx::continuation c = ctx::callcc(
569 []( ctx::continuation && c) {
573 sscanf("3.14 7.13", "%lf %lf", & n1, & n2);
574 BOOST_CHECK( n1 == 3.14);
575 BOOST_CHECK( n2 == 7.13);
580 sscanf("1 23", "%d %d", & n1, & n2);
581 BOOST_CHECK( n1 == 1);
582 BOOST_CHECK( n2 == 23);
587 sscanf("1 jjj 23", "%d %*[j] %d", & n1, & n2);
588 BOOST_CHECK( n1 == 1);
589 BOOST_CHECK( n2 == 23);
591 return std::move( c);
595 void test_snprintf() {
596 ctx::continuation c = ctx::callcc(
597 []( ctx::continuation && c) {
599 const char *fmt = "sqrt(2) = %f";
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) );
606 std::uint64_t n = 0xbcdef1234567890;
607 const char *fmt = "0x%016llX";
609 snprintf( buf, sizeof( buf), fmt, n);
610 BOOST_ASSERT( std::string("0x0BCDEF1234567890") == std::string( buf) );
612 return std::move( c);
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);
627 boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
629 boost::unit_test::test_suite * test =
630 BOOST_TEST_SUITE("Boost.Context: callcc test suite");
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) );
648 test->add( BOOST_TEST_CASE( & test_bug12215) );
654 #if defined(BOOST_MSVC)
655 # pragma warning(pop)