mirror of
https://github.com/boostorg/context.git
synced 2026-01-19 04:02:17 +00:00
make execution_context (v2) typesafe
This commit is contained in:
@@ -26,22 +26,30 @@ project boost/context/example/execution_context
|
||||
<threading>multi
|
||||
;
|
||||
|
||||
exe jump
|
||||
: jump.cpp
|
||||
exe jump_void
|
||||
: jump_void.cpp
|
||||
;
|
||||
|
||||
exe parser
|
||||
: parser.cpp
|
||||
exe jump
|
||||
: jump.cpp
|
||||
;
|
||||
|
||||
exe fibonacci
|
||||
: fibonacci.cpp
|
||||
;
|
||||
|
||||
exe parser
|
||||
: parser.cpp
|
||||
;
|
||||
|
||||
exe parameter
|
||||
: parameter.cpp
|
||||
;
|
||||
|
||||
exe ontop_void
|
||||
: ontop_void.cpp
|
||||
;
|
||||
|
||||
exe ontop
|
||||
: ontop.cpp
|
||||
;
|
||||
|
||||
@@ -14,12 +14,12 @@ namespace ctx = boost::context;
|
||||
|
||||
int main() {
|
||||
int n=35;
|
||||
ctx::execution_context source(
|
||||
[n](ctx::execution_context sink,void*)mutable{
|
||||
ctx::execution_context< int > source(
|
||||
[n](ctx::execution_context< int > sink, int) mutable {
|
||||
int a=0;
|
||||
int b=1;
|
||||
while(n-->0){
|
||||
auto result=sink(&a);
|
||||
auto result=sink(a);
|
||||
sink=std::move(std::get<0>(result));
|
||||
auto next=a+b;
|
||||
a=b;
|
||||
@@ -28,9 +28,9 @@ int main() {
|
||||
return sink;
|
||||
});
|
||||
for(int i=0;i<10;++i){
|
||||
auto result=source();
|
||||
auto result=source(i);
|
||||
source=std::move(std::get<0>(result));
|
||||
std::cout<<*(int*)std::get<1>(result)<<" ";
|
||||
std::cout<<std::get<1>(result)<<" ";
|
||||
}
|
||||
std::cout<<std::endl;
|
||||
|
||||
|
||||
@@ -11,27 +11,20 @@
|
||||
|
||||
namespace ctx = boost::context;
|
||||
|
||||
ctx::execution_context f1( ctx::execution_context ctxm, void * data) {
|
||||
std::cout << "f1: entered first time" << std::endl;
|
||||
std::tie( ctxm, data) = ctxm();
|
||||
std::cout << "f1: entered second time" << std::endl;
|
||||
ctx::execution_context ctx2 = std::move( * static_cast< ctx::execution_context * >( data) );
|
||||
ctx2( & ctxm);
|
||||
return ctxm;
|
||||
}
|
||||
|
||||
ctx::execution_context f2( ctx::execution_context ctx1, void * data) {
|
||||
std::cout << "f2: entered first time" << std::endl;
|
||||
ctx::execution_context ctxm = std::move( * static_cast< ctx::execution_context * >( data) );
|
||||
ctx::execution_context< int > f1( ctx::execution_context< int > ctxm, int data) {
|
||||
std::cout << "f1: entered first time: " << data << std::endl;
|
||||
std::tie( ctxm, data) = ctxm( data + 2);
|
||||
std::cout << "f1: entered second time: " << data << std::endl;
|
||||
return ctxm;
|
||||
}
|
||||
|
||||
int main() {
|
||||
ctx::execution_context ctx1( f1);
|
||||
void * ignored;
|
||||
std::tie( ctx1, ignored) = ctx1();
|
||||
ctx::execution_context ctx2( f2);
|
||||
std::tie( ctx1, ignored) = ctx1( & ctx2);
|
||||
int data = 1;
|
||||
ctx::execution_context< int > ctx1( f1);
|
||||
std::tie( ctx1, data) = ctx1( data + 2);
|
||||
std::cout << "f1: returned first time: " << data << std::endl;
|
||||
std::tie( ctx1, data) = ctx1( data + 2);
|
||||
std::cout << "f1: returned second time: " << data << std::endl;
|
||||
|
||||
std::cout << "main: done" << std::endl;
|
||||
|
||||
|
||||
31
example/v2/jump_void.cpp
Normal file
31
example/v2/jump_void.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
// 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)
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/context/all.hpp>
|
||||
|
||||
namespace ctx = boost::context;
|
||||
|
||||
ctx::execution_context< void > f1( ctx::execution_context< void > ctxm) {
|
||||
std::cout << "f1: entered first time" << std::endl;
|
||||
ctxm = ctxm();
|
||||
std::cout << "f1: entered second time" << std::endl;
|
||||
return ctxm;
|
||||
}
|
||||
|
||||
int main() {
|
||||
ctx::execution_context< void > ctx1( f1);
|
||||
ctx1 = ctx1();
|
||||
std::cout << "f1: returned first time" << std::endl;
|
||||
ctx1 = ctx1();
|
||||
std::cout << "f1: returned second time" << std::endl;
|
||||
|
||||
std::cout << "main: done" << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -12,29 +12,29 @@
|
||||
|
||||
namespace ctx = boost::context;
|
||||
|
||||
ctx::execution_context f1( ctx::execution_context ctx, void * ignored) {
|
||||
std::cout << "f1: entered first time" << std::endl;
|
||||
std::tie( ctx, ignored) = ctx();
|
||||
std::cout << "f1: entered second time" << std::endl;
|
||||
std::tie( ctx, ignored) = ctx();
|
||||
std::cout << "f1: entered third time" << std::endl;
|
||||
ctx::execution_context< int > f1( ctx::execution_context< int > ctx, int data) {
|
||||
std::cout << "f1: entered first time: " << data << std::endl;
|
||||
std::tie( ctx, data) = ctx( data);
|
||||
std::cout << "f1: entered second time: " << data << std::endl;
|
||||
std::tie( ctx, data) = ctx( data);
|
||||
std::cout << "f1: entered third time: " << data << std::endl;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
std::tuple< ctx::execution_context, void * > f2( ctx::execution_context ctx, void * data) {
|
||||
std::cout << "f2: entered" << std::endl;
|
||||
return std::make_tuple( std::move( ctx), data);
|
||||
ctx::execution_context< int > f2( ctx::execution_context< int > ctx, int data) {
|
||||
std::cout << "f2: entered: " << data << std::endl;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int main() {
|
||||
void * ignored;
|
||||
ctx::execution_context ctx( f1);
|
||||
std::tie( ctx, ignored) = ctx();
|
||||
std::cout << "f1: returned first time" << std::endl;
|
||||
std::tie( ctx, ignored) = ctx();
|
||||
std::cout << "f1: returned second time" << std::endl;
|
||||
std::tie( ctx, ignored) = ctx( ctx::exec_ontop_arg, f2);
|
||||
std::cout << "f1: returned third time" << std::endl;
|
||||
int data = 3;
|
||||
ctx::execution_context< int > ctx( f1);
|
||||
std::tie( ctx, data) = ctx( data);
|
||||
std::cout << "f1: returned first time: " << data << std::endl;
|
||||
std::tie( ctx, data) = ctx( data);
|
||||
std::cout << "f1: returned second time: " << data << std::endl;
|
||||
std::tie( ctx, data) = ctx( ctx::exec_ontop_arg, f2, data + 2);
|
||||
std::cout << "f1: returned third time: " << data << std::endl;
|
||||
|
||||
std::cout << "main: done" << std::endl;
|
||||
|
||||
|
||||
41
example/v2/ontop_void.cpp
Normal file
41
example/v2/ontop_void.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
// 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)
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <tuple>
|
||||
|
||||
#include <boost/context/all.hpp>
|
||||
|
||||
namespace ctx = boost::context;
|
||||
|
||||
ctx::execution_context< void > f1( ctx::execution_context< void > ctx) {
|
||||
std::cout << "f1: entered first time" << std::endl;
|
||||
ctx = ctx();
|
||||
std::cout << "f1: entered second time" << std::endl;
|
||||
ctx = ctx();
|
||||
std::cout << "f1: entered third time" << std::endl;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context< void > f2( ctx::execution_context< void > ctx) {
|
||||
std::cout << "f2: entered" << std::endl;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int main() {
|
||||
ctx::execution_context< void > ctx( f1);
|
||||
ctx = ctx();
|
||||
std::cout << "f1: returned first time" << std::endl;
|
||||
ctx = ctx();
|
||||
std::cout << "f1: returned second time" << std::endl;
|
||||
ctx = ctx( ctx::exec_ontop_arg, f2);
|
||||
std::cout << "f1: returned third time" << std::endl;
|
||||
|
||||
std::cout << "main: done" << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -10,28 +10,31 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/context/all.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
typedef boost::variant<int,std::string> variant_t;
|
||||
|
||||
namespace ctx = boost::context;
|
||||
|
||||
class X{
|
||||
private:
|
||||
std::exception_ptr excptr_;
|
||||
ctx::execution_context ctx_;
|
||||
ctx::execution_context<variant_t> ctx_;
|
||||
|
||||
public:
|
||||
X():
|
||||
excptr_(),
|
||||
ctx_(
|
||||
[=](ctx::execution_context ctx, void * vp){
|
||||
[=](ctx::execution_context<variant_t> ctx, variant_t data){
|
||||
try {
|
||||
for (;;) {
|
||||
int i = * static_cast< int * >( vp);
|
||||
std::string str = boost::lexical_cast<std::string>(i);
|
||||
auto result = ctx( & str);
|
||||
int i = boost::get<int>(data);
|
||||
data = boost::lexical_cast<std::string>(i);
|
||||
auto result = ctx( data);
|
||||
ctx = std::move( std::get<0>( result) );
|
||||
vp = std::get<1>( result);
|
||||
data = std::get<1>( result);
|
||||
}
|
||||
} catch ( ctx::detail::forced_unwind const&) {
|
||||
throw;
|
||||
@@ -43,13 +46,14 @@ public:
|
||||
{}
|
||||
|
||||
std::string operator()(int i){
|
||||
auto result = ctx_( & i);
|
||||
variant_t data = i;
|
||||
auto result = ctx_( data);
|
||||
ctx_ = std::move( std::get<0>( result) );
|
||||
void * ret = std::get<1>( result);
|
||||
data = std::get<1>( result);
|
||||
if(excptr_){
|
||||
std::rethrow_exception(excptr_);
|
||||
}
|
||||
return * static_cast< std::string * >( ret);
|
||||
return boost::get<std::string>(data);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -96,13 +96,13 @@ int main() {
|
||||
std::exception_ptr except;
|
||||
|
||||
// execute parser in new execution context
|
||||
boost::context::execution_context source(
|
||||
[&is,&done,&except](ctx::execution_context sink,void*){
|
||||
boost::context::execution_context<char> source(
|
||||
[&is,&done,&except](ctx::execution_context<char> sink,char){
|
||||
// create parser with callback function
|
||||
Parser p( is,
|
||||
[&sink](char ch){
|
||||
// resume main execution context
|
||||
auto result = sink(&ch);
|
||||
auto result = sink(ch);
|
||||
sink = std::move(std::get<0>(result));
|
||||
});
|
||||
try {
|
||||
@@ -120,15 +120,15 @@ int main() {
|
||||
|
||||
// user-code pulls parsed data from parser
|
||||
// invert control flow
|
||||
auto result = source();
|
||||
auto result = source('\0');
|
||||
source = std::move(std::get<0>(result));
|
||||
void * vp = std::get<1>(result);
|
||||
char c = std::get<1>(result);
|
||||
if ( except) {
|
||||
std::rethrow_exception(except);
|
||||
}
|
||||
while( ! done) {
|
||||
printf("Parsed: %c\n",* static_cast<char*>(vp));
|
||||
std::tie(source,vp) = source();
|
||||
printf("Parsed: %c\n",c);
|
||||
std::tie(source,c) = source('\0');
|
||||
if (except) {
|
||||
std::rethrow_exception(except);
|
||||
}
|
||||
|
||||
@@ -76,31 +76,29 @@ void context_entry( transfer_t t_) noexcept {
|
||||
BOOST_ASSERT_MSG( false, "context already terminated");
|
||||
}
|
||||
|
||||
template< typename Ctx, typename Fn, typename Tpl >
|
||||
template< typename Ctx, typename Fn, typename ArgsTpl >
|
||||
transfer_t context_ontop( transfer_t t) {
|
||||
auto tpl = static_cast< std::tuple< void *, Fn, Tpl > * >( t.data);
|
||||
auto tpl = static_cast< std::tuple< Fn, ArgsTpl > * >( t.data);
|
||||
BOOST_ASSERT( nullptr != tpl);
|
||||
auto data = std::get< 0 >( * tpl);
|
||||
typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 1 >( * tpl) );
|
||||
auto args = std::forward< Tpl >( std::get< 2 >( * tpl) );
|
||||
typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * tpl) );
|
||||
auto args = std::get< 1 >( * tpl);
|
||||
Ctx ctx{ t.fctx };
|
||||
// execute function
|
||||
std::tie( ctx, data) = apply(
|
||||
ctx = apply(
|
||||
fn,
|
||||
std::tuple_cat(
|
||||
args,
|
||||
std::forward_as_tuple( std::move( ctx) ),
|
||||
std::tie( data) ) );
|
||||
return { exchange( ctx.fctx_, nullptr), data };
|
||||
args) );
|
||||
return { exchange( ctx.fctx_, nullptr), nullptr };
|
||||
}
|
||||
|
||||
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Args >
|
||||
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
|
||||
class record {
|
||||
private:
|
||||
StackAlloc salloc_;
|
||||
stack_context sctx_;
|
||||
typename std::decay< Fn >::type fn_;
|
||||
std::tuple< typename std::decay< Args >::type ... > args_;
|
||||
std::tuple< typename std::decay< Params >::type ... > params_;
|
||||
|
||||
static void destroy( record * p) noexcept {
|
||||
StackAlloc salloc = p->salloc_;
|
||||
@@ -113,11 +111,11 @@ private:
|
||||
|
||||
public:
|
||||
record( stack_context sctx, StackAlloc const& salloc,
|
||||
Fn && fn, Args && ... args) noexcept :
|
||||
Fn && fn, Params && ... params) noexcept :
|
||||
salloc_( salloc),
|
||||
sctx_( sctx),
|
||||
fn_( std::forward< Fn >( fn) ),
|
||||
args_( std::forward< Args >( args) ... ) {
|
||||
params_( std::forward< Params >( params) ... ) {
|
||||
}
|
||||
|
||||
record( record const&) = delete;
|
||||
@@ -129,20 +127,21 @@ public:
|
||||
|
||||
transfer_t run( transfer_t t) {
|
||||
Ctx from{ t.fctx };
|
||||
typename Ctx::args_tpl_t args = std::move( * static_cast< typename Ctx::args_tpl_t * >( t.data) );
|
||||
// invoke context-function
|
||||
Ctx cc = apply(
|
||||
fn_,
|
||||
std::move( fn_),
|
||||
std::tuple_cat(
|
||||
args_,
|
||||
params_,
|
||||
std::forward_as_tuple( std::move( from) ),
|
||||
std::tie( t.data) ) );
|
||||
std::move( args) ) );
|
||||
return { exchange( cc.fctx_, nullptr), nullptr };
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Args >
|
||||
fcontext_t context_create( StackAlloc salloc, Fn && fn, Args && ... args) {
|
||||
typedef record< Ctx, StackAlloc, Fn, Args ... > record_t;
|
||||
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
|
||||
fcontext_t context_create( StackAlloc salloc, Fn && fn, Params && ... params) {
|
||||
typedef record< Ctx, StackAlloc, Fn, Params ... > record_t;
|
||||
|
||||
auto sctx = salloc.allocate();
|
||||
// reserve space for control structure
|
||||
@@ -166,14 +165,14 @@ fcontext_t context_create( StackAlloc salloc, Fn && fn, Args && ... args) {
|
||||
BOOST_ASSERT( nullptr != fctx);
|
||||
// placment new for control structure on context-stack
|
||||
auto rec = ::new ( sp) record_t{
|
||||
sctx, salloc, std::forward< Fn >( fn), std::forward< Args >( args) ... };
|
||||
sctx, salloc, std::forward< Fn >( fn), std::forward< Params >( params) ... };
|
||||
// transfer control structure to context-stack
|
||||
return jump_fcontext( fctx, rec).fctx;
|
||||
}
|
||||
|
||||
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Args >
|
||||
fcontext_t context_create( preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args) {
|
||||
typedef record< Ctx, StackAlloc, Fn, Args ... > record_t;
|
||||
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
|
||||
fcontext_t context_create( preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params) {
|
||||
typedef record< Ctx, StackAlloc, Fn, Params ... > record_t;
|
||||
|
||||
// reserve space for control structure
|
||||
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
|
||||
@@ -196,19 +195,23 @@ fcontext_t context_create( preallocated palloc, StackAlloc salloc, Fn && fn, Arg
|
||||
BOOST_ASSERT( nullptr != fctx);
|
||||
// placment new for control structure on context-stack
|
||||
auto rec = ::new ( sp) record_t{
|
||||
palloc.sctx, salloc, std::forward< Fn >( fn), std::forward< Args >( args) ... };
|
||||
palloc.sctx, salloc, std::forward< Fn >( fn), std::forward< Params >( params) ... };
|
||||
// transfer control structure to context-stack
|
||||
return jump_fcontext( fctx, rec).fctx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class BOOST_CONTEXT_DECL execution_context {
|
||||
template< typename ... Args >
|
||||
class execution_context {
|
||||
private:
|
||||
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Args >
|
||||
typedef std::tuple< typename std::decay< Args >::type ... > args_tpl_t;
|
||||
typedef std::tuple< execution_context, typename std::decay< Args >::type ... > ret_tpl_t;
|
||||
|
||||
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
|
||||
friend class detail::record;
|
||||
|
||||
template< typename Ctx, typename Fn, typename Tpl >
|
||||
template< typename Ctx, typename Fn, typename ArgsTpl >
|
||||
friend detail::transfer_t detail::context_ontop( detail::transfer_t);
|
||||
|
||||
detail::fcontext_t fctx_{ nullptr };
|
||||
@@ -217,34 +220,23 @@ private:
|
||||
fctx_( fctx) {
|
||||
}
|
||||
|
||||
template< typename Fn, typename ... Args >
|
||||
detail::transfer_t resume_ontop_( void * data, Fn && fn, Args && ... args) {
|
||||
typedef std::tuple< typename std::decay< Args >::type ... > tpl_t;
|
||||
tpl_t tpl{ std::forward< Args >( args) ... };
|
||||
std::tuple< void *, Fn, tpl_t > p = std::forward_as_tuple( data, fn, tpl);
|
||||
return detail::ontop_fcontext(
|
||||
detail::exchange( fctx_, nullptr),
|
||||
& p,
|
||||
detail::context_ontop< execution_context, Fn, tpl_t >);
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr execution_context() noexcept = default;
|
||||
|
||||
#if defined(BOOST_USE_SEGMENTED_STACKS)
|
||||
// segmented-stack requires to preserve the segments of the `current` context
|
||||
// which is not possible (no global pointer to current context)
|
||||
template< typename Fn, typename ... Args >
|
||||
execution_context( std::allocator_arg_t, segmented_stack, Fn &&, Args && ...) = delete;
|
||||
template< typename Fn, typename ... Params >
|
||||
execution_context( std::allocator_arg_t, segmented_stack, Fn &&, Params && ...) = delete;
|
||||
|
||||
template< typename Fn, typename ... Args >
|
||||
execution_context( std::allocator_arg_t, preallocated, segmented_stack, Fn &&, Args && ...) = delete;
|
||||
template< typename Fn, typename ... Params >
|
||||
execution_context( std::allocator_arg_t, preallocated, segmented_stack, Fn &&, Params && ...) = delete;
|
||||
#else
|
||||
template< typename Fn,
|
||||
typename ... Args,
|
||||
typename ... Params,
|
||||
typename = detail::disable_overload< execution_context, Fn >
|
||||
>
|
||||
execution_context( Fn && fn, Args && ... args) :
|
||||
execution_context( Fn && fn, Params && ... params) :
|
||||
// deferred execution of fn and its arguments
|
||||
// arguments are stored in std::tuple<>
|
||||
// non-type template parameter pack via std::index_sequence_for<>
|
||||
@@ -253,14 +245,14 @@ public:
|
||||
fctx_( detail::context_create< execution_context >(
|
||||
fixedsize_stack(),
|
||||
std::forward< Fn >( fn),
|
||||
std::forward< Args >( args) ... ) ) {
|
||||
std::forward< Params >( params) ... ) ) {
|
||||
}
|
||||
|
||||
template< typename StackAlloc,
|
||||
typename Fn,
|
||||
typename ... Args
|
||||
typename ... Params
|
||||
>
|
||||
execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args) :
|
||||
execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Params && ... params) :
|
||||
// deferred execution of fn and its arguments
|
||||
// arguments are stored in std::tuple<>
|
||||
// non-type template parameter pack via std::index_sequence_for<>
|
||||
@@ -269,14 +261,14 @@ public:
|
||||
fctx_( detail::context_create< execution_context >(
|
||||
salloc,
|
||||
std::forward< Fn >( fn),
|
||||
std::forward< Args >( args) ... ) ) {
|
||||
std::forward< Params >( params) ... ) ) {
|
||||
}
|
||||
|
||||
template< typename StackAlloc,
|
||||
typename Fn,
|
||||
typename ... Args
|
||||
typename ... Params
|
||||
>
|
||||
execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args) :
|
||||
execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params) :
|
||||
// deferred execution of fn and its arguments
|
||||
// arguments are stored in std::tuple<>
|
||||
// non-type template parameter pack via std::index_sequence_for<>
|
||||
@@ -285,7 +277,7 @@ public:
|
||||
fctx_( detail::context_create< execution_context >(
|
||||
palloc, salloc,
|
||||
std::forward< Fn >( fn),
|
||||
std::forward< Args >( args) ... ) ) {
|
||||
std::forward< Params >( params) ... ) ) {
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -311,28 +303,31 @@ public:
|
||||
execution_context( execution_context const& other) noexcept = delete;
|
||||
execution_context & operator=( execution_context const& other) noexcept = delete;
|
||||
|
||||
std::tuple< execution_context, void * > operator()( void * data = nullptr) {
|
||||
ret_tpl_t operator()( Args ... args) {
|
||||
BOOST_ASSERT( nullptr != fctx_);
|
||||
detail::transfer_t t = detail::jump_fcontext( detail::exchange( fctx_, nullptr), data);
|
||||
return std::make_tuple( execution_context( t.fctx), t.data);
|
||||
args_tpl_t tpl( std::forward< Args >( args) ... );
|
||||
detail::transfer_t t = detail::jump_fcontext( detail::exchange( fctx_, nullptr), & tpl);
|
||||
args_tpl_t data; // Note: value-initialization, all elements must be default constructible
|
||||
if ( nullptr != t.data) {
|
||||
data = std::move( * static_cast< args_tpl_t * >( t.data) );
|
||||
}
|
||||
return std::tuple_cat( std::forward_as_tuple( execution_context( t.fctx) ), std::move( data) );
|
||||
}
|
||||
|
||||
template< typename Fn, typename ... Args >
|
||||
std::tuple< execution_context, void * > operator()( exec_ontop_arg_t, Fn && fn, Args && ... args) {
|
||||
template< typename Fn >
|
||||
ret_tpl_t operator()( exec_ontop_arg_t, Fn && fn, Args ... args) {
|
||||
BOOST_ASSERT( nullptr != fctx_);
|
||||
detail::transfer_t t = resume_ontop_( nullptr,
|
||||
std::forward< Fn >( fn),
|
||||
std::forward< Args >( args) ... );
|
||||
return std::make_tuple( execution_context( t.fctx), t.data);
|
||||
}
|
||||
|
||||
template< typename Fn, typename ... Args >
|
||||
std::tuple< execution_context, void * > operator()( void * data, exec_ontop_arg_t, Fn && fn, Args && ... args) {
|
||||
BOOST_ASSERT( nullptr != fctx_);
|
||||
detail::transfer_t t = resume_ontop_( data,
|
||||
std::forward< Fn >( fn),
|
||||
std::forward< Args >( args) ... );
|
||||
return std::make_tuple( execution_context( t.fctx), t.data);
|
||||
args_tpl_t tpl{ std::forward< Args >( args) ... };
|
||||
std::tuple< Fn, args_tpl_t > p = std::forward_as_tuple( fn, tpl);
|
||||
detail::transfer_t t = detail::ontop_fcontext(
|
||||
detail::exchange( fctx_, nullptr),
|
||||
& p,
|
||||
detail::context_ontop< execution_context, Fn, args_tpl_t >);
|
||||
args_tpl_t data; // Note: value-initialization, all elements must be default constructible
|
||||
if ( nullptr != t.data) {
|
||||
data = * static_cast< args_tpl_t * >( t.data);
|
||||
}
|
||||
return std::tuple_cat( std::forward_as_tuple( execution_context( t.fctx) ), data);
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
@@ -382,8 +377,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
inline
|
||||
void swap( execution_context & l, execution_context & r) noexcept {
|
||||
#include <boost/context/execution_context_v2_void.ipp>
|
||||
|
||||
template< typename ... Args >
|
||||
void swap( execution_context< Args ... > & l, execution_context< Args ... > & r) noexcept {
|
||||
l.swap( r);
|
||||
}
|
||||
|
||||
|
||||
290
include/boost/context/execution_context_v2_void.ipp
Normal file
290
include/boost/context/execution_context_v2_void.ipp
Normal file
@@ -0,0 +1,290 @@
|
||||
|
||||
// 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)
|
||||
|
||||
namespace detail {
|
||||
|
||||
template< typename Ctx, typename Fn >
|
||||
transfer_t context_ontop_void( transfer_t t) {
|
||||
auto tpl = static_cast< std::tuple< Fn > * >( t.data);
|
||||
BOOST_ASSERT( nullptr != tpl);
|
||||
typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * tpl) );
|
||||
Ctx ctx{ t.fctx };
|
||||
// execute function
|
||||
ctx = apply(
|
||||
fn,
|
||||
std::forward_as_tuple( std::move( ctx) ) );
|
||||
return { exchange( ctx.fctx_, nullptr), nullptr };
|
||||
}
|
||||
|
||||
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
|
||||
class record_void {
|
||||
private:
|
||||
StackAlloc salloc_;
|
||||
stack_context sctx_;
|
||||
typename std::decay< Fn >::type fn_;
|
||||
std::tuple< typename std::decay< Params >::type ... > params_;
|
||||
|
||||
static void destroy( record_void * p) noexcept {
|
||||
StackAlloc salloc = p->salloc_;
|
||||
stack_context sctx = p->sctx_;
|
||||
// deallocate record
|
||||
p->~record_void();
|
||||
// destroy stack with stack allocator
|
||||
salloc.deallocate( sctx);
|
||||
}
|
||||
|
||||
public:
|
||||
record_void( stack_context sctx, StackAlloc const& salloc,
|
||||
Fn && fn, Params && ... params) noexcept :
|
||||
salloc_( salloc),
|
||||
sctx_( sctx),
|
||||
fn_( std::forward< Fn >( fn) ),
|
||||
params_( std::forward< Params >( params) ... ) {
|
||||
}
|
||||
|
||||
record_void( record_void const&) = delete;
|
||||
record_void & operator=( record_void const&) = delete;
|
||||
|
||||
void deallocate() noexcept {
|
||||
destroy( this);
|
||||
}
|
||||
|
||||
transfer_t run( transfer_t t) {
|
||||
Ctx from{ t.fctx };
|
||||
// invoke context-function
|
||||
Ctx cc = apply(
|
||||
fn_,
|
||||
std::tuple_cat(
|
||||
params_,
|
||||
std::forward_as_tuple( std::move( from) ) ) );
|
||||
return { exchange( cc.fctx_, nullptr), nullptr };
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
|
||||
fcontext_t context_create_void( StackAlloc salloc, Fn && fn, Params && ... params) {
|
||||
typedef record_void< Ctx, StackAlloc, Fn, Params ... > record_t;
|
||||
|
||||
auto sctx = salloc.allocate();
|
||||
// reserve space for control structure
|
||||
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
|
||||
const std::size_t size = sctx.size - sizeof( record_t);
|
||||
void * sp = static_cast< char * >( sctx.sp) - sizeof( record_t);
|
||||
#else
|
||||
constexpr std::size_t func_alignment = 64; // alignof( record_t);
|
||||
constexpr std::size_t func_size = sizeof( record_t);
|
||||
// reserve space on stack
|
||||
void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
|
||||
// align sp pointer
|
||||
std::size_t space = func_size + func_alignment;
|
||||
sp = std::align( func_alignment, func_size, sp, space);
|
||||
BOOST_ASSERT( nullptr != sp);
|
||||
// calculate remaining size
|
||||
const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
|
||||
#endif
|
||||
// create fast-context
|
||||
const fcontext_t fctx = make_fcontext( sp, size, & context_entry< record_t >);
|
||||
BOOST_ASSERT( nullptr != fctx);
|
||||
// placment new for control structure on context-stack
|
||||
auto rec = ::new ( sp) record_t{
|
||||
sctx, salloc, std::forward< Fn >( fn), std::forward< Params >( params) ... };
|
||||
// transfer control structure to context-stack
|
||||
return jump_fcontext( fctx, rec).fctx;
|
||||
}
|
||||
|
||||
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
|
||||
fcontext_t context_create_void( preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params) {
|
||||
typedef record_void< Ctx, StackAlloc, Fn, Params ... > record_t;
|
||||
|
||||
// reserve space for control structure
|
||||
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
|
||||
const std::size_t size = palloc.size - sizeof( record_t);
|
||||
void * sp = static_cast< char * >( palloc.sp) - sizeof( record_t);
|
||||
#else
|
||||
constexpr std::size_t func_alignment = 64; // alignof( record_t);
|
||||
constexpr std::size_t func_size = sizeof( record_t);
|
||||
// reserve space on stack
|
||||
void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment;
|
||||
// align sp pointer
|
||||
std::size_t space = func_size + func_alignment;
|
||||
sp = std::align( func_alignment, func_size, sp, space);
|
||||
BOOST_ASSERT( nullptr != sp);
|
||||
// calculate remaining size
|
||||
const std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
|
||||
#endif
|
||||
// create fast-context
|
||||
const fcontext_t fctx = make_fcontext( sp, size, & context_entry< record_t >);
|
||||
BOOST_ASSERT( nullptr != fctx);
|
||||
// placment new for control structure on context-stack
|
||||
auto rec = ::new ( sp) record_t{
|
||||
palloc.sctx, salloc, std::forward< Fn >( fn), std::forward< Params >( params) ... };
|
||||
// transfer control structure to context-stack
|
||||
return jump_fcontext( fctx, rec).fctx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
class execution_context< void > {
|
||||
private:
|
||||
template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
|
||||
friend class detail::record_void;
|
||||
|
||||
template< typename Ctx, typename Fn >
|
||||
friend detail::transfer_t detail::context_ontop_void( detail::transfer_t);
|
||||
|
||||
detail::fcontext_t fctx_{ nullptr };
|
||||
|
||||
execution_context( detail::fcontext_t fctx) noexcept :
|
||||
fctx_( fctx) {
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr execution_context() noexcept = default;
|
||||
|
||||
#if defined(BOOST_USE_SEGMENTED_STACKS)
|
||||
// segmented-stack requires to preserve the segments of the `current` context
|
||||
// which is not possible (no global pointer to current context)
|
||||
template< typename Fn, typename ... Params >
|
||||
execution_context( std::allocator_arg_t, segmented_stack, Fn &&, Params && ...) = delete;
|
||||
|
||||
template< typename Fn, typename ... Params >
|
||||
execution_context( std::allocator_arg_t, preallocated, segmented_stack, Fn &&, Params && ...) = delete;
|
||||
#else
|
||||
template< typename Fn,
|
||||
typename ... Params,
|
||||
typename = detail::disable_overload< execution_context, Fn >
|
||||
>
|
||||
execution_context( Fn && fn, Params && ... params) :
|
||||
// deferred execution of fn and its arguments
|
||||
// arguments are stored in std::tuple<>
|
||||
// non-type template parameter pack via std::index_sequence_for<>
|
||||
// preserves the number of arguments
|
||||
// used to extract the function arguments from std::tuple<>
|
||||
fctx_( detail::context_create_void< execution_context >(
|
||||
fixedsize_stack(),
|
||||
std::forward< Fn >( fn),
|
||||
std::forward< Params >( params) ... ) ) {
|
||||
}
|
||||
|
||||
template< typename StackAlloc,
|
||||
typename Fn,
|
||||
typename ... Params
|
||||
>
|
||||
execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Params && ... params) :
|
||||
// deferred execution of fn and its arguments
|
||||
// arguments are stored in std::tuple<>
|
||||
// non-type template parameter pack via std::index_sequence_for<>
|
||||
// preserves the number of arguments
|
||||
// used to extract the function arguments from std::tuple<>
|
||||
fctx_( detail::context_create_void< execution_context >(
|
||||
salloc,
|
||||
std::forward< Fn >( fn),
|
||||
std::forward< Params >( params) ... ) ) {
|
||||
}
|
||||
|
||||
template< typename StackAlloc,
|
||||
typename Fn,
|
||||
typename ... Params
|
||||
>
|
||||
execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params) :
|
||||
// deferred execution of fn and its arguments
|
||||
// arguments are stored in std::tuple<>
|
||||
// non-type template parameter pack via std::index_sequence_for<>
|
||||
// preserves the number of arguments
|
||||
// used to extract the function arguments from std::tuple<>
|
||||
fctx_( detail::context_create_void< execution_context >(
|
||||
palloc, salloc,
|
||||
std::forward< Fn >( fn),
|
||||
std::forward< Params >( params) ... ) ) {
|
||||
}
|
||||
#endif
|
||||
|
||||
~execution_context() {
|
||||
if ( nullptr != fctx_) {
|
||||
detail::ontop_fcontext( detail::exchange( fctx_, nullptr), nullptr, detail::context_unwind);
|
||||
}
|
||||
}
|
||||
|
||||
execution_context( execution_context && other) noexcept :
|
||||
fctx_( other.fctx_) {
|
||||
other.fctx_ = nullptr;
|
||||
}
|
||||
|
||||
execution_context & operator=( execution_context && other) noexcept {
|
||||
if ( this != & other) {
|
||||
execution_context tmp = std::move( other);
|
||||
swap( tmp);
|
||||
}
|
||||
return * this;
|
||||
}
|
||||
|
||||
execution_context( execution_context const& other) noexcept = delete;
|
||||
execution_context & operator=( execution_context const& other) noexcept = delete;
|
||||
|
||||
execution_context operator()() {
|
||||
BOOST_ASSERT( nullptr != fctx_);
|
||||
detail::transfer_t t = detail::jump_fcontext( detail::exchange( fctx_, nullptr), nullptr);
|
||||
return execution_context( t.fctx);
|
||||
}
|
||||
|
||||
template< typename Fn >
|
||||
execution_context operator()( exec_ontop_arg_t, Fn && fn) {
|
||||
BOOST_ASSERT( nullptr != fctx_);
|
||||
std::tuple< Fn > p = std::forward_as_tuple( fn);
|
||||
detail::transfer_t t = detail::ontop_fcontext(
|
||||
detail::exchange( fctx_, nullptr),
|
||||
& p,
|
||||
detail::context_ontop_void< execution_context, Fn >);
|
||||
return execution_context( t.fctx);
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return nullptr != fctx_;
|
||||
}
|
||||
|
||||
bool operator!() const noexcept {
|
||||
return nullptr == fctx_;
|
||||
}
|
||||
|
||||
bool operator==( execution_context const& other) const noexcept {
|
||||
return fctx_ == other.fctx_;
|
||||
}
|
||||
|
||||
bool operator!=( execution_context const& other) const noexcept {
|
||||
return fctx_ != other.fctx_;
|
||||
}
|
||||
|
||||
bool operator<( execution_context const& other) const noexcept {
|
||||
return fctx_ < other.fctx_;
|
||||
}
|
||||
|
||||
bool operator>( execution_context const& other) const noexcept {
|
||||
return other.fctx_ < fctx_;
|
||||
}
|
||||
|
||||
bool operator<=( execution_context const& other) const noexcept {
|
||||
return ! ( * this > other);
|
||||
}
|
||||
|
||||
bool operator>=( execution_context const& other) const noexcept {
|
||||
return ! ( * this < other);
|
||||
}
|
||||
|
||||
template< typename charT, class traitsT >
|
||||
friend std::basic_ostream< charT, traitsT > &
|
||||
operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other) {
|
||||
if ( nullptr != other.fctx_) {
|
||||
return os << other.fctx_;
|
||||
} else {
|
||||
return os << "{not-a-context}";
|
||||
}
|
||||
}
|
||||
|
||||
void swap( execution_context & other) noexcept {
|
||||
std::swap( fctx_, other.fctx_);
|
||||
}
|
||||
};
|
||||
@@ -13,12 +13,16 @@
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <boost/context/all.hpp>
|
||||
#include <boost/context/detail/config.hpp>
|
||||
|
||||
typedef boost::variant<int,std::string> variant_t;
|
||||
|
||||
namespace ctx = boost::context;
|
||||
|
||||
int value1 = 0;
|
||||
@@ -26,7 +30,7 @@ std::string value2;
|
||||
double value3 = 0.;
|
||||
|
||||
struct X {
|
||||
ctx::execution_context foo( int i, ctx::execution_context ctx, void * ignored) {
|
||||
ctx::execution_context< void > foo( int i, ctx::execution_context< void > ctx) {
|
||||
value1 = i;
|
||||
return ctx;
|
||||
}
|
||||
@@ -42,21 +46,60 @@ struct Y {
|
||||
}
|
||||
};
|
||||
|
||||
struct my_exception : public std::runtime_error {
|
||||
ctx::execution_context ctx;
|
||||
class moveable {
|
||||
public:
|
||||
bool state;
|
||||
int value;
|
||||
|
||||
my_exception( char const* what, ctx::execution_context && ctx_) :
|
||||
std::runtime_error( what),
|
||||
ctx( std::forward< ctx::execution_context >( ctx_) ) {
|
||||
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;
|
||||
|
||||
void operator()() {
|
||||
value1 = value;
|
||||
}
|
||||
};
|
||||
|
||||
ctx::execution_context fn1( int i, ctx::execution_context ctx, void * ignored) {
|
||||
struct my_exception : public std::runtime_error {
|
||||
ctx::execution_context< void > ctx;
|
||||
|
||||
my_exception( char const* what, ctx::execution_context< void > && ctx_) :
|
||||
std::runtime_error( what),
|
||||
ctx( std::forward< ctx::execution_context< void > >( ctx_) ) {
|
||||
}
|
||||
};
|
||||
|
||||
ctx::execution_context< void > fn1( int i, ctx::execution_context< void > ctx) {
|
||||
value1 = i;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context fn2( const char * what, ctx::execution_context ctx, void * ignored) {
|
||||
ctx::execution_context< void > fn2( const char * what, ctx::execution_context< void > ctx) {
|
||||
try {
|
||||
throw std::runtime_error( what);
|
||||
} catch ( std::runtime_error const& e) {
|
||||
@@ -65,30 +108,30 @@ ctx::execution_context fn2( const char * what, ctx::execution_context ctx, void
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context fn3( double d, ctx::execution_context ctx, void * ignored) {
|
||||
ctx::execution_context< void > fn3( double d, ctx::execution_context< void > ctx) {
|
||||
d += 3.45;
|
||||
value3 = d;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context fn5( ctx::execution_context ctx, void * ignored) {
|
||||
ctx::execution_context< void > fn5( ctx::execution_context< void > ctx) {
|
||||
value1 = 3;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context fn4( ctx::execution_context ctx, void * ignored) {
|
||||
ctx::execution_context ctx1( fn5);
|
||||
ctx::execution_context< void > fn4( ctx::execution_context< void > ctx) {
|
||||
ctx::execution_context< void > ctx1( fn5);
|
||||
ctx1();
|
||||
value3 = 3.14;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context fn6( ctx::execution_context ctx, void * ignored) {
|
||||
ctx::execution_context< void > fn6( ctx::execution_context< void > ctx) {
|
||||
try {
|
||||
value1 = 3;
|
||||
std::tie( ctx, ignored) = ctx();
|
||||
ctx = ctx();
|
||||
value1 = 7;
|
||||
std::tie( ctx, ignored) = ctx( ignored);
|
||||
ctx = ctx();
|
||||
} catch ( my_exception & e) {
|
||||
value2 = e.what();
|
||||
ctx = std::move( e.ctx);
|
||||
@@ -96,18 +139,55 @@ ctx::execution_context fn6( ctx::execution_context ctx, void * ignored) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context fn7( ctx::execution_context ctx, void * ignored) {
|
||||
ctx::execution_context< void > fn7( ctx::execution_context< void > ctx) {
|
||||
Y y;
|
||||
std::tie( ctx, ignored) = ctx();
|
||||
return ctx();
|
||||
}
|
||||
|
||||
ctx::execution_context< int > fn8( ctx::execution_context< int > ctx, int i) {
|
||||
value1 = i;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context< int > fn9( ctx::execution_context< int > ctx, int i) {
|
||||
std::tie( ctx, i) = ctx( i);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context< int & > fn10( ctx::execution_context< int & > ctx, int & i) {
|
||||
std::tie( ctx, i) = ctx( i);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context< moveable > fn11( ctx::execution_context< moveable > ctx, moveable m) {
|
||||
std::tie( ctx, m) = ctx( std::move( m) );
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context< int, std::string > fn12( ctx::execution_context< int, std::string > ctx, int i, std::string str) {
|
||||
std::tie( ctx, i, str) = ctx( i, str);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context< int, moveable > fn13( ctx::execution_context< int, moveable > ctx, int i, moveable m) {
|
||||
std::tie( ctx, i, m) = ctx( i, std::move( m) );
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ctx::execution_context< variant_t > fn14( ctx::execution_context< variant_t > ctx, variant_t data) {
|
||||
int i = boost::get< int >( data);
|
||||
data = boost::lexical_cast< std::string >( i);
|
||||
std::tie( ctx, data) = ctx( data);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
void test_move() {
|
||||
value1 = 0;
|
||||
ctx::execution_context ctx;
|
||||
ctx::execution_context< void > ctx;
|
||||
BOOST_CHECK( ! ctx);
|
||||
ctx::execution_context ctx1( fn1, 1);
|
||||
ctx::execution_context ctx2( fn1, 3);
|
||||
ctx::execution_context< void > ctx1( fn1, 1);
|
||||
ctx::execution_context< void > ctx2( fn1, 3);
|
||||
BOOST_CHECK( ctx1);
|
||||
BOOST_CHECK( ctx2);
|
||||
ctx1 = std::move( ctx2);
|
||||
@@ -121,21 +201,21 @@ void test_move() {
|
||||
void test_memfn() {
|
||||
value1 = 0;
|
||||
X x;
|
||||
ctx::execution_context ctx( & X::foo, x, 7);
|
||||
ctx::execution_context< void > ctx( & X::foo, x, 7);
|
||||
ctx();
|
||||
BOOST_CHECK_EQUAL( 7, value1);
|
||||
}
|
||||
|
||||
void test_exception() {
|
||||
const char * what = "hello world";
|
||||
ctx::execution_context ctx( fn2, what);
|
||||
ctx::execution_context< void > ctx( fn2, what);
|
||||
ctx();
|
||||
BOOST_CHECK_EQUAL( std::string( what), value2);
|
||||
}
|
||||
|
||||
void test_fp() {
|
||||
double d = 7.13;
|
||||
ctx::execution_context ctx( fn3, d);
|
||||
ctx::execution_context< void > ctx( fn3, d);
|
||||
ctx();
|
||||
BOOST_CHECK_EQUAL( 10.58, value3);
|
||||
}
|
||||
@@ -143,7 +223,7 @@ void test_fp() {
|
||||
void test_stacked() {
|
||||
value1 = 0;
|
||||
value3 = 0.;
|
||||
ctx::execution_context ctx( fn4);
|
||||
ctx::execution_context< void > ctx( fn4);
|
||||
ctx();
|
||||
BOOST_CHECK_EQUAL( 3, value1);
|
||||
BOOST_CHECK_EQUAL( 3.14, value3);
|
||||
@@ -155,7 +235,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::execution_context ctx( std::allocator_arg, ctx::preallocated( sp, size, sctx), alloc, fn1, 7);
|
||||
ctx::execution_context< void > ctx( std::allocator_arg, ctx::preallocated( sp, size, sctx), alloc, fn1, 7);
|
||||
ctx();
|
||||
BOOST_CHECK_EQUAL( 7, value1);
|
||||
}
|
||||
@@ -163,36 +243,31 @@ void test_prealloc() {
|
||||
void test_ontop() {
|
||||
value1 = 0;
|
||||
value2 = "";
|
||||
void * ignored;
|
||||
ctx::execution_context ctx( fn6);
|
||||
std::tie( ctx, ignored) = ctx();
|
||||
ctx::execution_context< void > ctx( fn6);
|
||||
ctx = ctx();
|
||||
BOOST_CHECK_EQUAL( 3, value1);
|
||||
BOOST_CHECK( value2.empty() );
|
||||
std::string str("abc");
|
||||
int i = 3;
|
||||
std::tie( ctx, ignored) = ctx( & i, ctx::exec_ontop_arg,
|
||||
[str](ctx::execution_context ctx, void * data){
|
||||
value2 = str;
|
||||
return std::make_tuple( std::move( ctx), data);
|
||||
} );
|
||||
ctx = ctx( ctx::exec_ontop_arg,
|
||||
[str](ctx::execution_context< void > ctx){
|
||||
value2 = str;
|
||||
return ctx;
|
||||
} );
|
||||
BOOST_CHECK_EQUAL( 7, value1);
|
||||
BOOST_CHECK_EQUAL( str, value2);
|
||||
BOOST_CHECK_EQUAL( ignored, & i);
|
||||
BOOST_CHECK_EQUAL( i, *( int*) ignored);
|
||||
}
|
||||
|
||||
void test_ontop_exception() {
|
||||
value1 = 0;
|
||||
value2 = "";
|
||||
void * ignored;
|
||||
ctx::execution_context ctx( fn6);
|
||||
std::tie( ctx, ignored) = ctx();
|
||||
ctx::execution_context< void > ctx( fn6);
|
||||
ctx = ctx();
|
||||
BOOST_CHECK_EQUAL( 3, value1);
|
||||
const char * what = "hello world";
|
||||
ctx( ctx::exec_ontop_arg,
|
||||
[what](ctx::execution_context ctx, void * data){
|
||||
[what](ctx::execution_context< void > ctx){
|
||||
throw my_exception( what, std::move( ctx) );
|
||||
return std::make_tuple( std::move( ctx), data);
|
||||
return ctx;
|
||||
});
|
||||
BOOST_CHECK_EQUAL( 3, value1);
|
||||
BOOST_CHECK_EQUAL( std::string( what), value2);
|
||||
@@ -201,15 +276,90 @@ void test_ontop_exception() {
|
||||
void test_termination() {
|
||||
value1 = 0;
|
||||
{
|
||||
void * ignored;
|
||||
ctx::execution_context ctx( fn7);
|
||||
ctx::execution_context< void > ctx( fn7);
|
||||
BOOST_CHECK_EQUAL( 0, value1);
|
||||
std::tie( ctx, ignored) = ctx();
|
||||
ctx = ctx();
|
||||
BOOST_CHECK_EQUAL( 3, value1);
|
||||
}
|
||||
BOOST_CHECK_EQUAL( 7, value1);
|
||||
}
|
||||
|
||||
void test_one_arg() {
|
||||
{
|
||||
value1 = 0;
|
||||
ctx::execution_context< int > ctx( fn8);
|
||||
ctx( 7);
|
||||
BOOST_CHECK_EQUAL( 7, value1);
|
||||
}
|
||||
{
|
||||
int i = 3, j = 0;
|
||||
ctx::execution_context< int > ctx( fn9);
|
||||
std::tie( ctx, j) = ctx( i);
|
||||
BOOST_CHECK_EQUAL( i, j);
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
int i = 3, j = 0;
|
||||
int & k = j;
|
||||
BOOST_CHECK( & i != & k);
|
||||
BOOST_CHECK( & j == & k);
|
||||
ctx::execution_context< int & > ctx( fn10);
|
||||
std::tie( ctx, k) = ctx( i);
|
||||
BOOST_CHECK( & i != & k);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
moveable m1( 7), m2;
|
||||
BOOST_CHECK( 7 == m1.value);
|
||||
BOOST_CHECK( m1.state);
|
||||
BOOST_CHECK( -1 == m2.value);
|
||||
BOOST_CHECK( ! m2.state);
|
||||
ctx::execution_context< moveable > ctx( fn11);
|
||||
std::tie( ctx, m2) = ctx( std::move( m1) );
|
||||
BOOST_CHECK( -1 == m1.value);
|
||||
BOOST_CHECK( ! m1.state);
|
||||
BOOST_CHECK( 7 == m2.value);
|
||||
BOOST_CHECK( m2.state);
|
||||
}
|
||||
}
|
||||
|
||||
void test_two_args() {
|
||||
{
|
||||
int i1 = 3, i2 = 0;
|
||||
std::string str1("abc"), str2;
|
||||
ctx::execution_context< int, std::string > ctx( fn12);
|
||||
std::tie( ctx, i2, str2) = ctx( i1, str1);
|
||||
BOOST_CHECK_EQUAL( i1, i2);
|
||||
BOOST_CHECK_EQUAL( str1, str2);
|
||||
}
|
||||
{
|
||||
int i1 = 3, i2 = 0;
|
||||
moveable m1( 7), m2;
|
||||
BOOST_CHECK( 7 == m1.value);
|
||||
BOOST_CHECK( m1.state);
|
||||
BOOST_CHECK( -1 == m2.value);
|
||||
BOOST_CHECK( ! m2.state);
|
||||
ctx::execution_context< int, moveable > ctx( fn13);
|
||||
std::tie( ctx, i2, m2) = ctx( i1, std::move( m1) );
|
||||
BOOST_CHECK_EQUAL( i1, i2);
|
||||
BOOST_CHECK( -1 == m1.value);
|
||||
BOOST_CHECK( ! m1.state);
|
||||
BOOST_CHECK( 7 == m2.value);
|
||||
BOOST_CHECK( m2.state);
|
||||
}
|
||||
}
|
||||
|
||||
void test_variant() {
|
||||
{
|
||||
int i = 7;
|
||||
variant_t data1 = i, data2;
|
||||
ctx::execution_context< variant_t > ctx( fn14);
|
||||
std::tie( ctx, data2) = ctx( data1);
|
||||
std::string str = boost::get< std::string >( data2);
|
||||
BOOST_CHECK_EQUAL( std::string("7"), str);
|
||||
}
|
||||
}
|
||||
|
||||
boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
|
||||
{
|
||||
boost::unit_test::test_suite * test =
|
||||
@@ -225,6 +375,9 @@ boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
|
||||
test->add( BOOST_TEST_CASE( & test_ontop) );
|
||||
test->add( BOOST_TEST_CASE( & test_ontop_exception) );
|
||||
test->add( BOOST_TEST_CASE( & test_termination) );
|
||||
test->add( BOOST_TEST_CASE( & test_one_arg) );
|
||||
test->add( BOOST_TEST_CASE( & test_two_args) );
|
||||
test->add( BOOST_TEST_CASE( & test_variant) );
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user