diff --git a/example/callcc/Jamfile.v2 b/example/callcc/Jamfile.v2 index d33f55d..247202d 100644 --- a/example/callcc/Jamfile.v2 +++ b/example/callcc/Jamfile.v2 @@ -42,6 +42,14 @@ exe jump : jump.cpp ; +exe jump_ref + : jump_ref.cpp + ; + +exe jump_mov + : jump_mov.cpp + ; + exe fibonacci : fibonacci.cpp ; @@ -54,10 +62,10 @@ exe ontop : ontop.cpp ; -exe backtrace - : backtrace.cpp - ; - -exe echosse - : echosse.cpp - ; +#exe backtrace +# : backtrace.cpp +# ; +# +#exe echosse +# : echosse.cpp +# ; diff --git a/example/callcc/backtrace.cpp b/example/callcc/backtrace.cpp index dec2b89..b944f64 100644 --- a/example/callcc/backtrace.cpp +++ b/example/callcc/backtrace.cpp @@ -51,7 +51,7 @@ ctx::continuation f1( ctx::continuation && c) { } int main() { - ctx::callcc< void >( f1); + ctx::callcc( f1); std::cout << "main: done" << std::endl; return EXIT_SUCCESS; } diff --git a/example/callcc/echosse.cpp b/example/callcc/echosse.cpp index 71d1685..20b2073 100644 --- a/example/callcc/echosse.cpp +++ b/example/callcc/echosse.cpp @@ -30,16 +30,16 @@ ctx::continuation echo( ctx::continuation && c, int i) { std::cout << i; echoSSE( i); std::cout << " "; - c = ctx::callcc< int >( std::move( c), 0); - i = ctx::get_data< int >( c); + c = ctx::callcc( std::move( c), 0); + std::tie( i) = ctx::data< int >( c); } return std::move( c); } int main( int argc, char * argv[]) { - ctx::continuation c = ctx::callcc< int >( echo, 0); + ctx::continuation c = ctx::callcc( echo, 0); for ( int i = 1; i < 10; ++i) { - c = ctx::callcc< int >( std::move( c), i); + c = ctx::callcc( std::move( c), i); } std::cout << "\nmain: done" << std::endl; return EXIT_SUCCESS; diff --git a/example/callcc/fibonacci.cpp b/example/callcc/fibonacci.cpp index a6583f6..0e9e6b1 100644 --- a/example/callcc/fibonacci.cpp +++ b/example/callcc/fibonacci.cpp @@ -15,12 +15,14 @@ namespace ctx = boost::context; int main() { ctx::continuation c; int i=0; - c=ctx::callcc< int >( - [](ctx::continuation && c, int) mutable { + c=ctx::callcc( + std::allocator_arg, + ctx::fixedsize_stack(), + [](ctx::continuation && c, int){ int a=0; int b=1; for(;;){ - c=ctx::callcc< int >(std::move(c),a); + c=ctx::callcc(std::move(c),a); auto next=a+b; a=b; b=next; @@ -28,14 +30,11 @@ int main() { return std::move( c); }, 0); - c=ctx::callcc< int >(std::move(c),0); i=ctx::get_data(c); std::cout<(std::move(c),0); i=ctx::get_data(c); std::cout<(std::move(c),0); i=ctx::get_data(c); std::cout<(std::move(c),0); i=ctx::get_data(c); std::cout<(std::move(c),0); i=ctx::get_data(c); std::cout<(std::move(c),0); i=ctx::get_data(c); std::cout<(std::move(c),0); i=ctx::get_data(c); std::cout<(std::move(c),0); i=ctx::get_data(c); std::cout<(c); + std::cout<( std::move( c), data + 2); - data = ctx::get_data< int >( c); + c = ctx::callcc( std::move( c), data + 2); + data = ctx::data< int >( c); std::cout << "f1: entered second time: " << data << std::endl; return std::move( c); } @@ -22,12 +22,12 @@ ctx::continuation f1( ctx::continuation && c, int data) { int main() { ctx::continuation c; int data = 1; - c = ctx::callcc< int >( f1, data); - data = ctx::get_data< int >( c); + c = ctx::callcc( f1, data); + data = ctx::data< int >( c); std::cout << "f1: returned first time: " << data << std::endl; - c = ctx::callcc< int >( std::move( c), data + 2); + c = ctx::callcc( std::move( c), data + 2); if ( ctx::has_data( c) ) { - data = ctx::get_data< int >( c); + data = ctx::data< int >( c); std::cout << "f1: returned second time: " << data << std::endl; } else { std::cout << "f1: returned second time: no data" << std::endl; diff --git a/example/callcc/jump_mov.cpp b/example/callcc/jump_mov.cpp new file mode 100644 index 0000000..7cbc536 --- /dev/null +++ b/example/callcc/jump_mov.cpp @@ -0,0 +1,62 @@ + +// Copyright Oliver Kowalke 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +#include + +namespace ctx = boost::context; + +class moveable { +public: + bool state; + int value; + + moveable() : + state( false), + value( -1) { + } + + moveable( int v) : + state( true), + value( v) { + } + + moveable( moveable && other) : + state( other.state), + value( other.value) { + other.state = false; + other.value = -1; + } + + moveable & operator=( moveable && other) { + if ( this == & other) return * this; + state = other.state; + value = other.value; + other.state = false; + other.value = -1; + return * this; + } + + moveable( moveable const& other) = delete; + moveable & operator=( moveable const& other) = delete; +}; + +ctx::continuation f1( ctx::continuation && c, moveable && data) { + c = ctx::callcc( std::move( c), std::move( data) ); + return std::move( c); +} + +int main() { + ctx::continuation c; + moveable data1{ 3 }; + c = ctx::callcc( std::allocator_arg, ctx::fixedsize_stack{}, f1, std::move( data1) ); + moveable data2; + data2 = ctx::data< moveable >( c); + std::cout << "main: done" << std::endl; + return EXIT_SUCCESS; +} diff --git a/example/callcc/jump_ref.cpp b/example/callcc/jump_ref.cpp new file mode 100644 index 0000000..e74e5a6 --- /dev/null +++ b/example/callcc/jump_ref.cpp @@ -0,0 +1,38 @@ + +// Copyright Oliver Kowalke 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +#include + +namespace ctx = boost::context; + +ctx::continuation f1( ctx::continuation && c, int & data) { + std::cout << "f1: entered first time: " << data << std::endl; + data += 2; + c = ctx::callcc( std::move( c), std::ref( data) ); + data += 2; + std::cout << "f1: entered second time: " << data << std::endl; + return std::move( c); +} + +int main() { + ctx::continuation c; + int data_ = 1; + int & data = data_; + c = ctx::callcc( std::allocator_arg, ctx::fixedsize_stack{}, f1, std::ref( data) ); + data = ctx::data< int & >( c); + std::cout << "f1: returned first time: " << data << std::endl; + c = ctx::callcc( std::move( c), std::ref( data) ); + if ( c) { + std::cout << "f1: returned second time: " << data << std::endl; + } else { + std::cout << "f1: returned second time: no data" << std::endl; + } + std::cout << "main: done" << std::endl; + return EXIT_SUCCESS; +} diff --git a/example/callcc/jump_void.cpp b/example/callcc/jump_void.cpp index 6338322..94fbd1f 100644 --- a/example/callcc/jump_void.cpp +++ b/example/callcc/jump_void.cpp @@ -13,15 +13,15 @@ namespace ctx = boost::context; ctx::continuation f1( ctx::continuation && cm) { std::cout << "f1: entered first time" << std::endl; - cm = ctx::callcc< void >( std::move( cm) ); + cm = ctx::callcc( std::move( cm) ); std::cout << "f1: entered second time" << std::endl; return std::move( cm); } int main() { - ctx::continuation c = ctx::callcc< void >( f1); + ctx::continuation c = ctx::callcc( f1); std::cout << "f1: returned first time" << std::endl; - c = ctx::callcc< void >( std::move( c) ); + c = ctx::callcc( std::move( c) ); std::cout << "f1: returned second time" << std::endl; std::cout << "main: done" << std::endl; diff --git a/example/callcc/ontop.cpp b/example/callcc/ontop.cpp index aa5081a..2792eae 100644 --- a/example/callcc/ontop.cpp +++ b/example/callcc/ontop.cpp @@ -12,32 +12,31 @@ namespace ctx = boost::context; -ctx::continuation f1( ctx::continuation && c, int data) { - std::cout << "f1: entered first time: " << data << std::endl; - c = ctx::callcc< int >( std::move( c), data + 1); - data = ctx::get_data< int >( c); - std::cout << "f1: entered second time: " << data << std::endl; - c = ctx::callcc< int >( std::move( c), data + 1); - data = ctx::get_data< int >( c); - std::cout << "f1: entered third time: " << data << std::endl; - return std::move( c); -} - -int f2( int data) { - std::cout << "f2: entered: " << data << std::endl; - return -1; -} - int main() { ctx::continuation c; int data = 0; - c = ctx::callcc< int >( f1, data + 1); - data = ctx::get_data< int >( c); + c = ctx::callcc( [](ctx::continuation && c,int data) { + std::cout << "f1: entered first time: " << data << std::endl; + c = ctx::callcc( std::move( c), data + 1); + data = ctx::data< int >( c); + std::cout << "f1: entered second time: " << data << std::endl; + c = ctx::callcc( std::move( c), data + 1); + data = ctx::data< int >( c); + std::cout << "f1: entered third time: " << data << std::endl; + return std::move( c); + }, + data + 1); + data = ctx::data< int >( c); std::cout << "f1: returned first time: " << data << std::endl; - c = ctx::callcc< int >( std::move( c), data + 1); - data = ctx::get_data< int >( c); + c = ctx::callcc( std::move( c), data + 1); + data = ctx::data< int >( c); std::cout << "f1: returned second time: " << data << std::endl; - c = ctx::callcc< int >( std::move( c), ctx::exec_ontop_arg, f2, data + 1); + c = ctx::callcc( std::move( c), ctx::exec_ontop_arg, + [](int data){ + std::cout << "f2: entered: " << data << std::endl; + return -1; + }, + data + 1); std::cout << "f1: returned third time" << std::endl; std::cout << "main: done" << std::endl; return EXIT_SUCCESS; diff --git a/example/callcc/ontop_void.cpp b/example/callcc/ontop_void.cpp index 444a076..6b03184 100644 --- a/example/callcc/ontop_void.cpp +++ b/example/callcc/ontop_void.cpp @@ -14,9 +14,9 @@ namespace ctx = boost::context; ctx::continuation f1( ctx::continuation && c) { std::cout << "f1: entered first time" << std::endl; - c = ctx::callcc< void >( std::move( c) ); + c = ctx::callcc( std::move( c) ); std::cout << "f1: entered second time" << std::endl; - c = ctx::callcc< void >( std::move( c) ); + c = ctx::callcc( std::move( c) ); std::cout << "f1: entered third time" << std::endl; return std::move( c); } @@ -26,11 +26,11 @@ void f2() { } int main() { - ctx::continuation c = ctx::callcc< void >( f1); + ctx::continuation c = ctx::callcc( f1); std::cout << "f1: returned first time" << std::endl; - c = ctx::callcc< void >( std::move( c) ); + c = ctx::callcc( std::move( c) ); std::cout << "f1: returned second time" << std::endl; - c = ctx::callcc< void >( std::move( c), ctx::exec_ontop_arg, f2); + c = ctx::callcc( std::move( c), ctx::exec_ontop_arg, f2); std::cout << "f1: returned third time" << std::endl; std::cout << "main: done" << std::endl; diff --git a/example/callcc/parser.cpp b/example/callcc/parser.cpp index 7054ea0..16eb0b9 100644 --- a/example/callcc/parser.cpp +++ b/example/callcc/parser.cpp @@ -96,13 +96,13 @@ int main() { boost::context::continuation source; // user-code pulls parsed data from parser // invert control flow - source=ctx::callcc( + source=ctx::callcc( [&is](ctx::continuation && sink,char){ // create parser with callback function Parser p( is, [&sink](char c){ // resume main execution context - sink=ctx::callcc(std::move(sink),c); + sink=ctx::callcc(std::move(sink),c); }); // start recursive parsing p.run(); @@ -111,9 +111,9 @@ int main() { }, '\0'); while(ctx::has_data(source)){ - char c=ctx::get_data(source); + char c=ctx::data(source); printf("Parsed: %c\n",c); - source=ctx::callcc(std::move(source),'\0'); + source=ctx::callcc(std::move(source),'\0'); if (!c) { break; } diff --git a/example/callcc/throw.cpp b/example/callcc/throw.cpp index 1788030..27d20ad 100644 --- a/example/callcc/throw.cpp +++ b/example/callcc/throw.cpp @@ -21,11 +21,11 @@ struct my_exception : public std::runtime_error { }; int main() { - ctx::continuation c = ctx::callcc< void >([](boost::context::continuation && c) { + ctx::continuation c = ctx::callcc([](boost::context::continuation && c) { for (;;) { try { std::cout << "entered" << std::endl; - c = ctx::callcc< void >( std::move( c) ); + c = ctx::callcc( std::move( c) ); } catch ( boost::context::ontop_error const& e) { try { std::rethrow_if_nested( e); @@ -37,9 +37,9 @@ int main() { } return std::move( c); }); - c = ctx::callcc< void >( std::move( c) ); - c = ctx::callcc< void >( std::move( c) ); - c = ctx::callcc< void >( std::move( c), ctx::exec_ontop_arg, []() { throw my_exception("abc"); }); + c = ctx::callcc( std::move( c) ); + c = ctx::callcc( std::move( c) ); + c = ctx::callcc( std::move( c), ctx::exec_ontop_arg, []() { throw my_exception("abc"); }); std::cout << "main: done" << std::endl; diff --git a/include/boost/context/continuation_v1.hpp b/include/boost/context/continuation_v1.hpp index 7e38238..ad8d122 100644 --- a/include/boost/context/continuation_v1.hpp +++ b/include/boost/context/continuation_v1.hpp @@ -27,6 +27,7 @@ #if defined(BOOST_NO_CXX17_STD_APPLY) #include #endif +#include #include #include #include @@ -293,8 +294,27 @@ fcontext_t context_create( preallocated palloc, StackAlloc salloc, Fn && fn) { return jump_fcontext( fctx, rec).fctx; } -template< typename ... Ret > -struct callcc_helper; +template< typename ... Arg > +struct result_type { + typedef std::tuple< Arg ... > type; + + static + type get( void * data) { + auto p = static_cast< std::tuple< std::exception_ptr, std::tuple< Arg ... > > * >( data); + return std::move( std::get< 1 >( * p) ); + } +}; + +template< typename Arg > +struct result_type< Arg > { + typedef Arg type; + + static + type get( void * data) { + auto p = static_cast< std::tuple< std::exception_ptr, std::tuple< Arg > > * >( data); + return std::forward< Arg >( std::get< 0 >( std::get< 1 >( * p) ) ); + } +}; }} @@ -302,24 +322,52 @@ inline namespace v1 { class continuation { private: - friend class ontop_error; - - template< typename ... Ret > - friend struct detail::callcc_helper; - template< typename Ctx, typename ArgTuple, typename StackAlloc, typename Fn > friend class detail::record; template< typename Ctx, typename StackAlloc, typename Fn > friend class detail::record_void; + friend class ontop_error; + + template< typename StackAlloc, typename Fn, typename ... Arg > + friend continuation + callcc( std::allocator_arg_t, StackAlloc, Fn &&, Arg ...); + + template< typename StackAlloc, typename Fn, typename ... Arg > + friend continuation + callcc( std::allocator_arg_t, preallocated, StackAlloc, Fn &&, Arg ...); + + template< typename ... Arg > + friend continuation + callcc( continuation &&, Arg ...); + + template< typename Fn, typename ... Arg > + friend continuation + callcc( continuation &&, exec_ontop_arg_t, Fn &&, Arg ...); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, StackAlloc, Fn &&); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, preallocated, StackAlloc, Fn &&); + + friend continuation + callcc( continuation &&); + + template< typename Fn > + friend continuation + callcc( continuation &&, exec_ontop_arg_t, Fn &&); + friend bool has_data( continuation const&) noexcept; template< typename Arg > - friend Arg get_data( continuation const&); + friend Arg get( continuation const&); template< typename ... Arg > - friend std::tuple< Arg ... > get_data( continuation const&); + friend typename detail::result_type< Arg ... >::type data( continuation const&); detail::fcontext_t fctx_{ nullptr }; void * data_{ nullptr }; @@ -408,6 +456,17 @@ public: } }; +inline +bool has_data( continuation const& c) noexcept { + return c && nullptr != c.data_; +} + +template< typename ... Arg > +typename detail::result_type< Arg ... >::type data( continuation const& c) { + BOOST_ASSERT( nullptr != c.data_); + return detail::result_type< Arg ... >::get( c.data_); +} + class ontop_error : public std::exception { private: detail::fcontext_t fctx_; @@ -422,238 +481,164 @@ public: } }; -inline -bool has_data( continuation const& c) noexcept { - return c && nullptr != c.data_; -} - -template< typename Arg > -Arg get_data( continuation const& c) { - BOOST_ASSERT( has_data( c) ); - using ArgTuple = std::tuple< Arg >; - auto p = static_cast< std::tuple< std::exception_ptr, ArgTuple > * >( c.data_); - return std::get< 0 >( std::move( std::get< 1 >( * p) ) ); -} - -template< typename ... Arg > -std::tuple< Arg ... > get_data( continuation const& c) { - BOOST_ASSERT( nullptr != c.data_); - using ArgTuple = std::tuple< Arg ... >; - auto p = static_cast< std::tuple< std::exception_ptr, ArgTuple > * >( c.data_); - return std::move( std::get< 1 >( * p) ); -} - -} - -namespace detail { -inline namespace v1 { - -template< typename ... Arg > -struct callcc_helper { - template< typename StackAlloc, typename Fn > - static - continuation - callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Arg ... arg) { - using ArgTuple = std::tuple< Arg ... >; - using Record = detail::record< continuation, ArgTuple, StackAlloc, Fn >; - return callcc( continuation{ - context_create< Record >( - salloc, std::forward< Fn >( fn) ) }, - std::forward< Arg >( arg) ... ); - } - - template< typename StackAlloc, typename Fn > - static - continuation - callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Arg ... arg) { - using ArgTuple = std::tuple< Arg ... >; - using Record = detail::record< continuation, ArgTuple, StackAlloc, Fn >; - return callcc( continuation{ - context_create< Record >( - palloc, salloc, std::forward< Fn >( fn) ) }, - std::forward< Arg >( arg) ... ); - } - - static - continuation - callcc( continuation && c, Arg ... arg) { - BOOST_ASSERT( nullptr != c.fctx_); - using ArgTuple = std::tuple< Arg ... >; - ArgTuple tpl{ std::forward< Arg >( arg) ... }; - auto p = std::make_tuple( std::exception_ptr{}, std::move( tpl) ); - detail::transfer_t t = detail::jump_fcontext( detail::exchange( c.fctx_, nullptr), & p); - if ( nullptr != t.data) { - auto p = static_cast< std::tuple< std::exception_ptr, ArgTuple > * >( t.data); - std::exception_ptr eptr = std::get< 0 >( * p); - if ( eptr) { - try { - std::rethrow_exception( eptr); - } catch (...) { - std::throw_with_nested( ontop_error{ t.fctx } ); - } - } - } - return continuation{ t.fctx, t.data }; - } - - template< typename Fn > - static - continuation - callcc( continuation && c, exec_ontop_arg_t, Fn && fn, Arg ... arg) { - BOOST_ASSERT( nullptr != c.fctx_); - using ArgTuple = std::tuple< Arg ... >; - ArgTuple tpl{ std::forward< Arg >( arg) ... }; - auto p = std::make_tuple( fn, std::make_tuple( std::exception_ptr{}, std::move( tpl) ) ); - detail::transfer_t t = detail::ontop_fcontext( - detail::exchange( c.fctx_, nullptr), - & p, - detail::context_ontop< Fn, Arg ... >); - if ( nullptr != t.data) { - auto p = static_cast< std::tuple< std::exception_ptr, ArgTuple > * >( t.data); - std::exception_ptr eptr = std::get< 0 >( * p); - if ( eptr) { - try { - std::rethrow_exception( eptr); - } catch (...) { - std::throw_with_nested( ontop_error{ t.fctx } ); - } - } - } - return continuation{ t.fctx, t.data }; - } -}; - -template<> -struct callcc_helper< void > { - template< typename StackAlloc, typename Fn > - static - continuation - callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn) { - using Record = detail::record_void< continuation, StackAlloc, Fn >; - return callcc( - continuation{ - detail::context_create< Record >( - salloc, std::forward< Fn >( fn) ) } ); - } - - template< typename StackAlloc, typename Fn > - static - continuation - callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn) { - using Record = detail::record_void< continuation, StackAlloc, Fn >; - return callcc( - continuation{ - detail::context_create< Record >( - palloc, salloc, std::forward< Fn >( fn) ) } ); - } - - static - continuation - callcc( continuation && c) { - BOOST_ASSERT( nullptr != c.fctx_); - detail::transfer_t t = detail::jump_fcontext( detail::exchange( c.fctx_, nullptr), nullptr); - if ( nullptr != t.data) { - std::exception_ptr * eptr = static_cast< std::exception_ptr * >( t.data); - try { - std::rethrow_exception( * eptr); - } catch (...) { - std::throw_with_nested( ontop_error{ t.fctx } ); - } - } - return continuation{ t.fctx }; - } - - template< typename Fn > - static - continuation - callcc( continuation && c, exec_ontop_arg_t, Fn && fn) { - BOOST_ASSERT( nullptr != c.fctx_); - auto p = std::make_tuple( fn, std::exception_ptr{} ); - detail::transfer_t t = detail::ontop_fcontext( - detail::exchange( c.fctx_, nullptr), - & p, - detail::context_ontop_void< Fn >); - if ( nullptr != t.data) { - std::exception_ptr * eptr = static_cast< std::exception_ptr * >( t.data); - try { - std::rethrow_exception( * eptr); - } catch (...) { - std::throw_with_nested( ontop_error{ t.fctx } ); - } - } - return continuation{ t.fctx }; - } - -}; - -}} - -inline namespace v1 { - +// Arg template< - typename ... Ret, typename Fn, typename ... Arg, typename = detail::disable_overload< continuation, Fn > > continuation -callcc( Fn && fn, Arg && ... arg) { - return detail::callcc_helper< Ret ... >::callcc( +callcc( Fn && fn, Arg ... arg) { + return callcc( std::allocator_arg, fixedsize_stack(), std::forward< Fn >( fn), std::forward< Arg >( arg) ...); } template< - typename ... Ret, typename StackAlloc, typename Fn, typename ... Arg > continuation -callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Arg && ... arg) { - return detail::callcc_helper< Ret ... >::callcc( - std::allocator_arg, salloc, - std::forward< Fn >( fn), std::forward< Arg >( arg) ...); +callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Arg ... arg) { + using ArgTuple = std::tuple< Arg ... >; + using Record = detail::record< continuation, ArgTuple, StackAlloc, Fn >; + return callcc( continuation{ + detail::context_create< Record >( + salloc, std::forward< Fn >( fn) ) }, + std::forward< Arg >( arg) ... ); } template< - typename ... Ret, typename StackAlloc, typename Fn, typename ... Arg > continuation -callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Arg && ... arg) { - return detail::callcc_helper< Ret ... >::callcc( - std::allocator_arg, palloc, salloc, - std::forward< Fn >( fn), std::forward< Arg >( arg) ...); +callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Arg ... arg) { + using ArgTuple = std::tuple< Arg ... >; + using Record = detail::record< continuation, ArgTuple, StackAlloc, Fn >; + return callcc( continuation{ + detail::context_create< Record >( + palloc, salloc, std::forward< Fn >( fn) ) }, + std::forward< Arg >( arg) ... ); } -template< - typename ... Ret, - typename ... Arg -> +template< typename ... Arg > continuation -callcc( continuation && c, Arg && ... arg) { - return detail::callcc_helper< Ret ... >::callcc( - std::move( c), std::forward< Arg >( arg) ... ); +callcc( continuation && c, Arg ... arg) { + BOOST_ASSERT( nullptr != c.fctx_); + using ArgTuple = std::tuple< Arg ... >; + auto p = std::make_tuple( std::exception_ptr{}, ArgTuple{ std::forward< Arg >( arg) ... } ); + detail::transfer_t t = detail::jump_fcontext( detail::exchange( c.fctx_, nullptr), & p); + if ( nullptr != t.data) { + auto p = static_cast< std::tuple< std::exception_ptr, ArgTuple > * >( t.data); + std::exception_ptr eptr = std::get< 0 >( * p); + if ( eptr) { + try { + std::rethrow_exception( eptr); + } catch (...) { + std::throw_with_nested( ontop_error{ t.fctx } ); + } + } + } + return continuation{ t.fctx, t.data }; } +template< typename Fn, typename ... Arg > +continuation +callcc( continuation && c, exec_ontop_arg_t, Fn && fn, Arg ... arg) { + BOOST_ASSERT( nullptr != c.fctx_); + using ArgTuple = std::tuple< Arg ... >; + auto p = std::make_tuple( fn, std::make_tuple( std::exception_ptr{}, ArgTuple{ std::forward< Arg >( arg) ... } ) ); + detail::transfer_t t = detail::ontop_fcontext( + detail::exchange( c.fctx_, nullptr), + & p, + detail::context_ontop< Fn, Arg ... >); + if ( nullptr != t.data) { + auto p = static_cast< std::tuple< std::exception_ptr, ArgTuple > * >( t.data); + std::exception_ptr eptr = std::get< 0 >( * p); + if ( eptr) { + try { + std::rethrow_exception( eptr); + } catch (...) { + std::throw_with_nested( ontop_error{ t.fctx } ); + } + } + } + return continuation{ t.fctx, t.data }; +} + +// void template< - typename ... Ret, typename Fn, - typename ... Arg + typename = detail::disable_overload< continuation, Fn > > continuation -callcc( continuation && c, exec_ontop_arg_t, Fn && fn, Arg && ... arg) { - return detail::callcc_helper< Ret ... >::callcc( - std::move( c), - exec_ontop_arg, std::forward< Fn >( fn), std::forward< Arg >( arg) ... ); +callcc( Fn && fn) { + return callcc( + std::allocator_arg, fixedsize_stack(), + std::forward< Fn >( fn) ); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn) { + using Record = detail::record_void< continuation, StackAlloc, Fn >; + return callcc( + continuation{ + detail::context_create< Record >( + salloc, std::forward< Fn >( fn) ) } ); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn) { + using Record = detail::record_void< continuation, StackAlloc, Fn >; + return callcc( + continuation{ + detail::context_create< Record >( + palloc, salloc, std::forward< Fn >( fn) ) } ); +} + +inline +continuation +callcc( continuation && c) { + BOOST_ASSERT( nullptr != c.fctx_); + detail::transfer_t t = detail::jump_fcontext( detail::exchange( c.fctx_, nullptr), nullptr); + if ( nullptr != t.data) { + std::exception_ptr * eptr = static_cast< std::exception_ptr * >( t.data); + try { + std::rethrow_exception( * eptr); + } catch (...) { + std::throw_with_nested( ontop_error{ t.fctx } ); + } + } + return continuation{ t.fctx }; +} + +template< typename Fn > +continuation +callcc( continuation && c, exec_ontop_arg_t, Fn && fn) { + BOOST_ASSERT( nullptr != c.fctx_); + auto p = std::make_tuple( fn, std::exception_ptr{} ); + detail::transfer_t t = detail::ontop_fcontext( + detail::exchange( c.fctx_, nullptr), + & p, + detail::context_ontop_void< Fn >); + if ( nullptr != t.data) { + std::exception_ptr * eptr = static_cast< std::exception_ptr * >( t.data); + try { + std::rethrow_exception( * eptr); + } catch (...) { + std::throw_with_nested( ontop_error{ t.fctx } ); + } + } + return continuation{ t.fctx }; } #if defined(BOOST_USE_SEGMENTED_STACKS) template< - typename ... Ret, typename Fn, typename ... Arg > @@ -661,7 +646,6 @@ continuation callcc( std::allocator_arg_t, segmented_stack, Fn &&, Arg ...); template< - typename ... Ret, typename StackAlloc, typename Fn, typename ... Arg diff --git a/include/boost/context/detail/decay_copy.hpp b/include/boost/context/detail/decay_copy.hpp new file mode 100644 index 0000000..84de23d --- /dev/null +++ b/include/boost/context/detail/decay_copy.hpp @@ -0,0 +1,36 @@ + +// Copyright Oliver Kowalke 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTEXT_DETAIL_DECAY_COPY_H +#define BOOST_CONTEXT_DETAIL_DECAY_COPY_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +template< typename T > +typename std::decay< T >::type +decay_copy( T && t) { + return std::forward< T >( t); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_DECAY_COPY_H diff --git a/test/test_callcc.cpp b/test/test_callcc.cpp index 0a650cd..fa7314c 100644 --- a/test/test_callcc.cpp +++ b/test/test_callcc.cpp @@ -138,7 +138,7 @@ ctx::continuation fn5( ctx::continuation && c) { } ctx::continuation fn4( ctx::continuation && c) { - ctx::continuation c1 = ctx::callcc< void >( fn5); + ctx::continuation c1 = ctx::callcc( fn5); value3 = 3.14; return std::move( c); } @@ -146,9 +146,9 @@ ctx::continuation fn4( ctx::continuation && c) { ctx::continuation fn6( ctx::continuation && c) { try { value1 = 3; - c = ctx::callcc< void >( std::move( c) ); + c = ctx::callcc( std::move( c) ); value1 = 7; - c = ctx::callcc< void >( std::move( c) ); + c = ctx::callcc( std::move( c) ); } catch ( my_exception & e) { value2 = e.what(); } @@ -157,7 +157,7 @@ ctx::continuation fn6( ctx::continuation && c) { ctx::continuation fn7( ctx::continuation && c) { Y y; - return ctx::callcc< void >( std::move( c) ); + return ctx::callcc( std::move( c) ); } ctx::continuation fn8( ctx::continuation && c, int i) { @@ -167,50 +167,50 @@ ctx::continuation fn8( ctx::continuation && c, int i) { ctx::continuation fn9( ctx::continuation && c, int i) { value1 = i; - c = ctx::callcc< int >( std::move( c), i); - value1 = ctx::get_data< int >( c); + c = ctx::callcc( std::move( c), i); + value1 = ctx::data< int >( c); return std::move( c); } ctx::continuation fn10( ctx::continuation && c, int & i) { - return ctx::callcc< int & >( std::move( c), i); + return ctx::callcc( std::move( c), std::ref( i) ); } ctx::continuation fn11( ctx::continuation && c, moveable m) { - c = ctx::callcc< moveable >( std::move( c), std::move( m) ); - m = ctx::get_data< moveable >( c); - return ctx::callcc< moveable >( std::move( c), std::move( m) ); + c = ctx::callcc( std::move( c), std::move( m) ); + m = ctx::data< moveable >( c); + return ctx::callcc( std::move( c), std::move( m) ); } ctx::continuation fn12( ctx::continuation && c, int i, std::string str) { - return ctx::callcc< int, std::string >( std::move( c), i, str); + return ctx::callcc( std::move( c), i, str); } ctx::continuation fn13( ctx::continuation && c, int i, moveable m) { - return ctx::callcc< int, moveable >( std::move( c), i, std::move( m) ); + return ctx::callcc( std::move( c), i, std::move( m) ); } ctx::continuation fn14( ctx::continuation && c, variant_t data) { int i = boost::get< int >( data); data = boost::lexical_cast< std::string >( i); - return ctx::callcc< variant_t >( std::move( c), data); + return ctx::callcc( std::move( c), data); } ctx::continuation fn15( ctx::continuation && c, Y * py) { - return ctx::callcc< Y * >( std::move( c), py); + return ctx::callcc( std::move( c), py); } ctx::continuation fn16( ctx::continuation && c, int i) { value1 = i; - c = ctx::callcc< int >( std::move( c), i); - value1 = ctx::get_data< int >( c); + c = ctx::callcc( std::move( c), i); + value1 = ctx::data< int >( c); return std::move( c); } ctx::continuation fn17( ctx::continuation && c, int i, int j) { for (;;) { - c = ctx::callcc< int, int >( std::move( c), i, j); - std::tie( i, j) = ctx::get_data< int, int >( c); + c = ctx::callcc( std::move( c), i, j); + std::tie( i, j) = ctx::data< int, int >( c); } return std::move( c); } @@ -220,15 +220,15 @@ void test_move() { value1 = 0; ctx::continuation c; BOOST_CHECK( ! c ); - ctx::continuation c1 = ctx::callcc< int >( fn9, 1); - ctx::continuation c2 = ctx::callcc< int >( fn9, 3); + ctx::continuation c1 = ctx::callcc( fn9, 1); + ctx::continuation c2 = ctx::callcc( fn9, 3); BOOST_CHECK( c1 ); BOOST_CHECK( c2 ); c1 = std::move( c2); BOOST_CHECK( c1 ); BOOST_CHECK( ! c2 ); BOOST_CHECK_EQUAL( 3, value1); - ctx::callcc< int >( std::move( c1), 0); + ctx::callcc( std::move( c1), 0); BOOST_CHECK_EQUAL( 0, value1); BOOST_CHECK( ! c1 ); BOOST_CHECK( ! c2 ); @@ -237,14 +237,14 @@ void test_move() { void test_bind() { value1 = 0; X x; - ctx::continuation c = ctx::callcc< int >( std::bind( & X::foo, x, std::placeholders::_1, std::placeholders::_2), 7); + ctx::continuation c = ctx::callcc( std::bind( & X::foo, x, std::placeholders::_1, std::placeholders::_2), 7); BOOST_CHECK_EQUAL( 7, value1); } void test_exception() { { const char * what = "hello world"; - ctx::continuation c = ctx::callcc< const char * >( fn2, what); + ctx::continuation c = ctx::callcc( fn2, what); BOOST_CHECK_EQUAL( std::string( what), value2); BOOST_CHECK( ! c ); } @@ -252,13 +252,13 @@ void test_exception() { { bool catched = false; std::thread([&catched](){ - ctx::continuation c = ctx::callcc< void >([&catched](ctx::continuation && c){ - c = ctx::callcc< void >( std::move( c) ); + ctx::continuation c = ctx::callcc([&catched](ctx::continuation && c){ + c = ctx::callcc( std::move( c) ); seh( catched); return std::move( c); }); BOOST_CHECK( c ); - ctx::callcc< void >( std::move( c) ); + ctx::callcc( std::move( c) ); }).join(); BOOST_CHECK( catched); } @@ -267,7 +267,7 @@ void test_exception() { void test_fp() { double d = 7.13; - ctx::continuation c = ctx::callcc< double >( fn3, d); + ctx::continuation c = ctx::callcc( fn3, d); BOOST_CHECK_EQUAL( 10.58, value3); BOOST_CHECK( ! c ); } @@ -275,7 +275,7 @@ void test_fp() { void test_stacked() { value1 = 0; value3 = 0.; - ctx::continuation c = ctx::callcc< void >( fn4); + ctx::continuation c = ctx::callcc( fn4); BOOST_CHECK_EQUAL( 3, value1); BOOST_CHECK_EQUAL( 3.14, value3); BOOST_CHECK( ! c ); @@ -287,7 +287,7 @@ void test_prealloc() { ctx::stack_context sctx( alloc.allocate() ); void * sp = static_cast< char * >( sctx.sp) - 10; std::size_t size = sctx.size - 10; - ctx::continuation c = ctx::callcc< int >( std::allocator_arg, ctx::preallocated( sp, size, sctx), alloc, fn1, 7); + ctx::continuation c = ctx::callcc( std::allocator_arg, ctx::preallocated( sp, size, sctx), alloc, fn1, 7); BOOST_CHECK_EQUAL( 7, value1); BOOST_CHECK( ! c ); } @@ -295,36 +295,40 @@ void test_prealloc() { void test_ontop() { { int i = 3, j = 0; - ctx::continuation c = ctx::callcc< int >([](ctx::continuation && c, int x) { + ctx::continuation c = ctx::callcc([](ctx::continuation && c, int x) { for (;;) { - c = ctx::callcc< int >( std::move( c), x*10); - x = ctx::get_data< int >( c); + c = ctx::callcc( std::move( c), x*10); + if ( ctx::has_data( c) ) { + x = ctx::data< int >( c); + } } return std::move( c); }, i); - c = ctx::callcc< int >( std::move( c), ctx::exec_ontop_arg, [](int x){ return x-10; }, i); - j = ctx::get_data< int >( c); + c = ctx::callcc( std::move( c), ctx::exec_ontop_arg, [](int x){ return x-10; }, i); + if ( ctx::has_data( c) ) { + j = ctx::data< int >( c); + } BOOST_CHECK( c ); BOOST_CHECK_EQUAL( j, -70); } { int i = 3, j = 1; ctx::continuation c; - c = ctx::callcc< int, int >( fn17, i, j); - std::tie( i, j) = ctx::get_data< int, int >( c); - c = ctx::callcc< int, int >( std::move( c), ctx::exec_ontop_arg, [](int x,int y) { return std::make_tuple( x - y, x + y); }, i, j); - std::tie( i, j) = ctx::get_data< int, int >( c); + c = ctx::callcc( fn17, i, j); + std::tie( i, j) = ctx::data< int, int >( c); + c = ctx::callcc( std::move( c), ctx::exec_ontop_arg, [](int x,int y) { return std::make_tuple( x - y, x + y); }, i, j); + std::tie( i, j) = ctx::data< int, int >( c); BOOST_CHECK_EQUAL( i, 2); BOOST_CHECK_EQUAL( j, 4); } { moveable m1( 7), m2, dummy; - ctx::continuation c = ctx::callcc< moveable >( fn11, std::move( dummy) ); + ctx::continuation c = ctx::callcc( fn11, std::move( dummy) ); BOOST_CHECK( 7 == m1.value); BOOST_CHECK( m1.state); BOOST_CHECK( -1 == m2.value); BOOST_CHECK( ! m2.state); - c = ctx::callcc< moveable >( std::move( c), + c = ctx::callcc( std::move( c), ctx::exec_ontop_arg, [](moveable m){ BOOST_CHECK( m.state); @@ -332,7 +336,7 @@ void test_ontop() { return std::move( m); }, std::move( m1) ); - m2 = ctx::get_data< moveable >( c); + m2 = ctx::data< moveable >( c); BOOST_CHECK( ! m1.state); BOOST_CHECK( -1 == m1.value); BOOST_CHECK( m2.state); @@ -344,11 +348,11 @@ void test_ontop_exception() { { value1 = 0; value2 = ""; - ctx::continuation c = ctx::callcc< void >([](ctx::continuation && c){ + ctx::continuation c = ctx::callcc([](ctx::continuation && c){ for (;;) { value1 = 3; try { - c = ctx::callcc< void >( std::move( c) ); + c = ctx::callcc( std::move( c) ); } catch ( ctx::ontop_error const& e) { try { std::rethrow_if_nested( e); @@ -360,10 +364,10 @@ void test_ontop_exception() { } return std::move( c); }); - c = ctx::callcc< void >( std::move( c) ); + c = ctx::callcc( std::move( c) ); BOOST_CHECK_EQUAL( 3, value1); const char * what = "hello world"; - ctx::callcc< void >( std::move( c), ctx::exec_ontop_arg, [what](){ throw my_exception( what); }); + ctx::callcc( std::move( c), ctx::exec_ontop_arg, [what](){ throw my_exception( what); }); BOOST_CHECK_EQUAL( 3, value1); BOOST_CHECK_EQUAL( std::string( what), value2); } @@ -371,11 +375,11 @@ void test_ontop_exception() { value2 = ""; int i = 3, j = 1; ctx::continuation c; - c = ctx::callcc< int, int >([]( ctx::continuation && c, int x, int y) { + c = ctx::callcc([]( ctx::continuation && c, int x, int y) { for (;;) { try { - c = ctx::callcc< int, int >( std::move( c), x+y,x-y); - std::tie( x, y) = ctx::get_data< int, int >( c); + c = ctx::callcc( std::move( c), x+y,x-y); + std::tie( x, y) = ctx::data< int, int >( c); } catch ( boost::context::ontop_error const& e) { try { std::rethrow_if_nested( e); @@ -389,11 +393,11 @@ void test_ontop_exception() { }, i, j); BOOST_CHECK( c ); - std::tie( i, j) = ctx::get_data< int, int >( c); + std::tie( i, j) = ctx::data< int, int >( c); BOOST_CHECK_EQUAL( i, 4); BOOST_CHECK_EQUAL( j, 2); const char * what = "hello world"; - c = ctx::callcc< int, int >( std::move( c), + c = ctx::callcc( std::move( c), ctx::exec_ontop_arg, [what](int x, int y) { throw my_exception(what); @@ -410,14 +414,14 @@ void test_ontop_exception() { void test_termination() { { value1 = 0; - ctx::continuation c = ctx::callcc< void >( fn7); + ctx::continuation c = ctx::callcc( fn7); BOOST_CHECK_EQUAL( 3, value1); } BOOST_CHECK_EQUAL( 7, value1); { value1 = 0; BOOST_CHECK_EQUAL( 0, value1); - ctx::continuation c = ctx::callcc< void >( fn5); + ctx::continuation c = ctx::callcc( fn5); BOOST_CHECK_EQUAL( 3, value1); BOOST_CHECK( ! c ); } @@ -427,13 +431,13 @@ void test_termination() { int i = 3; ctx::continuation c; BOOST_CHECK( ! c ); - c = ctx::callcc< int >( fn9, i); + c = ctx::callcc( fn9, i); BOOST_CHECK( c ); - i = ctx::get_data< int >( c); + i = ctx::data< int >( c); BOOST_CHECK_EQUAL( i, value1); BOOST_CHECK( c ); i = 7; - c = ctx::callcc< int >( std::move( c), i); + c = ctx::callcc( std::move( c), i); BOOST_CHECK( ! c ); BOOST_CHECK_EQUAL( i, value1); } @@ -444,14 +448,14 @@ void test_one_arg() { int dummy = 0; value1 = 0; ctx::continuation c; - c = ctx::callcc< int >( fn8, 7); + c = ctx::callcc( fn8, 7); BOOST_CHECK_EQUAL( 7, value1); } { int i = 3, j = 0; ctx::continuation c; - c = ctx::callcc< int >( fn9, i); - j = ctx::get_data< int >( c); + c = ctx::callcc( fn9, i); + j = ctx::data< int >( c); BOOST_CHECK_EQUAL( i, j); } { @@ -460,9 +464,11 @@ void test_one_arg() { int & j = j_; BOOST_CHECK_EQUAL( i, i_); BOOST_CHECK_EQUAL( j, j_); + BOOST_CHECK( & i != & j); ctx::continuation c; - c = ctx::callcc< int & >( fn10, i); - j = ctx::get_data< int & >( c); + c = ctx::callcc( fn10, std::ref( i) ); + BOOST_CHECK( ctx::has_data( c) ); + j = ctx::data< int & >( c); BOOST_CHECK_EQUAL( i, i_); BOOST_CHECK_EQUAL( j, i_); } @@ -470,8 +476,8 @@ void test_one_arg() { Y y; Y * py = nullptr; ctx::continuation c; - c = ctx::callcc< Y * >( fn15, & y); - py = ctx::get_data< Y * >( c); + c = ctx::callcc( fn15, & y); + py = ctx::data< Y * >( c); BOOST_CHECK( py == & y); } { @@ -481,8 +487,8 @@ void test_one_arg() { BOOST_CHECK( -1 == m2.value); BOOST_CHECK( ! m2.state); ctx::continuation c; - c = ctx::callcc< moveable >( fn11, std::move( m1) ); - m2 = ctx::get_data< moveable >( c); + c = ctx::callcc( fn11, std::move( m1) ); + m2 = ctx::data< moveable >( c); BOOST_CHECK( -1 == m1.value); BOOST_CHECK( ! m1.state); BOOST_CHECK( 7 == m2.value); @@ -494,9 +500,8 @@ void test_two_args() { { int i1 = 3, i2 = 0; std::string str1("abc"), str2; - ctx::continuation c; - c = ctx::callcc< int, std::string >( fn12, i1, str1); - std::tie( i2, str2) = ctx::get_data< int, std::string >( c); + ctx::continuation c = ctx::callcc( fn12, i1, str1); + std::tie( i2, str2) = ctx::data< int, std::string >( c); BOOST_CHECK_EQUAL( i1, i2); BOOST_CHECK_EQUAL( str1, str2); } @@ -508,8 +513,8 @@ void test_two_args() { BOOST_CHECK( -1 == m2.value); BOOST_CHECK( ! m2.state); ctx::continuation c; - c = ctx::callcc< int, moveable >( fn13, i1, std::move( m1) ); - std::tie( i2, m2) = ctx::get_data< int, moveable >( c); + c = ctx::callcc( fn13, i1, std::move( m1) ); + std::tie( i2, m2) = ctx::data< int, moveable >( c); BOOST_CHECK_EQUAL( i1, i2); BOOST_CHECK( -1 == m1.value); BOOST_CHECK( ! m1.state); @@ -523,8 +528,8 @@ void test_variant() { int i = 7; variant_t data1 = i, data2; ctx::continuation c; - c = ctx::callcc< variant_t >( fn14, data1); - data2 = ctx::get_data< variant_t >( c); + c = ctx::callcc( fn14, data1); + data2 = ctx::data< variant_t >( c); std::string str = boost::get< std::string >( data2); BOOST_CHECK_EQUAL( std::string("7"), str); } @@ -532,7 +537,7 @@ void test_variant() { #ifdef BOOST_WINDOWS void test_bug12215() { - ctx::continuation c = ctx::callcc< void >( + ctx::continuation c = ctx::callcc( [](ctx::continuation && c) { char buffer[MAX_PATH]; GetModuleFileName( nullptr, buffer, MAX_PATH);