summaryrefslogtreecommitdiff
path: root/boost/context/continuation.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/context/continuation.hpp')
-rw-r--r--boost/context/continuation.hpp551
1 files changed, 5 insertions, 546 deletions
diff --git a/boost/context/continuation.hpp b/boost/context/continuation.hpp
index 6a50713158..8db62a9506 100644
--- a/boost/context/continuation.hpp
+++ b/boost/context/continuation.hpp
@@ -4,551 +4,10 @@
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
-#ifndef BOOST_CONTEXT_CONTINUATION_H
-#define BOOST_CONTEXT_CONTINUATION_H
-
-#include <boost/context/detail/config.hpp>
-
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <cstdlib>
-#include <exception>
-#include <functional>
-#include <memory>
-#include <ostream>
-#include <tuple>
-#include <utility>
-
-#include <boost/assert.hpp>
-#include <boost/config.hpp>
-#include <boost/intrusive_ptr.hpp>
-
-#if defined(BOOST_NO_CXX17_STD_APPLY)
-#include <boost/context/detail/apply.hpp>
-#endif
-#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
-#include <boost/context/detail/exchange.hpp>
-#endif
-#if defined(BOOST_NO_CXX17_STD_INVOKE)
-#include <boost/context/detail/invoke.hpp>
-#endif
-#include <boost/context/detail/disable_overload.hpp>
-#include <boost/context/detail/exception.hpp>
-#include <boost/context/detail/fcontext.hpp>
-#include <boost/context/detail/tuple.hpp>
-#include <boost/context/fixedsize_stack.hpp>
-#include <boost/context/flags.hpp>
-#include <boost/context/preallocated.hpp>
-#include <boost/context/segmented_stack.hpp>
-#include <boost/context/stack_context.hpp>
-
-#ifdef BOOST_HAS_ABI_HEADERS
-# include BOOST_ABI_PREFIX
-#endif
-
-#if defined(BOOST_MSVC)
-# pragma warning(push)
-# pragma warning(disable: 4702)
-#endif
-
-namespace boost {
-namespace context {
-namespace detail {
-
-template< int N >
-struct helper {
- template< typename T >
- static T convert( T && t) noexcept {
- return std::forward< T >( t);
- }
-};
-
-template<>
-struct helper< 1 > {
- template< typename T >
- static std::tuple< T > convert( T && t) noexcept {
- return std::make_tuple( std::forward< T >( t) );
- }
-};
-
-inline
-transfer_t context_unwind( transfer_t t) {
- throw forced_unwind( t.fctx);
- return { nullptr, nullptr };
-}
-
-template< typename Rec >
-transfer_t context_exit( transfer_t t) noexcept {
- Rec * rec = static_cast< Rec * >( t.data);
- // destroy context stack
- rec->deallocate();
- return { nullptr, nullptr };
-}
-
-template< typename Rec >
-void context_entry( transfer_t t_) noexcept {
- // transfer control structure to the context-stack
- Rec * rec = static_cast< Rec * >( t_.data);
- BOOST_ASSERT( nullptr != t_.fctx);
- BOOST_ASSERT( nullptr != rec);
- transfer_t t = { nullptr, nullptr };
- try {
- // jump back to `context_create()`
- t = jump_fcontext( t_.fctx, nullptr);
- // start executing
- t = rec->run( t);
- } catch ( forced_unwind const& e) {
- t = { e.fctx, nullptr };
- }
- BOOST_ASSERT( nullptr != t.fctx);
- // destroy context-stack of `this`context on next context
- ontop_fcontext( t.fctx, rec, context_exit< Rec >);
- BOOST_ASSERT_MSG( false, "context already terminated");
-}
-
-template<
- typename Ctx,
- typename StackAlloc,
- typename Fn
->
-class record {
-private:
- StackAlloc salloc_;
- stack_context sctx_;
- typename std::decay< Fn >::type fn_;
-
- static void destroy( record * p) noexcept {
- StackAlloc salloc = p->salloc_;
- stack_context sctx = p->sctx_;
- // deallocate record
- p->~record();
- // destroy stack with stack allocator
- salloc.deallocate( sctx);
- }
-
-public:
- record( stack_context sctx, StackAlloc const& salloc,
- Fn && fn) noexcept :
- salloc_( salloc),
- sctx_( sctx),
- fn_( std::forward< Fn >( fn) ) {
- }
-
- record( record const&) = delete;
- record & operator=( record const&) = delete;
-
- void deallocate() noexcept {
- destroy( this);
- }
-
- transfer_t run( transfer_t t) {
- Ctx from{ t };
- // invoke context-function
-#if defined(BOOST_NO_CXX17_STD_INVOKE)
- Ctx cc = invoke( fn_, std::move( from) );
-#else
- Ctx cc = std::invoke( fn_, std::move( from) );
-#endif
-#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
- return { exchange( cc.t_.fctx, nullptr), nullptr };
+#if defined(BOOST_USE_UCONTEXT)
+#include <boost/context/continuation_ucontext.hpp>
+#elif defined(BOOST_USE_WINFIB)
+#include <boost/context/continuation_winfib.hpp>
#else
- return { std::exchange( cc.t_.fctx, nullptr), nullptr };
+#include <boost/context/continuation_fcontext.hpp>
#endif
- }
-};
-
-template< typename Record, typename StackAlloc, typename Fn >
-fcontext_t context_create( StackAlloc salloc, Fn && fn) {
- auto sctx = salloc.allocate();
- // reserve space for control structure
-#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
- const std::size_t size = sctx.size - sizeof( Record);
- void * sp = static_cast< char * >( sctx.sp) - sizeof( Record);
-#else
- constexpr std::size_t func_alignment = 64; // alignof( Record);
- constexpr std::size_t func_size = sizeof( Record);
- // reserve space on stack
- void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
- // align sp pointer
- std::size_t space = func_size + func_alignment;
- sp = std::align( func_alignment, func_size, sp, space);
- BOOST_ASSERT( nullptr != sp);
- // calculate remaining size
- const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
-#endif
- // create fast-context
- const fcontext_t fctx = make_fcontext( sp, size, & context_entry< Record >);
- BOOST_ASSERT( nullptr != fctx);
- // placment new for control structure on context-stack
- auto rec = ::new ( sp) Record{
- sctx, salloc, std::forward< Fn >( fn) };
- // transfer control structure to context-stack
- return jump_fcontext( fctx, rec).fctx;
-}
-
-template< typename Record, typename StackAlloc, typename Fn >
-fcontext_t context_create( preallocated palloc, StackAlloc salloc, Fn && fn) {
- // reserve space for control structure
-#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
- const std::size_t size = palloc.size - sizeof( Record);
- void * sp = static_cast< char * >( palloc.sp) - sizeof( Record);
-#else
- constexpr std::size_t func_alignment = 64; // alignof( Record);
- constexpr std::size_t func_size = sizeof( Record);
- // reserve space on stack
- void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment;
- // align sp pointer
- std::size_t space = func_size + func_alignment;
- sp = std::align( func_alignment, func_size, sp, space);
- BOOST_ASSERT( nullptr != sp);
- // calculate remaining size
- const std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
-#endif
- // create fast-context
- const fcontext_t fctx = make_fcontext( sp, size, & context_entry< Record >);
- BOOST_ASSERT( nullptr != fctx);
- // placment new for control structure on context-stack
- auto rec = ::new ( sp) Record{
- palloc.sctx, salloc, std::forward< Fn >( fn) };
- // transfer control structure to context-stack
- return jump_fcontext( fctx, rec).fctx;
-}
-
-template< typename ... Arg >
-struct result_type {
- typedef std::tuple< Arg ... > type;
-
- static
- type get( detail::transfer_t & t) {
- auto p = static_cast< std::tuple< Arg ... > * >( t.data);
- return std::move( * p);
- }
-};
-
-template< typename Arg >
-struct result_type< Arg > {
- typedef Arg type;
-
- static
- type get( detail::transfer_t & t) {
- auto p = static_cast< std::tuple< Arg > * >( t.data);
- return std::forward< Arg >( std::get< 0 >( * p) );
- }
-};
-
-}
-
-template< typename Ctx, typename Fn, typename ... Arg >
-detail::transfer_t context_ontop( detail::transfer_t t) {
- auto p = static_cast< std::tuple< Fn, std::tuple< Arg ... > > * >( t.data);
- BOOST_ASSERT( nullptr != p);
- typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * p) );
- t.data = & std::get< 1 >( * p);
- Ctx c{ t };
- // execute function, pass continuation via reference
- std::get< 1 >( * p) = detail::helper< sizeof ... (Arg) >::convert( fn( std::move( c) ) );
-#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
- return { detail::exchange( c.t_.fctx, nullptr), & std::get< 1 >( * p) };
-#else
- return { std::exchange( c.t_.fctx, nullptr), & std::get< 1 >( * p) };
-#endif
-}
-
-template< typename Ctx, typename Fn >
-detail::transfer_t context_ontop_void( detail::transfer_t t) {
- auto p = static_cast< std::tuple< Fn > * >( t.data);
- BOOST_ASSERT( nullptr != p);
- typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * p) );
- Ctx c{ t };
- // execute function, pass continuation via reference
- fn( std::move( c) );
-#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
- return { detail::exchange( c.t_.fctx, nullptr), nullptr };
-#else
- return { std::exchange( c.t_.fctx, nullptr), nullptr };
-#endif
-}
-
-class continuation {
-private:
- template< typename Ctx, typename StackAlloc, typename Fn >
- friend class detail::record;
-
- template< typename Ctx, typename Fn, typename ... Arg >
- friend detail::transfer_t
- context_ontop( detail::transfer_t);
-
- template< typename Ctx, typename Fn >
- friend detail::transfer_t
- context_ontop_void( detail::transfer_t);
-
- template< typename StackAlloc, typename Fn, typename ... Arg >
- friend continuation
- callcc( std::allocator_arg_t, StackAlloc, Fn &&, Arg ...);
-
- template< typename StackAlloc, typename Fn, typename ... Arg >
- friend continuation
- callcc( std::allocator_arg_t, preallocated, StackAlloc, Fn &&, Arg ...);
-
- template< typename StackAlloc, typename Fn >
- friend continuation
- callcc( std::allocator_arg_t, StackAlloc, Fn &&);
-
- template< typename StackAlloc, typename Fn >
- friend continuation
- callcc( std::allocator_arg_t, preallocated, StackAlloc, Fn &&);
-
- detail::transfer_t t_{ nullptr, nullptr };
-
- continuation( detail::fcontext_t fctx) noexcept :
- t_{ fctx, nullptr } {
- }
-
- continuation( detail::transfer_t t) noexcept :
- t_{ t.fctx, t.data } {
- }
-
-public:
- continuation() noexcept = default;
-
- ~continuation() {
- if ( nullptr != t_.fctx) {
-#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
- detail::ontop_fcontext( detail::exchange( t_.fctx, nullptr), nullptr, detail::context_unwind);
-#else
- detail::ontop_fcontext( std::exchange( t_.fctx, nullptr), nullptr, detail::context_unwind);
-#endif
- }
- }
-
- continuation( continuation && other) noexcept :
- t_{ other.t_.fctx, other.t_.data } {
- other.t_ = { nullptr, nullptr };
- }
-
- continuation & operator=( continuation && other) noexcept {
- if ( this != & other) {
- continuation tmp = std::move( other);
- swap( tmp);
- }
- return * this;
- }
-
- continuation( continuation const& other) noexcept = delete;
- continuation & operator=( continuation const& other) noexcept = delete;
-
- template< typename ... Arg >
- continuation resume( Arg ... arg) {
- BOOST_ASSERT( nullptr != t_.fctx);
- auto tpl = std::make_tuple( std::forward< Arg >( arg) ... );
- return detail::jump_fcontext(
-#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
- detail::exchange( t_.fctx, nullptr),
-#else
- std::exchange( t_.fctx, nullptr),
-#endif
- & tpl);
- }
-
- template< typename Fn, typename ... Arg >
- continuation resume_with( Fn && fn, Arg ... arg) {
- BOOST_ASSERT( nullptr != t_.fctx);
- auto tpl = std::make_tuple( std::forward< Fn >( fn), std::forward< Arg >( arg) ... );
- return detail::ontop_fcontext(
-#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
- detail::exchange( t_.fctx, nullptr),
-#else
- std::exchange( t_.fctx, nullptr),
-#endif
- & tpl,
- context_ontop< continuation, Fn, Arg ... >);
- }
-
- continuation resume() {
- BOOST_ASSERT( nullptr != t_.fctx);
- return detail::jump_fcontext(
-#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
- detail::exchange( t_.fctx, nullptr),
-#else
- std::exchange( t_.fctx, nullptr),
-#endif
- nullptr);
- }
-
- template< typename Fn >
- continuation resume_with( Fn && fn) {
- BOOST_ASSERT( nullptr != t_.fctx);
- auto p = std::make_tuple( std::forward< Fn >( fn) );
- return detail::ontop_fcontext(
-#if defined(BOOST_NO_CXX14_STD_EXCHANGE)
- detail::exchange( t_.fctx, nullptr),
-#else
- std::exchange( t_.fctx, nullptr),
-#endif
- & p,
- context_ontop_void< continuation, Fn >);
- }
-
- bool data_available() noexcept {
- return * this && nullptr != t_.data;
- }
-
- template< typename ... Arg >
- typename detail::result_type< Arg ... >::type get_data() {
- BOOST_ASSERT( nullptr != t_.data);
- return detail::result_type< Arg ... >::get( t_);
- }
-
- explicit operator bool() const noexcept {
- return nullptr != t_.fctx;
- }
-
- bool operator!() const noexcept {
- return nullptr == t_.fctx;
- }
-
- bool operator==( continuation const& other) const noexcept {
- return t_.fctx == other.t_.fctx;
- }
-
- bool operator!=( continuation const& other) const noexcept {
- return t_.fctx != other.t_.fctx;
- }
-
- bool operator<( continuation const& other) const noexcept {
- return t_.fctx < other.t_.fctx;
- }
-
- bool operator>( continuation const& other) const noexcept {
- return other.t_.fctx < t_.fctx;
- }
-
- bool operator<=( continuation const& other) const noexcept {
- return ! ( * this > other);
- }
-
- bool operator>=( continuation const& other) const noexcept {
- return ! ( * this < other);
- }
-
- template< typename charT, class traitsT >
- friend std::basic_ostream< charT, traitsT > &
- operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) {
- if ( nullptr != other.t_.fctx) {
- return os << other.t_.fctx;
- } else {
- return os << "{not-a-context}";
- }
- }
-
- void swap( continuation & other) noexcept {
- std::swap( t_, other.t_);
- }
-};
-
-// Arg
-template<
- typename Fn,
- typename ... Arg,
- typename = detail::disable_overload< continuation, Fn >
->
-continuation
-callcc( Fn && fn, Arg ... arg) {
- return callcc(
- std::allocator_arg, fixedsize_stack(),
- std::forward< Fn >( fn), std::forward< Arg >( arg) ...);
-}
-
-template<
- typename StackAlloc,
- typename Fn,
- typename ... Arg
->
-continuation
-callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Arg ... arg) {
- using Record = detail::record< continuation, StackAlloc, Fn >;
- return continuation{
- detail::context_create< Record >(
- salloc, std::forward< Fn >( fn) ) }.resume(
- std::forward< Arg >( arg) ... );
-}
-
-template<
- typename StackAlloc,
- typename Fn,
- typename ... Arg
->
-continuation
-callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Arg ... arg) {
- using Record = detail::record< continuation, StackAlloc, Fn >;
- return continuation{
- detail::context_create< Record >(
- palloc, salloc, std::forward< Fn >( fn) ) }.resume(
- std::forward< Arg >( arg) ... );
-}
-
-// void
-template<
- typename Fn,
- typename = detail::disable_overload< continuation, Fn >
->
-continuation
-callcc( Fn && fn) {
- return callcc(
- std::allocator_arg, fixedsize_stack(),
- std::forward< Fn >( fn) );
-}
-
-template< typename StackAlloc, typename Fn >
-continuation
-callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn) {
- using Record = detail::record< continuation, StackAlloc, Fn >;
- return continuation{
- detail::context_create< Record >(
- salloc, std::forward< Fn >( fn) ) }.resume();
-}
-
-template< typename StackAlloc, typename Fn >
-continuation
-callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn) {
- using Record = detail::record< continuation, StackAlloc, Fn >;
- return continuation{
- detail::context_create< Record >(
- palloc, salloc, std::forward< Fn >( fn) ) }.resume();
-}
-
-#if defined(BOOST_USE_SEGMENTED_STACKS)
-template<
- typename Fn,
- typename ... Arg
->
-continuation
-callcc( std::allocator_arg_t, segmented_stack, Fn &&, Arg ...);
-
-template<
- typename StackAlloc,
- typename Fn,
- typename ... Arg
->
-continuation
-callcc( std::allocator_arg_t, preallocated, segmented_stack, Fn &&, Arg ...);
-#endif
-
-// swap
-inline
-void swap( continuation & l, continuation & r) noexcept {
- l.swap( r);
-}
-
-}}
-
-#if defined(BOOST_MSVC)
-# pragma warning(pop)
-#endif
-
-#ifdef BOOST_HAS_ABI_HEADERS
-# include BOOST_ABI_SUFFIX
-#endif
-
-#endif // BOOST_CONTEXT_CONTINUATION_H