|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r81511 - in trunk: boost/coroutine boost/coroutine/detail libs libs/coroutine libs/coroutine/doc libs/coroutine/doc/images libs/coroutine/example libs/coroutine/example/asio libs/coroutine/performance libs/coroutine/test status
From: oliver.kowalke_at_[hidden]
Date: 2012-11-24 14:42:15
Author: olli
Date: 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
New Revision: 81511
URL: http://svn.boost.org/trac/boost/changeset/81511
Log:
coroutine: initial commit
Added:
trunk/boost/coroutine/
trunk/boost/coroutine/all.hpp (contents, props changed)
trunk/boost/coroutine/attributes.hpp (contents, props changed)
trunk/boost/coroutine/coroutine.hpp (contents, props changed)
trunk/boost/coroutine/detail/
trunk/boost/coroutine/detail/arg.hpp (contents, props changed)
trunk/boost/coroutine/detail/config.hpp (contents, props changed)
trunk/boost/coroutine/detail/coroutine_base.hpp (contents, props changed)
trunk/boost/coroutine/detail/coroutine_base_resume.hpp (contents, props changed)
trunk/boost/coroutine/detail/coroutine_caller.hpp (contents, props changed)
trunk/boost/coroutine/detail/coroutine_get.hpp (contents, props changed)
trunk/boost/coroutine/detail/coroutine_object.hpp (contents, props changed)
trunk/boost/coroutine/detail/coroutine_object_result_0.ipp (contents, props changed)
trunk/boost/coroutine/detail/coroutine_object_result_1.ipp (contents, props changed)
trunk/boost/coroutine/detail/coroutine_object_result_arity.ipp (contents, props changed)
trunk/boost/coroutine/detail/coroutine_object_void_0.ipp (contents, props changed)
trunk/boost/coroutine/detail/coroutine_object_void_1.ipp (contents, props changed)
trunk/boost/coroutine/detail/coroutine_object_void_arity.ipp (contents, props changed)
trunk/boost/coroutine/detail/coroutine_op.hpp (contents, props changed)
trunk/boost/coroutine/detail/exceptions.hpp (contents, props changed)
trunk/boost/coroutine/detail/flags.hpp (contents, props changed)
trunk/boost/coroutine/detail/holder.hpp (contents, props changed)
trunk/boost/coroutine/detail/param.hpp (contents, props changed)
trunk/boost/coroutine/detail/stack_allocator_posix.hpp (contents, props changed)
trunk/boost/coroutine/detail/stack_allocator_windows.hpp (contents, props changed)
trunk/boost/coroutine/flags.hpp (contents, props changed)
trunk/boost/coroutine/stack_allocator.hpp (contents, props changed)
trunk/libs/coroutine/
trunk/libs/coroutine/doc/
trunk/libs/coroutine/doc/Jamfile.v2 (contents, props changed)
trunk/libs/coroutine/doc/acknowledgements.qbk (contents, props changed)
trunk/libs/coroutine/doc/attributes.qbk (contents, props changed)
trunk/libs/coroutine/doc/coro.qbk (contents, props changed)
trunk/libs/coroutine/doc/coroutine.qbk (contents, props changed)
trunk/libs/coroutine/doc/foo_bar.png (contents, props changed)
trunk/libs/coroutine/doc/images/
trunk/libs/coroutine/doc/images/foo_bar.png (contents, props changed)
trunk/libs/coroutine/doc/images/foo_bar_seq.png (contents, props changed)
trunk/libs/coroutine/doc/intro.qbk (contents, props changed)
trunk/libs/coroutine/doc/overview.qbk (contents, props changed)
trunk/libs/coroutine/doc/performance.qbk (contents, props changed)
trunk/libs/coroutine/doc/stack.qbk (contents, props changed)
trunk/libs/coroutine/example/
trunk/libs/coroutine/example/Jamfile.v2 (contents, props changed)
trunk/libs/coroutine/example/asio/
trunk/libs/coroutine/example/asio/stream_client.cpp (contents, props changed)
trunk/libs/coroutine/example/asio/stream_server.cpp (contents, props changed)
trunk/libs/coroutine/example/echo.cpp (contents, props changed)
trunk/libs/coroutine/example/fibonacci.cpp (contents, props changed)
trunk/libs/coroutine/example/parallel.cpp (contents, props changed)
trunk/libs/coroutine/example/power.cpp (contents, props changed)
trunk/libs/coroutine/example/same_fringe.cpp (contents, props changed)
trunk/libs/coroutine/example/tree.h (contents, props changed)
trunk/libs/coroutine/example/unwind.cpp (contents, props changed)
trunk/libs/coroutine/index.html (contents, props changed)
trunk/libs/coroutine/performance/
trunk/libs/coroutine/performance/Jamfile.v2 (contents, props changed)
trunk/libs/coroutine/performance/bind_processor.hpp (contents, props changed)
trunk/libs/coroutine/performance/bind_processor_aix.cpp (contents, props changed)
trunk/libs/coroutine/performance/bind_processor_freebsd.cpp (contents, props changed)
trunk/libs/coroutine/performance/bind_processor_hpux.cpp (contents, props changed)
trunk/libs/coroutine/performance/bind_processor_linux.cpp (contents, props changed)
trunk/libs/coroutine/performance/bind_processor_solaris.cpp (contents, props changed)
trunk/libs/coroutine/performance/bind_processor_windows.cpp (contents, props changed)
trunk/libs/coroutine/performance/cycle.hpp (contents, props changed)
trunk/libs/coroutine/performance/cycle_i386.hpp (contents, props changed)
trunk/libs/coroutine/performance/cycle_x86-64.hpp (contents, props changed)
trunk/libs/coroutine/performance/performance.cpp (contents, props changed)
trunk/libs/coroutine/performance/simple_stack_allocator.hpp (contents, props changed)
trunk/libs/coroutine/performance/zeit.hpp (contents, props changed)
trunk/libs/coroutine/test/
trunk/libs/coroutine/test/Jamfile.v2 (contents, props changed)
trunk/libs/coroutine/test/test_coroutine.cpp (contents, props changed)
Text files modified:
trunk/libs/libraries.htm | 2 ++
trunk/libs/maintainers.txt | 3 ++-
trunk/status/Jamfile.v2 | 1 +
3 files changed, 5 insertions(+), 1 deletions(-)
Added: trunk/boost/coroutine/all.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/all.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,15 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_ALL_H
+#define BOOST_COROUTINES_ALL_H
+
+#include <boost/coroutine/attributes.hpp>
+#include <boost/coroutine/coroutine.hpp>
+#include <boost/coroutine/flags.hpp>
+#include <boost/coroutine/stack_allocator.hpp>
+
+#endif // BOOST_COROUTINES_ALL_H
Added: trunk/boost/coroutine/attributes.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/attributes.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,85 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_ATTRIBUTES_H
+#define BOOST_COROUTINES_ATTRIBUTES_H
+
+#include <cstddef>
+
+#include <boost/config.hpp>
+
+#include <boost/coroutine/flags.hpp>
+#include <boost/coroutine/stack_allocator.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+
+struct attributes
+{
+ std::size_t size;
+ flag_unwind_t do_unwind;
+ flag_fpu_t preserve_fpu;
+
+ attributes() BOOST_NOEXCEPT :
+ size( stack_allocator::default_stacksize() ),
+ do_unwind( stack_unwind),
+ preserve_fpu( fpu_preserved)
+ {}
+
+ explicit attributes( std::size_t size_) BOOST_NOEXCEPT :
+ size( size_),
+ do_unwind( stack_unwind),
+ preserve_fpu( fpu_preserved)
+ {}
+
+ explicit attributes( flag_unwind_t do_unwind_) BOOST_NOEXCEPT :
+ size( stack_allocator::default_stacksize() ),
+ do_unwind( do_unwind_),
+ preserve_fpu( fpu_preserved)
+ {}
+
+ explicit attributes( flag_fpu_t preserve_fpu_) BOOST_NOEXCEPT :
+ size( stack_allocator::default_stacksize() ),
+ do_unwind( stack_unwind),
+ preserve_fpu( preserve_fpu_)
+ {}
+
+ explicit attributes(
+ std::size_t size_,
+ flag_unwind_t do_unwind_) BOOST_NOEXCEPT :
+ size( size_),
+ do_unwind( do_unwind_),
+ preserve_fpu( fpu_preserved)
+ {}
+
+ explicit attributes(
+ std::size_t size_,
+ flag_fpu_t preserve_fpu_) BOOST_NOEXCEPT :
+ size( size_),
+ do_unwind( stack_unwind),
+ preserve_fpu( preserve_fpu_)
+ {}
+
+ explicit attributes(
+ flag_unwind_t do_unwind_,
+ flag_fpu_t preserve_fpu_) BOOST_NOEXCEPT :
+ size( stack_allocator::default_stacksize() ),
+ do_unwind( do_unwind_),
+ preserve_fpu( preserve_fpu_)
+ {}
+};
+
+}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_ATTRIBUTES_H
Added: trunk/boost/coroutine/coroutine.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/coroutine.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,1405 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_COROUTINE_H
+#define BOOST_COROUTINES_COROUTINE_H
+
+#include <cstddef>
+#include <memory>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/context/fcontext.hpp>
+#include <boost/move/move.hpp>
+#include <boost/range.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/decay.hpp>
+#include <boost/type_traits/function_traits.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/utility/result_of.hpp>
+
+#include <boost/coroutine/attributes.hpp>
+#include <boost/coroutine/detail/arg.hpp>
+#include <boost/coroutine/detail/coroutine_base.hpp>
+#include <boost/coroutine/detail/coroutine_get.hpp>
+#include <boost/coroutine/detail/coroutine_object.hpp>
+#include <boost/coroutine/detail/coroutine_op.hpp>
+#include <boost/coroutine/detail/coroutine_caller.hpp>
+#include <boost/coroutine/stack_allocator.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template<
+ typename Signature,
+ template< class, int > class C,
+ typename Result = typename function_traits< Signature >::result_type,
+ int arity = function_traits< Signature >::arity
+>
+struct caller;
+
+template<
+ typename Signature,
+ template< class, int > class C
+>
+struct caller< Signature, C, void, 0 >
+{ typedef C< void(), 0 > type; };
+
+template<
+ typename Signature,
+ template< class, int > class C,
+ typename Result
+>
+struct caller< Signature, C, Result, 0 >
+{ typedef C< void( Result), 1 > type; };
+
+template<
+ typename Signature,
+ template< class, int > class C,
+ int arity
+>
+struct caller< Signature, C, void, arity >
+{ typedef C< typename detail::arg< Signature >::type(), 0 > type; };
+
+template<
+ typename Signature,
+ template< class, int > class C,
+ typename Result, int arity
+>
+struct caller
+{ typedef C< typename detail::arg< Signature >::type( Result), 1 > type; };
+
+}
+
+template< typename Signature, int arity = function_traits< Signature >::arity >
+class coroutine;
+
+template< typename Signature >
+class coroutine< Signature, 0 > : public detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >,
+ public detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >
+{
+private:
+ typedef detail::coroutine_base< Signature > base_t;
+ typedef typename base_t::ptr_t ptr_t;
+
+ template< typename X, typename Y, int >
+ friend struct detail::coroutine_get;
+ template< typename X, typename Y, typename Z, int >
+ friend struct detail::coroutine_op;
+ template< typename X, typename Y, typename Z, typename A, typename B, typename C, int >
+ friend class detail::coroutine_object;
+
+ struct dummy
+ { void nonnull() {} };
+
+ typedef void ( dummy::*safe_bool)();
+
+ ptr_t impl_;
+
+ BOOST_MOVABLE_BUT_NOT_COPYABLE( coroutine);
+
+ template< typename Allocator >
+ coroutine( context::fcontext_t * callee,
+ bool unwind, bool preserve_fpu,
+ Allocator const& alloc) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+
+ >(),
+ impl_()
+ {
+ typedef detail::coroutine_caller<
+ Signature, Allocator
+ > caller_t;
+ typename caller_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) caller_t(
+ callee, unwind, preserve_fpu, a) );
+ }
+
+public:
+ typedef typename detail::caller<
+ Signature,
+ boost::coroutines::coroutine
+ >::type caller_type;
+
+ coroutine() BOOST_NOEXCEPT :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {}
+
+#ifndef BOOST_NO_RVALUE_REFERENCES
+#ifdef BOOST_MSVC
+ typedef void ( * coroutine_fn) ( caller_type &);
+
+ explicit coroutine( coroutine_fn fn, attributes const& attr = attributes(),
+ stack_allocator const& stack_alloc =
+ stack_allocator(),
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >() ) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ typedef detail::coroutine_object<
+ Signature,
+ coroutine_fn, stack_allocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< coroutine_fn >( fn), attr, stack_alloc, a) );
+ }
+
+ template< typename StackAllocator >
+ explicit coroutine( coroutine_fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >() ) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ typedef detail::coroutine_object<
+ Signature,
+ coroutine_fn, StackAllocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< coroutine_fn >( fn), attr, stack_alloc, a) );
+ }
+
+ template< typename StackAllocator, typename Allocator >
+ explicit coroutine( coroutine_fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ Allocator const& alloc) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ typedef detail::coroutine_object<
+ Signature,
+ coroutine_fn, StackAllocator, Allocator,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< coroutine_fn >( fn), attr, stack_alloc, a) );
+ }
+#endif
+ template< typename Fn >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+ stack_allocator const& stack_alloc =
+ stack_allocator(),
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, stack_allocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator, typename Allocator >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ Allocator const& alloc,
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, Allocator,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+ }
+#else
+ template< typename Fn >
+ explicit coroutine( Fn fn, attributes const& attr = attributes(),
+ stack_allocator const& stack_alloc =
+ stack_allocator(),
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, stack_allocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator >
+ explicit coroutine( Fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator, typename Allocator >
+ explicit coroutine( Fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ Allocator const& alloc,
+ typename disable_if<
+ is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, Allocator,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+ stack_allocator const& stack_alloc =
+ stack_allocator(),
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, stack_allocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator, typename Allocator >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ Allocator const& alloc,
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, Allocator,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+ }
+#endif
+
+ coroutine( BOOST_RV_REF( coroutine) other) BOOST_NOEXCEPT :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ { swap( other); }
+
+ coroutine & operator=( BOOST_RV_REF( coroutine) other) BOOST_NOEXCEPT
+ {
+ coroutine tmp( boost::move( other) );
+ swap( tmp);
+ return * this;
+ }
+
+ bool empty() const BOOST_NOEXCEPT
+ { return ! impl_; }
+
+ operator safe_bool() const BOOST_NOEXCEPT
+ { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; }
+
+ bool operator!() const BOOST_NOEXCEPT
+ { return empty() || impl_->is_complete(); }
+
+ void swap( coroutine & other) BOOST_NOEXCEPT
+ { impl_.swap( other.impl_); }
+};
+
+template< typename Signature, int arity >
+class coroutine : public detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >,
+ public detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >
+{
+private:
+ typedef detail::coroutine_base< Signature > base_t;
+ typedef typename base_t::ptr_t ptr_t;
+
+ template< typename X, typename Y, int >
+ friend struct detail::coroutine_get;
+ template< typename X, typename Y, typename Z, int >
+ friend struct detail::coroutine_op;
+ template< typename X, typename Y, typename Z, typename A, typename B, typename C, int >
+ friend class detail::coroutine_object;
+
+ struct dummy
+ { void nonnull() {} };
+
+ typedef void ( dummy::*safe_bool)();
+
+ ptr_t impl_;
+
+ BOOST_MOVABLE_BUT_NOT_COPYABLE( coroutine);
+
+ template< typename Allocator >
+ coroutine( context::fcontext_t * callee,
+ bool unwind, bool preserve_fpu,
+ Allocator const& alloc) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ typedef detail::coroutine_caller<
+ Signature, Allocator
+ > caller_t;
+ typename caller_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) caller_t(
+ callee, unwind, preserve_fpu, a) );
+ }
+
+public:
+ typedef typename detail::caller<
+ Signature,
+ boost::coroutines::coroutine
+ >::type caller_type;
+ typedef typename detail::arg< Signature >::type arguments;
+
+ coroutine() BOOST_NOEXCEPT :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {}
+
+#ifndef BOOST_NO_RVALUE_REFERENCES
+#ifdef BOOST_MSVC
+ typedef void ( * coroutine_fn) ( caller_type &);
+
+ explicit coroutine( coroutine_fn fn, attributes const& attr = attributes(),
+ stack_allocator const& stack_alloc =
+ stack_allocator(),
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >() ) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ typedef detail::coroutine_object<
+ Signature,
+ coroutine_fn, stack_allocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< coroutine_fn >( fn), attr, stack_alloc, a) );
+ }
+
+ explicit coroutine( coroutine_fn fn, arguments arg, attributes const& attr = attributes(),
+ stack_allocator const& stack_alloc =
+ stack_allocator(),
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >() ) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ typedef detail::coroutine_object<
+ Signature,
+ coroutine_fn, stack_allocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< coroutine_fn >( fn), arg, attr, stack_alloc, a) );
+ }
+
+ template< typename StackAllocator >
+ explicit coroutine( coroutine_fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >() ) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ typedef detail::coroutine_object<
+ Signature,
+ coroutine_fn, StackAllocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< coroutine_fn >( fn), attr, stack_alloc, a) );
+ }
+
+ template< typename StackAllocator, typename Allocator >
+ explicit coroutine( coroutine_fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ Allocator const& alloc) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ typedef detail::coroutine_object<
+ Signature,
+ coroutine_fn, StackAllocator, Allocator,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< coroutine_fn >( fn), attr, stack_alloc, a) );
+ }
+#endif
+ template< typename Fn >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+ stack_allocator const& stack_alloc =
+ stack_allocator(),
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, stack_allocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+ }
+
+ template< typename Fn >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, arguments arg, attributes const& attr = attributes(),
+ stack_allocator const& stack_alloc =
+ stack_allocator(),
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, stack_allocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), arg, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, arguments arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), arg, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator, typename Allocator >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ Allocator const& alloc,
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, Allocator,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator, typename Allocator >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, arguments arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ Allocator const& alloc,
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, Allocator,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), arg, attr, stack_alloc, a) );
+ }
+#else
+ template< typename Fn >
+ explicit coroutine( Fn fn, attributes const& attr = attributes(),
+ stack_allocator const& stack_alloc =
+ stack_allocator(),
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, stack_allocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn >
+ explicit coroutine( Fn fn, arguments arg, attributes const& attr = attributes(),
+ stack_allocator const& stack_alloc =
+ stack_allocator(),
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, stack_allocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, arg, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator >
+ explicit coroutine( Fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator, typename Allocator >
+ explicit coroutine( Fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ Allocator const& alloc,
+ typename disable_if<
+ is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, Allocator,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+ stack_allocator const& stack_alloc =
+ stack_allocator(),
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, stack_allocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ std::allocator< coroutine > const& alloc =
+ std::allocator< coroutine >(),
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, std::allocator< coroutine >,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+ }
+
+ template< typename Fn, typename StackAllocator, typename Allocator >
+ explicit coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ Allocator const& alloc,
+ typename disable_if<
+ is_same< typename decay< Fn >::type, coroutine >,
+ dummy *
+ >::type = 0) :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ {
+ BOOST_STATIC_ASSERT((
+ is_same< void, typename result_of< Fn() >::type >::value));
+ typedef detail::coroutine_object<
+ Signature,
+ Fn, StackAllocator, Allocator,
+ caller_type,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ > object_t;
+ typename object_t::allocator_t a( alloc);
+ impl_ = ptr_t(
+ // placement new
+ ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+ }
+#endif
+
+ coroutine( BOOST_RV_REF( coroutine) other) BOOST_NOEXCEPT :
+ detail::coroutine_op<
+ Signature,
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ detail::coroutine_get<
+ coroutine< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ impl_()
+ { swap( other); }
+
+ coroutine & operator=( BOOST_RV_REF( coroutine) other) BOOST_NOEXCEPT
+ {
+ coroutine tmp( boost::move( other) );
+ swap( tmp);
+ return * this;
+ }
+
+ bool empty() const BOOST_NOEXCEPT
+ { return ! impl_; }
+
+ operator safe_bool() const BOOST_NOEXCEPT
+ { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; }
+
+ bool operator!() const BOOST_NOEXCEPT
+ { return empty() || impl_->is_complete(); }
+
+ void swap( coroutine & other) BOOST_NOEXCEPT
+ { impl_.swap( other.impl_); }
+};
+
+template< typename Signature >
+void swap( coroutine< Signature > & l, coroutine< Signature > & r) BOOST_NOEXCEPT
+{ l.swap( r); }
+
+template< typename Signature >
+inline
+typename coroutine< Signature >::iterator
+range_begin( coroutine< Signature > & c)
+{ return typename coroutine< Signature >::iterator( & c); }
+
+template< typename Signature >
+inline
+typename coroutine< Signature >::const_iterator
+range_begin( coroutine< Signature > const& c)
+{ return typename coroutine< Signature >::const_iterator( & c); }
+
+template< typename Signature >
+inline
+typename coroutine< Signature >::iterator
+range_end( coroutine< Signature > & c)
+{ return typename coroutine< Signature >::iterator(); }
+
+template< typename Signature >
+inline
+typename coroutine< Signature >::const_iterator
+range_end( coroutine< Signature > const& c)
+{ return typename coroutine< Signature >::const_iterator(); }
+
+}
+
+template< typename Signature >
+struct range_mutable_iterator< coroutines::coroutine< Signature > >
+{ typedef typename coroutines::coroutine< Signature >::iterator type; };
+
+template< typename Signature >
+struct range_const_iterator< coroutines::coroutine< Signature > >
+{ typedef typename coroutines::coroutine< Signature >::const_iterator type; };
+
+}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_COROUTINE_H
Added: trunk/boost/coroutine/detail/arg.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/arg.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,61 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_ARG_H
+#define BOOST_COROUTINES_DETAIL_ARG_H
+
+#include <boost/config.hpp>
+#include <boost/preprocessor/arithmetic/add.hpp>
+#include <boost/preprocessor/arithmetic/sub.hpp>
+#include <boost/preprocessor/cat.hpp>
+#include <boost/preprocessor/punctuation/comma_if.hpp>
+#include <boost/preprocessor/repetition/repeat_from_to.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/type_traits/function_traits.hpp>
+
+#include <boost/coroutine/detail/config.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template<
+ typename Signature,
+ int arity = function_traits< Signature >::arity >
+struct arg;
+
+template< typename Signature >
+struct arg< Signature, 1 >
+{
+ typedef typename function_traits< Signature >::arg1_type type;
+};
+
+#define BOOST_CONTEXT_TUPLE_COMMA(n) BOOST_PP_COMMA_IF(BOOST_PP_SUB(n,1))
+#define BOOST_CONTEXT_TUPLE_TYPE(z,n,unused) \
+ BOOST_CONTEXT_TUPLE_COMMA(n) typename function_traits< Signature >::BOOST_PP_CAT(BOOST_PP_CAT(arg,n),_type)
+#define BOOST_CONTEXT_TUPLE_TYPES(n) BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(n,1),BOOST_CONTEXT_TUPLE_TYPE,~)
+#define BOOST_CONTEXT_TUPLE(z,n,unused) \
+template< typename Signature > \
+struct arg< Signature, n > \
+{ \
+ typedef tuple< BOOST_CONTEXT_TUPLE_TYPES(n) > type; \
+};
+BOOST_PP_REPEAT_FROM_TO(2,11,BOOST_CONTEXT_TUPLE,~)
+#undef BOOST_CONTEXT_TUPLE
+#undef BOOST_CONTEXT_TUPLE_TYPES
+#undef BOOST_CONTEXT_TUPLE_TYPE
+#undef BOOST_CONTEXT_TUPLE_COMMA
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_ARG_H
Added: trunk/boost/coroutine/detail/config.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/config.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,42 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_CONFIG_H
+#define BOOST_COROUTINES_DETAIL_CONFIG_H
+
+#include <boost/config.hpp>
+#include <boost/detail/workaround.hpp>
+
+#ifdef BOOST_COROUTINES_DECL
+# undef BOOST_COROUTINES_DECL
+#endif
+
+#if defined(BOOST_HAS_DECLSPEC)
+# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES_DYN_LINK)
+# if ! defined(BOOST_DYN_LINK)
+# define BOOST_DYN_LINK
+# endif
+# if defined(BOOST_COROUTINES_SOURCE)
+# define BOOST_COROUTINES_DECL BOOST_SYMBOL_EXPORT
+# else
+# define BOOST_COROUTINES_DECL BOOST_SYMBOL_IMPORT
+# endif
+# endif
+#endif
+
+#if ! defined(BOOST_COROUTINES_DECL)
+# define BOOST_COROUTINES_DECL
+#endif
+
+#if ! defined(BOOST_COROUTINES_SOURCE) && ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_COROUTINES_NO_LIB)
+# define BOOST_LIB_NAME boost_context
+# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES_DYN_LINK)
+# define BOOST_DYN_LINK
+# endif
+# include <boost/config/auto_link.hpp>
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_CONFIG_H
Added: trunk/boost/coroutine/detail/coroutine_base.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/coroutine_base.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,103 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_COROUTINE_BASE_H
+#define BOOST_COROUTINES_DETAIL_COROUTINE_BASE_H
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/context/fcontext.hpp>
+#include <boost/exception_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/type_traits/function_traits.hpp>
+#include <boost/utility.hpp>
+
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/detail/coroutine_base_resume.hpp>
+#include <boost/coroutine/detail/flags.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template< typename Signature >
+class coroutine_base : private noncopyable,
+ public coroutine_base_resume<
+ Signature,
+ coroutine_base< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >
+{
+public:
+ typedef intrusive_ptr< coroutine_base > ptr_t;
+
+private:
+ template< typename X, typename Y, typename Z, int >
+ friend class coroutine_base_resume;
+ template< typename X, typename Y, typename Z, typename A, typename B, typename C, int >
+ friend class coroutine_object;
+
+ unsigned int use_count_;
+ context::fcontext_t caller_;
+ context::fcontext_t * callee_;
+ int flags_;
+ exception_ptr except_;
+
+protected:
+ virtual void deallocate_object() = 0;
+
+public:
+ coroutine_base( context::fcontext_t * callee, bool unwind, bool preserve_fpu) :
+ coroutine_base_resume<
+ Signature,
+ coroutine_base< Signature >,
+ typename function_traits< Signature >::result_type,
+ function_traits< Signature >::arity
+ >(),
+ use_count_( 0),
+ caller_(),
+ callee_( callee),
+ flags_( 0),
+ except_()
+ {
+ if ( unwind) flags_ |= flag_force_unwind;
+ if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+ }
+
+ virtual ~coroutine_base()
+ {}
+
+ bool force_unwind() const BOOST_NOEXCEPT
+ { return 0 != ( flags_ & flag_force_unwind); }
+
+ bool unwind_requested() const BOOST_NOEXCEPT
+ { return 0 != ( flags_ & flag_unwind_stack); }
+
+ bool preserve_fpu() const BOOST_NOEXCEPT
+ { return 0 != ( flags_ & flag_preserve_fpu); }
+
+ bool is_complete() const BOOST_NOEXCEPT
+ { return 0 != ( flags_ & flag_complete); }
+
+ friend inline void intrusive_ptr_add_ref( coroutine_base * p) BOOST_NOEXCEPT
+ { ++p->use_count_; }
+
+ friend inline void intrusive_ptr_release( coroutine_base * p) BOOST_NOEXCEPT
+ { if ( --p->use_count_ == 0) p->deallocate_object(); }
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_COROUTINE_BASE_H
Added: trunk/boost/coroutine/detail/coroutine_base_resume.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/coroutine_base_resume.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,237 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_COROUTINE_BASE_RESUME_H
+#define BOOST_COROUTINES_DETAIL_COROUTINE_BASE_RESUME_H
+
+#include <iterator>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/context/fcontext.hpp>
+#include <boost/optional.hpp>
+#include <boost/preprocessor/arithmetic/add.hpp>
+#include <boost/preprocessor/arithmetic/sub.hpp>
+#include <boost/preprocessor/cat.hpp>
+#include <boost/preprocessor/punctuation/comma_if.hpp>
+#include <boost/preprocessor/repetition/repeat_from_to.hpp>
+#include <boost/range.hpp>
+
+#include <boost/coroutine/detail/arg.hpp>
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/detail/exceptions.hpp>
+#include <boost/coroutine/detail/holder.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template< typename Signature, typename D, typename Result, int arity >
+class coroutine_base_resume;
+
+template< typename Signature, typename D >
+class coroutine_base_resume< Signature, D, void, 0 >
+{
+public:
+ void resume()
+ {
+ BOOST_ASSERT( static_cast< D * >( this)->callee_);
+
+ holder< void > hldr_to( & static_cast< D * >( this)->caller_);
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx,
+ static_cast< D * >( this)->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ static_cast< D * >( this)->preserve_fpu() ) ) );
+ static_cast< D * >( this)->callee_ = hldr_from->ctx;
+ if ( hldr_from->force_unwind) throw forced_unwind();
+ if ( static_cast< D * >( this)->except_)
+ rethrow_exception( static_cast< D * >( this)->except_);
+ }
+};
+
+template< typename Signature, typename D, typename Result >
+class coroutine_base_resume< Signature, D, Result, 0 >
+{
+public:
+ void resume()
+ {
+ BOOST_ASSERT( static_cast< D * >( this));
+ BOOST_ASSERT( ! static_cast< D * >( this)->is_complete() );
+ BOOST_ASSERT( static_cast< D * >( this)->callee_);
+
+ holder< void > hldr_to( & static_cast< D * >( this)->caller_);
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx,
+ static_cast< D * >( this)->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ static_cast< D * >( this)->preserve_fpu() ) ) );
+ static_cast< D * >( this)->callee_ = hldr_from->ctx;
+ result_ = hldr_from->data;
+ if ( hldr_from->force_unwind) throw forced_unwind();
+ if ( static_cast< D * >( this)->except_)
+ rethrow_exception( static_cast< D * >( this)->except_);
+ }
+
+protected:
+ template< typename X, typename Y, int >
+ friend struct coroutine_get;
+
+ optional< Result > result_;
+};
+
+template< typename Signature, typename D >
+class coroutine_base_resume< Signature, D, void, 1 >
+{
+public:
+ typedef typename arg< Signature >::type arg_type;
+
+ void resume( arg_type a1)
+ {
+ BOOST_ASSERT( static_cast< D * >( this));
+ BOOST_ASSERT( ! static_cast< D * >( this)->is_complete() );
+ BOOST_ASSERT( static_cast< D * >( this)->callee_);
+
+ holder< arg_type > hldr_to( & static_cast< D * >( this)->caller_, a1);
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx,
+ static_cast< D * >( this)->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ static_cast< D * >( this)->preserve_fpu() ) ) );
+ static_cast< D * >( this)->callee_ = hldr_from->ctx;
+ if ( hldr_from->force_unwind) throw forced_unwind();
+ if ( static_cast< D * >( this)->except_)
+ rethrow_exception( static_cast< D * >( this)->except_);
+ }
+};
+
+template< typename Signature, typename D, typename Result >
+class coroutine_base_resume< Signature, D, Result, 1 >
+{
+public:
+ typedef typename arg< Signature >::type arg_type;
+
+ void resume( arg_type a1)
+ {
+ BOOST_ASSERT( static_cast< D * >( this));
+ BOOST_ASSERT( ! static_cast< D * >( this)->is_complete() );
+ BOOST_ASSERT( static_cast< D * >( this)->callee_);
+
+ context::fcontext_t caller;
+ holder< arg_type > hldr_to( & static_cast< D * >( this)->caller_, a1);
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx,
+ static_cast< D * >( this)->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ static_cast< D * >( this)->preserve_fpu() ) ) );
+ static_cast< D * >( this)->callee_ = hldr_from->ctx;
+ result_ = hldr_from->data;
+ if ( hldr_from->force_unwind) throw forced_unwind();
+ if ( static_cast< D * >( this)->except_)
+ rethrow_exception( static_cast< D * >( this)->except_);
+ }
+
+protected:
+ template< typename X, typename Y, int >
+ friend struct coroutine_get;
+
+ optional< Result > result_;
+};
+
+#define BOOST_COROUTINE_BASE_RESUME_COMMA(n) BOOST_PP_COMMA_IF(BOOST_PP_SUB(n,1))
+#define BOOST_COROUTINE_BASE_RESUME_VAL(z,n,unused) BOOST_COROUTINE_BASE_RESUME_COMMA(n) BOOST_PP_CAT(a,n)
+#define BOOST_COROUTINE_BASE_RESUME_VALS(n) BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(n,1),BOOST_COROUTINE_BASE_RESUME_VAL,~)
+#define BOOST_COROUTINE_BASE_RESUME_ARG_TYPE(n) \
+ typename function_traits< Signature >::BOOST_PP_CAT(BOOST_PP_CAT(arg,n),_type)
+#define BOOST_COROUTINE_BASE_RESUME_ARG(z,n,unused) BOOST_COROUTINE_BASE_RESUME_COMMA(n) BOOST_COROUTINE_BASE_RESUME_ARG_TYPE(n) BOOST_PP_CAT(a,n)
+#define BOOST_COROUTINE_BASE_RESUME_ARGS(n) BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(n,1),BOOST_COROUTINE_BASE_RESUME_ARG,~)
+#define BOOST_COROUTINE_BASE_RESUME(z,n,unused) \
+template< typename Signature, typename D > \
+class coroutine_base_resume< Signature, D, void, n > \
+{ \
+public: \
+ typedef typename arg< Signature >::type arg_type; \
+\
+ void resume( BOOST_COROUTINE_BASE_RESUME_ARGS(n)) \
+ { \
+ BOOST_ASSERT( static_cast< D * >( this)); \
+ BOOST_ASSERT( ! static_cast< D * >( this)->is_complete() ); \
+ BOOST_ASSERT( static_cast< D * >( this)->callee_); \
+\
+ holder< arg_type > hldr_to( \
+ & static_cast< D * >( this)->caller_, \
+ arg_type(BOOST_COROUTINE_BASE_RESUME_VALS(n) ) ); \
+ holder< void > * hldr_from( \
+ reinterpret_cast< holder< void > * >( context::jump_fcontext( \
+ hldr_to.ctx, \
+ static_cast< D * >( this)->callee_, \
+ reinterpret_cast< intptr_t >( & hldr_to), \
+ static_cast< D * >( this)->preserve_fpu() ) ) ); \
+ static_cast< D * >( this)->callee_ = hldr_from->ctx; \
+ if ( hldr_from->force_unwind) throw forced_unwind(); \
+ if ( static_cast< D * >( this)->except_) \
+ rethrow_exception( static_cast< D * >( this)->except_); \
+ } \
+}; \
+\
+template< typename Signature, typename D, typename Result > \
+class coroutine_base_resume< Signature, D, Result, n > \
+{ \
+public: \
+ typedef typename arg< Signature >::type arg_type; \
+\
+ void resume( BOOST_COROUTINE_BASE_RESUME_ARGS(n)) \
+ { \
+ BOOST_ASSERT( static_cast< D * >( this)); \
+ BOOST_ASSERT( ! static_cast< D * >( this)->is_complete() ); \
+ BOOST_ASSERT( static_cast< D * >( this)->callee_); \
+\
+ holder< arg_type > hldr_to( \
+ & static_cast< D * >( this)->caller_, \
+ arg_type(BOOST_COROUTINE_BASE_RESUME_VALS(n) ) ); \
+ holder< Result > * hldr_from( \
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext( \
+ hldr_to.ctx, \
+ static_cast< D * >( this)->callee_, \
+ reinterpret_cast< intptr_t >( & hldr_to), \
+ static_cast< D * >( this)->preserve_fpu() ) ) ); \
+ static_cast< D * >( this)->callee_ = hldr_from->ctx; \
+ result_ = hldr_from->data; \
+ if ( hldr_from->force_unwind) throw forced_unwind(); \
+ if ( static_cast< D * >( this)->except_) \
+ rethrow_exception( static_cast< D * >( this)->except_); \
+ } \
+\
+protected: \
+ template< typename X, typename Y, int > \
+ friend struct coroutine_get; \
+\
+ optional< Result > result_; \
+};
+BOOST_PP_REPEAT_FROM_TO(2,11,BOOST_COROUTINE_BASE_RESUME,~)
+#undef BOOST_COROUTINE_BASE_RESUME
+#undef BOOST_COROUTINE_BASE_RESUME_ARGS
+#undef BOOST_COROUTINE_BASE_RESUME_ARG
+#undef BOOST_COROUTINE_BASE_RESUME_ARG_TYPE
+#undef BOOST_COROUTINE_BASE_RESUME_VALS
+#undef BOOST_COROUTINE_BASE_RESUME_VAL
+#undef BOOST_COROUTINE_BASE_RESUME_COMMA
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_coroutine_base_resume_H
Added: trunk/boost/coroutine/detail/coroutine_caller.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/coroutine_caller.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,57 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_COROUTINE_CALLER_H
+#define BOOST_COROUTINES_DETAIL_COROUTINE_CALLER_H
+
+#include <boost/config.hpp>
+#include <boost/context/fcontext.hpp>
+
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/detail/coroutine_base.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template< typename Signature, typename Allocator >
+class coroutine_caller : public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_caller< Signature, Allocator >
+ >::other allocator_t;
+
+ coroutine_caller( context::fcontext_t * callee, bool unwind, bool preserve_fpu,
+ allocator_t const& alloc) BOOST_NOEXCEPT :
+ coroutine_base< Signature >( callee, unwind, preserve_fpu),
+ alloc_( alloc)
+ {}
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+
+private:
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_caller * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_COROUTINE_CALLER_H
Added: trunk/boost/coroutine/detail/coroutine_get.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/coroutine_get.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,54 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_COROUTINE_GET_H
+#define BOOST_COROUTINES_DETAIL_COROUTINE_GET_H
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/type_traits/function_traits.hpp>
+
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/detail/param.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template<
+ typename D,
+ typename Result, int arity
+>
+struct coroutine_get;
+
+template< typename D, int arity >
+struct coroutine_get< D, void, arity >
+{};
+
+template< typename D, typename Result, int arity >
+struct coroutine_get
+{
+ bool has_result() const
+ { return static_cast< D const* >( this)->impl_->result_; }
+
+ typename param< Result >::type get() const
+ {
+ BOOST_ASSERT( static_cast< D const* >( this)->impl_->result_);
+ return static_cast< D const* >( this)->impl_->result_.get();
+ }
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_COROUTINE_GET_H
Added: trunk/boost/coroutine/detail/coroutine_object.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/coroutine_object.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,83 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_COROUTINE_OBJECT_H
+#define BOOST_COROUTINES_DETAIL_COROUTINE_OBJECT_H
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/exception_ptr.hpp>
+#include <boost/move/move.hpp>
+#include <boost/ref.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/type_traits/function_traits.hpp>
+
+#include <boost/coroutine/attributes.hpp>
+#include <boost/coroutine/detail/arg.hpp>
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/detail/coroutine_base.hpp>
+#include <boost/coroutine/detail/exceptions.hpp>
+#include <boost/coroutine/detail/flags.hpp>
+#include <boost/coroutine/detail/holder.hpp>
+#include <boost/coroutine/detail/param.hpp>
+#include <boost/coroutine/flags.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template< typename Context >
+void trampoline1( intptr_t vp)
+{
+ BOOST_ASSERT( vp);
+
+ holder< Context * > * hldr(
+ reinterpret_cast< holder< Context * > * >( vp) );
+ Context * ctx( hldr->data.get() );
+
+ ctx->run( hldr->ctx);
+}
+
+template< typename Context, typename Arg >
+void trampoline2( intptr_t vp)
+{
+ BOOST_ASSERT( vp);
+
+ holder< tuple< Context *, Arg > > * hldr(
+ reinterpret_cast< holder< tuple< Context *, Arg > > * >( vp) );
+ Context * ctx( hldr->data.get().get< 0 >() );
+ Arg arg( hldr->data.get().get< 1 >() );
+
+ ctx->run( hldr->ctx, arg);
+}
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ typename Result, int arity
+>
+class coroutine_object;
+
+#include <boost/coroutine/detail/coroutine_object_void_0.ipp>
+#include <boost/coroutine/detail/coroutine_object_void_1.ipp>
+#include <boost/coroutine/detail/coroutine_object_void_arity.ipp>
+#include <boost/coroutine/detail/coroutine_object_result_0.ipp>
+#include <boost/coroutine/detail/coroutine_object_result_1.ipp>
+#include <boost/coroutine/detail/coroutine_object_result_arity.ipp>
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_COROUTINE_OBJECT_H
Added: trunk/boost/coroutine/detail/coroutine_object_result_0.ipp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/coroutine_object_result_0.ipp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,394 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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)
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ typename Result
+>
+class coroutine_object< Signature, Fn, StackAllocator, Allocator, Caller, Result, 0 > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, Result, 0
+ >
+ >::other allocator_t;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object const&);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< void > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( forward< Fn >( fn) ),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+#else
+ coroutine_object( Fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+#endif
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ holder< Result > hldr_to( & caller);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ hldr_to.ctx, callee,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ typename Result
+>
+class coroutine_object< Signature, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, 0 > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, Result, 0
+ >
+ >::other allocator_t;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object const&);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< void > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+ coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ holder< Result > hldr_to( & caller);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ hldr_to.ctx, callee,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ typename Result
+>
+class coroutine_object< Signature, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, 0 > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, Result, 0
+ >
+ >::other allocator_t;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object const&);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< void > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+ coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ holder< Result > hldr_to( & caller);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ hldr_to.ctx, callee,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
Added: trunk/boost/coroutine/detail/coroutine_object_result_1.ipp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/coroutine_object_result_1.ipp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,565 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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)
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ typename Result
+>
+class coroutine_object< Signature, Fn, StackAllocator, Allocator, Caller, Result, 1 > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, Result, 1
+ >
+ >::other allocator_t;
+ typedef typename arg< Signature >::type arg_type;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object &);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void enter_( typename detail::param< arg_type >::type arg)
+ {
+ holder<
+ tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >
+ > hldr_to(
+ & this->caller_, tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >( this, arg) );
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void run_( Caller & c)
+ {
+ context::fcontext_t * callee( 0);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< Result > hldr_to( & caller);
+ context::jump_fcontext(
+ hldr_to.ctx, callee,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< arg_type > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( forward< Fn >( fn) ),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( forward< Fn >( fn) ),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+#else
+ coroutine_object( Fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( Fn fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+#endif
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ run_( c);
+ }
+
+ void run( context::fcontext_t * callee, typename detail::param< arg_type >::type arg)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ c.impl_->result_ = arg;
+ run_( c);
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ typename Result
+>
+class coroutine_object< Signature, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, 1 > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, Result, 1
+ >
+ >::other allocator_t;
+ typedef typename arg< Signature >::type arg_type;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object &);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void enter_( typename detail::param< arg_type >::type arg)
+ {
+ holder<
+ tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >
+ > hldr_to(
+ & this->caller_, tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >( this, arg) );
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void run_( Caller & c)
+ {
+ context::fcontext_t * callee( 0);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< Result > hldr_to( & caller);
+ context::jump_fcontext(
+ hldr_to.ctx, callee,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< arg_type > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+ coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( reference_wrapper< Fn > fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ run_( c);
+ }
+
+ void run( context::fcontext_t * callee, typename detail::param< arg_type >::type arg)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ c.impl_->result_ = arg;
+ run_( c);
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ typename Result
+>
+class coroutine_object< Signature, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, 1 > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, Result, 1
+ >
+ >::other allocator_t;
+ typedef typename arg< Signature >::type arg_type;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object &);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void enter_( typename detail::param< arg_type >::type arg)
+ {
+ holder<
+ tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >
+ > hldr_to(
+ & this->caller_, tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >( this, arg) );
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void run_( Caller & c)
+ {
+ context::fcontext_t * callee( 0);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< Result > hldr_to( & caller);
+ context::jump_fcontext(
+ hldr_to.ctx, callee,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< arg_type > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+ coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( const reference_wrapper< Fn > fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ run_( c);
+ }
+
+ void run( context::fcontext_t * callee, typename detail::param< arg_type >::type arg)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ c.impl_->result_ = arg;
+ run_( c);
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
Added: trunk/boost/coroutine/detail/coroutine_object_result_arity.ipp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/coroutine_object_result_arity.ipp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,565 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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)
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ typename Result, int arity
+>
+class coroutine_object :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, Result, arity
+ >
+ >::other allocator_t;
+ typedef typename arg< Signature >::type arg_type;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object &);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void enter_( typename detail::param< arg_type >::type arg)
+ {
+ holder<
+ tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >
+ > hldr_to(
+ & this->caller_, tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >( this, arg) );
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void run_( Caller & c)
+ {
+ context::fcontext_t * callee( 0);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< Result > hldr_to( & caller);
+ context::jump_fcontext(
+ hldr_to.ctx, callee,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< arg_type > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( forward< Fn >( fn) ),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( forward< Fn >( fn) ),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+#else
+ coroutine_object( Fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( Fn fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+#endif
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ run_( c);
+ }
+
+ void run( context::fcontext_t * callee, typename detail::param< arg_type >::type arg)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ c.impl_->result_ = arg;
+ run_( c);
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ typename Result, int arity
+>
+class coroutine_object< Signature, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, arity > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, Result, arity
+ >
+ >::other allocator_t;
+ typedef typename arg< Signature >::type arg_type;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object &);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void enter_( typename detail::param< arg_type >::type arg)
+ {
+ holder<
+ tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >
+ > hldr_to(
+ & this->caller_, tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >( this, arg) );
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void run_( Caller & c)
+ {
+ context::fcontext_t * callee( 0);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< Result > hldr_to( & caller);
+ context::jump_fcontext(
+ hldr_to.ctx, callee,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< arg_type > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+ coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( reference_wrapper< Fn > fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ run_( c);
+ }
+
+ void run( context::fcontext_t * callee, typename detail::param< arg_type >::type arg)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ c.impl_->result_ = arg;
+ run_( c);
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ typename Result, int arity
+>
+class coroutine_object< Signature, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, Result, arity > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, Result, arity
+ >
+ >::other allocator_t;
+ typedef typename arg< Signature >::type arg_type;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object &);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void enter_( typename detail::param< arg_type >::type arg)
+ {
+ holder<
+ tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >
+ > hldr_to(
+ & this->caller_, tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >( this, arg) );
+ holder< Result > * hldr_from(
+ reinterpret_cast< holder< Result > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ this->result_ = hldr_from->data;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void run_( Caller & c)
+ {
+ context::fcontext_t * callee( 0);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< Result > hldr_to( & caller);
+ context::jump_fcontext(
+ hldr_to.ctx, callee,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< arg_type > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+ coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( const reference_wrapper< Fn > fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ run_( c);
+ }
+
+ void run( context::fcontext_t * callee, typename detail::param< arg_type >::type arg)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ c.impl_->result_ = arg;
+ run_( c);
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
Added: trunk/boost/coroutine/detail/coroutine_object_void_0.ipp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/coroutine_object_void_0.ipp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,388 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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)
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller
+>
+class coroutine_object< Signature, Fn, StackAllocator, Allocator, Caller, void, 0 > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, void, 0
+ >
+ >::other allocator_t;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object const&);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< void > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( forward< Fn >( fn) ),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+#else
+ coroutine_object( Fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+#endif
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< void > hldr_to( & caller);
+ context::jump_fcontext(
+ hldr_to.ctx, callee,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller
+>
+class coroutine_object< Signature, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, void, 0 > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, void, 0
+ >
+ >::other allocator_t;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object const&);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< void > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+ coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< void > hldr_to( & caller);
+ context::jump_fcontext(
+ hldr_to.ctx, callee,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller
+>
+class coroutine_object< Signature, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, void, 0 > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, void, 0
+ >
+ >::other allocator_t;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object const&);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< void > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+ coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< void > hldr_to( & caller);
+ context::jump_fcontext(
+ hldr_to.ctx, callee,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
Added: trunk/boost/coroutine/detail/coroutine_object_void_1.ipp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/coroutine_object_void_1.ipp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,546 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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)
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller
+>
+class coroutine_object< Signature, Fn, StackAllocator, Allocator, Caller, void, 1 > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, void, 1
+ >
+ >::other allocator_t;
+ typedef typename arg< Signature >::type arg_type;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object &);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void enter_( typename detail::param< arg_type >::type arg)
+ {
+ holder< tuple< coroutine_object *, typename detail::param< arg_type >::type > > hldr_to(
+ & this->caller_, tuple< coroutine_object *, typename detail::param< arg_type >::type >( this, arg) );
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void run_( Caller & c)
+ {
+ context::fcontext_t * callee( 0);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< void > hldr( & caller);
+ context::jump_fcontext(
+ hldr.ctx, callee,
+ ( intptr_t) & hldr,
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< arg_type > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( forward< Fn >( fn) ),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( forward< Fn >( fn) ),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+#else
+ coroutine_object( Fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( Fn fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+#endif
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ run_( c);
+ }
+
+ void run( context::fcontext_t * callee, typename detail::param< arg_type >::type arg)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ c.impl_->result_ = arg;
+ run_( c);
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller
+>
+class coroutine_object< Signature, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, void, 1 > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, void, 1
+ >
+ >::other allocator_t;
+ typedef typename arg< Signature >::type arg_type;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object &);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void enter_( typename detail::param< arg_type >::type arg)
+ {
+ holder< tuple< coroutine_object *, typename detail::param< arg_type >::type > > hldr_to(
+ & this->caller_, tuple< coroutine_object *, typename detail::param< arg_type >::type >( this, arg) );
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void run_( Caller & c)
+ {
+ context::fcontext_t * callee( 0);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< void > hldr( & caller);
+ context::jump_fcontext(
+ hldr.ctx, callee,
+ ( intptr_t) & hldr,
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< arg_type > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+ coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( reference_wrapper< Fn > fn,
+ typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ run_( c);
+ }
+
+ void run( context::fcontext_t * callee, typename detail::param< arg_type >::type arg)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ c.impl_->result_ = arg;
+ run_( c);
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller
+>
+class coroutine_object< Signature, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, void, 1 > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, void, 1
+ >
+ >::other allocator_t;
+ typedef typename arg< Signature >::type arg_type;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object &);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void enter_( typename detail::param< arg_type >::type arg)
+ {
+ holder< tuple< coroutine_object *, typename detail::param< arg_type >::type > > hldr_to(
+ & this->caller_, tuple< coroutine_object *, typename detail::param< arg_type >::type >( this, arg) );
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void run_( Caller & c)
+ {
+ context::fcontext_t * callee( 0);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< void > hldr( & caller);
+ context::jump_fcontext(
+ hldr.ctx, callee,
+ ( intptr_t) & hldr,
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< arg_type > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+ coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( const reference_wrapper< Fn > fn,
+ typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ run_( c);
+ }
+
+ void run( context::fcontext_t * callee, typename detail::param< arg_type >::type arg)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ c.impl_->result_ = arg;
+ run_( c);
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
Added: trunk/boost/coroutine/detail/coroutine_object_void_arity.ipp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/coroutine_object_void_arity.ipp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,559 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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)
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ int arity
+>
+class coroutine_object< Signature, Fn, StackAllocator, Allocator, Caller, void, arity > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, void, arity
+ >
+ >::other allocator_t;
+ typedef typename arg< Signature >::type arg_type;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object &);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void enter_( typename detail::param< arg_type >::type arg)
+ {
+ holder<
+ tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >
+ > hldr_to(
+ & this->caller_, tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >( this, arg) );
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void run_( Caller & c)
+ {
+ context::fcontext_t * callee( 0);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< void > hldr( & caller);
+ context::jump_fcontext(
+ hldr.ctx, callee,
+ ( intptr_t) & hldr,
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< arg_type > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( forward< Fn >( fn) ),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( forward< Fn >( fn) ),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+#else
+ coroutine_object( Fn fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( Fn fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( BOOST_RV_REF( Fn) fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+#endif
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ run_( c);
+ }
+
+ void run( context::fcontext_t * callee, typename detail::param< arg_type >::type arg)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ c.impl_->result_ = arg;
+ run_( c);
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ int arity
+>
+class coroutine_object< Signature, reference_wrapper< Fn >, StackAllocator, Allocator, Caller, void, arity > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, void, arity
+ >
+ >::other allocator_t;
+ typedef typename arg< Signature >::type arg_type;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object &);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void enter_( typename detail::param< arg_type >::type arg)
+ {
+ holder<
+ tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >
+ > hldr_to(
+ & this->caller_, tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >( this, arg) );
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void run_( Caller & c)
+ {
+ context::fcontext_t * callee( 0);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< void > hldr( & caller);
+ context::jump_fcontext(
+ hldr.ctx, callee,
+ ( intptr_t) & hldr,
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< arg_type > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+ coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( reference_wrapper< Fn > fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ run_( c);
+ }
+
+ void run( context::fcontext_t * callee, typename detail::param< arg_type >::type arg)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ c.impl_->result_ = arg;
+ run_( c);
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
+
+template<
+ typename Signature,
+ typename Fn, typename StackAllocator, typename Allocator,
+ typename Caller,
+ int arity
+>
+class coroutine_object< Signature, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller, void, arity > :
+ public coroutine_base< Signature >
+{
+public:
+ typedef typename Allocator::template rebind<
+ coroutine_object<
+ Signature, Fn, StackAllocator, Allocator, Caller, void, arity
+ >
+ >::other allocator_t;
+ typedef typename arg< Signature >::type arg_type;
+
+private:
+ typedef coroutine_base< Signature > base_type;
+
+ Fn fn_;
+ context::stack_t stack_;
+ StackAllocator stack_alloc_;
+ allocator_t alloc_;
+
+ static void destroy_( allocator_t & alloc, coroutine_object * p)
+ {
+ alloc.destroy( p);
+ alloc.deallocate( p, 1);
+ }
+
+ coroutine_object( coroutine_object &);
+ coroutine_object & operator=( coroutine_object const&);
+
+ void enter_()
+ {
+ holder< coroutine_object * > hldr_to( & this->caller_, this);
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void enter_( typename detail::param< arg_type >::type arg)
+ {
+ holder<
+ tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >
+ > hldr_to(
+ & this->caller_, tuple< coroutine_object *,
+ typename detail::param< arg_type >::type >( this, arg) );
+ holder< void > * hldr_from(
+ reinterpret_cast< holder< void > * >( context::jump_fcontext(
+ hldr_to.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr_to),
+ this->preserve_fpu() ) ) );
+ this->callee_ = hldr_from->ctx;
+ if ( this->except_) rethrow_exception( this->except_);
+ }
+
+ void run_( Caller & c)
+ {
+ context::fcontext_t * callee( 0);
+ context::fcontext_t caller;
+ try
+ {
+ fn_( c);
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ holder< void > hldr( & caller);
+ context::jump_fcontext(
+ hldr.ctx, callee,
+ ( intptr_t) & hldr,
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+ catch ( forced_unwind const&)
+ {}
+ catch (...)
+ { this->except_ = current_exception(); }
+
+ this->flags_ |= flag_complete;
+ callee = c.impl_->callee_;
+ BOOST_ASSERT( callee);
+ context::jump_fcontext(
+ & caller, callee,
+ reinterpret_cast< intptr_t >( & caller),
+ this->preserve_fpu() );
+ BOOST_ASSERT_MSG( false, "coroutine is complete");
+ }
+
+ void unwind_stack_() BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT( ! this->is_complete() );
+
+ this->flags_ |= flag_unwind_stack;
+ holder< arg_type > hldr( & this->caller_, true);
+ context::jump_fcontext(
+ hldr.ctx, this->callee_,
+ reinterpret_cast< intptr_t >( & hldr),
+ this->preserve_fpu() );
+ this->flags_ &= ~flag_unwind_stack;
+
+ BOOST_ASSERT( this->is_complete() );
+ }
+
+public:
+ coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline1< coroutine_object >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_(); }
+
+ coroutine_object( const reference_wrapper< Fn > fn, typename detail::param< arg_type >::type arg, attributes const& attr,
+ StackAllocator const& stack_alloc,
+ allocator_t const& alloc) :
+ base_type(
+ context::make_fcontext(
+ stack_alloc.allocate( attr.size), attr.size,
+ trampoline2< coroutine_object, typename detail::param< arg_type >::type >),
+ stack_unwind == attr.do_unwind,
+ fpu_preserved == attr.preserve_fpu),
+ fn_( fn),
+ stack_( base_type::callee_->fc_stack),
+ stack_alloc_( stack_alloc),
+ alloc_( alloc)
+ { enter_( arg); }
+
+ ~coroutine_object()
+ {
+ if ( ! this->is_complete() && this->force_unwind() ) unwind_stack_();
+ stack_alloc_.deallocate( stack_.sp, stack_.size);
+ }
+
+ void run( context::fcontext_t * callee)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ run_( c);
+ }
+
+ void run( context::fcontext_t * callee, typename detail::param< arg_type >::type arg)
+ {
+ Caller c( callee, false, this->preserve_fpu(), alloc_);
+ c.impl_->result_ = arg;
+ run_( c);
+ }
+
+ void deallocate_object()
+ { destroy_( alloc_, this); }
+};
Added: trunk/boost/coroutine/detail/coroutine_op.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/coroutine_op.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,312 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_COROUTINE_OP_H
+#define BOOST_COROUTINES_DETAIL_COROUTINE_OP_H
+
+#include <iterator>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/context/fcontext.hpp>
+#include <boost/optional.hpp>
+#include <boost/preprocessor/arithmetic/add.hpp>
+#include <boost/preprocessor/arithmetic/sub.hpp>
+#include <boost/preprocessor/cat.hpp>
+#include <boost/preprocessor/punctuation/comma_if.hpp>
+#include <boost/preprocessor/repetition/repeat_from_to.hpp>
+#include <boost/type_traits/function_traits.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+
+#include <boost/coroutine/detail/arg.hpp>
+#include <boost/coroutine/detail/config.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template< typename Signature, typename D, typename Result, int arity >
+struct coroutine_op;
+
+template< typename Signature, typename D >
+struct coroutine_op< Signature, D, void, 0 >
+{
+ D & operator()()
+ {
+ BOOST_ASSERT( static_cast< D * >( this)->impl_);
+ BOOST_ASSERT( ! static_cast< D * >( this)->impl_->is_complete() );
+
+ static_cast< D * >( this)->impl_->resume();
+
+ return * static_cast< D * >( this);
+ }
+};
+
+template< typename Signature, typename D, typename Result >
+struct coroutine_op< Signature, D, Result, 0 >
+{
+ class iterator : public std::iterator< std::input_iterator_tag, typename remove_reference< Result >::type >
+ {
+ private:
+ D * dp_;
+ optional< Result > val_;
+
+ void fetch_()
+ {
+ BOOST_ASSERT( dp_);
+
+ if ( ! dp_->has_result() )
+ {
+ dp_ = 0;
+ val_ = none;
+ return;
+ }
+ val_ = dp_->get();
+ }
+
+ void increment_()
+ {
+ BOOST_ASSERT( dp_);
+ BOOST_ASSERT( * dp_);
+
+ ( * dp_)();
+ fetch_();
+ }
+
+ public:
+ typedef typename std::iterator_traits< iterator >::pointer pointer_t;
+ typedef typename std::iterator_traits< iterator >::reference reference_t;
+
+ iterator() :
+ dp_( 0), val_()
+ {}
+
+ explicit iterator( D * dp) :
+ dp_( dp), val_()
+ { fetch_(); }
+
+ iterator( iterator const& other) :
+ dp_( other.dp_), val_( other.val_)
+ {}
+
+ iterator & operator=( iterator const& other)
+ {
+ if ( this == & other) return * this;
+ dp_ = other.dp_;
+ val_ = other.val_;
+ return * this;
+ }
+
+ bool operator==( iterator const& other)
+ { return other.dp_ == dp_ && other.val_ == val_; }
+
+ bool operator!=( iterator const& other)
+ { return other.dp_ != dp_ || other.val_ != val_; }
+
+ iterator & operator++()
+ {
+ increment_();
+ return * this;
+ }
+
+ reference_t operator*() const
+ { return const_cast< optional< Result > & >( val_).get(); }
+
+ pointer_t operator->() const
+ { return const_cast< optional< Result > & >( val_).get_ptr(); }
+ };
+
+ class const_iterator : public std::iterator< std::input_iterator_tag, typename remove_reference< const Result >::type >
+ {
+ private:
+ D * dp_;
+ optional< const Result > val_;
+
+ void fetch_()
+ {
+ BOOST_ASSERT( dp_);
+
+ if ( ! dp_->has_result() )
+ {
+ dp_ = 0;
+ val_ = none;
+ return;
+ }
+ val_ = dp_->get();
+ }
+
+ void increment_()
+ {
+ BOOST_ASSERT( dp_);
+ BOOST_ASSERT( * dp_);
+
+ ( * dp_)();
+ fetch_();
+ }
+
+ public:
+ typedef typename std::iterator_traits< iterator >::pointer pointer_t;
+ typedef typename std::iterator_traits< iterator >::reference reference_t;
+
+ const_iterator() :
+ dp_( 0), val_()
+ {}
+
+ explicit const_iterator( D * dp) :
+ dp_( dp), val_()
+ { fetch_(); }
+
+ const_iterator( const_iterator const& other) :
+ dp_( other.dp_), val_( other.val_)
+ {}
+
+ const_iterator & operator=( const_iterator const& other)
+ {
+ if ( this == & other) return * this;
+ dp_ = other.dp_;
+ val_ = other.val_;
+ return * this;
+ }
+
+ bool operator==( const_iterator const& other)
+ { return other.dp_ == dp_ && other.val_ == val_; }
+
+ bool operator!=( const_iterator const& other)
+ { return other.dp_ != dp_ || other.val_ != val_; }
+
+ const_iterator & operator++()
+ {
+ increment_();
+ return * this;
+ }
+
+ reference_t operator*() const
+ { return val_.get(); }
+
+ pointer_t operator->() const
+ { return val_.get_ptr(); }
+ };
+
+ D & operator()()
+ {
+ BOOST_ASSERT( static_cast< D * >( this)->impl_);
+ BOOST_ASSERT( ! static_cast< D * >( this)->impl_->is_complete() );
+
+ static_cast< D * >( this)->impl_->resume();
+
+ return * static_cast< D * >( this);
+ }
+};
+
+template< typename Signature, typename D >
+struct coroutine_op< Signature, D, void, 1 >
+{
+ typedef typename arg< Signature >::type arg_type;
+
+ class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void >
+ {
+ private:
+ D * dp_;
+
+ public:
+ iterator() :
+ dp_( 0)
+ {}
+
+ explicit iterator( D * dp) :
+ dp_( dp)
+ {}
+
+ iterator & operator=( arg_type a1)
+ {
+ BOOST_ASSERT( dp_);
+ if ( ! ( * dp_)( a1) ) dp_ = 0;
+ return * this;
+ }
+
+ bool operator==( iterator const& other)
+ { return other.dp_ == dp_; }
+
+ bool operator!=( iterator const& other)
+ { return other.dp_ != dp_; }
+
+ iterator & operator*()
+ { return * this; }
+
+ iterator & operator++()
+ { return * this; }
+ };
+
+ struct const_iterator;
+
+ D & operator()( arg_type a1)
+ {
+ BOOST_ASSERT( static_cast< D * >( this)->impl_);
+ BOOST_ASSERT( ! static_cast< D * >( this)->impl_->is_complete() );
+
+ static_cast< D * >( this)->impl_->resume( a1);
+
+ return * static_cast< D * >( this);
+ }
+};
+
+template< typename Signature, typename D, typename Result >
+struct coroutine_op< Signature, D, Result, 1 >
+{
+ typedef typename arg< Signature >::type arg_type;
+
+ D & operator()( arg_type a1)
+ {
+ BOOST_ASSERT( static_cast< D * >( this)->impl_);
+ BOOST_ASSERT( ! static_cast< D * >( this)->impl_->is_complete() );
+
+ static_cast< D * >( this)->impl_->resume( a1);
+
+ return * static_cast< D * >( this);
+ }
+};
+
+#define BOOST_COROUTINE_OP_COMMA(n) BOOST_PP_COMMA_IF(BOOST_PP_SUB(n,1))
+#define BOOST_COROUTINE_OP_VAL(z,n,unused) BOOST_COROUTINE_OP_COMMA(n) BOOST_PP_CAT(a,n)
+#define BOOST_COROUTINE_OP_VALS(n) BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(n,1),BOOST_COROUTINE_OP_VAL,~)
+#define BOOST_COROUTINE_OP_ARG_TYPE(n) \
+ typename function_traits< Signature >::BOOST_PP_CAT(BOOST_PP_CAT(arg,n),_type)
+#define BOOST_COROUTINE_OP_ARG(z,n,unused) BOOST_COROUTINE_OP_COMMA(n) BOOST_COROUTINE_OP_ARG_TYPE(n) BOOST_PP_CAT(a,n)
+#define BOOST_COROUTINE_OP_ARGS(n) BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(n,1),BOOST_COROUTINE_OP_ARG,~)
+#define BOOST_COROUTINE_OP(z,n,unused) \
+template< typename Signature, typename D, typename Result > \
+struct coroutine_op< Signature, D, Result, n > \
+{ \
+ D & operator()( BOOST_COROUTINE_OP_ARGS(n)) \
+ { \
+ BOOST_ASSERT( static_cast< D * >( this)->impl_); \
+ BOOST_ASSERT( ! static_cast< D * >( this)->impl_->is_complete() ); \
+\
+ static_cast< D * >( this)->impl_->resume(BOOST_COROUTINE_OP_VALS(n)); \
+\
+ return * static_cast< D * >( this); \
+ } \
+};
+BOOST_PP_REPEAT_FROM_TO(2,11,BOOST_COROUTINE_OP,~)
+#undef BOOST_COROUTINE_OP
+#undef BOOST_COROUTINE_OP_ARGS
+#undef BOOST_COROUTINE_OP_ARG
+#undef BOOST_COROUTINE_OP_ARG_TYPE
+#undef BOOST_COROUTINE_OP_VALS
+#undef BOOST_COROUTINE_OP_VAL
+#undef BOOST_COROUTINE_OP_COMMA
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_COROUTINE_OP_H
Added: trunk/boost/coroutine/detail/exceptions.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/exceptions.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,28 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_EXCEPTIONs_H
+#define BOOST_COROUTINES_DETAIL_EXCEPTIONs_H
+
+#include <boost/config.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+struct forced_unwind {};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_EXCEPTIONs_H
Added: trunk/boost/coroutine/detail/flags.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/flags.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,34 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_FLAGS_H
+#define BOOST_COROUTINES_DETAIL_FLAGS_H
+
+#include <boost/config.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+enum flag_t
+{
+ flag_complete = 1 << 1,
+ flag_unwind_stack = 1 << 2,
+ flag_force_unwind = 1 << 3,
+ flag_preserve_fpu = 1 << 4
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_FLAGS_H
Added: trunk/boost/coroutine/detail/holder.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/holder.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,88 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_HOLDER_H
+#define BOOST_COROUTINES_DETAIL_HOLDER_H
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/optional.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template< typename Data >
+struct holder
+{
+ context::fcontext_t * ctx;
+ optional< Data > data;
+ bool force_unwind;
+
+ holder( context::fcontext_t * ctx_) :
+ ctx( ctx_), data(), force_unwind( false)
+ { BOOST_ASSERT( ctx); }
+
+ holder( context::fcontext_t * ctx_, Data data_) :
+ ctx( ctx_), data( data_), force_unwind( false)
+ { BOOST_ASSERT( ctx); }
+
+ holder( context::fcontext_t * ctx_, bool force_unwind_) :
+ ctx( ctx_), data(), force_unwind( force_unwind_)
+ {
+ BOOST_ASSERT( ctx);
+ BOOST_ASSERT( force_unwind);
+ }
+
+ holder( holder const& other) :
+ ctx( other.ctx), data( other.data),
+ force_unwind( other.force_unwind)
+ {}
+
+ holder & operator=( holder const& other)
+ {
+ if ( this == & other) return * this;
+ ctx = other.ctx;
+ data = other.data;
+ force_unwind = other.force_unwind;
+ return * this;
+ }
+};
+
+template<>
+struct holder< void >
+{
+ context::fcontext_t * ctx;
+ bool force_unwind;
+
+ holder( context::fcontext_t * ctx_, bool force_unwind_ = false) :
+ ctx( ctx_), force_unwind( force_unwind_)
+ { BOOST_ASSERT( ctx); }
+
+ holder( holder const& other) :
+ ctx( other.ctx), force_unwind( other.force_unwind)
+ {}
+
+ holder & operator=( holder const& other)
+ {
+ if ( this == & other) return * this;
+ ctx = other.ctx;
+ force_unwind = other.force_unwind;
+ return * this;
+ }
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_HOLDER_H
Added: trunk/boost/coroutine/detail/param.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/param.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,46 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_PARAM_H
+#define BOOST_COROUTINES_DETAIL_PARAM_H
+
+#include <boost/config.hpp>
+#include <boost/mpl/eval_if.hpp>
+#include <boost/mpl/identity.hpp>
+#include <boost/mpl/or.hpp>
+#include <boost/type_traits/add_reference.hpp>
+#include <boost/type_traits/is_reference.hpp>
+#include <boost/type_traits/is_scalar.hpp>
+#include <boost/type_traits/is_stateless.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template< typename T >
+struct param :
+ public mpl::eval_if<
+ mpl::or_<
+ is_scalar< T >,
+ is_stateless< T >,
+ is_reference< T >
+ >,
+ mpl::identity< T >,
+ add_reference< T >
+ >
+{};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_PARAM_H
Added: trunk/boost/coroutine/detail/stack_allocator_posix.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/stack_allocator_posix.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,165 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_STACK_ALLOCATOR_H
+#define BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H
+
+#include <boost/config.hpp>
+
+extern "C" {
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+}
+
+//#if _POSIX_C_SOURCE >= 200112L
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
+#include <stdexcept>
+
+#include <boost/assert.hpp>
+#include <boost/context/fcontext.hpp>
+#include <boost/context/detail/config.hpp>
+
+#if !defined (SIGSTKSZ)
+# define SIGSTKSZ (8 * 1024)
+# define UDEF_SIGSTKSZ
+#endif
+
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+inline
+std::size_t pagesize()
+{
+ // conform to POSIX.1-2001
+ static std::size_t size = ::sysconf( _SC_PAGESIZE);
+ return size;
+}
+
+inline
+rlimit stacksize_limit_()
+{
+ rlimit limit;
+ // conforming to POSIX.1-2001
+ const int result = ::getrlimit( RLIMIT_STACK, & limit);
+ BOOST_ASSERT( 0 == result);
+ return limit;
+}
+
+inline
+rlimit stacksize_limit()
+{
+ static rlimit limit = stacksize_limit_();
+ return limit;
+}
+
+inline
+std::size_t page_count( std::size_t stacksize)
+{
+ return static_cast< std::size_t >(
+ std::ceil(
+ static_cast< float >( stacksize) / pagesize() ) );
+}
+
+class stack_allocator
+{
+public:
+ static bool is_stack_unbound()
+ { return RLIM_INFINITY == stacksize_limit().rlim_max; }
+
+ static std::size_t default_stacksize()
+ {
+ std::size_t size = 8 * minimum_stacksize();
+ if ( is_stack_unbound() ) return size;
+
+ BOOST_ASSERT( maximum_stacksize() >= minimum_stacksize() );
+ return maximum_stacksize() == size
+ ? size
+ : std::min( size, maximum_stacksize() );
+ }
+
+ static std::size_t minimum_stacksize()
+ { return SIGSTKSZ + sizeof( context::fcontext_t) + 15; }
+
+ static std::size_t maximum_stacksize()
+ {
+ BOOST_ASSERT( ! is_stack_unbound() );
+ return static_cast< std::size_t >( stacksize_limit().rlim_max);
+ }
+
+ void * allocate( std::size_t size) const
+ {
+ BOOST_ASSERT( minimum_stacksize() <= size);
+ BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= size) );
+
+ const std::size_t pages( page_count( size) + 1); // add one guard page
+ const std::size_t size_( pages * pagesize() );
+ BOOST_ASSERT( 0 < size && 0 < size_);
+
+ const int fd( ::open("/dev/zero", O_RDONLY) );
+ BOOST_ASSERT( -1 != fd);
+ // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L)
+ void * limit =
+# if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+ ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+# else
+ ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+# endif
+ ::close( fd);
+ if ( ! limit) throw std::bad_alloc();
+
+ std::memset( limit, size_, '\0');
+
+ // conforming to POSIX.1-2001
+ const int result( ::mprotect( limit, pagesize(), PROT_NONE) );
+ BOOST_ASSERT( 0 == result);
+
+ return static_cast< char * >( limit) + size_;
+ }
+
+ void deallocate( void * vp, std::size_t size) const
+ {
+ BOOST_ASSERT( vp);
+ BOOST_ASSERT( minimum_stacksize() <= size);
+ BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= size) );
+
+ const std::size_t pages = page_count( size) + 1;
+ const std::size_t size_ = pages * pagesize();
+ BOOST_ASSERT( 0 < size && 0 < size_);
+ void * limit = static_cast< char * >( vp) - size_;
+ // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L)
+ ::munmap( limit, size_);
+ }
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#ifdef UDEF_SIGSTKSZ
+# undef SIGSTKSZ
+#endif
+
+//#endif
+
+#endif // BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H
Added: trunk/boost/coroutine/detail/stack_allocator_windows.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/detail/stack_allocator_windows.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,160 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_STACK_ALLOCATOR_H
+#define BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H
+
+#include <boost/config.hpp>
+
+extern "C" {
+#include <windows.h>
+}
+
+//#if defined (BOOST_WINDOWS) || _POSIX_C_SOURCE >= 200112L
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
+#include <stdexcept>
+
+#include <boost/assert.hpp>
+#include <boost/context/detail/config.hpp>
+#include <boost/context/fcontext.hpp>
+
+# if defined(BOOST_MSVC)
+# pragma warning(push)
+# pragma warning(disable:4244 4267)
+# endif
+
+// x86_64
+// test x86_64 before i386 because icc might
+// define __i686__ for x86_64 too
+#if defined(__x86_64__) || defined(__x86_64) \
+ || defined(__amd64__) || defined(__amd64) \
+ || defined(_M_X64) || defined(_M_AMD64)
+
+// Windows seams not to provide a constant or function
+// telling the minimal stacksize
+# define MIN_STACKSIZE 8 * 1024
+#else
+# define MIN_STACKSIZE 4 * 1024
+#endif
+
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+inline
+SYSTEM_INFO system_info_()
+{
+ SYSTEM_INFO si;
+ ::GetSystemInfo( & si);
+ return si;
+}
+
+inline
+SYSTEM_INFO system_info()
+{
+ static SYSTEM_INFO si = system_info_();
+ return si;
+}
+
+inline
+std::size_t pagesize()
+{ return static_cast< std::size_t >( system_info().dwPageSize); }
+
+inline
+std::size_t page_count( std::size_t stacksize)
+{
+ return static_cast< std::size_t >(
+ std::ceil(
+ static_cast< float >( stacksize) / pagesize() ) );
+}
+
+class stack_allocator
+{
+public:
+ // Windows seams not to provide a limit for the stacksize
+ static bool is_stack_unbound()
+ { return true; }
+
+ static std::size_t default_stacksize()
+ {
+ using namespace std;
+
+ std::size_t size = 64 * 1024; // 64 kB
+ if ( is_stack_unbound() )
+ return max( size, minimum_stacksize() );
+
+ BOOST_ASSERT( maximum_stacksize() >= minimum_stacksize() );
+ return maximum_stacksize() == minimum_stacksize()
+ ? minimum_stacksize()
+ : min( size, maximum_stacksize() );
+ }
+
+ // because Windows seams not to provide a limit for minimum stacksize
+ static std::size_t minimum_stacksize()
+ { return MIN_STACKSIZE; }
+
+ // because Windows seams not to provide a limit for maximum stacksize
+ // maximum_stacksize() can never be called (pre-condition ! is_stack_unbound() )
+ static std::size_t maximum_stacksize()
+ {
+ BOOST_ASSERT( ! is_stack_unbound() );
+ return 1 * 1024 * 1024 * 1024; // 1GB
+ }
+
+ void * allocate( std::size_t size) const
+ {
+ BOOST_ASSERT( minimum_stacksize() <= size);
+ BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= size) );
+
+ const std::size_t pages( page_count( size) + 1); // add one guard page
+ const std::size_t size_ = pages * pagesize();
+ BOOST_ASSERT( 0 < size && 0 < size_);
+
+ void * limit = ::VirtualAlloc( 0, size_, MEM_COMMIT, PAGE_READWRITE);
+ if ( ! limit) throw std::bad_alloc();
+
+ std::memset( limit, size_, '\0');
+
+ DWORD old_options;
+ const BOOL result = ::VirtualProtect(
+ limit, pagesize(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options);
+ BOOST_ASSERT( FALSE != result);
+
+ return static_cast< char * >( limit) + size_;
+ }
+
+ void deallocate( void * vp, std::size_t size) const
+ {
+ BOOST_ASSERT( vp);
+ BOOST_ASSERT( minimum_stacksize() <= size);
+ BOOST_ASSERT( is_stack_unbound() || ( maximum_stacksize() >= size) );
+
+ const std::size_t pages = page_count( size) + 1;
+ const std::size_t size_ = pages * pagesize();
+ BOOST_ASSERT( 0 < size && 0 < size_);
+ void * limit = static_cast< char * >( vp) - size_;
+ ::VirtualFree( limit, 0, MEM_RELEASE);
+ }
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+//#endif
+
+#endif // BOOST_COROUTINES_DETAIL_STACK_ALLOCATOR_H
Added: trunk/boost/coroutine/flags.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/flags.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,27 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_FLAGS_H
+#define BOOST_COROUTINES_FLAGS_H
+
+namespace boost {
+namespace coroutines {
+
+enum flag_unwind_t
+{
+ stack_unwind = 0,
+ no_stack_unwind
+};
+
+enum flag_fpu_t
+{
+ fpu_preserved = 0,
+ fpu_not_preserved
+};
+
+}}
+
+#endif // BOOST_COROUTINES_FLAGS_H
Added: trunk/boost/coroutine/stack_allocator.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/coroutine/stack_allocator.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,23 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_STACK_ALLOCATOR_H
+#define BOOST_COROUTINES_STACK_ALLOCATOR_H
+
+#include <boost/config.hpp>
+
+#if defined (BOOST_WINDOWS)
+#include <boost/coroutine/detail/stack_allocator_windows.hpp>
+#else
+#include <boost/coroutine/detail/stack_allocator_posix.hpp>
+#endif
+
+namespace boost {
+namespace coroutines {
+using detail::stack_allocator;
+}}
+
+#endif // BOOST_COROUTINES_STACK_ALLOCATOR_H
Added: trunk/libs/coroutine/doc/Jamfile.v2
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/doc/Jamfile.v2 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,25 @@
+# (C) Copyright 2008 Anthony Williams
+#
+# 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)
+
+xml coro : coro.qbk ;
+
+boostbook standalone
+ :
+ coro
+ :
+ # HTML options first:
+ # How far down we chunk nested sections, basically all of them:
+ <xsl:param>chunk.section.depth=3
+ # Don't put the first section on the same page as the TOC:
+ <xsl:param>chunk.first.sections=1
+ # How far down sections get TOC's
+ <xsl:param>toc.section.depth=10
+ # Max depth in each TOC:
+ <xsl:param>toc.max.depth=3
+ # How far down we go with TOC's
+ <xsl:param>generate.section.toc.level=10
+ # Path for links to Boost:
+ <xsl:param>boost.root=../../../..
+ ;
Added: trunk/libs/coroutine/doc/acknowledgements.qbk
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/doc/acknowledgements.qbk 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,17 @@
+[/
+ Copyright Oliver Kowalke 2009.
+ 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
+]
+
+[section:acknowledgements Acknowledgments]
+
+I'd like to thank Alex Hagen-Zanker, Christopher Kormanyos, Conrad Poelman,
+Eugene Yakubovich, Giovanni Piero Deretta, Hartmut Kaiser, Jeffrey Lee Hellrung,
+Nat Goodspeed, Robert Stewart, Vicente J. Botet Escriba and Yuriy Krasnoschek.
+
+Especially Eugene Yakubovich, Giovanni Piero Deretta and Vicente J. Botet
+Escriba contributed many good ideas during the review.
+
+[endsect]
Added: trunk/libs/coroutine/doc/attributes.qbk
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/doc/attributes.qbk 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,120 @@
+[/
+ Copyright Oliver Kowalke 2009.
+ 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
+]
+
+[section:attributes Attributes]
+
+Class `attributes` is used to transfers parameters required to setup a
+coroutines's context.
+
+ struct attributes
+ {
+ std::size_t size;
+ flag_unwind_t do_unwind;
+ bool preserve_fpu;
+
+ attributes() BOOST_NOEXCEPT :
+ size( ctx::default_stacksize() ),
+ do_unwind( stack_unwind),
+ preserve_fpu( true)
+ {}
+
+ explicit attributes( std::size_t size_) BOOST_NOEXCEPT :
+ size( size_),
+ do_unwind( stack_unwind),
+ preserve_fpu( true)
+ {}
+
+ explicit attributes( flag_unwind_t do_unwind_) BOOST_NOEXCEPT :
+ size( ctx::default_stacksize() ),
+ do_unwind( do_unwind_),
+ preserve_fpu( true)
+ {}
+
+ explicit attributes( bool preserve_fpu_) BOOST_NOEXCEPT :
+ size( ctx::default_stacksize() ),
+ do_unwind( stack_unwind),
+ preserve_fpu( preserve_fpu_)
+ {}
+
+ explicit attributes(
+ std::size_t size_,
+ flag_unwind_t do_unwind_) BOOST_NOEXCEPT :
+ size( size_),
+ do_unwind( do_unwind_),
+ preserve_fpu( true)
+ {}
+
+ explicit attributes(
+ std::size_t size_,
+ bool preserve_fpu_) BOOST_NOEXCEPT :
+ size( size_),
+ do_unwind( stack_unwind),
+ preserve_fpu( preserve_fpu_)
+ {}
+
+ explicit attributes(
+ flag_unwind_t do_unwind_,
+ bool preserve_fpu_) BOOST_NOEXCEPT :
+ size( ctx::default_stacksize() ),
+ do_unwind( do_unwind_),
+ preserve_fpu( preserve_fpu_)
+ {}
+ };
+
+[heading `attributes()`]
+[variablelist
+[[Effects:] [Default constructor using `ctx::default_stacksize()`, does unwind
+the stack after coroutine/generator is complete and preserves FPU registers.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `attributes( std::size_t size)`]
+[variablelist
+[[Effects:] [Argument `size` defines stack size of the inner `context`.
+Stack unwinding after termination and preserving FPU registers is set by
+default.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `attributes( flag_unwind_t do_unwind)`]
+[variablelist
+[[Effects:] [Argument `do_unwind` determines if stack will be unwound after
+termination or not. The default stacksize is used for the inner `context`
+and FPU registers are preserved.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `attributes( bool preserve_fpu)`]
+[variablelist
+[[Effects:] [Argument `preserve_fpu` determines if FPU register have to be
+preserved if a `context` switches. THe default stacksize is used for the
+inner `context` and the stack will be unwound after termination.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `attributes( std::size_t size, flag_unwind_t do_unwind)`]
+[variablelist
+[[Effects:] [Arguments `size` and `do_unwind` are given by the user.
+FPU registers preserved during each `context` switch.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `attributes( std::size_t size, bool preserve_fpu)`]
+[variablelist
+[[Effects:] [Arguments `size` and `preserve_fpu` are given by the user.
+The stack is automatically unwound after coroutine/generator terminates.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `attributes( flag_unwind_t do_unwind, bool preserve_fpu)`]
+[variablelist
+[[Effects:] [Arguments `do_unwind` and `preserve_fpu` are given by the user.
+The stack gets a default value of `ctx::default_stacksize()`.]]
+[[Throws:] [Nothing.]]
+]
+
+[endsect]
Added: trunk/libs/coroutine/doc/coro.qbk
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/doc/coro.qbk 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,82 @@
+[/
+ Copyright Oliver Kowalke 2009.
+ 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
+]
+
+[article Coroutine
+ [quickbook 1.5]
+ [authors [Kowalke, Oliver]]
+ [copyright 2009 Oliver Kowalke]
+ [purpose C++ Library providing coroutine facility]
+ [category text]
+ [license
+ 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])
+ ]
+]
+
+
+[def __boost_build__ [*Boost.Build]]
+[def __boost_context__ [*Boost.Context]]
+[def __boost_coroutine__ [*Boost.Coroutine]]
+[def __boost_exception__ [*Boost.Exception]]
+[def __boost_function_types__ [*Boost.FunctionTypes]]
+[def __boost_move__ [*Boost.Move]]
+[def __boost_mpl__ [*Boost.MPL]]
+[def __boost_optional__ [*Boost.Optional]]
+[def __boost_preprocessor__ [*Boost.Preprocessor]]
+[def __boost_range__ [*Boost.Range]]
+[def __boost_result_of__ [*Boost.ResultOf]]
+[def __boost_smart_ptr__ [*Boost.SmartPtr]]
+[def __boost_static_assert__ [*Boost.StaticAssert]]
+[def __boost_tuple__ [*Boost.Tuple]]
+[def __boost_type_traits__ [*Boost.TypeTraits]]
+[def __boost_utility__ [*Boost.Utility]]
+[def __boost_version__ [*Boost-1.52.0]]
+
+[def __ctx__ ['context]]
+[def __coro__ ['coroutine]]
+[def __coro_fn__ ['coroutine-function]]
+[def __coros__ ['coroutines]]
+[def __not_a_coro__ ['not-a-coroutine]]
+[def __signature__ ['Signature]]
+[def __stack_allocator__ ['stack-allocator]]
+[def __stack_allocator_concept__ ['stack-allocator concept]]
+[def __stack__ ['stack]]
+[def __tls__ ['thread-local-storage]]
+
+[def __args__ ['boost::coroutines::coroutine<>::arguments]]
+[def __attrs__ ['boost::coroutines::attributes]]
+[def __begin__ ['boost::begin()]]
+[def __bind__ ['boost::bind()]]
+[def __coro_allocator__ ['boost::coroutines::stack_allocator]]
+[def __coro_bool__ ['boost::coroutines::coroutine<>::operator bool]]
+[def __coro_caller__ ['boost::coroutines::coroutine<>::caller_type]]
+[def __coro_get__ ['boost::coroutines::coroutine<>::get()]]
+[def __coro_ns__ ['boost::coroutines]]
+[def __coro_op__ ['boost::coroutines::coroutine<>::operator()]]
+[def __end__ ['boost::end()]]
+[def __fcontext__ ['boost::contexts::fcontext_t]]
+[def __fetch__ ['inbuf::fetch()]]
+[def __forced_unwind__ ['boost::coroutines::detail::forced_unwind]]
+[def __getline__ ['std::getline()]]
+[def __handle_read__ ['session::handle_read()]]
+[def __io_service__ ['boost::asio::io_sevice]]
+[def __server__ ['server]]
+[def __session__ ['session]]
+[def __start__ ['session::start()]]
+[def __thread__ ['boost::thread]]
+[def __tie__ ['boost::tie]]
+[def __tuple__ ['boost::tuple<>]]
+[def __underflow__ ['stream_buf::underflow()]]
+
+[include overview.qbk]
+[include intro.qbk]
+[include coroutine.qbk]
+[include attributes.qbk]
+[include stack.qbk]
+[include performance.qbk]
+[include acknowledgements.qbk]
Added: trunk/libs/coroutine/doc/coroutine.qbk
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/doc/coroutine.qbk 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,795 @@
+[/
+ Copyright Oliver Kowalke 2009.
+ 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
+]
+
+[section:coroutine Coroutine]
+
+Each instance of __coro__ has its own context of execution (CPU registers and
+stack space) or represents __not_a_coro__ (similar to __thread__).
+Objects of type __coro__ are moveable but not copyable and can be returned by a
+function.
+
+ boost::coroutines::coroutine< void() > f();
+
+ void g()
+ {
+ boost::coroutines::coroutine< void() > c( f() );
+ c();
+ }
+
+[note __boost_move__ is used to emulate rvalue references.]
+
+
+[heading Creating a coroutine]
+
+A new __coro__ is created from a __coro_fn__ (function or functor) which will be
+executed in a new __ctx__ (CPU registers and stack space).
+
+[note __coro_fn__ is required to return ['void] and accept a reference of type
+__coro_caller__.]
+
+The template argument __signature__ determines the data-types transferred to
+__coro_fn__ and from __coro_fn__ by calling __coro_op__ and __coro_get__.
+
+ typedef boost::coroutines::coroutine< int( std::string const&) > coro_t;
+
+ void f( coro_t::caller_type & ca)
+ {
+ ...
+ // access argument
+ std::string str( ca.get() );
+ ...
+ ca( 7);
+ ...
+ }
+
+ std::string str;
+ ...
+ coro_t c( f);
+ // pass argument
+ c( str);
+ // returned value
+ int res = c.get();
+
+
+The __coro_fn__ is started at __coro__ construction (similar to __thread__)
+in a newly created __coro__ complete with registers, flags, stack and
+instruction pointer.
+If __coro_fn__ requires some arguments (types defined by __signature__)
+on start-up those parameters must be applied to the __coro__ constructor.
+A single arguments can be passed as it is:
+
+ typedef boost::coroutines::coroutine< int( std::string const&) > coro_t;
+
+ void f( coro_t::caller_type & ca);
+
+ std::string str("abc");
+ coro_t c( f, str);
+
+
+For multiple arguments __args__ must be used (it is a typedef of __tuple__):
+
+ typedef boost::coroutines::coroutine< int( int, std::string const&) > coro_t;
+
+ void f( coro_t::caller_type & ca);
+
+ std::string str("abc");
+ coro_t c( f, coro_t::arguments( 7, str) );
+
+
+[note The maximum number of arguments is limited to 10 (limit defined by
+__boost_tuple__).]
+
+[note Parameters bound with __bind__ to __coro_fn__ will not be part of the
+__coro_op__ signature.]
+
+__attrs__, an additional constructor argument of __coro__, defines the stack
+size, stack unwinding and floating-point preserving behaviour used for __ctx__
+construction.
+
+The __coro__ constructor uses the __stack_allocator_concept__ to allocate an
+associated stack, and the destructor uses the same __stack_allocator_concept__
+to deallocate the stack. The default __stack_allocator_concept__ is
+__stack_allocator__, but a custom stack-allocator can be passed to the
+constructor.
+
+
+[heading Calling a coroutine]
+
+The execution control is transferred to __coro__ at construction (__coro_fn__
+entered) - when control should be returned to the original calling routine,
+invoke __coro_op__ on the first argument of type __coro_caller__ inside
+__coro_fn__. __coro_caller__ is a typedef of __coro__ with an inverted
+__signature__. Inverted __signature__ means that the return type becomes an
+argument and vice versa. Multiple arguments are wrapped into __tuple__.
+
+ void f( boost::coroutines::coroutine< std::string const&( int) & ca);
+ boost::coroutines::coroutine< int( std::string const&) > c1( f);
+
+ void g( boost::coroutines::coroutine< boost::tuple< X, Y >( int) & ca);
+ boost::coroutines::coroutine< int( X, X) > c2( g);
+
+
+The current coroutine information (registers, flags, and stack and instruction
+pointer) is saved and the original context information is restored. Calling
+__coro_op__ resumes execution in the coroutine after saving the new state of the
+original routine.
+
+ typedef boost::coroutines::coroutine< void() > coro_t;
+
+ // void fn( boost::coroutines::coroutine< void() > & ca, int j)
+ void fn( coro_t::caller_type & ca, int j)
+ {
+ for( int i = 0; i < j; ++i)
+ {
+ std::cout << "fn(): local variable i == " << i << std::endl;
+
+ // save current coroutine
+ // value of local variable is preserved
+ // transfer execution control back to main()
+ ca();
+
+ // coroutine<>::operator()() was called
+ // execution control transferred back from main()
+ }
+ }
+
+ int main( int argc, char * argv[])
+ {
+ // bind parameter '7' to coroutine-fn
+ coro_t c( boost::bind( fn, _1, 7) );
+
+ std::cout << "main() starts coroutine c" << std::endl;
+
+ while ( c)
+ {
+ std::cout << "main() calls coroutine c" << std::endl;
+ // execution control is transferred to c
+ c();
+ }
+
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+ }
+
+ output:
+ main() starts coroutine c
+ fn(): local variable i == 0
+ main() calls coroutine c
+ fn(): local variable i == 1
+ main() calls coroutine c
+ fn(): local variable i == 2
+ main() calls coroutine c
+ fn(): local variable i == 3
+ main() calls coroutine c
+ fn(): local variable i == 4
+ main() calls coroutine c
+ fn(): local variable i == 5
+ main() calls coroutine c
+ fn(): local variable i == 6
+ main() calls coroutine c
+ Done
+
+[warning Calling __coro_op__ from inside the [_same] coroutine results in
+undefined behaviour.]
+
+
+[heading Transfer of data]
+
+__signature__, the template argument of __coro__, defines the types transferred
+to and returned from the __coro_fn__, e.g. it determines the signature of
+__coro_op__ and the return-type of __coro_get__.
+
+[note __coro_caller__ is not part of __signature__ and __coro_fn__ is required
+to return void and accept __coro_caller__ as argument.]
+
+__coro_op__ accepts arguments as defined in __signature__ and returns a
+reference to __coro__. The arguments passed to __coro_op__, in one coroutine,
+is returned (as a __tuple__) by __coro_get__ in the other coroutine.
+If __coro__ is constructed and arguments are passed to the constructor, the
+__coro_fn__ will be entered and the arguments are accessed thorough __coro_get__
+in __coro_fn__ on entry.
+
+The value given to __coro_op__ of __coro_caller__, in one coroutine, is returned by
+__coro_get__ in the other routine.
+
+ typedef boost::coroutines::coroutine< int( int) > coro_t;
+
+ void fn( coro_t::caller_type & ca)
+ {
+ // access the integer argument given to coroutine ctor
+ int i = ca.get();
+ std::cout << "fn(): local variable i == " << i << std::endl;
+
+ // save current coroutine context and
+ // transfer execution control back to caller
+ // pass content of variable 'i' to caller
+ // after execution control is returned back coroutine<>::operator()
+ // returns and the transferred integer s accessed via coroutine<>::get()
+ i = ca( i).get();
+
+ // i == 10 because c( 10) in main()
+ std::cout << "fn(): local variable i == " << i << std::endl;
+ ca( i);
+ }
+
+ int main( int argc, char * argv[])
+ {
+ std::cout << "main(): call coroutine c" << std::endl;
+ coro_t c( fn, 7);
+
+ int x = c.get();
+ std::cout << "main(): transferred value: " << x << std::endl;
+
+ x = c( 10).get();
+ std::cout << "main(): transferred value: " << x << std::endl;
+
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+ }
+
+ output:
+ main(): call coroutine c
+ fn(): local variable i == 7
+ main(): transferred value: 7
+ fn(): local variable i == 10
+ main(): transferred value: 10
+ Done
+
+
+[heading __coro_fn__ with multiple arguments]
+
+If __coro_fn__ has more than one argument __coro_op__ has the same size of
+arguments and __coro_get__ from __coro_caller__ returns a __tuple__ corresponding
+to the arguments of __signature__. __tie__ helps to access the values stored in
+the __tuple__ returned by __coro_get__.
+
+ typedef boost::coroutines::coroutine< int(int,int) > coro_t;
+
+ void fn( coro_t::caller_type & ca)
+ {
+ int a, b;
+ boost::tie( a, b) = ca.get();
+ boost::tie( a, b) = ca( a + b).get();
+ ca( a + b);
+ }
+
+ int main( int argc, char * argv[])
+ {
+ std::cout << "main(): call coroutine c" << std::endl;
+ coro_t coro( fn, coro_t::arguments( 3, 7) );
+
+ int res = coro.get();
+ std::cout << "main(): 3 + 7 == " << res << std::endl;
+
+ res = coro( 5, 7).get();
+ std::cout << "main(): 5 + 7 == " << res << std::endl;
+
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+ }
+
+ output:
+ main(): call coroutine c
+ main(): 3 + 7 == 10
+ main(): 5 + 7 == 12
+ Done
+
+
+[heading Transfer of pointers and references]
+
+You can transfer references and pointers from and to coroutines but as usual
+you must take care (scope, no re-assignment of const references etc.).
+In the following code `x` points to `local` which is allocated on stack of
+`c`. When `c` goes out of scope the stack becomes deallocated. Using `x`
+after `c` is gone will fail!
+
+ struct X
+ {
+ void g();
+ };
+
+ typedef boost::coroutines::coroutine< X*() > coro_t;
+
+ void fn( coro_t::caller_t & ca) {
+ X local;
+ ca( & local);
+ }
+
+ int main() {
+ X * x = 0;
+ {
+ coro_t c( fn);
+ x = c.get(); // let x point to X on stack owned by c
+ // stack gets unwound -> X will be destructed
+ }
+ x->g(); // segmentation fault!
+ return EXIT_SUCCESS;
+ }
+
+
+[heading Range iterators]
+
+__boost_coroutine__ provides output- and input-iterators using __boost_range__.
+`coroutine< T() >` can be used via output-iterators using __begin__ and __end__.
+
+ typedef boost::coroutines::coroutine< int() > coro_t;
+ typedef boost::range_iterator< coro_t >::type iterator_t;
+
+ void power( coro_t::caller_type & ca, int number, int exponent)
+ {
+ int counter = 0;
+ int result = 1;
+ while ( counter++ < exponent)
+ {
+ result = result * number;
+ ca( result);
+ }
+ }
+
+ int main()
+ {
+ coro_t c( boost::bind( power, _1, 2, 8) );
+ iterator_t e( boost::end( c) );
+ for ( iterator_t i( boost::begin( c) ); i != e; ++i)
+ std::cout << * i << " ";
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+ }
+
+ output:
+ 2 4 8 16 32 64 128 256
+ Done
+
+`BOOST_FOREACH` can be used to iterate over the coroutine range too.
+
+ typedef boost::coroutines::coroutine< int() > coro_t;
+ typedef boost::range_iterator< coro_t >::type iterator_t;
+
+ void power( coro_t::caller_type & ca, int number, int exponent)
+ {
+ int counter = 0;
+ int result = 1;
+ while ( counter++ < exponent)
+ {
+ result = result * number;
+ ca( result);
+ }
+ }
+
+ int main()
+ {
+ coro_t c( boost::bind( power, _1, 2, 8) );
+ BOOST_FOREACH( int i, c)
+ { std::cout << i << " "; }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+ }
+
+ output:
+ 2 4 8 16 32 64 128 256
+ Done
+
+
+Input iterators are created from coroutines of type `coroutine< void( T) >`.
+
+
+
+[heading Exit a __coro_fn__]
+
+__coro_fn__ is exited with a simple return statement jumping back to the calling
+routine. The __coro__ becomes complete, e.g. __coro_bool__ will return 'false'.
+
+ typedef boost::coroutines::coroutine< int(int,int) > coro_t;
+
+ void fn( coro_t::caller_type & ca)
+ {
+ int a, b;
+ boost::tie( a, b) = ca.get();
+ boost::tie( a, b) = ca( a + b).get();
+ ca( a + b);
+ }
+
+ int main( int argc, char * argv[])
+ {
+ std::cout << "main(): call coroutine c" << std::endl;
+ coro_t coro( fn, coro_t::arguments( 3, 7) );
+
+ BOOST_ASSERT( coro);
+ int res = coro.get();
+ std::cout << "main(): 3 + 7 == " << res << std::endl;
+
+ res = coro( 5, 7).get();
+ BOOST_ASSERT( ! coro);
+ std::cout << "main(): 5 + 7 == " << res << std::endl;
+
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+ }
+
+ output:
+ main(): call coroutine c
+ main(): 3 + 7 == 10
+ main(): 5 + 7 == 12
+ Done
+
+[important After returning from __coro_fn__ the __coro__ is complete (can not
+resumed with __coro_op__).]
+
+
+[heading Exceptions in __coro_fn__]
+
+An exception thrown inside __coro_fn__ will transferred via exception-pointer
+(see __boost_exception__ for details) and re-thrown by constructor or
+__coro_op__.
+
+ typedef boost::coroutines::coroutine< void() > coro_t;
+
+ void fn( coro_t::caller_type & ca)
+ {
+ ca();
+ throw std::runtime_error("abc");
+ }
+
+ int main( int argc, char * argv[])
+ {
+ coro_t c( f);
+ try
+ {
+ c();
+ }
+ catch ( std::exception const& e)
+ {
+ std::cout << "exception catched:" << e.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+ }
+
+ output:
+ exception catched: abc
+
+[important Code executed by coroutine must not prevent the propagation of the
+__forced_unwind__ exception. Absorbing that exception will cause stack
+unwinding to fail. Thus, any code that catches all exceptions must re-throw the
+pending exception.]
+
+ try
+ {
+ // code that might throw
+ }
+ catch( forced_unwind)
+ {
+ throw;
+ }
+ catch(...)
+ {
+ // possibly not re-throw pending exception
+ }
+
+
+[heading Stack unwinding]
+
+Sometimes it is necessary to unwind the stack of an unfinished coroutine to
+destroy local stack variables so they can release allocated resources (RAII
+pattern). The third argument of the coroutine constructor, `do_unwind`,
+indicates whether the destructor should unwind the stack (stack is unwound by
+default).
+
+Stack unwinding assumes the following preconditions:
+
+* The coroutine is not __not_a_coro__
+* The coroutine is not complete
+* The coroutine is not running
+* The coroutine owns a stack
+
+After unwinding, a __coro__ is complete.
+
+
+ typedef boost::coroutines::coroutine< void() > coro_t;
+
+ struct X
+ {
+ X()
+ { std::cout << "X()" << std::endl; }
+
+ ~X()
+ { std::cout << "~X()" << std::endl; }
+ };
+
+ void fn( coro_t::caller_type & ca)
+ {
+ X x;
+
+ for ( int = 0;; ++i)
+ {
+ std::cout << "fn(): " << i << std::endl;
+ // transfer execution control back to main()
+ ca();
+ }
+ }
+
+ int main( int argc, char * argv[])
+ {
+ {
+ coro_t c( fn,
+ boost::coroutines::attributes(
+ boost::ctx::default_stacksize(),
+ boost::coroutines::stack_unwind) );
+
+ c();
+ c();
+ c();
+ c();
+ c();
+
+ std::cout << "c is complete: " << std::boolalpha << c.is_complete() << "\n";
+ }
+
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+ }
+
+ output:
+ X()
+ fn(): 0
+ fn(): 1
+ fn(): 2
+ fn(): 3
+ fn(): 4
+ fn(): 5
+ c is complete: false
+ ~X()
+ Done
+
+[important You must not swallow __forced_unwind__ exceptions!]
+
+
+[heading FPU preserving]
+
+Some applications do not use floating-point registers and can disable preserving
+fpu registers for performance reasons.
+
+[note According to the calling convetion the FPU registers are preserved by default.]
+
+
+[section:coroutine Class `coroutine`]
+
+ #include <boost/coroutine/coroutine.hpp>
+
+ template< typename Signature >
+ class coroutine;
+
+ template<
+ typename R,
+ typename ArgTypes...
+ >
+ class coroutine< R ( ArgTypes...) >
+ {
+ public:
+ typedef unspec-type caller_type;
+ typedef unspec-type arguments;
+
+ coroutine();
+
+ template<
+ typename Fn,
+ typename StackAllocator = stack_allocator,
+ typename Allocator = std::allocator< coroutine >
+ >
+ coroutine( Fn fn, attributes const& attr = attributes(),
+ StackAllocator const& stack_alloc = StackAllocator(),
+ Allocator const& alloc = Allocator() );
+
+ template<
+ typename Fn,
+ typename StackAllocator = stack_allocator,
+ typename Allocator = std::allocator< coroutine >
+ >
+ coroutine( Fn fn, arguments const& args,
+ attributes const& attr = attributes(),
+ StackAllocator const& stack_alloc = StackAllocator(),
+ Allocator const& alloc = Allocator() );
+
+ template<
+ typename Fn,
+ typename StackAllocator = stack_allocator,
+ typename Allocator = std::allocator< coroutine >
+ >
+ coroutine( Fn && fn, attributes const& attr = attributes(),
+ StackAllocator stack_alloc = StackAllocator(),
+ Allocator const& alloc = Allocator() );
+
+ template<
+ typename Fn,
+ typename StackAllocator = stack_allocator,
+ typename Allocator = std::allocator< coroutine >
+ >
+ coroutine( Fn && fn arguments const& args,
+ attributes const& attr = attributes(),
+ StackAllocator stack_alloc = StackAllocator(),
+ Allocator const& alloc = Allocator() );
+
+ coroutine( coroutine && other);
+
+ coroutine & operator=( coroutine && other);
+
+ operator unspecified-bool-type() const;
+
+ bool operator!() const;
+
+ void swap( coroutine & other);
+
+ bool empty() const;
+
+ coroutine & operator()(A0 a0, ..., A9 a9);
+
+ R get() const;
+ };
+
+ template< typename Signature >
+ void swap( coroutine< Signature > & l, coroutine< Signature > & r);
+
+ template< typename T >
+ range_iterator< coroutine< T() > >::type begin( coroutine< T() > &);
+ template< typename T >
+ range_iterator< coroutine< void(T) > >::type begin( coroutine< void(T) > &);
+
+ template< typename T >
+ range_iterator< coroutine< T() > >::type end( coroutine< T() > &);
+ template< typename T >
+ range_iterator< coroutine< void(T) > >::type end( coroutine< void(T) > &);
+
+[heading `coroutine()`]
+[variablelist
+[[Effects:] [Creates a coroutine representing __not_a_coro__.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `template< typename Fn, typename StackAllocator, typename Allocator >
+ coroutine( Fn fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`]
+[variablelist
+[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize()
+when ! is_stack_unbound().]]
+[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr`
+determines stack clean-up and preserving floating-point registers.
+For allocating/deallocating the stack `stack_alloc` is used and internal
+data are allocated by Allocator.]]
+]
+
+[heading `template< typename Fn, typename StackAllocator, typename Allocator >
+ coroutine( Fn && fn, attributes const& attr, StackAllocator const& stack_alloc, Allocator const& alloc)`]
+[variablelist
+[[Preconditions:] [`size` > minimum_stacksize(), `size` < maximum_stacksize()
+when ! is_stack_unbound().]]
+[[Effects:] [Creates a coroutine which will execute `fn`. Argument `attr`
+determines stack clean-up and preserving floating-point registers.
+For allocating/deallocating the stack `stack_alloc` is used and internal
+data are allocated by Allocator.]]
+]
+
+[heading `coroutine( coroutine && other)`]
+[variablelist
+[[Effects:] [Moves the internal data of `other` to `*this`.
+`other` becomes __not_a_coro__.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `coroutine & operator=( coroutine && other)`]
+[variablelist
+[[Effects:] [Destroys the internal data of `*this` and moves the
+internal data of `other` to `*this`. `other` becomes __not_a_coro__.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `operator unspecified-bool-type() const`]
+[variablelist
+[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function
+has returned (completed), the function returns false. Otherwise true.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `bool operator!() const`]
+[variablelist
+[[Returns:] [If `*this` refers to __not_a_coro__ or the coroutine-function
+has returned (completed), the function returns true. Otherwise false.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `bool empty()`]
+[variablelist
+[[Returns:] [If `*this` refers to __not_a_coro__, the function returns true.
+Otherwise false.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `coroutine<> & operator()(A0 a0, A9 a9)`]
+[variablelist
+[[Preconditions:] [operator unspecified-bool-type() returns true for `*this`.]
+[[Effects:] [Execution control is transferred to __coro_fn__ and the arguments
+`a0`,..., are passed to the coroutine-function.]]
+[[Throws:] [Exceptions thrown inside __coro_fn__.]]
+]
+
+[heading `R get()()`]
+[variablelist
+[[Preconditions:] [`*this` is not a __not_a_coro__, `! is_complete()`.]]
+[[Returns:] [Returns data transferred from coroutine-function via __coro_op__
+of __coro_caller__.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `void swap( coroutine & other)`]
+[variablelist
+[[Effects:] [Swaps the internal data from `*this` with the values
+of `other`.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading `T caller_type::operator()( R)`]
+[variablelist
+[[Effects:] [Gives execution control back to calling context by returning
+a value of type R. The return type of this function is a __tuple__ containing
+the arguments passed to __coro_op__.]]
+[[Throws:] [Nothing.]]
+]
+
+[heading Non-member function `swap()`]
+
+ template< typename Signature >
+ void swap( coroutine< Signature > & l, coroutine< Signature > & r);
+
+[variablelist
+[[Effects:] [As if 'l.swap( r)'.]]
+]
+
+[heading Non-member function `begin( coroutine< T() > &)`]
+ template< typename T >
+ range_iterator< coroutine< T() > >::type begin( coroutine< T() > &);
+
+[variablelist
+[[Returns:] [Returns a range-iterator (input-iterator).]]
+]
+
+[heading Non-member function `begin( coroutine< void(T) > &)`]
+ template< typename T >
+ range_iterator< coroutine< void(T) > >::type begin( coroutine< void(T) > &);
+
+[variablelist
+[[Returns:] [Returns a range-iterator (output-iterator).]]
+]
+
+[heading Non-member function `end( coroutine< T() > &)`]
+ template< typename T >
+ range_iterator< coroutine< T() > >::type end( coroutine< T() > &);
+
+[variablelist
+[[Returns:] [Returns a end range-iterator (input-iterator).]]
+]
+
+[heading Non-member function `end( coroutine< void(T) > &)`]
+ template< typename T >
+ range_iterator< coroutine< void(T) > >::type end( coroutine< void(T) > &);
+
+[variablelist
+[[Returns:] [Returns a end range-iterator (output-iterator).]]
+]
+
+[endsect]
+
+[endsect]
Added: trunk/libs/coroutine/doc/foo_bar.png
==============================================================================
Binary file. No diff available.
Added: trunk/libs/coroutine/doc/images/foo_bar.png
==============================================================================
Binary file. No diff available.
Added: trunk/libs/coroutine/doc/images/foo_bar_seq.png
==============================================================================
Binary file. No diff available.
Added: trunk/libs/coroutine/doc/intro.qbk
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/doc/intro.qbk 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,335 @@
+[/
+ Copyright Oliver Kowalke 2009.
+ 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
+]
+
+[section:intro Introduction]
+
+[heading Definition]
+
+In computer science routines are defined as a sequence of operations.
+The execution of routines form a parent-child relationship and the child
+terminates always before the parent.
+Coroutines are a generalization of routines.
+The principal difference between coroutines and routines is that a coroutine
+enables explicit suspend and resume their progress via additional operations by
+preserving local state, e.g. a coroutine is a kind of continuation.
+A continuation is a object representing a suspended execution (registers,
+stack). Each coroutine has its own stack and local variables, sub-routine calls
+etc.
+In this sense coroutines are (actually) a language concept.
+
+[heading How it works]
+
+Functions foo() and bar() are supposed to alternate their execution (leave and
+enter function body).
+
+[$../../../../libs/coroutine/doc/images/foo_bar.png [align center]]
+
+If coroutines would be called such as routines, the stack would grow with
+every call and will never be degraded. A jump into the middle of a coroutine
+would not be possible, because the return address would have been on top of
+stack entries.
+
+The solution is that each coroutine has its own stack and control-block
+(__fcontext__ from __boost_context__).
+Before the coroutine gets suspended, the non-volatile registers (including stack
+and instruction/program pointer) of the currently active coroutine are stored in
+coroutine's control-block.
+The registers of the newly activated coroutine must be restored from its
+associated control-block before it can continue with their work.
+
+[$../../../../libs/coroutine/doc/images/foo_bar_seq.png [align center]]
+
+The context switch requires no system privileges and provides cooperative
+multitasking on the level of language. Coroutines provide quasi parallelism.
+When a program is supposed to do several things at the same time, coroutines
+help to do this much simpler and more elegant than with only a single flow of
+control.
+Advantages can be seen particularly clearly with the use of a recursive
+function, such as traversal of binary trees (see example 'same fringe').
+
+
+[heading Example: asio::io_stream with std::stream]
+
+This section demonstrates how stackfull coroutines help to use standard C++
+IO-streams together with IO-demultiplexer like __io_service__ (using
+non-blocking IO).
+
+ int main( int argc, char * argv[])
+ {
+ ...
+ {
+ boost::asio::io_service io_service;
+ io_service.post(
+ boost::bind(
+ & server::start,
+ server::create(
+ io_service, port) ) );
+ io_service.run();
+ }
+ ...
+ }
+
+
+__server__ accepts connection-requests made by clients, creates for each new
+connection an instance of type __session__ and invokes __start__ on it.
+
+ class server : public boost::enable_shared_from_this< server >
+ {
+ private:
+ boost::asio::io_service & io_service_;
+ boost::asio::ip::tcp::acceptor acceptor_;
+
+ void handle_accept_( session * new_session, boost::system::error_code const& error)
+ {
+ if ( ! error)
+ {
+ // start asynchronous read
+ new_session->start();
+
+ // start asynchronous accept
+ start();
+ }
+ }
+
+ server( boost::asio::io_service & io_service, short port) :
+ io_service_( io_service),
+ acceptor_(
+ io_service_,
+ boost::asio::ip::tcp::endpoint( boost::asio::ip::tcp::v4(), port) )
+ {}
+
+ public:
+ typedef boost::shared_ptr< server > ptr_t;
+
+ static ptr_t create( boost::asio::io_service & io_service, short port)
+ { return ptr_t( new server( io_service, port) ); }
+
+ void start()
+ {
+ // create new session which gets started if asynchronous
+ // accept completes
+ session * new_session( new session( io_service_) );
+ acceptor_.async_accept(
+ new_session->socket(),
+ boost::bind( & server::handle_accept_, this->shared_from_this(),
+ new_session, boost::asio::placeholders::error) );
+ }
+ };
+
+
+Each __session__ communicates with the connected client and handles the
+requests.
+The application protocol in this example uses TCP-sockets as channel and
+'newline' to separate the messages in the byte stream.
+An application protocol is a set of rules for the order in which messages are
+exchanged.
+['std::istream] is used to extract the messages from the character stream .
+Message 'exit' terminates the session.
+
+ class session : private boost::noncopyable
+ {
+ private:
+ void handle_read_( coro_t::caller_type & self)
+ {
+ // create stream-buffer reading from socket
+ inbuf buf( socket_);
+ std::istream s( & buf);
+
+ // messages are separated by 'newline'
+ std::string msg;
+ std::getline( s, msg);
+ std::cout << msg << std::endl;
+
+ // terminate session for message 'exit'
+ // else do asynchronous read
+ if ( "exit" == msg)
+ io_service_.post(
+ boost::bind(
+ & session::destroy_, this) );
+ else
+ start();
+ }
+
+ void destroy_()
+ { delete this; }
+
+ boost::asio::io_service & io_service_;
+ boost::asio::ip::tcp::socket socket_;
+
+ public:
+ session( boost::asio::io_service & io_service) :
+ io_service_( io_service),
+ socket_( io_service_)
+ { std::cout << "service(): " << socket_.remote_endpoint() << std::endl; }
+
+ ~session()
+ { std::cout << "~service(): " << socket_.remote_endpoint() << std::endl; }
+
+ boost::asio::ip::tcp::socket & socket()
+ { return socket_; }
+
+ void start()
+ {
+ // register on io_service for asynchronous read
+ io_service_.async_read(
+ socket_,
+ boost::bind(
+ & session::handle_read_, this->shared_from_this(), _1, _2) );
+ }
+ };
+
+
+Function __getline__ returns only if a 'newline' was read from the socket.
+Therefore the application will block until 'newline' is received by the socket.
+The stream-buffer used by the stream maintains an internal buffer which gets
+(re-)filled by its function __underflow__. __underflow__ does the
+read-operation on the socket. The C++ IO-streams framework does not provide an
+easy way to create an continuation which represents reading bytes from the socket.
+
+
+Coroutines help in this case to make the application non-blocking even if no
+'newline' was received.
+Class ['session] creates a coroutine which uses __handle_read__ as
+__coro_fn__. On a new created ['session] ['start()] called starting the
+coroutine. In the __coro_fn__ __handle_read__ the messages are received
+via __getline__ in a loop until 'exit' is delivered.
+
+ class session : private boost::noncopyable
+ {
+ private:
+ void handle_read_( coro_t::caller_type & ca)
+ {
+ // create stream-buffer with coroutine
+ inbuf buf( socket_, coro_, ca);
+ std::istream s( & buf);
+
+ std::string msg;
+ do
+ {
+ // read message
+ // we not block if no newline was received yet
+ std::getline( s, msg);
+ std::cout << msg << std::endl;
+ } while ( msg != "exit");
+ io_service_.post(
+ boost::bind(
+ & session::destroy_, this) );
+ }
+
+ void destroy_()
+ { delete this; }
+
+ coro_t coro_;
+ boost::asio::io_service & io_service_;
+ boost::asio::ip::tcp::socket socket_;
+
+ public:
+ session( boost::asio::io_service & io_service) :
+ coro_(),
+ io_service_( io_service),
+ socket_( io_service_)
+ { std::cout << "service(): " << socket_.remote_endpoint() << std::endl; }
+
+ ~session()
+ { std::cout << "~service(): " << socket_.remote_endpoint() << std::endl; }
+
+ boost::asio::ip::tcp::socket & socket()
+ { return socket_; }
+
+ void start()
+ {
+ // create and start a coroutine
+ // handle_read_() is used as coroutine-function
+ coro_ = coro_t( boost::bind( & session::handle_read_, this, _1) );
+ }
+ };
+
+
+The stream-buffer is created with __coro_caller__ and handles suspend/resume of this
+code path depending on if bytes can be read from the socket.
+
+ class inbuf : public std::streambuf,
+ private boost::noncopyable
+ {
+ private:
+ static const std::streamsize pb_size;
+
+ enum
+ { bf_size = 16 };
+
+ int fetch_()
+ {
+ std::streamsize num = std::min(
+ static_cast< std::streamsize >( gptr() - eback() ), pb_size);
+
+ std::memmove(
+ buffer_ + ( pb_size - num),
+ gptr() - num, num);
+
+ // read bytes from the socket into internal buffer 'buffer_'
+ // make coro_t::operator() as callback, invoked if some
+ // bytes are read into 'buffer_'
+ s_.async_read_some(
+ boost::asio::buffer( buffer_ + pb_size, bf_size - pb_size),
+ boost::bind( & coro_t::operator(), & coro_, _1, _2) );
+ // suspend this coroutine
+ ca_();
+
+ // coroutine was resumed by boost::asio::io_sevice
+ boost::system::error_code ec;
+ std::size_t n = 0;
+
+ // check arguments
+ boost::tie( ec, n) = ca_.get();
+
+ // check if an error occurred
+ if ( ec)
+ {
+ setg( 0, 0, 0);
+ return -1;
+ }
+
+ setg( buffer_ + pb_size - num, buffer_ + pb_size, buffer_ + pb_size + n);
+ return n;
+ }
+
+ boost::asio::ip::tcp::socket & s_;
+ coro_t & coro_;
+ coro_t::caller_type & ca_;
+ char buffer_[bf_size];
+
+ protected:
+ virtual int underflow()
+ {
+ if ( gptr() < egptr() )
+ return traits_type::to_int_type( * gptr() );
+
+ if ( 0 > fetch_() )
+ return traits_type::eof();
+ else
+ return traits_type::to_int_type( * gptr() );
+ }
+
+ public:
+ inbuf(
+ boost::asio::ip::tcp::socket & s,
+ coro_t & coro,
+ coro_t::caller_type & ca) :
+ s_( s), coro_( coro), ca_( ca), buffer_()
+ { setg( buffer_ + 4, buffer_ + 4, buffer_ + 4); }
+ };
+ const std::streamsize inbuf::pb_size = 4;
+
+
+__fetch__ uses __coro_op__ as callback for the asynchronous read-operation on the
+socket and suspends itself (['ca_()] jumps back to __start__). If some bytes are
+available in the socket receive buffer __io_service__ copies the bytes to the
+internal buffer ['buffer_] and invokes the callback which resumes the coroutine
+(['ca_()] returns).
+
+
+[endsect]
Added: trunk/libs/coroutine/doc/overview.qbk
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/doc/overview.qbk 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,47 @@
+[/
+ Copyright Oliver Kowalke 2009.
+ 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
+]
+
+[section:overview Overview]
+
+__boost_coroutine__ provides templates for generalized subroutines which allow
+multiple entry points for suspending and resuming execution at certain
+locations.
+It preserves the local state of execution and allows re-entering subroutines more
+than once (useful if state must be kept across function calls).
+
+Coroutines can be viewed as a language-level construct providing a special kind
+of control flow.
+
+In contrast to threads, which are pre-emptive, __coro__ switches are
+cooperative (programmer controls when a switch will happen). The kernel is not
+involved in the coroutine switches.
+
+The implementation uses __boost_context__ for context switching.
+
+This library is a follow-up on
+[@http://www.crystalclearsoftware.com/soc/coroutine/ Boost.Coroutine]
+by Giovanni P. Deretta.
+
+In order to use the classes and functions described here, you can either include
+the specific headers specified by the descriptions of each class or function, or
+include the master library header:
+
+ #include <boost/coroutine/all.hpp>
+
+which includes all the other headers in turn.
+
+All functions and classes are contained in the namespace __coro_ns__.
+
+__boost_coroutine__ depends on __boost_context__, __boost_exception__,
+__boost_function_types__, __boost_move__, __boost_mpl__, __boost_optional__,
+__boost_preprocessor__, __boost_range__, __boost_result_of__,
+__boost_smart_ptr__, __boost_static_assert__, __boost_tuple__,
+__boost_type_traits__ as well as __boost_utility__ and requires
+__boost_version__.
+
+
+[endsect]
Added: trunk/libs/coroutine/doc/performance.qbk
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/doc/performance.qbk 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,35 @@
+[/
+ Copyright Oliver Kowalke 2009.
+ 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
+]
+
+[section:performance Performance]
+
+Performance of __boost_coroutine__ was measured on the platforms shown in the
+following table. Performance measurements were taken using `rdtsc` and
+`::clock_gettime()`, with overhead corrections, on x86 platforms. In each case,
+stack protection was active, cache warm-up was accounted for, and the one
+running thread was pinned to a single CPU. The code was compiled using the
+build options, 'variant = release cxxflags = -DBOOST_DISABLE_ASSERTS'.
+
+The numbers in the table are the number of cycles per iteration, based upon an
+average computed over 10 iterations.
+
+[table Perfomance of coroutine switch
+ [[Platform] [CPU cycles] [nanoseconds]]
+ [
+ [AMD Athlon 64 DualCore 4400+ (32bit Linux)]
+ [58]
+ [65]
+ ]
+ [
+ [Intel Core2 Q6700 (64bit Linux)]
+ [80]
+ [28]
+ ]
+]
+
+
+[endsect]
Added: trunk/libs/coroutine/doc/stack.qbk
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/doc/stack.qbk 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,120 @@
+[/
+ Copyright Oliver Kowalke 2009.
+ 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
+]
+
+[section:stack Stack allocation]
+
+A __coro__ uses internally a __ctx__ which manages a set of registers and a stack.
+The memory used by the stack is allocated/deallocated via a __stack_allocator__
+which is required to model a __stack_allocator_concept__.
+
+
+[heading __stack_allocator_concept__]
+A __stack_allocator__ must satisfy the __stack_allocator_concept__ requirements
+shown in the following table, in which `a` is an object of a
+__stack_allocator__ type, `p` is a `void *`, and `s` is a `std::size_t`:
+
+[table
+ [[expression][return type][notes]]
+ [
+ [`a.allocate( s)`]
+ [`void *`]
+ [returns a pointer to `s` bytes allocated from the stack]
+ ]
+ [
+ [`a.deallocate( p, s)`]
+ [`void`]
+ [deallocates `s` bytes of memory beginning at `p`,
+ a pointer previously returned by `a.allocate()`]
+ ]
+]
+
+[important The implementation of `allocate()` might include logic to protect
+against exceeding the context's available stack size rather than leaving it as
+undefined behaviour.]
+
+[important Calling `deallocate()` with a pointer not returned by `allocate()`
+results in undefined behaviour.]
+
+[note The stack is not required to be aligned; alignment takes place inside
+__coro__.]
+
+[note Depending on the architecture `allocate()` returns an address from the
+top of the stack (growing downwards) or the bottom of the stack (growing
+upwards).]
+
+
+[section:stack_allocator Class ['stack_allocator]]
+
+__boost_coroutine__ provides the class __coro_allocator__ which models
+the __stack_allocator_concept__.
+It appends a guard page at the end of each stack to protect against exceeding
+the stack. If the guard page is accessed (read or write operation) a
+segmentation fault/access violation is generated by the operating system.
+
+[note The appended `guard page` is [*not] mapped to physical memory, only
+virtual addresses are used.]
+
+ class stack_allocator
+ {
+ static bool is_stack_unbound();
+
+ static std::size_t maximum_stacksize();
+
+ static std::size_t default_stacksize();
+
+ static std::size_t minimum_stacksize();
+
+ void * allocate( std::size_t size);
+
+ void deallocate( void * sp, std::size_t size);
+ }
+
+[heading `static bool is_stack_unbound()`]
+[variablelist
+[[Returns:] [Returns `true` if the environment defines no limit for the size of a stack.]]
+]
+
+[heading `static std::size_t maximum_stacksize()`]
+[variablelist
+[[Preconditions:] [`is_stack_unbound()` returns `false`.]]
+[[Returns:] [Returns the maximum size in bytes of stack defined by the environment.]]
+]
+
+[heading `static std::size_t default_stacksize()`]
+[variablelist
+[[Returns:] [Returns a default stack size, which may be platform specific.
+If the stack is unbound then the present implementation returns the maximum of
+`64 kB` and `minimum_stacksize()`.]]
+]
+
+[heading `static std::size_t minimum_stacksize()`]
+[variablelist
+[[Returns:] [Returns the minimum size in bytes of stack defined by the
+environment (Win32 4kB/Win64 8kB, defined by rlimit on POSIX).]]
+]
+
+[heading `void * allocate( std::size_t size)`]
+[variablelist
+[[Preconditions:] [`minimum_stacksize() > size` and
+`! is_stack_unbound() && ( maximum_stacksize() < size)`.]]
+[[Effects:] [Allocates memory of `size` Bytes and appends one guard page at the
+end of the allocated memory.]]
+[[Returns:] [Returns pointer to the start address of the new stack. Depending
+on the architecture the stack grows downwards/upwards the returned address is
+the highest/lowest address of the stack.]]
+]
+
+[heading `void deallocate( void * sp, std::size_t size)`]
+[variablelist
+[[Preconditions:] [`sp` is valid, `minimum_stacksize() > size` and
+`! is_stack_unbound() && ( maximum_stacksize() < size)`.]]
+[[Effects:] [Deallocates the stack space.]]
+]
+
+[endsect]
+
+[endsect]
Added: trunk/libs/coroutine/example/Jamfile.v2
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/example/Jamfile.v2 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,81 @@
+# Boost.Coroutine Library Examples Jamfile
+
+# Copyright Oliver Kowalke 2009.
+# 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)
+
+# For more information, see http://www.boost.org/
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import toolset ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+else if [ os.name ] = HPUX
+{
+ lib ipv6 ;
+}
+
+project boost/coroutine/example
+ : requirements
+ <library>/boost/context//boost_context
+ <library>/boost/program_options//boost_program_options
+ <library>/boost/system//boost_system
+ <library>/boost/thread//boost_thread
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT:<define>_WIN32_WINNT=0x0501
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ <os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
+ <os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
+ <os>HPUX:<library>ipv6
+ <link>static
+ ;
+
+exe fibonacci
+ : fibonacci.cpp
+ ;
+
+exe echo
+ : echo.cpp
+ ;
+
+exe power
+ : power.cpp
+ ;
+
+exe parallel
+ : parallel.cpp
+ ;
+
+exe unwind
+ : unwind.cpp
+ ;
+
+exe same_fringe
+ : same_fringe.cpp
+ ;
+
+exe asio/stream_client
+ : asio/stream_client.cpp
+ ;
+
+exe asio/stream_server
+ : asio/stream_server.cpp
+ ;
Added: trunk/libs/coroutine/example/asio/stream_client.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/example/asio/stream_client.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,64 @@
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/asio.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/program_options.hpp>
+#include <boost/thread.hpp>
+
+int main( int argc, char* argv[])
+{
+ try
+ {
+ std::string host, msg, port;
+ int timeout = 1;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help,h", "help message")
+ ("host,a", boost::program_options::value< std::string >( & host), "host running the service")
+ ("port,p", boost::program_options::value< std::string >( & port), "port service is listening")
+ ("message,m", boost::program_options::value< std::string >( & msg), "message to send")
+ ("timeout,t", boost::program_options::value< int >( & timeout), "timeout between message 'exit' message in seconds");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ boost::asio::io_service io_service;
+
+ boost::asio::ip::tcp::resolver resolver( io_service);
+ boost::asio::ip::tcp::resolver::query query( boost::asio::ip::tcp::v4(), host, port);
+ boost::asio::ip::tcp::resolver::iterator iterator( resolver.resolve( query) );
+
+ boost::asio::ip::tcp::socket s( io_service);
+ s.connect( * iterator);
+
+ msg.append("\n"); // each message is terminated by newline
+ boost::asio::write( s, boost::asio::buffer( msg, msg.size() ) );
+ std::cout << msg << " sendet" << std::endl;
+ boost::this_thread::sleep( boost::posix_time::seconds( timeout) );
+ std::string exit("exit\n"); // newline
+ boost::asio::write( s, boost::asio::buffer( exit, exit.size() ) );
+ std::cout << exit << " sendet" << std::endl;
+
+ std::cout << "Done" << std::endl;
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return EXIT_FAILURE;
+}
Added: trunk/libs/coroutine/example/asio/stream_server.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/example/asio/stream_server.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,207 @@
+#define NOMINMAX
+
+#include <cstdlib>
+#include <cstring>
+#include <iterator>
+#include <iostream>
+#include <streambuf>
+
+#include <boost/array.hpp>
+#include <boost/asio.hpp>
+#include <boost/bind.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/function.hpp>
+#include <boost/program_options.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/utility.hpp>
+
+typedef boost::tuple< boost::system::error_code, std::size_t > tuple_t;
+typedef boost::coroutines::coroutine< void( boost::system::error_code, std::size_t) > coro_t;
+
+class inbuf : public std::streambuf,
+ private boost::noncopyable
+{
+private:
+ static const std::streamsize pb_size;
+
+ enum
+ { bf_size = 16 };
+
+ int fetch_()
+ {
+ std::streamsize num = std::min(
+ static_cast< std::streamsize >( gptr() - eback() ), pb_size);
+
+ std::memmove(
+ buffer_ + ( pb_size - num),
+ gptr() - num, num);
+
+ s_.async_read_some(
+ boost::asio::buffer( buffer_ + pb_size, bf_size - pb_size),
+ boost::bind( & coro_t::operator(), & coro_, _1, _2) );
+ ca_();
+
+ boost::system::error_code ec;
+ std::size_t n = 0;
+
+ boost::tie( ec, n) = ca_.get();
+ if ( ec)
+ {
+ setg( 0, 0, 0);
+ return -1;
+ }
+
+ setg( buffer_ + pb_size - num, buffer_ + pb_size, buffer_ + pb_size + n);
+ return n;
+ }
+
+ boost::asio::ip::tcp::socket & s_;
+ coro_t & coro_;
+ coro_t::caller_type & ca_;
+ char buffer_[bf_size];
+
+protected:
+ virtual int underflow()
+ {
+ if ( gptr() < egptr() )
+ return traits_type::to_int_type( * gptr() );
+
+ if ( 0 > fetch_() )
+ return traits_type::eof();
+ else
+ return traits_type::to_int_type( * gptr() );
+ }
+
+public:
+ inbuf(
+ boost::asio::ip::tcp::socket & s,
+ coro_t & coro,
+ coro_t::caller_type & ca) :
+ s_( s), coro_( coro), ca_( ca), buffer_()
+ { setg( buffer_ + 4, buffer_ + 4, buffer_ + 4); }
+};
+const std::streamsize inbuf::pb_size = 4;
+
+class session : private boost::noncopyable
+{
+private:
+ void handle_read_( coro_t::caller_type & ca)
+ {
+ inbuf buf( socket_, coro_, ca);
+ std::istream s( & buf);
+
+ std::string msg;
+ do
+ {
+ std::getline( s, msg);
+ std::cout << msg << std::endl;
+ } while ( "exit" != msg);
+ io_service_.post(
+ boost::bind(
+ & session::destroy_, this) );
+ }
+
+ void destroy_()
+ { delete this; }
+
+ coro_t coro_;
+ boost::asio::io_service & io_service_;
+ boost::asio::ip::tcp::socket socket_;
+
+public:
+ session( boost::asio::io_service & io_service) :
+ coro_(),
+ io_service_( io_service),
+ socket_( io_service_)
+ {}
+
+ boost::asio::ip::tcp::socket & socket()
+ { return socket_; }
+
+ void start()
+ { coro_ = coro_t( boost::bind( & session::handle_read_, this, _1) ); }
+};
+
+class server : public boost::enable_shared_from_this< server >
+{
+private:
+ boost::asio::io_service & io_service_;
+ boost::asio::ip::tcp::acceptor acceptor_;
+
+ void handle_accept_( session * new_session, boost::system::error_code const& error)
+ {
+ if ( ! error)
+ {
+ new_session->start();
+ start();
+ }
+ }
+
+ server( boost::asio::io_service & io_service, short port) :
+ io_service_( io_service),
+ acceptor_(
+ io_service_,
+ boost::asio::ip::tcp::endpoint( boost::asio::ip::tcp::v4(), port) )
+ {}
+
+public:
+ typedef boost::shared_ptr< server > ptr_t;
+
+ static ptr_t create( boost::asio::io_service & io_service, short port)
+ { return ptr_t( new server( io_service, port) ); }
+
+ void start()
+ {
+ session * new_session( new session( io_service_) );
+ acceptor_.async_accept(
+ new_session->socket(),
+ boost::bind( & server::handle_accept_, this->shared_from_this(),
+ new_session, boost::asio::placeholders::error) );
+ }
+};
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ int port = 0;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help,h", "help message")
+ ("port,p", boost::program_options::value< int >( & port), "port service is listening");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+ {
+ boost::asio::io_service io_service;
+ io_service.post(
+ boost::bind(
+ & server::start,
+ server::create(
+ io_service, port) ) );
+ io_service.run();
+ }
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "Exception: " << e.what() << std::endl; }
+
+ return EXIT_FAILURE;
+}
+
Added: trunk/libs/coroutine/example/echo.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/example/echo.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,46 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/bind.hpp>
+#include <boost/coroutine/all.hpp>
+
+typedef boost::coroutines::coroutine< void() > coro_t;
+
+void echo( coro_t & ca, int i)
+{
+ std::cout << i;
+ ca();
+}
+
+void runit( coro_t & ca)
+{
+ std::cout << "started! ";
+ for ( int i = 0; i < 10; ++i)
+ {
+ coro_t c( boost::bind( echo, _1, i) );
+ while ( c)
+ c();
+ ca();
+ }
+}
+
+int main( int argc, char * argv[])
+{
+ {
+ coro_t c( runit);
+ while ( c) {
+ std::cout << "-";
+ c();
+ }
+ }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
Added: trunk/libs/coroutine/example/fibonacci.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/example/fibonacci.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,43 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+#include <boost/coroutine/all.hpp>
+
+typedef boost::coroutines::coroutine< int() > coro_t;
+typedef boost::range_iterator< coro_t >::type iterator_t;
+
+void fibonacci( coro_t::caller_type & c)
+{
+ int first = 1, second = 1;
+ while ( true)
+ {
+ int third = first + second;
+ first = second;
+ second = third;
+ c( third);
+ }
+}
+
+int main()
+{
+ coro_t c( fibonacci);
+ iterator_t it( boost::begin( c) );
+ BOOST_ASSERT( boost::end( c) != it);
+ for ( int i = 0; i < 10; ++i)
+ {
+ std::cout << * it << " ";
+ ++it;
+ }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
Added: trunk/libs/coroutine/example/parallel.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/example/parallel.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,51 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/bind.hpp>
+#include <boost/coroutine/all.hpp>
+
+typedef boost::coroutines::coroutine< void() > coroutine_t;
+
+void first( coroutine_t::caller_type & self)
+{
+ std::cout << "started first! ";
+ for ( int i = 0; i < 10; ++i)
+ {
+ self();
+ std::cout << "a" << i;
+ }
+}
+
+void second( coroutine_t::caller_type & self)
+{
+ std::cout << "started second! ";
+ for ( int i = 0; i < 10; ++i)
+ {
+ self();
+ std::cout << "b" << i;
+ }
+}
+
+int main( int argc, char * argv[])
+{
+ {
+ coroutine_t c1( boost::bind( first, _1) );
+ coroutine_t c2( boost::bind( second, _1) );
+ while ( c1 && c2) {
+ c1();
+ std::cout << " ";
+ c2();
+ std::cout << " ";
+ }
+ }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
Added: trunk/libs/coroutine/example/power.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/example/power.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,50 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/range.hpp>
+#include <boost/coroutine/all.hpp>
+
+typedef boost::coroutines::coroutine< int() > coro1_t;
+typedef boost::coroutines::coroutine< void( int) > coro2_t;
+typedef boost::range_iterator< coro1_t >::type iterator_t;
+
+void power( coro2_t & c, int number, int exponent)
+{
+ int counter = 0;
+ int result = 1;
+ while ( counter++ < exponent)
+ {
+ result = result * number;
+ c( result);
+ }
+}
+
+int main()
+{
+ {
+ std::cout << "using range functions" << std::endl;
+ coro1_t c( boost::bind( power, _1, 2, 8) );
+ iterator_t e( boost::end( c) );
+ for ( iterator_t i( boost::begin( c) ); i != e; ++i)
+ std::cout << * i << " ";
+ }
+
+ {
+ std::cout << "\nusing BOOST_FOREACH" << std::endl;
+ coro1_t c( boost::bind( power, _1, 2, 8) );
+ BOOST_FOREACH( int i, c)
+ { std::cout << i << " "; }
+ }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
Added: trunk/libs/coroutine/example/same_fringe.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/example/same_fringe.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,81 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <cstddef>
+#include <cstdlib>
+#include <iostream>
+#include <string>
+#include <utility>
+
+#include <boost/bind.hpp>
+#include <boost/range.hpp>
+
+#include "tree.h"
+
+bool match_trees( coro_t & c1, coro_t & c2)
+{
+ typedef boost::range_iterator< coro_t >::type iterator_t;
+ iterator_t i1( boost::begin( c1) );
+ iterator_t e1( boost::end( c1) );
+ iterator_t i2( boost::begin( c2) );
+ return std::equal( i1, e1, i2);
+}
+
+std::pair< node::ptr_t, node::ptr_t > create_eq_trees()
+{
+ branch::ptr_t tree1 = branch::create(
+ leaf::create( "A"),
+ branch::create(
+ leaf::create( "B"),
+ leaf::create( "C") ) );
+
+ branch::ptr_t tree2 = branch::create(
+ branch::create(
+ leaf::create( "A"),
+ leaf::create( "B") ),
+ leaf::create( "C") );
+
+ return std::make_pair( tree1, tree2);
+}
+
+std::pair< node::ptr_t, node::ptr_t > create_diff_trees()
+{
+ branch::ptr_t tree1 = branch::create(
+ leaf::create( "A"),
+ branch::create(
+ leaf::create( "B"),
+ leaf::create( "C") ) );
+
+ branch::ptr_t tree2 = branch::create(
+ branch::create(
+ leaf::create( "A"),
+ leaf::create( "X") ),
+ leaf::create( "C") );
+
+ return std::make_pair( tree1, tree2);
+}
+
+int main()
+{
+ {
+ std::pair< node::ptr_t, node::ptr_t > pt = create_eq_trees();
+ coro_t te1( boost::bind( enumerate_leafs, _1, pt.first) );
+ coro_t te2( boost::bind( enumerate_leafs, _1, pt.second) );
+ bool result = match_trees( te1, te2);
+ std::cout << std::boolalpha << "eq. trees matched == " << result << std::endl;
+ }
+ {
+ std::pair< node::ptr_t, node::ptr_t > pt = create_diff_trees();
+ coro_t te1( boost::bind( enumerate_leafs, _1, pt.first) );
+ coro_t te2( boost::bind( enumerate_leafs, _1, pt.second) );
+ bool result = match_trees( te1, te2);
+ std::cout << std::boolalpha << "diff. trees matched == " << result << std::endl;
+ }
+
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+}
Added: trunk/libs/coroutine/example/tree.h
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/example/tree.h 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,127 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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 TREE_H
+#define TREE_H
+
+#include <cstddef>
+#include <string>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+# if defined(BOOST_MSVC)
+# pragma warning(push)
+# pragma warning(disable:4355)
+# endif
+
+struct branch;
+struct leaf;
+
+struct visitor
+{
+ virtual ~visitor() {};
+
+ virtual void visit( branch & b) = 0;
+ virtual void visit( leaf & l) = 0;
+};
+
+struct node
+{
+ typedef boost::intrusive_ptr< node > ptr_t;
+
+ std::size_t use_count;
+
+ node() :
+ use_count( 0)
+ {}
+
+ virtual ~node() {}
+
+ virtual void accept( visitor & v) = 0;
+
+ friend inline void intrusive_ptr_add_ref( node * p)
+ { ++p->use_count; }
+
+ friend inline void intrusive_ptr_release( node * p)
+ { if ( 0 == --p->use_count) delete p; }
+};
+
+struct branch : public node
+{
+ node::ptr_t left;
+ node::ptr_t right;
+
+ static ptr_t create( node::ptr_t left_, node::ptr_t right_)
+ { return ptr_t( new branch( left_, right_) ); }
+
+ branch( node::ptr_t left_, node::ptr_t right_) :
+ left( left_), right( right_)
+ {}
+
+ void accept( visitor & v)
+ { v.visit( * this); }
+};
+
+struct leaf : public node
+{
+ std::string value;
+
+ static ptr_t create( std::string const& value_)
+ { return ptr_t( new leaf( value_) ); }
+
+ leaf( std::string const& value_) :
+ value( value_)
+ {}
+
+ void accept( visitor & v)
+ { v.visit( * this); }
+};
+
+inline
+bool operator==( leaf const& l, leaf const& r)
+{ return l.value == r.value; }
+
+inline
+bool operator!=( leaf const& l, leaf const& r)
+{ return l.value != r.value; }
+
+typedef boost::coroutines::coroutine< leaf&() > coro_t;
+
+class tree_visitor : public visitor
+{
+private:
+ coro_t::caller_type & c_;
+
+public:
+ tree_visitor( coro_t::caller_type & c) :
+ c_( c)
+ {}
+
+ void visit( branch & b)
+ {
+ if ( b.left) b.left->accept( * this);
+ if ( b.right) b.right->accept( * this);
+ }
+
+ void visit( leaf & l)
+ { c_( l); }
+};
+
+void enumerate_leafs( coro_t::caller_type & c, node::ptr_t root)
+{
+ tree_visitor v( c);
+ root->accept( v);
+}
+
+# if defined(BOOST_MSVC)
+# pragma warning(pop)
+# endif
+
+
+#endif // TREE_H
Added: trunk/libs/coroutine/example/unwind.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/example/unwind.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,46 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/bind.hpp>
+#include <boost/coroutine/all.hpp>
+
+typedef boost::coroutines::coroutine< void() > coro_t;
+
+struct X : private boost::noncopyable
+{
+ X() { std::cout << "X()" << std::endl; }
+ ~X() { std::cout << "~X()" << std::endl; }
+};
+
+void fn( coro_t & ca)
+{
+ X x;
+ int i = 0;
+ while ( true)
+ {
+ std::cout << "fn() : " << ++i << std::endl;
+ ca();
+ }
+}
+
+int main( int argc, char * argv[])
+{
+ {
+ coro_t c( fn);
+ for ( int k = 0; k < 3; ++k)
+ {
+ c();
+ }
+ std::cout << "destroying coroutine and unwinding stack" << std::endl;
+ }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
Added: trunk/libs/coroutine/index.html
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/index.html 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,14 @@
+<html>
+<head>
+<meta http-equiv="refresh" content="0; URL=doc/html/index.html">
+</head>
+<body>
+Automatic redirection failed, please go to
+doc/html/index.html
+<hr>
+<p>© Copyright Beman Dawes, 2001</p>
+<p> Distributed under the Boost Software
+License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
+www.boost.org/LICENSE_1_0.txt</a>)</p>
+</body>
+</html>
Added: trunk/libs/coroutine/performance/Jamfile.v2
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/Jamfile.v2 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,64 @@
+
+# Copyright Oliver Kowalke 2009.
+# 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)
+
+# For more information, see http://www.boost.org/
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import toolset ;
+
+project boost/context/performance
+ : requirements
+ <library>/boost/context//boost_context
+ <link>static
+ <linkflags>"-lrt"
+ <threading>single
+ ;
+
+alias sources
+ : performance.cpp
+ bind_processor_aix.cpp
+ : <target-os>aix
+ ;
+
+alias sources
+ : performance.cpp
+ bind_processor_freebsd.cpp
+ : <target-os>freebsd
+ ;
+
+alias sources
+ : performance.cpp
+ bind_processor_hpux.cpp
+ : <target-os>hpux
+ ;
+
+alias sources
+ : performance.cpp
+ bind_processor_linux.cpp
+ : <target-os>linux
+ ;
+
+alias sources
+ : performance.cpp
+ bind_processor_solaris.cpp
+ : <target-os>solaris
+ ;
+
+alias sources
+ : performance.cpp
+ bind_processor_windows.cpp
+ : <target-os>windows
+ ;
+
+explicit sources ;
+
+exe performance
+ : sources
+ ;
Added: trunk/libs/coroutine/performance/bind_processor.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/bind_processor.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,12 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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 BIND_TO_PROCESSOR_H
+#define BIND_TO_PROCESSOR_H
+
+void bind_to_processor( unsigned int n);
+
+#endif // BIND_TO_PROCESSOR_H
Added: trunk/libs/coroutine/performance/bind_processor_aix.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/bind_processor_aix.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,25 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "bind_processor.hpp"
+
+extern "C"
+{
+#include <sys/processor.h>
+#include <sys/thread.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ if ( ::bindprocessor( BINDTHREAD, ::thread_self(), static_cast< cpu_t >( n) ) == -1)
+ throw std::runtime_error("::bindprocessor() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
Added: trunk/libs/coroutine/performance/bind_processor_freebsd.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/bind_processor_freebsd.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,29 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "bind_processor.hpp"
+
+extern "C"
+{
+#include <sys/param.h>
+#include <sys/cpuset.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ cpuset_t cpuset;
+ CPU_ZERO( & cpuset);
+ CPU_SET( n, & cpuset);
+
+ if ( ::cpuset_setaffinity( CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof( cpuset), & cpuset) == -1)
+ throw std::runtime_error("::cpuset_setaffinity() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
Added: trunk/libs/coroutine/performance/bind_processor_hpux.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/bind_processor_hpux.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,31 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "bind_processor.hpp"
+
+extern "C"
+{
+#include <sys/pthread.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ ::pthread_spu_t spu;
+ int errno_(
+ ::pthread_processor_bind_np(
+ PTHREAD_BIND_FORCED_NP,
+ & spu,
+ static_cast< pthread_spu_t >( n),
+ PTHREAD_SELFTID_NP) );
+ if ( errno_ != 0)
+ throw std::runtime_error("::pthread_processor_bind_np() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
Added: trunk/libs/coroutine/performance/bind_processor_linux.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/bind_processor_linux.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,30 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "bind_processor.hpp"
+
+extern "C"
+{
+#include <pthread.h>
+#include <sched.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ cpu_set_t cpuset;
+ CPU_ZERO( & cpuset);
+ CPU_SET( n, & cpuset);
+
+ int errno_( ::pthread_setaffinity_np( ::pthread_self(), sizeof( cpuset), & cpuset) );
+ if ( errno_ != 0)
+ throw std::runtime_error("::pthread_setaffinity_np() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
Added: trunk/libs/coroutine/performance/bind_processor_solaris.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/bind_processor_solaris.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,26 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "bind_processor.hpp"
+
+extern "C"
+{
+#include <sys/types.h>
+#include <sys/processor.h>
+#include <sys/procset.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ if ( ::processor_bind( P_LWPID, P_MYID, static_cast< processorid_t >( n), 0) == -1)
+ throw std::runtime_error("::processor_bind() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
Added: trunk/libs/coroutine/performance/bind_processor_windows.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/bind_processor_windows.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,24 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "bind_processor.hpp"
+
+extern "C"
+{
+#include <windows.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ if ( ::SetThreadAffinityMask( ::GetCurrentThread(), ( DWORD_PTR)1 << n) == 0)
+ throw std::runtime_error("::SetThreadAffinityMask() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
Added: trunk/libs/coroutine/performance/cycle.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/cycle.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,26 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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 CYCLE_H
+#define CYCLE_H
+
+// x86_64
+// test x86_64 before i386 because icc might
+// define __i686__ for x86_64 too
+#if defined(__x86_64__) || defined(__x86_64) \
+ || defined(__amd64__) || defined(__amd64) \
+ || defined(_M_X64) || defined(_M_AMD64)
+# include "cycle_x86-64.hpp"
+// i386
+#elif defined(i386) || defined(__i386__) || defined(__i386) \
+ || defined(__i486__) || defined(__i586__) || defined(__i686__) \
+ || defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) \
+ || defined(__I86__) || defined(__INTEL__) || defined(__IA32__) \
+ || defined(_M_IX86) || defined(_I86_)
+# include "cycle_i386.hpp"
+#endif
+
+#endif // CYCLE_H
Added: trunk/libs/coroutine/performance/cycle_i386.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/cycle_i386.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,83 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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 CYCLE_I386_H
+#define CYCLE_I386_H
+
+#include <algorithm>
+#include <numeric>
+#include <cstddef>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include <boost/cstdint.hpp>
+
+#define BOOST_CONTEXT_CYCLE
+
+typedef boost::uint64_t cycle_t;
+
+#if _MSC_VER
+inline
+cycle_t cycles()
+{
+ cycle_t c;
+ __asm {
+ cpuid
+ rdtsc
+ mov dword ptr [c + 0], eax
+ mov dword ptr [c + 4], edx
+ }
+ return c;
+}
+#elif defined(__GNUC__) || \
+ defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL)
+inline
+cycle_t cycles()
+{
+ boost::uint32_t lo, hi;
+
+ __asm__ __volatile__ (
+ "xorl %%eax, %%eax\n"
+ "cpuid\n"
+ ::: "%eax", "%ebx", "%ecx", "%edx"
+ );
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi) );
+ __asm__ __volatile__ (
+ "xorl %%eax, %%eax\n"
+ "cpuid\n"
+ ::: "%eax", "%ebx", "%ecx", "%edx"
+ );
+
+ return ( cycle_t)hi << 32 | lo;
+}
+#else
+# error "this compiler is not supported"
+#endif
+
+struct measure_cycles
+{
+ cycle_t operator()()
+ {
+ cycle_t start( cycles() );
+ return cycles() - start;
+ }
+};
+
+inline
+cycle_t overhead_cycles()
+{
+ std::size_t iterations( 10);
+ std::vector< cycle_t > overhead( iterations, 0);
+ for ( std::size_t i( 0); i < iterations; ++i)
+ std::generate(
+ overhead.begin(), overhead.end(),
+ measure_cycles() );
+ BOOST_ASSERT( overhead.begin() != overhead.end() );
+ return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations;
+}
+
+#endif // CYCLE_I386_H
Added: trunk/libs/coroutine/performance/cycle_x86-64.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/cycle_x86-64.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,79 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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 CYCLE_X86_64_H
+#define CYCLE_X86_64_H
+
+#include <algorithm>
+#include <numeric>
+#include <cstddef>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include <boost/cstdint.hpp>
+
+#define BOOST_CONTEXT_CYCLE
+
+typedef boost::uint64_t cycle_t;
+
+#if _MSC_VER >= 1400
+# include <intrin.h>
+# pragma intrinsic(__rdtsc)
+inline
+cycle_t cycles()
+{ return __rdtsc(); }
+#elif defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL)
+inline
+cycle_t cycles()
+{ return __rdtsc(); }
+#elif defined(__GNUC__) || defined(__SUNPRO_C)
+inline
+cycle_t cycles()
+{
+ boost::uint32_t lo, hi;
+
+ __asm__ __volatile__ (
+ "xorl %%eax, %%eax\n"
+ "cpuid\n"
+ ::: "%rax", "%rbx", "%rcx", "%rdx"
+ );
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi) );
+ __asm__ __volatile__ (
+ "xorl %%eax, %%eax\n"
+ "cpuid\n"
+ ::: "%rax", "%rbx", "%rcx", "%rdx"
+ );
+
+ return ( cycle_t)hi << 32 | lo;
+}
+#else
+# error "this compiler is not supported"
+#endif
+
+struct measure_cycles
+{
+ cycle_t operator()()
+ {
+ cycle_t start( cycles() );
+ return cycles() - start;
+ }
+};
+
+inline
+cycle_t overhead_cycles()
+{
+ std::size_t iterations( 10);
+ std::vector< cycle_t > overhead( iterations, 0);
+ for ( std::size_t i( 0); i < iterations; ++i)
+ std::generate(
+ overhead.begin(), overhead.end(),
+ measure_cycles() );
+ BOOST_ASSERT( overhead.begin() != overhead.end() );
+ return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations;
+}
+
+#endif // CYCLE_X86_64_H
Added: trunk/libs/coroutine/performance/performance.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/performance.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,119 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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)
+
+#define BOOST_PP_LIMIT_MAG 10
+
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include <boost/context/all.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/preprocessor/repetition/repeat_from_to.hpp>
+
+#include "bind_processor.hpp"
+#include "cycle.hpp"
+#include "simple_stack_allocator.hpp"
+
+#if _POSIX_C_SOURCE >= 199309L
+#include "zeit.hpp"
+#endif
+
+namespace coro = boost::coroutines;
+namespace ctx = boost::context;
+
+typedef coro::coroutine< void() > coro_t;
+
+#define COUNTER BOOST_PP_LIMIT_MAG
+
+#define CALL_COROUTINE(z,n,unused) \
+ c();
+
+void fn( coro_t::caller_type & c)
+{ while ( true) c(); }
+
+#ifdef BOOST_CONTEXT_CYCLE
+cycle_t test_cycles( cycle_t ov, coro::flag_fpu_t preserve_fpu)
+{
+ ctx::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc;
+ coro_t c( fn, coro::attributes( preserve_fpu), alloc);
+
+ // cache warum-up
+BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~)
+
+ cycle_t start( cycles() );
+BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~)
+ cycle_t total( cycles() - start);
+
+ // we have two jumps and two measuremt-overheads
+ total -= ov; // overhead of measurement
+ total /= COUNTER; // per call
+ total /= 2; // 2x jump_to c1->c2 && c2->c1
+
+ return total;
+}
+#endif
+
+#if _POSIX_C_SOURCE >= 199309L
+zeit_t test_zeit( zeit_t ov, coro::flag_fpu_t preserve_fpu)
+{
+ ctx::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc;
+ coro_t c( fn, coro::attributes( preserve_fpu), alloc);
+
+ // cache warum-up
+BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~)
+
+ zeit_t start( zeit() );
+BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~)
+ zeit_t total( zeit() - start);
+
+ // we have two jumps and two measuremt-overheads
+ total -= ov; // overhead of measurement
+ total /= BOOST_PP_LIMIT_MAG; // per call
+ total /= 2; // 2x jump_to c1->c2 && c2->c1
+
+ return total;
+}
+#endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ coro::flag_fpu_t preserve_fpu = coro::fpu_not_preserved;
+ bind_to_processor( 0);
+
+#ifdef BOOST_CONTEXT_CYCLE
+ {
+ cycle_t ov( overhead_cycles() );
+ std::cout << "overhead for rdtsc == " << ov << " cycles" << std::endl;
+
+ unsigned int res = test_cycles( ov, preserve_fpu);
+ std::cout << "coroutine: average of " << res << " cycles per switch" << std::endl;
+ }
+#endif
+
+#if _POSIX_C_SOURCE >= 199309L
+ {
+ zeit_t ov( overhead_zeit() );
+ std::cout << "\noverhead for clock_gettime() == " << ov << " ns" << std::endl;
+
+ unsigned int res = test_zeit( ov, preserve_fpu);
+ std::cout << "coroutine: average of " << res << " ns per switch" << std::endl;
+ }
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
Added: trunk/libs/coroutine/performance/simple_stack_allocator.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/simple_stack_allocator.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,67 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_CONTEXT_SIMPLE_STACK_ALLOCATOR_H
+#define BOOST_CONTEXT_SIMPLE_STACK_ALLOCATOR_H
+
+#include <cstddef>
+#include <cstdlib>
+#include <stdexcept>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+
+#include <boost/context/detail/config.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace context {
+
+template< std::size_t Max, std::size_t Default, std::size_t Min >
+class simple_stack_allocator
+{
+public:
+ static std::size_t maximum_stacksize()
+ { return Max; }
+
+ static std::size_t default_stacksize()
+ { return Default; }
+
+ static std::size_t minimum_stacksize()
+ { return Min; }
+
+ void * allocate( std::size_t size) const
+ {
+ BOOST_ASSERT( minimum_stacksize() <= size);
+ BOOST_ASSERT( maximum_stacksize() >= size);
+
+ void * limit = std::calloc( size, sizeof( char) );
+ if ( ! limit) throw std::bad_alloc();
+
+ return static_cast< char * >( limit) + size;
+ }
+
+ void deallocate( void * vp, std::size_t size) const
+ {
+ BOOST_ASSERT( vp);
+ BOOST_ASSERT( minimum_stacksize() <= size);
+ BOOST_ASSERT( maximum_stacksize() >= size);
+
+ void * limit = static_cast< char * >( vp) - size;
+ std::free( limit);
+ }
+};
+
+}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_CONTEXT_SIMPLE_STACK_ALLOCATOR_H
Added: trunk/libs/coroutine/performance/zeit.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/performance/zeit.hpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,53 @@
+
+// Copyright Oliver Kowalke 2009.
+// 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 ZEIT_H
+#define ZEIT_H
+
+#include <time.h>
+
+#include <algorithm>
+#include <numeric>
+#include <cstddef>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include <boost/cstdint.hpp>
+
+typedef boost::uint64_t zeit_t;
+
+inline
+zeit_t zeit()
+{
+ timespec t;
+ ::clock_gettime( CLOCK_PROCESS_CPUTIME_ID, & t);
+ return t.tv_sec * 1000000000 + t.tv_nsec;
+}
+
+struct measure_zeit
+{
+ zeit_t operator()()
+ {
+ zeit_t start( zeit() );
+ return zeit() - start;
+ }
+};
+
+inline
+zeit_t overhead_zeit()
+{
+ std::size_t iterations( 10);
+ std::vector< zeit_t > overhead( iterations, 0);
+ for ( std::size_t i( 0); i < iterations; ++i)
+ std::generate(
+ overhead.begin(), overhead.end(),
+ measure_zeit() );
+ BOOST_ASSERT( overhead.begin() != overhead.end() );
+ return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations;
+}
+
+#endif // ZEIT_H
Added: trunk/libs/coroutine/test/Jamfile.v2
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/test/Jamfile.v2 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,25 @@
+# Boost.Coroutine Library Tests Jamfile
+
+# Copyright Oliver Kowalke 2009.
+# 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)
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import testing ;
+import toolset ;
+
+project boost/coroutine/test
+ : requirements
+ <library>../../test/build//boost_unit_test_framework
+ <library>/boost/context//boost_context
+ <link>static
+ ;
+
+test-suite "coroutine" :
+ [ run test_coroutine.cpp ]
+ ;
Added: trunk/libs/coroutine/test/test_coroutine.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/coroutine/test/test_coroutine.cpp 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -0,0 +1,494 @@
+
+// Copyright Oliver Kowalke 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include <cstdio>
+
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/move/move.hpp>
+#include <boost/range.hpp>
+#include <boost/ref.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/utility.hpp>
+
+#include <boost/coroutine/all.hpp>
+
+namespace coro = boost::coroutines;
+
+int value1 = 0;
+std::string value2 = "";
+bool value3 = false;
+
+typedef coro::coroutine< void() > coro_void_void;
+typedef coro::coroutine< int() > coro_int_void;
+typedef coro::coroutine< std::string() > coro_string_void;
+typedef coro::coroutine< void(int) > coro_void_int;
+typedef coro::coroutine< void(std::string const&) > coro_void_string;
+typedef coro::coroutine< double(double,double) > coro_double;
+typedef coro::coroutine< int(int,int) > coro_int;
+typedef coro::coroutine< int(int) > coro_int_int;
+typedef coro::coroutine< int*(int*) > coro_ptr;
+typedef coro::coroutine< int const&(int const&) > coro_ref;
+typedef coro::coroutine< boost::tuple<int&,int&>(int&,int&) > coro_tuple;
+
+struct X : private boost::noncopyable
+{
+ X() { value1 = 7; }
+ ~X() { value1 = 0; }
+};
+
+class copyable
+{
+public:
+ bool state;
+
+ copyable() :
+ state( false)
+ {}
+
+ copyable( int) :
+ state( true)
+ {}
+
+ void operator()( coro_int_void::caller_type &)
+ { value3 = state; }
+};
+
+class moveable
+{
+private:
+ BOOST_MOVABLE_BUT_NOT_COPYABLE( moveable);
+
+public:
+ bool state;
+
+ moveable() :
+ state( false)
+ {}
+
+ moveable( int) :
+ state( true)
+ {}
+
+ moveable( BOOST_RV_REF( moveable) other) :
+ state( false)
+ { std::swap( state, other.state); }
+
+ moveable & operator=( BOOST_RV_REF( moveable) other)
+ {
+ if ( this == & other) return * this;
+ moveable tmp( boost::move( other) );
+ std::swap( state, tmp.state);
+ return * this;
+ }
+
+ void operator()( coro_int_void::caller_type &)
+ { value3 = state; }
+};
+
+struct my_exception {};
+
+void f1( coro_void_void::caller_type & s)
+{ s(); }
+
+void f2( coro_void_void::caller_type &)
+{ ++value1; }
+
+void f3( coro_void_void::caller_type & self)
+{
+ ++value1;
+ self();
+ ++value1;
+}
+
+void f4( coro_int_void::caller_type & self)
+{
+ self( 3);
+ self( 7);
+}
+
+void f5( coro_string_void::caller_type & self)
+{
+ std::string res("abc");
+ self( res);
+ res = "xyz";
+ self( res);
+}
+
+void f6( coro_void_int::caller_type & self)
+{ value1 = self.get(); }
+
+void f7( coro_void_string::caller_type & self)
+{ value2 = self.get(); }
+
+void f8( coro_double::caller_type & self)
+{
+ double x = 0, y = 0;
+ boost::tie( x, y) = self.get();
+ self( x + y);
+ boost::tie( x, y) = self.get();
+ self( x + y);
+}
+
+void f9( coro_ptr::caller_type & self)
+{ self( self.get() ); }
+
+void f10( coro_ref::caller_type & self)
+{ self( self.get() ); }
+
+void f11( coro_tuple::caller_type & self)
+{
+ boost::tuple<int&,int&> tpl( self.get().get< 0 >(), self.get().get< 1 >() );
+ self( tpl);
+}
+
+void f12( coro_int::caller_type & self)
+{
+ X x_;
+ int x, y;
+ boost::tie( x, y) = self.get();
+ self( x +y);
+ boost::tie( x, y) = self.get();
+ self( x +y);
+}
+
+template< typename E >
+void f14( coro_void_void::caller_type & self, E const& e)
+{ throw e; }
+
+void f16( coro_int_void::caller_type & self)
+{
+ self( 1);
+ self( 2);
+ self( 3);
+ self( 4);
+ self( 5);
+}
+
+void f17( coro_void_int::caller_type & self, std::vector< int > & vec)
+{
+ int x = self.get();
+ while ( 5 > x)
+ {
+ vec.push_back( x);
+ x = self().get();
+ }
+}
+
+void f18( coro_int_int::caller_type & self)
+{
+ if ( self.has_result() )
+ {
+ int x = self.get();
+ self( x + 1);
+ }
+ else
+ {
+ self( -1);
+ }
+}
+
+void test_move()
+{
+ {
+ coro_void_void coro1;
+ coro_void_void coro2( f1);
+ BOOST_CHECK( ! coro1);
+ BOOST_CHECK( coro1.empty() );
+ BOOST_CHECK( coro2);
+ BOOST_CHECK( ! coro2.empty() );
+ coro1 = boost::move( coro2);
+ BOOST_CHECK( coro1);
+ BOOST_CHECK( ! coro1.empty() );
+ BOOST_CHECK( ! coro2);
+ BOOST_CHECK( coro2.empty() );
+ }
+
+ {
+ value3 = false;
+ copyable cp( 3);
+ BOOST_CHECK( cp.state);
+ BOOST_CHECK( ! value3);
+ coro_int_void coro( cp);
+ BOOST_CHECK( cp.state);
+ BOOST_CHECK( value3);
+ }
+
+ {
+ value3 = false;
+ moveable mv( 7);
+ BOOST_CHECK( mv.state);
+ BOOST_CHECK( ! value3);
+ coro_int_void coro( boost::move( mv) );
+ BOOST_CHECK( ! mv.state);
+ BOOST_CHECK( value3);
+ }
+}
+
+void test_complete()
+{
+ value1 = 0;
+
+ coro_void_void coro( f2);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( int)1, value1);
+}
+
+void test_jump()
+{
+ value1 = 0;
+
+ coro_void_void coro( f3);
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int)1, value1);
+ coro();
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( int)2, value1);
+}
+
+void test_result_int()
+{
+ coro_int_void coro( f4);
+ BOOST_CHECK( coro);
+ int result = coro.get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( 3, result);
+ result = coro().get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( 7, result);
+ coro();
+ BOOST_CHECK( ! coro);
+}
+
+void test_result_string()
+{
+ coro_string_void coro( f5);
+ BOOST_CHECK( coro);
+ std::string result = coro.get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( std::string("abc"), result);
+ result = coro().get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( std::string("xyz"), result);
+ coro();
+ BOOST_CHECK( ! coro);
+}
+
+void test_arg_int()
+{
+ value1 = 0;
+
+ coro_void_int coro( f6, 3);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( 3, value1);
+}
+
+void test_arg_string()
+{
+ value2 = "";
+
+ coro_void_string coro( f7, std::string("abc") );
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( std::string("abc"), value2);
+}
+
+void test_fp()
+{
+ coro_double coro( f8, coro_double::arguments( 7.35, 3.14) );
+ BOOST_CHECK( coro);
+ double res = coro.get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( double) 10.49, res);
+ res = coro( 1.15, 3.14).get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( double) 4.29, res);
+ coro( 1.15, 3.14);
+ BOOST_CHECK( ! coro);
+}
+
+void test_ptr()
+{
+ int a = 3;
+ coro_ptr coro( f9, & a);
+ BOOST_CHECK( coro);
+ int * res = coro.get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( & a, res);
+ coro( & a);
+ BOOST_CHECK( ! coro);
+}
+
+void test_ref()
+{
+ int a = 3;
+ coro_ref coro( f10, a);
+ BOOST_CHECK( coro);
+ int const& res = coro.get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( & a, & res);
+ coro( a);
+ BOOST_CHECK( ! coro);
+}
+
+void test_tuple()
+{
+ int a = 3, b = 7;
+ coro_tuple coro( f11, coro_tuple::arguments( a, b) );
+ BOOST_CHECK( coro);
+ boost::tuple<int&,int&> tpl = coro.get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( & a, & tpl.get< 0 >() );
+ BOOST_CHECK_EQUAL( & b, & tpl.get< 1 >() );
+ coro( a, b);
+ BOOST_CHECK( ! coro);
+}
+
+void test_unwind()
+{
+ value1 = 0;
+ {
+ BOOST_CHECK_EQUAL( ( int) 0, value1);
+ coro_int coro( f12, coro_int::arguments( 3, 7) );
+ BOOST_CHECK( coro);
+ int res = coro.get();
+ BOOST_CHECK_EQUAL( ( int) 7, value1);
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int) 10, res);
+ }
+ BOOST_CHECK_EQUAL( ( int) 0, value1);
+}
+
+void test_no_unwind()
+{
+ value1 = 0;
+ {
+ BOOST_CHECK_EQUAL( ( int) 0, value1);
+ coro_int coro(
+ f12,
+ coro_int::arguments( 3, 7),
+ coro::attributes(
+ coro::stack_allocator::default_stacksize(),
+ coro::no_stack_unwind) );
+ BOOST_CHECK( coro);
+ int res = coro.get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int) 10, res);
+ }
+ BOOST_CHECK_EQUAL( ( int) 7, value1);
+}
+
+void test_exceptions()
+{
+ bool thrown = false;
+ std::runtime_error ex("abc");
+ try
+ {
+ coro_void_void coro( boost::bind( f14< std::runtime_error >, _1, ex) );
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK( false);
+ }
+ catch ( std::runtime_error const&)
+ { thrown = true; }
+ catch ( std::exception const&)
+ {}
+ catch (...)
+ {}
+ BOOST_CHECK( thrown);
+}
+
+void test_output_iterator()
+{
+ std::vector< int > vec;
+ coro_int_void coro( f16);
+ BOOST_FOREACH( int i, coro)
+ { vec.push_back( i); }
+ BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() );
+ BOOST_CHECK_EQUAL( ( int)1, vec[0] );
+ BOOST_CHECK_EQUAL( ( int)2, vec[1] );
+ BOOST_CHECK_EQUAL( ( int)3, vec[2] );
+ BOOST_CHECK_EQUAL( ( int)4, vec[3] );
+ BOOST_CHECK_EQUAL( ( int)5, vec[4] );
+}
+
+void test_input_iterator()
+{
+ int counter = 0;
+ std::vector< int > vec;
+ coro_void_int coro(
+ boost::bind( f17, _1, boost::ref( vec) ),
+ counter);
+ coro_void_int::iterator e( boost::end( coro) );
+ for ( coro_void_int::iterator i( boost::begin( coro) );
+ i != e; ++i)
+ {
+ i = ++counter;
+ }
+ BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() );
+ BOOST_CHECK_EQUAL( ( int)0, vec[0] );
+ BOOST_CHECK_EQUAL( ( int)1, vec[1] );
+ BOOST_CHECK_EQUAL( ( int)2, vec[2] );
+ BOOST_CHECK_EQUAL( ( int)3, vec[3] );
+ BOOST_CHECK_EQUAL( ( int)4, vec[4] );
+}
+
+void test_pre()
+{
+ coro_int_int coro( f18, 0);
+ BOOST_CHECK( coro);
+ int res = coro.get();
+ BOOST_CHECK_EQUAL( ( int) 1, res);
+ BOOST_CHECK( coro);
+ coro( -1);
+ BOOST_CHECK( ! coro);
+}
+
+void test_post()
+{
+ coro_int_int coro( f18);
+ BOOST_CHECK( coro);
+ int res = coro.get();
+ BOOST_CHECK_EQUAL( ( int) -1, res);
+ BOOST_CHECK( coro);
+ coro( -1);
+ BOOST_CHECK( ! coro);
+}
+
+
+boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
+{
+ boost::unit_test::test_suite * test =
+ BOOST_TEST_SUITE("Boost.coroutine: coroutine test suite");
+
+ test->add( BOOST_TEST_CASE( & test_move) );
+ test->add( BOOST_TEST_CASE( & test_complete) );
+ test->add( BOOST_TEST_CASE( & test_jump) );
+ test->add( BOOST_TEST_CASE( & test_pre) );
+ test->add( BOOST_TEST_CASE( & test_post) );
+ test->add( BOOST_TEST_CASE( & test_result_int) );
+ test->add( BOOST_TEST_CASE( & test_result_string) );
+ test->add( BOOST_TEST_CASE( & test_arg_int) );
+ test->add( BOOST_TEST_CASE( & test_arg_string) );
+ test->add( BOOST_TEST_CASE( & test_fp) );
+ test->add( BOOST_TEST_CASE( & test_ptr) );
+ test->add( BOOST_TEST_CASE( & test_ref) );
+ test->add( BOOST_TEST_CASE( & test_tuple) );
+ test->add( BOOST_TEST_CASE( & test_unwind) );
+ test->add( BOOST_TEST_CASE( & test_no_unwind) );
+ test->add( BOOST_TEST_CASE( & test_exceptions) );
+ test->add( BOOST_TEST_CASE( & test_output_iterator) );
+ test->add( BOOST_TEST_CASE( & test_input_iterator) );
+
+ return test;
+}
Modified: trunk/libs/libraries.htm
==============================================================================
--- trunk/libs/libraries.htm (original)
+++ trunk/libs/libraries.htm 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -118,6 +118,7 @@
intended for library users.</li>
<li>container - Standard library containers and extensions, from Ion Gaztañaga</li>
<li>context - Context switching library, from Oliver Kowalke</li>
+ <li>coroutine - Coroutine library, from Oliver Kowalke</li>
<li>conversion - Polymorphic and lexical casts, from Dave Abrahams and
Kevlin Henney.</li>
<li>crc - Cyclic Redundancy Code, from Daryle
@@ -398,6 +399,7 @@
I/O, including sockets, timers, hostname resolution, socket iostreams, serial
ports, file descriptors and Windows HANDLEs, from Chris Kohlhoff.</li>
<li>context - Context switching library, from Oliver Kowalke</li>
+ <li>coroutine - Coroutine library, from Oliver Kowalke</li>
<li>interprocess - Shared memory, memory mapped files,
process-shared mutexes, condition variables, containers and allocators, from Ion Gaztañaga</li>
<li>lockfree - Lockfree data structures, from Tim Blechmann</li>
Modified: trunk/libs/maintainers.txt
==============================================================================
--- trunk/libs/maintainers.txt (original)
+++ trunk/libs/maintainers.txt 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -24,7 +24,8 @@
concept_check Jeremy Siek <jeremy.siek -at- gmail.com>
config John Maddock <john -at- johnmaddock.co.uk>
container Ion Gaztanaga <igaztanaga -at- gmail.com>
-context Oliver Kowalke <oliver.kowalke -at- gmx.de>
+context Oliver Kowalke <oliver.kowalke -at- gmail.com>
+coroutine Oliver Kowalke <oliver.kowalke -at- gmail.com>
conversion Antony Polukhin <antoshkka -at- gmail.com>
crc Daryle Walker <darylew -at- hotmail.com>
date_time Jeff Garland <jeff -at- crystalclearsoftware.com>
Modified: trunk/status/Jamfile.v2
==============================================================================
--- trunk/status/Jamfile.v2 (original)
+++ trunk/status/Jamfile.v2 2012-11-24 14:42:09 EST (Sat, 24 Nov 2012)
@@ -65,6 +65,7 @@
container/example # test-suite container_example
container/test # test-suite container_test
context/test # test-suite context
+ coroutine/test # test-suite coroutine
crc/test # test-suite crc
date_time/test # test-suite date_time
detail/test # test-suite detail
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk