mirror of
https://github.com/boostorg/coroutine2.git
synced 2025-05-11 13:34:08 +00:00
Merge branch 'develop'
This commit is contained in:
commit
1f15040a55
@ -3,7 +3,7 @@
|
|||||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
# 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)
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
project coroutine/doc ;
|
project coroutine2/doc ;
|
||||||
|
|
||||||
import boostbook ;
|
import boostbook ;
|
||||||
import quickbook ;
|
import quickbook ;
|
||||||
|
@ -13,28 +13,35 @@ following table. Performance measurements were taken using `rdtsc` and
|
|||||||
platforms. In each case, cache warm-up was accounted for, and the one
|
platforms. In each case, cache warm-up was accounted for, and the one
|
||||||
running thread was pinned to a single CPU.
|
running thread was pinned to a single CPU.
|
||||||
|
|
||||||
[table Performance of asymmetric coroutines
|
[table Performance of asymmetric coroutines (using captured_context)
|
||||||
[
|
[
|
||||||
[Platform]
|
[Platform]
|
||||||
[switch]
|
[switch]
|
||||||
[construction (protected stack-allocator)]
|
[construction (protected stack-allocator)]
|
||||||
[construction (preallocated stack-allocator)]
|
|
||||||
[construction (standard stack-allocator)]
|
[construction (standard stack-allocator)]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[i386 (AMD Athlon 64 DualCore 4400+, Linux 32bit)]
|
[x86_64 (Intel Core2 Q6700, Linux 64bit)]
|
||||||
[49 ns / 50 cycles]
|
[7 ns / 20 cycles]
|
||||||
[51 \u00b5s / 51407 cycles]
|
[19 \u00b5s / cw6306445402 cycles]
|
||||||
[14 \u00b5s / 15231 cycles]
|
[10 \u00b5s / 29896 cycles]
|
||||||
[14 \u00b5s / 15216 cycles]
|
]
|
||||||
|
]
|
||||||
|
[/
|
||||||
|
[table Performance of asymmetric coroutines (using execution_context)
|
||||||
|
[
|
||||||
|
[Platform]
|
||||||
|
[switch]
|
||||||
|
[construction (protected stack-allocator)]
|
||||||
|
[construction (standard stack-allocator)]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[x86_64 (Intel Core2 Q6700, Linux 64bit)]
|
[x86_64 (Intel Core2 Q6700, Linux 64bit)]
|
||||||
[12 ns / 39 cycles]
|
[140 ns / 424 cycles]
|
||||||
[16 \u00b5s / 41802 cycles]
|
[14 \u00b5s / 32750 cycles]
|
||||||
[6 \u00b5s / 10350 cycles]
|
[8 \u00b5s / 15313 cycles]
|
||||||
[6 \u00b5s / 18817 cycles]
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
@ -89,77 +89,83 @@ void traverse(node::ptr_t n, boost::coroutines2::coroutine<std::string>::push_ty
|
|||||||
int main() {
|
int main() {
|
||||||
{
|
{
|
||||||
node::ptr_t left_d(create_left_tree_from("d"));
|
node::ptr_t left_d(create_left_tree_from("d"));
|
||||||
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
|
|
||||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
|
||||||
traverse(left_d,out);
|
|
||||||
});
|
|
||||||
std::cout << "left tree from d:\n";
|
|
||||||
std::copy(begin(left_d_reader),
|
|
||||||
end(left_d_reader),
|
|
||||||
std::ostream_iterator<std::string>(std::cout, " "));
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
node::ptr_t right_b(create_right_tree_from("b"));
|
node::ptr_t right_b(create_right_tree_from("b"));
|
||||||
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
|
|
||||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
|
||||||
traverse(right_b,out);
|
|
||||||
});
|
|
||||||
std::cout << "right tree from b:\n";
|
|
||||||
std::copy(begin(right_b_reader),
|
|
||||||
end(right_b_reader),
|
|
||||||
std::ostream_iterator<std::string>(std::cout, " "));
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
node::ptr_t right_x(create_right_tree_from("x"));
|
node::ptr_t right_x(create_right_tree_from("x"));
|
||||||
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
|
{
|
||||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
|
||||||
traverse(right_x,out);
|
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||||
});
|
traverse(left_d,out);
|
||||||
std::cout << "right tree from x:\n";
|
});
|
||||||
std::copy(begin(right_x_reader),
|
std::cout << "left tree from d:\n";
|
||||||
end(right_x_reader),
|
std::copy(begin(left_d_reader),
|
||||||
std::ostream_iterator<std::string>(std::cout, " "));
|
end(left_d_reader),
|
||||||
std::cout << std::endl;
|
std::ostream_iterator<std::string>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
|
||||||
|
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||||
|
traverse(right_b,out);
|
||||||
|
});
|
||||||
|
std::cout << "right tree from b:\n";
|
||||||
|
std::copy(begin(right_b_reader),
|
||||||
|
end(right_b_reader),
|
||||||
|
std::ostream_iterator<std::string>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
|
||||||
|
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||||
|
traverse(right_x,out);
|
||||||
|
});
|
||||||
|
std::cout << "right tree from x:\n";
|
||||||
|
std::copy(begin(right_x_reader),
|
||||||
|
end(right_x_reader),
|
||||||
|
std::ostream_iterator<std::string>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
node::ptr_t left_d(create_left_tree_from("d"));
|
node::ptr_t left_d(create_left_tree_from("d"));
|
||||||
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
|
|
||||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
|
||||||
traverse(left_d,out);
|
|
||||||
});
|
|
||||||
|
|
||||||
node::ptr_t right_b(create_right_tree_from("b"));
|
node::ptr_t right_b(create_right_tree_from("b"));
|
||||||
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
|
{
|
||||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
|
||||||
traverse(right_b,out);
|
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||||
});
|
traverse(left_d,out);
|
||||||
|
});
|
||||||
|
|
||||||
std::cout << "left tree from d == right tree from b? "
|
boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
|
||||||
<< std::boolalpha
|
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||||
<< std::equal(begin(left_d_reader),
|
traverse(right_b,out);
|
||||||
end(left_d_reader),
|
});
|
||||||
begin(right_b_reader))
|
|
||||||
<< std::endl;
|
std::cout << "left tree from d == right tree from b? "
|
||||||
|
<< std::boolalpha
|
||||||
|
<< std::equal(begin(left_d_reader),
|
||||||
|
end(left_d_reader),
|
||||||
|
begin(right_b_reader))
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
node::ptr_t left_d(create_left_tree_from("d"));
|
node::ptr_t left_d(create_left_tree_from("d"));
|
||||||
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
|
|
||||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
|
||||||
traverse(left_d,out);
|
|
||||||
});
|
|
||||||
|
|
||||||
node::ptr_t right_x(create_right_tree_from("x"));
|
node::ptr_t right_x(create_right_tree_from("x"));
|
||||||
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
|
{
|
||||||
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
|
||||||
traverse(right_x,out);
|
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||||
});
|
traverse(left_d,out);
|
||||||
|
});
|
||||||
|
|
||||||
std::cout << "left tree from d == right tree from x? "
|
boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
|
||||||
<< std::boolalpha
|
[&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
|
||||||
<< std::equal(begin(left_d_reader),
|
traverse(right_x,out);
|
||||||
end(left_d_reader),
|
});
|
||||||
begin(right_x_reader))
|
|
||||||
<< std::endl;
|
std::cout << "left tree from d == right tree from x? "
|
||||||
|
<< std::boolalpha
|
||||||
|
<< std::equal(begin(left_d_reader),
|
||||||
|
end(left_d_reader),
|
||||||
|
begin(right_x_reader))
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::cout << "Done" << std::endl;
|
std::cout << "Done" << std::endl;
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
@ -28,14 +28,25 @@ class push_coroutine;
|
|||||||
#include <boost/coroutine2/detail/pull_coroutine.hpp>
|
#include <boost/coroutine2/detail/pull_coroutine.hpp>
|
||||||
#include <boost/coroutine2/detail/push_coroutine.hpp>
|
#include <boost/coroutine2/detail/push_coroutine.hpp>
|
||||||
|
|
||||||
#include <boost/coroutine2/detail/pull_control_block.hpp>
|
#if ! defined(BOOST_USE_EXECUTION_CONTEXT)
|
||||||
#include <boost/coroutine2/detail/push_control_block.hpp>
|
#include <boost/coroutine2/detail/pull_control_block_cc.hpp>
|
||||||
|
#include <boost/coroutine2/detail/push_control_block_cc.hpp>
|
||||||
|
#else
|
||||||
|
#include <boost/coroutine2/detail/pull_control_block_ec.hpp>
|
||||||
|
#include <boost/coroutine2/detail/push_control_block_ec.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <boost/coroutine2/detail/pull_coroutine.ipp>
|
#include <boost/coroutine2/detail/pull_coroutine.ipp>
|
||||||
#include <boost/coroutine2/detail/push_coroutine.ipp>
|
#include <boost/coroutine2/detail/push_coroutine.ipp>
|
||||||
|
|
||||||
#include <boost/coroutine2/detail/pull_control_block.ipp>
|
#if ! defined(BOOST_USE_EXECUTION_CONTEXT)
|
||||||
#include <boost/coroutine2/detail/push_control_block.ipp>
|
#include <boost/coroutine2/detail/pull_control_block_cc.hpp>
|
||||||
|
#include <boost/coroutine2/detail/pull_control_block_cc.ipp>
|
||||||
|
#include <boost/coroutine2/detail/push_control_block_cc.ipp>
|
||||||
|
#else
|
||||||
|
#include <boost/coroutine2/detail/pull_control_block_ec.ipp>
|
||||||
|
#include <boost/coroutine2/detail/push_control_block_ec.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef BOOST_HAS_ABI_HEADERS
|
#ifdef BOOST_HAS_ABI_HEADERS
|
||||||
# include BOOST_ABI_SUFFIX
|
# include BOOST_ABI_SUFFIX
|
||||||
|
@ -31,7 +31,7 @@ template< typename ControlBlock, typename StackAllocator, typename Fn >
|
|||||||
ControlBlock * create_control_block( StackAllocator salloc, Fn && fn) {
|
ControlBlock * create_control_block( StackAllocator salloc, Fn && fn) {
|
||||||
auto sctx = salloc.allocate();
|
auto sctx = salloc.allocate();
|
||||||
// reserve space for control structure
|
// reserve space for control structure
|
||||||
#if defined(BOOST_NO_CXX14_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
|
#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
|
||||||
void * sp = static_cast< char * >( sctx.sp) - sizeof( ControlBlock);
|
void * sp = static_cast< char * >( sctx.sp) - sizeof( ControlBlock);
|
||||||
const std::size_t size = sctx.size - sizeof( ControlBlock);
|
const std::size_t size = sctx.size - sizeof( ControlBlock);
|
||||||
#else
|
#else
|
||||||
|
@ -24,6 +24,12 @@ namespace detail {
|
|||||||
|
|
||||||
struct forced_unwind {};
|
struct forced_unwind {};
|
||||||
|
|
||||||
|
inline
|
||||||
|
void * unwind_coroutine( void * data) {
|
||||||
|
throw forced_unwind{};
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
}}}
|
}}}
|
||||||
|
|
||||||
#ifdef BOOST_HAS_ABI_HEADERS
|
#ifdef BOOST_HAS_ABI_HEADERS
|
||||||
|
114
include/boost/coroutine2/detail/pull_control_block_cc.hpp
Normal file
114
include/boost/coroutine2/detail/pull_control_block_cc.hpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
|
||||||
|
// 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_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP
|
||||||
|
#define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/context/captured_context.hpp>
|
||||||
|
|
||||||
|
#include <boost/coroutine2/detail/state.hpp>
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_ABI_HEADERS
|
||||||
|
# include BOOST_ABI_PREFIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace coroutines2 {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
struct pull_coroutine< T >::control_block {
|
||||||
|
boost::context::captured_context ctx;
|
||||||
|
typename push_coroutine< T >::control_block * other;
|
||||||
|
state_t state;
|
||||||
|
std::exception_ptr except;
|
||||||
|
bool bvalid;
|
||||||
|
typename std::aligned_storage< sizeof( T), alignof( T) >::type storage;
|
||||||
|
|
||||||
|
static void destroy( control_block * cb) noexcept;
|
||||||
|
|
||||||
|
template< typename StackAllocator, typename Fn >
|
||||||
|
control_block( context::preallocated, StackAllocator, Fn &&);
|
||||||
|
|
||||||
|
control_block( typename push_coroutine< T >::control_block *, boost::context::captured_context &) noexcept;
|
||||||
|
|
||||||
|
~control_block();
|
||||||
|
|
||||||
|
control_block( control_block &) = delete;
|
||||||
|
control_block & operator=( control_block &) = delete;
|
||||||
|
|
||||||
|
void deallocate() noexcept;
|
||||||
|
|
||||||
|
void resume();
|
||||||
|
|
||||||
|
void set( T *);
|
||||||
|
|
||||||
|
T & get() noexcept;
|
||||||
|
|
||||||
|
bool valid() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
struct pull_coroutine< T & >::control_block {
|
||||||
|
boost::context::captured_context ctx;
|
||||||
|
typename push_coroutine< T & >::control_block * other;
|
||||||
|
state_t state;
|
||||||
|
std::exception_ptr except;
|
||||||
|
T * t;
|
||||||
|
|
||||||
|
static void destroy( control_block * cb) noexcept;
|
||||||
|
|
||||||
|
template< typename StackAllocator, typename Fn >
|
||||||
|
control_block( context::preallocated, StackAllocator, Fn &&);
|
||||||
|
|
||||||
|
control_block( typename push_coroutine< T & >::control_block *, boost::context::captured_context &) noexcept;
|
||||||
|
|
||||||
|
control_block( control_block &) = delete;
|
||||||
|
control_block & operator=( control_block &) = delete;
|
||||||
|
|
||||||
|
void deallocate() noexcept;
|
||||||
|
|
||||||
|
void resume();
|
||||||
|
|
||||||
|
T & get() noexcept;
|
||||||
|
|
||||||
|
bool valid() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pull_coroutine< void >::control_block {
|
||||||
|
boost::context::captured_context ctx;
|
||||||
|
push_coroutine< void >::control_block * other;
|
||||||
|
state_t state;
|
||||||
|
std::exception_ptr except;
|
||||||
|
|
||||||
|
static void destroy( control_block * cb) noexcept;
|
||||||
|
|
||||||
|
template< typename StackAllocator, typename Fn >
|
||||||
|
control_block( context::preallocated, StackAllocator, Fn &&);
|
||||||
|
|
||||||
|
control_block( push_coroutine< void >::control_block *, boost::context::captured_context &) noexcept;
|
||||||
|
|
||||||
|
control_block( control_block &) = delete;
|
||||||
|
control_block & operator=( control_block &) = delete;
|
||||||
|
|
||||||
|
void deallocate() noexcept;
|
||||||
|
|
||||||
|
void resume();
|
||||||
|
|
||||||
|
bool valid() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}}
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_ABI_HEADERS
|
||||||
|
# include BOOST_ABI_SUFFIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_HPP
|
416
include/boost/coroutine2/detail/pull_control_block_cc.ipp
Normal file
416
include/boost/coroutine2/detail/pull_control_block_cc.ipp
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
|
||||||
|
// 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_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
|
||||||
|
#define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <exception>
|
||||||
|
#include <memory>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/context/captured_context.hpp>
|
||||||
|
|
||||||
|
#include <boost/coroutine2/detail/config.hpp>
|
||||||
|
#include <boost/coroutine2/detail/forced_unwind.hpp>
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_ABI_HEADERS
|
||||||
|
# include BOOST_ABI_PREFIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace coroutines2 {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
// pull_coroutine< T >
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
|
||||||
|
boost::context::captured_context ctx = std::move( cb->ctx);
|
||||||
|
// destroy control structure
|
||||||
|
cb->~control_block();
|
||||||
|
// destroy coroutine's stack
|
||||||
|
ctx();
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
template< typename StackAllocator, typename Fn >
|
||||||
|
pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||||
|
Fn && fn) :
|
||||||
|
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||||
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
|
std::move(
|
||||||
|
std::bind(
|
||||||
|
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void *) mutable {
|
||||||
|
// create synthesized push_coroutine< T >
|
||||||
|
typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
||||||
|
push_coroutine< T > synthesized{ & synthesized_cb };
|
||||||
|
other = & synthesized_cb;
|
||||||
|
try {
|
||||||
|
auto fn = std::move( fn_);
|
||||||
|
// call coroutine-fn with synthesized push_coroutine as argument
|
||||||
|
fn( synthesized);
|
||||||
|
} catch ( boost::context::detail::forced_unwind const&) {
|
||||||
|
throw;
|
||||||
|
} catch (...) {
|
||||||
|
// store other exceptions in exception-pointer
|
||||||
|
except = std::current_exception();
|
||||||
|
}
|
||||||
|
// set termination flags
|
||||||
|
state |= state_t::complete;
|
||||||
|
// jump back to ctx
|
||||||
|
auto result = other->ctx();
|
||||||
|
other->ctx = std::move( std::get< 0 >( result) );
|
||||||
|
return std::move( other->ctx);
|
||||||
|
},
|
||||||
|
std::forward< Fn >( fn),
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::placeholders::_2))},
|
||||||
|
#else
|
||||||
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
|
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void *) mutable {
|
||||||
|
// create synthesized push_coroutine< T >
|
||||||
|
typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
||||||
|
push_coroutine< T > synthesized{ & synthesized_cb };
|
||||||
|
other = & synthesized_cb;
|
||||||
|
try {
|
||||||
|
auto fn = std::move( fn_);
|
||||||
|
// call coroutine-fn with synthesized push_coroutine as argument
|
||||||
|
fn( synthesized);
|
||||||
|
} catch ( boost::context::detail::forced_unwind const&) {
|
||||||
|
throw;
|
||||||
|
} catch (...) {
|
||||||
|
// store other exceptions in exception-pointer
|
||||||
|
except = std::current_exception();
|
||||||
|
}
|
||||||
|
// set termination flags
|
||||||
|
state |= state_t::complete;
|
||||||
|
// jump back to ctx
|
||||||
|
auto result = other->ctx();
|
||||||
|
other->ctx = std::move( std::get< 0 >( result) );
|
||||||
|
return std::move( other->ctx);
|
||||||
|
}},
|
||||||
|
#endif
|
||||||
|
other{ nullptr },
|
||||||
|
state{ state_t::unwind },
|
||||||
|
except{},
|
||||||
|
bvalid{ false },
|
||||||
|
storage{} {
|
||||||
|
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
|
||||||
|
auto result = ctx();
|
||||||
|
ctx = std::move( std::get< 0 >( result) );
|
||||||
|
set( static_cast< T * >( std::get< 1 >( result) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
|
||||||
|
boost::context::captured_context & ctx_) noexcept :
|
||||||
|
ctx{ std::move( ctx_) },
|
||||||
|
other{ cb },
|
||||||
|
state{ state_t::none },
|
||||||
|
except{},
|
||||||
|
bvalid{ false },
|
||||||
|
storage{} {
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
pull_coroutine< T >::control_block::~control_block() {
|
||||||
|
// destroy data if set
|
||||||
|
if ( bvalid) {
|
||||||
|
reinterpret_cast< T * >( std::addressof( storage) )->~T();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
pull_coroutine< T >::control_block::deallocate() noexcept {
|
||||||
|
if ( state_t::none != ( state & state_t::unwind) ) {
|
||||||
|
destroy( this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
pull_coroutine< T >::control_block::resume() {
|
||||||
|
auto result = ctx();
|
||||||
|
ctx = std::move( std::get< 0 >( result) );
|
||||||
|
set( static_cast< T * >( std::get< 1 >( result) ) );
|
||||||
|
if ( except) {
|
||||||
|
std::rethrow_exception( except);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
pull_coroutine< T >::control_block::set( T * t) {
|
||||||
|
// destroy data if set
|
||||||
|
if ( bvalid) {
|
||||||
|
reinterpret_cast< T * >( std::addressof( storage) )->~T();
|
||||||
|
}
|
||||||
|
if ( nullptr != t) {
|
||||||
|
::new ( static_cast< void * >( std::addressof( storage) ) ) T( std::move( * t) );
|
||||||
|
bvalid = true;
|
||||||
|
} else {
|
||||||
|
bvalid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T &
|
||||||
|
pull_coroutine< T >::control_block::get() noexcept {
|
||||||
|
return * reinterpret_cast< T * >( std::addressof( storage) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
bool
|
||||||
|
pull_coroutine< T >::control_block::valid() const noexcept {
|
||||||
|
return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// pull_coroutine< T & >
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
|
||||||
|
boost::context::captured_context ctx = std::move( cb->ctx);
|
||||||
|
// destroy control structure
|
||||||
|
cb->~control_block();
|
||||||
|
// destroy coroutine's stack
|
||||||
|
ctx();
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
template< typename StackAllocator, typename Fn >
|
||||||
|
pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||||
|
Fn && fn) :
|
||||||
|
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||||
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
|
std::move(
|
||||||
|
std::bind(
|
||||||
|
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void *) mutable {
|
||||||
|
// create synthesized push_coroutine< T >
|
||||||
|
typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
||||||
|
push_coroutine< T & > synthesized{ & synthesized_cb };
|
||||||
|
other = & synthesized_cb;
|
||||||
|
try {
|
||||||
|
auto fn = std::move( fn_);
|
||||||
|
// call coroutine-fn with synthesized push_coroutine as argument
|
||||||
|
fn( synthesized);
|
||||||
|
} catch ( boost::context::detail::forced_unwind const&) {
|
||||||
|
throw;
|
||||||
|
} catch (...) {
|
||||||
|
// store other exceptions in exception-pointer
|
||||||
|
except = std::current_exception();
|
||||||
|
}
|
||||||
|
// set termination flags
|
||||||
|
state |= state_t::complete;
|
||||||
|
// jump back to ctx
|
||||||
|
auto result = other->ctx();
|
||||||
|
other->ctx = std::move( std::get< 0 >( result) );
|
||||||
|
return std::move( other->ctx);
|
||||||
|
},
|
||||||
|
std::forward< Fn >( fn),
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::placeholders::_2))},
|
||||||
|
#else
|
||||||
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
|
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void *) mutable {
|
||||||
|
// create synthesized push_coroutine< T >
|
||||||
|
typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
||||||
|
push_coroutine< T & > synthesized{ & synthesized_cb };
|
||||||
|
other = & synthesized_cb;
|
||||||
|
try {
|
||||||
|
auto fn = std::move( fn_);
|
||||||
|
// call coroutine-fn with synthesized push_coroutine as argument
|
||||||
|
fn( synthesized);
|
||||||
|
} catch ( boost::context::detail::forced_unwind const&) {
|
||||||
|
throw;
|
||||||
|
} catch (...) {
|
||||||
|
// store other exceptions in exception-pointer
|
||||||
|
except = std::current_exception();
|
||||||
|
}
|
||||||
|
// set termination flags
|
||||||
|
state |= state_t::complete;
|
||||||
|
// jump back to ctx
|
||||||
|
auto result = other->ctx();
|
||||||
|
other->ctx = std::move( std::get< 0 >( result) );
|
||||||
|
return std::move( other->ctx);
|
||||||
|
}},
|
||||||
|
#endif
|
||||||
|
other{ nullptr },
|
||||||
|
state{ state_t::unwind },
|
||||||
|
except{},
|
||||||
|
t{ nullptr } {
|
||||||
|
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
|
||||||
|
auto result = ctx();
|
||||||
|
ctx = std::move( std::get< 0 >( result) );
|
||||||
|
t = static_cast< T * >( std::get< 1 >( result) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
|
||||||
|
boost::context::captured_context & ctx_) noexcept :
|
||||||
|
ctx{ std::move( ctx_) },
|
||||||
|
other{ cb },
|
||||||
|
state{ state_t::none },
|
||||||
|
except{},
|
||||||
|
t{ nullptr } {
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
pull_coroutine< T & >::control_block::deallocate() noexcept {
|
||||||
|
if ( state_t::none != ( state & state_t::unwind) ) {
|
||||||
|
destroy( this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
pull_coroutine< T & >::control_block::resume() {
|
||||||
|
auto result = ctx();
|
||||||
|
ctx = std::move( std::get< 0 >( result) );
|
||||||
|
t = static_cast< T * >( std::get< 1 >( result) );
|
||||||
|
if ( except) {
|
||||||
|
std::rethrow_exception( except);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T &
|
||||||
|
pull_coroutine< T & >::control_block::get() noexcept {
|
||||||
|
return * static_cast< T * >( t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
bool
|
||||||
|
pull_coroutine< T & >::control_block::valid() const noexcept {
|
||||||
|
return nullptr != other && state_t::none == ( state & state_t::complete) && nullptr != t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// pull_coroutine< void >
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
|
||||||
|
boost::context::captured_context ctx = std::move( cb->ctx);
|
||||||
|
// destroy control structure
|
||||||
|
cb->~control_block();
|
||||||
|
// destroy coroutine's stack
|
||||||
|
ctx();
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename StackAllocator, typename Fn >
|
||||||
|
pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||||
|
Fn && fn) :
|
||||||
|
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||||
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
|
std::move(
|
||||||
|
std::bind(
|
||||||
|
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void *) mutable {
|
||||||
|
// create synthesized push_coroutine< T >
|
||||||
|
typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
||||||
|
push_coroutine< void > synthesized{ & synthesized_cb };
|
||||||
|
other = & synthesized_cb;
|
||||||
|
try {
|
||||||
|
auto fn = std::move( fn_);
|
||||||
|
// call coroutine-fn with synthesized push_coroutine as argument
|
||||||
|
fn( synthesized);
|
||||||
|
} catch ( boost::context::detail::forced_unwind const&) {
|
||||||
|
throw;
|
||||||
|
} catch (...) {
|
||||||
|
// store other exceptions in exception-pointer
|
||||||
|
except = std::current_exception();
|
||||||
|
}
|
||||||
|
// set termination flags
|
||||||
|
state |= state_t::complete;
|
||||||
|
// jump back to ctx
|
||||||
|
auto result = other->ctx();
|
||||||
|
other->ctx = std::move( std::get< 0 >( result) );
|
||||||
|
return std::move( other->ctx);
|
||||||
|
},
|
||||||
|
std::forward< Fn >( fn),
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::placeholders::_2))},
|
||||||
|
#else
|
||||||
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
|
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void *) mutable {
|
||||||
|
// create synthesized push_coroutine< T >
|
||||||
|
typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
||||||
|
push_coroutine< void > synthesized{ & synthesized_cb };
|
||||||
|
other = & synthesized_cb;
|
||||||
|
try {
|
||||||
|
auto fn = std::move( fn_);
|
||||||
|
// call coroutine-fn with synthesized push_coroutine as argument
|
||||||
|
fn( synthesized);
|
||||||
|
} catch ( boost::context::detail::forced_unwind const&) {
|
||||||
|
throw;
|
||||||
|
} catch (...) {
|
||||||
|
// store other exceptions in exception-pointer
|
||||||
|
except = std::current_exception();
|
||||||
|
}
|
||||||
|
// set termination flags
|
||||||
|
state |= state_t::complete;
|
||||||
|
// jump back to ctx
|
||||||
|
auto result = other->ctx();
|
||||||
|
other->ctx = std::move( std::get< 0 >( result) );
|
||||||
|
return std::move( other->ctx);
|
||||||
|
}},
|
||||||
|
#endif
|
||||||
|
other{ nullptr },
|
||||||
|
state{ state_t::unwind },
|
||||||
|
except{} {
|
||||||
|
// enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
|
||||||
|
auto result = ctx();
|
||||||
|
ctx = std::move( std::get< 0 >( result) );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
|
||||||
|
boost::context::captured_context & ctx_) noexcept :
|
||||||
|
ctx{ std::move( ctx_) },
|
||||||
|
other{ cb },
|
||||||
|
state{ state_t::none },
|
||||||
|
except{} {
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
pull_coroutine< void >::control_block::deallocate() noexcept {
|
||||||
|
if ( state_t::none != ( state & state_t::unwind) ) {
|
||||||
|
destroy( this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
pull_coroutine< void >::control_block::resume() {
|
||||||
|
auto result = ctx();
|
||||||
|
ctx = std::move( std::get< 0 >( result) );
|
||||||
|
if ( except) {
|
||||||
|
std::rethrow_exception( except);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
bool
|
||||||
|
pull_coroutine< void >::control_block::valid() const noexcept {
|
||||||
|
return nullptr != other && state_t::none == ( state & state_t::complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
}}}
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_ABI_HEADERS
|
||||||
|
# include BOOST_ABI_SUFFIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
|
@ -26,13 +26,15 @@ namespace detail {
|
|||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
struct pull_coroutine< T >::control_block {
|
struct pull_coroutine< T >::control_block {
|
||||||
typename push_coroutine< T >::control_block * other;
|
|
||||||
boost::context::execution_context ctx;
|
boost::context::execution_context ctx;
|
||||||
|
typename push_coroutine< T >::control_block * other;
|
||||||
state_t state;
|
state_t state;
|
||||||
std::exception_ptr except;
|
std::exception_ptr except;
|
||||||
bool bvalid;
|
bool bvalid;
|
||||||
typename std::aligned_storage< sizeof( T), alignof( T) >::type storage;
|
typename std::aligned_storage< sizeof( T), alignof( T) >::type storage;
|
||||||
|
|
||||||
|
static void destroy( control_block * cb) noexcept;
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
template< typename StackAllocator, typename Fn >
|
||||||
control_block( context::preallocated, StackAllocator, Fn &&);
|
control_block( context::preallocated, StackAllocator, Fn &&);
|
||||||
|
|
||||||
@ -43,6 +45,8 @@ struct pull_coroutine< T >::control_block {
|
|||||||
control_block( control_block &) = delete;
|
control_block( control_block &) = delete;
|
||||||
control_block & operator=( control_block &) = delete;
|
control_block & operator=( control_block &) = delete;
|
||||||
|
|
||||||
|
void deallocate() noexcept;
|
||||||
|
|
||||||
void resume();
|
void resume();
|
||||||
|
|
||||||
void set( T *);
|
void set( T *);
|
||||||
@ -54,12 +58,14 @@ struct pull_coroutine< T >::control_block {
|
|||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
struct pull_coroutine< T & >::control_block {
|
struct pull_coroutine< T & >::control_block {
|
||||||
typename push_coroutine< T & >::control_block * other;
|
|
||||||
boost::context::execution_context ctx;
|
boost::context::execution_context ctx;
|
||||||
|
typename push_coroutine< T & >::control_block * other;
|
||||||
state_t state;
|
state_t state;
|
||||||
std::exception_ptr except;
|
std::exception_ptr except;
|
||||||
T * t;
|
T * t;
|
||||||
|
|
||||||
|
static void destroy( control_block * cb) noexcept;
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
template< typename StackAllocator, typename Fn >
|
||||||
control_block( context::preallocated, StackAllocator, Fn &&);
|
control_block( context::preallocated, StackAllocator, Fn &&);
|
||||||
|
|
||||||
@ -70,6 +76,8 @@ struct pull_coroutine< T & >::control_block {
|
|||||||
control_block( control_block &) = delete;
|
control_block( control_block &) = delete;
|
||||||
control_block & operator=( control_block &) = delete;
|
control_block & operator=( control_block &) = delete;
|
||||||
|
|
||||||
|
void deallocate() noexcept;
|
||||||
|
|
||||||
void resume();
|
void resume();
|
||||||
|
|
||||||
T & get() noexcept;
|
T & get() noexcept;
|
||||||
@ -78,11 +86,13 @@ struct pull_coroutine< T & >::control_block {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct pull_coroutine< void >::control_block {
|
struct pull_coroutine< void >::control_block {
|
||||||
push_coroutine< void >::control_block * other;
|
|
||||||
boost::context::execution_context ctx;
|
boost::context::execution_context ctx;
|
||||||
|
push_coroutine< void >::control_block * other;
|
||||||
state_t state;
|
state_t state;
|
||||||
std::exception_ptr except;
|
std::exception_ptr except;
|
||||||
|
|
||||||
|
static void destroy( control_block * cb) noexcept;
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
template< typename StackAllocator, typename Fn >
|
||||||
control_block( context::preallocated, StackAllocator, Fn &&);
|
control_block( context::preallocated, StackAllocator, Fn &&);
|
||||||
|
|
||||||
@ -93,6 +103,8 @@ struct pull_coroutine< void >::control_block {
|
|||||||
control_block( control_block &) = delete;
|
control_block( control_block &) = delete;
|
||||||
control_block & operator=( control_block &) = delete;
|
control_block & operator=( control_block &) = delete;
|
||||||
|
|
||||||
|
void deallocate() noexcept;
|
||||||
|
|
||||||
void resume();
|
void resume();
|
||||||
|
|
||||||
bool valid() const noexcept;
|
bool valid() const noexcept;
|
@ -31,11 +31,18 @@ namespace detail {
|
|||||||
|
|
||||||
// pull_coroutine< T >
|
// pull_coroutine< T >
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
|
||||||
|
boost::context::execution_context ctx = cb->ctx;
|
||||||
|
// destroy control structure
|
||||||
|
cb->~control_block();
|
||||||
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
template< typename StackAllocator, typename Fn >
|
template< typename StackAllocator, typename Fn >
|
||||||
pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||||
Fn && fn) :
|
Fn && fn) :
|
||||||
other{ nullptr },
|
|
||||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
std::move(
|
std::move(
|
||||||
@ -88,6 +95,7 @@ pull_coroutine< T >::control_block::control_block( context::preallocated palloc,
|
|||||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
||||||
}},
|
}},
|
||||||
#endif
|
#endif
|
||||||
|
other{ nullptr },
|
||||||
state{ state_t::unwind },
|
state{ state_t::unwind },
|
||||||
except{},
|
except{},
|
||||||
bvalid{ false },
|
bvalid{ false },
|
||||||
@ -99,8 +107,8 @@ pull_coroutine< T >::control_block::control_block( context::preallocated palloc,
|
|||||||
template< typename T >
|
template< typename T >
|
||||||
pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
|
pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
|
||||||
boost::context::execution_context const& ctx_) noexcept :
|
boost::context::execution_context const& ctx_) noexcept :
|
||||||
other{ cb },
|
|
||||||
ctx{ ctx_ },
|
ctx{ ctx_ },
|
||||||
|
other{ cb },
|
||||||
state{ state_t::none },
|
state{ state_t::none },
|
||||||
except{},
|
except{},
|
||||||
bvalid{ false },
|
bvalid{ false },
|
||||||
@ -108,12 +116,11 @@ pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
pull_coroutine< T >::control_block::~control_block() noexcept {
|
pull_coroutine< T >::control_block::~control_block() {
|
||||||
if ( state_t::none == ( state & state_t::complete) &&
|
if ( state_t::none == ( state & state_t::complete) &&
|
||||||
state_t::none != ( state & state_t::unwind) ) {
|
state_t::none != ( state & state_t::unwind) ) {
|
||||||
// set early-exit flag
|
// unwind coroutine stack
|
||||||
state |= state_t::early_exit;
|
ctx( context::exec_ontop_arg, unwind_coroutine);
|
||||||
ctx();
|
|
||||||
}
|
}
|
||||||
// destroy data if it set
|
// destroy data if it set
|
||||||
if ( bvalid) {
|
if ( bvalid) {
|
||||||
@ -121,6 +128,14 @@ pull_coroutine< T >::control_block::~control_block() noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
pull_coroutine< T >::control_block::deallocate() noexcept {
|
||||||
|
if ( state_t::none != ( state & state_t::unwind) ) {
|
||||||
|
destroy( this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
void
|
void
|
||||||
pull_coroutine< T >::control_block::resume() {
|
pull_coroutine< T >::control_block::resume() {
|
||||||
@ -129,10 +144,6 @@ pull_coroutine< T >::control_block::resume() {
|
|||||||
if ( except) {
|
if ( except) {
|
||||||
std::rethrow_exception( except);
|
std::rethrow_exception( except);
|
||||||
}
|
}
|
||||||
// test early-exit-flag
|
|
||||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
|
||||||
throw forced_unwind();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
@ -165,11 +176,18 @@ pull_coroutine< T >::control_block::valid() const noexcept {
|
|||||||
|
|
||||||
// pull_coroutine< T & >
|
// pull_coroutine< T & >
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
|
||||||
|
boost::context::execution_context ctx = cb->ctx;
|
||||||
|
// destroy control structure
|
||||||
|
cb->~control_block();
|
||||||
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
template< typename StackAllocator, typename Fn >
|
template< typename StackAllocator, typename Fn >
|
||||||
pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||||
Fn && fn) :
|
Fn && fn) :
|
||||||
other{ nullptr },
|
|
||||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
std::move(
|
std::move(
|
||||||
@ -222,6 +240,7 @@ pull_coroutine< T & >::control_block::control_block( context::preallocated pallo
|
|||||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
||||||
}},
|
}},
|
||||||
#endif
|
#endif
|
||||||
|
other{ nullptr },
|
||||||
state{ state_t::unwind },
|
state{ state_t::unwind },
|
||||||
except{},
|
except{},
|
||||||
t{ nullptr } {
|
t{ nullptr } {
|
||||||
@ -232,20 +251,27 @@ pull_coroutine< T & >::control_block::control_block( context::preallocated pallo
|
|||||||
template< typename T >
|
template< typename T >
|
||||||
pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
|
pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
|
||||||
boost::context::execution_context const& ctx_) noexcept :
|
boost::context::execution_context const& ctx_) noexcept :
|
||||||
other{ cb },
|
|
||||||
ctx{ ctx_ },
|
ctx{ ctx_ },
|
||||||
|
other{ cb },
|
||||||
state{ state_t::none },
|
state{ state_t::none },
|
||||||
except{},
|
except{},
|
||||||
t( nullptr) {
|
t( nullptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
pull_coroutine< T & >::control_block::~control_block() noexcept {
|
pull_coroutine< T & >::control_block::~control_block() {
|
||||||
if ( state_t::none == ( state & state_t::complete) &&
|
if ( state_t::none == ( state & state_t::complete) &&
|
||||||
state_t::none != ( state & state_t::unwind) ) {
|
state_t::none != ( state & state_t::unwind) ) {
|
||||||
// set early-exit flag
|
// unwind coroutine stack
|
||||||
state |= state_t::early_exit;
|
ctx( context::exec_ontop_arg, unwind_coroutine);
|
||||||
ctx();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
pull_coroutine< T & >::control_block::deallocate() noexcept {
|
||||||
|
if ( state_t::none != ( state & state_t::unwind) ) {
|
||||||
|
destroy( this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,10 +283,6 @@ pull_coroutine< T & >::control_block::resume() {
|
|||||||
if ( except) {
|
if ( except) {
|
||||||
std::rethrow_exception( except);
|
std::rethrow_exception( except);
|
||||||
}
|
}
|
||||||
// test early-exit-flag
|
|
||||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
|
||||||
throw forced_unwind();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
@ -278,10 +300,17 @@ pull_coroutine< T & >::control_block::valid() const noexcept {
|
|||||||
|
|
||||||
// pull_coroutine< void >
|
// pull_coroutine< void >
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
|
||||||
|
boost::context::execution_context ctx = cb->ctx;
|
||||||
|
// destroy control structure
|
||||||
|
cb->~control_block();
|
||||||
|
}
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
template< typename StackAllocator, typename Fn >
|
||||||
pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||||
Fn && fn) :
|
Fn && fn) :
|
||||||
other{ nullptr },
|
|
||||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
std::move(
|
std::move(
|
||||||
@ -334,6 +363,7 @@ pull_coroutine< void >::control_block::control_block( context::preallocated pall
|
|||||||
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
|
||||||
}},
|
}},
|
||||||
#endif
|
#endif
|
||||||
|
other{ nullptr },
|
||||||
state{ state_t::unwind },
|
state{ state_t::unwind },
|
||||||
except{} {
|
except{} {
|
||||||
// enter coroutine-fn in order to have first value available after ctor returns
|
// enter coroutine-fn in order to have first value available after ctor returns
|
||||||
@ -343,19 +373,26 @@ pull_coroutine< void >::control_block::control_block( context::preallocated pall
|
|||||||
inline
|
inline
|
||||||
pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
|
pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
|
||||||
boost::context::execution_context const& ctx_) noexcept :
|
boost::context::execution_context const& ctx_) noexcept :
|
||||||
other{ cb },
|
|
||||||
ctx{ ctx_ },
|
ctx{ ctx_ },
|
||||||
|
other{ cb },
|
||||||
state{ state_t::none },
|
state{ state_t::none },
|
||||||
except{} {
|
except{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
pull_coroutine< void >::control_block::~control_block() noexcept {
|
pull_coroutine< void >::control_block::~control_block() {
|
||||||
if ( state_t::none == ( state & state_t::complete) &&
|
if ( state_t::none == ( state & state_t::complete) &&
|
||||||
state_t::none != ( state & state_t::unwind) ) {
|
state_t::none != ( state & state_t::unwind) ) {
|
||||||
// set early-exit flag
|
// unwind coroutine stack
|
||||||
state |= state_t::early_exit;
|
ctx( context::exec_ontop_arg, unwind_coroutine);
|
||||||
ctx();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
pull_coroutine< void >::control_block::deallocate() noexcept {
|
||||||
|
if ( state_t::none != ( state & state_t::unwind) ) {
|
||||||
|
destroy( this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,10 +404,6 @@ pull_coroutine< void >::control_block::resume() {
|
|||||||
if ( except) {
|
if ( except) {
|
||||||
std::rethrow_exception( except);
|
std::rethrow_exception( except);
|
||||||
}
|
}
|
||||||
// test early-exit-flag
|
|
||||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
|
||||||
throw forced_unwind();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
@ -53,7 +53,7 @@ template< typename StackAllocator, typename Fn >
|
|||||||
pull_coroutine< T >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
pull_coroutine< T >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
||||||
cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
|
cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
|
||||||
if ( ! cb_->valid() ) {
|
if ( ! cb_->valid() ) {
|
||||||
cb_->~control_block();
|
cb_->deallocate();
|
||||||
cb_ = nullptr;
|
cb_ = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ pull_coroutine< T >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
|||||||
template< typename T >
|
template< typename T >
|
||||||
pull_coroutine< T >::~pull_coroutine() noexcept {
|
pull_coroutine< T >::~pull_coroutine() noexcept {
|
||||||
if ( nullptr != cb_) {
|
if ( nullptr != cb_) {
|
||||||
cb_->~control_block();
|
cb_->deallocate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ template< typename StackAllocator, typename Fn >
|
|||||||
pull_coroutine< T & >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
pull_coroutine< T & >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
||||||
cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
|
cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
|
||||||
if ( ! cb_->valid() ) {
|
if ( ! cb_->valid() ) {
|
||||||
cb_->~control_block();
|
cb_->deallocate();
|
||||||
cb_ = nullptr;
|
cb_ = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,7 +130,7 @@ pull_coroutine< T & >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
|||||||
template< typename T >
|
template< typename T >
|
||||||
pull_coroutine< T & >::~pull_coroutine() noexcept {
|
pull_coroutine< T & >::~pull_coroutine() noexcept {
|
||||||
if ( nullptr != cb_) {
|
if ( nullptr != cb_) {
|
||||||
cb_->~control_block();
|
cb_->deallocate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +183,7 @@ template< typename StackAllocator, typename Fn >
|
|||||||
pull_coroutine< void >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
pull_coroutine< void >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
||||||
cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
|
cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
|
||||||
if ( ! cb_->valid() ) {
|
if ( ! cb_->valid() ) {
|
||||||
cb_->~control_block();
|
cb_->deallocate();
|
||||||
cb_ = nullptr;
|
cb_ = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ pull_coroutine< void >::pull_coroutine( StackAllocator salloc, Fn && fn) :
|
|||||||
inline
|
inline
|
||||||
pull_coroutine< void >::~pull_coroutine() noexcept {
|
pull_coroutine< void >::~pull_coroutine() noexcept {
|
||||||
if ( nullptr != cb_) {
|
if ( nullptr != cb_) {
|
||||||
cb_->~control_block();
|
cb_->deallocate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
104
include/boost/coroutine2/detail/push_control_block_cc.hpp
Normal file
104
include/boost/coroutine2/detail/push_control_block_cc.hpp
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
|
||||||
|
// 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_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP
|
||||||
|
#define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/context/captured_context.hpp>
|
||||||
|
|
||||||
|
#include <boost/coroutine2/detail/state.hpp>
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_ABI_HEADERS
|
||||||
|
# include BOOST_ABI_PREFIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace coroutines2 {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
struct push_coroutine< T >::control_block {
|
||||||
|
boost::context::captured_context ctx;
|
||||||
|
typename pull_coroutine< T >::control_block * other;
|
||||||
|
state_t state;
|
||||||
|
std::exception_ptr except;
|
||||||
|
|
||||||
|
static void destroy( control_block * cb) noexcept;
|
||||||
|
|
||||||
|
template< typename StackAllocator, typename Fn >
|
||||||
|
control_block( context::preallocated, StackAllocator, Fn &&);
|
||||||
|
|
||||||
|
control_block( typename pull_coroutine< T >::control_block *, boost::context::captured_context &) noexcept;
|
||||||
|
|
||||||
|
control_block( control_block &) = delete;
|
||||||
|
control_block & operator=( control_block &) = delete;
|
||||||
|
|
||||||
|
void deallocate() noexcept;
|
||||||
|
|
||||||
|
void resume( T const&);
|
||||||
|
|
||||||
|
void resume( T &&);
|
||||||
|
|
||||||
|
bool valid() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
struct push_coroutine< T & >::control_block {
|
||||||
|
boost::context::captured_context ctx;
|
||||||
|
typename pull_coroutine< T & >::control_block * other;
|
||||||
|
state_t state;
|
||||||
|
std::exception_ptr except;
|
||||||
|
|
||||||
|
static void destroy( control_block * cb) noexcept;
|
||||||
|
|
||||||
|
template< typename StackAllocator, typename Fn >
|
||||||
|
control_block( context::preallocated, StackAllocator, Fn &&);
|
||||||
|
|
||||||
|
control_block( typename pull_coroutine< T & >::control_block *, boost::context::captured_context &) noexcept;
|
||||||
|
|
||||||
|
control_block( control_block &) = delete;
|
||||||
|
control_block & operator=( control_block &) = delete;
|
||||||
|
|
||||||
|
void deallocate() noexcept;
|
||||||
|
|
||||||
|
void resume( T &);
|
||||||
|
|
||||||
|
bool valid() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct push_coroutine< void >::control_block {
|
||||||
|
boost::context::captured_context ctx;
|
||||||
|
pull_coroutine< void >::control_block * other;
|
||||||
|
state_t state;
|
||||||
|
std::exception_ptr except;
|
||||||
|
|
||||||
|
static void destroy( control_block * cb) noexcept;
|
||||||
|
|
||||||
|
template< typename StackAllocator, typename Fn >
|
||||||
|
control_block( context::preallocated, StackAllocator, Fn &&);
|
||||||
|
|
||||||
|
control_block( pull_coroutine< void >::control_block *, boost::context::captured_context &) noexcept;
|
||||||
|
|
||||||
|
control_block( control_block &) = delete;
|
||||||
|
control_block & operator=( control_block &) = delete;
|
||||||
|
|
||||||
|
void deallocate() noexcept;
|
||||||
|
|
||||||
|
void resume();
|
||||||
|
|
||||||
|
bool valid() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}}
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_ABI_HEADERS
|
||||||
|
# include BOOST_ABI_SUFFIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_HPP
|
381
include/boost/coroutine2/detail/push_control_block_cc.ipp
Normal file
381
include/boost/coroutine2/detail/push_control_block_cc.ipp
Normal file
@ -0,0 +1,381 @@
|
|||||||
|
|
||||||
|
// 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_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP
|
||||||
|
#define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <exception>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/context/captured_context.hpp>
|
||||||
|
|
||||||
|
#include <boost/coroutine2/detail/config.hpp>
|
||||||
|
#include <boost/coroutine2/detail/forced_unwind.hpp>
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_ABI_HEADERS
|
||||||
|
# include BOOST_ABI_PREFIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace coroutines2 {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
// push_coroutine< T >
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
push_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
|
||||||
|
boost::context::captured_context ctx = std::move( cb->ctx);
|
||||||
|
// destroy control structure
|
||||||
|
cb->~control_block();
|
||||||
|
// destroy coroutine's stack
|
||||||
|
ctx();
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
template< typename StackAllocator, typename Fn >
|
||||||
|
push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||||
|
Fn && fn) :
|
||||||
|
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||||
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
|
std::move(
|
||||||
|
std::bind(
|
||||||
|
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void * data) mutable {
|
||||||
|
// create synthesized pull_coroutine< T >
|
||||||
|
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
||||||
|
pull_coroutine< T > synthesized{ & synthesized_cb };
|
||||||
|
other = & synthesized_cb;
|
||||||
|
// set transferred value
|
||||||
|
synthesized_cb.set( static_cast< T * >( data) );
|
||||||
|
try {
|
||||||
|
auto fn = std::move( fn_);
|
||||||
|
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||||
|
fn( synthesized);
|
||||||
|
} catch ( boost::context::detail::forced_unwind const&) {
|
||||||
|
throw;
|
||||||
|
} catch (...) {
|
||||||
|
// store other exceptions in exception-pointer
|
||||||
|
except = std::current_exception();
|
||||||
|
}
|
||||||
|
// set termination flags
|
||||||
|
state |= state_t::complete;
|
||||||
|
// jump back to ctx
|
||||||
|
auto result = other->ctx();
|
||||||
|
other->ctx = std::move( std::get< 0 >( result) );
|
||||||
|
return std::move( other->ctx);
|
||||||
|
},
|
||||||
|
std::forward< Fn >( fn),
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::placeholders::_2))},
|
||||||
|
#else
|
||||||
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
|
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void * data) mutable {
|
||||||
|
// create synthesized pull_coroutine< T >
|
||||||
|
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
||||||
|
pull_coroutine< T > synthesized{ & synthesized_cb };
|
||||||
|
other = & synthesized_cb;
|
||||||
|
// set transferred value
|
||||||
|
synthesized_cb.set( static_cast< T * >( data) );
|
||||||
|
try {
|
||||||
|
auto fn = std::move( fn_);
|
||||||
|
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||||
|
fn( synthesized);
|
||||||
|
} catch ( boost::context::detail::forced_unwind const&) {
|
||||||
|
throw;
|
||||||
|
} catch (...) {
|
||||||
|
// store other exceptions in exception-pointer
|
||||||
|
except = std::current_exception();
|
||||||
|
}
|
||||||
|
// set termination flags
|
||||||
|
state |= state_t::complete;
|
||||||
|
// jump back to ctx
|
||||||
|
auto result = other->ctx();
|
||||||
|
other->ctx = std::move( std::get< 0 >( result) );
|
||||||
|
return std::move( other->ctx);
|
||||||
|
}},
|
||||||
|
#endif
|
||||||
|
other{ nullptr },
|
||||||
|
state{ state_t::unwind },
|
||||||
|
except{} {
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
|
||||||
|
boost::context::captured_context & ctx_) noexcept :
|
||||||
|
ctx{ std::move( ctx_) },
|
||||||
|
other{ cb },
|
||||||
|
state{ state_t::none },
|
||||||
|
except{} {
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
push_coroutine< T >::control_block::deallocate() noexcept {
|
||||||
|
if ( state_t::none != ( state & state_t::unwind) ) {
|
||||||
|
destroy( this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
push_coroutine< T >::control_block::resume( T const& data) {
|
||||||
|
// pass an pointer to other context
|
||||||
|
auto result = ctx( const_cast< T * >( & data) );
|
||||||
|
ctx = std::move( std::get< 0 >( result) );
|
||||||
|
if ( except) {
|
||||||
|
std::rethrow_exception( except);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
push_coroutine< T >::control_block::resume( T && data) {
|
||||||
|
// pass an pointer to other context
|
||||||
|
auto result = ctx( std::addressof( data) );
|
||||||
|
ctx = std::move( std::get< 0 >( result) );
|
||||||
|
if ( except) {
|
||||||
|
std::rethrow_exception( except);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
bool
|
||||||
|
push_coroutine< T >::control_block::valid() const noexcept {
|
||||||
|
return state_t::none == ( state & state_t::complete );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// push_coroutine< T & >
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
|
||||||
|
boost::context::captured_context ctx = std::move( cb->ctx);
|
||||||
|
// destroy control structure
|
||||||
|
cb->~control_block();
|
||||||
|
// destroy coroutine's stack
|
||||||
|
ctx();
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
template< typename StackAllocator, typename Fn >
|
||||||
|
push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||||
|
Fn && fn) :
|
||||||
|
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||||
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
|
std::move(
|
||||||
|
std::bind(
|
||||||
|
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void * data) mutable {
|
||||||
|
// create synthesized pull_coroutine< T >
|
||||||
|
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
||||||
|
pull_coroutine< T & > synthesized{ & synthesized_cb };
|
||||||
|
other = & synthesized_cb;
|
||||||
|
// set transferred value
|
||||||
|
synthesized_cb.t = static_cast< T * >( data);
|
||||||
|
try {
|
||||||
|
auto fn = std::move( fn_);
|
||||||
|
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||||
|
fn( synthesized);
|
||||||
|
} catch ( boost::context::detail::forced_unwind const&) {
|
||||||
|
throw;
|
||||||
|
} catch (...) {
|
||||||
|
// store other exceptions in exception-pointer
|
||||||
|
except = std::current_exception();
|
||||||
|
}
|
||||||
|
// set termination flags
|
||||||
|
state |= state_t::complete;
|
||||||
|
// jump back to ctx
|
||||||
|
auto result = other->ctx();
|
||||||
|
other->ctx = std::move( std::get< 0 >( result) );
|
||||||
|
return std::move( other->ctx);
|
||||||
|
},
|
||||||
|
std::forward< Fn >( fn),
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::placeholders::_2))},
|
||||||
|
#else
|
||||||
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
|
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void * data) mutable {
|
||||||
|
// create synthesized pull_coroutine< T >
|
||||||
|
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
||||||
|
pull_coroutine< T & > synthesized{ & synthesized_cb };
|
||||||
|
other = & synthesized_cb;
|
||||||
|
// set transferred value
|
||||||
|
synthesized_cb.t = static_cast< T * >( data);
|
||||||
|
try {
|
||||||
|
auto fn = std::move( fn_);
|
||||||
|
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||||
|
fn( synthesized);
|
||||||
|
} catch ( boost::context::detail::forced_unwind const&) {
|
||||||
|
throw;
|
||||||
|
} catch (...) {
|
||||||
|
// store other exceptions in exception-pointer
|
||||||
|
except = std::current_exception();
|
||||||
|
}
|
||||||
|
// set termination flags
|
||||||
|
state |= state_t::complete;
|
||||||
|
// jump back to ctx
|
||||||
|
auto result = other->ctx();
|
||||||
|
other->ctx = std::move( std::get< 0 >( result) );
|
||||||
|
return std::move( other->ctx);
|
||||||
|
}},
|
||||||
|
#endif
|
||||||
|
other{ nullptr },
|
||||||
|
state{ state_t::unwind },
|
||||||
|
except{} {
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
|
||||||
|
boost::context::captured_context & ctx_) noexcept :
|
||||||
|
ctx{ std::move( ctx_) },
|
||||||
|
other{ cb },
|
||||||
|
state{ state_t::none },
|
||||||
|
except{} {
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
push_coroutine< T & >::control_block::deallocate() noexcept {
|
||||||
|
if ( state_t::none != ( state & state_t::unwind) ) {
|
||||||
|
destroy( this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
push_coroutine< T & >::control_block::resume( T & t) {
|
||||||
|
// pass an pointer to other context
|
||||||
|
auto result = ctx( const_cast< typename std::remove_const< T >::type * >( std::addressof( t) ) );
|
||||||
|
ctx = std::move( std::get< 0 >( result) );
|
||||||
|
if ( except) {
|
||||||
|
std::rethrow_exception( except);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
bool
|
||||||
|
push_coroutine< T & >::control_block::valid() const noexcept {
|
||||||
|
return state_t::none == ( state & state_t::complete );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// push_coroutine< void >
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
push_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
|
||||||
|
boost::context::captured_context ctx = std::move( cb->ctx);
|
||||||
|
// destroy control structure
|
||||||
|
cb->~control_block();
|
||||||
|
// destroy coroutine's stack
|
||||||
|
ctx();
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename StackAllocator, typename Fn >
|
||||||
|
push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) :
|
||||||
|
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||||
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
|
std::move(
|
||||||
|
std::bind(
|
||||||
|
[this]( typename std::decay< Fn >::type & fn_, boost::context::captured_context ctx, void *) mutable {
|
||||||
|
// create synthesized pull_coroutine< T >
|
||||||
|
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
||||||
|
pull_coroutine< void > synthesized{ & synthesized_cb };
|
||||||
|
other = & synthesized_cb;
|
||||||
|
try {
|
||||||
|
auto fn = std::move( fn_);
|
||||||
|
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||||
|
fn( synthesized);
|
||||||
|
} catch ( boost::context::detail::forced_unwind const&) {
|
||||||
|
throw;
|
||||||
|
} catch (...) {
|
||||||
|
// store other exceptions in exception-pointer
|
||||||
|
except = std::current_exception();
|
||||||
|
}
|
||||||
|
// set termination flags
|
||||||
|
state |= state_t::complete;
|
||||||
|
// jump back to ctx
|
||||||
|
auto result = other->ctx();
|
||||||
|
other->ctx = std::move( std::get< 0 >( result) );
|
||||||
|
return std::move( other->ctx);
|
||||||
|
},
|
||||||
|
std::forward< Fn >( fn),
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::placeholders::_2))},
|
||||||
|
#else
|
||||||
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
|
[this,fn_=std::forward< Fn >( fn)]( boost::context::captured_context ctx, void *) mutable {
|
||||||
|
// create synthesized pull_coroutine< T >
|
||||||
|
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx};
|
||||||
|
pull_coroutine< void > synthesized{ & synthesized_cb };
|
||||||
|
other = & synthesized_cb;
|
||||||
|
try {
|
||||||
|
auto fn = std::move( fn_);
|
||||||
|
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||||
|
fn( synthesized);
|
||||||
|
} catch ( boost::context::detail::forced_unwind const&) {
|
||||||
|
throw;
|
||||||
|
} catch (...) {
|
||||||
|
// store other exceptions in exception-pointer
|
||||||
|
except = std::current_exception();
|
||||||
|
}
|
||||||
|
// set termination flags
|
||||||
|
state |= state_t::complete;
|
||||||
|
// jump back to ctx
|
||||||
|
auto result = other->ctx();
|
||||||
|
other->ctx = std::move( std::get< 0 >( result) );
|
||||||
|
return std::move( other->ctx);
|
||||||
|
}},
|
||||||
|
#endif
|
||||||
|
other{ nullptr },
|
||||||
|
state{ state_t::unwind },
|
||||||
|
except{} {
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
|
||||||
|
boost::context::captured_context & ctx_) noexcept :
|
||||||
|
ctx{ std::move( ctx_) },
|
||||||
|
other{ cb },
|
||||||
|
state{ state_t::none },
|
||||||
|
except{} {
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
push_coroutine< void >::control_block::deallocate() noexcept {
|
||||||
|
if ( state_t::none != ( state & state_t::unwind) ) {
|
||||||
|
destroy( this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
push_coroutine< void >::control_block::resume() {
|
||||||
|
auto result = ctx();
|
||||||
|
ctx = std::move( std::get< 0 >( result) );
|
||||||
|
if ( except) {
|
||||||
|
std::rethrow_exception( except);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
bool
|
||||||
|
push_coroutine< void >::control_block::valid() const noexcept {
|
||||||
|
return state_t::none == ( state & state_t::complete );
|
||||||
|
}
|
||||||
|
|
||||||
|
}}}
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_ABI_HEADERS
|
||||||
|
# include BOOST_ABI_SUFFIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP
|
@ -25,11 +25,13 @@ namespace detail {
|
|||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
struct push_coroutine< T >::control_block {
|
struct push_coroutine< T >::control_block {
|
||||||
typename pull_coroutine< T >::control_block * other;
|
|
||||||
boost::context::execution_context ctx;
|
boost::context::execution_context ctx;
|
||||||
|
typename pull_coroutine< T >::control_block * other;
|
||||||
state_t state;
|
state_t state;
|
||||||
std::exception_ptr except;
|
std::exception_ptr except;
|
||||||
|
|
||||||
|
static void destroy( control_block * cb) noexcept;
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
template< typename StackAllocator, typename Fn >
|
||||||
control_block( context::preallocated, StackAllocator, Fn &&);
|
control_block( context::preallocated, StackAllocator, Fn &&);
|
||||||
|
|
||||||
@ -40,6 +42,8 @@ struct push_coroutine< T >::control_block {
|
|||||||
control_block( control_block &) = delete;
|
control_block( control_block &) = delete;
|
||||||
control_block & operator=( control_block &) = delete;
|
control_block & operator=( control_block &) = delete;
|
||||||
|
|
||||||
|
void deallocate() noexcept;
|
||||||
|
|
||||||
void resume( T const&);
|
void resume( T const&);
|
||||||
|
|
||||||
void resume( T &&);
|
void resume( T &&);
|
||||||
@ -49,11 +53,13 @@ struct push_coroutine< T >::control_block {
|
|||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
struct push_coroutine< T & >::control_block {
|
struct push_coroutine< T & >::control_block {
|
||||||
typename pull_coroutine< T & >::control_block * other;
|
|
||||||
boost::context::execution_context ctx;
|
boost::context::execution_context ctx;
|
||||||
|
typename pull_coroutine< T & >::control_block * other;
|
||||||
state_t state;
|
state_t state;
|
||||||
std::exception_ptr except;
|
std::exception_ptr except;
|
||||||
|
|
||||||
|
static void destroy( control_block * cb) noexcept;
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
template< typename StackAllocator, typename Fn >
|
||||||
control_block( context::preallocated, StackAllocator, Fn &&);
|
control_block( context::preallocated, StackAllocator, Fn &&);
|
||||||
|
|
||||||
@ -64,17 +70,21 @@ struct push_coroutine< T & >::control_block {
|
|||||||
control_block( control_block &) = delete;
|
control_block( control_block &) = delete;
|
||||||
control_block & operator=( control_block &) = delete;
|
control_block & operator=( control_block &) = delete;
|
||||||
|
|
||||||
|
void deallocate() noexcept;
|
||||||
|
|
||||||
void resume( T &);
|
void resume( T &);
|
||||||
|
|
||||||
bool valid() const noexcept;
|
bool valid() const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct push_coroutine< void >::control_block {
|
struct push_coroutine< void >::control_block {
|
||||||
pull_coroutine< void >::control_block * other;
|
|
||||||
boost::context::execution_context ctx;
|
boost::context::execution_context ctx;
|
||||||
|
pull_coroutine< void >::control_block * other;
|
||||||
state_t state;
|
state_t state;
|
||||||
std::exception_ptr except;
|
std::exception_ptr except;
|
||||||
|
|
||||||
|
static void destroy( control_block * cb) noexcept;
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
template< typename StackAllocator, typename Fn >
|
||||||
control_block( context::preallocated, StackAllocator, Fn &&);
|
control_block( context::preallocated, StackAllocator, Fn &&);
|
||||||
|
|
||||||
@ -85,6 +95,8 @@ struct push_coroutine< void >::control_block {
|
|||||||
control_block( control_block &) = delete;
|
control_block( control_block &) = delete;
|
||||||
control_block & operator=( control_block &) = delete;
|
control_block & operator=( control_block &) = delete;
|
||||||
|
|
||||||
|
void deallocate() noexcept;
|
||||||
|
|
||||||
void resume();
|
void resume();
|
||||||
|
|
||||||
bool valid() const noexcept;
|
bool valid() const noexcept;
|
@ -32,11 +32,18 @@ namespace detail {
|
|||||||
|
|
||||||
// push_coroutine< T >
|
// push_coroutine< T >
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
push_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
|
||||||
|
boost::context::execution_context ctx = cb->ctx;
|
||||||
|
// destroy control structure
|
||||||
|
cb->~control_block();
|
||||||
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
template< typename StackAllocator, typename Fn >
|
template< typename StackAllocator, typename Fn >
|
||||||
push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||||
Fn && fn) :
|
Fn && fn) :
|
||||||
other{ nullptr },
|
|
||||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
std::move(
|
std::move(
|
||||||
@ -46,11 +53,11 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc,
|
|||||||
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
||||||
pull_coroutine< T > synthesized{ & synthesized_cb };
|
pull_coroutine< T > synthesized{ & synthesized_cb };
|
||||||
other = & synthesized_cb;
|
other = & synthesized_cb;
|
||||||
// jump back to ctor
|
|
||||||
T * t = static_cast< T * >( ctx() );
|
|
||||||
// set transferred value
|
|
||||||
synthesized_cb.set( t);
|
|
||||||
try {
|
try {
|
||||||
|
// jump back to ctor
|
||||||
|
T * t = static_cast< T * >( ctx() );
|
||||||
|
// set transferred value
|
||||||
|
synthesized_cb.set( t);
|
||||||
auto fn = std::move( fn_);
|
auto fn = std::move( fn_);
|
||||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||||
fn( synthesized);
|
fn( synthesized);
|
||||||
@ -76,11 +83,11 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc,
|
|||||||
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
|
||||||
pull_coroutine< T > synthesized{ & synthesized_cb };
|
pull_coroutine< T > synthesized{ & synthesized_cb };
|
||||||
other = & synthesized_cb;
|
other = & synthesized_cb;
|
||||||
// jump back to ctor
|
|
||||||
T * t = static_cast< T * >( ctx() );
|
|
||||||
// set transferred value
|
|
||||||
synthesized_cb.set( t);
|
|
||||||
try {
|
try {
|
||||||
|
// jump back to ctor
|
||||||
|
T * t = static_cast< T * >( ctx() );
|
||||||
|
// set transferred value
|
||||||
|
synthesized_cb.set( t);
|
||||||
auto fn = std::move( fn_);
|
auto fn = std::move( fn_);
|
||||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||||
fn( synthesized);
|
fn( synthesized);
|
||||||
@ -97,6 +104,7 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc,
|
|||||||
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
||||||
}},
|
}},
|
||||||
#endif
|
#endif
|
||||||
|
other{ nullptr },
|
||||||
state{ state_t::unwind },
|
state{ state_t::unwind },
|
||||||
except{} {
|
except{} {
|
||||||
// enter coroutine-fn in order to get other set
|
// enter coroutine-fn in order to get other set
|
||||||
@ -106,19 +114,26 @@ push_coroutine< T >::control_block::control_block( context::preallocated palloc,
|
|||||||
template< typename T >
|
template< typename T >
|
||||||
push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
|
push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
|
||||||
boost::context::execution_context const& ctx_) noexcept :
|
boost::context::execution_context const& ctx_) noexcept :
|
||||||
other{ cb },
|
|
||||||
ctx{ ctx_ },
|
ctx{ ctx_ },
|
||||||
|
other{ cb },
|
||||||
state{ state_t::none },
|
state{ state_t::none },
|
||||||
except{} {
|
except{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
push_coroutine< T >::control_block::~control_block() noexcept {
|
push_coroutine< T >::control_block::~control_block() {
|
||||||
if ( state_t::none == ( state & state_t::complete) &&
|
if ( state_t::none == ( state & state_t::complete) &&
|
||||||
state_t::none != ( state & state_t::unwind) ) {
|
state_t::none != ( state & state_t::unwind) ) {
|
||||||
// set early-exit flag
|
// unwind coroutine stack
|
||||||
state |= state_t::early_exit;
|
ctx( context::exec_ontop_arg, unwind_coroutine);
|
||||||
ctx();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
push_coroutine< T >::control_block::deallocate() noexcept {
|
||||||
|
if ( state_t::none != ( state & state_t::unwind) ) {
|
||||||
|
destroy( this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,10 +146,6 @@ push_coroutine< T >::control_block::resume( T const& t) {
|
|||||||
if ( except) {
|
if ( except) {
|
||||||
std::rethrow_exception( except);
|
std::rethrow_exception( except);
|
||||||
}
|
}
|
||||||
// test early-exit-flag
|
|
||||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
|
||||||
throw forced_unwind();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
@ -146,10 +157,6 @@ push_coroutine< T >::control_block::resume( T && t) {
|
|||||||
if ( except) {
|
if ( except) {
|
||||||
std::rethrow_exception( except);
|
std::rethrow_exception( except);
|
||||||
}
|
}
|
||||||
// test early-exit-flag
|
|
||||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
|
||||||
throw forced_unwind();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
@ -161,11 +168,18 @@ push_coroutine< T >::control_block::valid() const noexcept {
|
|||||||
|
|
||||||
// push_coroutine< T & >
|
// push_coroutine< T & >
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
|
||||||
|
boost::context::execution_context ctx = cb->ctx;
|
||||||
|
// destroy control structure
|
||||||
|
cb->~control_block();
|
||||||
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
template< typename StackAllocator, typename Fn >
|
template< typename StackAllocator, typename Fn >
|
||||||
push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
|
||||||
Fn && fn) :
|
Fn && fn) :
|
||||||
other{ nullptr },
|
|
||||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
std::move(
|
std::move(
|
||||||
@ -175,11 +189,11 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo
|
|||||||
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
||||||
pull_coroutine< T & > synthesized{ & synthesized_cb };
|
pull_coroutine< T & > synthesized{ & synthesized_cb };
|
||||||
other = & synthesized_cb;
|
other = & synthesized_cb;
|
||||||
// jump back to ctor
|
|
||||||
T * t = static_cast< T * >( ctx() );
|
|
||||||
// set transferred value
|
|
||||||
synthesized_cb.t = t;
|
|
||||||
try {
|
try {
|
||||||
|
// jump back to ctor
|
||||||
|
T * t = static_cast< T * >( ctx() );
|
||||||
|
// set transferred value
|
||||||
|
synthesized_cb.t = t;
|
||||||
auto fn = std::move( fn_);
|
auto fn = std::move( fn_);
|
||||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||||
fn( synthesized);
|
fn( synthesized);
|
||||||
@ -205,11 +219,11 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo
|
|||||||
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
|
||||||
pull_coroutine< T & > synthesized{ & synthesized_cb };
|
pull_coroutine< T & > synthesized{ & synthesized_cb };
|
||||||
other = & synthesized_cb;
|
other = & synthesized_cb;
|
||||||
// jump back to ctor
|
|
||||||
T * t = static_cast< T * >( ctx() );
|
|
||||||
// set transferred value
|
|
||||||
synthesized_cb.t = t;
|
|
||||||
try {
|
try {
|
||||||
|
// jump back to ctor
|
||||||
|
T * t = static_cast< T * >( ctx() );
|
||||||
|
// set transferred value
|
||||||
|
synthesized_cb.t = t;
|
||||||
auto fn = std::move( fn_);
|
auto fn = std::move( fn_);
|
||||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||||
fn( synthesized);
|
fn( synthesized);
|
||||||
@ -226,6 +240,7 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo
|
|||||||
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
||||||
}},
|
}},
|
||||||
#endif
|
#endif
|
||||||
|
other{ nullptr },
|
||||||
state{ state_t::unwind },
|
state{ state_t::unwind },
|
||||||
except{} {
|
except{} {
|
||||||
// enter coroutine-fn in order to get other set
|
// enter coroutine-fn in order to get other set
|
||||||
@ -235,19 +250,26 @@ push_coroutine< T & >::control_block::control_block( context::preallocated pallo
|
|||||||
template< typename T >
|
template< typename T >
|
||||||
push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
|
push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
|
||||||
boost::context::execution_context const& ctx_) noexcept :
|
boost::context::execution_context const& ctx_) noexcept :
|
||||||
other{ cb },
|
|
||||||
ctx{ ctx_ },
|
ctx{ ctx_ },
|
||||||
|
other{ cb },
|
||||||
state{ state_t::none },
|
state{ state_t::none },
|
||||||
except{} {
|
except{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
push_coroutine< T & >::control_block::~control_block() noexcept {
|
push_coroutine< T & >::control_block::~control_block() {
|
||||||
if ( state_t::none == ( state & state_t::complete) &&
|
if ( state_t::none == ( state & state_t::complete) &&
|
||||||
state_t::none != ( state & state_t::unwind) ) {
|
state_t::none != ( state & state_t::unwind) ) {
|
||||||
// set early-exit flag
|
// unwind coroutine stack
|
||||||
state |= state_t::early_exit;
|
ctx( context::exec_ontop_arg, unwind_coroutine);
|
||||||
ctx();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void
|
||||||
|
push_coroutine< T & >::control_block::deallocate() noexcept {
|
||||||
|
if ( state_t::none != ( state & state_t::unwind) ) {
|
||||||
|
destroy( this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,10 +282,6 @@ push_coroutine< T & >::control_block::resume( T & t) {
|
|||||||
if ( except) {
|
if ( except) {
|
||||||
std::rethrow_exception( except);
|
std::rethrow_exception( except);
|
||||||
}
|
}
|
||||||
// test early-exit-flag
|
|
||||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
|
||||||
throw forced_unwind();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
@ -275,9 +293,16 @@ push_coroutine< T & >::control_block::valid() const noexcept {
|
|||||||
|
|
||||||
// push_coroutine< void >
|
// push_coroutine< void >
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
push_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
|
||||||
|
boost::context::execution_context ctx = cb->ctx;
|
||||||
|
// destroy control structure
|
||||||
|
cb->~control_block();
|
||||||
|
}
|
||||||
|
|
||||||
template< typename StackAllocator, typename Fn >
|
template< typename StackAllocator, typename Fn >
|
||||||
push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) :
|
push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) :
|
||||||
other{ nullptr },
|
|
||||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
|
||||||
ctx{ std::allocator_arg, palloc, salloc,
|
ctx{ std::allocator_arg, palloc, salloc,
|
||||||
std::move(
|
std::move(
|
||||||
@ -288,9 +313,9 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall
|
|||||||
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
||||||
pull_coroutine< void > synthesized{ & synthesized_cb };
|
pull_coroutine< void > synthesized{ & synthesized_cb };
|
||||||
other = & synthesized_cb;
|
other = & synthesized_cb;
|
||||||
// jump back to ctor
|
|
||||||
ctx();
|
|
||||||
try {
|
try {
|
||||||
|
// jump back to ctor
|
||||||
|
ctx();
|
||||||
auto fn = std::move( fn_);
|
auto fn = std::move( fn_);
|
||||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||||
fn( synthesized);
|
fn( synthesized);
|
||||||
@ -316,9 +341,9 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall
|
|||||||
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
|
||||||
pull_coroutine< void > synthesized{ & synthesized_cb };
|
pull_coroutine< void > synthesized{ & synthesized_cb };
|
||||||
other = & synthesized_cb;
|
other = & synthesized_cb;
|
||||||
// jump back to ctor
|
|
||||||
ctx();
|
|
||||||
try {
|
try {
|
||||||
|
// jump back to ctor
|
||||||
|
ctx();
|
||||||
auto fn = std::move( fn_);
|
auto fn = std::move( fn_);
|
||||||
// call coroutine-fn with synthesized pull_coroutine as argument
|
// call coroutine-fn with synthesized pull_coroutine as argument
|
||||||
fn( synthesized);
|
fn( synthesized);
|
||||||
@ -335,6 +360,7 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall
|
|||||||
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
BOOST_ASSERT_MSG( false, "push_coroutine is complete");
|
||||||
}},
|
}},
|
||||||
#endif
|
#endif
|
||||||
|
other{ nullptr },
|
||||||
state{ state_t::unwind },
|
state{ state_t::unwind },
|
||||||
except{} {
|
except{} {
|
||||||
// enter coroutine-fn in order to get other set
|
// enter coroutine-fn in order to get other set
|
||||||
@ -344,19 +370,26 @@ push_coroutine< void >::control_block::control_block( context::preallocated pall
|
|||||||
inline
|
inline
|
||||||
push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
|
push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
|
||||||
boost::context::execution_context const& ctx_) noexcept :
|
boost::context::execution_context const& ctx_) noexcept :
|
||||||
other{ cb },
|
|
||||||
ctx{ ctx_ },
|
ctx{ ctx_ },
|
||||||
|
other{ cb },
|
||||||
state{ state_t::none },
|
state{ state_t::none },
|
||||||
except{} {
|
except{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
push_coroutine< void >::control_block::~control_block() noexcept {
|
push_coroutine< void >::control_block::~control_block() {
|
||||||
if ( state_t::none == ( state & state_t::complete) &&
|
if ( state_t::none == ( state & state_t::complete) &&
|
||||||
state_t::none != ( state & state_t::unwind) ) {
|
state_t::none != ( state & state_t::unwind) ) {
|
||||||
// set early-exit flag
|
// unwind coroutine stack
|
||||||
state |= state_t::early_exit;
|
ctx( context::exec_ontop_arg, unwind_coroutine);
|
||||||
ctx();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
push_coroutine< void >::control_block::deallocate() noexcept {
|
||||||
|
if ( state_t::none != ( state & state_t::unwind) ) {
|
||||||
|
destroy( this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,10 +401,6 @@ push_coroutine< void >::control_block::resume() {
|
|||||||
if ( except) {
|
if ( except) {
|
||||||
std::rethrow_exception( except);
|
std::rethrow_exception( except);
|
||||||
}
|
}
|
||||||
// test early-exit-flag
|
|
||||||
if ( state_t::none != ( other->state & state_t::early_exit) ) {
|
|
||||||
throw forced_unwind();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
@ -50,7 +50,7 @@ push_coroutine< T >::push_coroutine( StackAllocator salloc, Fn && fn) :
|
|||||||
template< typename T >
|
template< typename T >
|
||||||
push_coroutine< T >::~push_coroutine() noexcept {
|
push_coroutine< T >::~push_coroutine() noexcept {
|
||||||
if ( nullptr != cb_) {
|
if ( nullptr != cb_) {
|
||||||
cb_->~control_block();
|
cb_->deallocate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ push_coroutine< T & >::push_coroutine( StackAllocator salloc, Fn && fn) :
|
|||||||
template< typename T >
|
template< typename T >
|
||||||
push_coroutine< T & >::~push_coroutine() noexcept {
|
push_coroutine< T & >::~push_coroutine() noexcept {
|
||||||
if ( nullptr != cb_) {
|
if ( nullptr != cb_) {
|
||||||
cb_->~control_block();
|
cb_->deallocate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +161,7 @@ push_coroutine< void >::push_coroutine( StackAllocator salloc, Fn && fn) :
|
|||||||
inline
|
inline
|
||||||
push_coroutine< void >::~push_coroutine() noexcept {
|
push_coroutine< void >::~push_coroutine() noexcept {
|
||||||
if ( nullptr != cb_) {
|
if ( nullptr != cb_) {
|
||||||
cb_->~control_block();
|
cb_->deallocate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +25,7 @@ namespace detail {
|
|||||||
enum class state_t : unsigned int {
|
enum class state_t : unsigned int {
|
||||||
none = 0,
|
none = 0,
|
||||||
complete = 1 << 1,
|
complete = 1 << 1,
|
||||||
unwind = 1 << 2,
|
unwind = 1 << 2
|
||||||
early_exit = 1 << 3
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,12 +85,10 @@ int main( int argc, char * argv[])
|
|||||||
if ( bind) bind_to_processor( 0);
|
if ( bind) bind_to_processor( 0);
|
||||||
|
|
||||||
duration_type overhead_c = overhead_clock();
|
duration_type overhead_c = overhead_clock();
|
||||||
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
|
|
||||||
boost::uint64_t res = measure_time( overhead_c).count();
|
boost::uint64_t res = measure_time( overhead_c).count();
|
||||||
std::cout << "average of " << res << " nano seconds" << std::endl;
|
std::cout << "average of " << res << " nano seconds" << std::endl;
|
||||||
#ifdef BOOST_CONTEXT_CYCLE
|
#ifdef BOOST_CONTEXT_CYCLE
|
||||||
cycle_type overhead_y = overhead_cycle();
|
cycle_type overhead_y = overhead_cycle();
|
||||||
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
|
|
||||||
res = measure_cycles( overhead_y);
|
res = measure_cycles( overhead_y);
|
||||||
std::cout << "average of " << res << " cpu cycles" << std::endl;
|
std::cout << "average of " << res << " cpu cycles" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
@ -85,12 +85,10 @@ int main( int argc, char * argv[])
|
|||||||
if ( bind) bind_to_processor( 0);
|
if ( bind) bind_to_processor( 0);
|
||||||
|
|
||||||
duration_type overhead_c = overhead_clock();
|
duration_type overhead_c = overhead_clock();
|
||||||
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
|
|
||||||
boost::uint64_t res = measure_time( overhead_c).count();
|
boost::uint64_t res = measure_time( overhead_c).count();
|
||||||
std::cout << "average of " << res << " nano seconds" << std::endl;
|
std::cout << "average of " << res << " nano seconds" << std::endl;
|
||||||
#ifdef BOOST_CONTEXT_CYCLE
|
#ifdef BOOST_CONTEXT_CYCLE
|
||||||
cycle_type overhead_y = overhead_cycle();
|
cycle_type overhead_y = overhead_cycle();
|
||||||
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
|
|
||||||
res = measure_cycles( overhead_y);
|
res = measure_cycles( overhead_y);
|
||||||
std::cout << "average of " << res << " cpu cycles" << std::endl;
|
std::cout << "average of " << res << " cpu cycles" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
@ -168,7 +168,6 @@ int main( int argc, char * argv[])
|
|||||||
if ( bind) bind_to_processor( 0);
|
if ( bind) bind_to_processor( 0);
|
||||||
|
|
||||||
duration_type overhead_c = overhead_clock();
|
duration_type overhead_c = overhead_clock();
|
||||||
std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
|
|
||||||
boost::uint64_t res = measure_time_void( overhead_c).count();
|
boost::uint64_t res = measure_time_void( overhead_c).count();
|
||||||
std::cout << "void: average of " << res << " nano seconds" << std::endl;
|
std::cout << "void: average of " << res << " nano seconds" << std::endl;
|
||||||
res = measure_time_int( overhead_c).count();
|
res = measure_time_int( overhead_c).count();
|
||||||
@ -177,7 +176,6 @@ int main( int argc, char * argv[])
|
|||||||
std::cout << "X: average of " << res << " nano seconds" << std::endl;
|
std::cout << "X: average of " << res << " nano seconds" << std::endl;
|
||||||
#ifdef BOOST_CONTEXT_CYCLE
|
#ifdef BOOST_CONTEXT_CYCLE
|
||||||
cycle_type overhead_y = overhead_cycle();
|
cycle_type overhead_y = overhead_cycle();
|
||||||
std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
|
|
||||||
res = measure_cycles_void( overhead_y);
|
res = measure_cycles_void( overhead_y);
|
||||||
std::cout << "void: average of " << res << " cpu cycles" << std::endl;
|
std::cout << "void: average of " << res << " cpu cycles" << std::endl;
|
||||||
res = measure_cycles_int( overhead_y);
|
res = measure_cycles_int( overhead_y);
|
||||||
|
@ -28,15 +28,14 @@ project boost/coroutine2/test
|
|||||||
|
|
||||||
run test_coroutine.cpp :
|
run test_coroutine.cpp :
|
||||||
: :
|
: :
|
||||||
[ requires cxx11_constexpr
|
[ requires cxx11_auto_declarations
|
||||||
cxx11_decltype
|
cxx11_constexpr
|
||||||
cxx11_deleted_functions
|
cxx11_defaulted_functions
|
||||||
cxx11_explicit_conversion_operators
|
cxx11_final
|
||||||
cxx11_hdr_tuple cxx11_lambdas
|
cxx11_hdr_tuple
|
||||||
|
cxx11_lambdas
|
||||||
cxx11_noexcept
|
cxx11_noexcept
|
||||||
cxx11_nullptr
|
cxx11_nullptr
|
||||||
cxx11_template_aliases
|
|
||||||
cxx11_rvalue_references
|
cxx11_rvalue_references
|
||||||
cxx11_variadic_macros
|
cxx11_template_aliases
|
||||||
cxx11_variadic_templates
|
cxx11_variadic_templates ] ;
|
||||||
cxx14_initialized_lambda_captures ] ;
|
|
||||||
|
@ -613,7 +613,7 @@ void test_chaining()
|
|||||||
boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
|
boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
|
||||||
{
|
{
|
||||||
boost::unit_test::test_suite * test =
|
boost::unit_test::test_suite * test =
|
||||||
BOOST_TEST_SUITE("Boost.coroutine: coroutine test suite");
|
BOOST_TEST_SUITE("Boost.Coroutine2: coroutine test suite");
|
||||||
|
|
||||||
test->add( BOOST_TEST_CASE( & test_move) );
|
test->add( BOOST_TEST_CASE( & test_move) );
|
||||||
test->add( BOOST_TEST_CASE( & test_complete) );
|
test->add( BOOST_TEST_CASE( & test_complete) );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user